xenserver: Honor the MAC address specified in xapi database for bonds.
authorBen Pfaff <blp@nicira.com>
Wed, 22 Jul 2009 19:21:25 +0000 (12:21 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 29 Jul 2009 18:20:43 +0000 (11:20 -0700)
The xapi database for PIFs specifies the MAC address that should be used
for bonds, but interface-reconfigure didn't honor it and ovs-vswitchd
didn't have a way to configure it anyhow.  This commit fixes both problems.

Bug #1645.

vswitchd/bridge.c
vswitchd/ovs-vswitchd.conf.5.in
xenserver/opt_xensource_libexec_interface-reconfigure

index 6a82a03..10bd244 100644 (file)
@@ -613,31 +613,63 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     memset(ea, 0xff, sizeof ea);
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
+        uint8_t iface_ea[ETH_ADDR_LEN];
+        uint64_t iface_ea_u64;
+        struct iface *iface;
+
+        /* Mirror output ports don't participate. */
         if (port->is_mirror_output_port) {
             continue;
         }
-        for (j = 0; j < port->n_ifaces; j++) {
-            struct iface *iface = port->ifaces[j];
-            uint8_t iface_ea[ETH_ADDR_LEN];
+
+        /* Choose the MAC address to represent the port. */
+        iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name);
+        if (iface_ea_u64) {
+            /* User specified explicitly. */
+            eth_addr_from_uint64(iface_ea_u64, iface_ea);
+        } else {
+            /* Choose the interface whose MAC address will represent the port.
+             * The Linux kernel bonding code always chooses the MAC address of
+             * the first slave added to a bond, and the Fedora networking
+             * scripts always add slaves to a bond in alphabetical order, so
+             * for compatibility we choose the interface with the name that is
+             * first in alphabetical order. */
+            iface = port->ifaces[0];
+            for (j = 1; j < port->n_ifaces; j++) {
+                struct iface *candidate = port->ifaces[j];
+                if (strcmp(candidate->name, iface->name) < 0) {
+                    iface = candidate;
+                }
+            }
+
+            /* The local port doesn't count (since we're trying to choose its
+             * MAC address anyway).  Other internal ports don't count because
+             * we really want a physical MAC if we can get it, and internal
+             * ports typically have randomly generated MACs. */
             if (iface->dp_ifidx == ODPP_LOCAL
                 || cfg_get_bool(0, "iface.%s.internal", iface->name)) {
                 continue;
             }
+
+            /* Grab MAC. */
             error = netdev_nodev_get_etheraddr(iface->name, iface_ea);
-            if (!error) {
-                if (!eth_addr_is_multicast(iface_ea) &&
-                    !eth_addr_is_reserved(iface_ea) &&
-                    !eth_addr_is_zero(iface_ea) &&
-                    memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0) {
-                    memcpy(ea, iface_ea, ETH_ADDR_LEN);
-                    *devname = iface->name;
-                }
-            } else {
+            if (error) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
                             iface->name, strerror(error));
+                continue;
             }
         }
+
+        /* Compare against our current choice. */
+        if (!eth_addr_is_multicast(iface_ea) &&
+            !eth_addr_is_reserved(iface_ea) &&
+            !eth_addr_is_zero(iface_ea) &&
+            memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
+        {
+            memcpy(ea, iface_ea, ETH_ADDR_LEN);
+            *devname = iface->name;
+        }
     }
     if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
         memcpy(ea, br->default_ea, ETH_ADDR_LEN);
index 25332db..bd0ffb7 100644 (file)
@@ -72,11 +72,23 @@ in the bridge, by specifying it as one of the values for key
 included, then its MAC address is by default the lowest-numbered MAC
 address among the other bridge ports, ignoring other internal ports
 and bridge ports that are
-used as port mirroring destinations (see \fBPort Mirroring\fR, below).  To
-use a specific MAC address instead, set \fBbridge.\fIname\fB.mac\fR to
-a MAC address in the format
+used as port mirroring destinations (see \fBPort Mirroring\fR, below).
+For this purpose, the MAC of a bonded port (see \fBNetwork Device
+Bonding\fR, below) is by default the MAC of its slave whose name is first in
+alphabetical order.
+There are two ways to modify this algorithm for selecting the MAC
+address of the local port:
+.IP \(bu
+To use a specific MAC address for the local port, set
+\fBbridge.\fIname\fB.mac\fR to a MAC address in the format
 \fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR, where each
-\fIx\fR is a hex digit.  If no valid MAC address can be determined
+\fIx\fR is a hex digit.
+.IP \(bu
+To override the MAC of a port for the purpose of this algorithm, set
+\fBport.\fIport\fB.mac\fR to a MAC address in the format described
+above.
+.PP
+If no valid MAC address can be determined
 either of these ways, then a MAC address is randomly generated.
 .PP
 The following syntax defines a bridge named \fBmybr\fR, configured
index 2a32fad..1ff5359 100755 (executable)
@@ -750,6 +750,9 @@ def configure_bond(pif):
     argv += ["--add=bonding.%s.slave=%s" % (interface, slave)
              for slave in physdevs]
 
+    if pifrec['MAC'] != "":
+        argv += ['--add=port.%s.mac=%s' % (interface, pifrec['MAC'])]
+
     # Bonding options.
     bond_options = { 
         "mode":   "balance-slb",