xenserver: Fix bringing up VLAN PIFs.
[cascardo/ovs.git] / xenserver / opt_xensource_libexec_InterfaceReconfigureVswitch.py
index c083859..fd66d37 100644 (file)
@@ -1,5 +1,5 @@
 # Copyright (c) 2008,2009 Citrix Systems, Inc.
-# Copyright (c) 2009 Nicira Networks.
+# Copyright (c) 2009,2010 Nicira Networks.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published
@@ -36,27 +36,6 @@ def netdev_up(netdev, mtu=None):
 
     run_command(["/sbin/ifconfig", netdev, 'up'] + mtu)
 
-#
-# Bridges
-#
-
-def pif_bridge_name(pif):
-    """Return the bridge name of a pif.
-
-    PIF must not be a VLAN and must be a bridged PIF."""
-
-    pifrec = db().get_pif_record(pif)
-
-    if pif_is_vlan(pif):
-        raise Error("PIF %(uuid)s cannot be a bridge, VLAN is %(VLAN)s" % pifrec)
-
-    nwrec = db().get_network_record(pifrec['network'])
-
-    if nwrec['bridge']:
-        return nwrec['bridge']
-    else:
-        raise Error("PIF %(uuid)s does not have a bridge name" % pifrec)
-
 #
 # PIF miscellanea
 #
@@ -89,8 +68,9 @@ def pif_currently_in_use(pif):
 
 def pif_datapath(pif):
     """Return the datapath PIF associated with PIF.
-For a non-VLAN PIF, the datapath name is the bridge name.
-For a VLAN PIF, the datapath name is the bridge name for the PIF's VLAN slave.
+A non-VLAN PIF is its own datapath PIF, except that a bridgeless PIF has
+no datapath PIF at all.
+A VLAN PIF's datapath PIF is its VLAN slave's datapath PIF.
 """
     if pif_is_vlan(pif):
         return pif_datapath(pif_get_vlan_slave(pif))
@@ -118,11 +98,11 @@ A VLAN PIF cannot be a datapath PIF.
         return [pif]
 
 def datapath_deconfigure_physical(netdev):
-    return ['--', '--if-exists', 'del-port', netdev]
+    return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
 
 def datapath_configure_bond(pif,slaves):
     bridge = pif_bridge_name(pif)
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
     interface = pif_netdev_name(pif)
 
     argv = ['--', '--fake-iface', 'add-bond', bridge, interface]
@@ -155,16 +135,15 @@ def datapath_configure_bond(pif,slaves):
     return argv
 
 def datapath_deconfigure_bond(netdev):
-    return ['--', '--if-exists', 'del-port', netdev]
+    return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
 
 def datapath_deconfigure_ipdev(interface):
-    return ['--', '--if-exists', 'del-port', interface]
+    return ['--', '--with-iface', '--if-exists', 'del-port', interface]
 
 def datapath_modify_config(commands):
-    if debug_mode():
-        log("modifying configuration:")
-        for c in commands:
-            log("  %s" % c)
+    #log("modifying configuration:")
+    #for c in commands:
+    #    log("  %s" % c)
             
     rc = run_command(['/usr/bin/ovs-vsctl'] + ['--timeout=20']
                      + [c for c in commands if not c.startswith('#')])
@@ -177,11 +156,11 @@ def datapath_modify_config(commands):
 #
 
 def configure_datapath(pif):
-    """Bring up the datapath configuration for PIF.
-
-    Should be careful not to glitch existing users of the datapath, e.g. other VLANs etc.
-
-    Should take care of tearing down other PIFs which encompass common physical devices.
+    """Bring up the configuration for 'pif', which must not be a VLAN PIF, by:
+    - Tearing down other PIFs that use the same physical devices as 'pif'.
+    - Ensuring that 'pif' itself is set up.
+    - *Not* tearing down any PIFs that are stacked on top of 'pif' (i.e. VLANs
+      on top of 'pif'.
 
     Returns a tuple containing
     - A list containing the necessary vsctl command line arguments
@@ -265,16 +244,18 @@ def configure_datapath(pif):
         vsctl_argv += ['# deconfigure physical port %s' % dev]
         vsctl_argv += datapath_deconfigure_physical(dev)
 
+    vsctl_argv += ['--', '--may-exist', 'add-br', bridge]
+
     if len(physical_devices) > 1:
         vsctl_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
         vsctl_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
         vsctl_argv += ['# configure bond %s' % pif_netdev_name(pif)]
         vsctl_argv += datapath_configure_bond(pif, physical_devices)
         extra_up_ports += [pif_netdev_name(pif)]
-     else:
+    else:
         iface = pif_netdev_name(physical_devices[0])
         vsctl_argv += ['# add physical device %s' % iface]
-        vsctl_argv += ['--', 'add-port', bridge, iface]
+        vsctl_argv += ['--', '--may-exist', 'add-port', bridge, iface]
 
     return vsctl_argv,extra_up_ports
 
@@ -326,19 +307,23 @@ class DatapathVswitch(Datapath):
         extra_ports = []
 
         pifrec = db().get_pif_record(self._pif)
+        dprec = db().get_pif_record(self._dp)
 
         ipdev = self._ipdev
-        bridge = pif_bridge_name(self._dp)
         c,e = configure_datapath(self._dp)
+        bridge = pif_bridge_name(self._pif)
         vsctl_argv += c
         extra_ports += e
 
-        if pif_is_vlan(pif):
-            datapath = pif_datapath(pif)
-            vsctl_argv += ['--', 'add-br', bridge, datapath, pifrec['VLAN']]
-        else:
-            vsctl_argv += ['--', 'add-br', bridge]
-
+        if pif_is_vlan(self._pif):
+            # XXX this is only needed on XS5.5, because XAPI misguidedly
+            # creates the fake bridge (via bridge ioctl) before it calls us.
+            vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
+
+            # configure_datapath() set up the underlying datapath bridge.
+            # Stack a VLAN bridge on top of it.
+            vsctl_argv += ['--', '--may-exist', 'add-br',
+                           bridge, pif_bridge_name(self._dp), pifrec['VLAN']]
         xs_network_uuids = []
         for nwpif in db().get_pifs_by_device(db().get_pif_record(self._pif)['device']):
             rec = db().get_pif_record(nwpif)
@@ -356,16 +341,17 @@ class DatapathVswitch(Datapath):
         vsctl_argv += ['--', 'br-set-external-id', bridge,
                 'xs-network-uuids', ';'.join(xs_network_uuids)]
 
-        vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
-        vsctl_argv += datapath_deconfigure_ipdev(ipdev)
-        vsctl_argv += ["# reconfigure ipdev %s" % ipdev]
-        vsctl_argv += ['--', 'add-port', bridge, ipdev]
+        if ipdev != bridge:
+            vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
+            vsctl_argv += datapath_deconfigure_ipdev(ipdev)
+            vsctl_argv += ["# reconfigure ipdev %s" % ipdev]
+            vsctl_argv += ['--', 'add-port', bridge, ipdev]
 
         # XXX Needs support in ovs-vsctl
         #if bridge == ipdev:
-        #    vsctl_argv += ['--add=bridge.%s.mac=%s' % (bridge, pifrec['MAC'])]
+        #    vsctl_argv += ['--add=bridge.%s.mac=%s' % (bridge, dprec['MAC'])]
         #else:
-        #    vsctl_argv += ['--add=iface.%s.mac=%s' % (ipdev, pifrec['MAC'])]
+        #    vsctl_argv += ['--add=iface.%s.mac=%s' % (ipdev, dprec['MAC'])]
 
         self._vsctl_argv = vsctl_argv
         self._extra_ports = extra_ports