vswitch: Use weak references in Mirror table.
[openvswitch] / vswitchd / bridge.c
index 66f0884fe73edf3ba7868822e7c7515ff0149313..11ec99d813202982e35c0cdf228db77b171e3e70 100644 (file)
@@ -61,6 +61,7 @@
 #include "vswitchd/vswitch-idl.h"
 #include "xenserver.h"
 #include "xtoxll.h"
+#include "sflow_api.h"
 
 #define THIS_MODULE VLM_bridge
 #include "vlog.h"
@@ -162,6 +163,13 @@ struct bridge {
     /* OpenFlow switch processing. */
     struct ofproto *ofproto;    /* OpenFlow switch. */
 
+    /* Description strings. */
+    char *mfr_desc;             /* Manufacturer. */
+    char *hw_desc;              /* Hardware. */
+    char *sw_desc;              /* Software version. */
+    char *serial_desc;          /* Serial number. */
+    char *dp_desc;              /* Datapath description. */
+
     /* Kernel datapath information. */
     struct dpif *dpif;          /* Datapath. */
     struct port_array ifaces;   /* Indexed by kernel datapath port number. */
@@ -198,6 +206,9 @@ static void bridge_destroy(struct bridge *);
 static struct bridge *bridge_lookup(const char *name);
 static unixctl_cb_func bridge_unixctl_dump_flows;
 static int bridge_run_one(struct bridge *);
+static const struct ovsrec_controller *bridge_get_controller(
+                      const struct ovsrec_open_vswitch *ovs_cfg,
+                      const struct bridge *br);
 static void bridge_reconfigure_one(const struct ovsrec_open_vswitch *,
                                    struct bridge *);
 static void bridge_reconfigure_controller(const struct ovsrec_open_vswitch *,
@@ -406,7 +417,12 @@ set_up_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface,
 
         memset(&netdev_options, 0, sizeof netdev_options);
         netdev_options.name = iface_cfg->name;
-        netdev_options.type = iface_cfg->type;
+        if (!strcmp(iface_cfg->type, "internal")) {
+            /* An "internal" config type maps to a netdev "system" type. */
+            netdev_options.type = "system";
+        } else {
+            netdev_options.type = iface_cfg->type;
+        }
         netdev_options.args = &options;
         netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
         netdev_options.may_create = true;
@@ -424,6 +440,11 @@ set_up_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface,
         const char *iface_type = iface_cfg->type && strlen(iface_cfg->type)
                                   ? iface_cfg->type : NULL;
 
+        /* An "internal" config type maps to a netdev "system" type. */
+        if (iface_type && !strcmp(iface_type, "internal")) {
+            iface_type = "system";
+        }
+
         if (!iface_type || !strcmp(netdev_type, iface_type)) {
             error = netdev_reconfigure(iface->netdev, &options);
         } else {
@@ -448,8 +469,8 @@ reconfigure_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface)
 }
 
 static bool
-check_iface_netdev(struct bridge *br UNUSED, struct iface *iface,
-                   void *aux UNUSED)
+check_iface_netdev(struct bridge *br OVS_UNUSED, struct iface *iface,
+                   void *aux OVS_UNUSED)
 {
     if (!iface->netdev) {
         int error = set_up_iface(iface->cfg, iface, true);
@@ -464,7 +485,8 @@ check_iface_netdev(struct bridge *br UNUSED, struct iface *iface,
 }
 
 static bool
-check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED)
+check_iface_dp_ifidx(struct bridge *br, struct iface *iface,
+                     void *aux OVS_UNUSED)
 {
     if (iface->dp_ifidx >= 0) {
         VLOG_DBG("%s has interface %s on port %d",
@@ -479,8 +501,8 @@ check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED)
 }
 
 static bool
-set_iface_properties(struct bridge *br UNUSED, struct iface *iface,
-                   void *aux UNUSED)
+set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface,
+                     void *aux OVS_UNUSED)
 {
     /* Set policing attributes. */
     netdev_set_policing(iface->netdev,
@@ -536,6 +558,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     struct shash_node *node;
     struct bridge *br, *next;
     size_t i;
+    int sflow_bridge_number;
 
     COVERAGE_INC(bridge_reconfigure);
 
@@ -669,6 +692,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         shash_destroy(&cur_ifaces);
         shash_destroy(&want_ifaces);
     }
+    sflow_bridge_number = 0;
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         uint8_t ea[8];
         uint64_t dpid;
@@ -750,6 +774,44 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
             ofproto_set_netflow(br->ofproto, NULL);
         }
 
+        /* Set sFlow configuration on this bridge. */
+        if (br->cfg->sflow) {
+            const struct ovsrec_sflow *sflow_cfg = br->cfg->sflow;
+            const struct ovsrec_controller *ctrl;
+            struct ofproto_sflow_options oso;
+
+            memset(&oso, 0, sizeof oso);
+
+            oso.targets.n = sflow_cfg->n_targets;
+            oso.targets.names = sflow_cfg->targets;
+
+            oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
+            if (sflow_cfg->sampling) {
+                oso.sampling_rate = *sflow_cfg->sampling;
+            }
+
+            oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL;
+            if (sflow_cfg->polling) {
+                oso.polling_interval = *sflow_cfg->polling;
+            }
+
+            oso.header_len = SFL_DEFAULT_HEADER_SIZE;
+            if (sflow_cfg->header) {
+                oso.header_len = *sflow_cfg->header;
+            }
+
+            oso.sub_id = sflow_bridge_number++;
+            oso.agent_device = sflow_cfg->agent;
+
+            ctrl = bridge_get_controller(ovs_cfg, br);
+            oso.control_ip = ctrl ? ctrl->local_ip : NULL;
+            ofproto_set_sflow(br->ofproto, &oso);
+
+            svec_destroy(&oso.targets);
+        } else {
+            ofproto_set_sflow(br->ofproto, NULL);
+        }
+
         /* Update the controller and related settings.  It would be more
          * straightforward to call this from bridge_reconfigure_one(), but we
          * can't do it there for two reasons.  First, and most importantly, at
@@ -1055,7 +1117,7 @@ bridge_get_local_iface(struct bridge *br)
 /* Bridge unixctl user interface functions. */
 static void
 bridge_unixctl_fdb_show(struct unixctl_conn *conn,
-                        const char *args, void *aux UNUSED)
+                        const char *args, void *aux OVS_UNUSED)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     const struct bridge *br;
@@ -1113,7 +1175,7 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
     br->cfg = br_cfg;
     br->ml = mac_learning_create();
     br->sent_config_request = false;
-    eth_addr_random(br->default_ea);
+    eth_addr_nicira_random(br->default_ea);
 
     port_array_init(&br->ifaces);
 
@@ -1183,7 +1245,7 @@ bridge_get_datapathid(const char *name)
  * stack, including those normally hidden. */
 static void
 bridge_unixctl_dump_flows(struct unixctl_conn *conn,
-                          const char *args, void *aux UNUSED)
+                          const char *args, void *aux OVS_UNUSED)
 {
     struct bridge *br;
     struct ds results;
@@ -1253,6 +1315,75 @@ check_duplicate_ifaces(struct bridge *br, struct iface *iface, void *ifaces_)
     }
 }
 
+static void
+bridge_update_desc(struct bridge *br)
+{
+#if 0
+    bool changed = false;
+    const char *desc;
+
+    desc = cfg_get_string(0, "bridge.%s.mfr-desc", br->name);
+    if (desc != br->mfr_desc) {
+        free(br->mfr_desc);
+        if (desc) {
+            br->mfr_desc = xstrdup(desc);
+        } else {
+            br->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
+        }
+        changed = true;
+    }
+
+    desc = cfg_get_string(0, "bridge.%s.hw-desc", br->name);
+    if (desc != br->hw_desc) {
+        free(br->hw_desc);
+        if (desc) {
+            br->hw_desc = xstrdup(desc);
+        } else {
+            br->hw_desc = xstrdup(DEFAULT_HW_DESC);
+        }
+        changed = true;
+    }
+
+    desc = cfg_get_string(0, "bridge.%s.sw-desc", br->name);
+    if (desc != br->sw_desc) {
+        free(br->sw_desc);
+        if (desc) {
+            br->sw_desc = xstrdup(desc);
+        } else {
+            br->sw_desc = xstrdup(DEFAULT_SW_DESC);
+        }
+        changed = true;
+    }
+
+    desc = cfg_get_string(0, "bridge.%s.serial-desc", br->name);
+    if (desc != br->serial_desc) {
+        free(br->serial_desc);
+        if (desc) {
+            br->serial_desc = xstrdup(desc);
+        } else {
+            br->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
+        }
+        changed = true;
+    }
+
+    desc = cfg_get_string(0, "bridge.%s.dp-desc", br->name);
+    if (desc != br->dp_desc) {
+        free(br->dp_desc);
+        if (desc) {
+            br->dp_desc = xstrdup(desc);
+        } else {
+            br->dp_desc = xstrdup(DEFAULT_DP_DESC);
+        }
+        changed = true;
+    }
+
+    if (changed) {
+        ofproto_set_desc(br->ofproto, br->mfr_desc, br->hw_desc,
+                br->sw_desc, br->serial_desc, br->dp_desc);
+    }
+#endif
+}
+
 static void
 bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg,
                        struct bridge *br)
@@ -1391,13 +1522,14 @@ bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg,
 #endif
 
     mirror_reconfigure(br);
+
+    bridge_update_desc(br);
 }
 
 static void
 bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg,
                               struct bridge *br)
 {
-    char *pfx = xasprintf("bridge.%s.controller", br->name);
     const struct ovsrec_controller *c;
 
     c = bridge_get_controller(ovs_cfg, br);
@@ -1428,7 +1560,7 @@ bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg,
             local_iface = bridge_get_local_iface(br);
             if (local_iface && c->local_ip && inet_aton(c->local_ip, &ip)) {
                 struct netdev *netdev = local_iface->netdev;
-                struct in_addr ip, mask, gateway;
+                struct in_addr mask, gateway;
 
                 if (!c->local_netmask || !inet_aton(c->local_netmask, &mask)) {
                     mask.s_addr = 0;
@@ -1491,7 +1623,6 @@ bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg,
         ofproto_set_probe_interval(br->ofproto, 5);
         ofproto_set_failure(br->ofproto, false);
     }
-    free(pfx);
 
     ofproto_set_controller(br->ofproto, br->controller);
 }
@@ -1950,7 +2081,7 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
     return dst - dsts;
 }
 
-static void UNUSED
+static void OVS_UNUSED
 print_dsts(const struct dst *dsts, size_t n)
 {
     for (; n--; dsts++) {
@@ -2665,7 +2796,7 @@ bond_send_learning_packets(struct port *port)
 
 static void
 bond_unixctl_list(struct unixctl_conn *conn,
-                  const char *args UNUSED, void *aux UNUSED)
+                  const char *args OVS_UNUSED, void *aux OVS_UNUSED)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     const struct bridge *br;
@@ -2716,7 +2847,7 @@ bond_find(const char *name)
 
 static void
 bond_unixctl_show(struct unixctl_conn *conn,
-                  const char *args, void *aux UNUSED)
+                  const char *args, void *aux OVS_UNUSED)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     const struct port *port;
@@ -2782,7 +2913,7 @@ bond_unixctl_show(struct unixctl_conn *conn,
 
 static void
 bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_,
-                     void *aux UNUSED)
+                     void *aux OVS_UNUSED)
 {
     char *args = (char *) args_;
     char *save_ptr = NULL;
@@ -2839,7 +2970,7 @@ bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_,
 
 static void
 bond_unixctl_set_active_slave(struct unixctl_conn *conn, const char *args_,
-                              void *aux UNUSED)
+                              void *aux OVS_UNUSED)
 {
     char *args = (char *) args_;
     char *save_ptr = NULL;
@@ -2920,21 +3051,21 @@ enable_slave(struct unixctl_conn *conn, const char *args_, bool enable)
 
 static void
 bond_unixctl_enable_slave(struct unixctl_conn *conn, const char *args,
-                          void *aux UNUSED)
+                          void *aux OVS_UNUSED)
 {
     enable_slave(conn, args, true);
 }
 
 static void
 bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args,
-                           void *aux UNUSED)
+                           void *aux OVS_UNUSED)
 {
     enable_slave(conn, args, false);
 }
 
 static void
 bond_unixctl_hash(struct unixctl_conn *conn, const char *args,
-                  void *aux UNUSED)
+                  void *aux OVS_UNUSED)
 {
        uint8_t mac[ETH_ADDR_LEN];
        uint8_t hash;
@@ -3039,7 +3170,7 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
 
         iface = shash_find_data(&old_ifaces, if_cfg->name);
         if (!iface) {
-            iface = iface_create(port, if_cfg);
+            iface_create(port, if_cfg);
         } else {
             iface->cfg = if_cfg;
         }
@@ -3636,7 +3767,7 @@ mirror_collect_vlans(struct mirror *m, const struct ovsrec_mirror *cfg,
     size_t n_vlans;
     size_t i;
 
-    *vlans = xmalloc(sizeof *vlans * cfg->n_select_vlan);
+    *vlans = xmalloc(sizeof **vlans * cfg->n_select_vlan);
     n_vlans = 0;
     for (i = 0; i < cfg->n_select_vlan; i++) {
         int64_t vlan = cfg->select_vlan[i];
@@ -3686,9 +3817,6 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
     size_t n_vlans;
     int *vlans;
     size_t i;
-    bool mirror_all_ports;
-    bool any_ports_specified;
-    bool any_vlans_specified;
 
     /* Get output port. */
     if (cfg->output_port) {
@@ -3716,30 +3844,25 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
         return;
     }
 
-    /* Get all the ports, and drop duplicates and ports that don't exist. */
     shash_init(&src_ports);
     shash_init(&dst_ports);
-    mirror_collect_ports(m, cfg->select_src_port, cfg->n_select_src_port,
-                         &src_ports);
-    mirror_collect_ports(m, cfg->select_dst_port, cfg->n_select_dst_port,
-                         &dst_ports);
-    any_ports_specified = cfg->n_select_dst_port || cfg->n_select_dst_port;
-    if (any_ports_specified
-        && shash_is_empty(&src_ports) && shash_is_empty(&dst_ports)) {
-        VLOG_ERR("bridge %s: disabling mirror %s since none of the specified "
-                 "selection ports exists", m->bridge->name, m->name);
-        mirror_destroy(m);
-        goto exit;
-    }
+    if (cfg->select_all) {
+        for (i = 0; i < m->bridge->n_ports; i++) {
+            const char *name = m->bridge->ports[i]->name;
+            shash_add_once(&src_ports, name, NULL);
+            shash_add_once(&dst_ports, name, NULL);
+        }
+        vlans = NULL;
+        n_vlans = 0;
+    } else {
+        /* Get ports, and drop duplicates and ports that don't exist. */
+        mirror_collect_ports(m, cfg->select_src_port, cfg->n_select_src_port,
+                             &src_ports);
+        mirror_collect_ports(m, cfg->select_dst_port, cfg->n_select_dst_port,
+                             &dst_ports);
 
-    /* Get all the vlans, and drop duplicate and invalid vlans. */
-    n_vlans = mirror_collect_vlans(m, cfg, &vlans);
-    any_vlans_specified = cfg->n_select_vlan > 0;
-    if (any_vlans_specified && !n_vlans) {
-        VLOG_ERR("bridge %s: disabling mirror %s since none of the specified "
-                 "VLANs exists", m->bridge->name, m->name);
-        mirror_destroy(m);
-        goto exit;
+        /* Get all the vlans, and drop duplicate and invalid vlans. */
+        n_vlans = mirror_collect_vlans(m, cfg, &vlans);
     }
 
     /* Update mirror data. */
@@ -3759,16 +3882,12 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
     m->out_port = out_port;
     m->out_vlan = out_vlan;
 
-    /* If no selection criteria have been given, mirror for all ports. */
-    mirror_all_ports = !any_ports_specified && !any_vlans_specified;
-
     /* Update ports. */
     mirror_bit = MIRROR_MASK_C(1) << m->idx;
     for (i = 0; i < m->bridge->n_ports; i++) {
         struct port *port = m->bridge->ports[i];
 
-        if (mirror_all_ports
-            || shash_find(&m->src_ports, port->name)
+        if (shash_find(&m->src_ports, port->name)
             || (m->n_vlans
                 && (!port->vlan
                     ? port_trunks_any_mirrored_vlan(m, port)
@@ -3778,7 +3897,7 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
             port->src_mirrors &= ~mirror_bit;
         }
 
-        if (mirror_all_ports || shash_find(&m->dst_ports, port->name)) {
+        if (shash_find(&m->dst_ports, port->name)) {
             port->dst_mirrors |= mirror_bit;
         } else {
             port->dst_mirrors &= ~mirror_bit;
@@ -3786,7 +3905,6 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
     }
 
     /* Clean up. */
-exit:
     shash_destroy(&src_ports);
     shash_destroy(&dst_ports);
 }