Merge "citrix" branch into "master.
[sliver-openvswitch.git] / vswitchd / bridge.c
index 48d02b3..ef390f7 100644 (file)
@@ -245,6 +245,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;
@@ -312,6 +314,7 @@ bridge_init(void)
             dpif_close(dpif);
         }
     }
+    svec_destroy(&dpif_names);
 
     unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
 
@@ -400,12 +403,23 @@ check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED)
 }
 
 static bool
-set_iface_policing(struct bridge *br UNUSED, struct iface *iface,
+set_iface_properties(struct bridge *br UNUSED, struct iface *iface,
                    void *aux UNUSED)
 {
-    int rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name);
-    int burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name);
+    int rate, burst;
+
+    /* Set policing attributes. */
+    rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name);
+    burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name);
     netdev_set_policing(iface->netdev, rate, burst);
+
+    /* Set MAC address of internal interfaces other than the local
+     * interface. */
+    if (iface->dp_ifidx != ODPP_LOCAL
+        && iface_is_internal(br, iface->name)) {
+        iface_set_mac(iface);
+    }
+
     return true;
 }
 
@@ -533,18 +547,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,
                                   internal ? ODP_PORT_INTERNAL : 0, NULL);
             if (error == EFBIG) {
@@ -620,6 +624,7 @@ bridge_reconfigure(void)
             VLOG_ERR("bridge %s: problem setting netflow collectors", 
                     br->name);
         }
+        svec_destroy(&nf_hosts);
 
         /* Update the controller and related settings.  It would be more
          * straightforward to call this from bridge_reconfigure_one(), but we
@@ -635,13 +640,14 @@ 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);
             port_update_bonding(port);
         }
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         brstp_reconfigure(br);
-        iterate_and_prune_ifaces(br, set_iface_policing, NULL);
+        iterate_and_prune_ifaces(br, set_iface_properties, NULL);
     }
 }
 
@@ -1589,6 +1595,7 @@ bond_enable_slave(struct iface *iface, bool enable)
         }
         iface->tag = tag_create_random();
     }
+    port_update_bond_compat(port);
 }
 
 static void
@@ -2413,10 +2420,7 @@ bond_send_learning_packets(struct port *port)
     ofpbuf_init(&packet, 128);
     error = n_packets = n_errors = 0;
     LIST_FOR_EACH (e, struct mac_entry, lru_node, &br->ml->lrus) {
-        static const char s[] = "Open vSwitch Bond Failover";
         union ofp_action actions[2], *a;
-        struct eth_header *eth;
-        struct llc_snap_header *llc_snap;
         uint16_t dp_ifidx;
         tag_type tags = 0;
         flow_t flow;
@@ -2427,23 +2431,6 @@ bond_send_learning_packets(struct port *port)
             continue;
         }
 
-        /* Compose packet to send. */
-        ofpbuf_clear(&packet);
-        eth = ofpbuf_put_zeros(&packet, ETH_HEADER_LEN);
-        llc_snap = ofpbuf_put_zeros(&packet, LLC_SNAP_HEADER_LEN);
-        ofpbuf_put(&packet, s, sizeof s); /* Includes null byte. */
-        ofpbuf_put(&packet, e->mac, ETH_ADDR_LEN);
-
-        memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN);
-        memcpy(eth->eth_src, e->mac, ETH_ADDR_LEN);
-        eth->eth_type = htons(packet.size - ETH_HEADER_LEN);
-
-        llc_snap->llc.llc_dsap = LLC_DSAP_SNAP;
-        llc_snap->llc.llc_ssap = LLC_SSAP_SNAP;
-        llc_snap->llc.llc_cntl = LLC_CNTL_SNAP;
-        memcpy(llc_snap->snap.snap_org, "\x00\x23\x20", 3);
-        llc_snap->snap.snap_type = htons(0xf177); /* Random number. */
-
         /* Compose actions. */
         memset(actions, 0, sizeof actions);
         a = actions;
@@ -2460,6 +2447,8 @@ bond_send_learning_packets(struct port *port)
 
         /* Send packet. */
         n_packets++;
+        compose_benign_packet(&packet, "Open vSwitch Bond Failover", 0xf177,
+                              e->mac);
         flow_extract(&packet, ODPP_NONE, &flow);
         retval = ofproto_send_packet(br->ofproto, &flow, actions, a - actions,
                                      &packet);
@@ -2750,6 +2739,25 @@ bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args)
     enable_slave(conn, args, false);
 }
 
+static void
+bond_unixctl_hash(struct unixctl_conn *conn, const char *args)
+{
+       uint8_t mac[ETH_ADDR_LEN];
+       uint8_t hash;
+       char *hash_cstr;
+
+       if (sscanf(args, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
+           == ETH_ADDR_SCAN_COUNT) {
+               hash = bond_hash(mac);
+
+               hash_cstr = xasprintf("%u", hash);
+               unixctl_command_reply(conn, 200, hash_cstr);
+               free(hash_cstr);
+       } else {
+               unixctl_command_reply(conn, 501, "invalid mac");
+       }
+}
+
 static void
 bond_init(void)
 {
@@ -2760,6 +2768,7 @@ bond_init(void)
                              bond_unixctl_set_active_slave);
     unixctl_command_register("bond/enable-slave", bond_unixctl_enable_slave);
     unixctl_command_register("bond/disable-slave", bond_unixctl_disable_slave);
+    unixctl_command_register("bond/hash", bond_unixctl_hash);
 }
 \f
 /* Port functions. */
@@ -3040,8 +3049,21 @@ 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));
+
+        /* We need to make the same determination as the Linux bonding
+         * code to determine whether a slave should be consider "up".
+         * The Linux function bond_miimon_inspect() supports four 
+         * BOND_LINK_* states:
+         *      
+         *    - BOND_LINK_UP: carrier detected, updelay has passed.
+         *    - BOND_LINK_FAIL: carrier lost, downdelay in progress.
+         *    - BOND_LINK_DOWN: carrier lost, downdelay has passed.
+         *    - BOND_LINK_BACK: carrier detected, updelay in progress.
+         *
+         * The function bond_info_show_slave() only considers BOND_LINK_UP 
+         * to be "up" and anything else to be "down".
+         */
+        slave->up = iface->enabled && iface->delay_expires == LLONG_MAX;
         if (slave->up) {
             bond.up = true;
         }
@@ -3171,6 +3193,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_set_etheraddr(iface->netdev, ea);
+            if (error) {
+                VLOG_ERR("interface %s: setting MAC failed (%s)",
+                         iface->name, strerror(error));
+            }
+        }
+    }
+}
 \f
 /* Port mirroring. */