Merge commit 'origin/citrix'
authorJustin Pettit <jpettit@nicira.com>
Tue, 25 Aug 2009 20:23:11 +0000 (13:23 -0700)
committerJustin Pettit <jpettit@nicira.com>
Tue, 25 Aug 2009 20:23:11 +0000 (13:23 -0700)
1  2 
datapath/datapath.c
ofproto/netflow.c
xenserver/opt_xensource_libexec_interface-reconfigure

diff --combined datapath/datapath.c
@@@ -165,8 -165,7 +165,8 @@@ static void dp_ifinfo_notify(int event
                kfree_skb(skb);
                goto errout;
        }
 -      err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
 +      rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
 +      return;
  errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
@@@ -225,7 -224,9 +225,7 @@@ static int create_dp(int dp_idx, const 
  
        /* Initialize kobject for bridge.  This will be added as
         * /sys/class/net/<devname>/brif later, if sysfs is enabled. */
 -      kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); /* "brif" */
        dp->ifobj.kset = NULL;
 -      dp->ifobj.parent = NULL;
        kobject_init(&dp->ifobj, &dp_ktype);
  
        /* Allocate table. */
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
  
 -#ifdef SUPPORT_SYSFS
        dp_sysfs_add_dp(dp);
 -#endif
  
        return 0;
  
@@@ -283,7 -286,9 +283,7 @@@ static void do_destroy_dp(struct datapa
                if (p->port_no != ODPP_LOCAL)
                        dp_del_port(p);
  
 -#ifdef SUPPORT_SYSFS
        dp_sysfs_del_dp(dp);
 -#endif
  
        rcu_assign_pointer(dps[dp->dp_idx], NULL);
  
@@@ -328,7 -333,7 +328,7 @@@ static void release_nbp(struct kobject 
  }
  
  struct kobj_type brport_ktype = {
 -#ifdef SUPPORT_SYSFS
 +#ifdef CONFIG_SYSFS
        .sysfs_ops = &brport_sysfs_ops,
  #endif
        .release = release_nbp
@@@ -365,7 -370,9 +365,7 @@@ static int new_nbp(struct datapath *dp
  
        /* Initialize kobject for bridge.  This will be added as
         * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
 -      kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); /* "brport" */
        p->kobj.kset = NULL;
 -      p->kobj.parent = &p->dev->NETDEV_DEV_MEMBER.kobj;
        kobject_init(&p->kobj, &brport_ktype);
  
        dp_ifinfo_notify(RTM_NEWLINK, p);
@@@ -385,6 -392,11 +385,6 @@@ static int add_port(int dp_idx, struct 
        if (copy_from_user(&port, portp, sizeof port))
                goto out;
        port.devname[IFNAMSIZ - 1] = '\0';
 -      port_no = port.port;
 -
 -      err = -EINVAL;
 -      if (port_no < 0 || port_no >= DP_MAX_PORTS)
 -              goto out;
  
        rtnl_lock();
        dp = get_dp_locked(dp_idx);
        if (!dp)
                goto out_unlock_rtnl;
  
 -      err = -EEXIST;
 -      if (dp->ports[port_no])
 -              goto out_unlock_dp;
 +      for (port_no = 1; port_no < DP_MAX_PORTS; port_no++)
 +              if (!dp->ports[port_no])
 +                      goto got_port_no;
 +      err = -EXFULL;
 +      goto out_unlock_dp;
  
 +got_port_no:
        if (!(port.flags & ODP_PORT_INTERNAL)) {
                err = -ENODEV;
                dev = dev_get_by_name(&init_net, port.devname);
        if (err)
                goto out_put;
  
 -#ifdef SUPPORT_SYSFS
        dp_sysfs_add_if(dp->ports[port_no]);
 -#endif
 +
 +      err = __put_user(port_no, &port.port);
  
  out_put:
        dev_put(dev);
@@@ -439,8 -448,10 +439,8 @@@ int dp_del_port(struct net_bridge_port 
  {
        ASSERT_RTNL();
  
 -#ifdef SUPPORT_SYSFS
        if (p->port_no != ODPP_LOCAL)
                dp_sysfs_del_if(p);
 -#endif
        dp_ifinfo_notify(RTM_DELLINK, p);
  
        p->dp->n_ports--;
@@@ -576,7 -587,7 +576,7 @@@ static int dp_frame_hook(struct net_bri
  #error
  #endif
  
 -#ifdef CONFIG_XEN
 +#if defined(CONFIG_XEN) && LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
  /* This code is copied verbatim from net/dev/core.c in Xen's
   * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644.  We can't call those functions
   * directly because they aren't exported. */
@@@ -592,7 -603,7 +592,7 @@@ static int skb_pull_up_to(struct sk_buf
        }
  }
  
 -int skb_checksum_setup(struct sk_buff *skb)
 +int vswitch_skb_checksum_setup(struct sk_buff *skb)
  {
        if (skb->proto_csum_blank) {
                if (skb->protocol != htons(ETH_P_IP))
  out:
        return -EPROTO;
  }
 -#endif
 +#else
 +int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; }
 +#endif /* CONFIG_XEN && linux == 2.6.18 */
  
  int
  dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no,
         * the non-Xen case, but it is difficult to trigger or test this case
         * there, hence the WARN_ON_ONCE().
         */
 -      err = skb_checksum_setup(skb);
 +      err = vswitch_skb_checksum_setup(skb);
        if (err)
                goto err_kfree_skb;
  #ifndef CHECKSUM_HW
@@@ -827,7 -836,6 +827,7 @@@ static void get_stats(struct sw_flow *f
        stats->n_bytes = flow->byte_count;
        stats->ip_tos = flow->ip_tos;
        stats->tcp_flags = flow->tcp_flags;
 +      stats->error = 0;
  }
  
  static void clear_stats(struct sw_flow *flow)
@@@ -857,7 -865,7 +857,7 @@@ retry
        bucket = dp_table_lookup_for_insert(table, &uf.flow.key);
        if (!bucket) {
                /* No such flow, and the slots where it could go are full. */
-               error = uf.flags & ODPPF_CREATE ? -EXFULL : -ENOENT;
+               error = uf.flags & ODPPF_CREATE ? -EFBIG : -ENOENT;
                goto error;
        } else if (!*bucket) {
                /* No such flow, but we found an available slot for it. */
@@@ -956,6 -964,8 +956,6 @@@ static int put_actions(const struct sw_
  
        if (!n_actions)
                return 0;
 -      if (ufp->n_actions > INT_MAX / sizeof(union odp_action))
 -              return -EINVAL;
  
        sf_acts = rcu_dereference(flow->sf_acts);
        if (__put_user(sf_acts->n_actions, &ufp->n_actions) ||
@@@ -981,7 -991,9 +981,7 @@@ static int answer_query(struct sw_flow 
        return put_actions(flow, ufp);
  }
  
 -static int del_or_query_flow(struct datapath *dp,
 -                           struct odp_flow __user *ufp,
 -                           unsigned int cmd)
 +static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
  {
        struct dp_table *table = rcu_dereference(dp->table);
        struct odp_flow uf;
        if (!flow)
                goto error;
  
 -      if (cmd == ODP_FLOW_DEL) {
 -              /* XXX redundant lookup */
 -              error = dp_table_delete(table, flow);
 -              if (error)
 -                      goto error;
 +      /* XXX redundant lookup */
 +      error = dp_table_delete(table, flow);
 +      if (error)
 +              goto error;
  
 -              /* XXX These statistics might lose a few packets, since other
 -               * CPUs can be using this flow.  We used to synchronize_rcu()
 -               * to make sure that we get completely accurate stats, but that
 -               * blows our performance, badly. */
 -              dp->n_flows--;
 -              error = answer_query(flow, ufp);
 -              flow_deferred_free(flow);
 -      } else {
 -              error = answer_query(flow, ufp);
 -      }
 +      /* XXX These statistics might lose a few packets, since other CPUs can
 +       * be using this flow.  We used to synchronize_rcu() to make sure that
 +       * we get completely accurate stats, but that blows our performance,
 +       * badly. */
 +      dp->n_flows--;
 +      error = answer_query(flow, ufp);
 +      flow_deferred_free(flow);
  
  error:
        return error;
  }
  
 -static int query_multiple_flows(struct datapath *dp,
 -                              const struct odp_flowvec *flowvec)
 +static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
  {
        struct dp_table *table = rcu_dereference(dp->table);
        int i;
  
                flow = dp_table_lookup(table, &uf.key);
                if (!flow)
 -                      error = __clear_user(&ufp->stats, sizeof ufp->stats);
 +                      error = __put_user(ENOENT, &ufp->stats.error);
                else
                        error = answer_query(flow, ufp);
                if (error)
@@@ -1164,7 -1181,8 +1164,7 @@@ error
        return err;
  }
  
 -static int
 -get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
 +static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
  {
        struct odp_stats stats;
        int i;
@@@ -1279,7 -1297,7 +1279,7 @@@ list_ports(struct datapath *dp, struct 
                                break;
                }
        }
 -      return put_user(idx, &pvp->n_ports);
 +      return put_user(dp->n_ports, &pvp->n_ports);
  }
  
  /* RCU callback for freeing a dp_port_group */
@@@ -1363,28 -1381,24 +1363,28 @@@ static long openvswitch_ioctl(struct fi
        /* Handle commands with special locking requirements up front. */
        switch (cmd) {
        case ODP_DP_CREATE:
 -              return create_dp(dp_idx, (char __user *)argp);
 +              err = create_dp(dp_idx, (char __user *)argp);
 +              goto exit;
  
        case ODP_DP_DESTROY:
 -              return destroy_dp(dp_idx);
 +              err = destroy_dp(dp_idx);
 +              goto exit;
  
        case ODP_PORT_ADD:
 -              return add_port(dp_idx, (struct odp_port __user *)argp);
 +              err = add_port(dp_idx, (struct odp_port __user *)argp);
 +              goto exit;
  
        case ODP_PORT_DEL:
                err = get_user(port_no, (int __user *)argp);
 -              if (err)
 -                      break;
 -              return del_port(dp_idx, port_no);
 +              if (!err)
 +                      err = del_port(dp_idx, port_no);
 +              goto exit;
        }
  
        dp = get_dp_locked(dp_idx);
 +      err = -ENODEV;
        if (!dp)
 -              return -ENODEV;
 +              goto exit;
  
        switch (cmd) {
        case ODP_DP_STATS:
                break;
  
        case ODP_FLOW_DEL:
 -      case ODP_FLOW_GET:
 -              err = del_or_query_flow(dp, (struct odp_flow __user *)argp,
 -                                      cmd);
 +              err = del_flow(dp, (struct odp_flow __user *)argp);
                break;
  
 -      case ODP_FLOW_GET_MULTIPLE:
 -              err = do_flowvec_ioctl(dp, argp, query_multiple_flows);
 +      case ODP_FLOW_GET:
 +              err = do_flowvec_ioctl(dp, argp, query_flows);
                break;
  
        case ODP_FLOW_LIST:
                break;
        }
        mutex_unlock(&dp->mutex);
 +exit:
        return err;
  }
  
diff --combined ofproto/netflow.c
@@@ -197,7 -197,6 +197,6 @@@ netflow_expire(struct netflow *nf, cons
          uint16_t iface = (nf->engine_id & 0x7f) << 9;
          nf_rec->input = htons(iface | (expired->flow.in_port & 0x1ff));
          nf_rec->output = htons(iface);
-         printf("input: %x\n", ntohs(nf_rec->input));
      } else {
          nf_rec->input = htons(expired->flow.in_port);
          nf_rec->output = htons(0);
@@@ -62,9 -62,8 +62,9 @@@ import syslo
  import traceback
  import time
  import re
 -import pickle
  import random
 +from xml.dom.minidom import getDOMImplementation
 +from xml.dom.minidom import parse as parseXML
  
  output_directory = None
  
@@@ -273,215 -272,11 +273,215 @@@ def get_netdev_by_mac(mac)
                  return device
      return None
  
 +#
 +# Helper functions for encoding/decoding database attributes to/from XML.
 +#
 +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)),
 +            }
 +
 +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:
 +                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()
  
                  session._session = session_ref
  
              try:
 -                self.__vlans = session.xenapi.VLAN.get_all_records()
 -                self.__bonds = session.xenapi.Bond.get_all_records()
 -                self.__pifs = session.xenapi.PIF.get_all_records()
 -                self.__networks = session.xenapi.network.get_all_records()
 +                
 +                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)
 -            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']
 +            xml = parseXML(cache_file)
 +
 +            self.__pifs = {}
 +            self.__bonds = {}
 +            self.__vlans = {}
 +            self.__networks = {}
  
 -    def save(self, cache_file, extras):
 +            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')
 -        pickle.dump({'vlans': self.__vlans,
 -                     'bonds': self.__bonds,
 -                     'pifs': self.__pifs,
 -                     'networks': self.__networks}, f)
 -        pickle.dump(extras, f)
 +        f.write(xml.toprettyxml())
          f.close()
  
      def get_pif_by_uuid(self, 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
 -            
 +    def get_pifs_by_device(self, device):
          return map(lambda (ref,rec): ref,
 -                   filter(lambda (ref,rec): match(rec),
 +                   filter(lambda (ref,rec): rec['device'] == device,
                            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):
 +    def get_pif_by_bridge(self, bridge):
          networks = map(lambda (ref,rec): ref,
                         filter(lambda (ref,rec): rec['bridge'] == bridge,
                                self.__networks.items()))
              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))
 +                    raise Error("Multiple PIFs on host for network %s" % (bridge))
                  answer = pif
          if not answer:
 -            raise Error("No PIF on %s for network %s" % (host, bridge))
 +            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\"" % 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, host):
 +    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'] and pifrec['host'] == host :
 -                return pif
 +            if pifrec['management']: return pif
          return None
  
      def get_network_record(self, network):
@@@ -660,7 -441,6 +660,7 @@@ For a VLAN PIF, the datapath name is th
  use it.)
  """
  
 +
      pifrec = db.get_pif_record(pif)
  
      if pifrec['VLAN'] == '-1':
@@@ -683,10 -463,11 +683,10 @@@ For a VLAN PIF, this is the VLAN slave'
  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_vlan_slave_of_pif(pif)]
+         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:
@@@ -703,16 -484,13 +703,16 @@@ For a non-VLAN, non-bond master PIF, th
  
  def log_pif_action(action, pif):
      pifrec = db.get_pif_record(pif)
 -    pifrec['action'] = action
 -    pifrec['interface-name'] = interface_name(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":
 -        pifrec['message'] = "Rewrite PIF %(uuid)s configuration" % pifrec
 +        rec['message'] = "Rewrite PIF %(uuid)s configuration" % rec
      else:
 -        pifrec['message'] = "Bring %(action)s PIF %(uuid)s" % pifrec
 -    log("%(message)s: %(interface-name)s configured as %(ip_configuration_mode)s" % pifrec)
 +        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"""
@@@ -738,6 -516,7 +738,6 @@@ 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']
  
      bmo = pifrec['bond_master_of']
      if len(bmo) > 1:
@@@ -878,8 -657,10 +878,8 @@@ This is because when we are called to b
  we should bring down that master."""
  
      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 
 +    pifs = [ __pif for __pif in db.get_all_pifs() if
                       (not  __pif in get_bond_masters_of_pif(pif)) ]
  
      peerdns_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:
 +    for __pif in pifs:
          __pifrec = db.get_pif_record(__pif)
          __oc = __pifrec['other_config']
          if __oc.has_key('peerdns') and __oc['peerdns'] == 'true':
@@@ -966,6 -747,7 +966,6 @@@ def configure_local_port(pif)
      datapath = datapath_name(pif)
      ipdev = ipdev_name(pif)
  
 -    host = pifrec['host']
      nw = pifrec['network']
      nwrec = db.get_network_record(nw)
  
@@@ -1198,7 -980,8 +1198,7 @@@ def action_up(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']}):
 +    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']]
  
@@@ -1457,8 -1240,9 +1457,8 @@@ def main(argv=None)
                  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)
 +                pif = db.get_pif_by_bridge(force_interface)
 +                management_pif = db.get_management_pif()
  
                  if action == "up":
                      action_up(pif)
                  # 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)
 +                management_pif = db.get_management_pif()
  
              log_pif_action(action, pif)
  
  
              # 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
@@@ -1666,6 -1451,7 +1666,6 @@@ def configure_network(pif, f)
      """
      
      pifrec = db.get_pif_record(pif)
 -    host = pifrec['host']
      nw = pifrec['network']
      nwrec = db.get_network_record(nw)
      oc = None
      # 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)) ]
 +                     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