netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / xenserver / opt_xensource_libexec_interface-reconfigure
index 6f2b5bc..3b5c861 100755 (executable)
-#!/usr/bin/python
+#!/usr/bin/env python
 #
-# Copyright (c) Citrix Systems 2008. All rights reserved.
-# Copyright (c) 2009 Nicira Networks.
+# Copyright (c) 2008,2009 Citrix Systems, Inc.
+#
+# 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
+# by the Free Software Foundation; version 2.1 only. with the special
+# exception on linking described in file LICENSE.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
 #
 """Usage:
 
-    %(command-name)s --session <SESSION-REF> --pif <PIF-REF> [up|down|rewrite]
-    %(command-name)s --force <BRIDGE> [up|down|rewrite <CONFIG>]
-    %(command-name)s --force all down
+    %(command-name)s <PIF> up
+    %(command-name)s <PIF> down
+    %(command-name)s rewrite
+    %(command-name)s --force <BRIDGE> up
+    %(command-name)s --force <BRIDGE> down
+    %(command-name)s --force <BRIDGE> rewrite --device=<INTERFACE> --mac=<MAC-ADDRESS> <CONFIG>
 
-    where,
-          <CONFIG> = --device=<INTERFACE> --mode=dhcp
-          <CONFIG> = --device=<INTERFACE> --mode=static --ip=<IPADDR> --netmask=<NM> [--gateway=<GW>]
+    where <PIF> is one of:
+       --session <SESSION-REF> --pif <PIF-REF>
+       --pif-uuid <PIF-UUID>
+    and <CONFIG> is one of:
+       --mode=dhcp
+       --mode=static --ip=<IPADDR> --netmask=<NM> [--gateway=<GW>]
 
   Options:
-    --session          A session reference to use to access the xapi DB
-    --pif               A PIF reference.
-    --force-interface  An interface name. Mutually exclusive with --session/--pif.
-
-  Either both --session and --pif  or just --pif-uuid.
-  
-  <ACTION> is either "up" or "down" or "rewrite"
+    --session           A session reference to use to access the xapi DB
+    --pif               A PIF reference within the session.
+    --pif-uuid          The UUID of a PIF.
+    --force             An interface name.
+    --root-prefix=DIR   Use DIR as alternate root directory (for testing).
+    --no-syslog         Write log messages to stderr instead of system log.
 """
 
-#
-# Undocumented parameters for test & dev:
-#
-#  --output-directory=<DIR>    Write configuration to <DIR>. Also disables actually
-#                               raising/lowering the interfaces
-#  --pif-uuid                  A PIF UUID, use instead of --session/--pif.
-#
-#
-#
 # Notes:
 # 1. Every pif belongs to exactly one network
 # 2. Every network has zero or one pifs
 # 3. A network may have an associated bridge, allowing vifs to be attached
 # 4. A network may be bridgeless (there's no point having a bridge over a storage pif)
 
-# XXX: --force-interface=all down
+from InterfaceReconfigure import *
 
-# XXX: --force-interface rewrite
-
-# XXX: Sometimes this leaves "orphaned" datapaths, e.g. a datapath whose
-#      only port is the local port.  Should delete those.
-
-# XXX: This can leave crud in ovs-vswitchd.conf in this scenario:
-#      - Create bond in XenCenter.
-#      - Create VLAN on bond in XenCenter.
-#      - Attempt to delete bond in XenCenter (this will fail because there
-#        is a VLAN on the bond, although the error may not be reported
-#        until the next step)
-#      - Delete VLAN in XenCenter.
-#      - Delete bond in XenCenter.
-# At this point there will still be some configuration data for the bond
-# or the VLAN in ovs-vswitchd.conf.
-
-import XenAPI
-import os, sys, getopt, time, signal
+import os, sys, getopt
 import syslog
 import traceback
-import time
 import re
-import pickle
-
-output_directory = None
+import random
+import syslog
 
-db = None
 management_pif = None
 
-dbcache_file = "/etc/ovs-vswitch.dbcache"
-vswitch_config_dir = "/etc/openvswitch"
+dbcache_file = "/var/xapi/network.dbcache"
+
+#
+# Logging.
+#
+
+def log_pif_action(action, pif):
+    pifrec = db().get_pif_record(pif)
+    rec = {}
+    rec['uuid'] = pifrec['uuid']
+    rec['ip_configuration_mode'] = pifrec['ip_configuration_mode']
+    rec['action'] = action
+    rec['pif_netdev_name'] = pif_netdev_name(pif)
+    rec['message'] = "Bring %(action)s PIF %(uuid)s" % rec
+    log("%(message)s: %(pif_netdev_name)s configured as %(ip_configuration_mode)s" % rec)
+
+#
+# Exceptions.
+#
 
 class Usage(Exception):
     def __init__(self, msg):
         Exception.__init__(self)
         self.msg = msg
 
-class Error(Exception):
-    def __init__(self, msg):
-        Exception.__init__(self)
-        self.msg = msg
+#
+# Boot from Network filesystem or device.
+#
 
-class ConfigurationFile(object):
-    """Write a file, tracking old and new versions.
+def check_allowed(pif):
+    """Determine whether interface-reconfigure should be manipulating this PIF.
 
-    Supports writing a new version of a file and applying and
-    reverting those changes.
+    Used to prevent system PIFs (such as network root disk) from being interfered with.
     """
 
-    __STATE = {"OPEN":"OPEN",
-               "NOT-APPLIED":"NOT-APPLIED", "APPLIED":"APPLIED",
-               "REVERTED":"REVERTED", "COMMITTED": "COMMITTED"}
-    
-    def __init__(self, fname, path="/etc/sysconfig/network-scripts"):
-
-        self.__state = self.__STATE['OPEN']
-        self.__fname = fname
-        self.__children = []
-        
-        if debug_mode():
-            dirname = output_directory
-        else:
-            dirname = path
-            
-        self.__path    = os.path.join(dirname, fname)
-        self.__oldpath = os.path.join(dirname, "." + fname + ".xapi-old")
-        self.__newpath = os.path.join(dirname, "." + fname + ".xapi-new")
-        self.__unlink = False
-        
-        self.__f = open(self.__newpath, "w")
-
-    def attach_child(self, child):
-        self.__children.append(child)
-
-    def path(self):
-        return self.__path
-
-    def readlines(self):
-        try:
-            return open(self.path()).readlines()
-        except:
-            return ""
-        
-    def write(self, args):
-        if self.__state != self.__STATE['OPEN']:
-            raise Error("Attempt to write to file in state %s" % self.__state)
-        self.__f.write(args)
-
-    def unlink(self):
-        if self.__state != self.__STATE['OPEN']:
-            raise Error("Attempt to unlink file in state %s" % self.__state)
-        self.__unlink = True
-        self.__f.close()
-        self.__state = self.__STATE['NOT-APPLIED']
-    
-    def close(self):
-        if self.__state != self.__STATE['OPEN']:
-            raise Error("Attempt to close file in state %s" % self.__state)
-        
-        self.__f.close()
-        self.__state = self.__STATE['NOT-APPLIED']
-
-    def changed(self):
-        if self.__state != self.__STATE['NOT-APPLIED']:
-            raise Error("Attempt to compare file in state %s" % self.__state)
-
-        return True
-
-    def apply(self):
-        if self.__state != self.__STATE['NOT-APPLIED']:
-            raise Error("Attempt to apply configuration from state %s" % self.__state)
-
-        for child in self.__children:
-            child.apply()
-
-        log("Applying changes to %s configuration" % self.__fname)
-
-        # Remove previous backup.
-        if os.access(self.__oldpath, os.F_OK):
-            os.unlink(self.__oldpath)
-
-        # Save current configuration.
-        if os.access(self.__path, os.F_OK):
-            os.link(self.__path, self.__oldpath)
-            os.unlink(self.__path)
-
-        # Apply new configuration.
-        assert(os.path.exists(self.__newpath))
-        if not self.__unlink:
-            os.link(self.__newpath, self.__path)
-        else:
-            pass # implicit unlink of original file 
-
-        # Remove temporary file.
-        os.unlink(self.__newpath)
-
-        self.__state = self.__STATE['APPLIED']
-
-    def revert(self):
-        if self.__state != self.__STATE['APPLIED']:
-            raise Error("Attempt to revert configuration from state %s" % self.__state)
-
-        for child in self.__children:
-            child.revert()
-
-        log("Reverting changes to %s configuration" % self.__fname)
-
-        # Remove existing new configuration
-        if os.access(self.__newpath, os.F_OK):
-            os.unlink(self.__newpath)
-
-        # Revert new configuration.
-        if os.access(self.__path, os.F_OK):
-            os.link(self.__path, self.__newpath)
-            os.unlink(self.__path)
-
-        # Revert to old configuration.
-        if os.access(self.__oldpath, os.F_OK):
-            os.link(self.__oldpath, self.__path)
-            os.unlink(self.__oldpath)
-
-        # Leave .*.xapi-new as an aid to debugging.
-        
-        self.__state = self.__STATE['REVERTED']
-    
-    def commit(self):
-        if self.__state != self.__STATE['APPLIED']:
-            raise Error("Attempt to commit configuration from state %s" % self.__state)
-
-        for child in self.__children:
-            child.commit()
-
-        log("Committing changes to %s configuration" % self.__fname)
-        
-        if os.access(self.__oldpath, os.F_OK):
-            os.unlink(self.__oldpath)
-        if os.access(self.__newpath, os.F_OK):
-            os.unlink(self.__newpath)
-
-        self.__state = self.__STATE['COMMITTED']
-
-def debug_mode():
-    return output_directory is not None
-
-def log(s):
-    if debug_mode():
-        print >>sys.stderr, s
-    else:
-        syslog.syslog(s)
-
-def check_allowed(pif):
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
     try:
-        f = open("/proc/ardence")
+        f = open(root_prefix() + "/proc/ardence")
         macline = filter(lambda x: x.startswith("HWaddr:"), f.readlines())
         f.close()
         if len(macline) == 1:
@@ -245,821 +103,475 @@ def check_allowed(pif):
         pass
     return True
 
-def interface_exists(i):
-    return os.path.exists("/sys/class/net/" + i)
+#
+# Bare Network Devices -- network devices without IP configuration
+#
 
-class DatabaseCache(object):
-    def __get_pif_records_from_xapi(self, session):
-        self.__pifs = session.xenapi.PIF.get_all_records()
-    
-    def __get_vlan_records_from_xapi(self, session):
-        self.__vlans = session.xenapi.VLAN.get_all_records()
-    
-    def __get_bond_records_from_xapi(self, session):
-        self.__bonds = session.xenapi.Bond.get_all_records()
-    
-    def __get_network_records_from_xapi(self, session):
-        self.__networks = session.xenapi.network.get_all_records()
-    
-    def __init__(self, session_ref=None, cache_file=None):
-        if session_ref and cache_file:
-            raise Error("can't specify session reference and cache file")
+def netdev_remap_name(pif, already_renamed=[]):
+    """Check whether 'pif' exists and has the correct MAC.
+    If not, try to find a device with the correct MAC and rename it.
+    'already_renamed' is used to avoid infinite recursion.
+    """
 
-        if cache_file == None:
-            session = XenAPI.xapi_local()
+    def read1(name):
+        file = None
+        try:
+            file = open(name, 'r')
+            return file.readline().rstrip('\n')
+        finally:
+            if file != None:
+                file.close()
 
-            if not session_ref:
-                log("No session ref given on command line, logging in.")
-                session.xenapi.login_with_password("root", "")
-            else:
-                session._session = session_ref
-
-            try:
-                self.__get_pif_records_from_xapi(session)
-                self.__get_vlan_records_from_xapi(session)
-                self.__get_bond_records_from_xapi(session)
-                self.__get_network_records_from_xapi(session)
-            finally:
-                if not session_ref:
-                    session.xenapi.session.logout()
-        else:
-            log("Loading xapi database cache from %s" % cache_file)
-            f = open(cache_file, 'r')
-            members = pickle.load(f)
-            self.extras = pickle.load(f)
-            f.close()
-
-            self.__vlans = members['vlans']
-            self.__bonds = members['bonds']
-            self.__pifs = members['pifs']
-            self.__networks = members['networks']
-
-    def save(self, cache_file, extras):
-        f = open(cache_file, 'w')
-        pickle.dump({'vlans': self.__vlans,
-                     'bonds': self.__bonds,
-                     'pifs': self.__pifs,
-                     'networks': self.__networks}, f)
-        pickle.dump(extras, f)
-        f.close()
+    def get_netdev_mac(device):
+        try:
+            return read1("%s/sys/class/net/%s/address" % (root_prefix(), device))
+        except:
+            # Probably no such device.
+            return None
 
-    def get_pif_by_uuid(self, uuid):
-        pifs = map(lambda (ref,rec): ref,
-                  filter(lambda (ref,rec): uuid == rec['uuid'],
-                         self.__pifs.items()))
-        if len(pifs) == 0:
-            raise Error("Unknown PIF \"%s\"" % uuid)
-        elif len(pifs) > 1:
-            raise Error("Non-unique PIF \"%s\"" % uuid)
-
-        return pifs[0]
-
-    def get_pifs_by_record(self, record):
-        """record is partial pif record.
-        Get the pif(s) whose record matches.
-        """
-        def match(pifrec):
-            for key in record:
-                if record[key] != pifrec[key]:
-                    return False
-            return True
-            
-        return map(lambda (ref,rec): ref,
-                   filter(lambda (ref,rec): match(rec),
-                          self.__pifs.items()))
-
-    def get_pif_by_record(self, record):
-        """record is partial pif record.
-        Get the pif whose record matches.
-        """
-        pifs = self.get_pifs_by_record(record)
-        if len(pifs) == 0:
-            raise Error("No matching PIF \"%s\"" % str(record))
-        elif len(pifs) > 1:
-            raise Error("Multiple matching PIFs \"%s\"" % str(record))
-
-        return pifs[0]
-
-    def get_pif_by_bridge(self, host, bridge):
-        networks = map(lambda (ref,rec): ref,
-                       filter(lambda (ref,rec): rec['bridge'] == bridge,
-                              self.__networks.items()))
-        if len(networks) == 0:
-            raise Error("No matching network \"%s\"")
-
-        answer = None
-        for network in networks:
-            nwrec = self.get_network_record(network)
-            for pif in nwrec['PIFs']:
-                pifrec = self.get_pif_record(pif)
-                if pifrec['host'] != host:
-                    continue
-                if answer:
-                    raise Error("Multiple PIFs on %s for network %s" % (host, bridge))
-                answer = pif
-        if not answer:
-            raise Error("No PIF on %s for network %s" % (host, bridge))
-        return answer
-
-    def get_pif_record(self, pif):
-        if self.__pifs.has_key(pif):
-            return self.__pifs[pif]
-        raise Error("Unknown PIF \"%s\"" % pif)
-    def get_all_pifs(self):
-        return self.__pifs
-    def pif_exists(self, pif):
-        return self.__pifs.has_key(pif)
-    
-    def get_management_pif(self, host):
-        """ Returns the management pif on host
-        """
-        all = self.get_all_pifs()
-        for pif in all: 
-            pifrec = self.get_pif_record(pif)
-            if pifrec['management'] and pifrec['host'] == host :
-                return pif
-        return None
+    def get_netdev_tx_queue_len(device):
+        try:
+            return int(read1("%s/sys/class/net/%s/tx_queue_len" % (root_prefix(), device)))
+        except:
+            # Probably no such device.
+            return None
 
-    def get_network_record(self, network):
-        if self.__networks.has_key(network):
-            return self.__networks[network]
-        raise Error("Unknown network \"%s\"" % network)
-    def get_all_networks(self):
-        return self.__networks
+    def get_netdev_by_mac(mac):
+        for device in os.listdir(root_prefix() + "/sys/class/net"):
+            dev_mac = get_netdev_mac(device)
+            if (dev_mac and mac.lower() == dev_mac.lower() and
+                get_netdev_tx_queue_len(device)):
+                return device
+        return None
 
-    def get_bond_record(self, bond):
-        if self.__bonds.has_key(bond):
-            return self.__bonds[bond]
-        else:
-            return None
-        
-    def get_vlan_record(self, vlan):
-        if self.__vlans.has_key(vlan):
-            return self.__vlans[vlan]
-        else:
-            return None
-            
-def bridge_name(pif):
-    """Return the bridge name associated with pif, or None if network is bridgeless"""
-    pifrec = db.get_pif_record(pif)
-    nwrec = db.get_network_record(pifrec['network'])
-
-    if nwrec['bridge']:
-        # TODO: sanity check that nwrec['bridgeless'] != 'true'
-        return nwrec['bridge']
+    def rename_netdev(old_name, new_name):
+        raise Error("Trying to rename %s to %s - This functionality has been removed" % (old_name, new_name))
+        # log("Changing the name of %s to %s" % (old_name, new_name))
+        # run_command(['/sbin/ifconfig', old_name, 'down'])
+        # if not run_command(['/sbin/ip', 'link', 'set', old_name, 'name', new_name]):
+        #     raise Error("Could not rename %s to %s" % (old_name, new_name))
+
+    pifrec = db().get_pif_record(pif)
+    device = pifrec['device']
+    mac = pifrec['MAC']
+
+    # Is there a network device named 'device' at all?
+    device_exists = netdev_exists(device)
+    if device_exists:
+        # Yes.  Does it have MAC 'mac'?
+        found_mac = get_netdev_mac(device)
+        if found_mac and mac.lower() == found_mac.lower():
+            # Yes, everything checks out the way we want.  Nothing to do.
+            return
     else:
-        # TODO: sanity check that nwrec['bridgeless'] == 'true'
-        return None
+        log("No network device %s" % device)
 
-def interface_name(pif):
-    """Construct an interface name from the given PIF record."""
+    # What device has MAC 'mac'?
+    cur_device = get_netdev_by_mac(mac)
+    if not cur_device:
+        log("No network device has MAC %s" % mac)
+        return
 
-    pifrec = db.get_pif_record(pif)
+    # First rename 'device', if it exists, to get it out of the way
+    # for 'cur_device' to replace it.
+    if device_exists:
+        rename_netdev(device, "dev%d" % random.getrandbits(24))
 
-    if pifrec['VLAN'] == '-1':
-        return pifrec['device']
-    else:
-        return "%(device)s.%(VLAN)s" % pifrec
-
-def datapath_name(pif):
-    """Return the OpenFlow datapath name 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.
-(xapi will create a datapath named with the bridge name even though we won't
-use it.)
-"""
+    # Rename 'cur_device' to 'device'.
+    rename_netdev(cur_device, device)
 
-    pifrec = db.get_pif_record(pif)
+#
+# IP Network Devices -- network devices with IP configuration
+#
+
+def ifdown(netdev):
+    """Bring down a network interface"""
+    if not netdev_exists(netdev):
+        log("ifdown: device %s does not exist, ignoring" % netdev)
+        return
+    if not os.path.exists("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), netdev)):
+        log("ifdown: device %s exists but ifcfg-%s does not" % (netdev,netdev))
+        run_command(["/sbin/ifconfig", netdev, 'down'])
+        return
+    run_command(["/sbin/ifdown", netdev])
+
+def ifup(netdev):
+    """Bring up a network interface"""
+    if not os.path.exists(root_prefix() + "/etc/sysconfig/network-scripts/ifcfg-%s" % netdev):
+        raise Error("ifup: device %s exists but ifcfg-%s does not" % (netdev,netdev))
+    d = os.getenv("DHCLIENTARGS","")
+    if os.path.exists("/etc/firstboot.d/data/firstboot_in_progress"):
+        os.putenv("DHCLIENTARGS", d + " -T 240 " )
+    run_command(["/sbin/ifup", netdev])
+    os.putenv("DHCLIENTARGS", d )
 
-    if pifrec['VLAN'] == '-1':
-        return bridge_name(pif)
+#
+#
+#
+
+def pif_rename_physical_devices(pif):
+    if pif_is_tunnel(pif):
+        return
+
+    if pif_is_vlan(pif):
+        pif = pif_get_vlan_slave(pif)
+
+    if pif_is_bond(pif):
+        pifs = pif_get_bond_slaves(pif)
     else:
-        return bridge_name(get_vlan_slave_of_pif(pif))
+        pifs = [pif]
 
-def ipdev_name(pif):
-    """Return the the name of the network device that carries the
-IP configuration (if any) associated with pif.
-The ipdev name is the same as the bridge name.
-"""
+    for pif in pifs:
+        netdev_remap_name(pif)
 
-    pifrec = db.get_pif_record(pif)
-    return bridge_name(pif)
+#
+# IP device configuration
+#
 
-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.
-For a bond master PIF, the physical devices are the bond slaves.
-For a non-VLAN, non-bond master PIF, the physical device is the PIF itself.
-"""
+def ipdev_configure_static_routes(interface, oc, f):
+    """Open a route-<interface> file for static routes.
 
-    pifrec = db.get_pif_record(pif)
+    Opens the static routes configuration file for interface and writes one
+    line for each route specified in the network's other config "static-routes" value.
+    E.g. if
+           interface ( RO): xenbr1
+           other-config (MRW): static-routes: 172.16.0.0/15/192.168.0.3,172.18.0.0/16/192.168.0.4;...
 
-    if pifrec['VLAN'] != '-1':
-        return physdev_names(get_vlan_slave_of_pif(pif))
-    elif len(pifrec['bond_master_of']) != 0:
-        physdevs = []
-        for slave in get_bond_slaves_of_pif(pif):
-            physdevs += physdev_names(slave)
-        return physdevs
+    Then route-xenbr1 should be
+          172.16.0.0/15 via 192.168.0.3 dev xenbr1
+          172.18.0.0/16 via 192.168.0.4 dev xenbr1
+    """
+    if oc.has_key('static-routes'):
+        # The key is present - extract comma separates entries
+        lines = oc['static-routes'].split(',')
     else:
-        return [pifrec['device']]
+        # The key is not present, i.e. there are no static routes
+        lines = []
 
-def log_pif_action(action, pif):
-    pifrec = db.get_pif_record(pif)
-    pifrec['action'] = action
-    pifrec['interface-name'] = interface_name(pif)
-    if action == "rewrite":
-        pifrec['message'] = "Rewrite PIF %(uuid)s configuration" % pifrec
-    else:
-        pifrec['message'] = "Bring %(action)s PIF %(uuid)s" % pifrec
-    log("%(message)s: %(interface-name)s configured as %(ip_configuration_mode)s" % pifrec)
+    child = ConfigurationFile("%s/etc/sysconfig/network-scripts/route-%s" % (root_prefix(), interface))
+    child.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
+            (os.path.basename(child.path()), os.path.basename(sys.argv[0])))
 
-def get_bond_masters_of_pif(pif):
-    """Returns a list of PIFs which are bond masters of this PIF"""
+    try:
+        for l in lines:
+            network, masklen, gateway = l.split('/')
+            child.write("%s/%s via %s dev %s\n" % (network, masklen, gateway, interface))
 
-    pifrec = db.get_pif_record(pif)
+        f.attach_child(child)
+        child.close()
 
-    bso = pifrec['bond_slave_of']
+    except ValueError, e:
+        log("Error in other-config['static-routes'] format for network %s: %s" % (interface, e))
 
-    # bond-slave-of is currently a single reference but in principle a
-    # PIF could be a member of several bonds which are not
-    # concurrently attached. Be robust to this possibility.
-    if not bso or bso == "OpaqueRef:NULL":
-        bso = []
-    elif not type(bso) == list:
-        bso = [bso]
+def ipdev_open_ifcfg(pif):
+    ipdev = pif_ipdev_name(pif)
 
-    bondrecs = [db.get_bond_record(bond) for bond in bso]
-    bondrecs = [rec for rec in bondrecs if rec]
+    log("Writing network configuration for %s" % ipdev)
 
-    return [bond['master'] for bond in bondrecs]
+    f = ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), ipdev))
 
-def get_bond_slaves_of_pif(pif):
-    """Returns a list of PIFs which make up the given bonded pif."""
-    
-    pifrec = db.get_pif_record(pif)
-    host = pifrec['host']
+    f.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
+            (os.path.basename(f.path()), os.path.basename(sys.argv[0])))
+    f.write("XEMANAGED=yes\n")
+    f.write("DEVICE=%s\n" % ipdev)
+    f.write("ONBOOT=no\n")
+    f.write("NOZEROCONF=yes\n")
 
-    bmo = pifrec['bond_master_of']
-    if len(bmo) > 1:
-        raise Error("Bond-master-of contains too many elements")
-    
-    if len(bmo) == 0:
-        return []
-    
-    bondrec = db.get_bond_record(bmo[0])
-    if not bondrec:
-        raise Error("No bond record for bond master PIF")
+    return f
 
-    return bondrec['slaves']
+def ipdev_configure_network(pif, dp):
+    """Write the configuration file for a network.
 
-def get_vlan_slave_of_pif(pif):
-    """Find the PIF which is the VLAN slave of pif.
+    Writes configuration derived from the network object into the relevant
+    ifcfg file.  The configuration file is passed in, but if the network is
+    bridgeless it will be ifcfg-<interface>, otherwise it will be ifcfg-<bridge>.
 
-Returns the 'physical' PIF underneath the a VLAN PIF @pif."""
-    
-    pifrec = db.get_pif_record(pif)
+    This routine may also write ifcfg files of the networks corresponding to other PIFs
+    in order to maintain consistency.
 
-    vlan = pifrec['VLAN_master_of']
-    if not vlan or vlan == "OpaqueRef:NULL":
-        raise Error("PIF is not a VLAN master")
+    params:
+        pif:  Opaque_ref of pif
+        dp:   Datapath object
+    """
 
-    vlanrec = db.get_vlan_record(vlan)
-    if not vlanrec:
-        raise Error("No VLAN record found for PIF")
+    pifrec = db().get_pif_record(pif)
+    nw = pifrec['network']
+    nwrec = db().get_network_record(nw)
 
-    return vlanrec['tagged_PIF']
+    ipdev = pif_ipdev_name(pif)
 
-def get_vlan_masters_of_pif(pif):
-    """Returns a list of PIFs which are VLANs on top of the given pif."""
-    
-    pifrec = db.get_pif_record(pif)
-    vlans = [db.get_vlan_record(v) for v in pifrec['VLAN_slave_of']]
-    return [v['untagged_PIF'] for v in vlans if v and db.pif_exists(v['untagged_PIF'])]
-
-def interface_deconfigure_commands(interface):
-    # The use of [!0-9] keeps an interface of 'eth0' from matching
-    # VLANs attached to eth0 (such as 'eth0.123'), which are distinct
-    # interfaces.
-    return ['--del-match=bridge.*.port=%s' % interface,
-            '--del-match=bonding.%s.[!0-9]*' % interface,
-            '--del-match=bonding.*.slave=%s' % interface,
-            '--del-match=vlan.%s.[!0-9]*' % interface,
-            '--del-match=port.%s.[!0-9]*' % interface,
-            '--del-match=iface.%s.[!0-9]*' % interface]
-
-def run_command(command):
-    log("Running command: " + ' '.join(command))
-    if os.spawnl(os.P_WAIT, command[0], *command) != 0:
-        log("Command failed: " + ' '.join(command))
-        return False
-    return True
+    f = ipdev_open_ifcfg(pif)
 
-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']
+    mode = pifrec['ip_configuration_mode']
+    log("Configuring %s using %s configuration" % (ipdev, mode))
 
-        # 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)
-        except:
-            pass
-        if pidfile != None:
-            pidfile.close()
+    oc = None
+    if pifrec.has_key('other_config'):
+        oc = pifrec['other_config']
 
-        # Remove dhclient pidfile.
-        try:
-            os.remove(pidfile_name)
-        except:
-            pass
-    run_command(argv)
+    dp.configure_ipdev(f)
+
+    if pifrec['ip_configuration_mode'] == "DHCP":
+        f.write("BOOTPROTO=dhcp\n")
+        f.write("PERSISTENT_DHCLIENT=yes\n")
+    elif pifrec['ip_configuration_mode'] == "Static":
+        f.write("BOOTPROTO=none\n")
+        f.write("NETMASK=%(netmask)s\n" % pifrec)
+        f.write("IPADDR=%(IP)s\n" % pifrec)
+        f.write("GATEWAY=%(gateway)s\n" % pifrec)
+    elif pifrec['ip_configuration_mode'] == "None":
+        f.write("BOOTPROTO=none\n")
+    else:
+        raise Error("Unknown ip-configuration-mode %s" % pifrec['ip_configuration_mode'])
 
-def up_netdev(interface):
-    run_command(["/sbin/ifconfig", interface, 'up'])
+    if nwrec.has_key('other_config'):
+        settings,offload = ethtool_settings(nwrec['other_config'])
+        if len(settings):
+            f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings))
+        if len(offload):
+            f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload))
 
-def find_distinguished_pifs(pif):
-    """Returns the PIFs on host that own DNS and the default route.
-The peerdns pif will be the one with pif::other-config:peerdns=true, or the mgmt pif if none have this set.
-The gateway pif will be the one with pif::other-config:defaultroute=true, or the mgmt pif if none have this set.
+        ipdev_configure_static_routes(ipdev, nwrec['other_config'], f)
 
-Note: we prune out the bond master pif (if it exists).
-This is because when we are called to bring up an interface with a bond master, it is implicit that
-we should bring down that master."""
+    mtu = mtu_setting(nw, "Network", nwrec['other_config'])
+    if mtu:
+        f.write("MTU=%s\n" % mtu)
 
-    pifrec = db.get_pif_record(pif)
-    host = pifrec['host']
 
-    pifs_on_host = [ __pif for __pif in db.get_all_pifs() if
-                     db.get_pif_record(__pif)['host'] == host and 
-                     (not  __pif in get_bond_masters_of_pif(pif)) ]
+    if pifrec.has_key('DNS') and pifrec['DNS'] != "":
+        ServerList = pifrec['DNS'].split(",")
+        for i in range(len(ServerList)): f.write("DNS%d=%s\n" % (i+1, ServerList[i]))
+    if oc and oc.has_key('domain'):
+        f.write("DOMAIN='%s'\n" % oc['domain'].replace(',', ' '))
+
+    # There can be only one DNSDEV and one GATEWAYDEV in /etc/sysconfig/network.
+    #
+    # The peerdns pif will be the one with
+    # pif::other-config:peerdns=true, or the mgmt pif if none have
+    # this set.
+    #
+    # The gateway pif will be the one with
+    # pif::other-config:defaultroute=true, or the mgmt pif if none
+    # have this set.
+
+    # Work out which pif on this host should be the DNSDEV and which
+    # should be the GATEWAYDEV
+    #
+    # Note: we prune out the bond master pif (if it exists). This is
+    # because when we are called to bring up an interface with a bond
+    # master, it is implicit that we should bring down that master.
+
+    pifs_on_host = [p for p in db().get_all_pifs() if not p in pif_get_bond_masters(pif)]
+
+    # now prune out bond slaves as they are not connected to the IP 
+    # stack and so cannot be used as gateway or DNS devices.
+    pifs_on_host = [ p for p in pifs_on_host if len(pif_get_bond_masters(p)) == 0]
 
-    peerdns_pif = None
-    defaultroute_pif = None
-    
     # loop through all the pifs on this host looking for one with
     #   other-config:peerdns = true, and one with
     #   other-config:default-route=true
+    peerdns_pif = None
+    defaultroute_pif = None
     for __pif in pifs_on_host:
-        __pifrec = db.get_pif_record(__pif)
+        __pifrec = db().get_pif_record(__pif)
         __oc = __pifrec['other_config']
         if __oc.has_key('peerdns') and __oc['peerdns'] == 'true':
             if peerdns_pif == None:
                 peerdns_pif = __pif
             else:
                 log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \
-                        (db.get_pif_record(peerdns_pif)['device'], __pifrec['device']))
+                        (db().get_pif_record(peerdns_pif)['device'], __pifrec['device']))
         if __oc.has_key('defaultroute') and __oc['defaultroute'] == 'true':
             if defaultroute_pif == None:
                 defaultroute_pif = __pif
             else:
                 log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \
-                        (db.get_pif_record(defaultroute_pif)['device'], __pifrec['device']))
-    
-    # If no pif is explicitly specified then use the mgmt pif for peerdns/defaultroute
+                        (db().get_pif_record(defaultroute_pif)['device'], __pifrec['device']))
+
+    # If no pif is explicitly specified then use the mgmt pif for
+    # peerdns/defaultroute.
     if peerdns_pif == None:
         peerdns_pif = management_pif
     if defaultroute_pif == None:
         defaultroute_pif = management_pif
 
-    return peerdns_pif, defaultroute_pif
-
-def ethtool_settings(oc):
-    # Options for "ethtool -s"
-    settings = []
-    if oc.has_key('ethtool-speed'):
-        val = oc['ethtool-speed']
-        if val in ["10", "100", "1000"]:
-            settings += ['speed', val]
-        else:
-            log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val)
-    if oc.has_key('ethtool-duplex'):
-        val = oc['ethtool-duplex']
-        if val in ["10", "100", "1000"]:
-            settings += ['duplex', 'val']
-        else:
-            log("Invalid value for ethtool-duplex = %s. Must be half|full." % val)
-    if oc.has_key('ethtool-autoneg'):
-        val = oc['ethtool-autoneg']
-        if val in ["true", "on"]:
-            settings += ['autoneg', 'on']
-        elif val in ["false", "off"]:
-            settings += ['autoneg', 'off']
-        else:
-            log("Invalid value for ethtool-autoneg = %s. Must be on|true|off|false." % val)
-
-    # Options for "ethtool -K"
-    offload = []
-    for opt in ("rx", "tx", "sg", "tso", "ufo", "gso"):
-        if oc.has_key("ethtool-" + opt):
-            val = oc["ethtool-" + opt]
-            if val in ["true", "on"]:
-                offload += [opt, 'on']
-            elif val in ["false", "off"]:
-                offload += [opt, 'off']
+    is_dnsdev = peerdns_pif == pif
+    is_gatewaydev = defaultroute_pif == pif
+
+    if is_dnsdev or is_gatewaydev:
+        fnetwork = ConfigurationFile(root_prefix() + "/etc/sysconfig/network")
+        for line in fnetwork.readlines():
+            if is_dnsdev and line.lstrip().startswith('DNSDEV='):
+                fnetwork.write('DNSDEV=%s\n' % ipdev)
+                is_dnsdev = False
+            elif is_gatewaydev and line.lstrip().startswith('GATEWAYDEV='):
+                fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
+                is_gatewaydev = False
             else:
-                log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val))
+                fnetwork.write(line)
 
-    return settings, offload
+        if is_dnsdev:
+            fnetwork.write('DNSDEV=%s\n' % ipdev)
+        if is_gatewaydev:
+            fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
 
-def configure_netdev(pif):
-    pifrec = db.get_pif_record(pif)
-    datapath = datapath_name(pif)
-    ipdev = ipdev_name(pif)
+        fnetwork.close()
+        f.attach_child(fnetwork)
 
-    host = pifrec['host']
-    nw = pifrec['network']
-    nwrec = db.get_network_record(nw)
+    return f
 
-    ifconfig_argv = ['/sbin/ifconfig', ipdev, 'up']
-    gateway = ''
-    if pifrec['ip_configuration_mode'] == "DHCP":
-        pass
-    elif pifrec['ip_configuration_mode'] == "Static":
-        ifconfig_argv += [pifrec['IP']]
-        ifconfig_argv += ['netmask', pifrec['netmask']]
-        gateway = pifrec['gateway']
-    elif pifrec['ip_configuration_mode'] == "None":
-        # Nothing to do.
-        pass
-    else:
-        raise Error("Unknown IP-configuration-mode %s" % pifrec['ip_configuration_mode'])
+#
+# Toplevel actions
+#
 
-    oc = {}
-    if pifrec.has_key('other_config'):
-        oc = pifrec['other_config']
-        if oc.has_key('mtu'):
-            int(oc['mtu'])      # Check that the value is an integer
-            ifconfig_argv += ['mtu', oc['mtu']]
+def action_up(pif, force):
+    pifrec = db().get_pif_record(pif)
 
-    run_command(ifconfig_argv)
-    
-    (peerdns_pif, defaultroute_pif) = find_distinguished_pifs(pif)
-
-    if peerdns_pif == pif:
-        f = ConfigurationFile('resolv.conf', "/etc")
-        if oc.has_key('domain'):
-            f.write("search %s\n" % oc['domain'])
-        for dns in pifrec['DNS'].split(","): 
-            f.write("nameserver %s\n" % dns)
-        f.close()
-        f.apply()
-        f.commit()
+    ipdev = pif_ipdev_name(pif)
+    dp = DatapathFactory()(pif)
 
-    if defaultroute_pif == pif and gateway != '':
-        run_command(['/sbin/ip', 'route', 'replace', 'default',
-                     'via', gateway, 'dev', ipdev])
-    
-    if oc.has_key('static-routes'):
-        for line in oc['static-routes'].split(','):
-            network, masklen, gateway = line.split('/')
-            run_command(['/sbin/ip', 'route', 'add',
-                         '%s/%s' % (netmask, masklen), 'via', gateway,
-                         'dev', ipdev])
-
-    settings, offload = ethtool_settings(oc)
-    if settings:
-        run_command(['/sbin/ethtool', '-s', ipdev] + settings)
-    if offload:
-        run_command(['/sbin/ethtool', '-K', ipdev] + offload)
+    log("action_up: %s" % ipdev)
 
-    if pifrec['ip_configuration_mode'] == "DHCP":
-        print
-        print "Determining IP information for %s..." % ipdev,
-        argv = ['/sbin/dhclient', '-q',
-                '-lf', '/var/lib/dhclient/dhclient-%s.leases' % ipdev,
-                '-pf', '/var/run/dhclient-%s.pid' % ipdev,
-                ipdev]
-        if run_command(argv):
-            print 'done.'
-        else:
-            print 'failed.'
-
-def modify_config(commands):
-    run_command(['/root/vswitch/bin/ovs-cfg-mod', '-vANY:console:emer',
-                 '-F', '/etc/ovs-vswitchd.conf']
-                + commands + ['-c'])
-    run_command(['/sbin/service', 'vswitch', 'reload'])
-
-def is_bond_pif(pif):
-    pifrec = db.get_pif_record(pif)
-    return len(pifrec['bond_master_of']) != 0
-
-def configure_bond(pif):
-    pifrec = db.get_pif_record(pif)
-    interface = interface_name(pif)
-    ipdev = ipdev_name(pif)
-    datapath = datapath_name(pif)
-    physdevs = physdev_names(pif)
-
-    argv = ['--del-match=bonding.%s.[!0-9]*' % interface]
-    argv += ["--add=bonding.%s.slave=%s" % (interface, slave)
-             for slave in physdevs]
-
-    # Bonding options.
-    bond_options = { 
-        "mode":   "balance-slb",
-        "miimon": "100",
-        "downdelay": "200",
-        "updelay": "31000",
-        "use_carrier": "1",
-        }
-    # override defaults with values from other-config whose keys
-    # being with "bond-"
-    oc = pifrec['other_config']
-    overrides = filter(lambda (key,val):
-                           key.startswith("bond-"), oc.items())
-    overrides = map(lambda (key,val): (key[5:], val), overrides)
-    bond_options.update(overrides)
-    for (name,val) in bond_options.items():
-        argv += ["--add=bonding.%s.%s=%s" % (interface, name, val)]
-    return argv
-
-def action_up(pif):
-    pifrec = db.get_pif_record(pif)
-
-    bridge = bridge_name(pif)
-    interface = interface_name(pif)
-    ipdev = ipdev_name(pif)
-    datapath = datapath_name(pif)
-    physdevs = physdev_names(pif)
-    vlan_slave = None
-    if pifrec['VLAN'] != '-1':
-        vlan_slave = get_vlan_slave_of_pif(pif)
-    if vlan_slave and is_bond_pif(vlan_slave):
-        bond_master = vlan_slave
-    elif is_bond_pif(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)
+    f = ipdev_configure_network(pif, dp)
+
+    dp.preconfigure(f)
 
-    # Support "rpm -e vswitch" gracefully by keeping Centos configuration
-    # files up-to-date, even though we don't use them or need them.
-    f = configure_pif(pif)
-    mode = pifrec['ip_configuration_mode']
-    if bridge:
-        log("Configuring %s using %s configuration" % (bridge, mode))
-        br = open_network_ifcfg(pif)
-        configure_network(pif, br)
-        br.close()
-        f.attach_child(br)
-    else:
-        log("Configuring %s using %s configuration" % (interface, mode))
-        configure_network(pif, f)
     f.close()
-    for master in bond_masters:
-        master_bridge = bridge_name(master)
-        removed = unconfigure_pif(master)
-        f.attach_child(removed)
-        if master_bridge:
-            removed = open_network_ifcfg(master)
-            log("Unlinking stale file %s" % removed.path())
-            removed.unlink()
-            f.attach_child(removed)
-
-    # /etc/xensource/scripts/vif needs to know where to add VIFs.
-    if vlan_slave:
-        if not os.path.exists(vswitch_config_dir):
-            os.mkdir(vswitch_config_dir)
-        br = ConfigurationFile("br-%s" % bridge, vswitch_config_dir)
-        br.write("VLAN_SLAVE=%s\n" % datapath)
-        br.write("VLAN_VID=%s\n" % pifrec['VLAN'])
-        br.close()
-        f.attach_child(br)
-
-    # Update all configuration files (both ours and Centos's).
-    f.apply()
-    f.commit()
-
-    # "ifconfig down" the network device and delete its IP address, etc.
-    down_netdev(ipdev)
-    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:
-        del_ports += [interface_name(bond_master)]
-    
-    # What ports do we need to add to the datapath?
-    #
-    # We definitely need the ipdev, and ordinarily we want the
-    # physical devices too, but for bonds we need the bond as bridge
-    # port.
-    add_ports = [ipdev, datapath]
-    if not bond_master:
-        add_ports += physdevs
-    else:
-        add_ports += [interface_name(bond_master)]
 
-    # 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.
-    #    
-    #  - The physical devices, since they will either be in add_ports
-    #    or added to the bonding device (see below).
-    #
-    #  - The bond masters for pif.  (Ordinarily pif shouldn't have any
-    #    bond masters.  If it does then interface-reconfigure is
-    #    implicitly being asked to take them down.)
-    del_ports = add_ports + physdevs + bond_masters
+    pif_rename_physical_devices(pif)
+
+    # if we are not forcing the interface up then attempt to tear down
+    # any existing devices which might interfere with brinign this one
+    # up.
+    if not force:
+        ifdown(ipdev)
+
+        dp.bring_down_existing()
 
-    # What networks does this datapath carry?
-    #
-    # - The network corresponding to the datapath's PIF.
-    #
-    # - The networks corresponding to any VLANs attached to the
-    #   datapath's PIF.
-    network_uuids = []
-    for nwpif in db.get_pifs_by_record({'device': pifrec['device'],
-                                        'host': pifrec['host']}):
-        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):
-        argv += interface_deconfigure_commands(port)
-    for port in set(add_ports):
-        argv += ['--add=bridge.%s.port=%s' % (datapath, port)]
-    if vlan_slave:
-        argv += ['--add=vlan.%s.tag=%s' % (ipdev, pifrec['VLAN'])]
-        argv += ['--add=iface.%s.internal=true' % (ipdev)]
-
-        # xapi creates a bridge by the name of the ipdev and requires
-        # that the IP address will be on it.  We need to delete this
-        # bridge because we need that device to be a member of our
-        # datapath.
-        argv += ['--del-match=bridge.%s.[!0-9]*' % ipdev]
-
-        # xapi insists that its attempts to create the bridge succeed,
-        # so force that to happen.
-        argv += ['--add=iface.%s.fake-bridge=true' % (ipdev)]
-    else:
-        try:
-            os.unlink("%s/br-%s" % (vswitch_config_dir, bridge))
-        except OSError:
-            pass
-    argv += ['--del-match=bridge.%s.xs-network-uuids=*' % datapath]
-    argv += ['--add=bridge.%s.xs-network-uuids=%s' % (datapath, uuid)
-             for uuid in set(network_uuids)]
-    if bond_master:
-        argv += configure_bond(bond_master)
-    modify_config(argv)
-
-    # Configure network devices.
-    configure_netdev(pif)
-
-    # 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 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)    
-    interface = interface_name(pif)
-    bridge = bridge_name(pif)
-    ipdev = ipdev_name(pif)
-
-    # Support "rpm -e vswitch" gracefully by keeping Centos configuration
-    # files up-to-date, even though we don't use them or need them.
-    f = unconfigure_pif(pif)
-    if bridge:
-        br = open_network_ifcfg(pif)
-        log("Unlinking stale file %s" % br.path())
-        br.unlink()
-        f.attach_child(br)
     try:
         f.apply()
+
+        dp.configure()
+
+        ifup(ipdev)
+
+        dp.post()
+
+        # Update /etc/issue (which contains the IP address of the management interface)
+        os.system(root_prefix() + "/sbin/update-issue")
+
         f.commit()
     except Error, e:
-        log("action_down failed to apply changes: %s" % e.msg)
+        log("failed to apply changes: %s" % e.msg)
         f.revert()
         raise
 
-    argv = []
-    if rec['VLAN'] != '-1':
-        # Get rid of the VLAN device itself.
-        down_netdev(ipdev)
-        argv += interface_deconfigure_commands(ipdev)
-
-        # If the VLAN's slave is attached, stop here.
-        slave = get_vlan_slave_of_pif(pif)
-        if db.get_pif_record(slave)['currently_attached']:
-            log("VLAN slave is currently attached")
-            modify_config(argv)
-            return
-        
-        # If the VLAN's slave has other VLANs that are attached, stop here.
-        masters = get_vlan_masters_of_pif(slave)
-        for m in masters:
-            if m != pif and db.get_pif_record(m)['currently_attached']:
-                log("VLAN slave has other master %s" % interface_naem(m))
-                modify_config(argv)
-                return
-
-        # Otherwise, take down the VLAN's slave too.
-        log("No more masters, bring down vlan slave %s" % interface_name(slave))
-        pif = slave
+def action_down(pif):
+    ipdev = pif_ipdev_name(pif)
+    dp = DatapathFactory()(pif)
+
+    log("action_down: %s" % ipdev)
+
+    ifdown(ipdev)
+
+    dp.bring_down()
+
+def action_rewrite():
+    DatapathFactory().rewrite()
+    
+# This is useful for reconfiguring the mgmt interface after having lost connectivity to the pool master
+def action_force_rewrite(bridge, config):
+    def getUUID():
+        import subprocess
+        uuid,_ = subprocess.Popen(['uuidgen'], stdout = subprocess.PIPE).communicate()
+        return uuid.strip()
+
+    # Notes:
+    # 1. that this assumes the interface is bridged
+    # 2. If --gateway is given it will make that the default gateway for the host
+
+    # extract the configuration
+    try:
+        mode = config['mode']
+        mac = config['mac']
+        interface = config['device']
+    except:
+        raise Usage("Please supply --mode, --mac and --device")
+
+    if mode == 'static':
+        try:
+            netmask = config['netmask']
+            ip = config['ip']
+        except:
+            raise Usage("Please supply --netmask and --ip")
+        try:
+            gateway = config['gateway']
+        except:
+            gateway = None
+    elif mode != 'dhcp':
+        raise Usage("--mode must be either static or dhcp")
+
+    if config.has_key('vlan'):
+        is_vlan = True
+        vlan_slave, vlan_vid = config['vlan'].split('.')
     else:
-        # Stop here if this PIF has attached VLAN masters.
-        vlan_masters = get_vlan_masters_of_pif(pif)
-        log("VLAN masters of %s - %s" % (rec['device'], [interface_name(m) for m in vlan_masters]))
-        for m in vlan_masters:
-            if db.get_pif_record(m)['currently_attached']:
-                log("Leaving %s up due to currently attached VLAN master %s" % (interface, interface_name(m)))
-                return
-
-    # pif is now either a bond or a physical device which needs to be
-    # brought down.  pif might have changed so re-check all its attributes.
-    rec = db.get_pif_record(pif)
-    interface = interface_name(pif)
-    bridge = bridge_name(pif)
-    ipdev = ipdev_name(pif)
-
-
-    bond_slaves = get_bond_slaves_of_pif(pif)
-    log("bond slaves of %s - %s" % (rec['device'], [interface_name(s) for s in bond_slaves]))
-    for slave in bond_slaves:
-        slave_interface = interface_name(slave)
-        log("bring down bond slave %s" % slave_interface)
-        argv += interface_deconfigure_commands(slave_interface)
-        down_netdev(slave_interface)
-
-    argv += interface_deconfigure_commands(ipdev)
-    down_netdev(ipdev)
-
-    argv += ['--del-match', 'bridge.%s.*' % datapath_name(pif)]
-    argv += ['--del-match', 'bonding.%s.[!0-9]*' % interface]
-    modify_config(argv)
-
-def action_rewrite(pif):
-    # Support "rpm -e vswitch" gracefully by keeping Centos configuration
-    # files up-to-date, even though we don't use them or need them.
-    pifrec = db.get_pif_record(pif)
-    f = configure_pif(pif)
-    interface = interface_name(pif)
-    bridge = bridge_name(pif)
-    mode = pifrec['ip_configuration_mode']
-    if bridge:
-        log("Configuring %s using %s configuration" % (bridge, mode))
-        br = open_network_ifcfg(pif)
-        configure_network(pif, br)
-        br.close()
-        f.attach_child(br)
+        is_vlan = False
+
+    if is_vlan:
+        raise Error("Force rewrite of VLAN not implemented")
+
+    log("Configuring %s using %s configuration" % (bridge, mode))
+
+    f = ConfigurationFile(root_prefix() + dbcache_file)
+
+    pif_uuid = getUUID()
+    network_uuid = getUUID()
+
+    f.write('<?xml version="1.0" ?>\n')
+    f.write('<xenserver-network-configuration>\n')
+    f.write('\t<pif ref="OpaqueRef:%s">\n' % pif_uuid)
+    f.write('\t\t<network>OpaqueRef:%s</network>\n' % network_uuid)
+    f.write('\t\t<management>True</management>\n')
+    f.write('\t\t<uuid>%sPif</uuid>\n' % interface)
+    f.write('\t\t<bond_slave_of>OpaqueRef:NULL</bond_slave_of>\n')
+    f.write('\t\t<bond_master_of/>\n')
+    f.write('\t\t<VLAN_slave_of/>\n')
+    f.write('\t\t<VLAN_master_of>OpaqueRef:NULL</VLAN_master_of>\n')
+    f.write('\t\t<VLAN>-1</VLAN>\n')
+    f.write('\t\t<tunnel_access_PIF_of/>\n')
+    f.write('\t\t<tunnel_transport_PIF_of/>\n')
+    f.write('\t\t<device>%s</device>\n' % interface)
+    f.write('\t\t<MAC>%s</MAC>\n' % mac)
+    f.write('\t\t<other_config/>\n')
+    if mode == 'dhcp':
+        f.write('\t\t<ip_configuration_mode>DHCP</ip_configuration_mode>\n')
+        f.write('\t\t<IP></IP>\n')
+        f.write('\t\t<netmask></netmask>\n')
+        f.write('\t\t<gateway></gateway>\n')
+        f.write('\t\t<DNS></DNS>\n')
+    elif mode == 'static':
+        f.write('\t\t<ip_configuration_mode>Static</ip_configuration_mode>\n')
+        f.write('\t\t<IP>%s</IP>\n' % ip)
+        f.write('\t\t<netmask>%s</netmask>\n' % netmask)
+        if gateway is not None:
+            f.write('\t\t<gateway>%s</gateway>\n' % gateway)
+        f.write('\t\t<DNS></DNS>\n')
     else:
-        log("Configuring %s using %s configuration" % (interface, mode))
-        configure_network(pif, f)
+        raise Error("Unknown mode %s" % mode)
+    f.write('\t</pif>\n')
+
+    f.write('\t<network ref="OpaqueRef:%s">\n' % network_uuid)
+    f.write('\t\t<uuid>InitialManagementNetwork</uuid>\n')
+    f.write('\t\t<PIFs>\n')
+    f.write('\t\t\t<PIF>OpaqueRef:%s</PIF>\n' % pif_uuid)
+    f.write('\t\t</PIFs>\n')
+    f.write('\t\t<bridge>%s</bridge>\n' % bridge)
+    f.write('\t\t<other_config/>\n')
+    f.write('\t</network>\n')
+    f.write('</xenserver-network-configuration>\n')
+
     f.close()
+
     try:
         f.apply()
         f.commit()
@@ -1068,44 +580,39 @@ def action_rewrite(pif):
         f.revert()
         raise
 
-    # We have no code of our own to run here.
-    pass
-
 def main(argv=None):
-    global output_directory, management_pif
-    
+    global management_pif
+
     session = None
     pif_uuid = None
     pif = None
 
     force_interface = None
     force_management = False
-    
+
     if argv is None:
         argv = sys.argv
 
     try:
         try:
             shortops = "h"
-            longops = [ "output-directory=",
-                        "pif=", "pif-uuid=",
+            longops = [ "pif=", "pif-uuid=",
                         "session=",
                         "force=",
                         "force-interface=",
                         "management",
-                        "test-mode",
-                        "device=", "mode=", "ip=", "netmask=", "gateway=",
+                        "mac=", "device=", "mode=", "ip=", "netmask=", "gateway=",
+                        "root-prefix=",
+                        "no-syslog",
                         "help" ]
             arglist, args = getopt.gnu_getopt(argv[1:], shortops, longops)
         except getopt.GetoptError, msg:
             raise Usage(msg)
 
         force_rewrite_config = {}
-        
+
         for o,a in arglist:
-            if o == "--output-directory":
-                output_directory = a
-            elif o == "--pif":
+            if o == "--pif":
                 pif = a
             elif o == "--pif-uuid":
                 pif_uuid = a
@@ -1115,26 +622,33 @@ def main(argv=None):
                 force_interface = a
             elif o == "--management":
                 force_management = True
-            elif o in ["--device", "--mode", "--ip", "--netmask", "--gateway"]:
+            elif o in ["--mac", "--device", "--mode", "--ip", "--netmask", "--gateway"]:
                 force_rewrite_config[o[2:]] = a
+            elif o == "--root-prefix":
+                set_root_prefix(a)
+            elif o == "--no-syslog":
+                set_log_destination("stderr")
             elif o == "-h" or o == "--help":
                 print __doc__ % {'command-name': os.path.basename(argv[0])}
                 return 0
 
-        if not debug_mode():
+        if get_log_destination() == "syslog":
             syslog.openlog(os.path.basename(argv[0]))
             log("Called as " + str.join(" ", argv))
+
         if len(args) < 1:
             raise Usage("Required option <action> not present")
         if len(args) > 1:
             raise Usage("Too many arguments")
 
         action = args[0]
+
+        if not action in ["up", "down", "rewrite", "rewrite-configuration"]:
+            raise Usage("Unknown action \"%s\"" % action)
+
         # backwards compatibility
         if action == "rewrite-configuration": action = "rewrite"
-        
-        if output_directory and ( session or pif ):
-            raise Usage("--session/--pif cannot be used with --output-directory")
+
         if ( session or pif ) and pif_uuid:
             raise Usage("--session/--pif and --pif-uuid are mutually exclusive.")
         if ( session and not pif ) or ( not session and pif ):
@@ -1143,62 +657,62 @@ def main(argv=None):
             raise Usage("--force is mutually exclusive with --session, --pif and --pif-uuid")
         if len(force_rewrite_config) and not (force_interface and action == "rewrite"):
             raise Usage("\"--force rewrite\" needed for --device, --mode, --ip, --netmask, and --gateway")
-
+        if (action == "rewrite") and (pif or pif_uuid ):
+            raise Usage("rewrite action does not take --pif or --pif-uuid")
+        
         global db
         if force_interface:
             log("Force interface %s %s" % (force_interface, action))
 
             if action == "rewrite":
                 action_force_rewrite(force_interface, force_rewrite_config)
-            else:
-                db = DatabaseCache(cache_file=dbcache_file)
-                host = db.extras['host']
-                pif = db.get_pif_by_bridge(host, force_interface)
-                management_pif = db.get_management_pif(host)
+            elif action in ["up", "down"]:
+                db_init_from_cache(dbcache_file)
+                pif = db().get_pif_by_bridge(force_interface)
+                management_pif = db().get_management_pif()
 
                 if action == "up":
-                    action_up(pif)
+                    action_up(pif, True)
                 elif action == "down":
                     action_down(pif)
-                else:
-                    raise Usage("Unknown action %s"  % action)
+            else:
+                raise Error("Unknown action %s"  % action)
         else:
-            db = DatabaseCache(session_ref=session)
+            db_init_from_xenapi(session)
 
             if pif_uuid:
-                pif = db.get_pif_by_uuid(pif_uuid)
-        
-            if not pif:
-                raise Usage("No PIF given")
+                pif = db().get_pif_by_uuid(pif_uuid)
 
-            if force_management:
-                # pif is going to be the management pif 
-                management_pif = pif
+            if action == "rewrite":
+                action_rewrite()
             else:
-                # pif is not going to be the management pif.
-                # Search DB cache for pif on same host with management=true
-                pifrec = db.get_pif_record(pif)
-                host = pifrec['host']
-                management_pif = db.get_management_pif(host)
+                if not pif:
+                    raise Usage("No PIF given")
 
-            log_pif_action(action, pif)
+                if force_management:
+                    # pif is going to be the management pif
+                    management_pif = pif
+                else:
+                    # pif is not going to be the management pif.
+                    # Search DB cache for pif on same host with management=true
+                    pifrec = db().get_pif_record(pif)
+                    management_pif = db().get_management_pif()
 
-            if not check_allowed(pif):
-                return 0
+                log_pif_action(action, pif)
 
-            if action == "up":
-                action_up(pif)
-            elif action == "down":
-                action_down(pif)
-            elif action == "rewrite":
-                action_rewrite(pif)
-            else:
-                raise Usage("Unknown action %s"  % action)
+                if not check_allowed(pif):
+                    return 0
+
+                if action == "up":
+                    action_up(pif, False)
+                elif action == "down":
+                    action_down(pif)
+                else:
+                    raise Error("Unknown action %s"  % action)
 
             # Save cache.
-            pifrec = db.get_pif_record(pif)
-            db.save(dbcache_file, {'host': pifrec['host']})
-        
+            db().save(dbcache_file)
+
     except Usage, err:
         print >>sys.stderr, err.msg
         print >>sys.stderr, "For help use --help."
@@ -1206,405 +720,9 @@ def main(argv=None):
     except Error, err:
         log(err.msg)
         return 1
-    
-    return 0
-\f
-# The following code allows interface-reconfigure to keep Centos
-# network configuration files up-to-date, even though the vswitch
-# never uses them.  In turn, that means that "rpm -e vswitch" does not
-# have to update any configuration files.
-
-def configure_ethtool(oc, f):
-    # Options for "ethtool -s"
-    settings = None
-    setting_opts = ["autoneg", "speed", "duplex"]
-    # Options for "ethtool -K"
-    offload = None
-    offload_opts = ["rx", "tx", "sg", "tso", "ufo", "gso"]
-    
-    for opt in [opt for opt in setting_opts + offload_opts if oc.has_key("ethtool-" + opt)]:
-        val = oc["ethtool-" + opt]
-
-        if opt in ["speed"]:
-            if val in ["10", "100", "1000"]:
-                val = "speed " + val
-            else:
-                log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val)
-                val = None
-        elif opt in ["duplex"]:
-            if val in ["half", "full"]:
-                val = "duplex " + val
-            else:
-                log("Invalid value for ethtool-duplex = %s. Must be half|full." % val)
-                val = None
-        elif opt in ["autoneg"] + offload_opts:
-            if val in ["true", "on"]:
-                val = opt + " on"
-            elif val in ["false", "off"]:
-                val = opt + " off"
-            else:
-                log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val))
-                val = None
-
-        if opt in setting_opts:
-            if val and settings:
-                settings = settings + " " + val
-            else:
-                settings = val
-        elif opt in offload_opts:
-            if val and offload:
-                offload = offload + " " + val
-            else:
-                offload = val
 
-    if settings:
-        f.write("ETHTOOL_OPTS=\"%s\"\n" % settings)
-    if offload:
-        f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % offload)
-
-def configure_mtu(oc, f):
-    if not oc.has_key('mtu'):
-        return
-    
-    try:
-        mtu = int(oc['mtu'])
-        f.write("MTU=%d\n" % mtu)
-    except ValueError, x:
-        log("Invalid value for mtu = %s" % mtu)
-
-def configure_static_routes(interface, oc, f):
-    """Open a route-<interface> file for static routes.
-    
-    Opens the static routes configuration file for interface and writes one
-    line for each route specified in the network's other config "static-routes" value.
-    E.g. if
-           interface ( RO): xenbr1
-           other-config (MRW): static-routes: 172.16.0.0/15/192.168.0.3,172.18.0.0/16/192.168.0.4;...
-
-    Then route-xenbr1 should be
-          172.16.0.0/15 via 192.168.0.3 dev xenbr1
-          172.18.0.0/16 via 192.168.0.4 dev xenbr1
-    """
-    fname = "route-%s" % interface
-    if oc.has_key('static-routes'):
-        # The key is present - extract comma seperates entries
-        lines = oc['static-routes'].split(',')
-    else:
-        # The key is not present, i.e. there are no static routes
-        lines = []
-
-    child = ConfigurationFile(fname)
-    child.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
-            (os.path.basename(child.path()), os.path.basename(sys.argv[0])))
-
-    try:
-        for l in lines:
-            network, masklen, gateway = l.split('/')
-            child.write("%s/%s via %s dev %s\n" % (network, masklen, gateway, interface))
-            
-        f.attach_child(child)
-        child.close()
-
-    except ValueError, e:
-        log("Error in other-config['static-routes'] format for network %s: %s" % (interface, e))
-
-def __open_ifcfg(interface):
-    """Open a network interface configuration file.
-
-    Opens the configuration file for interface, writes a header and
-    common options and returns the file object.
-    """
-    fname = "ifcfg-%s" % interface
-    f = ConfigurationFile(fname)
-    
-    f.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
-            (os.path.basename(f.path()), os.path.basename(sys.argv[0])))
-    f.write("XEMANAGED=yes\n")
-    f.write("DEVICE=%s\n" % interface)
-    f.write("ONBOOT=no\n")
-    
-    return f
-
-def open_network_ifcfg(pif):    
-    bridge = bridge_name(pif)
-    interface = interface_name(pif)
-    if bridge:
-        return __open_ifcfg(bridge)
-    else:
-        return __open_ifcfg(interface)
-
-
-def open_pif_ifcfg(pif):
-    pifrec = db.get_pif_record(pif)
-    
-    log("Configuring %s (%s)" % (interface_name(pif), pifrec['MAC']))
-    
-    f = __open_ifcfg(interface_name(pif))
-
-    if pifrec.has_key('other_config'):
-        configure_ethtool(pifrec['other_config'], f)
-        configure_mtu(pifrec['other_config'], f)
-
-    return f
-
-def configure_network(pif, f):
-    """Write the configuration file for a network.
-
-    Writes configuration derived from the network object into the relevant 
-    ifcfg file.  The configuration file is passed in, but if the network is 
-    bridgeless it will be ifcfg-<interface>, otherwise it will be ifcfg-<bridge>.
-
-    This routine may also write ifcfg files of the networks corresponding to other PIFs
-    in order to maintain consistency.
-
-    params:
-        pif:  Opaque_ref of pif
-        f :   ConfigurationFile(/path/to/ifcfg) to which we append network configuration
-    """
-    
-    pifrec = db.get_pif_record(pif)
-    host = pifrec['host']
-    nw = pifrec['network']
-    nwrec = db.get_network_record(nw)
-    oc = None
-    bridge = bridge_name(pif)
-    interface = interface_name(pif)
-    if bridge:
-        device = bridge
-    else:
-        device = interface
-
-    if nwrec.has_key('other_config'):
-        configure_ethtool(nwrec['other_config'], f)
-        configure_mtu(nwrec['other_config'], f)
-        configure_static_routes(device, nwrec['other_config'], f)
-
-    
-    if pifrec.has_key('other_config'):
-        oc = pifrec['other_config']
-
-    if device == bridge:
-        f.write("TYPE=Bridge\n")
-        f.write("DELAY=0\n")
-        f.write("STP=off\n")
-        f.write("PIFDEV=%s\n" % interface_name(pif))
-
-    if pifrec['ip_configuration_mode'] == "DHCP":
-        f.write("BOOTPROTO=dhcp\n")
-        f.write("PERSISTENT_DHCLIENT=yes\n")
-    elif pifrec['ip_configuration_mode'] == "Static":
-        f.write("BOOTPROTO=none\n") 
-        f.write("NETMASK=%(netmask)s\n" % pifrec)
-        f.write("IPADDR=%(IP)s\n" % pifrec)
-        f.write("GATEWAY=%(gateway)s\n" % pifrec)
-    elif pifrec['ip_configuration_mode'] == "None":
-        f.write("BOOTPROTO=none\n")
-    else:
-        raise Error("Unknown ip-configuration-mode %s" % pifrec['ip_configuration_mode'])
-
-    if pifrec.has_key('DNS') and pifrec['DNS'] != "":
-        ServerList = pifrec['DNS'].split(",")
-        for i in range(len(ServerList)): f.write("DNS%d=%s\n" % (i+1, ServerList[i]))
-    if oc and oc.has_key('domain'):
-        f.write("DOMAIN='%s'\n" % oc['domain'].replace(',', ' '))
-
-    # We only allow one ifcfg-xenbr* to have PEERDNS=yes and there can be only one GATEWAYDEV in /etc/sysconfig/network.
-    # The peerdns pif will be the one with pif::other-config:peerdns=true, or the mgmt pif if none have this set.
-    # The gateway pif will be the one with pif::other-config:defaultroute=true, or the mgmt pif if none have this set.
-
-    # Work out which pif on this host should be the one with PEERDNS=yes and which should be the GATEWAYDEV
-    #
-    # Note: we prune out the bond master pif (if it exists).
-    # This is because when we are called to bring up an interface with a bond master, it is implicit that
-    # we should bring down that master.
-    pifs_on_host = [ __pif for __pif in db.get_all_pifs() if
-                     db.get_pif_record(__pif)['host'] == host and 
-                     (not  __pif in get_bond_masters_of_pif(pif)) ]
-    other_pifs_on_host = [ __pif for __pif in pifs_on_host if __pif != pif ]
-
-    peerdns_pif = None
-    defaultroute_pif = None
-    
-    # loop through all the pifs on this host looking for one with
-    #   other-config:peerdns = true, and one with
-    #   other-config:default-route=true
-    for __pif in pifs_on_host:
-        __pifrec = db.get_pif_record(__pif)
-        __oc = __pifrec['other_config']
-        if __oc.has_key('peerdns') and __oc['peerdns'] == 'true':
-            if peerdns_pif == None:
-                peerdns_pif = __pif
-            else:
-                log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \
-                        (db.get_pif_record(peerdns_pif)['device'], __pifrec['device']))
-        if __oc.has_key('defaultroute') and __oc['defaultroute'] == 'true':
-            if defaultroute_pif == None:
-                defaultroute_pif = __pif
-            else:
-                log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \
-                        (db.get_pif_record(defaultroute_pif)['device'], __pifrec['device']))
-    
-    # If no pif is explicitly specified then use the mgmt pif for peerdns/defaultroute
-    if peerdns_pif == None:
-        peerdns_pif = management_pif
-    if defaultroute_pif == None:
-        defaultroute_pif = management_pif
-        
-    # Update all the other network's ifcfg files and ensure consistency
-    for __pif in other_pifs_on_host:
-        __f = open_network_ifcfg(__pif)
-        peerdns_line_wanted = 'PEERDNS=%s\n' % ((__pif == peerdns_pif) and 'yes' or 'no')
-        lines =  __f.readlines()
-
-        if not peerdns_line_wanted in lines:
-            # the PIF selected for DNS has changed and as a result this ifcfg file needs rewriting
-            for line in lines:
-                if not line.lstrip().startswith('PEERDNS'):
-                    __f.write(line)
-            log("Setting %s in %s" % (peerdns_line_wanted.strip(), __f.path()))
-            __f.write(peerdns_line_wanted)
-            __f.close()
-            f.attach_child(__f)
-
-        else:
-            # There is no need to change this ifcfg file.  So don't attach_child.
-            pass
-        
-    # ... and for this pif too
-    f.write('PEERDNS=%s\n' % ((pif == peerdns_pif) and 'yes' or 'no'))
-    
-    # Update gatewaydev
-    fnetwork = ConfigurationFile("network", "/etc/sysconfig")
-    for line in fnetwork.readlines():
-        if line.lstrip().startswith('GATEWAY') :
-            continue
-        fnetwork.write(line)
-    if defaultroute_pif:
-        gatewaydev = bridge_name(defaultroute_pif)
-        if not gatewaydev:
-            gatewaydev = interface_name(defaultroute_pif)
-        fnetwork.write('GATEWAYDEV=%s\n' % gatewaydev)
-    fnetwork.close()
-    f.attach_child(fnetwork)
-
-    return
-
-
-def configure_physical_interface(pif):
-    """Write the configuration for a physical interface.
-
-    Writes the configuration file for the physical interface described by
-    the pif object.
-
-    Returns the open file handle for the interface configuration file.
-    """
-
-    pifrec = db.get_pif_record(pif)
-
-    f = open_pif_ifcfg(pif)
-    
-    f.write("TYPE=Ethernet\n")
-    f.write("HWADDR=%(MAC)s\n" % pifrec)
-
-    return f
-
-def configure_bond_interface(pif):
-    """Write the configuration for a bond interface.
-
-    Writes the configuration file for the bond interface described by
-    the pif object. Handles writing the configuration for the slave
-    interfaces.
-
-    Returns the open file handle for the bond interface configuration
-    file.
-    """
-
-    pifrec = db.get_pif_record(pif)
-    oc = pifrec['other_config']
-    f = open_pif_ifcfg(pif)
-
-    if pifrec['MAC'] != "":
-        f.write("MACADDR=%s\n" % pifrec['MAC'])
-
-    for slave in get_bond_slaves_of_pif(pif):
-        s = configure_physical_interface(slave)
-        s.write("MASTER=%(device)s\n" % pifrec)
-        s.write("SLAVE=yes\n")
-        s.close()
-        f.attach_child(s)
-
-    # The bond option defaults
-    bond_options = { 
-        "mode":   "balance-slb",
-        "miimon": "100",
-        "downdelay": "200",
-        "updelay": "31000",
-        "use_carrier": "1",
-        }
-
-    # override defaults with values from other-config whose keys being with "bond-"
-    overrides = filter(lambda (key,val): key.startswith("bond-"), oc.items())
-    overrides = map(lambda (key,val): (key[5:], val), overrides)
-    bond_options.update(overrides)
-
-    # write the bond options to ifcfg-bondX
-    f.write('BONDING_OPTS="')
-    for (name,val) in bond_options.items():
-        f.write("%s=%s " % (name,val))
-    f.write('"\n')
-    return f
-
-def configure_vlan_interface(pif):
-    """Write the configuration for a VLAN interface.
-
-    Writes the configuration file for the VLAN interface described by
-    the pif object. Handles writing the configuration for the master
-    interface if necessary.
-
-    Returns the open file handle for the VLAN interface configuration
-    file.
-    """
-
-    slave = configure_pif(get_vlan_slave_of_pif(pif))
-    slave.close()
-
-    f = open_pif_ifcfg(pif)
-    f.write("VLAN=yes\n")
-    f.attach_child(slave)
-    
-    return f
-
-def configure_pif(pif):
-    """Write the configuration for a PIF object.
-
-    Writes the configuration file the PIF and all dependent
-    interfaces (bond slaves and VLAN masters etc).
-
-    Returns the open file handle for the interface configuration file.
-    """
-
-    pifrec = db.get_pif_record(pif)
-
-    if pifrec['VLAN'] != '-1':
-        f = configure_vlan_interface(pif)
-    elif len(pifrec['bond_master_of']) != 0:
-        f = configure_bond_interface(pif)
-    else:
-        f = configure_physical_interface(pif)
-
-    bridge = bridge_name(pif)
-    if bridge:
-        f.write("BRIDGE=%s\n" % bridge)
-
-    return f
+    return 0
 
-def unconfigure_pif(pif):
-    """Clear up the files created by configure_pif"""
-    f = open_pif_ifcfg(pif)
-    log("Unlinking stale file %s" % f.path())
-    f.unlink()
-    return f
-\f
 if __name__ == "__main__":
     rc = 1
     try:
@@ -1615,7 +733,6 @@ if __name__ == "__main__":
         for exline in err:
             log(exline)
 
-    if not debug_mode():
-        syslog.closelog()
-        
+    syslog.closelog()
+
     sys.exit(rc)