Merge citrix into master.
authorBen Pfaff <blp@nicira.com>
Wed, 19 Aug 2009 20:03:46 +0000 (13:03 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 19 Aug 2009 20:03:46 +0000 (13:03 -0700)
This was a somewhat difficult merge since there was a fair amount of
superficially divergent development on the two branches, especially in the
datapath.

This has been build-tested against XenServer 5.5.0 and XenServer 5.7.0
build 15122.  It has been booted and connected to XenCenter on 5.5.0.

The merge revealed a couple of outstanding bugs, which will be fixed on
citrix and then merged back into master.

27 files changed:
1  2 
datapath/datapath.c
datapath/datapath.h
datapath/dp_dev.c
datapath/dp_sysfs.h
datapath/dp_sysfs_dp.c
datapath/dp_sysfs_if.c
datapath/linux-2.6/compat-2.6/include/linux/kobject.h
debian/openvswitch-switch.template
include/openvswitch/datapath-protocol.h
lib/dhcp-client.c
lib/rconn.c
ofproto/fail-open.c
ofproto/netflow.c
ofproto/ofproto.c
ofproto/ofproto.h
utilities/ovs-discover.8.in
utilities/ovs-discover.c
utilities/ovs-dpctl.8.in
utilities/ovs-dpctl.c
utilities/ovs-openflowd.8.in
utilities/ovs-openflowd.c
vswitchd/bridge.c
vswitchd/ovs-brcompatd.c
vswitchd/ovs-vswitchd.c
vswitchd/ovs-vswitchd.conf.5.in
xenserver/opt_xensource_libexec_interface-reconfigure
xenserver/vswitch-xen.spec

@@@ -222,13 -225,6 +223,11 @@@ static int create_dp(int dp_idx, const 
                skb_queue_head_init(&dp->queues[i]);
        init_waitqueue_head(&dp->waitqueue);
  
-       kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); /* "bridge" */
 +      /* Initialize kobject for bridge.  This will be added as
 +       * /sys/class/net/<devname>/bridge later, if sysfs is enabled. */
-       dp->ifobj.parent = NULL;
 +      dp->ifobj.kset = NULL;
 +      kobject_init(&dp->ifobj, &dp_ktype);
 +
        /* Allocate table. */
        err = -ENOMEM;
        rcu_assign_pointer(dp->table, dp_table_create(DP_L1_SIZE));
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
  
- #ifdef SUPPORT_SYSFS
 -      if (dp_add_dp_hook)
 -              dp_add_dp_hook(dp);
 +      dp_sysfs_add_dp(dp);
- #endif
  
        return 0;
  
@@@ -286,9 -281,8 +283,7 @@@ static void do_destroy_dp(struct datapa
                if (p->port_no != ODPP_LOCAL)
                        dp_del_port(p);
  
- #ifdef SUPPORT_SYSFS
 -      if (dp_del_dp_hook)
 -              dp_del_dp_hook(dp);
 +      dp_sysfs_del_dp(dp);
- #endif
  
        rcu_assign_pointer(dps[dp->dp_idx], NULL);
  
@@@ -326,19 -320,6 +321,19 @@@ err_unlock
        return err;
  }
  
- #ifdef SUPPORT_SYSFS
 +static void release_nbp(struct kobject *kobj)
 +{
 +      struct net_bridge_port *p = container_of(kobj, struct net_bridge_port, kobj);
 +      kfree(p);
 +}
 +
 +struct kobj_type brport_ktype = {
++#ifdef CONFIG_SYSFS
 +      .sysfs_ops = &brport_sysfs_ops,
 +#endif
 +      .release = release_nbp
 +};
 +
  /* Called with RTNL lock and dp_mutex. */
  static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
  {
        list_add_rcu(&p->node, &dp->port_list);
        dp->n_ports++;
  
-       kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); /* "brport" */
 +      /* Initialize kobject for bridge.  This will be added as
 +       * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
-       p->kobj.parent = &p->dev->NETDEV_DEV_MEMBER.kobj;
 +      p->kobj.kset = NULL;
 +      kobject_init(&p->kobj, &brport_ktype);
 +
        dp_ifinfo_notify(RTM_NEWLINK, p);
  
        return 0;
@@@ -430,9 -402,10 +421,9 @@@ got_port_no
        if (err)
                goto out_put;
  
- #ifdef SUPPORT_SYSFS
 -      if (dp_add_if_hook)
 -              dp_add_if_hook(dp->ports[port_no]);
 +      dp_sysfs_add_if(dp->ports[port_no]);
- #endif
+       err = __put_user(port_no, &port.port);
  
  out_put:
        dev_put(dev);
@@@ -448,10 -421,13 +439,8 @@@ int dp_del_port(struct net_bridge_port 
  {
        ASSERT_RTNL();
  
- #ifdef SUPPORT_SYSFS
 -      if (p->port_no != ODPP_LOCAL && dp_del_if_hook) {
 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
 -              sysfs_remove_link(&p->dp->ifobj, p->dev->name);
 -#else
 -              sysfs_remove_link(p->dp->ifobj, p->dev->name);
 -#endif
 -      }
 +      if (p->port_no != ODPP_LOCAL)
 +              dp_sysfs_del_if(p);
- #endif
        dp_ifinfo_notify(RTM_DELLINK, p);
  
        p->dp->n_ports--;
@@@ -18,8 -18,9 +18,9 @@@
  #include <linux/netdevice.h>
  #include <linux/workqueue.h>
  #include <linux/skbuff.h>
+ #include <linux/version.h>
  #include "flow.h"
 -#include "brc_sysfs.h"
 +#include "dp_sysfs.h"
  
  /* Mask for the priority bits in a vlan header.  If we ever merge upstream
   * then this should go into include/linux/if_vlan.h. */
Simple merge
index c0ac01b,0000000..be044ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,28 @@@
- #include <linux/version.h>
- #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
- #define SUPPORT_SYSFS 1
- #else
- /* We only support sysfs on Linux 2.6.18 because that's the only place we
-  * really need it (on Xen, for brcompat) and it's a big pain to try to support
-  * multiple versions. */
- #endif
- #ifdef SUPPORT_SYSFS
 +/*
 + * Copyright (c) 2009 Nicira Networks.
 + * Distributed under the terms of the GNU GPL version 2.
 + *
 + * Significant portions of this file may be copied from parts of the Linux
 + * kernel, by Linus Torvalds and others.
 + */
 +
 +#ifndef DP_SYSFS_H
 +#define DP_SYSFS_H 1
 +
 +struct datapath;
 +struct net_bridge_port;
 +
 +/* dp_sysfs_dp.c */
 +int dp_sysfs_add_dp(struct datapath *dp);
 +int dp_sysfs_del_dp(struct datapath *dp);
 +
 +/* dp_sysfs_if.c */
 +int dp_sysfs_add_if(struct net_bridge_port *p);
 +int dp_sysfs_del_if(struct net_bridge_port *p);
 +
++#ifdef CONFIG_SYSFS
 +extern struct sysfs_ops brport_sysfs_ops;
 +#endif
 +
 +#endif /* dp_sysfs.h */
 +
  
  /* Hack to attempt to build on more platforms. */
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
- #define to_kobj(d) &(d)->class_dev.kobj
 -#define BRC_DEVICE_ATTR CLASS_DEVICE_ATTR
 +#define DP_DEVICE_ATTR CLASS_DEVICE_ATTR
+ #define DEVICE_PARAMS struct class_device *d
+ #define DEVICE_ARGS d
+ #define DEV_ATTR(NAME) class_device_attr_##NAME
  #else
- #define to_kobj(d) &(d)->dev.kobj
 -#define BRC_DEVICE_ATTR DEVICE_ATTR
 +#define DP_DEVICE_ATTR DEVICE_ATTR
+ #define DEVICE_PARAMS struct device *d, struct device_attribute *attr
+ #define DEVICE_ARGS d, attr
+ #define DEV_ATTR(NAME) dev_attr_##NAME
  #endif
  
  /*
@@@ -99,15 -102,15 +102,15 @@@ static void set_forward_delay(struct da
  #endif
  }
  
- static ssize_t store_forward_delay(struct class_device *d,
+ static ssize_t store_forward_delay(DEVICE_PARAMS,
                                   const char *buf, size_t len)
  {
-       return store_bridge_parm(d, buf, len, set_forward_delay);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay);
  }
 -static BRC_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
 +static DP_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
                   show_forward_delay, store_forward_delay);
  
- static ssize_t show_hello_time(struct class_device *d, char *buf)
+ static ssize_t show_hello_time(DEVICE_PARAMS, char *buf)
  {
  #if 0
        return sprintf(buf, "%lu\n",
@@@ -133,13 -136,12 +136,12 @@@ static ssize_t store_hello_time(DEVICE_
                                const char *buf,
                                size_t len)
  {
-       return store_bridge_parm(d, buf, len, set_hello_time);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time);
  }
 -static BRC_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
 +static DP_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
                   store_hello_time);
  
- static ssize_t show_max_age(struct class_device *d, 
-                           char *buf)
+ static ssize_t show_max_age(DEVICE_PARAMS, char *buf)
  {
  #if 0
        return sprintf(buf, "%lu\n",
@@@ -161,15 -163,14 +163,14 @@@ static void set_max_age(struct datapat
  #endif
  }
  
- static ssize_t store_max_age(struct class_device *d, 
+ static ssize_t store_max_age(DEVICE_PARAMS,
                             const char *buf, size_t len)
  {
-       return store_bridge_parm(d, buf, len, set_max_age);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_max_age);
  }
 -static BRC_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
 +static DP_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
  
- static ssize_t show_ageing_time(struct class_device *d,
-                               char *buf)
+ static ssize_t show_ageing_time(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@@ -188,16 -189,15 +189,15 @@@ static void set_ageing_time(struct data
  #endif
  }
  
- static ssize_t store_ageing_time(struct class_device *d,
+ static ssize_t store_ageing_time(DEVICE_PARAMS,
                                 const char *buf, size_t len)
  {
-       return store_bridge_parm(d, buf, len, set_ageing_time);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time);
  }
 -static BRC_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
 +static DP_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
                   store_ageing_time);
  
- static ssize_t show_stp_state(struct class_device *d,
-                             char *buf)
+ static ssize_t show_stp_state(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@@ -233,11 -233,10 +233,10 @@@ static ssize_t store_stp_state(DEVICE_P
  
        return len;
  }
 -static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
 +static DP_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
                   store_stp_state);
  
- static ssize_t show_priority(struct class_device *d, 
-                            char *buf)
+ static ssize_t show_priority(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@@ -257,15 -256,14 +256,14 @@@ static void set_priority(struct datapat
  #endif
  }
  
- static ssize_t store_priority(struct class_device *d, 
+ static ssize_t store_priority(DEVICE_PARAMS,
                               const char *buf, size_t len)
  {
-       return store_bridge_parm(d, buf, len, set_priority);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority);
  }
 -static BRC_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
 +static DP_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
  
- static ssize_t show_root_id(struct class_device *d, 
-                           char *buf)
+ static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
  {
  #if 0
        return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
        return sprintf(buf, "0000.010203040506\n");
  #endif
  }
 -static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 +static DP_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
  
- static ssize_t show_bridge_id(struct class_device *d, 
-                             char *buf)
+ static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
  {
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr;
        return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
                        0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
  }
 -static BRC_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 +static DP_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
  
- static ssize_t show_root_port(struct class_device *d, 
-                             char *buf)
+ static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
  {
  #if 0
        return sprintf(buf, "%d\n", to_bridge(d)->root_port);
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
 +static DP_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
  
- static ssize_t show_root_path_cost(struct class_device *d,
-                                  char *buf)
+ static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
  {
  #if 0
        return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
 +static DP_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
  
- static ssize_t show_topology_change(struct class_device *d,
-                                   char *buf)
+ static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
  {
  #if 0
        return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
 +static DP_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
  
- static ssize_t show_topology_change_detected(struct class_device *d,
-                                            char *buf)
+ static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO,
 +static DP_DEVICE_ATTR(topology_change_detected, S_IRUGO,
                   show_topology_change_detected, NULL);
  
- static ssize_t show_hello_timer(struct class_device *d,
-                               char *buf)
+ static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
 +static DP_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
  
- static ssize_t show_tcn_timer(struct class_device *d, 
-                             char *buf)
+ static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
 +static DP_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
  
- static ssize_t show_topology_change_timer(struct class_device *d,
-                                         char *buf)
+ static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
 +static DP_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
                   NULL);
  
- static ssize_t show_gc_timer(struct class_device *d, 
-                            char *buf)
+ static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        return sprintf(buf, "%d\n", 0);
  #endif
  }
 -static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
 +static DP_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
  
- static ssize_t show_group_addr(struct class_device *d,
-                              char *buf)
+ static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@@ -474,9 -462,9 +462,9 @@@ static struct attribute_group bridge_gr
   *   to hold links.  The ifobj exists in the same data structure
   *   as its parent the bridge so reference counting works.
   */
 -int brc_sysfs_add_dp(struct datapath *dp)
 +int dp_sysfs_add_dp(struct datapath *dp)
  {
-       struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev);
+       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
        int err;
  
        err = sysfs_create_group(kobj, &bridge_group);
                goto out1;
        }
  
-       /* Create /sys/class/net/<devname>/bridge directory. */
 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
 -      kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR);
 -      dp->ifobj.ktype = NULL;
 -      dp->ifobj.kset = NULL;
--      dp->ifobj.parent = kobj;
-       err = kobject_add(&dp->ifobj);
 -
 -      err = kobject_register(&dp->ifobj);
++      /* Create /sys/class/net/<devname>/brif directory. */
++      err = kobject_add(&dp->ifobj, kobj, SYSFS_BRIDGE_PORT_SUBDIR);
        if (err) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
-                               __FUNCTION__, dp_name(dp), dp->ifobj.name);
+                       __FUNCTION__, dp_name(dp), kobject_name(&dp->ifobj));
                goto out2;
        }
 -#else
 -      dp->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, kobj);
 -      if (!dp->ifobj) {
 -              pr_info("%s: can't add kobject (directory) %s/%s\n",
 -                      __func__, dp_name(dp), SYSFS_BRIDGE_PORT_SUBDIR);
 -              goto out2;
 -      }
 -#endif
 +      kobject_uevent(&dp->ifobj, KOBJ_ADD);
        return 0;
  
   out2:
        return err;
  }
  
 -int brc_sysfs_del_dp(struct datapath *dp)
 +int dp_sysfs_del_dp(struct datapath *dp)
  {
-       struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev);
+       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
  
 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
 -      kobject_unregister(&dp->ifobj);
 -#else 
 -      kobject_put(dp->ifobj);
 -#endif
 +      kobject_del(&dp->ifobj);
        sysfs_remove_group(kobj, &bridge_group);
  
        return 0;
  }
- #else /* !SUPPORT_SYSFS */
+ #else /* !CONFIG_SYSFS */
 -int brc_sysfs_add_dp(struct datapath *dp) { return 0; }
 -int brc_sysfs_del_dp(struct datapath *dp) { return 0; }
 -int brc_sysfs_add_if(struct net_bridge_port *p) { return 0; }
 -int brc_sysfs_del_if(struct net_bridge_port *p)
 -{
 -      dev_put(p->dev);
 -      kfree(p);
 -      return 0;
 -}
 +int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
 +int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
 +int dp_sysfs_add_if(struct net_bridge_port *p) { return 0; }
- int dp_sysfs_del_if(struct net_bridge_port *p)
- {
-       dev_put(p->dev);
-       kfree(p);
-       return 0;
- }
- #endif /* !SUPPORT_SYSFS */
++int dp_sysfs_del_if(struct net_bridge_port *p) { return 0; }
+ #endif /* !CONFIG_SYSFS */
  #include <linux/if_bridge.h>
  #include <linux/rtnetlink.h>
  #include <linux/spinlock.h>
 -#include "brc_sysfs.h"
 +#include "dp_sysfs.h"
  #include "datapath.h"
  
- #ifdef SUPPORT_SYSFS
+ #ifdef CONFIG_SYSFS
  
  struct brport_attribute {
        struct attribute        attr;
@@@ -277,16 -289,15 +277,17 @@@ int dp_sysfs_add_if(struct net_bridge_p
        struct brport_attribute **a;
        int err;
  
 -      err = kobject_init_and_add(&p->kobj, &brport_ktype,
 -                                 &(p->dev->NETDEV_DEV_MEMBER.kobj),
 -                                 SYSFS_BRIDGE_PORT_ATTR);
 +      /* Create /sys/class/net/<devname>/brport directory. */
-       err = kobject_add(&p->kobj);
++      err = kobject_add(&p->kobj, &p->dev->NETDEV_DEV_MEMBER.kobj,
++                        SYSFS_BRIDGE_PORT_ATTR);
        if (err)
-               goto err_put;
+               goto err;
  
 +      /* Create symlink from /sys/class/net/<devname>/brport/bridge to
 +       * /sys/class/net/<bridgename>. */
        err = sysfs_create_link(&p->kobj,
                                &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj,
 -                              SYSFS_BRIDGE_PORT_LINK);
 +                              SYSFS_BRIDGE_PORT_LINK); /* "bridge" */
        if (err)
                goto err_del;
  
  
        kobject_uevent(&p->kobj, KOBJ_ADD);
  
--      return err;
++      return 0;
  
  err_del:
        kobject_del(&p->kobj);
- err_put:
--      kobject_put(&p->kobj);
-       /* Ensure that dp_sysfs_del_if becomes a no-op. */
-       p->kobj.dentry = NULL;
+ err:
++      p->linkname[0] = 0;
        return err;
  }
  
 -int brc_sysfs_del_if(struct net_bridge_port *p)
 +int dp_sysfs_del_if(struct net_bridge_port *p)
  {
 -      struct net_device *dev = p->dev;
 -
 -      kobject_uevent(&p->kobj, KOBJ_REMOVE);
 -      kobject_del(&p->kobj);
 -
 -      dev_put(dev);
 -
 -      kobject_put(&p->kobj);
 -
 +      if (p->linkname[0]) {
 +              sysfs_remove_link(&p->dp->ifobj, p->linkname);
-               p->linkname[0] = '\0';
-       }
-       if (p->kobj.dentry) {
 +              kobject_uevent(&p->kobj, KOBJ_REMOVE);
 +              kobject_del(&p->kobj);
++              p->linkname[0] = '\0';
 +      }
        return 0;
  }
- #endif /* SUPPORT_SYSFS */
+ #endif /* CONFIG_SYSFS */
@@@ -4,13 -4,20 +4,27 @@@
  #include_next <linux/kobject.h>
  
  #include <linux/version.h>
++
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
 -static inline int kobject_init_and_add(struct kobject *kobj,
 -                                      struct kobj_type *ktype,
 -                                      struct kobject *parent,
 -                                      const char *name)
 +#define kobject_init(kobj, ktype) rpl_kobject_init(kobj, ktype)
 +static inline void rpl_kobject_init(struct kobject *kobj, struct kobj_type *ktype)
  {
 -      kobject_init(kobj);
 -      kobject_set_name(kobj, "%s", name);
        kobj->ktype = ktype;
 -      kobj->kset = NULL;
 -      kobj->parent = parent;
 +      (kobject_init)(kobj);
 +}
 -      return kobject_add(kobj);
++#define kobject_add(kobj, parent, name) rpl_kobject_add(kobj, parent, name)
++static inline int rpl_kobject_add(struct kobject *kobj,
++                                struct kobject *parent,
++                                const char *name)
++{
++      int err = kobject_set_name(kobj, "%s", name);
++      if (err)
++              return err;
++      kobj->parent = parent;
++      return (kobject_add)(kobj);
+ }
  #endif
  
++
  #endif /* linux/kobject.h wrapper */
@@@ -133,17 -133,17 +133,17 @@@ MGMT_VCONNS="punix:/var/run/ovs-openflo
  #RATE_LIMIT=1000
  
  # INACTIVITY_PROBE: The maximum number of seconds of inactivity on the
- # controller connection before secchan sends an inactivity probe
+ # controller connection before ovs-openflowd sends an inactivity probe
  # message to the controller.  The valid range is 5 and up.  If unset,
- # secchan defaults to 5 seconds.
 -# ovs-openflowd defaults to 15 seconds.
++# ovs-openflowd defaults to 5 seconds.
  #INACTIVITY_PROBE=5
  
- # MAX_BACKOFF: The maximum time that secchan will wait between
+ # MAX_BACKOFF: The maximum time that ovs-openflowd will wait between
  # attempts to connect to the controller.  The valid range is 1 and up.
- # If unset, secchan defaults to 8 seconds.
 -# If unset, ovs-openflowd defaults to 15 seconds.
 -#MAX_BACKOFF=15
++# If unset, ovs-openflowd defaults to 8 seconds.
 +#MAX_BACKOFF=8
  
- # DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open"
+ # DAEMON_OPTS: Additional options to pass to ovs-openflowd, e.g. "--fail=open"
  DAEMON_OPTS=""
  
  # CORE_LIMIT: Maximum size for core dumps.
@@@ -923,10 -927,9 +927,9 @@@ do_receive_msg(struct dhclient *cli, st
          flow_extract(&b, 0, &flow);
          if (flow.dl_type != htons(ETH_TYPE_IP)
              || flow.nw_proto != IP_TYPE_UDP
 -            || flow.tp_dst != htons(68)
 +            || flow.tp_dst != htons(DHCP_CLIENT_PORT)
              || !(eth_addr_is_broadcast(flow.dl_dst)
-                  || eth_addr_equals(flow.dl_dst,
-                                     netdev_get_etheraddr(cli->netdev)))) {
+                  || eth_addr_equals(flow.dl_dst, cli_mac))) {
              continue;
          }
  
diff --cc lib/rconn.c
Simple merge
Simple merge
Simple merge
@@@ -1218,27 -1219,45 +1222,27 @@@ update_port(struct ofproto *p, const ch
      int error;
  
      COVERAGE_INC(ofproto_update_port);
 -    ofport = shash_find_data(&p->port_by_name, devname);
 +
 +    /* Query the datapath for port information. */
-     error = dpif_port_query_by_name(&p->dpif, devname, &odp_port);
+     error = dpif_port_query_by_name(p->dpif, devname, &odp_port);
 -    if (!error) {
 -        if (!ofport) {
 -            /* New port. */
 -            if (!ofport_conflicts(p, &odp_port)) {
 -                ofport = make_ofport(&odp_port);
 -                if (ofport) {
 -                    ofport_install(p, ofport);
 -                    send_port_status(p, ofport, OFPPR_ADD);
 -                }
 -            }
 -        } else {
 -            /* Modified port. */
 -            struct ofport *new_ofport = make_ofport(&odp_port);
 -            if (!new_ofport) {
 -                return;
 -            }
  
 -            new_ofport->opp.config &= OFPPC_PORT_DOWN;
 -            new_ofport->opp.config |= ofport->opp.config & ~OFPPC_PORT_DOWN;
 -            if (ofport_equal(ofport, new_ofport)) {
 -                /* False alarm--no change. */
 -                ofport_free(new_ofport);
 -            } else {
 -                ofport_remove(p, ofport);
 -                ofport_install(p, new_ofport);
 -                ofport_free(ofport);
 -                send_port_status(p, new_ofport, OFPPR_MODIFY);
 -            }
 -        }
 -    } else if (error == ENOENT || error == ENODEV) {
 -        /* Deleted port. */
 -        if (ofport) {
 -            send_port_status(p, ofport, OFPPR_DELETE);
 -            ofport_remove(p, ofport);
 -            ofport_free(ofport);
 +    /* Find the old ofport. */
 +    old_ofport = shash_find_data(&p->port_by_name, devname);
 +    if (!error) {
 +        if (!old_ofport) {
 +            /* There's no port named 'devname' but there might be a port with
 +             * the same port number.  This could happen if a port is deleted
 +             * and then a new one added in its place very quickly, or if a port
 +             * is renamed.  In the former case we want to send an OFPPR_DELETE
 +             * and an OFPPR_ADD, and in the latter case we want to send a
 +             * single OFPPR_MODIFY.  We can distinguish the cases by comparing
 +             * the old port's ifindex against the new port, or perhaps less
 +             * reliably but more portably by comparing the old port's MAC
 +             * against the new port's MAC.  However, this code isn't that smart
 +             * and always sends an OFPPR_MODIFY (XXX). */
 +            old_ofport = port_array_get(&p->ports, odp_port.port);
          }
 -    } else {
 +    } else if (error != ENOENT && error != ENODEV) {
          VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error "
                       "%s", strerror(error));
          return;
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -467,35 -428,6 +430,30 @@@ do_show(int argc, char *argv[]
      }
  }
  
-         struct dpif dpif;
-         char dpif_name[IF_NAMESIZE];
-         if (dpif_open(all_dps.names[i], &dpif)) {
-             continue;
-         }
-         if (!dpif_get_name(&dpif, dpif_name, sizeof dpif_name)) {
-             printf("%s\n", dpif_name);
 +static void
 +do_dump_dps(int argc UNUSED, char *argv[] UNUSED)
 +{
 +    struct svec all_dps;
 +    unsigned int i;
 +    int error;
 +
 +    svec_init(&all_dps);
 +    error = dp_enumerate(&all_dps);
 +
 +    for (i = 0; i < all_dps.n; i++) {
-         dpif_close(&dpif);
++        struct dpif *dpif;
++        if (!dpif_open(all_dps.names[i], &dpif)) {
++            printf("%s\n", dpif_name(dpif));
++            dpif_close(dpif);
 +        }
 +    }
 +
 +    svec_destroy(&all_dps);
 +    if (error) {
 +        exit(EXIT_FAILURE);
 +    }
 +}
 +
  static void
  do_dump_flows(int argc UNUSED, char *argv[])
  {
@@@ -248,13 -248,13 +248,13 @@@ set up flows on its own when the contro
  
  .TP
  \fB--inactivity-probe=\fIsecs\fR
- When the secure channel is connected to the controller, the secure
channel waits for a message to be received from the controller for
+ When the OpenFlow switch is connected to the controller, the
switch waits for a message to be received from the controller for
  \fIsecs\fR seconds before it sends a inactivity probe to the
  controller.  After sending the inactivity probe, if no response is
- received for an additional \fIsecs\fR seconds, the secure channel
+ received for an additional \fIsecs\fR seconds, the switch
  assumes that the connection has been broken and attempts to reconnect.
 -The default is 15 seconds, and the minimum value is 5 seconds.
 +The default and the minimum value are both 5 seconds.
  
  When fail-open mode is configured, changing the inactivity probe
  interval also changes the interval before entering fail-open mode (see
@@@ -538,9 -540,9 +539,9 @@@ usage(void
             "                            closed: drop all packets\n"
             "                            open (default): act as learning switch\n"
             "  --inactivity-probe=SECS time between inactivity probes\n"
-            "  --max-idle=SECS         max idle for flows set up by secchan\n"
+            "  --max-idle=SECS         max idle for flows set up by switch\n"
             "  --max-backoff=SECS      max time between controller connection\n"
 -           "                          attempts (default: 15 seconds)\n"
 +           "                          attempts (default: 8 seconds)\n"
             "  -l, --listen=METHOD     allow management connections on METHOD\n"
             "                          (a passive OpenFlow connection method)\n"
             "  --snoop=METHOD          allow controller snooping on METHOD\n"
@@@ -305,8 -311,7 +313,9 @@@ bridge_init(void
          }
      }
  
 +    unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
 +
+     bond_init();
      bridge_reconfigure();
  }
  
@@@ -457,42 -524,20 +528,34 @@@ bridge_reconfigure(void
          bridge_get_all_ifaces(br, &want_ifaces);
          svec_diff(&want_ifaces, &cur_ifaces, &add_ifaces, NULL, NULL);
  
-         next_port_no = 1;
          for (i = 0; i < add_ifaces.n; i++) {
              const char *if_name = add_ifaces.names[i];
-             for (;;) {
-                 bool internal;
-                 int error;
-                 /* It's an internal interface if it's marked that way, or if
-                  * it's a bonded interface for which we're faking up a network
-                  * device. */
-                 internal = cfg_get_bool(0, "iface.%s.internal", if_name);
-                 if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
-                     struct port *port = port_lookup(br, if_name);
-                     if (port && port->n_ifaces > 1) {
-                         internal = true;
-                     }
-                 }
 -            int internal = cfg_get_bool(0, "iface.%s.internal", if_name);
 -            int flags = internal ? ODP_PORT_INTERNAL : 0;
 -            int error = dpif_port_add(br->dpif, if_name, flags, NULL);
++            bool internal;
++            int error;
 +
-                 /* Add to datapath. */
-                 error = dpif_port_add(&br->dpif, if_name, next_port_no++,
-                                       internal ? ODP_PORT_INTERNAL : 0);
-                 if (error != EEXIST) {
-                     if (next_port_no >= 256) {
-                         VLOG_ERR("ran out of valid port numbers on dp%u",
-                                  dpif_id(&br->dpif));
-                         goto out;
-                     }
-                     if (error) {
-                         VLOG_ERR("failed to add %s interface to dp%u: %s",
-                                  if_name, dpif_id(&br->dpif), strerror(error));
-                     }
-                     break;
++            /* It's an internal interface if it's marked that way, or if
++             * it's a bonded interface for which we're faking up a network
++             * device. */
++            internal = cfg_get_bool(0, "iface.%s.internal", if_name);
++            if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
++                struct port *port = port_lookup(br, if_name);
++                if (port && port->n_ifaces > 1) {
++                    internal = true;
 +                }
 +            }
++
++            /* Add to datapath. */
++            error = dpif_port_add(br->dpif, if_name,
++                                  internal ? ODP_PORT_INTERNAL : 0, NULL);
+             if (error == EXFULL) {
+                 VLOG_ERR("ran out of valid port numbers on %s",
+                          dpif_name(br->dpif));
+                 break;
+             } else if (error) {
+                 VLOG_ERR("failed to add %s interface to %s: %s",
+                          if_name, dpif_name(br->dpif), strerror(error));
+             }
          }
-     out:
          svec_destroy(&cur_ifaces);
          svec_destroy(&want_ifaces);
          svec_destroy(&add_ifaces);
@@@ -639,67 -660,28 +683,66 @@@ bridge_pick_local_hw_addr(struct bridg
          if (port->is_mirror_output_port) {
              continue;
          }
 -        for (j = 0; j < port->n_ifaces; j++) {
 -            struct iface *iface = port->ifaces[j];
 -            uint8_t iface_ea[ETH_ADDR_LEN];
 +
 +        /* Choose the MAC address to represent the port. */
 +        iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name);
 +        if (iface_ea_u64) {
 +            /* User specified explicitly. */
 +            eth_addr_from_uint64(iface_ea_u64, iface_ea);
 +
 +            /* Find the interface with this Ethernet address (if any) so that
 +             * we can provide the correct devname to the caller. */
 +            iface = NULL;
 +            for (j = 0; j < port->n_ifaces; j++) {
 +                struct iface *candidate = port->ifaces[j];
 +                uint8_t candidate_ea[ETH_ADDR_LEN];
-                 if (!netdev_nodev_get_etheraddr(candidate->name, candidate_ea)
++                if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
 +                    && eth_addr_equals(iface_ea, candidate_ea)) {
 +                    iface = candidate;
 +                }
 +            }
 +        } else {
 +            /* Choose the interface whose MAC address will represent the port.
 +             * The Linux kernel bonding code always chooses the MAC address of
 +             * the first slave added to a bond, and the Fedora networking
 +             * scripts always add slaves to a bond in alphabetical order, so
 +             * for compatibility we choose the interface with the name that is
 +             * first in alphabetical order. */
 +            iface = port->ifaces[0];
 +            for (j = 1; j < port->n_ifaces; j++) {
 +                struct iface *candidate = port->ifaces[j];
 +                if (strcmp(candidate->name, iface->name) < 0) {
 +                    iface = candidate;
 +                }
 +            }
 +
 +            /* The local port doesn't count (since we're trying to choose its
 +             * MAC address anyway).  Other internal ports don't count because
 +             * we really want a physical MAC if we can get it, and internal
 +             * ports typically have randomly generated MACs. */
              if (iface->dp_ifidx == ODPP_LOCAL
                  || cfg_get_bool(0, "iface.%s.internal", iface->name)) {
                  continue;
              }
-             error = netdev_nodev_get_etheraddr(iface->name, iface_ea);
 +
 +            /* Grab MAC. */
 -            if (!error) {
 -                if (!eth_addr_is_multicast(iface_ea) &&
 -                    !eth_addr_is_reserved(iface_ea) &&
 -                    !eth_addr_is_zero(iface_ea) &&
 -                    memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0) {
 -                    memcpy(ea, iface_ea, ETH_ADDR_LEN);
 -                    *hw_addr_iface = iface;
 -                }
 -            } else {
+             error = netdev_get_etheraddr(iface->netdev, iface_ea);
 +            if (error) {
                  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                  VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
                              iface->name, strerror(error));
 +                continue;
              }
          }
-             memcpy(ea, iface_ea, ETH_ADDR_LEN);
-             *devname = iface ? iface->name : NULL;
 +
 +        /* Compare against our current choice. */
 +        if (!eth_addr_is_multicast(iface_ea) &&
 +            !eth_addr_is_reserved(iface_ea) &&
 +            !eth_addr_is_zero(iface_ea) &&
 +            memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
 +        {
++            *hw_addr_iface = iface;
 +        }
      }
      if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
          memcpy(ea, br->default_ea, ETH_ADDR_LEN);
@@@ -2980,9 -2931,8 +3042,9 @@@ port_update_bond_compat(struct port *po
          if (slave->up) {
              bond.up = true;
          }
-         memcpy(slave->mac, iface->mac, ETH_ADDR_LEN);
+         netdev_get_etheraddr(iface->netdev, slave->mac);
      }
 +
      proc_net_compat_update_bond(port->name, &bond);
      free(bond.slaves);
  }
Simple merge
@@@ -80,13 -81,9 +81,12 @@@ main(int argc, char *argv[]
      }
      unixctl_command_register("vswitchd/reload", reload);
  
 -    cfg_read();
 +    retval = cfg_read();
 +    if (retval) {
 +        ovs_fatal(retval, "could not read config file");
 +    }
      mgmt_init();
      bridge_init();
-     port_init();
      mgmt_reconfigure();
  
      need_reconfigure = false;
Simple merge
@@@ -62,8 -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
  
@@@ -249,34 -249,212 +250,239 @@@ def check_allowed(pif)
  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):
 +    maybe = None
 +    for device in os.listdir("/sys/class/net"):
 +        dev_mac = get_netdev_mac(device)
 +        if dev_mac and mac.lower() == dev_mac.lower():
 +            if get_netdev_tx_queue_len(device):
 +                return device
 +            if not maybe:
 +                # Probably a datapath internal port.
 +                maybe = device
 +    return maybe
 +
+ #
+ # 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")
@@@ -461,13 -653,12 +681,12 @@@ The ipdev name is the same as the bridg
      pifrec = db.get_pif_record(pif)
      return bridge_name(pif)
  
 -def physdev_names(pif):
 -    """Return the name(s) of the physical network device(s) associated with pif.
 -For a VLAN PIF, the physical devices are the VLAN slave's physical devices.
 -For a bond master PIF, the physical devices are the bond slaves.
 -For a non-VLAN, non-bond master PIF, the physical device is the PIF itself.
 +def 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':
Simple merge