bonding: Compare ports, not interfaces, for loop checks.
[sliver-openvswitch.git] / vswitchd / bridge.c
index b525f3d..4ad7e9b 100644 (file)
@@ -242,6 +242,8 @@ static void iface_destroy(struct iface *);
 static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_from_dp_ifidx(const struct bridge *,
                                          uint16_t dp_ifidx);
+static bool iface_is_internal(const struct bridge *, const char *name);
+static void iface_set_mac(struct iface *);
 
 /* Hooks into ofproto processing. */
 static struct ofhooks bridge_ofhooks;
@@ -464,18 +466,8 @@ bridge_reconfigure(void)
                 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. */
+                internal = iface_is_internal(br, if_name);
                 error = dpif_port_add(&br->dpif, if_name, next_port_no++,
                                       internal ? ODP_PORT_INTERNAL : 0);
                 if (error != EEXIST) {
@@ -594,7 +586,16 @@ bridge_reconfigure(void)
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         for (i = 0; i < br->n_ports; i++) {
             struct port *port = br->ports[i];
+
             port_update_vlan_compat(port);
+
+            for (j = 0; j < port->n_ifaces; j++) {
+                struct iface *iface = port->ifaces[j];
+                if (iface->dp_ifidx != ODPP_LOCAL
+                    && iface_is_internal(br, iface->name)) {
+                    iface_set_mac(iface);
+                }
+            }
         }
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
@@ -1720,8 +1721,7 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
                         if (dst_is_duplicate(dsts, dst - dsts, dst)) {
                             continue;
                         }
-                        if (dst->dp_ifidx == flow->in_port
-                            && dst->vlan == vlan) {
+                        if (port == in_port && dst->vlan == vlan) {
                             /* Don't send out input port on same VLAN. */
                             continue;
                         }
@@ -2982,6 +2982,19 @@ port_update_bond_compat(struct port *port)
         memcpy(slave->mac, iface->mac, ETH_ADDR_LEN);
     }
 
+    if (cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
+        struct netdev *bond_netdev;
+
+        if (!netdev_open(port->name, NETDEV_ETH_TYPE_NONE, &bond_netdev)) {
+            if (bond.up) {
+                netdev_turn_flags_on(bond_netdev, NETDEV_UP, true);
+            } else {
+                netdev_turn_flags_off(bond_netdev, NETDEV_UP, true);
+            }
+            netdev_close(bond_netdev);
+        }
+    }
+
     proc_net_compat_update_bond(port->name, &bond);
     free(bond.slaves);
 }
@@ -3116,6 +3129,60 @@ iface_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
 {
     return port_array_get(&br->ifaces, dp_ifidx);
 }
+
+/* Returns true if 'iface' is the name of an "internal" interface on bridge
+ * 'br', that is, an interface that is entirely simulated within the datapath.
+ * The local port (ODPP_LOCAL) is always an internal interface.  Other local
+ * interfaces are created by setting "iface.<iface>.internal = true".
+ *
+ * In addition, we have a kluge-y feature that creates an internal port with
+ * the name of a bonded port if "bonding.<bondname>.fake-iface = true" is set.
+ * This feature needs to go away in the long term.  Until then, this is one
+ * reason why this function takes a name instead of a struct iface: the fake
+ * interfaces created this way do not have a struct iface. */
+static bool
+iface_is_internal(const struct bridge *br, const char *iface)
+{
+    if (!strcmp(iface, br->name)
+        || cfg_get_bool(0, "iface.%s.internal", iface)) {
+        return true;
+    }
+
+    if (cfg_get_bool(0, "bonding.%s.fake-iface", iface)) {
+        struct port *port = port_lookup(br, iface);
+        if (port && port->n_ifaces > 1) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/* Set Ethernet address of 'iface', if one is specified in the configuration
+ * file. */
+static void
+iface_set_mac(struct iface *iface)
+{
+    uint64_t mac = cfg_get_mac(0, "iface.%s.mac", iface->name);
+    if (mac) {
+        static uint8_t ea[ETH_ADDR_LEN];
+
+        eth_addr_from_uint64(mac, ea);
+        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_nodev_set_etheraddr(iface->name, ea);
+            if (error) {
+                VLOG_ERR("interface %s: setting MAC failed (%s)",
+                         iface->name, strerror(error));
+            }
+        }
+    }
+}
 \f
 /* Port mirroring. */