Merge citrix into master.
authorBen Pfaff <blp@nicira.com>
Wed, 19 Aug 2009 23:08:18 +0000 (16:08 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 19 Aug 2009 23:08:18 +0000 (16:08 -0700)
1  2 
datapath/datapath.c
datapath/dp_dev.c
datapath/dp_sysfs_dp.c
vswitchd/ovs-brcompatd.c
xenserver/opt_xensource_libexec_interface-reconfigure
xenserver/vswitch-xen.spec

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);
@@@ -224,8 -223,10 +224,8 @@@ static int create_dp(int dp_idx, const 
        init_waitqueue_head(&dp->waitqueue);
  
        /* Initialize kobject for bridge.  This will be added as
-        * /sys/class/net/<devname>/bridge later, if sysfs is enabled. */
+        * /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)
@@@ -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 datapath/dp_dev.c
@@@ -118,7 -118,7 +118,7 @@@ static void dp_getinfo(struct net_devic
  {
        struct dp_dev *dp_dev = dp_dev_priv(netdev);
        strcpy(info->driver, "openvswitch");
 -      sprintf(info->bus_info, "%d", dp_dev->dp->dp_idx);
 +      sprintf(info->bus_info, "%d.%d", dp_dev->dp->dp_idx, dp_dev->port_no);
  }
  
  static struct ethtool_ops dp_ethtool_ops = {
@@@ -211,16 -211,17 +211,17 @@@ struct net_device *dp_dev_create(struc
        if (!netdev)
                return ERR_PTR(-ENOMEM);
  
+       dp_dev = dp_dev_priv(netdev);
+       dp_dev->dp = dp;
+       dp_dev->port_no = port_no;
+       dp_dev->dev = netdev;
        err = register_netdevice(netdev);
        if (err) {
                free_netdev(netdev);
                return ERR_PTR(err);
        }
  
-       dp_dev = dp_dev_priv(netdev);
-       dp_dev->dp = dp;
-       dp_dev->port_no = port_no;
-       dp_dev->dev = netdev;
        return netdev;
  }
  
diff --combined datapath/dp_sysfs_dp.c
  #include "datapath.h"
  #include "dp_dev.h"
  
 -#ifdef SUPPORT_SYSFS
 +#ifdef CONFIG_SYSFS
  #define to_dev(obj)   container_of(obj, struct device, kobj)
  
  /* 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 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 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
  
  /*
   * Common code for storing bridge parameters.
   */
 -static ssize_t store_bridge_parm(struct class_device *d,
 +static ssize_t store_bridge_parm(DEVICE_PARAMS,
                                 const char *buf, size_t len,
                                 void (*set)(struct datapath *, unsigned long))
  {
@@@ -80,7 -76,8 +80,7 @@@
  }
  
  
 -static ssize_t show_forward_delay(struct class_device *d,
 -                                char *buf)
 +static ssize_t show_forward_delay(DEVICE_PARAMS, char *buf)
  {
  #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@@ -102,15 -99,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 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",
@@@ -132,16 -129,17 +132,16 @@@ static void set_hello_time(struct datap
  #endif
  }
  
 -static ssize_t store_hello_time(struct class_device *d,
 +static ssize_t store_hello_time(DEVICE_PARAMS,
                                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 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",
@@@ -163,14 -161,15 +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 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));
@@@ -189,15 -188,16 +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 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));
  }
  
  
 -static ssize_t store_stp_state(struct class_device *d,
 +static ssize_t store_stp_state(DEVICE_PARAMS,
                               const char *buf,
                               size_t len)
  {
  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));
@@@ -256,14 -257,15 +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 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);
  }
  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;
  }
  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);
  }
  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);
  }
  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);
  }
  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));
  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));
  }
  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));
  }
  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));
  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));
  }
  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));
  #endif
  }
  
 -static ssize_t store_group_addr(struct class_device *d,
 +static ssize_t store_group_addr(DEVICE_PARAMS,
                                const char *buf, size_t len)
  {
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@@ -427,28 -439,28 +427,28 @@@ static DP_DEVICE_ATTR(group_addr, S_IRU
                   show_group_addr, store_group_addr);
  
  static struct attribute *bridge_attrs[] = {
 -      &class_device_attr_forward_delay.attr,
 -      &class_device_attr_hello_time.attr,
 -      &class_device_attr_max_age.attr,
 -      &class_device_attr_ageing_time.attr,
 -      &class_device_attr_stp_state.attr,
 -      &class_device_attr_priority.attr,
 -      &class_device_attr_bridge_id.attr,
 -      &class_device_attr_root_id.attr,
 -      &class_device_attr_root_path_cost.attr,
 -      &class_device_attr_root_port.attr,
 -      &class_device_attr_topology_change.attr,
 -      &class_device_attr_topology_change_detected.attr,
 -      &class_device_attr_hello_timer.attr,
 -      &class_device_attr_tcn_timer.attr,
 -      &class_device_attr_topology_change_timer.attr,
 -      &class_device_attr_gc_timer.attr,
 -      &class_device_attr_group_addr.attr,
 +      &DEV_ATTR(forward_delay).attr,
 +      &DEV_ATTR(hello_time).attr,
 +      &DEV_ATTR(max_age).attr,
 +      &DEV_ATTR(ageing_time).attr,
 +      &DEV_ATTR(stp_state).attr,
 +      &DEV_ATTR(priority).attr,
 +      &DEV_ATTR(bridge_id).attr,
 +      &DEV_ATTR(root_id).attr,
 +      &DEV_ATTR(root_path_cost).attr,
 +      &DEV_ATTR(root_port).attr,
 +      &DEV_ATTR(topology_change).attr,
 +      &DEV_ATTR(topology_change_detected).attr,
 +      &DEV_ATTR(hello_timer).attr,
 +      &DEV_ATTR(tcn_timer).attr,
 +      &DEV_ATTR(topology_change_timer).attr,
 +      &DEV_ATTR(gc_timer).attr,
 +      &DEV_ATTR(group_addr).attr,
        NULL
  };
  
  static struct attribute_group bridge_group = {
-       .name = SYSFS_BRIDGE_ATTR,
+       .name = SYSFS_BRIDGE_ATTR, /* "bridge" */
        .attrs = bridge_attrs,
  };
  
   */
  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;
  
+       /* Create /sys/class/net/<devname>/bridge directory. */
        err = sysfs_create_group(kobj, &bridge_group);
        if (err) {
                pr_info("%s: can't create group %s/%s\n",
        }
  
        /* Create /sys/class/net/<devname>/brif directory. */
 -      dp->ifobj.parent = kobj;
 -      err = kobject_add(&dp->ifobj);
 +      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;
        }
        kobject_uevent(&dp->ifobj, KOBJ_ADD);
  
  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;
  
        kobject_del(&dp->ifobj);
        sysfs_remove_group(kobj, &bridge_group);
  
        return 0;
  }
 -#else /* !SUPPORT_SYSFS */
 +#else /* !CONFIG_SYSFS */
  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 */
diff --combined vswitchd/ovs-brcompatd.c
@@@ -38,6 -38,7 +38,6 @@@
  #include "coverage.h"
  #include "daemon.h"
  #include "dirs.h"
 -#include "dpif.h"
  #include "dynamic-string.h"
  #include "fatal-signal.h"
  #include "fault.h"
@@@ -303,6 -304,7 +303,6 @@@ static voi
  prune_ports(void)
  {
      int i, j;
 -    int error;
      struct svec bridges, delete;
  
      if (cfg_lock(NULL, 0)) {
          get_bridge_ifaces(br_name, &ifaces, -1);
          for (j = 0; j < ifaces.n; j++) {
              const char *iface_name = ifaces.names[j];
 -            enum netdev_flags flags;
  
              /* The local port and internal ports are created and destroyed by
               * ovs-vswitchd itself, so don't bother checking for them at all.
                  continue;
              }
  
 -            error = netdev_nodev_get_flags(iface_name, &flags);
 -            if (error == ENODEV) {
 +            if (!netdev_exists(iface_name)) {
                  VLOG_INFO_RL(&rl, "removing dead interface %s from %s",
                               iface_name, br_name);
                  svec_add(&delete, iface_name);
 -            } else if (error) {
 -                VLOG_INFO_RL(&rl, "unknown error %d on interface %s from %s",
 -                             error, iface_name, br_name);
              }
          }
          svec_destroy(&ifaces);
      svec_destroy(&delete);
  }
  
 -/* Checks whether a network device named 'name' exists and returns true if so,
 - * false otherwise.
 - *
 - * XXX it is possible that this doesn't entirely accomplish what we want in
 - * context, since ovs-vswitchd.conf may cause vswitchd to create or destroy
 - * network devices based on iface.*.internal settings.
 - *
 - * XXX may want to move this to lib/netdev.
 - *
 - * XXX why not just use netdev_nodev_get_flags() or similar function? */
 -static bool
 -netdev_exists(const char *name)
 -{
 -    struct stat s;
 -    char *filename;
 -    int error;
 -
 -    filename = xasprintf("/sys/class/net/%s", name);
 -    error = stat(filename, &s);
 -    free(filename);
 -    return !error;
 -}
 -
  static int
  add_bridge(const char *br_name)
  {
@@@ -655,14 -685,8 +655,14 @@@ handle_fdb_query_cmd(struct ofpbuf *buf
      for (i = 0; i < ifaces.n; i++) {
          const char *iface_name = ifaces.names[i];
          struct mac *mac = &local_macs[n_local_macs];
 -        if (!netdev_nodev_get_etheraddr(iface_name, mac->addr)) {
 -            n_local_macs++;
 +        struct netdev *netdev;
 +
 +        error = netdev_open(iface_name, NETDEV_ETH_TYPE_NONE, &netdev);
 +        if (netdev) {
 +            if (!netdev_get_etheraddr(netdev, mac->addr)) {
 +                n_local_macs++;
 +            }
 +            netdev_close(netdev);
          }
      }
      svec_destroy(&ifaces);
@@@ -790,6 -814,7 +790,7 @@@ handle_get_bridges_cmd(struct ofpbuf *b
  
      /* Get all the real bridges and all the fake ones. */
      cfg_read();
+     svec_init(&bridges);
      cfg_get_subsections(&bridges, "bridge");
      SVEC_FOR_EACH (i, br_name, &bridges) {
          const char *iface_name;
@@@ -840,6 -865,8 +841,8 @@@ handle_get_ports_cmd(struct ofpbuf *buf
  
      svec_init(&ports);
      get_bridge_ports(ovs_bridge, &ports, br_vlan);
+     svec_sort(&ports);
+     svec_del(&ports, linux_bridge);
      send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */
      svec_destroy(&ports);
  
@@@ -967,7 -994,7 +970,6 @@@ rtnl_recv_update(void
              const char *port_name = nl_attr_get_string(attrs[IFLA_IFNAME]);
              char br_name[IFNAMSIZ];
              uint32_t br_idx = nl_attr_get_u32(attrs[IFLA_MASTER]);
-             struct svec ports;
 -            enum netdev_flags flags;
  
              if (!if_indextoname(br_idx, br_name)) {
                  ofpbuf_delete(buf);
                  return;
              }
  
 -            if (netdev_nodev_get_flags(port_name, &flags) == ENODEV) {
 +            if (!netdev_exists(port_name)) {
                  /* Network device is really gone. */
+                 struct svec ports;
                  VLOG_INFO("network device %s destroyed, "
                            "removing from bridge %s", port_name, br_name);
                  svec_init(&ports);
                  cfg_get_all_keys(&ports, "bridge.%s.port", br_name);
                  svec_sort(&ports);
                      del_port(br_name, port_name);
                      rewrite_and_reload_config();
                  }
+                 svec_destroy(&ports);
              } else {
                  /* A network device by that name exists even though the kernel
                   * told us it had disappeared.  Probably, what happened was
@@@ -1085,7 -1116,6 +1091,7 @@@ main(int argc, char *argv[]
      for (;;) {
          unixctl_server_run(unixctl);
          brc_recv_update();
 +        netdev_run();
  
          /* If 'prune_timeout' is non-zero, we actively prune from the
           * config file any 'bridge.<br_name>.port' entries that are no 
  
          nl_sock_wait(brc_sock, POLLIN);
          unixctl_server_wait(unixctl);
 +        netdev_wait();
          poll_block();
      }
  
@@@ -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
  
@@@ -266,226 -265,18 +266,222 @@@ def get_netdev_tx_queue_len(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):
+         if (dev_mac and mac.lower() == dev_mac.lower() and
+             get_netdev_tx_queue_len(device)):
                  return device
-             if not maybe:
-                 # Probably a datapath internal port.
-                 maybe = device
-     return maybe
+     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):
@@@ -664,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':
@@@ -687,6 -463,7 +683,6 @@@ 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':
@@@ -707,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"""
@@@ -742,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:
@@@ -882,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':
@@@ -970,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)
  
@@@ -1202,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']]
  
@@@ -1461,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
@@@ -1670,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
@@@ -71,6 -71,8 +71,8 @@@ install -m 755 xenserver/root_vswitch_s
                 $RPM_BUILD_ROOT%{_prefix}/scripts/dump-vif-details
  install -m 755 xenserver/usr_sbin_xen-bugtool \
               $RPM_BUILD_ROOT%{_prefix}/scripts/xen-bugtool
+ install -m 755 xenserver/usr_sbin_brctl \
+              $RPM_BUILD_ROOT%{_prefix}/scripts/brctl
  install -m 644 \
          xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
                 $RPM_BUILD_ROOT%{_prefix}/scripts/XSFeatureVSwitch.py
@@@ -84,17 -86,16 +86,17 @@@ rm -rf 
      $RPM_BUILD_ROOT/root/vswitch/bin/ovs-controller \
      $RPM_BUILD_ROOT/root/vswitch/bin/ovs-discover \
      $RPM_BUILD_ROOT/root/vswitch/bin/ovs-kill \
 +    $RPM_BUILD_ROOT/root/vswitch/bin/ovs-openflowd \
      $RPM_BUILD_ROOT/root/vswitch/bin/ovs-pki \
      $RPM_BUILD_ROOT/root/vswitch/bin/ovs-switchui \
      $RPM_BUILD_ROOT/root/vswitch/bin/ovs-wdt \
 -    $RPM_BUILD_ROOT/root/vswitch/bin/secchan \
 +    $RPM_BUILD_ROOT/root/vswitch/kernel_modules/veth_mod.ko \
      $RPM_BUILD_ROOT/root/vswitch/sbin/ovs-monitor \
      $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-controller.8 \
      $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-discover.8 \
      $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-kill.8 \
 +    $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-openflowd.8 \
      $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-pki.8 \
 -    $RPM_BUILD_ROOT/root/vswitch/share/man/man8/secchan.8 \
      $RPM_BUILD_ROOT/root/vswitch/share/openvswitch
  
  %clean
@@@ -116,11 -117,28 +118,28 @@@ EO
          printf "\nThe original XenServer scripts replaced by this package\n"
          printf "are different than expected.  This could lead to unexpected\n"
          printf "behavior of your server.  Unless you are sure you know what\n"
-         printf "you are doing, it is highly recomended that you remove this\n"
+         printf "you are doing, it is highly recommended that you remove this\n"
          printf "package immediately after the install completes, which\n"
          printf "will restore the XenServer scripts that you were previously\n"
          printf "using.\n\n"
      fi
+     if test "`/usr/sbin/brctl --version`" != "bridge-utils, 1.1"; then
+ cat <<EOF
+ /usr/sbin/brctl replaced by this package reports the following version:
+ `/usr/sbin/brctl --version`
+ The expected version was:
+ bridge-utils, 1.1
+ Unless you are sure you know what you are doing, it is highly recommended that
+ you remove this package immediately after the install completes, which will
+ restore the original /usr/sbin/brctl.
+ EOF
+     fi
  fi
  
  if test ! -e /etc/ovs-vswitch.dbcache; then
  # Ensure ovs-vswitchd.conf exists
  touch /etc/ovs-vswitchd.conf
  
- # Replace original XenServer files
+ # Replace XenServer files by our versions.
  mkdir -p %{_prefix}/xs-original \
      || printf "Could not create script backup directory.\n"
  for f in \
      /opt/xensource/libexec/interface-reconfigure \
      /etc/xensource/scripts/vif \
-     /usr/sbin/xen-bugtool
+     /usr/sbin/xen-bugtool \
+     /usr/sbin/brctl
  do
      s=$(basename "$f")
      t=$(readlink "$f")
@@@ -253,7 -272,8 +273,8 @@@ if [ "$1" = "0" ]; then     # $1 = 1 fo
      for f in \
          /opt/xensource/libexec/interface-reconfigure \
          /etc/xensource/scripts/vif \
-         /usr/sbin/xen-bugtool
+         /usr/sbin/xen-bugtool \
+         /usr/sbin/brctl
      do
          s=$(basename "$f")
          if [ ! -f "%{_prefix}/xs-original/$s" ]; then
  /etc/profile.d/vswitch.sh
  /root/vswitch/kernel_modules/brcompat_mod.ko
  /root/vswitch/kernel_modules/openvswitch_mod.ko
 -/root/vswitch/kernel_modules/veth_mod.ko
  /root/vswitch/scripts/dump-vif-details
  /root/vswitch/scripts/interface-reconfigure
  /root/vswitch/scripts/vif
  /root/vswitch/scripts/xen-bugtool
  /root/vswitch/scripts/XSFeatureVSwitch.py
+ /root/vswitch/scripts/brctl
  # Following two files are generated automatically by rpm.  We don't
  # really need them and they won't be used on the XenServer, but there
  # isn't an obvious place to get rid of them since they are generated