tweaked ovs_check a little
[pyplnet.git] / plnet.py
index ad83423..bd07405 100755 (executable)
--- a/plnet.py
+++ b/plnet.py
@@ -6,6 +6,7 @@ import time
 import tempfile
 import errno
 import struct
+import re
 
 import sioc
 import modprobe
@@ -13,6 +14,21 @@ import modprobe
 global version
 version = 4.3
 
+def ovs_check(logger):
+    """ Return True if openvswitch is running, False otherwise. Try restarting
+        it once.
+    """
+    rc = os.system("service openvswitch status")
+    if rc == 0:
+        return True
+    logger.log("net: restarting openvswitch")
+    rc = os.system("service openvswitch restart")
+    rc = os.system("service openvswitch status")
+    if rc == 0:
+        return True
+    logger.log("net: failed to restart openvswitch")
+    return False
+
 def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeManager"):
     global version
 
@@ -59,6 +75,9 @@ def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeMa
     interfaces.sort( compare_by('is_primary') )
     interfaces.reverse()
 
+    # The names of the bridge devices
+    bridgeDevices = []
+
     for interface in interfaces:
         logger.verbose('net:InitInterfaces interface %d: %r'%(device_id,interface))
         logger.verbose('net:InitInterfaces macs = %r' % macs)
@@ -77,7 +96,10 @@ def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeMa
         if orig_ifname:
             logger.verbose('net:InitInterfaces orig_ifname = %s' % orig_ifname)
 
-        details = prepDetails(interface)
+        details = prepDetails(interface, hostname)
+
+        if interface['is_primary']:
+            gateway = interface['gateway']
 
         if 'interface_tag_ids' in interface:
             version = 4.3
@@ -104,8 +126,15 @@ def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeMa
 
             for setting in settings:
                 settingname = setting[name_key].upper()
-                if settingname in ('IFNAME','ALIAS','CFGOPTIONS','DRIVER'):
+                if ((settingname in ('IFNAME','ALIAS','CFGOPTIONS','DRIVER','VLAN','TYPE','DEVICETYPE')) or \
+                    (re.search('^IPADDR[0-9]+$|^NETMASK[0-9]+$', settingname))):
+                    # TD: Added match for secondary IPv4 configuration.
+                    details[settingname]=setting['value']
+                # IPv6 support on IPv4 interface
+                elif settingname in ('IPV6ADDR','IPV6_DEFAULTGW','IPV6ADDR_SECONDARIES', 'IPV6_AUTOCONF'):
+                    # TD: Added IPV6_AUTOCONF.
                     details[settingname]=setting['value']
+                    details['IPV6INIT']='yes'
                 # wireless settings
                 elif settingname in \
                         [  "MODE", "ESSID", "NW", "FREQ", "CHANNEL", "SENS", "RATE",
@@ -116,6 +145,15 @@ def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeMa
                 # Bridge setting
                 elif settingname in [ 'BRIDGE' ]:
                     details['BRIDGE'] = setting['value']
+                elif settingname in [ 'OVS_BRIDGE' ]:
+                    # If openvswitch isn't running, then we'll lose network
+                    # connectivity when we reconfigure eth0.
+                    if ovs_check(logger):
+                        details['OVS_BRIDGE'] = setting['value']
+                        details['TYPE'] = "OVSPort"
+                        details['DEVICETYPE'] = "ovs"
+                    else:
+                        logger.log("net:InitInterfaces ERROR: OVS_BRIDGE specified, yet ovs is not running")
                 else:
                     logger.log("net:InitInterfaces WARNING: ignored setting named %s"%setting[name_key])
 
@@ -149,22 +187,55 @@ def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeMa
             else:
                 logger.log("net:InitInterfaces WARNING: interface alias (%s) not matched to an interface"% details['ALIAS'])
             device_id -= 1
-        elif 'BRIDGE' in details:
-            #The bridge inherits the mac of the first attached interface.
-            if 'IFNAME' in details:
-                ifname = details['IFNAME']
-                device_id -= 1
-            elif orig_ifname:
-                ifname = orig_ifname
-                device_id -= 1
-            if 'PRIMARY' in details: del details['PRIMARY']
-            logger.log('net:InitInterfaces: Bridge detected. Adding %s to devices_map' % ifname)
-            devices_map[ifname] = details
-            bridgeName = details['BRIDGE']
+        elif ('BRIDGE' in details or 'OVS_BRIDGE' in details) and 'IFNAME' in details:
+            # The bridge inherits the mac of the first attached interface.
+            ifname = details['IFNAME']
+            device_id -= 1
+            if 'BRIDGE' in details:
+                bridgeName = details['BRIDGE']
+                bridgeType = 'Bridge'
+            else:
+                bridgeName = details['OVS_BRIDGE']
+                bridgeType = 'OVSBridge'
 
-            logger.log('net:InitInterfaces: Adding bridge %s' % bridgeName)
+            logger.log('net:InitInterfaces: %s detected. Adding %s to devices_map' % (bridgeType, ifname))
+            devices_map[ifname] = removeBridgedIfaceDetails(details)
+
+            logger.log('net:InitInterfaces: Adding %s %s' % (bridgeType, bridgeName))
             bridgeDetails = prepDetails(interface)
-            bridgeDetails['TYPE']   = 'Bridge'
+            
+            # TD: Add configuration for secondary IPv4 and IPv6 addresses to the bridge.
+            if len(interface[interface_tag_ids]) > 0:
+                try:
+                    if version == 4.3:
+                        settings = plc.GetInterfaceTags({interface_tag_id:interface[interface_tag_ids]})
+                    else:
+                        settings = plc.GetNodeNetworkSettings({interface_tag_id:interface[interface_tag_ids]})
+                except:
+                    logger.log("net:InitInterfaces FATAL: failed call GetInterfaceTags({'interface_tag_id':{%s})"% \
+                               interface[interface_tag_ids])
+                    failedToGetSettings = True
+                    continue # on to the next interface
+
+                for setting in settings:
+                    settingname = setting[name_key].upper()
+                    if (re.search('^IPADDR[0-9]+$|^NETMASK[0-9]+$', settingname)):
+                        # TD: Added match for secondary IPv4 configuration.
+                        bridgeDetails[settingname]=setting['value']
+                    # IPv6 support on IPv4 interface
+                    elif settingname in ('IPV6ADDR','IPV6_DEFAULTGW','IPV6ADDR_SECONDARIES', 'IPV6_AUTOCONF'):
+                        # TD: Added IPV6_AUTOCONF.
+                        bridgeDetails[settingname]=setting['value']
+                        bridgeDetails['IPV6INIT']='yes'
+
+            bridgeDevices.append(bridgeName)
+            bridgeDetails['TYPE'] = bridgeType
+            if bridgeType == 'OVSBridge':
+                bridgeDetails['DEVICETYPE'] = 'ovs'
+                if bridgeDetails['BOOTPROTO'] == 'dhcp':
+                    del bridgeDetails['BOOTPROTO']
+                    bridgeDetails['OVSBOOTPROTO'] = 'dhcp'
+                    bridgeDetails['OVSDHCPINTERFACES'] = ifname
             devices_map[bridgeName] = bridgeDetails
         else:
             if 'IFNAME' in details:
@@ -382,14 +453,23 @@ def InitInterfaces(logger, plc, data, root="", files_only=False, program="NodeMa
         # handle those correctly
         if getvar("SLAVE") == 'yes': continue
 
+        # Delay bringing up any bridge devices
+        if dev in bridgeDevices: continue
+
         if not files_only:
             logger.verbose('net:InitInterfaces bringing up %s' % dev)
             os.system("/sbin/ifup %s" % dev)
 
+    # Bring up the bridge devices
+    for bridge in bridgeDevices:
+        if not files_only and bridge in newdevs:
+            logger.verbose('net:InitInterfaces bringing up bridge %s' % bridge)
+            os.system("/sbin/ifup %s" % bridge)
+
 ##
 # Prepare the interface details.
 #
-def prepDetails(interface):
+def prepDetails(interface, hostname=''):
     details = {}
     details['ONBOOT']  = 'yes'
     details['USERCTL'] = 'no'
@@ -404,7 +484,6 @@ def prepDetails(interface):
         details['NETMASK']   = interface['netmask']
         details['GATEWAY']   = interface['gateway']
         if interface['is_primary']:
-            gateway = interface['gateway']
             if interface['dns1']:
                 details['DNS1'] = interface['dns1']
             if interface['dns2']:
@@ -422,6 +501,29 @@ def prepDetails(interface):
 
     return details
 
+##
+# Remove duplicate entry from the bridged interface's configuration file.
+#
+def removeBridgedIfaceDetails(details):
+    # TD: Also added secondary IPv4 keys and IPv6 keys to the keys to be removed.
+    allKeys = [ 'PRIMARY', 'PERSISTENT_DHCLIENT', 'DHCLIENTARGS', 'DHCP_HOSTNAME',
+                'BOOTPROTO', 'IPADDR', 'NETMASK', 'GATEWAY', 'DNS1', 'DNS2',
+                'IPV6ADDR', 'IPV6_DEFAULTGW', 'IPV6ADDR_SECONDARIES',
+                'IPV6_AUTOCONF', 'IPV6INIT' ]
+    for i in range(1, 256):
+       allKeys.append('IPADDR' + str(i))
+       allKeys.append('NETMASK' + str(i))
+
+    for key in allKeys:
+        if key in details:
+            del details[key]
+
+    # TD: Also turn off IPv6
+    details['IPV6INIT']      = 'no'
+    details['IPV6_AUTOCONF'] = 'no'
+    
+    return details
+
 if __name__ == "__main__":
     import optparse
     import sys
@@ -435,8 +537,6 @@ if __name__ == "__main__":
     parser.add_option("-p", "--program", action="store", type="string",
                       dest="program", default="plnet")
     (options, args) = parser.parse_args()
-    options.root = ''
-    options.verbose = True
     if len(args) != 1 or options.root is None:
         print sys.argv
         print >>sys.stderr, "Missing root or node_id"