*/
#include <config.h>
-#include "ofproto.h"
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
+
#include "bitmap.h"
+#include "bundles.h"
#include "byte-order.h"
#include "classifier.h"
#include "connectivity.h"
#include "connmgr.h"
#include "coverage.h"
-#include "openvswitch/dynamic-string.h"
+#include "dp-packet.h"
#include "hash.h"
-#include "hmap.h"
-#include "openvswitch/meta-flow.h"
+#include "openvswitch/hmap.h"
#include "netdev.h"
#include "nx-match.h"
-#include "ofp-actions.h"
-#include "ofp-msgs.h"
-#include "ofp-print.h"
-#include "ofp-util.h"
-#include "openvswitch/ofpbuf.h"
+#include "ofproto.h"
#include "ofproto-provider.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
+#include "openvswitch/dynamic-string.h"
+#include "openvswitch/meta-flow.h"
+#include "openvswitch/ofp-actions.h"
+#include "openvswitch/ofp-errors.h"
+#include "openvswitch/ofp-msgs.h"
+#include "openvswitch/ofp-print.h"
+#include "openvswitch/ofp-util.h"
+#include "openvswitch/ofpbuf.h"
+#include "openvswitch/vlog.h"
#include "ovs-rcu.h"
-#include "dp-packet.h"
#include "packets.h"
#include "pinsched.h"
#include "pktbuf.h"
#include "poll-loop.h"
#include "random.h"
#include "seq.h"
-#include "shash.h"
+#include "openvswitch/shash.h"
#include "simap.h"
#include "smap.h"
#include "sset.h"
#include "tun-metadata.h"
#include "unaligned.h"
#include "unixctl.h"
-#include "openvswitch/ofp-errors.h"
-#include "openvswitch/vlog.h"
-#include "bundles.h"
+#include "util.h"
VLOG_DEFINE_THIS_MODULE(ofproto);
/* ofport. */
static void ofport_destroy__(struct ofport *) OVS_EXCLUDED(ofproto_mutex);
static void ofport_destroy(struct ofport *, bool del);
+static inline bool ofport_is_internal(const struct ofport *);
static int update_port(struct ofproto *, const char *devname);
static int init_ports(struct ofproto *);
static uint64_t pick_fallback_dpid(void);
static void ofproto_destroy__(struct ofproto *);
static void update_mtu(struct ofproto *, struct ofport *);
+static void update_mtu_ofproto(struct ofproto *);
static void meter_delete(struct ofproto *, uint32_t first, uint32_t last);
static void meter_insert_rule(struct rule *);
ovs_list_init(&ofproto->expirable);
ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
guarded_list_init(&ofproto->rule_executes);
- ofproto->vlan_bitmap = NULL;
- ofproto->vlans_changed = false;
ofproto->min_mtu = INT_MAX;
ovs_rwlock_init(&ofproto->groups_rwlock);
hmap_init(&ofproto->groups);
ofproto_set_cpu_mask(const char *cmask)
{
free(pmd_cpu_mask);
-
- pmd_cpu_mask = cmask ? xstrdup(cmask) : NULL;
+ pmd_cpu_mask = nullable_xstrdup(cmask);
}
void
ofproto_set_dp_desc(struct ofproto *p, const char *dp_desc)
{
free(p->dp_desc);
- p->dp_desc = dp_desc ? xstrdup(dp_desc) : NULL;
+ p->dp_desc = nullable_xstrdup(dp_desc);
}
int
}
}
+static int
+ofproto_get_ipfix_stats(struct ofproto *ofproto,
+ bool bridge_ipfix,
+ struct ovs_list *replies)
+{
+ int error;
+
+ if (ofproto->ofproto_class->get_ipfix_stats) {
+ error = ofproto->ofproto_class->get_ipfix_stats(ofproto,
+ bridge_ipfix,
+ replies);
+ } else {
+ error = EOPNOTSUPP;
+ }
+
+ return error;
+}
+
+static enum ofperr
+handle_ipfix_bridge_stats_request(struct ofconn *ofconn,
+ const struct ofp_header *request)
+{
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ struct ovs_list replies;
+ enum ofperr error;
+
+ ofpmp_init(&replies, request);
+ error = ofproto_get_ipfix_stats(ofproto, true, &replies);
+
+ if (!error) {
+ ofconn_send_replies(ofconn, &replies);
+ } else {
+ ofpbuf_list_delete(&replies);
+ }
+
+ return error;
+}
+
+static enum ofperr
+handle_ipfix_flow_stats_request(struct ofconn *ofconn,
+ const struct ofp_header *request)
+{
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ struct ovs_list replies;
+ enum ofperr error;
+
+ ofpmp_init(&replies, request);
+ error = ofproto_get_ipfix_stats(ofproto, false, &replies);
+
+ if (!error) {
+ ofconn_send_replies(ofconn, &replies);
+ } else {
+ ofpbuf_list_delete(&replies);
+ }
+
+ return error;
+}
+
void
ofproto_set_flow_restore_wait(bool flow_restore_wait_db)
{
OVS_NOT_REACHED();
}
ofproto_rule_remove__(rule->ofproto, rule);
- ofproto->ofproto_class->rule_delete(rule);
+ if (ofproto->ofproto_class->rule_delete) {
+ ofproto->ofproto_class->rule_delete(rule);
+ }
ofproto_rule_unref(rule);
}
ovs_mutex_unlock(&ofproto_mutex);
ovs_assert(hmap_is_empty(&ofproto->learned_cookies));
hmap_destroy(&ofproto->learned_cookies);
- free(ofproto->vlan_bitmap);
-
ofproto->ofproto_class->dealloc(ofproto);
}
OVS_EXCLUDED(ofproto_mutex)
{
struct ofport *ofport, *next_ofport;
- struct ofport_usage *usage, *next_usage;
+ struct ofport_usage *usage;
if (!p) {
return;
ofport_destroy(ofport, del);
}
- HMAP_FOR_EACH_SAFE (usage, next_usage, hmap_node, &p->ofport_usage) {
- hmap_remove(&p->ofport_usage, &usage->hmap_node);
+ HMAP_FOR_EACH_POP (usage, hmap_node, &p->ofport_usage) {
free(usage);
}
static void
ofport_remove(struct ofport *ofport)
{
+ struct ofproto *p = ofport->ofproto;
+ bool is_internal = ofport_is_internal(ofport);
+
connmgr_send_port_status(ofport->ofproto->connmgr, NULL, &ofport->pp,
OFPPR_DELETE);
ofport_destroy(ofport, true);
+ if (!is_internal) {
+ update_mtu_ofproto(p);
+ }
}
/* If 'ofproto' contains an ofport named 'name', removes it from 'ofproto' and
{
struct ofport *port = ofproto_get_port(ofproto, ofp_port);
if (port) {
- if (port->ofproto->ofproto_class->set_realdev) {
- port->ofproto->ofproto_class->set_realdev(port, 0, 0);
- }
if (port->ofproto->ofproto_class->set_stp_port) {
port->ofproto->ofproto_class->set_stp_port(port, NULL);
}
return 0;
}
+static inline bool
+ofport_is_internal(const struct ofport *port)
+{
+ return !strcmp(netdev_get_type(port->netdev), "internal");
+}
+
/* Find the minimum MTU of all non-datapath devices attached to 'p'.
* Returns ETH_PAYLOAD_MAX or the minimum of the ports. */
static int
/* Skip any internal ports, since that's what we're trying to
* set. */
- if (!strcmp(netdev_get_type(netdev), "internal")) {
+ if (ofport_is_internal(ofport)) {
continue;
}
static void
update_mtu(struct ofproto *p, struct ofport *port)
{
- struct ofport *ofport;
struct netdev *netdev = port->netdev;
- int dev_mtu, old_min;
+ int dev_mtu;
if (netdev_get_mtu(netdev, &dev_mtu)) {
port->mtu = 0;
return;
}
- if (!strcmp(netdev_get_type(port->netdev), "internal")) {
+ if (ofport_is_internal(port)) {
if (dev_mtu > p->min_mtu) {
if (!netdev_set_mtu(port->netdev, p->min_mtu)) {
dev_mtu = p->min_mtu;
return;
}
- /* For non-internal port find new min mtu. */
- old_min = p->min_mtu;
port->mtu = dev_mtu;
+ /* For non-internal port find new min mtu. */
+ update_mtu_ofproto(p);
+}
+
+static void
+update_mtu_ofproto(struct ofproto *p)
+{
+ /* For non-internal port find new min mtu. */
+ struct ofport *ofport;
+ int old_min = p->min_mtu;
+
p->min_mtu = find_min_mtu(p);
if (p->min_mtu == old_min) {
return;
HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
struct netdev *netdev = ofport->netdev;
- if (!strcmp(netdev_get_type(netdev), "internal")) {
+ if (ofport_is_internal(ofport)) {
if (!netdev_set_mtu(netdev, p->min_mtu)) {
ofport->mtu = p->min_mtu;
}
if (!classifier_remove(&table->cls, &rule->cr)) {
OVS_NOT_REACHED();
}
- ofproto->ofproto_class->rule_delete(rule);
+ if (ofproto->ofproto_class->rule_delete) {
+ ofproto->ofproto_class->rule_delete(rule);
+ }
ofproto_rule_unref(rule);
}
if (old_rule) {
ovsrcu_postpone(remove_rule_rcu, old_rule);
} else {
- if (minimask_get_vid_mask(new_rule->cr.match.mask) == VLAN_VID_MASK) {
- if (ofproto->vlan_bitmap) {
- uint16_t vid = miniflow_get_vid(new_rule->cr.match.flow);
-
- if (!bitmap_is_set(ofproto->vlan_bitmap, vid)) {
- bitmap_set1(ofproto->vlan_bitmap, vid);
- ofproto->vlans_changed = true;
- }
- } else {
- ofproto->vlans_changed = true;
- }
- }
-
ofmonitor_report(ofproto->connmgr, new_rule, NXFME_ADDED, 0,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
return error;
}
+/* Implements the OFPGC11_ADD_OR_MOD command which creates the group when it does not
+ * exist yet and modifies it otherwise */
+static enum ofperr
+add_or_modify_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm)
+{
+ struct ofgroup *ofgroup;
+ enum ofperr error;
+ bool exists;
+
+ ovs_rwlock_rdlock(&ofproto->groups_rwlock);
+ exists = ofproto_group_lookup__(ofproto, gm->group_id, &ofgroup);
+ ovs_rwlock_unlock(&ofproto->groups_rwlock);
+
+ if (!exists) {
+ error = add_group(ofproto, gm);
+ } else {
+ error = modify_group(ofproto, gm);
+ }
+ return error;
+}
+
static void
delete_group__(struct ofproto *ofproto, struct ofgroup *ofgroup)
OVS_RELEASES(ofproto->groups_rwlock)
error = modify_group(ofproto, &gm);
break;
+ case OFPGC11_ADD_OR_MOD:
+ error = add_or_modify_group(ofproto, &gm);
+ break;
+
case OFPGC11_DELETE:
delete_group(ofproto, gm.group_id);
error = 0;
case OFPTYPE_NXT_TLV_TABLE_REQUEST:
return handle_tlv_table_request(ofconn, oh);
+ case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
+ return handle_ipfix_bridge_stats_request(ofconn, oh);
+
+ case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
+ return handle_ipfix_flow_stats_request(ofconn, oh);
+
case OFPTYPE_HELLO:
case OFPTYPE_ERROR:
case OFPTYPE_FEATURES_REPLY:
case OFPTYPE_REQUESTFORWARD:
case OFPTYPE_TABLE_STATUS:
case OFPTYPE_NXT_TLV_TABLE_REPLY:
+ case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
+ case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
default:
if (ofpmsg_is_stat_request(oh)) {
return OFPERR_OFPBRC_BAD_STAT;
unixctl_command_register("ofproto/list", "", 0, 0,
ofproto_unixctl_list, NULL);
}
-\f
-/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
- *
- * This is deprecated. It is only for compatibility with broken device drivers
- * in old versions of Linux that do not properly support VLANs when VLAN
- * devices are not used. When broken device drivers are no longer in
- * widespread use, we will delete these interfaces. */
-
-/* Sets a 1-bit in the 4096-bit 'vlan_bitmap' for each VLAN ID that is matched
- * (exactly) by an OpenFlow rule in 'ofproto'. */
-void
-ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
-{
- struct match match;
- struct cls_rule target;
- const struct oftable *oftable;
-
- match_init_catchall(&match);
- match_set_vlan_vid_masked(&match, htons(VLAN_CFI), htons(VLAN_CFI));
- cls_rule_init(&target, &match, 0);
-
- free(ofproto->vlan_bitmap);
- ofproto->vlan_bitmap = bitmap_allocate(4096);
- ofproto->vlans_changed = false;
-
- OFPROTO_FOR_EACH_TABLE (oftable, ofproto) {
- struct rule *rule;
-
- CLS_FOR_EACH_TARGET (rule, cr, &oftable->cls, &target,
- CLS_MAX_VERSION) {
- if (minimask_get_vid_mask(rule->cr.match.mask) == VLAN_VID_MASK) {
- uint16_t vid = miniflow_get_vid(rule->cr.match.flow);
-
- bitmap_set1(vlan_bitmap, vid);
- bitmap_set1(ofproto->vlan_bitmap, vid);
- }
- }
- }
-
- cls_rule_destroy(&target);
-}
-
-/* Returns true if new VLANs have come into use by the flow table since the
- * last call to ofproto_get_vlan_usage().
- *
- * We don't track when old VLANs stop being used. */
-bool
-ofproto_has_vlan_usage_changed(const struct ofproto *ofproto)
-{
- return ofproto->vlans_changed;
-}
-
-/* Configures a VLAN splinter binding between the ports identified by OpenFlow
- * port numbers 'vlandev_ofp_port' and 'realdev_ofp_port'. If
- * 'realdev_ofp_port' is nonzero, then the VLAN device is enslaved to the real
- * device as a VLAN splinter for VLAN ID 'vid'. If 'realdev_ofp_port' is zero,
- * then the VLAN device is un-enslaved. */
-int
-ofproto_port_set_realdev(struct ofproto *ofproto, ofp_port_t vlandev_ofp_port,
- ofp_port_t realdev_ofp_port, int vid)
-{
- struct ofport *ofport;
- int error;
-
- ovs_assert(vlandev_ofp_port != realdev_ofp_port);
-
- ofport = ofproto_get_port(ofproto, vlandev_ofp_port);
- if (!ofport) {
- VLOG_WARN("%s: cannot set realdev on nonexistent port %"PRIu16,
- ofproto->name, vlandev_ofp_port);
- return EINVAL;
- }
-
- if (!ofproto->ofproto_class->set_realdev) {
- if (!vlandev_ofp_port) {
- return 0;
- }
- VLOG_WARN("%s: vlan splinters not supported", ofproto->name);
- return EOPNOTSUPP;
- }
-
- error = ofproto->ofproto_class->set_realdev(ofport, realdev_ofp_port, vid);
- if (error) {
- VLOG_WARN("%s: setting realdev on port %"PRIu16" (%s) failed (%s)",
- ofproto->name, vlandev_ofp_port,
- netdev_get_name(ofport->netdev), ovs_strerror(error));
- }
- return error;
-}