vswitch: Correctly identify slave status in /proc compatibility layer
[openvswitch] / vswitchd / bridge.c
index 0d2ca89aaa51f51f83259174482e3a45c88ad14f..c39670a3b2a0d90f01a470e26cf8fa40479a9fd4 100644 (file)
@@ -461,9 +461,23 @@ bridge_reconfigure(void)
         for (i = 0; i < add_ifaces.n; i++) {
             const char *if_name = add_ifaces.names[i];
             for (;;) {
-                int internal = cfg_get_bool(0, "iface.%s.internal", if_name);
-                int error = dpif_port_add(&br->dpif, if_name, next_port_no++,
-                                          internal ? ODP_PORT_INTERNAL : 0);
+                bool internal;
+                int error;
+
+                /* It's an internal interface if it's marked that way, or if
+                 * it's a bonded interface for which we're faking up a network
+                 * device. */
+                internal = cfg_get_bool(0, "iface.%s.internal", if_name);
+                if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
+                    struct port *port = port_lookup(br, if_name);
+                    if (port && port->n_ifaces > 1) {
+                        internal = true;
+                    }
+                }
+
+                /* Add to datapath. */
+                error = dpif_port_add(&br->dpif, if_name, next_port_no++,
+                                      internal ? ODP_PORT_INTERNAL : 0);
                 if (error != EEXIST) {
                     if (next_port_no >= 256) {
                         VLOG_ERR("ran out of valid port numbers on dp%u",
@@ -631,6 +645,18 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
         if (iface_ea_u64) {
             /* User specified explicitly. */
             eth_addr_from_uint64(iface_ea_u64, iface_ea);
+
+            /* Find the interface with this Ethernet address (if any) so that
+             * we can provide the correct devname to the caller. */
+            iface = NULL;
+            for (j = 0; j < port->n_ifaces; j++) {
+                struct iface *candidate = port->ifaces[j];
+                uint8_t candidate_ea[ETH_ADDR_LEN];
+                if (!netdev_nodev_get_etheraddr(candidate->name, candidate_ea)
+                    && eth_addr_equals(iface_ea, candidate_ea)) {
+                    iface = candidate;
+                }
+            }
         } else {
             /* Choose the interface whose MAC address will represent the port.
              * The Linux kernel bonding code always chooses the MAC address of
@@ -672,7 +698,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
             memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
         {
             memcpy(ea, iface_ea, ETH_ADDR_LEN);
-            *devname = iface->name;
+            *devname = iface ? iface->name : NULL;
         }
     }
     if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
@@ -1309,9 +1335,12 @@ bridge_get_all_ifaces(const struct bridge *br, struct svec *ifaces)
             struct iface *iface = port->ifaces[j];
             svec_add(ifaces, iface->name);
         }
+        if (port->n_ifaces > 1
+            && cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
+            svec_add(ifaces, port->name);
+        }
     }
-    svec_sort(ifaces);
-    assert(svec_is_unique(ifaces));
+    svec_sort_unique(ifaces);
 }
 
 /* For robustness, in case the administrator moves around datapath ports behind
@@ -1496,6 +1525,7 @@ bond_enable_slave(struct iface *iface, bool enable)
         }
         iface->tag = tag_create_random();
     }
+    port_update_bond_compat(port);
 }
 
 static void
@@ -1681,12 +1711,14 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
                 for (i = 0; i < br->n_ports; i++) {
                     struct port *port = br->ports[i];
                     if (port_includes_vlan(port, m->out_vlan)
-                        && set_dst(dst, flow, in_port, port, tags)
-                        && !dst_is_duplicate(dsts, dst - dsts, dst))
+                        && set_dst(dst, flow, in_port, port, tags))
                     {
                         if (port->vlan < 0) {
                             dst->vlan = m->out_vlan;
                         }
+                        if (dst_is_duplicate(dsts, dst - dsts, dst)) {
+                            continue;
+                        }
                         if (dst->dp_ifidx == flow->in_port
                             && dst->vlan == vlan) {
                             /* Don't send out input port on same VLAN. */
@@ -1860,7 +1892,7 @@ process_flow(struct bridge *br, const flow_t *flow,
             goto done;
         } else {
             /* Drop all multicast packets for which we have learned a different
-             * input port, because we probably sent the packet on one slaves
+             * input port, because we probably sent the packet on one slave
              * and got it back on the active slave.  Broadcast ARP replies are
              * an exception to this rule: the host has moved to another
              * switch. */
@@ -2946,8 +2978,7 @@ port_update_bond_compat(struct port *port)
         struct iface *iface = port->ifaces[i];
         struct compat_bond_slave *slave = &bond.slaves[i];
         slave->name = iface->name;
-        slave->up = ((iface->enabled && iface->delay_expires == LLONG_MAX) ||
-                     (!iface->enabled && iface->delay_expires != LLONG_MAX));
+        slave->up = iface->enabled;
         if (slave->up) {
             bond.up = true;
         }
@@ -3288,6 +3319,7 @@ mirror_reconfigure_one(struct mirror *m)
     int *vlans;
     size_t i;
     bool mirror_all_ports;
+    bool any_ports_specified;
 
     /* Get output port. */
     out_port_name = cfg_get_key(0, "mirror.%s.%s.output.port",
@@ -3326,11 +3358,18 @@ mirror_reconfigure_one(struct mirror *m)
     cfg_get_all_keys(&src_ports, "%s.select.src-port", pfx);
     cfg_get_all_keys(&dst_ports, "%s.select.dst-port", pfx);
     cfg_get_all_keys(&ports, "%s.select.port", pfx);
+    any_ports_specified = src_ports.n || dst_ports.n || ports.n;
     svec_append(&src_ports, &ports);
     svec_append(&dst_ports, &ports);
     svec_destroy(&ports);
     prune_ports(m, &src_ports);
     prune_ports(m, &dst_ports);
+    if (any_ports_specified && !src_ports.n && !dst_ports.n) {
+        VLOG_ERR("%s: none of the specified ports exist; "
+                 "disabling port mirror %s", pfx, pfx);
+        mirror_destroy(m);
+        goto exit;
+    }
 
     /* Get all the vlans, and drop duplicate and invalid vlans. */
     svec_init(&vlan_strings);
@@ -3382,6 +3421,7 @@ mirror_reconfigure_one(struct mirror *m)
     }
 
     /* Clean up. */
+exit:
     svec_destroy(&src_ports);
     svec_destroy(&dst_ports);
     free(pfx);