xenserver: Make primary management interface on VLAN possible.
authorBen Pfaff <blp@nicira.com>
Mon, 18 May 2009 19:23:03 +0000 (12:23 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 18 May 2009 19:25:18 +0000 (12:25 -0700)
Before xapi puts the primary management interface on a new PIF, it verifies
that the PIF's network device exists and has an IP address.  For physical
PIFs and for bonds, this works fine.  For VLANs, the openvswitch does not
put the IP address on the network device that xapi expects, but on a
different network device (e.g. openvswitch puts it on eth0.X instead of on
xapiY), so this checks fails with the message "The specified interface
cannot be used because it has no IP address".

This commit makes interface-reconfigure "fake out" xapi by putting a
dummy IP address on the xapi# interface.

Bug #1325.

xenserver/opt_xensource_libexec_interface-reconfigure

index 427491ab957cf8690dfcb837961f3554634648b9..933f074d1e216126086ec0b6841efa8e95b94671 100755 (executable)
@@ -429,6 +429,36 @@ For a VLAN PIF, the ipdev name is the interface name.
     else:
         return interface_name(pif)
 
+def fakevlanbridge_name(pif):
+    """Return the name of the network device that xapi *thinks* carries the
+IP configuration associatied with pif, if this is different from the actual
+network device for pif (as returned by ipdev_name).
+Otherwise, returns None.
+
+This is important because xapi will refuse to put the primary management
+interface on a network device that does not have an IP address.  For ordinary
+network devices and bonds, this is no problem for us, since the device we
+want to use for the IP address is the same as what xapi expects.  But for
+VLANs, xapi expects us to put the IP address on the xapi# device, which is
+a bridge device (datapath local port device, actually), but we can't do that
+because it would have to be added to the xenbr# or xapi# bridge that
+represents the vlan slave, and a bridge port device can only be a member of
+a single bridge.
+
+So, in the latter case, we have to fake out xapi somehow.  We choose to do
+so by configuring a dummy 127.x.y.z address on the xapi# device that xapi
+expects.  xapi only cares that the interface has an address, not that the
+address is correct, so this is sufficient.
+"""
+
+    pifrec = db.get_pif_record(pif)
+
+    if pifrec['VLAN'] == '-1':
+        return None
+    else:
+        return bridge_name(pif)
+    
+
 def physdev_names(pif):
     """Return the name(s) of the physical network device(s) associated with pif.
 For a VLAN PIF, the physical devices are the VLAN slave's physical devices.
@@ -782,6 +812,10 @@ def configure_bond(pif):
         argv += ["--add=bonding.%s.%s=%s" % (interface, name, val)]
     return argv
 
+def get_ifindex(netdev):
+    """Return the ifindex of the given 'netdev'."""
+    return int(open("/sys/class/net/%s/ifindex" % netdev).readline())
+
 def action_up(pif):
     pifrec = db.get_pif_record(pif)
 
@@ -789,6 +823,7 @@ def action_up(pif):
     ipdev = ipdev_name(pif)
     datapath = datapath_name(pif)
     physdevs = physdev_names(pif)
+    fakevlanbridge = fakevlanbridge_name(pif)
     vlan_slave = None
     if pifrec['VLAN'] != '-1':
         vlan_slave = get_vlan_slave_of_pif(pif)
@@ -801,10 +836,9 @@ def action_up(pif):
 
     # "ifconfig down" the network device and delete its IP address, etc.
     down_netdev(ipdev)
-    #if datapath != ipdev:
-    #    down_netdev(datapath)
     if vlan_slave:
         down_netdev(ipdev_name(vlan_slave), False)
+        down_netdev(fakevlanbridge)
     for physdev in physdevs:
         down_netdev(physdev)
 
@@ -824,7 +858,7 @@ def action_up(pif):
     else:
         add_ports += [interface_name(bond_master)]
 
-    # What ports do we need to delete first?
+    # What ports do we need to delete?
     #
     #  - All the ports that we add, to avoid duplication and to drop
     #    them from another datapath in case they're misassigned.
@@ -856,6 +890,17 @@ def action_up(pif):
     # Bring up VLAN slave and bond slaves.
     if vlan_slave:
         up_netdev(ipdev_name(vlan_slave))
+
+        # Set up an IP address on the fake VLAN bridge.  See the
+        # comments on fakevlanbridge_name for details.
+        up_netdev(fakevlanbridge)
+        fakevlan_ifindex = get_ifindex(fakevlanbridge)
+        fakevlan_ifindex_octets = ((fakevlan_ifindex >> 16) & 0xff,
+                                   (fakevlan_ifindex >> 8) & 0xff,
+                                   fakevlan_ifindex & 0xff)
+        run_command(['/sbin/ifconfig', fakevlanbridge,
+                     '127.%d.%d.%d' % fakevlan_ifindex_octets,
+                     'netmask', '255.255.255.255'])
     for physdev in physdevs:
         up_netdev(physdev)
 
@@ -867,11 +912,13 @@ def action_down(pif):
     interface = interface_name(pif)
     bridge = bridge_name(pif)
     ipdev = ipdev_name(pif)
+    fakevlanbridge = fakevlanbridge_name(pif)
 
     argv = []
     if rec['VLAN'] != '-1':
         # Get rid of the VLAN device itself.
         down_netdev(ipdev)
+        down_netdev(fakevlanbridge)
         argv += interface_deconfigure_commands(ipdev)
 
         # If the VLAN's slave is attached, stop here.