bridge: Avoid memory leak from RSPAN mirrors in bridge_destroy().
[sliver-openvswitch.git] / vswitchd / bridge.c
index 951ce74..4be0d1e 100644 (file)
@@ -335,16 +335,54 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
     ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics);
     ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_external_ids);
+    ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_ovs_version);
+    ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_db_version);
+    ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_system_type);
+    ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_system_version);
 
+    ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_id);
     ovsdb_idl_omit(idl, &ovsrec_bridge_col_external_ids);
 
     ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
     ovsdb_idl_omit(idl, &ovsrec_port_col_fake_bridge);
 
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_admin_state);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_duplex);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_speed);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_state);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mtu);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_ofport);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_statistics);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_status);
     ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
 
+    ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_is_connected);
+    ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_role);
+    ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_status);
+    ovsdb_idl_omit(idl, &ovsrec_controller_col_external_ids);
+
+    ovsdb_idl_omit_alert(idl, &ovsrec_maintenance_point_col_fault);
+
+    ovsdb_idl_omit_alert(idl, &ovsrec_monitor_col_fault);
+
+    ovsdb_idl_omit(idl, &ovsrec_qos_col_external_ids);
+
+    ovsdb_idl_omit(idl, &ovsrec_queue_col_external_ids);
+
+    ovsdb_idl_omit(idl, &ovsrec_mirror_col_external_ids);
+
+    ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
+
+    ovsdb_idl_omit(idl, &ovsrec_sflow_col_external_ids);
+
+    ovsdb_idl_omit(idl, &ovsrec_manager_col_external_ids);
+    ovsdb_idl_omit(idl, &ovsrec_manager_col_inactivity_probe);
+    ovsdb_idl_omit(idl, &ovsrec_manager_col_is_connected);
+    ovsdb_idl_omit(idl, &ovsrec_manager_col_max_backoff);
+    ovsdb_idl_omit(idl, &ovsrec_manager_col_status);
+
+    ovsdb_idl_omit(idl, &ovsrec_ssl_col_external_ids);
+
     /* Register unixctl commands. */
     unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
     unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
@@ -374,8 +412,9 @@ static void
 bridge_configure_once(const struct ovsrec_open_vswitch *cfg)
 {
     static bool already_configured_once;
-    struct svec bridge_names;
-    struct svec dpif_names, dpif_types;
+    struct sset bridge_names;
+    struct sset dpif_names, dpif_types;
+    const char *type;
     size_t i;
 
     /* Only do this once per ovs-vswitchd run. */
@@ -387,30 +426,28 @@ bridge_configure_once(const struct ovsrec_open_vswitch *cfg)
     stats_timer = time_msec() + STATS_INTERVAL;
 
     /* Get all the configured bridges' names from 'cfg' into 'bridge_names'. */
-    svec_init(&bridge_names);
+    sset_init(&bridge_names);
     for (i = 0; i < cfg->n_bridges; i++) {
-        svec_add(&bridge_names, cfg->bridges[i]->name);
+        sset_add(&bridge_names, cfg->bridges[i]->name);
     }
-    svec_sort(&bridge_names);
 
     /* Iterate over all system dpifs and delete any of them that do not appear
      * in 'cfg'. */
-    svec_init(&dpif_names);
-    svec_init(&dpif_types);
+    sset_init(&dpif_names);
+    sset_init(&dpif_types);
     dp_enumerate_types(&dpif_types);
-    for (i = 0; i < dpif_types.n; i++) {
-        size_t j;
+    SSET_FOR_EACH (type, &dpif_types) {
+        const char *name;
 
-        dp_enumerate_names(dpif_types.names[i], &dpif_names);
+        dp_enumerate_names(type, &dpif_names);
 
         /* Delete each dpif whose name is not in 'bridge_names'. */
-        for (j = 0; j < dpif_names.n; j++) {
-            if (!svec_contains(&bridge_names, dpif_names.names[j])) {
+        SSET_FOR_EACH (name, &dpif_names) {
+            if (!sset_contains(&bridge_names, name)) {
                 struct dpif *dpif;
                 int retval;
 
-                retval = dpif_open(dpif_names.names[j], dpif_types.names[i],
-                                   &dpif);
+                retval = dpif_open(name, type, &dpif);
                 if (!retval) {
                     dpif_delete(dpif);
                     dpif_close(dpif);
@@ -418,9 +455,9 @@ bridge_configure_once(const struct ovsrec_open_vswitch *cfg)
             }
         }
     }
-    svec_destroy(&bridge_names);
-    svec_destroy(&dpif_names);
-    svec_destroy(&dpif_types);
+    sset_destroy(&bridge_names);
+    sset_destroy(&dpif_names);
+    sset_destroy(&dpif_types);
 }
 
 /* Callback for iterate_and_prune_ifaces(). */
@@ -455,9 +492,7 @@ set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface,
 
     /* Set MAC address of internal interfaces other than the local
      * interface. */
-    if (iface->dp_ifidx != ODPP_LOCAL && !strcmp(iface->type, "internal")) {
-        iface_set_mac(iface);
-    }
+    iface_set_mac(iface);
 
     return true;
 }
@@ -820,12 +855,14 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                 }
             }
 
-            opts.collectors.n = nf_cfg->n_targets;
-            opts.collectors.names = nf_cfg->targets;
+            sset_init(&opts.collectors);
+            sset_add_array(&opts.collectors,
+                           nf_cfg->targets, nf_cfg->n_targets);
             if (ofproto_set_netflow(br->ofproto, &opts)) {
                 VLOG_ERR("bridge %s: problem setting netflow collectors",
                          br->name);
             }
+            sset_destroy(&opts.collectors);
         } else {
             ofproto_set_netflow(br->ofproto, NULL);
         }
@@ -839,8 +876,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
             memset(&oso, 0, sizeof oso);
 
-            oso.targets.n = sflow_cfg->n_targets;
-            oso.targets.names = sflow_cfg->targets;
+            sset_init(&oso.targets);
+            sset_add_array(&oso.targets,
+                           sflow_cfg->targets, sflow_cfg->n_targets);
 
             oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
             if (sflow_cfg->sampling) {
@@ -870,7 +908,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
             }
             ofproto_set_sflow(br->ofproto, &oso);
 
-            /* Do not destroy oso.targets because it is owned by sflow_cfg. */
+            sset_destroy(&oso.targets);
         } else {
             ofproto_set_sflow(br->ofproto, NULL);
         }
@@ -912,8 +950,13 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         iterate_and_prune_ifaces(br, set_iface_properties, NULL);
     }
 
+    /* Some reconfiguration operations require the bridge to have been run at
+     * least once.  */
     LIST_FOR_EACH (br, node, &all_bridges) {
         struct iface *iface;
+
+        bridge_run_one(br);
+
         HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) {
             iface_update_cfm(iface);
         }
@@ -1685,10 +1728,14 @@ bridge_destroy(struct bridge *br)
     if (br) {
         struct port *port, *next;
         int error;
+        int i;
 
         HMAP_FOR_EACH_SAFE (port, next, hmap_node, &br->ports) {
             port_destroy(port);
         }
+        for (i = 0; i < MAX_MIRRORS; i++) {
+            mirror_destroy(br->mirrors[i]);
+        }
         list_remove(&br->node);
         ofproto_destroy(br->ofproto);
         error = dpif_delete(br->dpif);
@@ -1812,7 +1859,6 @@ static void
 bridge_reconfigure_one(struct bridge *br)
 {
     enum ofproto_fail_mode fail_mode;
-    struct svec snoops, old_snoops;
     struct port *port, *next;
     struct shash_node *node;
     struct shash new_ports;
@@ -1892,16 +1938,15 @@ bridge_reconfigure_one(struct bridge *br)
      * controller to another?) */
 
     /* Configure OpenFlow controller connection snooping. */
-    svec_init(&snoops);
-    svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
-                                       ovs_rundir(), br->name));
-    svec_init(&old_snoops);
-    ofproto_get_snoops(br->ofproto, &old_snoops);
-    if (!svec_equal(&snoops, &old_snoops)) {
+    if (!ofproto_has_snoops(br->ofproto)) {
+        struct sset snoops;
+
+        sset_init(&snoops);
+        sset_add_and_free(&snoops, xasprintf("punix:%s/%s.snoop",
+                                             ovs_rundir(), br->name));
         ofproto_set_snoops(br->ofproto, &snoops);
+        sset_destroy(&snoops);
     }
-    svec_destroy(&snoops);
-    svec_destroy(&old_snoops);
 
     mirror_reconfigure(br);
 }
@@ -4448,13 +4493,15 @@ iface_set_mac(struct iface *iface)
 {
     uint8_t ea[ETH_ADDR_LEN];
 
-    if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
-        if (eth_addr_is_multicast(ea)) {
+    if (!strcmp(iface->type, "internal")
+        && iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
+        if (iface->dp_ifidx == ODPP_LOCAL) {
+            VLOG_ERR("interface %s: ignoring mac in Interface record "
+                     "(use Bridge record to set local port's mac)",
+                     iface->name);
+        } else if (eth_addr_is_multicast(ea)) {
             VLOG_ERR("interface %s: cannot set MAC to multicast address",
                      iface->name);
-        } else if (iface->dp_ifidx == ODPP_LOCAL) {
-            VLOG_ERR("ignoring iface.%s.mac; use bridge.%s.mac instead",
-                     iface->name, iface->name);
         } else {
             int error = netdev_set_etheraddr(iface->netdev, ea);
             if (error) {
@@ -4750,6 +4797,7 @@ mirror_create(struct bridge *br, struct ovsrec_mirror *cfg)
     mac_learning_flush(br->ml);
 
     br->mirrors[i] = m = xzalloc(sizeof *m);
+    m->uuid = cfg->header_.uuid;
     m->bridge = br;
     m->idx = i;
     m->name = xstrdup(cfg->name);
@@ -4839,19 +4887,6 @@ vlan_is_mirrored(const struct mirror *m, int vlan)
     return false;
 }
 
-static bool
-port_trunks_any_mirrored_vlan(const struct mirror *m, const struct port *p)
-{
-    size_t i;
-
-    for (i = 0; i < m->n_vlans; i++) {
-        if (port_trunks_vlan(p, m->vlans[i])) {
-            return true;
-        }
-    }
-    return false;
-}
-
 static void
 mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
 {
@@ -4936,11 +4971,7 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
     /* Update ports. */
     mirror_bit = MIRROR_MASK_C(1) << m->idx;
     HMAP_FOR_EACH (port, hmap_node, &m->bridge->ports) {
-        if (sset_contains(&m->src_ports, port->name)
-            || (m->n_vlans
-                && (!port->vlan
-                    ? port_trunks_any_mirrored_vlan(m, port)
-                    : vlan_is_mirrored(m, port->vlan)))) {
+        if (sset_contains(&m->src_ports, port->name)) {
             port->src_mirrors |= mirror_bit;
         } else {
             port->src_mirrors &= ~mirror_bit;