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.

55 files changed:
datapath/Modules.mk
datapath/brc_sysfs.h [deleted file]
datapath/brcompat.c
datapath/datapath.c
datapath/datapath.h
datapath/dp_dev.c
datapath/dp_notify.c
datapath/dp_sysfs.h [new file with mode: 0644]
datapath/dp_sysfs_dp.c [moved from datapath/brc_sysfs_dp.c with 83% similarity]
datapath/dp_sysfs_if.c [moved from datapath/brc_sysfs_if.c with 89% similarity]
datapath/linux-2.6/.gitignore
datapath/linux-2.6/Modules.mk
datapath/linux-2.6/compat-2.6/include/linux/kobject.h
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h
debian/openvswitch-switch.template
include/openvswitch/brcompat-netlink.h
include/openvswitch/datapath-protocol.h
lib/cfg.c
lib/cfg.h
lib/daemon.c
lib/daemon.h
lib/daemon.man
lib/dhcp-client.c
lib/dhcp.h
lib/ofp-print.c
lib/ofp-print.h
lib/rconn.c
lib/svec.h
lib/vlog.c
ofproto/fail-open.c
ofproto/netflow.c
ofproto/ofproto.c
ofproto/ofproto.h
utilities/ovs-cfg-mod.c
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/mgmt.c
vswitchd/ovs-brcompatd.c
vswitchd/ovs-vswitchd.c
vswitchd/ovs-vswitchd.conf.5.in
vswitchd/proc-net-compat.c
vswitchd/proc-net-compat.h
xenserver/README
xenserver/automake.mk
xenserver/etc_init.d_vswitch
xenserver/etc_sysconfig_vswitch.example
xenserver/etc_xensource_scripts_vif
xenserver/opt_xensource_libexec_interface-reconfigure
xenserver/usr_sbin_xen-bugtool [new file with mode: 0755]
xenserver/vswitch-xen.spec

index 1b5de4a..211f96f 100644 (file)
@@ -14,6 +14,8 @@ openvswitch_sources = \
        datapath.c \
        dp_dev.c \
        dp_notify.c \
+       dp_sysfs_dp.c \
+       dp_sysfs_if.c \
        flow.c \
        table.c
 
@@ -22,6 +24,7 @@ openvswitch_headers = \
        compat.h \
        datapath.h \
        dp_dev.h \
+       dp_sysfs.h \
        flow.h
 
 dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
diff --git a/datapath/brc_sysfs.h b/datapath/brc_sysfs.h
deleted file mode 100644 (file)
index 78540d5..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 BRC_SYSFS_H
-#define BRC_SYSFS_H 1
-
-struct datapath;
-struct net_bridge_port;
-
-/* brc_sysfs_dp.c */
-int brc_sysfs_add_dp(struct datapath *dp);
-int brc_sysfs_del_dp(struct datapath *dp);
-
-/* brc_sysfs_if.c */
-int brc_sysfs_add_if(struct net_bridge_port *p);
-int brc_sysfs_del_if(struct net_bridge_port *p);
-
-#endif /* brc_sysfs.h */
-
index d9255e6..92fcecc 100644 (file)
@@ -9,10 +9,8 @@
 #include <linux/kernel.h>
 #include <asm/uaccess.h>
 #include <linux/completion.h>
-#include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/if_bridge.h>
-#include <linux/rculist.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/genetlink.h>
@@ -20,9 +18,7 @@
 #include "compat.h"
 #include "openvswitch/brcompat-netlink.h"
 #include "brc_procfs.h"
-#include "brc_sysfs.h"
 #include "datapath.h"
-#include "dp_dev.h"
 
 static struct genl_family brc_genl_family;
 static struct genl_multicast_group brc_mc_group;
@@ -46,36 +42,6 @@ static u32 brc_seq;               /* Sequence number for current op. */
 static struct sk_buff *brc_send_command(struct sk_buff *, struct nlattr **attrs);
 static int brc_send_simple_command(struct sk_buff *);
 
-static int
-get_dp_ifindices(int *indices, int num)
-{
-       int i, index = 0;
-
-       rcu_read_lock();
-       for (i=0; i < ODP_MAX && index < num; i++) {
-               struct datapath *dp = get_dp(i);
-               if (!dp)
-                       continue;
-               indices[index++] = dp->ports[ODPP_LOCAL]->dev->ifindex;
-       }
-       rcu_read_unlock();
-
-       return index;
-}
-
-static void
-get_port_ifindices(struct datapath *dp, int *ifindices, int num)
-{
-       struct net_bridge_port *p;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu (p, &dp->port_list, node) {
-               if (p->port_no < num)
-                       ifindices[p->port_no] = p->dev->ifindex;
-       }
-       rcu_read_unlock();
-}
-
 static struct sk_buff *
 brc_make_request(int op, const char *bridge, const char *port)
 {
@@ -84,7 +50,8 @@ brc_make_request(int op, const char *bridge, const char *port)
                goto error;
 
        genlmsg_put(skb, 0, 0, &brc_genl_family, 0, op);
-       NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
+       if (bridge)
+               NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
        if (port)
                NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port);
        return skb;
@@ -127,26 +94,57 @@ static int brc_add_del_bridge(char __user *uname, int add)
        return brc_send_simple_command(request);
 }
 
-static int brc_get_bridges(int __user *uindices, int n)
+static int brc_get_indices(int op, const char *br_name,
+                          int __user *uindices, int n)
 {
+       struct nlattr *attrs[BRC_GENL_A_MAX + 1];
+       struct sk_buff *request, *reply;
        int *indices;
        int ret;
+       int len;
 
+       if (n < 0)
+               return -EINVAL;
        if (n >= 2048)
                return -ENOMEM;
 
-       indices = kcalloc(n, sizeof(int), GFP_KERNEL);
-       if (indices == NULL)
+       request = brc_make_request(op, br_name, NULL);
+       if (!request)
                return -ENOMEM;
 
-       n = get_dp_ifindices(indices, n);
+       reply = brc_send_command(request, attrs);
+       ret = PTR_ERR(reply);
+       if (IS_ERR(reply))
+               goto exit;
+
+       ret = -nla_get_u32(attrs[BRC_GENL_A_ERR_CODE]);
+       if (ret < 0)
+               goto exit_free_skb;
+
+       ret = -EINVAL;
+       if (!attrs[BRC_GENL_A_IFINDEXES])
+               goto exit_free_skb;
+
+       len = nla_len(attrs[BRC_GENL_A_IFINDEXES]);
+       indices = nla_data(attrs[BRC_GENL_A_IFINDEXES]);
+       if (len % sizeof(int))
+               goto exit_free_skb;
 
+       n = min_t(int, n, len / sizeof(int));
        ret = copy_to_user(uindices, indices, n * sizeof(int)) ? -EFAULT : n;
 
-       kfree(indices);
+exit_free_skb:
+       kfree_skb(reply);
+exit:
        return ret;
 }
 
+/* Called with br_ioctl_mutex. */
+static int brc_get_bridges(int __user *uindices, int n)
+{
+       return brc_get_indices(BRC_GENL_C_GET_BRIDGES, NULL, uindices, n);
+}
+
 /* Legacy deviceless bridge ioctl's.  Called with br_ioctl_mutex. */
 static int
 old_deviceless(void __user *uarg)
@@ -239,26 +237,14 @@ brc_get_bridge_info(struct net_device *dev, struct __bridge_info __user *ub)
 static int
 brc_get_port_list(struct net_device *dev, int __user *uindices, int num)
 {
-       struct dp_dev *dp_dev = netdev_priv(dev);
-       struct datapath *dp = dp_dev->dp;
-       int *indices;
-
-       if (num < 0)
-               return -EINVAL;
-       if (num == 0)
-               num = 256;
-       if (num > DP_MAX_PORTS)
-               num = DP_MAX_PORTS;
+       int retval;
 
-       indices = kcalloc(num, sizeof(int), GFP_KERNEL);
-       if (indices == NULL)
-               return -ENOMEM;
+       rtnl_unlock();
+       retval = brc_get_indices(BRC_GENL_C_GET_PORTS, dev->name,
+                                uindices, num);
+       rtnl_lock();
 
-       get_port_ifindices(dp, indices, num);
-       if (copy_to_user(uindices, indices, num * sizeof(int)))
-               num = -EFAULT;
-       kfree(indices);
-       return num;
+       return retval;
 }
 
 /*
@@ -523,55 +509,19 @@ error:
        return ERR_PTR(error);
 }
 
-int brc_add_dp(struct datapath *dp)
-{
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-       brc_sysfs_add_dp(dp);
-
-       return 0;
-}
-
-int brc_del_dp(struct datapath *dp) 
-{
-       brc_sysfs_del_dp(dp);
-       module_put(THIS_MODULE);
-
-       return 0;
-}
-
 static int 
 __init brc_init(void)
 {
-       int i;
        int err;
 
        printk("Open vSwitch Bridge Compatibility, built "__DATE__" "__TIME__"\n");
 
-       rcu_read_lock();
-       for (i=0; i<ODP_MAX; i++) {
-               if (get_dp(i)) {
-                       rcu_read_unlock();
-                       printk(KERN_EMERG "brcompat: no datapaths may exist!\n");
-                       return -EEXIST;
-               }
-       }
-       rcu_read_unlock();
-
        /* Set the bridge ioctl handler */
        brioctl_set(brc_ioctl_deviceless_stub);
 
        /* Set the openvswitch_mod device ioctl handler */
        dp_ioctl_hook = brc_dev_ioctl;
 
-       /* Register hooks for datapath adds and deletes */
-       dp_add_dp_hook = brc_add_dp;
-       dp_del_dp_hook = brc_del_dp;
-
-       /* Register hooks for interface adds and deletes */
-       dp_add_if_hook = brc_sysfs_add_if;
-       dp_del_if_hook = brc_sysfs_del_if;
-
        /* Randomize the initial sequence number.  This is not a security
         * feature; it only helps avoid crossed wires between userspace and
         * the kernel when the module is unloaded and reloaded. */
@@ -612,14 +562,6 @@ error:
 static void 
 brc_cleanup(void)
 {
-       /* Unregister hooks for datapath adds and deletes */
-       dp_add_dp_hook = NULL;
-       dp_del_dp_hook = NULL;
-       
-       /* Unregister hooks for interface adds and deletes */
-       dp_add_if_hook = NULL;
-       dp_del_if_hook = NULL;
-
        /* Unregister ioctl hooks */
        dp_ioctl_hook = NULL;
        brioctl_set(NULL);
index 926f278..de607e8 100644 (file)
 int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 EXPORT_SYMBOL(dp_ioctl_hook);
 
-int (*dp_add_dp_hook)(struct datapath *dp);
-EXPORT_SYMBOL(dp_add_dp_hook);
-
-int (*dp_del_dp_hook)(struct datapath *dp);
-EXPORT_SYMBOL(dp_del_dp_hook);
-
-int (*dp_add_if_hook)(struct net_bridge_port *p);
-EXPORT_SYMBOL(dp_add_if_hook);
-
-int (*dp_del_if_hook)(struct net_bridge_port *p);
-EXPORT_SYMBOL(dp_del_if_hook);
-
 /* Datapaths.  Protected on the read side by rcu_read_lock, on the write side
  * by dp_mutex.  dp_mutex is almost completely redundant with genl_mutex
  * maintained by the Generic Netlink code, but the timeout path needs mutual
@@ -184,6 +172,16 @@ errout:
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
 
+static void release_dp(struct kobject *kobj)
+{
+       struct datapath *dp = container_of(kobj, struct datapath, ifobj);
+       kfree(dp);
+}
+
+struct kobj_type dp_ktype = {
+       .release = release_dp
+};
+
 static int create_dp(int dp_idx, const char __user *devnamep)
 {
        struct net_device *dp_dev;
@@ -225,6 +223,11 @@ static int create_dp(int dp_idx, const char __user *devnamep)
                skb_queue_head_init(&dp->queues[i]);
        init_waitqueue_head(&dp->waitqueue);
 
+       /* Initialize kobject for bridge.  This will be added as
+        * /sys/class/net/<devname>/bridge later, if sysfs is enabled. */
+       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));
@@ -252,8 +255,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
 
-       if (dp_add_dp_hook)
-               dp_add_dp_hook(dp);
+       dp_sysfs_add_dp(dp);
 
        return 0;
 
@@ -281,8 +283,7 @@ static void do_destroy_dp(struct datapath *dp)
                if (p->port_no != ODPP_LOCAL)
                        dp_del_port(p);
 
-       if (dp_del_dp_hook)
-               dp_del_dp_hook(dp);
+       dp_sysfs_del_dp(dp);
 
        rcu_assign_pointer(dps[dp->dp_idx], NULL);
 
@@ -295,7 +296,7 @@ static void do_destroy_dp(struct datapath *dp)
        for (i = 0; i < DP_MAX_GROUPS; i++)
                kfree(dp->groups[i]);
        free_percpu(dp->stats_percpu);
-       kfree(dp);
+       kobject_put(&dp->ifobj);
        module_put(THIS_MODULE);
 }
 
@@ -320,6 +321,19 @@ err_unlock:
        return err;
 }
 
+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)
 {
@@ -349,6 +363,11 @@ 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++;
 
+       /* Initialize kobject for bridge.  This will be added as
+        * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
+       p->kobj.kset = NULL;
+       kobject_init(&p->kobj, &brport_ktype);
+
        dp_ifinfo_notify(RTM_NEWLINK, p);
 
        return 0;
@@ -402,8 +421,7 @@ got_port_no:
        if (err)
                goto out_put;
 
-       if (dp_add_if_hook)
-               dp_add_if_hook(dp->ports[port_no]);
+       dp_sysfs_add_if(dp->ports[port_no]);
 
        err = __put_user(port_no, &port.port);
 
@@ -421,13 +439,8 @@ int dp_del_port(struct net_bridge_port *p)
 {
        ASSERT_RTNL();
 
-       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);
        dp_ifinfo_notify(RTM_DELLINK, p);
 
        p->dp->n_ports--;
@@ -448,15 +461,10 @@ int dp_del_port(struct net_bridge_port *p)
        /* Then wait until no one is still using it, and destroy it. */
        synchronize_rcu();
 
-       if (is_dp_dev(p->dev)) {
+       if (is_dp_dev(p->dev))
                dp_dev_destroy(p->dev);
-       }
-       if (p->port_no != ODPP_LOCAL && dp_del_if_hook) {
-               dp_del_if_hook(p);
-       } else {
-               dev_put(p->dev);
-               kfree(p);
-       }
+       dev_put(p->dev);
+       kobject_put(&p->kobj);
 
        return 0;
 }
@@ -1181,6 +1189,29 @@ static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
        return copy_to_user(statsp, &stats, sizeof stats) ? -EFAULT : 0;
 }
 
+/* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports */
+int dp_min_mtu(const struct datapath *dp)
+{
+       struct net_bridge_port *p;
+       int mtu = 0;
+
+       ASSERT_RTNL();
+
+       list_for_each_entry_rcu (p, &dp->port_list, node) {
+               struct net_device *dev = p->dev;
+
+               /* Skip any internal ports, since that's what we're trying to
+                * set. */
+               if (is_dp_dev(dev))
+                       continue;
+
+               if (!mtu || dev->mtu < mtu)
+                       mtu = dev->mtu;
+       }
+
+       return mtu ? mtu : ETH_DATA_LEN;
+}
+
 static int
 put_port(const struct net_bridge_port *p, struct odp_port __user *uop)
 {
index c6ec86a..b520084 100644 (file)
@@ -20,7 +20,7 @@
 #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. */
@@ -65,13 +65,7 @@ struct datapath {
        struct mutex mutex;
        int dp_idx;
 
-#ifdef CONFIG_SYSFS
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
        struct kobject ifobj;
-#else
-       struct kobject *ifobj;
-#endif
-#endif
 
        int drop_frags;
 
@@ -99,18 +93,13 @@ struct net_bridge_port {
        u16 port_no;
        struct datapath *dp;
        struct net_device *dev;
-#ifdef CONFIG_SYSFS
        struct kobject kobj;
-#endif
+       char linkname[IFNAMSIZ];
        struct list_head node;   /* Element in datapath.ports. */
 };
 
 extern struct notifier_block dp_device_notifier;
 extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
-extern int (*dp_add_dp_hook)(struct datapath *dp);
-extern int (*dp_del_dp_hook)(struct datapath *dp);
-extern int (*dp_add_if_hook)(struct net_bridge_port *p);
-extern int (*dp_del_if_hook)(struct net_bridge_port *p);
 
 /* Flow table. */
 struct dp_table *dp_table_create(unsigned int n_buckets);
@@ -127,6 +116,7 @@ int dp_table_foreach(struct dp_table *table,
 void dp_process_received_packet(struct sk_buff *, struct net_bridge_port *);
 int dp_del_port(struct net_bridge_port *);
 int dp_output_control(struct datapath *, struct sk_buff *, int, u32 arg);
+int dp_min_mtu(const struct datapath *dp);
 
 struct datapath *get_dp(int dp_idx);
 
index 9caf65a..069127e 100644 (file)
@@ -28,7 +28,6 @@ struct datapath *dp_dev_get_dp(struct net_device *netdev)
 {
        return dp_dev_priv(netdev)->dp;
 }
-EXPORT_SYMBOL(dp_dev_get_dp);
 
 static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev)
 {
@@ -130,6 +129,15 @@ static struct ethtool_ops dp_ethtool_ops = {
        .get_tso = ethtool_op_get_tso,
 };
 
+static int dp_dev_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if (new_mtu < 68 || new_mtu > dp_min_mtu(dp_dev_get_dp(dev)))
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 static int dp_dev_init(struct net_device *netdev)
 {
        struct dp_dev *dp_dev = dp_dev_priv(netdev);
@@ -162,6 +170,7 @@ do_setup(struct net_device *netdev)
        netdev->stop = dp_dev_stop;
        netdev->tx_queue_len = 0;
        netdev->set_mac_address = dp_dev_mac_addr;
+       netdev->change_mtu = dp_dev_change_mtu;
        netdev->init = dp_dev_init;
        netdev->destructor = dp_dev_free;
 
@@ -225,4 +234,3 @@ int is_dp_dev(struct net_device *netdev)
 {
        return netdev->open == dp_dev_open;
 }
-EXPORT_SYMBOL(is_dp_dev);
index 5b8cf17..f22d8b3 100644 (file)
@@ -17,12 +17,29 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
                void *ptr) 
 {
        struct net_device *dev = ptr;
-       struct net_bridge_port *p = dev->br_port;
-       if (event == NETDEV_UNREGISTER && p) {
-               struct datapath *dp = p->dp;
+       struct net_bridge_port *p;
+       struct datapath *dp;
+
+       p = dev->br_port;
+       if (!p)
+               return NOTIFY_DONE;
+       dp = p->dp;
+
+       switch (event) {
+       case NETDEV_UNREGISTER:
                mutex_lock(&dp->mutex);
                dp_del_port(p);
                mutex_unlock(&dp->mutex);
+               break;
+
+       case NETDEV_CHANGENAME:
+               if (p->port_no != ODPP_LOCAL) {
+                       mutex_lock(&dp->mutex);
+                       dp_sysfs_del_if(p);
+                       dp_sysfs_add_if(p);
+                       mutex_unlock(&dp->mutex);
+               }
+               break;
        }
        return NOTIFY_DONE;
 }
diff --git a/datapath/dp_sysfs.h b/datapath/dp_sysfs.h
new file mode 100644 (file)
index 0000000..be044ea
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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 */
+
similarity index 83%
rename from datapath/brc_sysfs_dp.c
rename to datapath/dp_sysfs_dp.c
index c1e82eb..fafd9a9 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/times.h>
 #include <linux/version.h>
 
-#include "brc_sysfs.h"
+#include "dp_sysfs.h"
 #include "datapath.h"
 #include "dp_dev.h"
 
 
 /* Hack to attempt to build on more platforms. */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
-#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 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
@@ -107,7 +107,7 @@ static ssize_t store_forward_delay(DEVICE_PARAMS,
 {
        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(DEVICE_PARAMS, char *buf)
@@ -138,7 +138,7 @@ static ssize_t store_hello_time(DEVICE_PARAMS,
 {
        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(DEVICE_PARAMS, char *buf)
@@ -168,7 +168,7 @@ static ssize_t store_max_age(DEVICE_PARAMS,
 {
        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(DEVICE_PARAMS, char *buf)
 {
@@ -194,7 +194,7 @@ static ssize_t store_ageing_time(DEVICE_PARAMS,
 {
        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(DEVICE_PARAMS, char *buf)
@@ -233,7 +233,7 @@ static ssize_t store_stp_state(DEVICE_PARAMS,
 
        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(DEVICE_PARAMS, char *buf)
@@ -261,7 +261,7 @@ static ssize_t store_priority(DEVICE_PARAMS,
 {
        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(DEVICE_PARAMS, char *buf)
 {
@@ -271,7 +271,7 @@ static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -282,7 +282,7 @@ static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -292,7 +292,7 @@ static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -302,7 +302,7 @@ static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -312,7 +312,7 @@ static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -323,7 +323,7 @@ static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
@@ -335,7 +335,7 @@ static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -346,7 +346,7 @@ static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -357,7 +357,7 @@ static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
@@ -369,7 +369,7 @@ static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
        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(DEVICE_PARAMS, char *buf)
 {
@@ -423,7 +423,7 @@ static ssize_t store_group_addr(DEVICE_PARAMS,
        return len;
 }
 
-static BRC_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+static DP_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
                   show_group_addr, store_group_addr);
 
 static struct attribute *bridge_attrs[] = {
@@ -462,7 +462,7 @@ static struct attribute_group bridge_group = {
  *   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 = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
        int err;
@@ -474,26 +474,14 @@ int brc_sysfs_add_dp(struct datapath *dp)
                goto out1;
        }
 
-#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_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), 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:
@@ -502,27 +490,18 @@ int brc_sysfs_add_dp(struct datapath *dp)
        return err;
 }
 
-int brc_sysfs_del_dp(struct datapath *dp)
+int dp_sysfs_del_dp(struct datapath *dp)
 {
        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 /* !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) { return 0; }
 #endif /* !CONFIG_SYSFS */
similarity index 89%
rename from datapath/brc_sysfs_if.c
rename to datapath/dp_sysfs_if.c
index 7a9b8b8..95c26dc 100644 (file)
@@ -18,7 +18,7 @@
 #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 CONFIG_SYSFS
@@ -266,77 +266,64 @@ struct sysfs_ops brport_sysfs_ops = {
        .store = brport_store,
 };
 
-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 = {
-       .sysfs_ops = &brport_sysfs_ops,
-       .release = release_nbp
-};
-
 /*
  * Add sysfs entries to ethernet device added to a bridge.
  * Creates a brport subdirectory with bridge attributes.
  * Puts symlink in bridge's brport subdirectory
  */
-int brc_sysfs_add_if(struct net_bridge_port *p)
+int dp_sysfs_add_if(struct net_bridge_port *p)
 {
        struct datapath *dp = p->dp;
        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, &p->dev->NETDEV_DEV_MEMBER.kobj,
+                         SYSFS_BRIDGE_PORT_ATTR);
        if (err)
                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;
 
+       /* Populate /sys/class/net/<devname>/brport directory with files. */
        for (a = brport_attrs; *a; ++a) {
                err = sysfs_create_file(&p->kobj, &((*a)->attr));
                if (err)
                        goto err_del;
        }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+       /* Create symlink from /sys/class/net/<bridgename>/brif/<devname> to
+        * /sys/class/net/<devname>/brport.  */
        err = sysfs_create_link(&dp->ifobj, &p->kobj, p->dev->name);
-#else
-       err = sysfs_create_link(dp->ifobj, &p->kobj, p->dev->name);
-#endif
        if (err)
                goto err_del;
+       strcpy(p->linkname, p->dev->name);
 
        kobject_uevent(&p->kobj, KOBJ_ADD);
 
-       return err;
+       return 0;
 
 err_del:
        kobject_del(&p->kobj);
-       kobject_put(&p->kobj);
 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);
+               kobject_uevent(&p->kobj, KOBJ_REMOVE);
+               kobject_del(&p->kobj);
+               p->linkname[0] = '\0';
+       }
        return 0;
 }
 #endif /* CONFIG_SYSFS */
index af5821a..aa10e66 100644 (file)
@@ -3,8 +3,8 @@
 /Makefile.main
 /actions.c
 /brcompat.c
-/brc_sysfs_dp.c
-/brc_sysfs_if.c
+/dp_sysfs_dp.c
+/dp_sysfs_if.c
 /datapath.c
 /dp_dev.c
 /dp_notify.c
index e7359a4..e5aa51d 100644 (file)
@@ -38,12 +38,9 @@ both_modules += brcompat
 brcompat_sources = \
        linux-2.6/compat-2.6/genetlink-brcompat.c \
        brcompat.c \
-       brc_procfs.c \
-       brc_sysfs_dp.c \
-       brc_sysfs_if.c 
+       brc_procfs.c
 brcompat_headers = \
-       brc_procfs.h \
-       brc_sysfs.h 
+       brc_procfs.h
 
 dist_modules += veth
 build_modules += $(if $(BUILD_VETH),veth)
index 7dbb010..4cf797e 100644 (file)
@@ -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 */
index d291513..b718283 100644 (file)
@@ -16,8 +16,7 @@ struct net;
 #endif
 
 #ifndef to_net_dev
-#define to_net_dev(class) \
-       container_of(class, struct net_device, NETDEV_DEV_MEMBER)
+#define to_net_dev(class) container_of(class, struct net_device, NETDEV_DEV_MEMBER)
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
index f06d4a0..44f9210 100644 (file)
@@ -135,13 +135,13 @@ MGMT_VCONNS="punix:/var/run/ovs-openflowd.mgmt"
 # INACTIVITY_PROBE: The maximum number of seconds of inactivity on the
 # controller connection before ovs-openflowd sends an inactivity probe
 # message to the controller.  The valid range is 5 and up.  If unset,
-# ovs-openflowd defaults to 15 seconds.
+# ovs-openflowd defaults to 5 seconds.
 #INACTIVITY_PROBE=5
 
 # 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, 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 ovs-openflowd, e.g. "--fail=open"
 DAEMON_OPTS=""
index 694bdcc..7d5ac4c 100644 (file)
@@ -47,8 +47,8 @@ enum {
        BRC_GENL_A_UNSPEC,
 
        /*
-        * "K:" messages appear in messages from the kernel to userspace.
-        * "U:" messages appear in messages from userspace to the kernel.
+        * "K:" attributes appear in messages from the kernel to userspace.
+        * "U:" attributes appear in messages from userspace to the kernel.
         */
 
        /* BRC_GENL_C_DP_ADD, BRC_GENL_C_DP_DEL. */
@@ -75,6 +75,7 @@ enum {
 
        /* BRC_GENL_C_DP_RESULT. */
        BRC_GENL_A_FDB_DATA,    /* U: FDB records. */
+       BRC_GENL_A_IFINDEXES,   /* U: "int" ifindexes of bridges or ports. */
 
        __BRC_GENL_A_MAX,
        BRC_GENL_A_MAX = __BRC_GENL_A_MAX - 1
@@ -96,6 +97,8 @@ enum brc_genl_command {
        BRC_GENL_C_QUERY_MC,    /* U: Get multicast group for brcompat. */
        BRC_GENL_C_SET_PROC,    /* U: Set contents of file in /proc. */
        BRC_GENL_C_FDB_QUERY,   /* K: Read records from forwarding database. */
+       BRC_GENL_C_GET_BRIDGES, /* K: Get ifindexes of all bridges. */
+       BRC_GENL_C_GET_PORTS,   /* K: Get ifindexes of all ports on a bridge. */
 
        __BRC_GENL_C_MAX,
        BRC_GENL_C_MAX = __BRC_GENL_C_MAX - 1
index ae36382..868c854 100644 (file)
@@ -151,17 +151,17 @@ struct odp_flow_stats {
 };
 
 struct odp_flow_key {
-       __be32 nw_src;               /* IP source address. */
-       __be32 nw_dst;               /* IP destination address. */
-       __u16  in_port;              /* Input switch port. */
-       __be16 dl_vlan;              /* Input VLAN. */
-       __be16 dl_type;              /* Ethernet frame type. */
-       __be16 tp_src;               /* TCP/UDP source port. */
-       __be16 tp_dst;               /* TCP/UDP destination port. */
-       __u8   dl_src[ETH_ALEN];     /* Ethernet source address. */
-       __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
-       __u8   nw_proto;             /* IP protocol. */
-       __u8   reserved;             /* Pad to 64 bits. */
+    __be32 nw_src;               /* IP source address. */
+    __be32 nw_dst;               /* IP destination address. */
+    __u16  in_port;              /* Input switch port. */
+    __be16 dl_vlan;              /* Input VLAN. */
+    __be16 dl_type;              /* Ethernet frame type. */
+    __be16 tp_src;               /* TCP/UDP source port. */
+    __be16 tp_dst;               /* TCP/UDP destination port. */
+    __u8   dl_src[ETH_ALEN];     /* Ethernet source address. */
+    __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
+    __u8   nw_proto;             /* IP protocol. */
+    __u8   reserved;             /* Pad to 64 bits. */
 };
 
 struct odp_flow {
index 433d7a0..225827e 100644 (file)
--- a/lib/cfg.c
+++ b/lib/cfg.c
@@ -92,6 +92,12 @@ static bool is_type(const char *s, enum cfg_flags);
 #define CC_FILE_NAME CC_ALNUM "._-"
 #define CC_KEY CC_ALNUM "._-@$:+"
 
+void
+cfg_init(void)
+{
+    svec_terminate(&cfg);
+}
+
 /* Sets 'file_name' as the configuration file read by cfg_read().  Returns 0 on
  * success, otherwise a positive errno value if 'file_name' cannot be opened.
  *
@@ -183,6 +189,7 @@ cfg_read(void)
     file = fopen(cfg_name, "r");
     if (!file) {
         VLOG_ERR("failed to open \"%s\": %s", cfg_name, strerror(errno));
+        svec_terminate(&cfg);
         return errno;
     }
 
index 42345f8..e159244 100644 (file)
--- a/lib/cfg.h
+++ b/lib/cfg.h
@@ -26,6 +26,7 @@
 struct svec;
 struct ofpbuf;
 
+void cfg_init(void);
 int cfg_set_file(const char *file_name);
 int cfg_read(void);
 int cfg_lock(uint8_t *cookie, int timeout);
index 4ad4af4..1e3f002 100644 (file)
@@ -35,7 +35,10 @@ static bool detach;
 static char *pidfile;
 
 /* Create pidfile even if one already exists and is locked? */
-static bool force;
+static bool overwrite_pidfile;
+
+/* Should we chdir to "/". */
+static bool chdir_ = true;
 
 /* Returns the file name that would be used for a pidfile if 'name' were
  * provided to set_pidfile().  The caller must free the returned string. */
@@ -69,13 +72,20 @@ get_pidfile(void)
     return pidfile;
 }
 
+/* Sets that we do not chdir to "/". */
+void
+set_no_chdir(void)
+{
+    chdir_ = false;
+}
+
 /* Normally, die_if_already_running() will terminate the program with a message
  * if a locked pidfile already exists.  If this function is called,
  * die_if_already_running() will merely log a warning. */
 void
 ignore_existing_pidfile(void)
 {
-    force = true;
+    overwrite_pidfile = true;
 }
 
 /* Sets up a following call to daemonize() to detach from the foreground
@@ -117,7 +127,7 @@ die_if_already_running(void)
 {
     pid_t pid = already_running();
     if (pid) {
-        if (!force) {
+        if (!overwrite_pidfile) {
             ovs_fatal(0, "%s: already running as pid %ld",
                       get_pidfile(), (long int) pid);
         } else {
@@ -209,7 +219,9 @@ daemonize(void)
             write(fds[1], &c, 1);
             close(fds[1]);
             setsid();
-            chdir("/");
+            if (chdir_) {
+                chdir("/");
+            }
             break;
 
         case -1:
@@ -227,9 +239,11 @@ daemon_usage(void)
 {
     printf(
         "\nDaemon options:\n"
-        "  -D, --detach            run in background as daemon\n"
-        "  -P, --pidfile[=FILE]    create pidfile (default: %s/%s.pid)\n"
-        "  -f, --force             with -P, start even if already running\n",
+        "  --detach                run in background as daemon\n"
+        "  --no-chdir              do not chdir to '/'\n"
+        "  --pidfile[=FILE]        create pidfile (default: %s/%s.pid)\n"
+        "  --overwrite-pidfile     with --pidfile, start even if already "
+                                   "running\n",
         ovs_rundir, program_name);
 }
 
index a54aa52..d0c324c 100644 (file)
 #ifndef DAEMON_H
 #define DAEMON_H 1
 
+#include <limits.h>
 #include <stdbool.h>
 #include <sys/types.h>
 
-#define DAEMON_LONG_OPTIONS                         \
-        {"detach",      no_argument, 0, 'D'},       \
-        {"force",       no_argument, 0, 'f'},       \
-        {"pidfile",     optional_argument, 0, 'P'}
+enum {
+    OPT_DETACH = UCHAR_MAX + 2048,
+    OPT_NO_CHDIR,
+    OPT_OVERWRITE_PIDFILE,
+    OPT_PIDFILE,
+};
+
+#define DAEMON_LONG_OPTIONS                                          \
+        {"detach",            no_argument, 0, OPT_DETACH},           \
+        {"no-chdir",          no_argument, 0, OPT_NO_CHDIR},         \
+        {"pidfile",           optional_argument, 0, OPT_PIDFILE},    \
+        {"overwrite-pidfile", no_argument, 0, OPT_OVERWRITE_PIDFILE}
 
 #define DAEMON_OPTION_HANDLERS                  \
-        case 'D':                               \
+        case OPT_DETACH:                        \
             set_detach();                       \
             break;                              \
                                                 \
-        case 'P':                               \
+        case OPT_NO_CHDIR:                      \
+            set_no_chdir();                     \
+            break;                              \
+                                                \
+        case OPT_PIDFILE:                       \
             set_pidfile(optarg);                \
             break;                              \
                                                 \
-        case 'f':                               \
+        case OPT_OVERWRITE_PIDFILE:             \
             ignore_existing_pidfile();          \
             break;
 
 char *make_pidfile_name(const char *name);
 void set_pidfile(const char *name);
 const char *get_pidfile(void);
+void set_no_chdir(void);
 void set_detach(void);
 void daemonize(void);
 void die_if_already_running(void);
index 4ab6568..ea0561d 100644 (file)
@@ -1,21 +1,36 @@
 .TP
-\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR]
+\fB--pidfile\fR[\fB=\fIpidfile\fR]
 Causes a file (by default, \fB\*(PN.pid\fR) to be created indicating
 the PID of the running process.  If \fIpidfile\fR is not specified, or
 if it does not begin with \fB/\fR, then it is created in
 \fB@RUNDIR@\fR.
 
 .TP
-\fB-f\fR, \fB--force\fR
-By default, when \fB-P\fR or \fB--pidfile\fR is specified and the
-specified pidfile already exists and is locked by a running process,
-\fB\*(PN\fR refuses to start.  Specify \fB-f\fR or \fB--force\fR
-to cause it to instead overwrite the pidfile.
+\fB--overwrite-pidfile\fR
+By default, when \fB--pidfile\fR is specified and the specified pidfile 
+already exists and is locked by a running process, \fB\*(PN\fR refuses 
+to start.  Specify \fB--overwrite-pidfile\fR to cause it to instead 
+overwrite the pidfile.
 
-When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no
-effect.
+When \fB--pidfile\fR is not specified, this option has no effect.
 
 .TP
-\fB-D\fR, \fB--detach\fR
+\fB--detach\fR
 Causes \fB\*(PN\fR to detach itself from the foreground session and
 run as a background process.
+
+.TP
+\fB--no-chdir\fR
+By default, when \fB--detach\fR is specified, \fB\*(PN\fR 
+changes its current working directory to the root directory after it 
+detaches.  Otherwise, invoking \fB\*(PN\fR from a carelessly chosen 
+directory would prevent the administrator from unmounting the file 
+system that holds that directory.
+.IP
+Specifying \fB--no-chdir\fR suppresses this behavior, preventing
+\fB\*(PN\fR from changing its current working directory.  This may be 
+useful for collecting core files, since it is common behavior to write 
+core dumps into the current working directory and the root directory 
+is not a good directory to use.
+.IP
+This option has no effect when \fB--detach\fR is not specified.
index c8ae00e..4f90781 100644 (file)
@@ -927,7 +927,7 @@ do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg)
         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, cli_mac))) {
             continue;
@@ -1009,8 +1009,8 @@ do_send_msg(struct dhclient *cli, const struct dhcp_msg *msg)
     nh.ip_dst = INADDR_BROADCAST;
     nh.ip_csum = csum(&nh, sizeof nh);
 
-    th.udp_src = htons(66);
-    th.udp_dst = htons(67);
+    th.udp_src = htons(DHCP_CLIENT_PORT);
+    th.udp_dst = htons(DHCP_SERVER_PORT);
     th.udp_len = htons(UDP_HEADER_LEN + b.size);
     th.udp_csum = 0;
     udp_csum = csum_add32(0, nh.ip_src);
index 07452c9..96696a2 100644 (file)
 struct ds;
 struct ofpbuf;
 
+/* Ports used by DHCP. */
+#define DHCP_SERVER_PORT        67       /* Port used by DHCP server. */
+#define DHCP_CLIENT_PORT        68       /* Port used by DHCP client. */
+
 /* Values for 'op' field. */
 #define DHCP_BOOTREQUEST        1        /* Message sent by DHCP client. */
 #define DHCP_BOOTREPLY          2        /* Message sent by DHCP server. */
index 1e0f0aa..63b59dd 100644 (file)
@@ -37,8 +37,6 @@
 #include "util.h"
 
 static void ofp_print_port_name(struct ds *string, uint16_t port);
-static void ofp_print_match(struct ds *, const struct ofp_match *,
-                            int verbosity);
 
 /* Returns a string that represents the contents of the Ethernet frame in the
  * 'len' bytes starting at 'data' to 'stream' as output by tcpdump.
@@ -380,7 +378,7 @@ ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
     return len;
 }
 
-static void 
+void 
 ofp_print_actions(struct ds *string, const struct ofp_action_header *action,
                   size_t actions_len) 
 {
@@ -627,7 +625,7 @@ print_ip_netmask(struct ds *string, const char *leader, uint32_t ip,
     ds_put_char(string, ',');
 }
 
-static void
+void
 ofp_print_match(struct ds *f, const struct ofp_match *om, int verbosity)
 {
     char *s = ofp_match_to_string(om, verbosity);
index 2c9548b..a362a65 100644 (file)
@@ -24,6 +24,8 @@
 
 struct ofp_flow_mod;
 struct ofp_match;
+struct ds;
+struct ofp_action_header;
 
 #ifdef  __cplusplus
 extern "C" {
@@ -32,11 +34,15 @@ extern "C" {
 void ofp_print(FILE *, const void *, size_t, int verbosity);
 void ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len);
 
+void ofp_print_actions(struct ds *, const struct ofp_action_header *, size_t);
+void ofp_print_match(struct ds *, const struct ofp_match *, int verbosity);
+
 char *ofp_to_string(const void *, size_t, int verbosity);
 char *ofp_match_to_string(const struct ofp_match *, int verbosity);
 char *ofp_packet_to_string(const void *data, size_t len, size_t total_len);
 char *ofp_message_type_to_string(uint8_t type);
 
+
 #ifdef  __cplusplus
 }
 #endif
index 181cae5..4c6c9e9 100644 (file)
@@ -159,7 +159,7 @@ rconn_new_from_vconn(const char *name, struct vconn *vconn)
  * 'max_backoff' is the maximum number of seconds between attempts to connect
  * to the peer.  The actual interval starts at 1 second and doubles on each
  * failure until it reaches 'max_backoff'.  If 0 is specified, the default of
- * 60 seconds is used. */
+ * 8 seconds is used. */
 struct rconn *
 rconn_create(int probe_interval, int max_backoff)
 {
@@ -175,7 +175,7 @@ rconn_create(int probe_interval, int max_backoff)
     queue_init(&rc->txq);
 
     rc->backoff = 0;
-    rc->max_backoff = max_backoff ? max_backoff : 60;
+    rc->max_backoff = max_backoff ? max_backoff : 8;
     rc->backoff_deadline = TIME_MIN;
     rc->last_received = time_now();
     rc->last_connected = time_now();
index 7d8777f..e1736bc 100644 (file)
@@ -57,4 +57,13 @@ char *svec_join(const struct svec *,
 const char *svec_back(const struct svec *);
 void svec_pop_back(struct svec *);
 
+/* Iterates over the names in SVEC, assigning each name in turn to NAME and its
+ * index to INDEX. */
+#define SVEC_FOR_EACH(INDEX, NAME, SVEC)        \
+    for ((INDEX) = 0;                           \
+         ((INDEX) < (SVEC)->n                   \
+          ? (NAME) = (SVEC)->names[INDEX], 1    \
+          : 0);                                 \
+         (INDEX)++)
+
 #endif /* svec.h */
index 97a930a..1b95d96 100644 (file)
@@ -314,7 +314,7 @@ vlog_reopen_log_file(void)
 char *
 vlog_set_levels_from_string(const char *s_)
 {
-    char *save_ptr;
+    char *save_ptr = NULL;
     char *s = xstrdup(s_);
     char *module, *facility;
 
index 0e88729..60890d4 100644 (file)
@@ -53,8 +53,9 @@ fail_open_run(struct fail_open *fo)
             memset(&flow, 0, sizeof flow);
             ofproto_delete_flow(fo->ofproto, &flow, OFPFW_ALL, 70000);
         } else {
-            VLOG_WARN("Could not connect to controller for %d seconds, "
-                      "failing open", disconn_secs);
+            VLOG_WARN("Could not connect to controller (or switch failed "
+                      "controller's post-connection admission control "
+                      "policy) for %d seconds, failing open", disconn_secs);
             fo->last_disconn_secs = disconn_secs;
 
             /* Flush all OpenFlow and datapath flows.  We will set up our
index e867c0e..0162c45 100644 (file)
@@ -107,7 +107,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 static int
 open_collector(char *dst)
 {
-    char *save_ptr;
+    char *save_ptr = NULL;
     const char *host_name;
     const char *port_string;
     struct sockaddr_in sin;
index 55eb2c2..c26cdc2 100644 (file)
@@ -26,6 +26,7 @@
 #include "coverage.h"
 #include "discovery.h"
 #include "dpif.h"
+#include "dynamic-string.h"
 #include "executer.h"
 #include "fail-open.h"
 #include "in-band.h"
@@ -51,6 +52,7 @@
 #include "svec.h"
 #include "tag.h"
 #include "timeval.h"
+#include "unixctl.h"
 #include "vconn.h"
 #include "vconn-ssl.h"
 #include "xtoxll.h"
@@ -322,7 +324,7 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
 
     /* Initialize OpenFlow connections. */
     list_init(&p->all_conns);
-    p->controller = ofconn_create(p, rconn_create(15, 15));
+    p->controller = ofconn_create(p, rconn_create(5, 8));
     p->controller->pktbuf = pktbuf_create();
     p->controller->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
     p->listeners = NULL;
@@ -1215,53 +1217,71 @@ static void
 update_port(struct ofproto *p, const char *devname)
 {
     struct odp_port odp_port;
-    struct ofport *ofport;
+    struct ofport *old_ofport;
+    struct ofport *new_ofport;
     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);
-    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;
     }
+
+    /* Create a new ofport. */
+    new_ofport = !error ? make_ofport(&odp_port) : NULL;
+
+    /* Eliminate a few pathological cases. */
+    if (!old_ofport && !new_ofport) {
+        return;
+    } else if (old_ofport && new_ofport) {
+        /* Most of the 'config' bits are OpenFlow soft state, but
+         * OFPPC_PORT_DOWN is maintained the kernel.  So transfer the OpenFlow
+         * bits from old_ofport.  (make_ofport() only sets OFPPC_PORT_DOWN and
+         * leaves the other bits 0.)  */
+        new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN;
+
+        if (ofport_equal(old_ofport, new_ofport)) {
+            /* False alarm--no change. */
+            ofport_free(new_ofport);
+            return;
+        }
+    }
+
+    /* Now deal with the normal cases. */
+    if (old_ofport) {
+        ofport_remove(p, old_ofport);
+    }
+    if (new_ofport) {
+        ofport_install(p, new_ofport);
+    }
+    send_port_status(p, new_ofport ? new_ofport : old_ofport,
+                     (!old_ofport ? OFPPR_ADD
+                      : !new_ofport ? OFPPR_DELETE
+                      : OFPPR_MODIFY));
+    ofport_free(old_ofport);
+
+    /* Update port groups. */
     refresh_port_groups(p);
 }
 
@@ -2475,6 +2495,59 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn,
     return 0;
 }
 
+struct flow_stats_ds_cbdata {
+    struct ofproto *ofproto;
+    struct ds *results;
+};
+
+static void
+flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_)
+{
+    struct rule *rule = rule_from_cls_rule(rule_);
+    struct flow_stats_ds_cbdata *cbdata = cbdata_;
+    struct ds *results = cbdata->results;
+    struct ofp_match match;
+    uint64_t packet_count, byte_count;
+    size_t act_len = sizeof *rule->actions * rule->n_actions;
+
+    /* Don't report on subrules. */
+    if (rule->super != NULL) {
+        return;
+    }
+
+    query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
+    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
+
+    ds_put_format(results, "duration=%llds, ",
+                  (time_msec() - rule->created) / 1000);
+    ds_put_format(results, "priority=%u", rule->cr.priority);
+    ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
+    ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
+    ofp_print_match(results, &match, true);
+    ofp_print_actions(results, &rule->actions->header, act_len);
+    ds_put_cstr(results, "\n");
+}
+
+/* Adds a pretty-printed description of all flows to 'results', including 
+ * those marked hidden by secchan (e.g., by in-band control). */
+void
+ofproto_get_all_flows(struct ofproto *p, struct ds *results)
+{
+    struct ofp_match match;
+    struct cls_rule target;
+    struct flow_stats_ds_cbdata cbdata;
+
+    memset(&match, 0, sizeof match);
+    match.wildcards = htonl(OFPFW_ALL);
+
+    cbdata.ofproto = p;
+    cbdata.results = results;
+
+    cls_rule_from_match(&target, &match, 0);
+    classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
+                              flow_stats_ds_cb, &cbdata);
+}
+
 struct aggregate_stats_cbdata {
     struct ofproto *ofproto;
     uint16_t out_port;
index f4c1b40..398cac4 100644 (file)
@@ -80,6 +80,7 @@ bool ofproto_get_discovery(const struct ofproto *);
 const char *ofproto_get_controller(const struct ofproto *);
 void ofproto_get_listeners(const struct ofproto *, struct svec *);
 void ofproto_get_snoops(const struct ofproto *, struct svec *);
+void ofproto_get_all_flows(struct ofproto *p, struct ds *);
 
 /* Functions for use by ofproto implementation modules, not by clients. */
 int ofproto_send_packet(struct ofproto *, const flow_t *,
index df942f5..1b52a7b 100644 (file)
@@ -60,6 +60,7 @@ open_config(char *config_file, int timeout)
 {
     int error;
 
+    cfg_init();
     error = cfg_set_file(config_file);
     if (error) {
         ovs_fatal(error, "failed to add configuration file \"%s\"",
index fcb579e..61e4b12 100644 (file)
@@ -75,7 +75,7 @@ This option is mutually exclusive with \fB--exit-without-bind\fR and
 \fB--exit-after-bind\fR.
 
 .TP
-\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR]
+\fB--pidfile\fR[\fB=\fIpidfile\fR]
 Causes a file (by default, \fBovs\-discover.pid\fR) to be created indicating
 the PID of the running process.  If \fIpidfile\fR is not specified, or
 if it does not begin with \fB/\fR, then it is created in
@@ -86,14 +86,13 @@ this this option has no effect when one of \fB--exit-without-bind\fR,
 \fB--exit-after-bind\fR, or \fB--no-detach\fR is also given.
 
 .TP
-\fB-f\fR, \fB--force\fR
-By default, when \fB-P\fR or \fB--pidfile\fR is specified and the
-specified pidfile already exists and is locked by a running process,
-\fBcontroller\fR refuses to start.  Specify \fB-f\fR or \fB--force\fR
-to cause it to instead overwrite the pidfile.
-
-When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no
-effect.
+\fB--overwrite-pidfile\fR
+By default, when \fB--pidfile\fR is specified and the specified pidfile 
+already exists and is locked by a running process, \fBcontroller\fR refuses 
+to start.  Specify \fB--overwrite-pidfile\fR to cause it to instead 
+overwrite the pidfile.
+
+When \fB--pidfile\fR is not specified, this option has no effect.
 
 .so lib/vlog.man
 .so lib/common.man
index 8c83cac..dc91bce 100644 (file)
@@ -282,7 +282,7 @@ parse_options(int argc, char *argv[])
         OPT_ACCEPT_VCONN = UCHAR_MAX + 1,
         OPT_EXIT_WITHOUT_BIND,
         OPT_EXIT_AFTER_BIND,
-        OPT_NO_DETACH,
+        OPT_NO_DETACH
     };
     static struct option long_options[] = {
         {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
@@ -290,8 +290,8 @@ parse_options(int argc, char *argv[])
         {"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND},
         {"no-detach",   no_argument, 0, OPT_NO_DETACH},
         {"timeout",     required_argument, 0, 't'},
-        {"pidfile",     optional_argument, 0, 'P'},
-        {"force",       no_argument, 0, 'f'},
+        {"pidfile",     optional_argument, 0, OPT_PIDFILE},
+        {"overwrite-pidfile", no_argument, 0, OPT_OVERWRITE_PIDFILE},
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
         {"version",     no_argument, 0, 'V'},
@@ -328,11 +328,11 @@ parse_options(int argc, char *argv[])
             detach_after_bind = false;
             break;
 
-        case 'P':
+        case OPT_PIDFILE:
             set_pidfile(optarg);
             break;
 
-        case 'f':
+        case OPT_OVERWRITE_PIDFILE:
             ignore_existing_pidfile();
             break;
 
@@ -396,8 +396,9 @@ usage(void)
     vlog_usage();
     printf("\nOther options:\n"
            "  -t, --timeout=SECS      give up discovery after SECS seconds\n"
-           "  -P, --pidfile[=FILE]    create pidfile (default: %s/%s.pid)\n"
-           "  -f, --force             with -P, start even if already running\n"
+           "  --pidfile[=FILE]        create pidfile (default: %s/%s.pid)\n"
+           "  --overwrite-pidfile     with --pidfile, start even if already "
+                                      "running\n"
            "  -h, --help              display this help message\n"
            "  -V, --version           display version information\n",
            ovs_rundir, program_name);
index 3d8854b..dc4d456 100644 (file)
@@ -1,4 +1,4 @@
-.TH ovs\-dpctl 8 "March 2009" "Open vSwitch" "Open vSwitch Manual"
+.TH ovs\-dpctl 8 "August 2009" "Open vSwitch" "Open vSwitch Manual"
 .ds PN ovs\-dpctl
 
 .SH NAME
@@ -80,6 +80,10 @@ port (analogous to the local port) with that name.
 Removes each \fInetdev\fR from the list of network devices datapath
 \fIdp\fR monitors.
 
+.TP
+\fBdump-dps\fR
+Prints the name of each configured datapath on a separate line.
+
 .TP
 \fBshow \fR[\fIdp\fR...]
 Prints a summary of configured datapaths, including their datapath
index 2702818..5a0da82 100644 (file)
@@ -36,6 +36,7 @@
 #include "dynamic-string.h"
 #include "netdev.h"
 #include "odp-util.h"
+#include "svec.h"
 #include "timeval.h"
 #include "util.h"
 
@@ -157,6 +158,7 @@ usage(void)
            "  del-dp DP                delete local datapath DP\n"
            "  add-if DP IFACE...       add each IFACE as a port on DP\n"
            "  del-if DP IFACE...       delete each IFACE from DP\n"
+           "  dump-dps                 display names of all datapaths\n"
            "  show                     show basic info on all datapaths\n"
            "  show DP...               show basic info on each DP\n"
            "  dump-flows DP            display flows in DP\n"
@@ -388,7 +390,7 @@ show_dpif(struct dpif *dpif)
 }
 
 static void
-do_show(int argc UNUSED, char *argv[])
+do_show(int argc, char *argv[])
 {
     bool failure = false;
     if (argc > 1) {
@@ -428,6 +430,30 @@ do_show(int argc UNUSED, char *argv[])
     }
 }
 
+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++) {
+        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[])
 {
@@ -506,6 +532,7 @@ static struct command all_commands[] = {
     { "del-dp", 1, 1, do_del_dp },
     { "add-if", 2, INT_MAX, do_add_if },
     { "del-if", 2, INT_MAX, do_del_if },
+    { "dump-dps", 0, 0, do_dump_dps },
     { "show", 0, INT_MAX, do_show },
     { "dump-flows", 1, 1, do_dump_flows },
     { "del-flows", 1, 1, do_del_flows },
index 4d1a858..3d25574 100644 (file)
@@ -254,7 +254,7 @@ switch waits for a message to be received from the controller for
 controller.  After sending the inactivity probe, if no response is
 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
@@ -294,7 +294,7 @@ Sets the maximum time between attempts to connect to the controller to
 \fIsecs\fR, which must be at least 1.  The actual interval between
 connection attempts starts at 1 second and doubles on each failing
 attempt until it reaches the maximum.  The default maximum backoff
-time is 15 seconds.
+time is 8 seconds.
 
 .TP
 \fB-l\fR, \fB--listen=\fImethod\fR
index 5dd77c0..603e258 100644 (file)
@@ -291,7 +291,7 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
     s->fail_mode = FAIL_OPEN;
     s->max_idle = 0;
     s->probe_interval = 0;
-    s->max_backoff = 15;
+    s->max_backoff = 8;
     s->update_resolv_conf = true;
     s->rate_limit = 0;
     s->burst_limit = 0;
@@ -353,8 +353,7 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
             } else if (!strcmp(optarg, "closed")) {
                 s->fail_mode = FAIL_CLOSED;
             } else {
-                ovs_fatal(0, "-f or --fail argument must be \"open\" "
-                          "or \"closed\"");
+                ovs_fatal(0, "--fail argument must be \"open\" or \"closed\"");
             }
             break;
 
@@ -542,7 +541,7 @@ usage(void)
            "  --inactivity-probe=SECS time between inactivity probes\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"
index 22fe19a..ea0641e 100644 (file)
@@ -131,6 +131,7 @@ struct port {
     tag_type active_iface_tag;  /* Tag for bcast flows. */
     tag_type no_ifaces_tag;     /* Tag for flows when all ifaces disabled. */
     int updelay, downdelay;     /* Delay before iface goes up/down, in ms. */
+    bool bond_compat_is_stale;  /* Need to call port_update_bond_compat()? */
 
     /* Port mirroring info. */
     mirror_mask_t src_mirrors;  /* Mirrors triggered when packet received. */
@@ -193,6 +194,7 @@ enum { DP_MAX = 256 };
 static struct bridge *bridge_create(const char *name);
 static void bridge_destroy(struct bridge *);
 static struct bridge *bridge_lookup(const char *name);
+static void bridge_unixctl_dump_flows(struct unixctl_conn *, const char *);
 static int bridge_run_one(struct bridge *);
 static void bridge_reconfigure_one(struct bridge *);
 static void bridge_reconfigure_controller(struct bridge *);
@@ -311,6 +313,8 @@ bridge_init(void)
         }
     }
 
+    unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
+
     bond_init();
     bridge_reconfigure();
 }
@@ -526,9 +530,23 @@ bridge_reconfigure(void)
 
         for (i = 0; i < add_ifaces.n; i++) {
             const char *if_name = add_ifaces.names[i];
-            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;
+
+            /* 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));
@@ -657,31 +675,74 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     memset(ea, 0xff, sizeof ea);
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
+        uint8_t iface_ea[ETH_ADDR_LEN];
+        uint64_t iface_ea_u64;
+        struct iface *iface;
+
+        /* Mirror output ports don't participate. */
         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_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;
             }
+
+            /* Grab MAC. */
             error = netdev_get_etheraddr(iface->netdev, iface_ea);
-            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 {
+            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;
             }
         }
+
+        /* 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);
@@ -990,6 +1051,27 @@ bridge_get_datapathid(const char *name)
     return br ? ofproto_get_datapath_id(br->ofproto) : 0;
 }
 
+/* Handle requests for a listing of all flows known by the OpenFlow
+ * stack, including those normally hidden. */
+static void
+bridge_unixctl_dump_flows(struct unixctl_conn *conn, const char *args)
+{
+    struct bridge *br;
+    struct ds results;
+    
+    br = bridge_lookup(args);
+    if (!br) {
+        unixctl_command_reply(conn, 501, "Unknown bridge");
+        return;
+    }
+
+    ds_init(&results);
+    ofproto_get_all_flows(br->ofproto, &results);
+
+    unixctl_command_reply(conn, 200, ds_cstr(&results));
+    ds_destroy(&results);
+}
+
 static int
 bridge_run_one(struct bridge *br)
 {
@@ -1236,7 +1318,7 @@ bridge_reconfigure_controller(struct bridge *br)
         if (probe < 5) {
             probe = cfg_get_int(0, "mgmt.inactivity-probe");
             if (probe < 5) {
-                probe = 15;
+                probe = 5;
             }
         }
         ofproto_set_probe_interval(br->ofproto, probe);
@@ -1245,7 +1327,7 @@ bridge_reconfigure_controller(struct bridge *br)
         if (!max_backoff) {
             max_backoff = cfg_get_int(0, "mgmt.max-backoff");
             if (!max_backoff) {
-                max_backoff = 15;
+                max_backoff = 8;
             }
         }
         ofproto_set_max_backoff(br->ofproto, max_backoff);
@@ -1316,9 +1398,12 @@ bridge_get_all_ifaces(const struct bridge *br, struct svec *ifaces)
             struct iface *iface = port->ifaces[j];
             svec_add(ifaces, iface->name);
         }
+        if (port->n_ifaces > 1
+            && cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
+            svec_add(ifaces, port->name);
+        }
     }
-    svec_sort(ifaces);
-    assert(svec_is_unique(ifaces));
+    svec_sort_unique(ifaces);
 }
 
 /* For robustness, in case the administrator moves around datapath ports behind
@@ -1413,6 +1498,7 @@ choose_output_iface(const struct port *port, const uint8_t *dl_src,
                 return false;
             }
             e->iface_tag = tag_create_random();
+            ((struct port *) port)->bond_compat_is_stale = true;
         }
         *tags |= e->iface_tag;
         iface = port->ifaces[e->iface_idx];
@@ -1511,6 +1597,12 @@ bond_run(struct bridge *br)
 
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
+
+        if (port->bond_compat_is_stale) {
+            port->bond_compat_is_stale = false;
+            port_update_bond_compat(port);
+        }
+
         if (port->n_ifaces < 2) {
             continue;
         }
@@ -2292,6 +2384,7 @@ bond_rebalance_port(struct port *port)
             } else {
                 from++;
             }
+            port->bond_compat_is_stale = true;
         }
     }
 
@@ -2558,6 +2651,7 @@ bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_)
     ofproto_revalidate(port->bridge->ofproto, entry->iface_tag);
     entry->iface_idx = iface->port_ifidx;
     entry->iface_tag = tag_create_random();
+    port->bond_compat_is_stale = true;
     unixctl_command_reply(conn, 200, "migrated");
 }
 
@@ -2822,6 +2916,7 @@ port_destroy(struct port *port)
         size_t i;
 
         proc_net_compat_update_vlan(port->name, NULL, 0);
+        proc_net_compat_update_bond(port->name, NULL);
 
         for (i = 0; i < MAX_MIRRORS; i++) {
             struct mirror *m = br->mirrors[i];
@@ -2888,7 +2983,7 @@ port_update_bonding(struct port *port)
         if (port->bond_hash) {
             free(port->bond_hash);
             port->bond_hash = NULL;
-            proc_net_compat_update_bond(port->name, NULL);
+            port->bond_compat_is_stale = true;
         }
     } else {
         if (!port->bond_hash) {
@@ -2903,23 +2998,39 @@ port_update_bonding(struct port *port)
             port->no_ifaces_tag = tag_create_random();
             bond_choose_active_iface(port);
         }
-        port_update_bond_compat(port);
+        port->bond_compat_is_stale = true;
     }
 }
 
 static void
 port_update_bond_compat(struct port *port)
 {
+    struct compat_bond_hash compat_hashes[BOND_MASK + 1];
     struct compat_bond bond;
     size_t i;
 
     if (port->n_ifaces < 2) {
+        proc_net_compat_update_bond(port->name, NULL);
         return;
     }
 
     bond.up = false;
     bond.updelay = port->updelay;
     bond.downdelay = port->downdelay;
+
+    bond.n_hashes = 0;
+    bond.hashes = compat_hashes;
+    if (port->bond_hash) {
+        const struct bond_entry *e;
+        for (e = port->bond_hash; e <= &port->bond_hash[BOND_MASK]; e++) {
+            if (e->iface_idx >= 0 && e->iface_idx < port->n_ifaces) {
+                struct compat_bond_hash *cbh = &bond.hashes[bond.n_hashes++];
+                cbh->hash = e - port->bond_hash;
+                cbh->netdev_name = port->ifaces[e->iface_idx]->name;
+            }
+        }
+    }
+
     bond.n_slaves = port->n_ifaces;
     bond.slaves = xmalloc(port->n_ifaces * sizeof *bond.slaves);
     for (i = 0; i < port->n_ifaces; i++) {
@@ -2933,6 +3044,7 @@ port_update_bond_compat(struct port *port)
         }
         netdev_get_etheraddr(iface->netdev, slave->mac);
     }
+
     proc_net_compat_update_bond(port->name, &bond);
     free(bond.slaves);
 }
index 45c3580..e6e7d4e 100644 (file)
@@ -526,20 +526,6 @@ send_config_update_ack(uint32_t xid, bool success)
     send_openflow_buffer(buffer);
 }
 
-static void
-send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
-            const void *data, size_t len)
-{
-    struct ofpbuf *buffer;
-    struct ofmp_error_msg *oem;
-
-    oem = make_ofmp_xid(sizeof(*oem)+len, OFMPT_ERROR, xid, &buffer);
-    oem->type = htons(type);
-    oem->code = htons(code);
-    memcpy(oem->data, data, len);
-    send_openflow_buffer(buffer);
-}
-
 static void
 send_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
             const void *data, size_t len)
@@ -654,6 +640,14 @@ recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph,
         /* xxx cfg_lock can fail for other reasons, such as being
          * xxx locked... */
         VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
+
+        /* Check if our local view matches the controller, in which
+         * case, it is likely that there were local modifications
+         * without our being told to reread the config file. */
+        if (!memcmp(cfg_cookie, ofmpcu->cookie, sizeof cfg_cookie)) {
+            VLOG_WARN_RL(&rl, "config appears to have been locally modified "
+                              "without having told ovs-vswitchd to reload");
+        }
         send_config_update_ack(xid, false);
         return 0;
     }
index 70570e9..39844f6 100644 (file)
@@ -239,21 +239,14 @@ rewrite_and_reload_config(void)
     return 0;
 }
 
-/* Get all the interfaces for 'bridge' as 'ifaces', breaking bonded interfaces
- * down into their constituent parts.
- *
- * If 'vlan' < 0, all interfaces on 'bridge' are reported.  If 'vlan' == 0,
- * then only interfaces for trunk ports or ports with implicit VLAN 0 are
- * reported.  If 'vlan' > 0, only interfaces with implict VLAN 'vlan' are
- * reported.  */
 static void
-get_bridge_ifaces(const char *bridge, struct svec *ifaces, int vlan)
+do_get_bridge_parts(const char *bridge, struct svec *parts, int vlan,
+                    bool break_down_bonds)
 {
     struct svec ports;
     int i;
 
     svec_init(&ports);
-    svec_init(ifaces);
     cfg_get_all_keys(&ports, "bridge.%s.port", bridge);
     for (i = 0; i < ports.n; i++) {
         const char *port_name = ports.names[i];
@@ -266,19 +259,44 @@ get_bridge_ifaces(const char *bridge, struct svec *ifaces, int vlan)
                 continue;
             }
         }
-        if (cfg_has_section("bonding.%s", port_name)) {
+        if (break_down_bonds && cfg_has_section("bonding.%s", port_name)) {
             struct svec slaves;
             svec_init(&slaves);
             cfg_get_all_keys(&slaves, "bonding.%s.slave", port_name);
-            svec_append(ifaces, &slaves);
+            svec_append(parts, &slaves);
             svec_destroy(&slaves);
         } else {
-            svec_add(ifaces, port_name);
+            svec_add(parts, port_name);
         }
     }
     svec_destroy(&ports);
 }
 
+/* Add all the interfaces for 'bridge' to 'ifaces', breaking bonded interfaces
+ * down into their constituent parts.
+ *
+ * If 'vlan' < 0, all interfaces on 'bridge' are reported.  If 'vlan' == 0,
+ * then only interfaces for trunk ports or ports with implicit VLAN 0 are
+ * reported.  If 'vlan' > 0, only interfaces with implicit VLAN 'vlan' are
+ * reported.  */
+static void
+get_bridge_ifaces(const char *bridge, struct svec *ifaces, int vlan)
+{
+    do_get_bridge_parts(bridge, ifaces, vlan, true);
+}
+
+/* Add all the ports for 'bridge' to 'ports'.  Bonded ports are reported under
+ * the bond name, not broken down into their constituent interfaces.
+ *
+ * If 'vlan' < 0, all ports on 'bridge' are reported.  If 'vlan' == 0, then
+ * only trunk ports or ports with implicit VLAN 0 are reported.  If 'vlan' > 0,
+ * only port with implicit VLAN 'vlan' are reported.  */
+static void
+get_bridge_ports(const char *bridge, struct svec *ports, int vlan)
+{
+    do_get_bridge_parts(bridge, ports, vlan, false);
+}
+
 /* Go through the configuration file and remove any ports that no longer
  * exist associated with a bridge. */
 static void
@@ -300,6 +318,7 @@ prune_ports(void)
         struct svec ifaces;
 
         /* Check that each bridge interface exists. */
+        svec_init(&ifaces);
         get_bridge_ifaces(br_name, &ifaces, -1);
         for (j = 0; j < ifaces.n; j++) {
             const char *iface_name = ifaces.names[j];
@@ -382,7 +401,7 @@ parse_command(struct ofpbuf *buffer, uint32_t *seq, const char **br_name,
               const char **port_name, uint64_t *count, uint64_t *skip)
 {
     static const struct nl_policy policy[] = {
-        [BRC_GENL_A_DP_NAME] = { .type = NL_A_STRING },
+        [BRC_GENL_A_DP_NAME] = { .type = NL_A_STRING, .optional = true },
         [BRC_GENL_A_PORT_NAME] = { .type = NL_A_STRING, .optional = true },
         [BRC_GENL_A_FDB_COUNT] = { .type = NL_A_U64, .optional = true },
         [BRC_GENL_A_FDB_SKIP] = { .type = NL_A_U64, .optional = true },
@@ -391,6 +410,7 @@ parse_command(struct ofpbuf *buffer, uint32_t *seq, const char **br_name,
 
     if (!nl_policy_parse(buffer, NLMSG_HDRLEN + GENL_HDRLEN, policy,
                          attrs, ARRAY_SIZE(policy))
+        || (br_name && !attrs[BRC_GENL_A_DP_NAME])
         || (port_name && !attrs[BRC_GENL_A_PORT_NAME])
         || (count && !attrs[BRC_GENL_A_FDB_COUNT])
         || (skip && !attrs[BRC_GENL_A_FDB_SKIP])) {
@@ -398,7 +418,9 @@ parse_command(struct ofpbuf *buffer, uint32_t *seq, const char **br_name,
     }
 
     *seq = ((struct nlmsghdr *) buffer->data)->nlmsg_seq;
-    *br_name = nl_attr_get_string(attrs[BRC_GENL_A_DP_NAME]);
+    if (br_name) {
+        *br_name = nl_attr_get_string(attrs[BRC_GENL_A_DP_NAME]);
+    }
     if (port_name) {
         *port_name = nl_attr_get_string(attrs[BRC_GENL_A_PORT_NAME]);
     }
@@ -411,30 +433,38 @@ parse_command(struct ofpbuf *buffer, uint32_t *seq, const char **br_name,
     return 0;
 }
 
-static void
-send_reply(uint32_t seq, int error, struct ofpbuf *fdb_query_data)
+/* Composes and returns a reply to a request made by the datapath with Netlink
+ * sequence number 'seq' and error code 'error'.  The caller may add additional
+ * attributes to the message, then it may send it with send_reply(). */
+static struct ofpbuf *
+compose_reply(uint32_t seq, int error)
 {
-    struct ofpbuf msg;
-    int retval;
-
-    /* Compose reply. */
-    ofpbuf_init(&msg, 0);
-    nl_msg_put_genlmsghdr(&msg, brc_sock, 32, brc_family, NLM_F_REQUEST,
+    struct ofpbuf *reply = ofpbuf_new(4096);
+    nl_msg_put_genlmsghdr(reply, brc_sock, 32, brc_family, NLM_F_REQUEST,
                           BRC_GENL_C_DP_RESULT, 1);
-    ((struct nlmsghdr *) msg.data)->nlmsg_seq = seq;
-    nl_msg_put_u32(&msg, BRC_GENL_A_ERR_CODE, error);
-    if (fdb_query_data) {
-        nl_msg_put_unspec(&msg, BRC_GENL_A_FDB_DATA,
-                          fdb_query_data->data, fdb_query_data->size);
-    }
+    ((struct nlmsghdr *) reply->data)->nlmsg_seq = seq;
+    nl_msg_put_u32(reply, BRC_GENL_A_ERR_CODE, error);
+    return reply;
+}
 
-    /* Send reply. */
-    retval = nl_sock_send(brc_sock, &msg, false);
+/* Sends 'reply' to the datapath and frees it. */
+static void
+send_reply(struct ofpbuf *reply)
+{
+    int retval = nl_sock_send(brc_sock, reply, false);
     if (retval) {
         VLOG_WARN_RL(&rl, "replying to brcompat request: %s",
                      strerror(retval));
     }
-    ofpbuf_uninit(&msg);
+    ofpbuf_delete(reply);
+}
+
+/* Composes and sends a reply to a request made by the datapath with Netlink
+ * sequence number 'seq' and error code 'error'. */
+static void
+send_simple_reply(uint32_t seq, int error)
+{
+    send_reply(compose_reply(seq, error));
 }
 
 static int
@@ -450,7 +480,7 @@ handle_bridge_cmd(struct ofpbuf *buffer, bool add)
         if (!error) {
             error = rewrite_and_reload_config();
         }
-        send_reply(seq, error, NULL);
+        send_simple_reply(seq, error);
     }
     return error;
 }
@@ -495,7 +525,7 @@ handle_port_cmd(struct ofpbuf *buffer, bool add)
             VLOG_INFO("%s %s %s: success", cmd_name, br_name, port_name);
             error = rewrite_and_reload_config();
         }
-        send_reply(seq, error, NULL);
+        send_simple_reply(seq, error);
     }
 
     return error;
@@ -522,6 +552,33 @@ get_bridge_containing_port(const char *port_name)
     return xmemdup0(start, end - start);
 }
 
+static int
+linux_bridge_to_ovs_bridge(const char *linux_bridge,
+                           char **ovs_bridge, int *br_vlan)
+{
+    if (bridge_exists(linux_bridge)) {
+        /* Bridge name is the same.  We are interested in VLAN 0. */
+        *ovs_bridge = xstrdup(linux_bridge);
+        *br_vlan = 0;
+        return 0;
+    } else {
+        /* No such Open vSwitch bridge 'linux_bridge', but there might be an
+         * internal port named 'linux_bridge' on some other bridge
+         * 'ovs_bridge'.  If so then we are interested in the VLAN assigned to
+         * port 'linux_bridge' on the bridge named 'ovs_bridge'. */
+        const char *port_name = linux_bridge;
+
+        *ovs_bridge = get_bridge_containing_port(port_name);
+        *br_vlan = cfg_get_vlan(0, "vlan.%s.tag", port_name);
+        if (*ovs_bridge && *br_vlan >= 0) {
+            return 0;
+        } else {
+            free(*ovs_bridge);
+            return ENODEV;
+        }
+    }
+}
+
 static int
 handle_fdb_query_cmd(struct ofpbuf *buffer)
 {
@@ -557,6 +614,7 @@ handle_fdb_query_cmd(struct ofpbuf *buffer)
     struct svec ifaces;
 
     struct ofpbuf query_data;
+    struct ofpbuf *reply;
     char *unixctl_command;
     uint64_t count, skip;
     char *output;
@@ -572,24 +630,10 @@ handle_fdb_query_cmd(struct ofpbuf *buffer)
 
     /* Figure out vswitchd bridge and VLAN. */
     cfg_read();
-    if (bridge_exists(linux_bridge)) {
-        /* Bridge name is the same.  We are interested in VLAN 0. */
-        ovs_bridge = xstrdup(linux_bridge);
-        br_vlan = 0;
-    } else {
-        /* No such Open vSwitch bridge 'linux_bridge', but there might be an
-         * internal port named 'linux_bridge' on some other bridge
-         * 'ovs_bridge'.  If so then we are interested in the VLAN assigned to
-         * port 'linux_bridge' on the bridge named 'ovs_bridge'. */
-        const char *port_name = linux_bridge;
-
-        ovs_bridge = get_bridge_containing_port(port_name);
-        br_vlan = cfg_get_vlan(0, "vlan.%s.tag", port_name);
-        if (!ovs_bridge || br_vlan < 0) {
-            free(ovs_bridge);
-            send_reply(seq, ENODEV, NULL);
-            return error;
-        }
+    error = linux_bridge_to_ovs_bridge(linux_bridge, &ovs_bridge, &br_vlan);
+    if (error) {
+        send_simple_reply(seq, error);
+        return error;
     }
 
     /* Fetch the forwarding database using ovs-appctl. */
@@ -598,12 +642,13 @@ handle_fdb_query_cmd(struct ofpbuf *buffer)
     free(unixctl_command);
     if (error) {
         free(ovs_bridge);
-        send_reply(seq, error, NULL);
+        send_simple_reply(seq, error);
         return error;
     }
 
     /* Fetch the MAC address for each interface on the bridge, so that we can
      * fill in the is_local field in the response. */
+    svec_init(&ifaces);
     get_bridge_ifaces(ovs_bridge, &ifaces, br_vlan);
     local_macs = xmalloc(ifaces.n * sizeof *local_macs);
     n_local_macs = 0;
@@ -677,13 +722,132 @@ handle_fdb_query_cmd(struct ofpbuf *buffer)
     }
     free(output);
 
-    send_reply(seq, 0, &query_data);
+    /* Compose and send reply to datapath. */
+    reply = compose_reply(seq, 0);
+    nl_msg_put_unspec(reply, BRC_GENL_A_FDB_DATA,
+                      query_data.data, query_data.size);
+    send_reply(reply);
+
+    /* Free memory. */
     ofpbuf_uninit(&query_data);
     free(ovs_bridge);
 
     return 0;
 }
 
+static void
+send_ifindex_reply(uint32_t seq, struct svec *ifaces)
+{
+    struct ofpbuf *reply;
+    const char *iface;
+    size_t n_indices;
+    int *indices;
+    size_t i;
+
+    /* Make sure that any given interface only occurs once.  This shouldn't
+     * happen, but who knows what people put into their configuration files. */
+    svec_sort_unique(ifaces);
+
+    /* Convert 'ifaces' into ifindexes. */
+    n_indices = 0;
+    indices = xmalloc(ifaces->n * sizeof *indices);
+    SVEC_FOR_EACH (i, iface, ifaces) {
+        int ifindex = if_nametoindex(iface);
+        if (ifindex) {
+            indices[n_indices++] = ifindex;
+        }
+    }
+
+    /* Compose and send reply. */
+    reply = compose_reply(seq, 0);
+    nl_msg_put_unspec(reply, BRC_GENL_A_IFINDEXES,
+                      indices, n_indices * sizeof *indices);
+    send_reply(reply);
+
+    /* Free memory. */
+    free(indices);
+}
+
+static int
+handle_get_bridges_cmd(struct ofpbuf *buffer)
+{
+    struct svec bridges;
+    const char *br_name;
+    size_t i;
+
+    uint32_t seq;
+
+    int error;
+
+    /* Parse Netlink command.
+     *
+     * The command doesn't actually have any arguments, but we need the
+     * sequence number to send the reply. */
+    error = parse_command(buffer, &seq, NULL, NULL, NULL, NULL);
+    if (error) {
+        return error;
+    }
+
+    /* Get all the real bridges and all the fake ones. */
+    cfg_read();
+    cfg_get_subsections(&bridges, "bridge");
+    SVEC_FOR_EACH (i, br_name, &bridges) {
+        const char *iface_name;
+        struct svec ifaces;
+        size_t j;
+
+        svec_init(&ifaces);
+        get_bridge_ifaces(br_name, &ifaces, -1);
+        SVEC_FOR_EACH (j, iface_name, &ifaces) {
+            if (cfg_get_bool(0, "iface.%s.fake-bridge", iface_name)) {
+                svec_add(&bridges, iface_name);
+            }
+        }
+        svec_destroy(&ifaces);
+    }
+
+    send_ifindex_reply(seq, &bridges);
+    svec_destroy(&bridges);
+
+    return 0;
+}
+
+static int
+handle_get_ports_cmd(struct ofpbuf *buffer)
+{
+    uint32_t seq;
+
+    const char *linux_bridge;
+    char *ovs_bridge;
+    int br_vlan;
+
+    struct svec ports;
+
+    int error;
+
+    /* Parse Netlink command. */
+    error = parse_command(buffer, &seq, &linux_bridge, NULL, NULL, NULL);
+    if (error) {
+        return error;
+    }
+
+    cfg_read();
+    error = linux_bridge_to_ovs_bridge(linux_bridge, &ovs_bridge, &br_vlan);
+    if (error) {
+        send_simple_reply(seq, error);
+        return error;
+    }
+
+    svec_init(&ports);
+    get_bridge_ports(ovs_bridge, &ports, br_vlan);
+    send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */
+    svec_destroy(&ports);
+
+    free(ovs_bridge);
+
+    return 0;
+}
+
 static int
 brc_recv_update(void)
 {
@@ -746,6 +910,14 @@ brc_recv_update(void)
         retval = handle_fdb_query_cmd(buffer);
         break;
 
+    case BRC_GENL_C_GET_BRIDGES:
+        retval = handle_get_bridges_cmd(buffer);
+        break;
+
+    case BRC_GENL_C_GET_PORTS:
+        retval = handle_get_ports_cmd(buffer);
+        break;
+
     default:
         retval = EPROTO;
     }
@@ -905,7 +1077,10 @@ main(int argc, char *argv[])
         }
     }
 
-    cfg_read();
+    retval = cfg_read();
+    if (retval) {
+        ovs_fatal(retval, "could not read config file");
+    }
 
     for (;;) {
         unixctl_server_run(unixctl);
@@ -1040,6 +1215,7 @@ parse_options(int argc, char *argv[])
                 "use --help for usage");
     }
 
+    cfg_init();
     config_file = argv[0];
     error = cfg_set_file(config_file);
     if (error) {
index a7b43f7..28491fc 100644 (file)
@@ -81,7 +81,10 @@ 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();
     mgmt_reconfigure();
@@ -222,6 +225,7 @@ parse_options(int argc, char *argv[])
                 "use --help for usage");
     }
 
+    cfg_init();
     config_file = argv[0];
     error = cfg_set_file(config_file);
     if (error) {
index 665d3d0..0dbf94d 100644 (file)
@@ -71,11 +71,23 @@ in the bridge, by specifying it as one of the values for key
 included, then its MAC address is by default the lowest-numbered MAC
 address among the other bridge ports, ignoring other internal ports
 and bridge ports that are
-used as port mirroring destinations (see \fBPort Mirroring\fR, below).  To
-use a specific MAC address instead, set \fBbridge.\fIname\fB.mac\fR to
-a MAC address in the format
+used as port mirroring destinations (see \fBPort Mirroring\fR, below).
+For this purpose, the MAC of a bonded port (see \fBNetwork Device
+Bonding\fR, below) is by default the MAC of its slave whose name is first in
+alphabetical order.
+There are two ways to modify this algorithm for selecting the MAC
+address of the local port:
+.IP \(bu
+To use a specific MAC address for the local port, set
+\fBbridge.\fIname\fB.mac\fR to a MAC address in the format
 \fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR, where each
-\fIx\fR is a hex digit.  If no valid MAC address can be determined
+\fIx\fR is a hex digit.
+.IP \(bu
+To override the MAC of a port for the purpose of this algorithm, set
+\fBport.\fIport\fB.mac\fR to a MAC address in the format described
+above.
+.PP
+If no valid MAC address can be determined
 either of these ways, then a MAC address is randomly generated.
 .PP
 The following syntax defines a bridge named \fBmybr\fR, configured
@@ -363,7 +375,7 @@ The specified TCP \fIport\fR (default: 6633) on the host at the given
 .PP
 The maximum time between attempts to connect to the controller may be
 specified in integral seconds with the \fBmgmt.max-backoff\fR key.  The
-default maximum backoff is 15 seconds, and the minimum value is 1
+default maximum backoff is 8 seconds, and the minimum value is 1
 second.
 
 An inactivity probe may be configured with the \fBmgmt.inactivity-probe\fR
@@ -371,7 +383,7 @@ key.  If \fBovs\-vswitchd\fR does not communicate with the controller for the
 specified number of seconds, it will send a probe.  If a response is not
 received for an additional amount of that time, \fBovs\-vswitchd\fR assumes
 the connection has been broken and attempts to reconnect.  The default
-is 15 seconds, and the minimum value is 5 seconds.
+and minimum values are both 5 seconds.
 
 A management id may be specified with the \fBmgmt.id\fR key.  It takes
 an id in the form of exactly 12 hexadecimal digits.  If one is not
index 8e8dd23..7a59526 100644 (file)
@@ -154,6 +154,12 @@ proc_net_compat_update_bond(const char *name, const struct compat_bond *bond)
         "\n"
         "Source load balancing info:\n",
         bond->up ? "up" : "down", bond->updelay, bond->downdelay);
+
+    for (i = 0; i < bond->n_hashes; i++) {
+        const struct compat_bond_hash *cbh = &bond->hashes[i];
+        ds_put_format(&ds, " [%03d] = %s\n", cbh->hash, cbh->netdev_name);
+    }
+
     for (i = 0; i < bond->n_slaves; i++) {
         const struct compat_bond_slave *slave = &bond->slaves[i];
         ds_put_format(
index a5b3196..82d550f 100644 (file)
@@ -22,10 +22,19 @@ struct compat_bond {
     bool up;
     int updelay;
     int downdelay;
+
+    int n_hashes;
+    struct compat_bond_hash *hashes;
+
     int n_slaves;
     struct compat_bond_slave *slaves;
 };
 
+struct compat_bond_hash {
+    int hash;
+    const char *netdev_name;
+};
+
 struct compat_bond_slave {
     const char *name;
     bool up;
index 2344835..6c91e94 100644 (file)
@@ -60,6 +60,10 @@ files are:
         used to control vswitch when integrated with Citrix management
         tools.
 
+    usr_sbin_xen-bugtool
+
+        vswitch-aware replacement for Citrix script of the same name.
+
     vswitch-xen.spec
 
         spec file for building RPMs to install on a XenServer host.
index 225b870..2fe1289 100644 (file)
@@ -17,4 +17,5 @@ EXTRA_DIST += \
        xenserver/opt_xensource_libexec_interface-reconfigure \
        xenserver/root_vswitch_scripts_dump-vif-details \
        xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
+       xenserver/usr_sbin_xen-bugtool \
        xenserver/vswitch-xen.spec
index eba4baf..462c2a6 100755 (executable)
@@ -27,12 +27,12 @@ test -e /etc/sysconfig/vswitch && . /etc/sysconfig/vswitch
 VSWITCH_BASE="${VSWITCH_BASE:-/root/vswitch}"
 ENABLE_BRCOMPAT="${ENABLE_BRCOMPAT:-y}"
 ENABLE_FAKE_PROC_NET="${ENABLE_FAKE_PROC_NET:-y}"
-FORCE_COREFILES="${FORCE_COREFILES:-n}"
-COREFILE_PATTERN="${COREFILE_PATTERN:-/var/log/%e-%t}"
+FORCE_COREFILES="${FORCE_COREFILES:-y}"
 
 # Config variables specific to ovs-vswitchd
 VSWITCHD_CONF="${VSWITCHD_CONF:-/etc/ovs-vswitchd.conf}"
 VSWITCHD_PIDFILE="${VSWITCHD_PIDFILE:-/var/run/ovs-vswitchd.pid}"
+VSWITCHD_RUN_DIR="${VSWITCHD_RUN_DIR:-/var/xen/vswitch}"
 VSWITCHD_PRIORITY="${VSWITCHD_PRIORITY:--5}"
 VSWITCHD_LOGFILE="${VSWITCHD_LOGFILE:-/var/log/ovs-vswitchd.log}"
 VSWITCHD_FILE_LOGLEVEL="${VSWITCHD_FILE_LOGLEVEL:-}"
@@ -45,6 +45,7 @@ VSWITCHD_VALGRIND_OPT="${VSWITCHD_VALGRIND_OPT:-}"
 
 # Config variables specific to ovs-brcompatd
 BRCOMPATD_PIDFILE="${BRCOMPATD_PIDFILE:-/var/run/ovs-brcompatd.pid}"
+BRCOMPATD_RUN_DIR="${BRCOMPATD_RUN_DIR:-/var/xen/vswitch}"
 BRCOMPATD_PRIORITY="${BRCOMPATD_PRIORITY:--5}"
 BRCOMPATD_LOGFILE="${BRCOMPATD_LOGFILE:-/var/log/ovs-brcompatd.log}"
 BRCOMPATD_FILE_LOGLEVEL="${BRCOMPATD_FILE_LOGLEVEL:-}"
@@ -78,9 +79,7 @@ function dp_list {
 }
 
 function turn_on_corefiles {
-    # This has global effect so should not normally be used...
-    ulimit -c unlimited
-    echo "$COREFILE_PATTERN" > /proc/sys/kernel/core_pattern
+    ulimit -Sc 67108864
 }
 
 function remove_all_dp {
@@ -120,6 +119,10 @@ function start_vswitchd {
     local syslog_opt="-vANY:SYSLOG:${VSWITCHD_SYSLOG_LOGLEVEL}"
     local logfile_file_opt=""
     local logfile_level_opt=""
+    if [ ! -d "$VSWITCHD_RUN_DIR" ]; then
+        mkdir -p "$VSWITCHD_RUN_DIR"
+    fi
+    cd "$VSWITCHD_RUN_DIR"
     if [ -n "$VSWITCHD_FILE_LOGLEVEL" ]; then
         logfile_level_opt="-vANY:FILE:${VSWITCHD_FILE_LOGLEVEL}"
         logfile_file_opt="--log-file=$VSWITCHD_LOGFILE"
@@ -152,9 +155,9 @@ function start_vswitchd {
     if [ "$daemonize" != "y" ]; then
         # Start in background and force a "success" message
         action "Starting ovs-vswitchd ($strace_opt$valgrind_opt)" true
-        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$vswitchd" -P"$VSWITCHD_PIDFILE" -D $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF") &
+        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$vswitchd" --pidfile="$VSWITCHD_PIDFILE" --detach --no-chdir $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF") &
     else
-        action "Starting ovs-vswitchd" nice -n "$VSWITCHD_PRIORITY" "$vswitchd" -P"$VSWITCHD_PIDFILE" -D $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF"
+        action "Starting ovs-vswitchd" nice -n "$VSWITCHD_PRIORITY" "$vswitchd" --pidfile="$VSWITCHD_PIDFILE" --detach --no-chdir $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF"
     fi
 }
 
@@ -162,7 +165,11 @@ function start_brcompatd {
     local syslog_opt="-vANY:SYSLOG:${BRCOMPATD_SYSLOG_LOGLEVEL}"
     local logfile_file_opt=""
     local logfile_level_opt=""
-    if [ -n "$BRCOMPATD_FILE_LOGLEVEL" ]; then
+    if [ -d "$BRCOMPATD_RUN_DIR" ]; then
+        mkdir -p "$BRCOMPATD_RUN_DIR"
+    fi
+    cd "$BRCOMPATD_RUN_DIR"
+    if [ ! -n "$BRCOMPATD_FILE_LOGLEVEL" ]; then
         logfile_level_opt="-vANY:FILE:${BRCOMPATD_FILE_LOGLEVEL}"
         logfile_file_opt="--log-file=$BRCOMPATD_LOGFILE"
     fi
@@ -191,9 +198,9 @@ function start_brcompatd {
     if [ "$daemonize" != "y" ]; then
         # Start in background and force a "success" message
         action "Starting ovs-brcompatd ($strace_opt$valgrind_opt)" true
-        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd" --appctl-command="$appctl_cmd" -P$BRCOMPATD_PIDFILE -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF") &
+        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd"--no-chdir --appctl-command="$appctl_cmd" --pidfile=$BRCOMPATD_PIDFILE -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF") &
     else
-        action "Starting ovs-brcompatd" nice -n "$BRCOMPATD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd" --appctl-command="$appctl_cmd" -P$BRCOMPATD_PIDFILE -D -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF"
+        action "Starting ovs-brcompatd" nice -n "$BRCOMPATD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd" --no-chdir --appctl-command="$appctl_cmd" --pidfile=$BRCOMPATD_PIDFILE --detach -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF"
     fi
 }
 
@@ -246,6 +253,11 @@ function start {
     fi
 
     insert_modules_if_required
+
+    # Increase the limit on the number of open file descriptors since
+    # ovs-vswitchd needs a few per bridge
+    ulimit -n 4096
+
     start_vswitchd
     start_brcompatd
     reload_vswitchd  # ensures ovs-vswitchd has fully read config file.
index cd13b59..789d61a 100644 (file)
@@ -21,7 +21,7 @@
 # ENABLE_FAKE_PROC_NET=y
 
 # FORCE_COREFILES: If 'y' then core files will be enabled.
-# FORCE_COREFILES=n
+# FORCE_COREFILES=y
 
 # COREFILE_PATTERN: Pattern used to determine path and filename for
 #     core files when FORCE_COREFILES is 'y'.  This is Linux specific.
 #     ovs-vswitchd.
 # VSWITCHD_PIDFILE=/var/run/ovs-vswitchd.pid
 
+# VSWITCHD_RUN_DIR: Set the directory in which ovs-vswitchd should be
+#     run.  This mainly affects where core files will be placed.
+# VSWITCHD_RUN_DIR=/var/xen/vswitch
+
 # VSWITCHD_PRIORITY: "nice" priority at which to run ovs-vswitchd and related
 #     processes.
 # VSWITCHD_PRIORITY=-5
 #     the default is to use brcompat!
 # BRCOMPATD_PIDFILE=/var/run/ovs-brcompatd.pid
 
+# BRCOMPATD_RUN_DIR: Set the directory in which ovs-brcompatd should be
+#     run.  This mainly affects where core files will be placed.
+# BRCOMPATD_RUN_DIR=/var/xen/vswitch
+
 # BRCOMPATD_PRIORITY: "nice" priority at which to run ovs-vswitchd and related
 #     processes.
 # BRCOMPATD_PRIORITY=-5
index aebb4cc..c3baba9 100755 (executable)
@@ -1,8 +1,6 @@
 #!/bin/sh
 
-# This file is based on /etc/xensource/script/vif from Citrix XenServer 5.0.0.
-# The original file did not contain a copyright notice or license statement.
-#
+# Copyright (C) 2008,2009 Citrix Systems, Inc. All rights reserved.
 # Copyright (C) 2009 Nicira Networks, Inc.
 
 # CA-23900: Warning: when VIFs are added to windows guests with PV drivers the backend vif device is registered,
@@ -33,8 +31,8 @@ handle_promiscuous()
     local arg=$(xenstore-read "${PRIVATE}/other-config/promiscuous")
     if [ $? -eq 0 -a -n "${arg}" ] ; then
         case "${arg}" in 
-            true|on) echo 1 > /sys/class/net/${vif}/brport/promisc ;;
-            *) echo 0 > /sys/class/net/${vif}/brport/promisc ;;
+            true|on) logger -t script-vif "${vif}: Promiscuous ports are not supported via vSwitch." ;;
+            *) ;;
         esac
     fi
 }
index 5f1ca82..98bcf4c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 #
-# Copyright (c) Citrix Systems 2008. All rights reserved.
+# Copyright (c) 2008,2009 Citrix Systems, Inc. All rights reserved.
 # Copyright (c) 2009 Nicira Networks.
 #
 """Usage:
@@ -62,6 +62,7 @@ import syslog
 import traceback
 import time
 import re
+import random
 from xml.dom.minidom import getDOMImplementation
 from xml.dom.minidom import parse as parseXML
 
@@ -249,6 +250,33 @@ 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.
 #
@@ -653,23 +681,29 @@ The ipdev name is the same as the bridge name.
     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':
-        return physdev_names(get_vlan_slave_of_pif(pif))
+        return [get_vlan_slave_of_pif(pif)]
     elif len(pifrec['bond_master_of']) != 0:
-        physdevs = []
-        for slave in get_bond_slaves_of_pif(pif):
-            physdevs += physdev_names(slave)
-        return physdevs
+        return get_bond_slaves_of_pif(pif)
     else:
-        return [pifrec['device']]
+        return [pif]
+
+def get_physdev_names(pif):
+    """Return the name(s) of the physical network device(s) associated with pif.
+For a VLAN PIF, the physical devices are the VLAN slave's physical devices.
+For a bond master PIF, the physical devices are the bond slaves.
+For a non-VLAN, non-bond master PIF, the physical device is the PIF itself.
+"""
+
+    return [db.get_pif_record(phys)['device'] for phys in get_physdev_pifs(pif)]
 
 def log_pif_action(action, pif):
     pifrec = db.get_pif_record(pif)
@@ -764,31 +798,76 @@ def run_command(command):
         return False
     return True
 
+def rename_netdev(old_name, new_name):
+    log("Changing the name of %s to %s" % (old_name, new_name))
+    run_command(['/sbin/ifconfig', old_name, 'down'])
+    if not run_command(['/sbin/ip', 'link', 'set', old_name,
+                        'name', new_name]):
+        raise Error("Could not rename %s to %s" % (old_name, new_name))
+
+# Check whether 'pif' exists and has the correct MAC.
+# If not, try to find a device with the correct MAC and rename it.
+# 'already_renamed' is used to avoid infinite recursion.
+def remap_pif(pif, already_renamed=[]):
+    pifrec = db.get_pif_record(pif)
+    device = pifrec['device']
+    mac = pifrec['MAC']
+
+    # Is there a network device named 'device' at all?
+    device_exists = interface_exists(device)
+    if device_exists:
+        # Yes.  Does it have MAC 'mac'?
+        found_mac = get_netdev_mac(device)
+        if found_mac and mac.lower() == found_mac.lower():
+            # Yes, everything checks out the way we want.  Nothing to do.
+            return
+    else:
+        log("No network device %s" % device)
+
+    # What device has MAC 'mac'?
+    cur_device = get_netdev_by_mac(mac)
+    if not cur_device:
+        log("No network device has MAC %s" % mac)
+        return
+
+    # First rename 'device', if it exists, to get it out of the way
+    # for 'cur_device' to replace it.
+    if device_exists:
+        rename_netdev(device, "dev%d" % random.getrandbits(24))
+
+    # Rename 'cur_device' to 'device'.
+    rename_netdev(cur_device, device)
+
+def read_first_line_of_file(name):
+    file = None
+    try:
+        file = open(name, 'r')
+        return file.readline().rstrip('\n')
+    finally:
+        if file != None:
+            file.close()
+
 def down_netdev(interface, deconfigure=True):
     if not interface_exists(interface):
         log("down_netdev: interface %s does not exist, ignoring" % interface)
         return
-    argv = ["/sbin/ifconfig", interface, 'down']
     if deconfigure:
-        argv += ['0.0.0.0']
-
         # Kill dhclient.
         pidfile_name = '/var/run/dhclient-%s.pid' % interface
-        pidfile = None
         try:
-            pidfile = open(pidfile_name, 'r')
-            os.kill(int(pidfile.readline()), signal.SIGTERM)
+            os.kill(int(read_first_line_of_file(pidfile_name)), signal.SIGTERM)
         except:
             pass
-        if pidfile != None:
-            pidfile.close()
 
         # Remove dhclient pidfile.
         try:
             os.remove(pidfile_name)
         except:
             pass
-    run_command(argv)
+        
+        run_command(["/sbin/ifconfig", interface, '0.0.0.0'])
+
+    run_command(["/sbin/ifconfig", interface, 'down'])
 
 def up_netdev(interface):
     run_command(["/sbin/ifconfig", interface, 'up'])
@@ -837,8 +916,8 @@ we should bring down that master."""
 
     return peerdns_pif, defaultroute_pif
 
-def ethtool_settings(oc):
-    # Options for "ethtool -s"
+def run_ethtool(device, oc):
+    # Run "ethtool -s" if there are any settings.
     settings = []
     if oc.has_key('ethtool-speed'):
         val = oc['ethtool-speed']
@@ -860,8 +939,10 @@ def ethtool_settings(oc):
             settings += ['autoneg', 'off']
         else:
             log("Invalid value for ethtool-autoneg = %s. Must be on|true|off|false." % val)
+    if settings:
+        run_command(['/sbin/ethtool', '-s', device] + settings)
 
-    # Options for "ethtool -K"
+    # Run "ethtool -K" if there are any offload settings.
     offload = []
     for opt in ("rx", "tx", "sg", "tso", "ufo", "gso"):
         if oc.has_key("ethtool-" + opt):
@@ -872,10 +953,19 @@ def ethtool_settings(oc):
                 offload += [opt, 'off']
             else:
                 log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val))
+    if offload:
+        run_command(['/sbin/ethtool', '-K', device] + offload)
 
-    return settings, offload
+def mtu_setting(oc):
+    if oc.has_key('mtu'):
+        try:
+            int(oc['mtu'])      # Check that the value is an integer
+            return ['mtu', oc['mtu']]
+        except ValueError, x:
+            log("Invalid value for mtu = %s" % mtu)
+    return []
 
-def configure_netdev(pif):
+def configure_local_port(pif):
     pifrec = db.get_pif_record(pif)
     datapath = datapath_name(pif)
     ipdev = ipdev_name(pif)
@@ -883,6 +973,10 @@ def configure_netdev(pif):
     nw = pifrec['network']
     nwrec = db.get_network_record(nw)
 
+    pif_oc = pifrec['other_config']
+    nw_oc = nwrec['other_config']
+
+    # IP (except DHCP) and MTU.
     ifconfig_argv = ['/sbin/ifconfig', ipdev, 'up']
     gateway = ''
     if pifrec['ip_configuration_mode'] == "DHCP":
@@ -896,45 +990,37 @@ def configure_netdev(pif):
         pass
     else:
         raise Error("Unknown IP-configuration-mode %s" % pifrec['ip_configuration_mode'])
-
-    oc = {}
-    if pifrec.has_key('other_config'):
-        oc = pifrec['other_config']
-        if oc.has_key('mtu'):
-            int(oc['mtu'])      # Check that the value is an integer
-            ifconfig_argv += ['mtu', oc['mtu']]
-
+    ifconfig_argv += mtu_setting(nw_oc)
     run_command(ifconfig_argv)
     
     (peerdns_pif, defaultroute_pif) = find_distinguished_pifs(pif)
 
+    # /etc/resolv.conf
     if peerdns_pif == pif:
         f = ConfigurationFile('resolv.conf', "/etc")
-        if oc.has_key('domain'):
-            f.write("search %s\n" % oc['domain'])
+        if pif_oc.has_key('domain'):
+            f.write("search %s\n" % pif_oc['domain'])
         for dns in pifrec['DNS'].split(","): 
             f.write("nameserver %s\n" % dns)
         f.close()
         f.apply()
         f.commit()
 
+    # Routing.
     if defaultroute_pif == pif and gateway != '':
         run_command(['/sbin/ip', 'route', 'replace', 'default',
                      'via', gateway, 'dev', ipdev])
-    
-    if oc.has_key('static-routes'):
-        for line in oc['static-routes'].split(','):
+    if nw_oc.has_key('static-routes'):
+        for line in nw_oc['static-routes'].split(','):
             network, masklen, gateway = line.split('/')
             run_command(['/sbin/ip', 'route', 'add',
-                         '%s/%s' % (netmask, masklen), 'via', gateway,
+                         '%s/%s' % (network, masklen), 'via', gateway,
                          'dev', ipdev])
 
-    settings, offload = ethtool_settings(oc)
-    if settings:
-        run_command(['/sbin/ethtool', '-s', ipdev] + settings)
-    if offload:
-        run_command(['/sbin/ethtool', '-K', ipdev] + offload)
+    # Ethtool.
+    run_ethtool(ipdev, nw_oc)
 
+    # DHCP.
     if pifrec['ip_configuration_mode'] == "DHCP":
         print
         print "Determining IP information for %s..." % ipdev,
@@ -947,6 +1033,14 @@ def configure_netdev(pif):
         else:
             print 'failed.'
 
+def configure_physdev(pif):
+    pifrec = db.get_pif_record(pif)
+    device = pifrec['device']
+    oc = pifrec['other_config']
+
+    run_command(['/sbin/ifconfig', device, 'up'] + mtu_setting(oc))
+    run_ethtool(device, oc)
+
 def modify_config(commands):
     run_command(['/root/vswitch/bin/ovs-cfg-mod', '-vANY:console:emer',
                  '-F', '/etc/ovs-vswitchd.conf']
@@ -962,11 +1056,15 @@ def configure_bond(pif):
     interface = interface_name(pif)
     ipdev = ipdev_name(pif)
     datapath = datapath_name(pif)
-    physdevs = physdev_names(pif)
+    physdev_names = get_physdev_names(pif)
 
     argv = ['--del-match=bonding.%s.[!0-9]*' % interface]
     argv += ["--add=bonding.%s.slave=%s" % (interface, slave)
-             for slave in physdevs]
+             for slave in physdev_names]
+    argv += ['--add=bonding.%s.fake-iface=true' % interface]
+
+    if pifrec['MAC'] != "":
+        argv += ['--add=port.%s.mac=%s' % (interface, pifrec['MAC'])]
 
     # Bonding options.
     bond_options = { 
@@ -994,7 +1092,8 @@ def action_up(pif):
     interface = interface_name(pif)
     ipdev = ipdev_name(pif)
     datapath = datapath_name(pif)
-    physdevs = physdev_names(pif)
+    physdev_pifs = get_physdev_pifs(pif)
+    physdev_names = get_physdev_names(pif)
     vlan_slave = None
     if pifrec['VLAN'] != '-1':
         vlan_slave = get_vlan_slave_of_pif(pif)
@@ -1048,10 +1147,15 @@ def action_up(pif):
     f.apply()
     f.commit()
 
+    # Check the MAC address of each network device and remap if
+    # necessary to make names match our expectations.
+    for physdev_pif in physdev_pifs:
+        remap_pif(physdev_pif)
+
     # "ifconfig down" the network device and delete its IP address, etc.
     down_netdev(ipdev)
-    for physdev in physdevs:
-        down_netdev(physdev)
+    for physdev_name in physdev_names:
+        down_netdev(physdev_name)
 
     # If we are bringing up a bond, remove IP addresses from the
     # slaves (because we are implicitly being asked to take them down).
@@ -1063,7 +1167,7 @@ def action_up(pif):
         run_command(["/sbin/ifconfig", ipdev_name(bond_pif), '0.0.0.0']) 
 
     # Remove all keys related to pif and any bond masters linked to PIF.
-    del_ports = [ipdev] + physdevs + bond_masters
+    del_ports = [ipdev] + physdev_names + bond_masters
     if vlan_slave and bond_master:
         del_ports += [interface_name(bond_master)]
     
@@ -1074,7 +1178,7 @@ def action_up(pif):
     # port.
     add_ports = [ipdev, datapath]
     if not bond_master:
-        add_ports += physdevs
+        add_ports += physdev_names
     else:
         add_ports += [interface_name(bond_master)]
 
@@ -1089,7 +1193,7 @@ def action_up(pif):
     #  - The bond masters for pif.  (Ordinarily pif shouldn't have any
     #    bond masters.  If it does then interface-reconfigure is
     #    implicitly being asked to take them down.)
-    del_ports = add_ports + physdevs + bond_masters
+    del_ports = add_ports + physdev_names + bond_masters
 
     # What networks does this datapath carry?
     #
@@ -1106,11 +1210,11 @@ def action_up(pif):
     # enables or disables bond slaves based on whether carrier is
     # detected when they are added, and a network device that is down
     # always reports "no carrier".
-    bond_slave_physdevs = []
+    bond_slave_physdev_pifs = []
     for slave in bond_slaves:
-        bond_slave_physdevs += physdev_names(slave)
-    for slave_physdev in bond_slave_physdevs:
-        up_netdev(slave_physdev)
+        bond_slave_physdev_pifs += get_physdev_pifs(slave)
+    for slave_physdev_pif in set(bond_slave_physdev_pifs):
+        configure_physdev(slave_physdev_pif)
 
     # Now modify the ovs-vswitchd config file.
     argv = []
@@ -1143,15 +1247,15 @@ def action_up(pif):
         argv += configure_bond(bond_master)
     modify_config(argv)
 
-    # Configure network devices.
-    configure_netdev(pif)
-
     # Bring up VLAN slave, plus physical devices other than bond
     # slaves (which we brought up earlier).
     if vlan_slave:
         up_netdev(ipdev_name(vlan_slave))
-    for physdev in set(physdevs) - set(bond_slave_physdevs):
-        up_netdev(physdev)
+    for physdev_pif in set(physdev_pifs) - set(bond_slave_physdev_pifs):
+        configure_physdev(physdev_pif)
+
+    # Configure network device for local port.
+    configure_local_port(pif)
 
     # Update /etc/issue (which contains the IP address of the management interface)
     os.system("/sbin/update-issue")
diff --git a/xenserver/usr_sbin_xen-bugtool b/xenserver/usr_sbin_xen-bugtool
new file mode 100755 (executable)
index 0000000..0c97601
--- /dev/null
@@ -0,0 +1,1451 @@
+#!/usr/bin/env python
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# Copyright (c) 2005, 2007 XenSource Ltd.
+
+
+#
+# To add new entries to the bugtool, you need to:
+#
+# Create a new capability.  These declare the new entry to the GUI, including
+# the expected size, time to collect, privacy implications, and whether the
+# capability should be selected by default.  One capability may refer to
+# multiple files, assuming that they can be reasonably grouped together, and
+# have the same privacy implications.  You need:
+#
+#   A new CAP_ constant.
+#   A cap() invocation to declare the capability.
+#
+# You then need to add calls to main() to collect the files.  These will
+# typically be calls to the helpers file_output(), tree_output(), cmd_output(),
+# or func_output().
+#
+
+import getopt
+import re
+import os
+import StringIO
+import sys
+import tarfile
+import time
+import commands
+import pprint
+from xml.dom.minidom import parse, getDOMImplementation
+import zipfile
+from subprocess import Popen, PIPE
+from select import select
+from signal import SIGTERM, SIGUSR1
+import md5
+import platform
+import fcntl
+import glob
+import urllib
+import socket
+import base64
+
+sys.path.append('/usr/lib/python')
+sys.path.append('/usr/lib64/python')
+
+import xen.lowlevel.xc
+import XenAPI
+
+OS_RELEASE = platform.release()
+
+#
+# Files & directories
+#
+
+BUG_DIR = "/var/opt/xen/bug-report"
+XAPI_BLOBS = '/var/xapi/blobs'
+EXTLINUX_CONFIG = '/boot/extlinux.conf'
+GRUB_CONFIG = '/boot/grub/menu.lst'
+BOOT_KERNEL = '/boot/vmlinuz-' + OS_RELEASE
+BOOT_INITRD = '/boot/initrd-' + OS_RELEASE + '.img'
+PROC_PARTITIONS = '/proc/partitions'
+FSTAB = '/etc/fstab'
+PROC_MOUNTS = '/proc/mounts'
+ISCSI_CONF = '/etc/iscsi/iscsid.conf'
+ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
+LVM_CACHE = '/etc/lvm/.cache'
+PROC_CPUINFO = '/proc/cpuinfo'
+PROC_MEMINFO = '/proc/meminfo'
+PROC_IOPORTS = '/proc/ioports'
+PROC_INTERRUPTS = '/proc/interrupts'
+PROC_SCSI = '/proc/scsi/scsi'
+FIRSTBOOT_DIR = '/etc/firstboot.d'
+PROC_VERSION = '/proc/version'
+PROC_MODULES = '/proc/modules'
+PROC_DEVICES = '/proc/devices'
+PROC_FILESYSTEMS = '/proc/filesystems'
+PROC_CMDLINE = '/proc/cmdline'
+PROC_CONFIG = '/proc/config.gz'
+PROC_USB_DEV = '/proc/bus/usb/devices'
+PROC_XEN_BALLOON = '/proc/xen/balloon'
+PROC_NET_BONDING_DIR = '/proc/net/bonding'
+PROC_NET_VLAN_DIR = '/proc/net/vlan'
+PROC_NET_SOFTNET_STAT = '/proc/net/softnet_stat'
+PROC_DRIVER_CCISS_DIR = '/proc/driver/cciss'
+MODPROBE_CONF = '/etc/modprobe.conf'
+MODPROBE_DIR = '/etc/modprobe.d'
+BOOT_TIME_CPUS = '/etc/xensource/boot_time_cpus'
+BOOT_TIME_MEMORY = '/etc/xensource/boot_time_memory'
+SYSCONFIG_HWCONF = '/etc/sysconfig/hwconf'
+SYSCONFIG_NETWORK = '/etc/sysconfig/network'
+SYSCONFIG_NETWORK_SCRIPTS = '/etc/sysconfig/network-scripts'
+IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
+ROUTE_RE = re.compile(r'^.*/route-.*')
+RESOLV_CONF = '/etc/resolv.conf'
+MULTIPATH_CONF = '/etc/multipath.conf'
+NSSWITCH_CONF = '/etc/nsswitch.conf'
+NTP_CONF = '/etc/ntp.conf'
+IPTABLES_CONFIG = '/etc/sysconfig/iptables-config'
+HOSTS_ALLOW = '/etc/hosts.allow'
+HOSTS_DENY = '/etc/hosts.deny'
+DHCP_LEASE_DIR = '/var/lib/dhclient'
+DELL_OMSA_LOGS = '/var/log/dell'
+HP_CMA_LOG = '/var/spool/compaq/cma.log'
+HP_HPASMD_LOG = '/var/spool/compaq/hpasmd.log'
+VAR_LOG_DIR = '/var/log/'
+VNCTERM_CORE_DIR = '/var/xen/vncterm'
+VSWITCH_CORE_DIR = '/var/xen/vswitch'
+OVS_VSWITCH_CONF = '/etc/ovs-vswitchd.conf'
+XENSOURCE_INVENTORY = '/etc/xensource-inventory'
+OEM_CONFIG_DIR = '/var/xsconfig'
+OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
+OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
+INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
+VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
+STATIC_VDIS = '/etc/xensource/static-vdis'
+POOL_CONF = '/etc/xensource/pool.conf'
+PTOKEN = '/etc/xensource/ptoken'
+XAPI_CONF = '/etc/xensource/xapi.conf'
+XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
+DB_CONF = '/etc/xensource/db.conf'
+DB_CONF_RIO = '/etc/xensource/db.conf.rio'
+DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
+DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
+XENSTORED_DB = '/var/lib/xenstored/tdb'
+HOST_CRASHDUMPS_DIR = '/var/crash'
+HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
+X11_LOGS_DIR = VAR_LOG_DIR
+X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
+X11_AUTH_DIR = '/root/'
+X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
+XAPI_DEBUG_DIR = '/var/xapi/debug'
+LOG_CONF = '/etc/xensource/log.conf'
+INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
+PATCH_APPLIED_DIR = '/var/patch/applied'
+XENSERVER_LOGS = \
+    [ VAR_LOG_DIR + x for x in
+      ['xensource.log', 'xenstored-access.log', 'SMlog', 'xen/xenstored-trace.log', 
+       'xen/xen-hotplug.log', 'xen/domain-builder-ng.log'] +
+      [ f % n for n in range(1, 20) \
+            for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz',
+                      'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
+                      'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz' ]]] \
+      + glob.glob('/tmp/qemu.[0-9]*')
+OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
+XHA_LOG = '/var/log/xha.log'
+XHAD_CONF = '/etc/xensource/xhad.conf'
+YUM_LOG = '/var/log/yum.log'
+YUM_REPOS_DIR = '/etc/yum.repos.d'
+PAM_DIR = '/etc/pam.d'
+
+
+#
+# External programs
+#
+
+ARP = '/sbin/arp'
+BIOSDEVNAME = '/sbin/biosdevname'
+BRCTL = '/usr/sbin/brctl'
+CAT = '/bin/cat'
+CHKCONFIG = '/sbin/chkconfig'
+CSL = '/opt/Citrix/StorageLink/bin/csl'
+DF = '/bin/df'
+DMESG = '/bin/dmesg'
+DMIDECODE = '/usr/sbin/dmidecode'
+DMSETUP = '/sbin/dmsetup'
+ETHTOOL = '/sbin/ethtool'
+FDISK = '/sbin/fdisk'
+FIND = '/usr/bin/find'
+HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
+HDPARM = '/sbin/hdparm'
+IFCONFIG = '/sbin/ifconfig'
+IPTABLES = '/sbin/iptables'
+ISCSIADM = '/sbin/iscsiadm'
+LIST_DOMAINS = '/opt/xensource/bin/list_domains'
+LOSETUP = '/sbin/losetup'
+LS = '/bin/ls'
+LSPCI = '/sbin/lspci'
+LVS = '/usr/sbin/lvs'
+MD5SUM = '/usr/bin/md5sum'
+MULTIPATHD = '/sbin/multipathd'
+NETSTAT = '/bin/netstat'
+OMREPORT = '/opt/dell/srvadmin/oma/bin/omreport'
+OVS_DPCTL = '/root/vswitch/bin/ovs-dpctl'
+OVS_OFCTL = '/root/vswitch/bin/ovs-ofctl'
+PS = '/bin/ps'
+PVS = '/usr/sbin/pvs'
+ROUTE = '/sbin/route'
+RPM = '/bin/rpm'
+SG_MAP = '/usr/bin/sg_map'
+SQLITE = '/usr/bin/sqlite3'
+BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
+SYSCTL = '/sbin/sysctl'
+TC = '/sbin/tc'
+UPTIME = '/usr/bin/uptime'
+VGS = '/usr/sbin/vgs'
+VGSCAN = '/sbin/vgscan'
+XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
+XE = '/opt/xensource/bin/xe'
+XS = '/opt/xensource/debug/xs'
+XENSTORE_LS = '/usr/bin/xenstore-ls'
+ZCAT = '/bin/zcat'
+
+#
+# PII -- Personally identifiable information.  Of particular concern are
+# things that would identify customers, or their network topology.
+# Passwords are never to be included in any bug report, regardless of any PII
+# declaration.
+#
+# NO            -- No PII will be in these entries.
+# YES           -- PII will likely or certainly be in these entries.
+# MAYBE         -- The user may wish to audit these entries for PII.
+# IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
+# but since we encourage customers to edit these files, PII may have been
+# introduced by the customer.  This is used in particular for the networking
+# scripts in dom0.
+#
+
+PII_NO            = 'no'
+PII_YES           = 'yes'
+PII_MAYBE         = 'maybe'
+PII_IF_CUSTOMIZED = 'if_customized'
+
+KEY      = 0
+PII      = 1
+MIN_SIZE = 2
+MAX_SIZE = 3
+MIN_TIME = 4
+MAX_TIME = 5
+MIME     = 6
+CHECKED  = 7
+
+MIME_DATA = 'application/data'
+MIME_TEXT = 'text/plain'
+
+INVENTORY_XML_ROOT = "system-status-inventory"
+INVENTORY_XML_SUMMARY = 'system-summary'
+INVENTORY_XML_ELEMENT = 'inventory-entry'
+CAP_XML_ROOT = "system-status-capabilities"
+CAP_XML_ELEMENT = 'capability'
+
+
+CAP_BLOBS                = 'blobs'
+CAP_BOOT_LOADER          = 'boot-loader'
+CAP_CVSM                 = 'CVSM'
+CAP_DISK_INFO            = 'disk-info'
+CAP_FIRSTBOOT            = 'firstboot'
+CAP_HARDWARE_INFO        = 'hardware-info'
+CAP_HDPARM_T             = 'hdparm-t'
+CAP_HIGH_AVAILABILITY    = 'high-availability'
+CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
+CAP_HOST_CRASHDUMP_LOGS  = 'host-crashdump-logs'
+CAP_KERNEL_INFO          = 'kernel-info'
+CAP_LOSETUP_A            = 'loopback-devices'
+CAP_MULTIPATH            = 'multipath'
+CAP_NETWORK_CONFIG       = 'network-config'
+CAP_NETWORK_STATUS       = 'network-status'
+CAP_OEM                  = 'oem'
+CAP_PAM                  = 'pam'
+CAP_PROCESS_LIST         = 'process-list'
+CAP_PERSISTENT_STATS     = 'persistent-stats'
+CAP_SYSTEM_LOGS          = 'system-logs'
+CAP_SYSTEM_SERVICES      = 'system-services'
+CAP_TAPDISK_LOGS         = 'tapdisk-logs'
+CAP_VNCTERM              = 'vncterm'
+CAP_VSWITCH_CONFIG       = 'vswitch-config'
+CAP_VSWITCH_STATUS       = 'vswitch-status'
+CAP_WLB                  = 'wlb'
+CAP_X11_LOGS             = 'X11'
+CAP_X11_AUTH             = 'X11-auth'
+CAP_XAPI_DEBUG           = 'xapi-debug'
+CAP_XAPI_SUBPROCESS      = 'xapi-subprocess'
+CAP_XENSERVER_CONFIG     = 'xenserver-config'
+CAP_XENSERVER_DOMAINS    = 'xenserver-domains'
+CAP_XENSERVER_DATABASES  = 'xenserver-databases'
+CAP_XENSERVER_INSTALL    = 'xenserver-install'
+CAP_XENSERVER_LOGS       = 'xenserver-logs'
+CAP_XEN_INFO             = 'xen-info'
+CAP_XHA_LIVESET          = 'xha-liveset'
+CAP_YUM                  = 'yum'
+
+KB = 1024
+MB = 1024 * 1024
+
+caps = {}
+cap_sizes = {}
+unlimited_data = False
+dbg = False
+
+def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
+        max_time=-1, mime=MIME_TEXT, checked=True):
+    caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
+                 checked)
+    cap_sizes[key] = 0
+
+
+cap(CAP_BLOBS,               PII_NO,                    max_size=5*MB)
+cap(CAP_BOOT_LOADER,         PII_NO,                    max_size=3*KB,
+    max_time=5)
+cap(CAP_CVSM,                PII_NO,                    max_size=3*MB,
+    max_time=60)
+cap(CAP_DISK_INFO,           PII_MAYBE,                 max_size=25*KB,
+    max_time=20)
+cap(CAP_FIRSTBOOT,           PII_YES,   min_size=60*KB, max_size=80*KB)
+cap(CAP_HARDWARE_INFO,       PII_MAYBE,                 max_size=30*KB,
+    max_time=20)
+cap(CAP_HDPARM_T,            PII_NO,    min_size=0,     max_size=5*KB,
+    min_time=20, max_time=90, checked=False)
+cap(CAP_HIGH_AVAILABILITY,   PII_MAYBE,                 max_size=5*MB)
+cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
+cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
+cap(CAP_KERNEL_INFO,         PII_MAYBE,                 max_size=80*KB,
+    max_time=5)
+cap(CAP_LOSETUP_A,           PII_MAYBE,                 max_size=KB, max_time=5)
+cap(CAP_MULTIPATH,           PII_MAYBE,                 max_size=10*KB,
+    max_time=10)
+cap(CAP_NETWORK_CONFIG,      PII_IF_CUSTOMIZED,
+                                        min_size=0,     max_size=20*KB)
+cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=19*KB,
+    max_time=30)
+cap(CAP_PAM,                 PII_NO,                    max_size=10*KB)
+cap(CAP_PERSISTENT_STATS,    PII_MAYBE,                 max_size=50*MB,
+    max_time=60)
+cap(CAP_PROCESS_LIST,        PII_YES,                   max_size=10*KB,
+    max_time=10)
+cap(CAP_SYSTEM_LOGS,         PII_MAYBE,                 max_size=50*MB,
+    max_time=5)
+cap(CAP_SYSTEM_SERVICES,     PII_NO,                    max_size=5*KB,
+    max_time=20)
+cap(CAP_TAPDISK_LOGS,        PII_NO,                    max_size=64*KB)
+cap(CAP_VNCTERM,             PII_MAYBE, checked = False)
+cap(CAP_VSWITCH_CONFIG,      PII_YES,
+                                        min_size=0,     max_size=20*MB)
+cap(CAP_VSWITCH_STATUS,      PII_YES,                   max_size=19*KB,
+    max_time=30)
+cap(CAP_WLB,                 PII_NO,                    max_size=3*MB,
+    max_time=20)
+cap(CAP_X11_LOGS,            PII_NO,                    max_size=100*KB)
+cap(CAP_X11_AUTH,            PII_NO,                    max_size=100*KB)
+cap(CAP_XAPI_DEBUG,          PII_MAYBE,                 max_size=10*MB)
+cap(CAP_XAPI_SUBPROCESS,     PII_NO,                    max_size=5*KB,
+    max_time=10)
+cap(CAP_XENSERVER_CONFIG,    PII_MAYBE,                 max_size=50*KB,
+    max_time=5)
+cap(CAP_XENSERVER_DOMAINS,   PII_NO,                    max_size=1*KB,
+    max_time=5)
+cap(CAP_XENSERVER_DATABASES, PII_YES,   min_size=500*KB,max_size=2*MB,
+    max_time=20)
+cap(CAP_XENSERVER_INSTALL,   PII_MAYBE, min_size=10*KB, max_size=300*KB)
+cap(CAP_XENSERVER_LOGS,      PII_MAYBE, min_size=0,     max_size=50*MB)
+cap(CAP_XEN_INFO,            PII_MAYBE,                 max_size=20*KB,
+    max_time=10)
+cap(CAP_XHA_LIVESET,         PII_MAYBE,                 max_size=10*KB,
+    max_time=10)
+cap(CAP_YUM,                 PII_IF_CUSTOMIZED,         max_size=10*KB,
+    max_time=30)
+
+ANSWER_YES_TO_ALL = False
+SILENT_MODE = False
+entries = None
+data = {}
+dev_null = open('/dev/null', 'r+')
+
+def output(x):
+    global SILENT_MODE
+    if not SILENT_MODE:
+        print x
+
+def output_ts(x):
+    output("[%s]  %s" % (time.strftime("%x %X %Z"), x))
+
+def cmd_output(cap, args, label = None, filter = None):
+    if cap in entries:
+        a = [aa for aa in args]
+        a[0] = os.path.basename(a[0])
+        if not label:
+            label = ' '.join(a)
+        data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
+
+def file_output(cap, path_list):
+    if cap in entries:
+        for p in path_list:
+            if os.path.exists(p):
+                if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
+                        cap_sizes[cap] < caps[cap][MAX_SIZE]:
+                    data[p] = {'cap': cap, 'filename': p}
+                    try:
+                        s = os.stat(p)
+                        cap_sizes[cap] += s.st_size
+                    except:
+                        pass
+                else:
+                    output("Omitting %s, size constraint of %s exceeded" % (p, cap))
+
+def tree_output(cap, path, pattern = None, negate = False):
+    if cap in entries:
+        if os.path.exists(path):
+            for f in os.listdir(path):
+                fn = os.path.join(path, f)
+                if os.path.isfile(fn) and matches(fn, pattern, negate):
+                    file_output(cap, [fn])
+                elif os.path.isdir(fn):
+                    tree_output(cap, fn, pattern, negate)
+
+def func_output(cap, label, func):
+    if cap in entries:
+        t = str(func).split()
+        data[label] = {'cap': cap, 'func': func}
+
+def collect_data():
+    process_lists = {}
+
+    for (k, v) in data.items():
+        cap = v['cap']
+        if v.has_key('cmd_args'):
+            v['output'] = StringIOmtime()
+            if not process_lists.has_key(cap):
+                process_lists[cap] = []
+            process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
+        elif v.has_key('filename') and v['filename'].startswith('/proc/'):
+            # proc files must be read into memory
+            try:
+                f = open(v['filename'], 'r')
+                s = f.read()
+                f.close()
+                if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
+                        cap_sizes[cap] < caps[cap][MAX_SIZE]:
+                    v['output'] = StringIOmtime(s)
+                    cap_sizes[cap] += len(s)
+                else:
+                    output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
+            except:
+                pass
+        elif v.has_key('func'):
+            try:
+                s = v['func'](cap)
+            except Exception, e:
+                s = str(e)
+            if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
+                    cap_sizes[cap] < caps[cap][MAX_SIZE]:
+                v['output'] = StringIOmtime(s)
+                cap_sizes[cap] += len(s)
+            else:
+                output("Omitting %s, size constraint of %s exceeded" % (k, cap))
+
+    run_procs(process_lists.values())
+
+
+def main(argv = None):
+    global ANSWER_YES_TO_ALL, SILENT_MODE
+    global entries, data, dbg
+
+    # we need access to privileged files, exit if we are not running as root
+    if os.getuid() != 0:
+        print >>sys.stderr, "Error: xen-bugtool must be run as root"
+        return 1
+
+    output_type = 'tar.bz2'
+    output_fd = -1
+    
+    if argv is None:
+        argv = sys.argv
+
+    try:
+        (options, params) = getopt.gnu_getopt(
+            argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
+                         'output=', 'outfd=', 'all', 'unlimited', 'debug'])
+    except getopt.GetoptError, opterr:
+        print >>sys.stderr, opterr
+        return 2
+
+    inventory = readKeyValueFile(XENSOURCE_INVENTORY)
+    if inventory.has_key('OEM_BUILD_NUMBER'):
+        cap(CAP_OEM,                 PII_MAYBE,                 max_size=5*MB,
+            max_time=90)
+
+    if  os.getenv('XEN_RT'):
+        entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO, 
+                   CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
+                   CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
+                   CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
+                   CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
+                   CAP_VNCTERM, CAP_VSWITCH_CONFIG, CAP_VSWITCH_STATUS, CAP_WLB, 
+                   CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS, 
+                   CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES, 
+                   CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
+    else:
+        entries = [e for e in caps.keys() if caps[e][CHECKED]]
+
+    for (k, v) in options:
+        if k == '--capabilities':
+            update_capabilities()
+            print_capabilities()
+            return 0
+
+        if k == '--output':
+            if  v in ['tar', 'tar.bz2', 'zip']:
+                output_type = v
+            else:
+                print >>sys.stderr, "Invalid output format '%s'" % v
+                return 2
+
+        # "-s" or "--silent" means suppress output (except for the final
+        # output filename at the end)
+        if k in ['-s', '--silent']:
+            SILENT_MODE = True
+
+        if k == '--entries' and v != '':
+            entries = v.split(',')
+
+        # If the user runs the script with "-y" or "--yestoall" we don't ask
+        # all the really annoying questions.
+        if k in ['-y', '--yestoall']:
+            ANSWER_YES_TO_ALL = True
+
+        if k == '--outfd':
+            output_fd = int(v)
+            try:
+                old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
+                fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
+            except:
+                print >>sys.stderr, "Invalid output file descriptor", output_fd
+                return 2
+
+        elif k == '--all':
+            entries = caps.keys()
+        elif k == '--unlimited':
+            unlimited_data = True
+        elif k == '--debug':
+            dbg = True
+            ProcOutput.debug = True
+
+    if len(params) != 1:
+        print >>sys.stderr, "Invalid additional arguments", str(params)
+        return 2
+
+    if output_fd != -1 and output_type != 'tar':
+        print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
+        return 2
+
+    if ANSWER_YES_TO_ALL:
+        output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
+
+    output('''
+This application will collate the Xen dmesg output, details of the
+hardware configuration of your machine, information about the build of
+Xen that you are using, plus, if you allow it, various logs.
+
+The collated information will be saved as a .%s for archiving or
+sending to a Technical Support Representative.
+
+The logs may contain private information, and if you are at all
+worried about that, you should exit now, or you should explicitly
+exclude those logs from the archive.
+
+''' % output_type)
+
+    # assemble potential data
+    tree_output(CAP_BLOBS, XAPI_BLOBS)
+
+    file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
+    cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
+    cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
+
+    func_output(CAP_CVSM, 'csl_logs', csl_logs)
+
+    cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
+    file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
+    file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
+    cmd_output(CAP_DISK_INFO, [DF, '-alT'])
+    cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
+    for d in disk_list():
+        cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
+    if len(pidof('iscsid')) != 0:
+        cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
+    cmd_output(CAP_DISK_INFO, [VGSCAN])
+    cmd_output(CAP_DISK_INFO, [PVS])
+    cmd_output(CAP_DISK_INFO, [VGS])
+    cmd_output(CAP_DISK_INFO, [LVS])
+    file_output(CAP_DISK_INFO, [LVM_CACHE])
+    cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
+    cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
+    cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
+    cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
+    func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
+    tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
+
+    tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
+
+    file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
+    cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
+    cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
+    cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
+    file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
+    file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
+    file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
+    # FIXME IDE?
+
+    for d in disk_list():
+        cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
+
+    file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
+
+    tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
+                HOST_CRASHDUMP_LOGS_RE, True)
+    tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
+                HOST_CRASHDUMP_LOGS_RE, False)
+
+    file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES, 
+                                  PROC_FILESYSTEMS, PROC_CMDLINE])
+    cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
+    cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
+    file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
+    tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
+
+    cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
+
+    file_output(CAP_MULTIPATH, [MULTIPATH_CONF])
+    cmd_output(CAP_MULTIPATH, [DMSETUP, 'status'])
+    func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
+
+    tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
+    tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
+    file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF])
+    file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
+
+    cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
+    cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
+    cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
+    cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
+    tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
+    cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
+    cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
+    cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
+    for p in os.listdir('/sys/class/net/'):
+        if os.path.isdir('/sys/class/net/%s/bridge' % p):
+            cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
+        else:
+            try:
+                f = open('/sys/class/net/%s/type' % p, 'r')
+                t = f.readline()
+                f.close()
+                if int(t) == 1:
+                    # ARPHRD_ETHER
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
+            except:
+                pass
+    tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
+    tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
+    cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
+    file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
+
+    tree_output(CAP_OEM, DELL_OMSA_LOGS)
+    file_output(CAP_OEM, [HP_CMA_LOG, HP_HPASMD_LOG])
+    if os.path.exists(OMREPORT):
+        cmd_output(CAP_OEM, [OMREPORT, 'system', 'alertlog'])
+        cmd_output(CAP_OEM, [OMREPORT, 'system', 'cmdlog'])
+        cmd_output(CAP_OEM, [OMREPORT, 'system', 'esmlog'])
+        cmd_output(CAP_OEM, [OMREPORT, 'system', 'postlog'])
+        cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'fans'])
+        cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'memory'])
+        cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'temps'])
+        cmd_output(CAP_OEM, [OMREPORT, 'storage', 'controller'])
+        for i in range(0, 4):
+            cmd_output(CAP_OEM, [OMREPORT, 'storage', 'adisk', 'controller=%d' % i])
+            cmd_output(CAP_OEM, [OMREPORT, 'storage', 'vdisk', 'controller=%d' % i])
+    cmd_output(CAP_OEM, [FIND, '/.state', '-size', '+20k', '-exec', 'ls', '-l', '{}',';'], 
+               label = "state+20k")
+
+    tree_output(CAP_PAM, PAM_DIR)
+
+    func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
+
+    cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,wchan:25,args'], label='process-tree')
+
+    file_output(CAP_SYSTEM_LOGS,
+         [ VAR_LOG_DIR + x for x in
+           [ 'syslog', 'messages', 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg' ] +
+           [ f % n for n in range(1, 20) \
+                 for f in ['messages.%d', 'messages.%d.gz', 'monitor_memory.log.%d', 
+                           'monitor_memory.log.%d.gz', 'secure.%d', 'secure.%d.gz']]])
+    if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
+        cmd_output(CAP_SYSTEM_LOGS, [DMESG])
+
+    cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
+
+    if CAP_TAPDISK_LOGS in entries:
+        generate_tapdisk_logs()
+
+    tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
+
+    file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_CONF])
+
+    cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'show'])
+    tree_output(CAP_VSWITCH_STATUS, VSWITCH_CORE_DIR)
+    for d in dp_list():
+        cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'show', d])
+        cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'status', d])
+        cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
+        cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
+
+    cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
+
+    tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
+    tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
+
+    tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
+
+    func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
+
+    file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
+    file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS, 
+                                       XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
+    cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
+    cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
+    tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
+
+    func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
+    cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
+    file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
+    tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
+    file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
+    cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='], 
+               label="xapi-db-dumped.xml", filter=filter_db_pii)
+    cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
+    cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
+
+    cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
+
+    tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
+    file_output(CAP_XENSERVER_INSTALL,
+                [ VAR_LOG_DIR + x for x in 
+                  [ 'firstboot-SR-commands-log', 
+                    'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
+                [ '/root/' + x for x in 
+                  [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
+                    'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
+                    'pci-log', 'processes-log', 'tty-log', 'uname-log',
+                    'vgscan-log']])
+    tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
+    tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
+
+    file_output(CAP_XENSERVER_LOGS, [LOG_CONF])
+    file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
+    tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
+
+    try:
+        def xen_dmesg(xc):
+            data = xc.readconsolering()
+            xc.send_debug_keys('q')
+            time.sleep(1)
+            return data
+
+        xc = xen.lowlevel.xc.xc()
+
+        func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
+        func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
+        func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
+    except:
+        pass
+    file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
+
+    cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
+
+    file_output(CAP_YUM, [YUM_LOG])
+    tree_output(CAP_YUM, YUM_REPOS_DIR)
+    cmd_output(CAP_YUM, [RPM, '-qa'])
+    
+    # permit the user to filter out data
+    for k in sorted(data.keys()):
+        if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
+            del data[k]
+
+    # collect selected data now
+    output_ts('Running commands to collect data')
+    collect_data()
+
+    subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
+    if subdir:
+        subdir = os.path.basename(subdir)
+        if subdir == '..' or subdir == '.':
+            subdir = None
+    if not subdir:
+        subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
+
+    # include inventory
+    data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
+
+    # create archive
+    if output_fd == -1 and not os.path.exists(BUG_DIR):
+        try:
+            os.makedirs(BUG_DIR)
+        except:
+            pass
+
+    if output_fd == -1:
+        output_ts('Creating output file')
+
+    if output_type.startswith('tar'):
+        make_tar(subdir, output_type, output_fd)
+    else:
+        make_zip(subdir)
+
+    clean_tapdisk_logs()
+
+    if dbg:
+        print >>sys.stderr, "Category sizes (max, actual):\n"
+        for c in caps.keys():
+            print >>sys.stderr, "    %s (%d, %d)" % (c, caps[c][MAX_SIZE], 
+                                                     cap_sizes[c])
+    return 0
+    
+def generate_tapdisk_logs():
+    for pid in pidof('tapdisk'):
+       try:
+           os.kill(pid, SIGUSR1)
+            output_ts("Including logs for tapdisk process %d" % pid)
+        except :
+            pass
+    # give processes a second to write their logs
+    time.sleep(1)
+    file_output(CAP_TAPDISK_LOGS, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
+
+def clean_tapdisk_logs():
+    for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
+        try:
+            os.remove(os.path.join('tmp', filename))
+        except :
+            pass
+
+def dump_xapi_subprocess_info(cap):
+    """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
+       Returns a string containing a pretty-printed pstree-like structure. """
+    pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
+    def readlines(filename):
+        lines = ''
+       try:
+            f = open(filename, "r")
+            lines = f.readlines()
+            f.close()
+        except:
+            pass
+        return lines
+    def cmdline(pid):
+       all = readlines("/proc/" + pid + "/cmdline")
+       if all == []:
+          return ""
+       else:
+          return all[0].replace('\x00', ' ')
+    def parent(pid):
+       for i in readlines("/proc/" + pid + "/status"):
+           if i.startswith("PPid:"):
+              return i.split()[-1]
+       return None
+    def pstree(pid):
+       result = { "cmdline": cmdline(pid) }
+       child_pids = filter(lambda x:parent(x) == pid, pids)
+       children = { }
+       for child in child_pids:
+           children[child] = pstree(child)
+       result['children'] = children
+       fds = { }
+       for fd in os.listdir("/proc/" + pid + "/fd"):
+            try:
+                fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
+            except:
+                pass
+       result['fds'] = fds
+       return result   
+    xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
+    xapis = filter(lambda x: parent(x) == "1", xapis)
+    result = {}
+    for xapi in xapis:
+       result[xapi] = pstree(xapi)
+    pp = pprint.PrettyPrinter(indent=4)
+    return pp.pformat(result)
+
+def dump_xapi_rrds(cap):
+    socket.setdefaulttimeout(5)
+    session = XenAPI.xapi_local()
+    session.xenapi.login_with_password('', '')
+    this_host = session.xenapi.session.get_this_host(session._session)
+    # better way to find pool master?
+    pool = session.xenapi.pool.get_all_records().values()[0]
+    i_am_master = (this_host == pool['master'])
+
+    for vm in session.xenapi.VM.get_all_records().values():
+        if vm['is_a_template']:
+            continue
+        if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
+            rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
+            try:
+                (i, o, x) = select([rrd], [], [], 5.0)
+                if len(i) == 1:
+                    data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap, 
+                                                        'output': StringIOmtime(rrd.read())}
+            finally:
+                rrd.close()
+
+    output = ''
+    rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
+    try:
+        for line in rrd:
+            output += line
+    finally:
+        rrd.close()
+        
+    session.xenapi.session.logout()
+    return output
+
+def filter_db_pii(str):
+    str = re.sub(r'(password_transformed&quot; &quot;)[^ ]+(&quot;)', r'\1REMOVED\2', str)
+    str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
+    return str
+
+def dump_filtered_xapi_db(cap):
+    db_file = None
+    format = None
+
+    # determine db format
+    c = open(DB_CONF, 'r')
+    try:
+        for line in c:
+            l = line.rstrip('\n')
+            if l.startswith('['):
+                db_file = l[1:-1]
+            if l.startswith('format:'):
+                format = l[7:]
+                break
+    finally:
+        c.close()
+
+    pipe = None
+    ih = None
+    output = ''
+
+    if format == 'sqlite':
+        pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null, 
+                     stdout=PIPE, stderr=dev_null)
+        ih = pipe.stdout
+    elif db_file:
+        ih = open(db_file, 'r')
+
+    if not ih:
+        return ''
+
+    remain = ''
+    rec = ih.read(2048)
+    while rec != '':
+        remain += rec
+        p = remain.find('>')
+        while p != -1:
+            str = remain[:p+1]
+            remain = remain[p+1:]
+            output += filter_db_pii(str)
+            p = remain.find('>')
+        rec = ih.read(2048)
+    output += remain
+
+    if pipe:
+        pipe.wait()
+    else:
+        ih.close()
+    return output
+
+def dump_scsi_hosts(cap):
+    output = ''
+    l = os.listdir('/sys/class/scsi_host')
+    l.sort()
+
+    for h in l:
+        procname = ''
+        try:
+                f = open('/sys/class/scsi_host/%s/proc_name' % h)
+                procname = f.readline().strip("\n")
+                f.close()
+        except:
+                pass
+        modelname = None
+        try:
+                f = open('/sys/class/scsi_host/%s/model_name' % h)
+                modelname = f.readline().strip("\n")
+                f.close()
+        except:
+                pass
+
+        output += "%s:\n" %h
+        output += "    %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
+
+    return output
+
+def csl_logs(cap):
+    socket.setdefaulttimeout(5)
+    session = XenAPI.xapi_local()
+    session.xenapi.login_with_password('', '')
+    this_host = session.xenapi.session.get_this_host(session._session)
+    # better way to find pool master?
+    pool = session.xenapi.pool.get_all_records().values()[0]
+    i_am_master = (this_host == pool['master'])
+
+    output = StringIO.StringIO()
+    procs = []
+
+    def rotate_string(x, n):
+        transtbl = ""
+        for a in range(0, 256):
+            transtbl = transtbl + chr(a)
+        transtbl = transtbl[n:] + transtbl[0:n]
+        return x.translate(transtbl)
+
+    def _untransform_string(str, remove_trailing_nulls=False):
+        """De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
+        remove_trailing_nulls should be set to True"""
+        tmp = base64.decodestring(str)
+        if remove_trailing_nulls:
+            tmp = tmp.rstrip('\x00')
+        return rotate_string(tmp, -13)
+
+    for pbd in session.xenapi.PBD.get_all_records().values():
+        if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
+            sr = session.xenapi.SR.get_record(pbd['SR'])
+            if sr.has_key('type') and sr['type'] == 'cslg':
+                if sr['shared'] and pbd['host'] != this_host and not i_am_master:
+                    continue
+                
+                dev_cfg = pbd['device_config']
+                server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
+                if dev_cfg.has_key('port'):
+                    server += ':' + dev_cfg['port']
+                if dev_cfg.has_key('username'):
+                    server += ',' + dev_cfg['username']
+                if dev_cfg.has_key('password_transformed'):
+                    server += ',' + _untransform_string(dev_cfg['password_transformed'])
+                procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
+
+    session.xenapi.session.logout()
+
+    run_procs([procs])
+
+    return output.getvalue()
+
+def multipathd_topology(cap):
+    pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE, 
+                     stdout=PIPE, stderr=dev_null)
+    stdout, stderr = pipe.communicate('show topology')
+
+    return stdout
+
+def make_tar(subdir, suffix, output_fd):
+    global SILENT_MODE, data
+
+    mode = 'w'
+    if suffix == 'tar.bz2':
+        mode = 'w:bz2'
+    filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
+
+    if output_fd == -1:
+        tf = tarfile.open(filename, mode)
+    else:
+        tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
+
+    try:
+        for (k, v) in data.items():
+            try:
+                tar_filename = os.path.join(subdir, construct_filename(k, v))
+                ti = tarfile.TarInfo(tar_filename)
+
+                ti.uname = 'root'
+                ti.gname = 'root'
+
+                if v.has_key('output'):
+                    ti.mtime = v['output'].mtime
+                    ti.size = len(v['output'].getvalue())
+                    v['output'].seek(0)
+                    tf.addfile(ti, v['output'])
+                elif v.has_key('filename'):
+                    s = os.stat(v['filename'])
+                    ti.mtime = s.st_mtime
+                    ti.size = s.st_size
+                    tf.addfile(ti, file(v['filename']))
+            except:
+                pass
+    finally:
+        tf.close()
+
+    if output_fd == -1:
+        output ('Writing tarball %s successful.' % filename)
+        if SILENT_MODE:
+            print filename
+
+
+def make_zip(subdir):
+    global SILENT_MODE, data
+
+    filename = "%s/%s.zip" % (BUG_DIR, subdir)
+    zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
+
+    try:
+        for (k, v) in data.items():
+            try:
+                dest = os.path.join(subdir, construct_filename(k, v))
+            
+                if v.has_key('output'):
+                    zf.writestr(dest, v['output'].getvalue())
+                else:
+                    if os.stat(v['filename']).st_size < 50:
+                        compress_type = zipfile.ZIP_STORED
+                    else:
+                        compress_type = zipfile.ZIP_DEFLATED
+                    zf.write(v['filename'], dest, compress_type)
+            except:
+                pass
+    finally:
+        zf.close()
+    
+    output ('Writing archive %s successful.' % filename)
+    if SILENT_MODE:
+        print filename
+
+
+def make_inventory(inventory, subdir):
+    document = getDOMImplementation().createDocument(
+        None, INVENTORY_XML_ROOT, None)
+
+    # create summary entry
+    s = document.createElement(INVENTORY_XML_SUMMARY)
+    user = os.getenv('SUDO_USER', os.getenv('USER'))
+    if user:
+        s.setAttribute('user', user)
+    s.setAttribute('date', time.strftime('%c'))
+    s.setAttribute('hostname', platform.node())
+    s.setAttribute('uname', ' '.join(platform.uname()))
+    s.setAttribute('uptime', commands.getoutput(UPTIME))
+    document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
+
+    map(lambda (k, v): inventory_entry(document, subdir, k, v),
+        inventory.items())
+    return document.toprettyxml()
+
+def inventory_entry(document, subdir, k, v):
+    try:
+        el = document.createElement(INVENTORY_XML_ELEMENT)
+        el.setAttribute('capability', v['cap'])
+        el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
+        el.setAttribute('md5sum', md5sum(v))
+        document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
+    except:
+        pass
+
+
+def md5sum(d):
+    m = md5.new()
+    if d.has_key('filename'):
+        f = open(d['filename'])
+        data = f.read(1024)
+        while len(data) > 0:
+            m.update(data)
+            data = f.read(1024)
+        f.close()
+    elif d.has_key('output'):
+        m.update(d['output'].getvalue())
+    return m.hexdigest()
+
+
+def construct_filename(k, v):
+    if v.has_key('filename'):
+        if v['filename'][0] == '/':
+            return v['filename'][1:]
+        else:
+            return v['filename']
+    s = k.replace(' ', '-')
+    s = s.replace('--', '-')
+    s = s.replace('/', '%')
+    if s.find('.') == -1:
+        s += '.out'
+
+    return s
+
+
+def update_capabilities():
+    update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
+                    size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
+    update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
+                    size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
+                                True))
+    update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
+    update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
+
+
+def update_cap_size(cap, size):
+    update_cap(cap, MIN_SIZE, size)
+    update_cap(cap, MAX_SIZE, size)
+    update_cap(cap, CHECKED, size > 0)
+
+
+def update_cap(cap, k, v):
+    global caps
+    l = list(caps[cap])
+    l[k] = v
+    caps[cap] = tuple(l)
+
+
+def size_of_dir(d, pattern = None, negate = False):
+    if os.path.isdir(d):
+        return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
+                           pattern, negate)
+    else:
+        return 0
+
+
+def size_of_all(files, pattern = None, negate = False):
+    return sum([size_of(f, pattern, negate) for f in files])
+
+
+def matches(f, pattern, negate):
+    if negate:
+        return not matches(f, pattern, False)
+    else:
+        return pattern is None or pattern.match(f)
+
+
+def size_of(f, pattern, negate):
+    if os.path.isfile(f) and matches(f, pattern, negate):
+        return os.stat(f)[6]
+    else:
+        return size_of_dir(f, pattern, negate)
+
+
+def print_capabilities():
+    document = getDOMImplementation().createDocument(
+        "ns", CAP_XML_ROOT, None)
+    map(lambda key: capability(document, key), caps.keys())
+    print document.toprettyxml()
+
+def capability(document, key):
+    c = caps[key]
+    el = document.createElement(CAP_XML_ELEMENT)
+    el.setAttribute('key', c[KEY])
+    el.setAttribute('pii', c[PII])
+    el.setAttribute('min-size', str(c[MIN_SIZE]))
+    el.setAttribute('max-size', str(c[MAX_SIZE]))
+    el.setAttribute('min-time', str(c[MIN_TIME]))
+    el.setAttribute('max-time', str(c[MAX_TIME]))
+    el.setAttribute('content-type', c[MIME])
+    el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
+    document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
+
+
+def prettyDict(d):
+    format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
+    return '\n'.join([format % i for i in d.items()]) + '\n'
+
+
+def yes(prompt):
+    yn = raw_input(prompt)
+
+    return len(yn) == 0 or yn.lower()[0] == 'y'
+
+
+partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
+
+def dp_list():
+    command = [OVS_DPCTL, "dump-dps"]
+    proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
+    (dps, err) = proc.communicate()
+    return dps.splitlines()
+
+
+def disk_list():
+    disks = []
+    try:
+        f = open('/proc/partitions')
+        f.readline()
+        f.readline()
+        for line in f.readlines():
+            (major, minor, blocks, name) = line.split()
+            if int(major) < 254 and not partition_re.match(name):
+                disks.append(name)
+        f.close()
+    except:
+        pass
+    return disks
+
+
+class ProcOutput:
+    debug = False
+    def __init__(self, command, max_time, inst=None, filter=None):
+        self.command = command
+        self.max_time = max_time
+        self.inst = inst
+        self.running = False
+        self.status = None
+        self.timed_out = False
+        self.failed = False
+        self.timeout = int(time.time()) + self.max_time
+        self.filter = filter
+
+    def __del__(self):
+        self.terminate()
+
+    def run(self):
+        self.timed_out = False
+        try:
+            if ProcOutput.debug:
+                output_ts("Starting '%s'" % ' '.join(self.command))
+            self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
+            old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
+            fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
+            self.running = True
+            self.failed = False
+        except:
+            output_ts("'%s' failed" % ' '.join(self.command))
+            self.running = False
+            self.failed = True
+
+    def terminate(self):
+        if self.running:
+            try:
+                os.kill(self.proc.pid, SIGTERM)
+            except:
+                pass
+            self.proc = None
+            self.running = False
+            self.status = SIGTERM
+
+    def read_line(self):
+        assert self.running
+        line = self.proc.stdout.readline()
+        if line == '':
+            # process exited
+            self.status = self.proc.wait()
+            self.proc = None
+            self.running = False
+        else:
+            if self.filter:
+                line = self.filter(line)
+            if self.inst:
+                self.inst.write(line)
+
+def run_procs(procs):
+    while True:
+        pipes = []
+        active_procs = []
+
+        for pp in procs:
+            for p in pp:
+                if p.running:
+                    active_procs.append(p)
+                    pipes.append(p.proc.stdout)
+                    break
+                elif p.status == None and not p.failed and not p.timed_out:
+                    p.run()
+                    if p.running:
+                        active_procs.append(p)
+                        pipes.append(p.proc.stdout)
+                        break
+
+        if len(pipes) == 0:
+            # all finished
+            break
+
+        (i, o, x) = select(pipes, [], [], 1.0)
+        now = int(time.time())
+
+        # handle process output
+        for p in active_procs:
+            if p.proc.stdout in i:
+                p.read_line()
+
+            # handle timeout
+            if p.running and now > p.timeout:
+                output_ts("'%s' timed out" % ' '.join(p.command))
+                if p.inst:
+                    p.inst.write("\n** timeout **\n")
+                p.timed_out = True
+                p.terminate()
+
+
+def pidof(name):
+    pids = []
+
+    for d in [p for p in os.listdir('/proc') if p.isdigit()]:
+        try:
+            if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
+                pids.append(int(d))
+        except:
+            pass
+        
+    return pids
+
+
+def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
+    """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a 
+    dictionary of key/values in the file.  Not designed for use with large files
+    as the file is read entirely into memory."""
+
+    f = open(filename, "r")
+    lines = [x.strip("\n") for x in f.readlines()]
+    f.close()
+
+    # remove lines contain
+    if allowed_keys:
+        lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
+                       lines)
+    
+    defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
+
+    if strip_quotes:
+        def quotestrip(x):
+            if assert_quotes:
+                assert x.startswith("'") and x.endswith("'")
+            return x.strip("'")
+        defs = [ (a, quotestrip(b)) for (a,b) in defs ]
+
+    return dict(defs)
+
+
+class StringIOmtime(StringIO.StringIO):
+    def __init__(self, buf = ''):
+        StringIO.StringIO.__init__(self, buf)
+        self.mtime = time.time()
+
+    def write(self, s):
+        StringIO.StringIO.write(self, s)
+        self.mtime = time.time()
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except KeyboardInterrupt:
+        print "\nInterrupted."
+        sys.exit(3)
index cf74138..94bd916 100644 (file)
@@ -21,7 +21,9 @@ Summary: Virtual switch
 Group: System Environment/Daemons
 URL: http://www.openvswitch.org/
 Version: %{vswitch_version}
-License: GPL3
+
+# The entire source code is ASL 2.0 except datapath/ which is GPLv2
+License: ASL 2.0 and GPLv2
 Release: 1
 Source: openvswitch-%{vswitch_version}.tar.gz
 Buildroot: /tmp/vswitch-xen-rpm
@@ -67,6 +69,8 @@ install -m 755 xenserver/etc_xensource_scripts_vif \
              $RPM_BUILD_ROOT%{_prefix}/scripts/vif
 install -m 755 xenserver/root_vswitch_scripts_dump-vif-details \
                $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 644 \
         xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
                $RPM_BUILD_ROOT%{_prefix}/scripts/XSFeatureVSwitch.py
@@ -106,6 +110,7 @@ if [ "$1" = "1" ]; then
     if ! md5sum -c --status <<EOF
 b8e9835862ef1a9cec2a3f477d26c989  /etc/xensource/scripts/vif
 51970ad613a3996d5997e18e44db47da  /opt/xensource/libexec/interface-reconfigure
+5654c8c36699fcc8744ca9cd5b855414  /usr/sbin/xen-bugtool
 EOF
     then
         printf "\nThe original XenServer scripts replaced by this package\n"
@@ -166,8 +171,6 @@ EOF
 fi
 
 %post
-source /etc/xensource-inventory
-
 if grep -F net.ipv4.conf.all.arp_filter /etc/sysctl.conf >/dev/null 2>&1; then :; else
     cat >>/etc/sysctl.conf <<EOF
 # This works around an issue in xhad, which binds to a particular
@@ -183,10 +186,6 @@ net.ipv4.conf.all.arp_filter = 1
 EOF
 fi
 
-xe host-param-set \
-    "other-config:vSwitchVersion=%{version}" uuid="$INSTALLATION_UUID" ||
-    echo "Could not set vSwitchVersion config parameter"
-
 # Ensure ovs-vswitchd.conf exists
 touch /etc/ovs-vswitchd.conf
 
@@ -195,7 +194,8 @@ 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
+    /etc/xensource/scripts/vif \
+    /usr/sbin/xen-bugtool
 do
     s=$(basename "$f")
     t=$(readlink "$f")
@@ -252,7 +252,8 @@ if [ "$1" = "0" ]; then     # $1 = 1 for upgrade
     # Restore original XenServer scripts
     for f in \
         /opt/xensource/libexec/interface-reconfigure \
-        /etc/xensource/scripts/vif
+        /etc/xensource/scripts/vif \
+        /usr/sbin/xen-bugtool
     do
         s=$(basename "$f")
         if [ ! -f "%{_prefix}/xs-original/$s" ]; then
@@ -274,18 +275,6 @@ if [ "$1" = "0" ]; then     # $1 = 1 for upgrade
     rm -f /var/log/vswitch*
     rm -f /etc/ovs-vswitchd.cacert
 
-    if [ ! -f /etc/xensource-inventory ]; then
-        printf "XenSource inventory not present in /etc/xensource-inventory\n"
-        printf "Could not remove vSwitchVersion from XAPI database.\n"
-        exit 1
-    else
-        source /etc/xensource-inventory
-        xe host-param-remove \
-            param-name=other-config param-key=vSwitchVersion \
-            uuid="$INSTALLATION_UUID" ||
-            echo "Could not clear vSwitchVersion config parameter."
-    fi
-
     printf "\nYou MUST reboot the server now to complete the change to\n"
     printf "standard Xen networking.  Attempts to modify networking on the\n"
     printf "server or any hosted VM will fail until after the reboot and\n"
@@ -306,6 +295,7 @@ fi
 /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
 # 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