netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / xenserver / opt_xensource_libexec_interface-reconfigure
index 5681d02..3b5c861 100755 (executable)
-#!/usr/bin/python
+#!/usr/bin/env python
 #
-# Copyright (c) 2008,2009 Citrix Systems, Inc. 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)
 
-import XenAPI
-import os, sys, getopt, time, signal
+from InterfaceReconfigure import *
+
+import os, sys, getopt
 import syslog
 import traceback
-import time
 import re
 import random
-from xml.dom.minidom import getDOMImplementation
-from xml.dom.minidom import parse as parseXML
-
-output_directory = None
+import syslog
 
-db = None
 management_pif = None
 
-vswitch_state_dir = "/var/lib/openvswitch/"
-dbcache_file = vswitch_state_dir + "dbcache"
+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:
@@ -229,1346 +103,134 @@ def check_allowed(pif):
         pass
     return True
 
-def interface_exists(i):
-    return os.path.exists("/sys/class/net/" + i)
-
-def get_netdev_mac(device):
-    try:
-        return read_first_line_of_file("/sys/class/net/%s/address" % device)
-    except:
-        # Probably no such device.
-        return None
-
-def get_netdev_tx_queue_len(device):
-    try:
-        return int(read_first_line_of_file("/sys/class/net/%s/tx_queue_len"
-                                           % device))
-    except:
-        # Probably no such device.
-        return None
-
-def get_netdev_by_mac(mac):
-    for device in os.listdir("/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
-
 #
-# Helper functions for encoding/decoding database attributes to/from XML.
+# Bare Network Devices -- network devices without IP configuration
 #
-def str_to_xml(xml, parent, tag, val):
-    e = xml.createElement(tag)
-    parent.appendChild(e)
-    v = xml.createTextNode(val)
-    e.appendChild(v)
-def str_from_xml(n):
-    def getText(nodelist):
-        rc = ""
-        for node in nodelist:
-            if node.nodeType == node.TEXT_NODE:
-                rc = rc + node.data
-        return rc
-    return getText(n.childNodes).strip()
-
-
-def bool_to_xml(xml, parent, tag, val):
-    if val:
-        str_to_xml(xml, parent, tag, "True")
-    else:
-        str_to_xml(xml, parent, tag, "False")
-def bool_from_xml(n):
-    s = str_from_xml(n)
-    if s == "True":
-        return True
-    elif s == "False":
-        return False
-    else:
-        raise Error("Unknown boolean value %s" % s);
-
-def strlist_to_xml(xml, parent, ltag, itag, val):
-    e = xml.createElement(ltag)
-    parent.appendChild(e)
-    for v in val:
-        c = xml.createElement(itag)
-        e.appendChild(c)
-        cv = xml.createTextNode(v)
-        c.appendChild(cv)
-def strlist_from_xml(n, ltag, itag):
-    ret = []
-    for n in n.childNodes:
-        if n.nodeName == itag:
-            ret.append(str_from_xml(n))
-    return ret
-
-def otherconfig_to_xml(xml, parent, val, attrs):
-    otherconfig = xml.createElement("other_config")
-    parent.appendChild(otherconfig)
-    for n,v in val.items():
-        if not n in attrs:
-            raise Error("Unknown other-config attribute: %s" % n)
-        str_to_xml(xml, otherconfig, n, v)
-def otherconfig_from_xml(n, attrs):
-    ret = {}
-    for n in n.childNodes:
-        if n.nodeName in attrs:
-            ret[n.nodeName] = str_from_xml(n)
-    return ret
 
-#
-# Definitions of the database objects (and their attributes) used by interface-reconfigure.
-#
-# Each object is defined by a dictionary mapping an attribute name in
-# the xapi database to a tuple containing two items:
-#  - a function which takes this attribute and encodes it as XML.
-#  - a function which takes XML and decocdes it into a value.
-#
-# other-config attributes are specified as a simple array of strings
-
-PIF_XML_TAG = "pif"
-VLAN_XML_TAG = "vlan"
-BOND_XML_TAG = "bond"
-NETWORK_XML_TAG = "network"
-
-ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ]
-
-PIF_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-              'management': (bool_to_xml,bool_from_xml),
-              'network': (str_to_xml,str_from_xml),
-              'device': (str_to_xml,str_from_xml),
-              'bond_master_of': (lambda x, p, t, v: strlist_to_xml(x, p, 'bond_master_of', 'slave', v),
-                                 lambda n: strlist_from_xml(n, 'bond_master_of', 'slave')),
-              'bond_slave_of': (str_to_xml,str_from_xml),
-              'VLAN': (str_to_xml,str_from_xml),
-              'VLAN_master_of': (str_to_xml,str_from_xml),
-              'VLAN_slave_of': (lambda x, p, t, v: strlist_to_xml(x, p, 'VLAN_slave_of', 'master', v),
-                                lambda n: strlist_from_xml(n, 'VLAN_slave_Of', 'master')),
-              'ip_configuration_mode': (str_to_xml,str_from_xml),
-              'IP': (str_to_xml,str_from_xml),
-              'netmask': (str_to_xml,str_from_xml),
-              'gateway': (str_to_xml,str_from_xml),
-              'DNS': (str_to_xml,str_from_xml),
-              'MAC': (str_to_xml,str_from_xml),
-              'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, PIF_OTHERCONFIG_ATTRS),
-                               lambda n: otherconfig_from_xml(n, PIF_OTHERCONFIG_ATTRS)),
-              
-              # Special case: We write the current value
-              # PIF.currently-attached to the cache but since it will
-              # not be valid when we come to use the cache later
-              # (i.e. after a reboot) we always read it as False.
-              'currently_attached': (bool_to_xml, lambda n: False),
-            }
-
-PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 'static-routes' ] + \
-                        [ 'bond-%s' % x for x in 'mode', 'miimon', 'downdelay', 'updelay', 'use_carrier' ] + \
-                        ETHTOOL_OTHERCONFIG_ATTRS
-
-VLAN_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-               'tagged_PIF': (str_to_xml,str_from_xml),
-               'untagged_PIF': (str_to_xml,str_from_xml),
-             }
-    
-BOND_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-               'master': (str_to_xml,str_from_xml),
-               'slaves': (lambda x, p, t, v: strlist_to_xml(x, p, 'slaves', 'slave', v),
-                          lambda n: strlist_from_xml(n, 'slaves', 'slave')),
-             }
-
-NETWORK_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-                  'bridge': (str_to_xml,str_from_xml),
-                  'PIFs': (lambda x, p, t, v: strlist_to_xml(x, p, 'PIFs', 'PIF', v),
-                           lambda n: strlist_from_xml(n, 'PIFs', 'PIF')),
-                  'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, NETWORK_OTHERCONFIG_ATTRS),
-                                   lambda n: otherconfig_from_xml(n, NETWORK_OTHERCONFIG_ATTRS)),
-                }
-
-NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + ETHTOOL_OTHERCONFIG_ATTRS
-
-class DatabaseCache(object):
-    def __read_xensource_inventory(self):
-        filename = "/etc/xensource-inventory"
-        f = open(filename, "r")
-        lines = [x.strip("\n") for x in f.readlines()]
-        f.close()
-
-        defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
-        defs = [ (a, b.strip("'")) for (a,b) in defs ]
-
-        return dict(defs)
-    def __pif_on_host(self,pif):
-        return self.__pifs.has_key(pif)
-
-    def __get_pif_records_from_xapi(self, session, host):
-        self.__pifs = {}
-        for (p,rec) in session.xenapi.PIF.get_all_records().items():
-            if rec['host'] != host:
-                continue
-            self.__pifs[p] = {}
-            for f in PIF_ATTRS:
-                self.__pifs[p][f] = rec[f]
-            self.__pifs[p]['other_config'] = {}
-            for f in PIF_OTHERCONFIG_ATTRS:
-                if not rec['other_config'].has_key(f): continue
-                self.__pifs[p]['other_config'][f] = rec['other_config'][f]
-
-    def __get_vlan_records_from_xapi(self, session):
-        self.__vlans = {}
-        for v in session.xenapi.VLAN.get_all():
-            rec = session.xenapi.VLAN.get_record(v)
-            if not self.__pif_on_host(rec['untagged_PIF']):
-                continue
-            self.__vlans[v] = {}
-            for f in VLAN_ATTRS:
-                self.__vlans[v][f] = rec[f]
-
-    def __get_bond_records_from_xapi(self, session):
-        self.__bonds = {}
-        for b in session.xenapi.Bond.get_all():
-            rec = session.xenapi.Bond.get_record(b)
-            if not self.__pif_on_host(rec['master']):
-                continue
-            self.__bonds[b] = {}
-            for f in BOND_ATTRS:
-                self.__bonds[b][f] = rec[f]
-
-    def __get_network_records_from_xapi(self, session):
-        self.__networks = {}
-        for n in session.xenapi.network.get_all():
-            rec = session.xenapi.network.get_record(n)
-            self.__networks[n] = {}
-            for f in NETWORK_ATTRS:
-                if f == "PIFs":
-                    # drop PIFs on other hosts
-                    self.__networks[n][f] = [p for p in rec[f] if self.__pif_on_host(p)]
-                else:
-                    self.__networks[n][f] = rec[f]
-            self.__networks[n]['other_config'] = {}
-            for f in NETWORK_OTHERCONFIG_ATTRS:
-                if not rec['other_config'].has_key(f): continue
-                self.__networks[n]['other_config'][f] = rec['other_config'][f]
-
-    def __to_xml(self, xml, parent, key, ref, rec, attrs):
-        """Encode a database object as XML"""
-        e = xml.createElement(key)
-        parent.appendChild(e)
-        if ref:
-            e.setAttribute('ref', ref)
-
-        for n,v in rec.items():
-            if attrs.has_key(n):
-                h,_ = attrs[n]
-                h(xml, e, n, v)
-            else:
-                raise Error("Unknown attribute %s" % n)
-    def __from_xml(self, e, attrs):
-        """Decode a database object from XML"""
-        ref = e.attributes['ref'].value
-        rec = {}
-        for n in e.childNodes:
-            if n.nodeName in attrs:
-                _,h = attrs[n.nodeName]
-                rec[n.nodeName] = h(n)
-        return (ref,rec)
-    
-    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")
-        if cache_file == None:
-            session = XenAPI.xapi_local()
-
-            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:
-                
-                inventory = self.__read_xensource_inventory()
-                assert(inventory.has_key('INSTALLATION_UUID'))
-                log("host uuid is %s" % inventory['INSTALLATION_UUID'])
-                
-                host = session.xenapi.host.get_by_uuid(inventory['INSTALLATION_UUID'])
-                
-                self.__get_pif_records_from_xapi(session, host)
-
-                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)
-
-            xml = parseXML(cache_file)
-
-            self.__pifs = {}
-            self.__bonds = {}
-            self.__vlans = {}
-            self.__networks = {}
-
-            assert(len(xml.childNodes) == 1)
-            toplevel = xml.childNodes[0]
-            
-            assert(toplevel.nodeName == "xenserver-network-configuration")
-            
-            for n in toplevel.childNodes:
-                if n.nodeName == "#text":
-                    pass
-                elif n.nodeName == PIF_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, PIF_ATTRS)
-                    self.__pifs[ref] = rec
-                elif n.nodeName == BOND_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, BOND_ATTRS)
-                    self.__bonds[ref] = rec
-                elif n.nodeName == VLAN_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, VLAN_ATTRS)
-                    self.__vlans[ref] = rec
-                elif n.nodeName == NETWORK_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, NETWORK_ATTRS)
-                    self.__networks[ref] = rec
-                else:
-                    raise Error("Unknown XML element %s" % n.nodeName)
-
-    def save(self, cache_file):
-
-        xml = getDOMImplementation().createDocument(
-            None, "xenserver-network-configuration", None)
-        for (ref,rec) in self.__pifs.items():
-            self.__to_xml(xml, xml.documentElement, PIF_XML_TAG, ref, rec, PIF_ATTRS)
-        for (ref,rec) in self.__bonds.items():
-            self.__to_xml(xml, xml.documentElement, BOND_XML_TAG, ref, rec, BOND_ATTRS)
-        for (ref,rec) in self.__vlans.items():
-            self.__to_xml(xml, xml.documentElement, VLAN_XML_TAG, ref, rec, VLAN_ATTRS)
-        for (ref,rec) in self.__networks.items():
-            self.__to_xml(xml, xml.documentElement, NETWORK_XML_TAG, ref, rec,
-                          NETWORK_ATTRS)
-            
-        f = open(cache_file, 'w')
-        f.write(xml.toprettyxml())
-        f.close()
-
-    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_device(self, device):
-        return map(lambda (ref,rec): ref,
-                   filter(lambda (ref,rec): rec['device'] == device,
-                          self.__pifs.items()))
-
-    def get_pif_by_bridge(self, 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 answer:
-                    raise Error("Multiple PIFs on host for network %s" % (bridge))
-                answer = pif
-        if not answer:
-            raise Error("No PIF on host for network %s" % (bridge))
-        return answer
-
-    def get_pif_record(self, pif):
-        if self.__pifs.has_key(pif):
-            return self.__pifs[pif]
-        raise Error("Unknown PIF \"%s\" (get_pif_record)" % 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):
-        """ Returns the management pif on host
-        """
-        all = self.get_all_pifs()
-        for pif in all: 
-            pifrec = self.get_pif_record(pif)
-            if pifrec['management']: return pif
-        return None
+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.
+    """
 
-    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 read1(name):
+        file = None
+        try:
+            file = open(name, 'r')
+            return file.readline().rstrip('\n')
+        finally:
+            if file != None:
+                file.close()
 
-    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:
+    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 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']
-    else:
-        # TODO: sanity check that nwrec['bridgeless'] == 'true'
-        return None
 
-def interface_name(pif):
-    """Construct an interface name from the given PIF record."""
-
-    pifrec = db.get_pif_record(pif)
-
-    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.)
-"""
-
-
-    pifrec = db.get_pif_record(pif)
-
-    if pifrec['VLAN'] == '-1':
-        return bridge_name(pif)
-    else:
-        return bridge_name(get_vlan_slave_of_pif(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.
-"""
-
-    pifrec = db.get_pif_record(pif)
-    return bridge_name(pif)
-
-def get_physdev_pifs(pif):
-    """Return the PIFs for the physical network device(s) associated with pif.
-For a VLAN PIF, this is the VLAN slave's physical device PIF.
-For a bond master PIF, these are the bond slave PIFs.
-For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
-"""
-    pifrec = db.get_pif_record(pif)
-
-    if pifrec['VLAN'] != '-1':
-        return get_physdev_pifs(get_vlan_slave_of_pif(pif))
-    elif len(pifrec['bond_master_of']) != 0:
-        return get_bond_slaves_of_pif(pif)
-    else:
-        return [pif]
-
-def get_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.
-"""
-
-    return [db.get_pif_record(phys)['device'] for phys in get_physdev_pifs(pif)]
-
-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['interface-name'] = interface_name(pif)
-    if action == "rewrite":
-        rec['message'] = "Rewrite PIF %(uuid)s configuration" % rec
-    else:
-        rec['message'] = "Bring %(action)s PIF %(uuid)s" % rec
-    log("%(message)s: %(interface-name)s configured as %(ip_configuration_mode)s" % rec)
-
-def get_bond_masters_of_pif(pif):
-    """Returns a list of PIFs which are bond masters of this PIF"""
-
-    pifrec = db.get_pif_record(pif)
-
-    bso = pifrec['bond_slave_of']
-
-    # 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]
-
-    bondrecs = [db.get_bond_record(bond) for bond in bso]
-    bondrecs = [rec for rec in bondrecs if rec]
-
-    return [bond['master'] for bond in bondrecs]
-
-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)
-
-    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 bondrec['slaves']
-
-def get_vlan_slave_of_pif(pif):
-    """Find the PIF which is the VLAN slave of pif.
-
-Returns the 'physical' PIF underneath the a VLAN PIF @pif."""
-    
-    pifrec = db.get_pif_record(pif)
-
-    vlan = pifrec['VLAN_master_of']
-    if not vlan or vlan == "OpaqueRef:NULL":
-        raise Error("PIF is not a VLAN master")
-
-    vlanrec = db.get_vlan_record(vlan)
-    if not vlanrec:
-        raise Error("No VLAN record found for PIF")
+    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
 
-    return vlanrec['tagged_PIF']
+    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_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
+    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))
 
-def rename_netdev(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))
-
-# 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.
-def remap_pif(pif, already_renamed=[]):
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
     device = pifrec['device']
     mac = pifrec['MAC']
 
     # Is there a network device named 'device' at all?
-    device_exists = interface_exists(device)
+    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:
-        log("No network device %s" % device)
-
-    # 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
-
-    # 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))
-
-    # Rename 'cur_device' to 'device'.
-    rename_netdev(cur_device, device)
-
-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
-    if deconfigure:
-        # Kill dhclient.
-        pidfile_name = '/var/run/dhclient-%s.pid' % interface
-        try:
-            os.kill(int(read_first_line_of_file(pidfile_name)), signal.SIGTERM)
-        except:
-            pass
-
-        # Remove dhclient pidfile.
-        try:
-            os.remove(pidfile_name)
-        except:
-            pass
-        
-        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'])
-
-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.
-
-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."""
-
-    pifrec = db.get_pif_record(pif)
-
-    pifs = [ __pif for __pif in db.get_all_pifs() if
-                     (not  __pif in get_bond_masters_of_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:
-        __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
-
-    return peerdns_pif, defaultroute_pif
-
-def run_ethtool(device, oc):
-    # Run "ethtool -s" if there are any settings.
-    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)
-    if settings:
-        run_command(['/sbin/ethtool', '-s', device] + settings)
-
-    # Run "ethtool -K" if there are any offload settings.
-    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']
-            else:
-                log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val))
-    if offload:
-        run_command(['/sbin/ethtool', '-K', device] + offload)
-
-def mtu_setting(oc):
-    if oc.has_key('mtu'):
-        try:
-            int(oc['mtu'])      # Check that the value is an integer
-            return ['mtu', oc['mtu']]
-        except ValueError, x:
-            log("Invalid value for mtu = %s" % mtu)
-    return []
-
-def configure_local_port(pif):
-    pifrec = db.get_pif_record(pif)
-    datapath = datapath_name(pif)
-    ipdev = ipdev_name(pif)
-
-    nw = pifrec['network']
-    nwrec = db.get_network_record(nw)
-
-    pif_oc = pifrec['other_config']
-    nw_oc = nwrec['other_config']
-
-    # IP (except DHCP) and MTU.
-    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'])
-    ifconfig_argv += mtu_setting(nw_oc)
-    run_command(ifconfig_argv)
-    
-    (peerdns_pif, defaultroute_pif) = find_distinguished_pifs(pif)
-
-    # /etc/resolv.conf
-    if peerdns_pif == pif:
-        f = ConfigurationFile('resolv.conf', "/etc")
-        if pif_oc.has_key('domain'):
-            f.write("search %s\n" % pif_oc['domain'])
-        for dns in pifrec['DNS'].split(","): 
-            f.write("nameserver %s\n" % dns)
-        f.close()
-        f.apply()
-        f.commit()
-
-    # Routing.
-    if defaultroute_pif == pif and gateway != '':
-        run_command(['/sbin/ip', 'route', 'replace', 'default',
-                     'via', gateway, 'dev', ipdev])
-    if nw_oc.has_key('static-routes'):
-        for line in nw_oc['static-routes'].split(','):
-            network, masklen, gateway = line.split('/')
-            run_command(['/sbin/ip', 'route', 'add',
-                         '%s/%s' % (network, masklen), 'via', gateway,
-                         'dev', ipdev])
-
-    # Ethtool.
-    run_ethtool(ipdev, nw_oc)
-
-    # DHCP.
-    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 configure_physdev(pif):
-    pifrec = db.get_pif_record(pif)
-    device = pifrec['device']
-    oc = pifrec['other_config']
-
-    run_command(['/sbin/ifconfig', device, 'up'] + mtu_setting(oc))
-    run_ethtool(device, oc)
-
-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)
-    physdev_names = get_physdev_names(pif)
-
-    argv = ['--del-match=bonding.%s.[!0-9]*' % interface]
-    argv += ["--add=bonding.%s.slave=%s" % (interface, slave)
-             for slave in physdev_names]
-    argv += ['--add=bonding.%s.fake-iface=true' % interface]
-
-    if pifrec['MAC'] != "":
-        argv += ['--add=port.%s.mac=%s' % (interface, pifrec['MAC'])]
-
-    # 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)
-    physdev_pifs = get_physdev_pifs(pif)
-    physdev_names = get_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)
-
-    # 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_state_dir):
-            os.mkdir(vswitch_state_dir)
-        br = ConfigurationFile("br-%s" % bridge, vswitch_state_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()
-
-    # Check the MAC address of each network device and remap if
-    # necessary to make names match our expectations.
-    for physdev_pif in physdev_pifs:
-        remap_pif(physdev_pif)
-
-    # "ifconfig down" the network device and delete its IP address, etc.
-    down_netdev(ipdev)
-    for physdev_name in physdev_names:
-        down_netdev(physdev_name)
-
-    # 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] + physdev_names + 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 += physdev_names
-    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 + physdev_names + bond_masters
-
-    # 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_device({'device': pifrec['device']}):
-        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_physdev_pifs = []
-    for slave in bond_slaves:
-        bond_slave_physdev_pifs += get_physdev_pifs(slave)
-    for slave_physdev_pif in set(bond_slave_physdev_pifs):
-        configure_physdev(slave_physdev_pif)
-
-    # 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_state_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)
-
-    # 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_pif in set(physdev_pifs) - set(bond_slave_physdev_pifs):
-        configure_physdev(physdev_pif)
-
-    # Configure network device for local port.
-    configure_local_port(pif)
-
-    # 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()
-        f.commit()
-    except Error, e:
-        log("action_down 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
-    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)
-    else:
-        log("Configuring %s using %s configuration" % (interface, mode))
-        configure_network(pif, f)
-    f.close()
-    try:
-        f.apply()
-        f.commit()
-    except Error, e:
-        log("failed to apply changes: %s" % e.msg)
-        f.revert()
-        raise
-
-    # We have no code of our own to run here.
-    pass
-
-def main(argv=None):
-    global output_directory, 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=",
-                        "session=",
-                        "force=",
-                        "force-interface=",
-                        "management",
-                        "test-mode",
-                        "device=", "mode=", "ip=", "netmask=", "gateway=",
-                        "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":
-                pif = a
-            elif o == "--pif-uuid":
-                pif_uuid = a
-            elif o == "--session":
-                session = a
-            elif o == "--force-interface" or o == "--force":
-                force_interface = a
-            elif o == "--management":
-                force_management = True
-            elif o in ["--device", "--mode", "--ip", "--netmask", "--gateway"]:
-                force_rewrite_config[o[2:]] = a
-            elif o == "-h" or o == "--help":
-                print __doc__ % {'command-name': os.path.basename(argv[0])}
-                return 0
-
-        if not debug_mode():
-            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]
-        # 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 ):
-            raise Usage("--session and --pif must be used together.")
-        if force_interface and ( session or pif or pif_uuid ):
-            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")
-
-        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)
-                pif = db.get_pif_by_bridge(force_interface)
-                management_pif = db.get_management_pif()
+    else:
+        log("No network device %s" % device)
 
-                if action == "up":
-                    action_up(pif)
-                elif action == "down":
-                    action_down(pif)
-                else:
-                    raise Usage("Unknown action %s"  % action)
-        else:
-            db = DatabaseCache(session_ref=session)
+    # 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
 
-            if pif_uuid:
-                pif = db.get_pif_by_uuid(pif_uuid)
-        
-            if not pif:
-                raise Usage("No PIF given")
+    # 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 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()
+    # Rename 'cur_device' to 'device'.
+    rename_netdev(cur_device, device)
 
-            log_pif_action(action, pif)
+#
+# IP Network Devices -- network devices with IP configuration
+#
 
-            if not check_allowed(pif):
-                return 0
+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 action == "up":
-                action_up(pif)
-            elif action == "down":
-                action_down(pif)
-            elif action == "rewrite":
-                action_rewrite(pif)
-            else:
-                raise Usage("Unknown action %s"  % action)
+#
+#
+#
 
-            # Save cache.
-            db.save(dbcache_file)
-        
-    except Usage, err:
-        print >>sys.stderr, err.msg
-        print >>sys.stderr, "For help use --help."
-        return 2
-    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]
+def pif_rename_physical_devices(pif):
+    if pif_is_tunnel(pif):
+        return
 
-        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 pif_is_vlan(pif):
+        pif = pif_get_vlan_slave(pif)
 
-        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 pif_is_bond(pif):
+        pifs = pif_get_bond_slaves(pif)
+    else:
+        pifs = [pif]
 
-    if settings:
-        f.write("ETHTOOL_OPTS=\"%s\"\n" % settings)
-    if offload:
-        f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % offload)
+    for pif in pifs:
+        netdev_remap_name(pif)
 
-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)
+#
+# IP device configuration
+#
 
-def configure_static_routes(interface, oc, f):
+def ipdev_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
@@ -1579,15 +241,14 @@ def configure_static_routes(interface, oc, f):
           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
+        # The key is present - extract comma separates entries
         lines = oc['static-routes'].split(',')
     else:
         # The key is not present, i.e. there are no static routes
         lines = []
 
-    child = ConfigurationFile(fname)
+    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])))
 
@@ -1595,57 +256,34 @@ def configure_static_routes(interface, oc, f):
         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.
+def ipdev_open_ifcfg(pif):
+    ipdev = pif_ipdev_name(pif)
+
+    log("Writing network configuration for %s" % ipdev)
+
+    f = ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), ipdev))
 
-    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("DEVICE=%s\n" % ipdev)
     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)
+    f.write("NOZEROCONF=yes\n")
 
     return f
 
-def configure_network(pif, f):
+def ipdev_configure_network(pif, dp):
     """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 
+    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
@@ -1653,40 +291,31 @@ def configure_network(pif, f):
 
     params:
         pif:  Opaque_ref of pif
-        f :   ConfigurationFile(/path/to/ifcfg) to which we append network configuration
+        dp:   Datapath object
     """
-    
-    pifrec = db.get_pif_record(pif)
+
+    pifrec = db().get_pif_record(pif)
     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
+    nwrec = db().get_network_record(nw)
 
-    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)
+    ipdev = pif_ipdev_name(pif)
 
-    
+    f = ipdev_open_ifcfg(pif)
+
+    mode = pifrec['ip_configuration_mode']
+    log("Configuring %s using %s configuration" % (ipdev, mode))
+
+    oc = None
     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))
+    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("BOOTPROTO=none\n")
         f.write("NETMASK=%(netmask)s\n" % pifrec)
         f.write("IPADDR=%(IP)s\n" % pifrec)
         f.write("GATEWAY=%(gateway)s\n" % pifrec)
@@ -1695,208 +324,405 @@ def configure_network(pif, f):
     else:
         raise Error("Unknown ip-configuration-mode %s" % pifrec['ip_configuration_mode'])
 
+    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))
+
+        ipdev_configure_static_routes(ipdev, nwrec['other_config'], f)
+
+    mtu = mtu_setting(nw, "Network", nwrec['other_config'])
+    if mtu:
+        f.write("MTU=%s\n" % mtu)
+
+
     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.
+    # 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 one with PEERDNS=yes and which should be the GATEWAYDEV
+    # 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 = [ __pif for __pif in db.get_all_pifs() if
-                     not __pif in get_bond_masters_of_pif(pif) ]
-    other_pifs_on_host = [ __pif for __pif in pifs_on_host if __pif != pif ]
+    # 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
-        
-    # 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.
-    """
+    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:
+                fnetwork.write(line)
 
-    pifrec = db.get_pif_record(pif)
+        if is_dnsdev:
+            fnetwork.write('DNSDEV=%s\n' % ipdev)
+        if is_gatewaydev:
+            fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
 
-    f = open_pif_ifcfg(pif)
-    
-    f.write("TYPE=Ethernet\n")
-    f.write("HWADDR=%(MAC)s\n" % pifrec)
+        fnetwork.close()
+        f.attach_child(fnetwork)
 
     return f
 
-def configure_bond_interface(pif):
-    """Write the configuration for a bond interface.
+#
+# Toplevel actions
+#
 
-    Writes the configuration file for the bond interface described by
-    the pif object. Handles writing the configuration for the slave
-    interfaces.
+def action_up(pif, force):
+    pifrec = db().get_pif_record(pif)
 
-    Returns the open file handle for the bond interface configuration
-    file.
-    """
+    ipdev = pif_ipdev_name(pif)
+    dp = DatapathFactory()(pif)
 
-    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
+    log("action_up: %s" % ipdev)
 
-def configure_vlan_interface(pif):
-    """Write the configuration for a VLAN interface.
+    f = ipdev_configure_network(pif, dp)
 
-    Writes the configuration file for the VLAN interface described by
-    the pif object. Handles writing the configuration for the master
-    interface if necessary.
+    dp.preconfigure(f)
 
-    Returns the open file handle for the VLAN interface configuration
-    file.
-    """
+    f.close()
 
-    slave = configure_pif(get_vlan_slave_of_pif(pif))
-    slave.close()
+    pif_rename_physical_devices(pif)
 
-    f = open_pif_ifcfg(pif)
-    f.write("VLAN=yes\n")
-    f.attach_child(slave)
-    
-    return f
+    # 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)
 
-def configure_pif(pif):
-    """Write the configuration for a PIF object.
+        dp.bring_down_existing()
 
-    Writes the configuration file the PIF and all dependent
-    interfaces (bond slaves and VLAN masters etc).
+    try:
+        f.apply()
 
-    Returns the open file handle for the interface configuration file.
-    """
+        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("failed to apply changes: %s" % e.msg)
+        f.revert()
+        raise
+
+def action_down(pif):
+    ipdev = pif_ipdev_name(pif)
+    dp = DatapathFactory()(pif)
+
+    log("action_down: %s" % ipdev)
 
-    pifrec = db.get_pif_record(pif)
+    ifdown(ipdev)
 
-    if pifrec['VLAN'] != '-1':
-        f = configure_vlan_interface(pif)
-    elif len(pifrec['bond_master_of']) != 0:
-        f = configure_bond_interface(pif)
+    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:
-        f = configure_physical_interface(pif)
+        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:
+        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')
 
-    bridge = bridge_name(pif)
-    if bridge:
-        f.write("BRIDGE=%s\n" % bridge)
+    f.close()
 
-    return f
+    try:
+        f.apply()
+        f.commit()
+    except Error, e:
+        log("failed to apply changes: %s" % e.msg)
+        f.revert()
+        raise
+
+def main(argv=None):
+    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 = [ "pif=", "pif-uuid=",
+                        "session=",
+                        "force=",
+                        "force-interface=",
+                        "management",
+                        "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 == "--pif":
+                pif = a
+            elif o == "--pif-uuid":
+                pif_uuid = a
+            elif o == "--session":
+                session = a
+            elif o == "--force-interface" or o == "--force":
+                force_interface = a
+            elif o == "--management":
+                force_management = True
+            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 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 ( 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 ):
+            raise Usage("--session and --pif must be used together.")
+        if force_interface and ( session or pif or pif_uuid ):
+            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)
+            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, True)
+                elif action == "down":
+                    action_down(pif)
+            else:
+                raise Error("Unknown action %s"  % action)
+        else:
+            db_init_from_xenapi(session)
+
+            if pif_uuid:
+                pif = db().get_pif_by_uuid(pif_uuid)
+
+            if action == "rewrite":
+                action_rewrite()
+            else:
+                if not pif:
+                    raise Usage("No PIF given")
+
+                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()
+
+                log_pif_action(action, pif)
+
+                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.
+            db().save(dbcache_file)
+
+    except Usage, err:
+        print >>sys.stderr, err.msg
+        print >>sys.stderr, "For help use --help."
+        return 2
+    except Error, err:
+        log(err.msg)
+        return 1
+
+    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:
@@ -1907,7 +733,6 @@ if __name__ == "__main__":
         for exline in err:
             log(exline)
 
-    if not debug_mode():
-        syslog.closelog()
-        
+    syslog.closelog()
+
     sys.exit(rc)