Use __linux__ instead of LINUX_DATAPATH in C code.
[sliver-openvswitch.git] / vswitchd / bridge.c
index aa4ab31..0f7ca84 100644 (file)
@@ -251,7 +251,7 @@ static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_find(const char *name);
 static struct iface *iface_from_ofp_port(const struct bridge *,
                                          ofp_port_t ofp_port);
-static void iface_set_mac(struct iface *, const uint8_t *);
+static void iface_set_mac(const struct bridge *, const struct port *, struct iface *);
 static void iface_set_ofport(const struct ovsrec_interface *, ofp_port_t ofport);
 static void iface_clear_db_record(const struct ovsrec_interface *if_cfg);
 static void iface_configure_qos(struct iface *, const struct ovsrec_qos *);
@@ -574,7 +574,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                 iface_set_ofport(iface->cfg, iface->ofp_port);
                 iface_configure_cfm(iface);
                 iface_configure_qos(iface, port->cfg->qos);
-                iface_set_mac(iface, port->cfg->fake_bridge ? br->ea : NULL);
+                iface_set_mac(br, port, iface);
                 ofproto_port_set_bfd(br->ofproto, iface->ofp_port,
                                      &iface->cfg->bfd);
             }
@@ -1548,31 +1548,15 @@ bridge_configure_mac_table(struct bridge *br)
 }
 
 static void
-bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
-                          struct iface **hw_addr_iface)
+find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
+                   const struct port *fake_br, struct iface **hw_addr_iface)
 {
     struct hmapx mirror_output_ports;
-    const char *hwaddr;
     struct port *port;
     bool found_addr = false;
     int error;
     int i;
 
-    *hw_addr_iface = NULL;
-
-    /* Did the user request a particular MAC? */
-    hwaddr = smap_get(&br->cfg->other_config, "hwaddr");
-    if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
-        if (eth_addr_is_multicast(ea)) {
-            VLOG_ERR("bridge %s: cannot set MAC address to multicast "
-                     "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
-        } else if (eth_addr_is_zero(ea)) {
-            VLOG_ERR("bridge %s: cannot set MAC address to zero", br->name);
-        } else {
-            return;
-        }
-    }
-
     /* Mirror output ports don't participate in picking the local hardware
      * address.  ofproto can't help us find out whether a given port is a
      * mirror output because we haven't configured mirrors yet, so we need to
@@ -1628,6 +1612,16 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
                 continue;
             }
 
+            /* For fake bridges we only choose from ports with the same tag */
+            if (fake_br && fake_br->cfg && fake_br->cfg->tag) {
+                if (!port->cfg->tag) {
+                    continue;
+                }
+                if (*port->cfg->tag != *fake_br->cfg->tag) {
+                    continue;
+                }
+            }
+
             /* Grab MAC. */
             error = netdev_get_etheraddr(iface->netdev, iface_ea);
             if (error) {
@@ -1656,6 +1650,30 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     hmapx_destroy(&mirror_output_ports);
 }
 
+static void
+bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
+                          struct iface **hw_addr_iface)
+{
+    const char *hwaddr;
+    *hw_addr_iface = NULL;
+
+    /* Did the user request a particular MAC? */
+    hwaddr = smap_get(&br->cfg->other_config, "hwaddr");
+    if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
+        if (eth_addr_is_multicast(ea)) {
+            VLOG_ERR("bridge %s: cannot set MAC address to multicast "
+                     "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
+        } else if (eth_addr_is_zero(ea)) {
+            VLOG_ERR("bridge %s: cannot set MAC address to zero", br->name);
+        } else {
+            return;
+        }
+    }
+
+    /* Find a local hw address */
+    find_local_hw_addr(br, ea, NULL, hw_addr_iface);
+}
+
 /* Choose and returns the datapath ID for bridge 'br' given that the bridge
  * Ethernet address is 'bridge_ea'.  If 'bridge_ea' is the Ethernet address of
  * an interface on 'br', then that interface must be passed in as
@@ -3469,9 +3487,10 @@ iface_from_ofp_port(const struct bridge *br, ofp_port_t ofp_port)
 /* Set Ethernet address of 'iface', if one is specified in the configuration
  * file. */
 static void
-iface_set_mac(struct iface *iface, const uint8_t *mac)
+iface_set_mac(const struct bridge *br, const struct port *port, struct iface *iface)
 {
-    uint8_t ea[ETH_ADDR_LEN];
+    uint8_t ea[ETH_ADDR_LEN], *mac = NULL;
+    struct iface *hw_addr_iface;
 
     if (strcmp(iface->type, "internal")) {
         return;
@@ -3479,6 +3498,10 @@ iface_set_mac(struct iface *iface, const uint8_t *mac)
 
     if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
         mac = ea;
+    } else if (port->cfg->fake_bridge) {
+        /* Fake bridge and no MAC set in the configuration. Pick a local one. */
+        find_local_hw_addr(br, ea, port, &hw_addr_iface);
+        mac = ea;
     }
 
     if (mac) {