xenserver: Add new helper function to interface-reconfigure.
[openvswitch] / xenserver / opt_xensource_libexec_interface-reconfigure
index 29d79added53d0f4cc1c1fb2e72d14d72523e4f3..6de62b38740188e70d911a50bc075fcb1772ad82 100755 (executable)
@@ -543,31 +543,36 @@ def run_command(command):
         return False
     return True
 
+def read_first_line_of_file(name):
+    file = None
+    try:
+        file = open(name, 'r')
+        return file.readline().rstrip('\n')
+    finally:
+        if file != None:
+            file.close()
+
 def down_netdev(interface, deconfigure=True):
     if not interface_exists(interface):
         log("down_netdev: interface %s does not exist, ignoring" % interface)
         return
-    argv = ["/sbin/ifconfig", interface, 'down']
     if deconfigure:
-        argv += ['0.0.0.0']
-
         # Kill dhclient.
         pidfile_name = '/var/run/dhclient-%s.pid' % interface
-        pidfile = None
         try:
-            pidfile = open(pidfile_name, 'r')
-            os.kill(int(pidfile.readline()), signal.SIGTERM)
+            os.kill(int(read_first_line_of_file(pidfile_name)), signal.SIGTERM)
         except:
             pass
-        if pidfile != None:
-            pidfile.close()
 
         # Remove dhclient pidfile.
         try:
             os.remove(pidfile_name)
         except:
             pass
-    run_command(argv)
+        
+        run_command(["/sbin/ifconfig", interface, '0.0.0.0'])
+
+    run_command(["/sbin/ifconfig", interface, 'down'])
 
 def up_netdev(interface):
     run_command(["/sbin/ifconfig", interface, 'up'])
@@ -750,6 +755,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",
@@ -786,6 +794,10 @@ def action_up(pif):
         bond_master = pif
     else:
         bond_master = None
+    if bond_master:
+        bond_slaves = get_bond_slaves_of_pif(bond_master)
+    else:
+        bond_slaves = []
     bond_masters = get_bond_masters_of_pif(pif)
 
     # Support "rpm -e vswitch" gracefully by keeping Centos configuration
@@ -831,6 +843,15 @@ def action_up(pif):
     for physdev in physdevs:
         down_netdev(physdev)
 
+    # If we are bringing up a bond, remove IP addresses from the
+    # slaves (because we are implicitly being asked to take them down).
+    # 
+    # Conversely, if we are bringing up an interface that has bond
+    # masters, remove IP addresses from the bond master (because we
+    # are implicitly being asked to take it down).
+    for bond_pif in bond_slaves + bond_masters:
+        run_command(["/sbin/ifconfig", ipdev_name(bond_pif), '0.0.0.0']) 
+
     # Remove all keys related to pif and any bond masters linked to PIF.
     del_ports = [ipdev] + physdevs + bond_masters
     if vlan_slave and bond_master:
@@ -872,6 +893,16 @@ def action_up(pif):
         net = db.get_pif_record(nwpif)['network']
         network_uuids += [db.get_network_record(net)['uuid']]
 
+    # Bring up bond slaves early, because ovs-vswitchd initially
+    # enables or disables bond slaves based on whether carrier is
+    # detected when they are added, and a network device that is down
+    # always reports "no carrier".
+    bond_slave_physdevs = []
+    for slave in bond_slaves:
+        bond_slave_physdevs += physdev_names(slave)
+    for slave_physdev in bond_slave_physdevs:
+        up_netdev(slave_physdev)
+
     # Now modify the ovs-vswitchd config file.
     argv = []
     for port in set(del_ports):
@@ -906,14 +937,28 @@ def action_up(pif):
     # Configure network devices.
     configure_netdev(pif)
 
-    # Bring up VLAN slave and bond slaves.
+    # Bring up VLAN slave, plus physical devices other than bond
+    # slaves (which we brought up earlier).
     if vlan_slave:
         up_netdev(ipdev_name(vlan_slave))
-    for physdev in physdevs:
+    for physdev in set(physdevs) - set(bond_slave_physdevs):
         up_netdev(physdev)
 
     # Update /etc/issue (which contains the IP address of the management interface)
     os.system("/sbin/update-issue")
+
+    if bond_slaves:
+        # There seems to be a race somewhere: without this sleep, using
+        # XenCenter to create a bond that becomes the management interface
+        # fails with "The underlying connection was closed: A connection that
+        # was expected to be kept alive was closed by the server." on every
+        # second or third try, even though /var/log/messages doesn't show
+        # anything unusual.
+        #
+        # The race is probably present even without vswitch, but bringing up a
+        # bond without vswitch involves a built-in pause of 10 seconds or more
+        # to wait for the bond to transition from learning to forwarding state.
+        time.sleep(5)
         
 def action_down(pif):
     rec = db.get_pif_record(pif)