]> git.proxmox.com Git - ovs.git/commitdiff
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.

57 files changed:
datapath/Modules.mk
datapath/brc_sysfs.h [deleted file]
datapath/brc_sysfs_dp.c [deleted file]
datapath/brc_sysfs_if.c [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 [new file with mode: 0644]
datapath/dp_sysfs_if.c [new file with mode: 0644]
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 1b5de4aba837a67461087bac5c9d6565d0dab556..211f96fc2e549b82cac5a1f5a834e5429ba7ca16 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 */
-
diff --git a/datapath/brc_sysfs_dp.c b/datapath/brc_sysfs_dp.c
deleted file mode 100644 (file)
index c1e82eb..0000000
+++ /dev/null
@@ -1,528 +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.
- */
-
-#include <linux/version.h>
-
-/*
- *     Sysfs attributes of bridge for Open vSwitch
- *
- *  This has been shamelessly copied from the kernel sources.
- */
-
-#include <linux/capability.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/if_bridge.h>
-#include <linux/rtnetlink.h>
-#include <linux/spinlock.h>
-#include <linux/times.h>
-#include <linux/version.h>
-
-#include "brc_sysfs.h"
-#include "datapath.h"
-#include "dp_dev.h"
-
-#ifdef CONFIG_SYSFS
-#define to_dev(obj)    container_of(obj, struct device, kobj)
-
-/* Hack to attempt to build on more platforms. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
-#define BRC_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 DEVICE_PARAMS struct device *d, struct device_attribute *attr
-#define DEVICE_ARGS d, attr
-#define DEV_ATTR(NAME) dev_attr_##NAME
-#endif
-
-/*
- * Common code for storing bridge parameters.
- */
-static ssize_t store_bridge_parm(DEVICE_PARAMS,
-                                const char *buf, size_t len,
-                                void (*set)(struct datapath *, unsigned long))
-{
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       char *endp;
-       unsigned long val;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               return -EINVAL;
-
-#if 0
-       spin_lock_bh(&br->lock);
-       (*set)(br, val);
-       spin_unlock_bh(&br->lock);
-#else
-       /* xxx We use a default value of 0 for all fields.  If the caller is
-        * xxx attempting to set the value to our default, just silently
-        * xxx ignore the request. 
-        */
-       if (val != 0) {
-               printk("%s: xxx writing dp parms not supported yet!\n", 
-                      dp_name(dp));
-       }
-#endif
-       return len;
-}
-
-
-static ssize_t show_forward_delay(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-
-static void set_forward_delay(struct datapath *dp, unsigned long val)
-{
-#if 0
-       unsigned long delay = clock_t_to_jiffies(val);
-       br->forward_delay = delay;
-       if (br_is_root_bridge(br))
-               br->bridge_forward_delay = delay;
-#else
-       printk("%s: xxx attempt to set_forward_delay()\n", dp_name(dp));
-#endif
-}
-
-static ssize_t store_forward_delay(DEVICE_PARAMS,
-                                  const char *buf, size_t len)
-{
-       return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay);
-}
-static BRC_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
-                  show_forward_delay, store_forward_delay);
-
-static ssize_t show_hello_time(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       return sprintf(buf, "%lu\n",
-                      jiffies_to_clock_t(to_bridge(d)->hello_time));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-
-static void set_hello_time(struct datapath *dp, unsigned long val)
-{
-#if 0
-       unsigned long t = clock_t_to_jiffies(val);
-       br->hello_time = t;
-       if (br_is_root_bridge(br))
-               br->bridge_hello_time = t;
-#else
-       printk("%s: xxx attempt to set_hello_time()\n", dp_name(dp));
-#endif
-}
-
-static ssize_t store_hello_time(DEVICE_PARAMS,
-                               const char *buf,
-                               size_t len)
-{
-       return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time);
-}
-static BRC_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
-                  store_hello_time);
-
-static ssize_t show_max_age(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       return sprintf(buf, "%lu\n",
-                      jiffies_to_clock_t(to_bridge(d)->max_age));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-
-static void set_max_age(struct datapath *dp, unsigned long val)
-{
-#if 0
-       unsigned long t = clock_t_to_jiffies(val);
-       br->max_age = t;
-       if (br_is_root_bridge(br))
-               br->bridge_max_age = t;
-#else
-       printk("%s: xxx attempt to set_max_age()\n", dp_name(dp));
-#endif
-}
-
-static ssize_t store_max_age(DEVICE_PARAMS,
-                            const char *buf, size_t len)
-{
-       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 ssize_t show_ageing_time(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-
-static void set_ageing_time(struct datapath *dp, unsigned long val)
-{
-#if 0
-       br->ageing_time = clock_t_to_jiffies(val);
-#else
-       printk("%s: xxx attempt to set_ageing_time()\n", dp_name(dp));
-#endif
-}
-
-static ssize_t store_ageing_time(DEVICE_PARAMS,
-                                const char *buf, size_t len)
-{
-       return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time);
-}
-static BRC_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
-                  store_ageing_time);
-
-static ssize_t show_stp_state(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%d\n", br->stp_enabled);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-
-
-static ssize_t store_stp_state(DEVICE_PARAMS,
-                              const char *buf,
-                              size_t len)
-{
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-#if 0
-       char *endp;
-       unsigned long val;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               return -EINVAL;
-
-       rtnl_lock();
-       br_stp_set_enabled(br, val);
-       rtnl_unlock();
-#else
-       printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
-#endif
-
-       return len;
-}
-static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
-                  store_stp_state);
-
-static ssize_t show_priority(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%d\n",
-                      (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-
-static void set_priority(struct datapath *dp, unsigned long val)
-{
-#if 0
-       br_stp_set_bridge_priority(br, (u16) val);
-#else
-       printk("%s: xxx attempt to set_priority()\n", dp_name(dp));
-#endif
-}
-
-static ssize_t store_priority(DEVICE_PARAMS,
-                              const char *buf, size_t len)
-{
-       return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority);
-}
-static BRC_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
-
-static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
-#else
-       return sprintf(buf, "0000.010203040506\n");
-#endif
-}
-static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
-
-static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
-{
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr;
-
-       /* xxx Do we need a lock of some sort? */
-       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 ssize_t show_root_port(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", to_bridge(d)->root_port);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
-
-static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
-
-static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
-
-static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%d\n", br->topology_change_detected);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO,
-                  show_topology_change_detected, NULL);
-
-static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
-
-static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
-
-static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
-                  NULL);
-
-static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
-
-static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
-{
-#if 0
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-       return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
-                      br->group_addr[0], br->group_addr[1],
-                      br->group_addr[2], br->group_addr[3],
-                      br->group_addr[4], br->group_addr[5]);
-#else
-       return sprintf(buf, "00:01:02:03:04:05\n");
-#endif
-}
-
-static ssize_t store_group_addr(DEVICE_PARAMS,
-                               const char *buf, size_t len)
-{
-       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
-#if 0
-       unsigned new_addr[6];
-       int i;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
-                  &new_addr[0], &new_addr[1], &new_addr[2],
-                  &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
-               return -EINVAL;
-
-       /* Must be 01:80:c2:00:00:0X */
-       for (i = 0; i < 5; i++)
-               if (new_addr[i] != br_group_address[i])
-                       return -EINVAL;
-
-       if (new_addr[5] & ~0xf)
-               return -EINVAL;
-
-       if (new_addr[5] == 1    /* 802.3x Pause address */
-           || new_addr[5] == 2 /* 802.3ad Slow protocols */
-           || new_addr[5] == 3) /* 802.1X PAE address */
-               return -EINVAL;
-
-       spin_lock_bh(&br->lock);
-       for (i = 0; i < 6; i++)
-               br->group_addr[i] = new_addr[i];
-       spin_unlock_bh(&br->lock);
-#else
-       printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
-#endif
-       return len;
-}
-
-static BRC_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
-                  show_group_addr, store_group_addr);
-
-static struct attribute *bridge_attrs[] = {
-       &DEV_ATTR(forward_delay).attr,
-       &DEV_ATTR(hello_time).attr,
-       &DEV_ATTR(max_age).attr,
-       &DEV_ATTR(ageing_time).attr,
-       &DEV_ATTR(stp_state).attr,
-       &DEV_ATTR(priority).attr,
-       &DEV_ATTR(bridge_id).attr,
-       &DEV_ATTR(root_id).attr,
-       &DEV_ATTR(root_path_cost).attr,
-       &DEV_ATTR(root_port).attr,
-       &DEV_ATTR(topology_change).attr,
-       &DEV_ATTR(topology_change_detected).attr,
-       &DEV_ATTR(hello_timer).attr,
-       &DEV_ATTR(tcn_timer).attr,
-       &DEV_ATTR(topology_change_timer).attr,
-       &DEV_ATTR(gc_timer).attr,
-       &DEV_ATTR(group_addr).attr,
-       NULL
-};
-
-static struct attribute_group bridge_group = {
-       .name = SYSFS_BRIDGE_ATTR,
-       .attrs = bridge_attrs,
-};
-
-/*
- * Add entries in sysfs onto the existing network class device
- * for the bridge.
- *   Adds a attribute group "bridge" containing tuning parameters.
- *   Sub directory to hold links to interfaces.
- *
- * Note: the ifobj exists only to be a subdirectory
- *   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)
-{
-       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
-       int err;
-
-       err = sysfs_create_group(kobj, &bridge_group);
-       if (err) {
-               pr_info("%s: can't create group %s/%s\n",
-                       __func__, dp_name(dp), bridge_group.name);
-               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);
-       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
-       return 0;
-
- out2:
-       sysfs_remove_group(kobj, &bridge_group);
- out1:
-       return err;
-}
-
-int brc_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
-       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;
-}
-#endif /* !CONFIG_SYSFS */
diff --git a/datapath/brc_sysfs_if.c b/datapath/brc_sysfs_if.c
deleted file mode 100644 (file)
index 7a9b8b8..0000000
+++ /dev/null
@@ -1,342 +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.
- */
-
-/*
- *     Sysfs attributes of bridge ports for Open vSwitch
- *
- *  This has been shamelessly copied from the kernel sources.
- */
-
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/if_bridge.h>
-#include <linux/rtnetlink.h>
-#include <linux/spinlock.h>
-#include "brc_sysfs.h"
-#include "datapath.h"
-
-#ifdef CONFIG_SYSFS
-
-struct brport_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(struct net_bridge_port *, char *);
-       ssize_t (*store)(struct net_bridge_port *, unsigned long);
-};
-
-#define BRPORT_ATTR(_name,_mode,_show,_store)                  \
-struct brport_attribute brport_attr_##_name = {                \
-       .attr = {.name = __stringify(_name),                    \
-                .mode = _mode,                                 \
-                .owner = THIS_MODULE, },                       \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-};
-
-static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->path_cost);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v)
-{
-#if 0
-       br_stp_set_path_cost(p, v);
-#endif
-       return 0;
-}
-static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
-                  show_path_cost, store_path_cost);
-
-static ssize_t show_priority(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->priority);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static ssize_t store_priority(struct net_bridge_port *p, unsigned long v)
-{
-#if 0
-       if (v >= (1<<(16-BR_PORT_BITS)))
-               return -ERANGE;
-       br_stp_set_port_priority(p, v);
-#endif
-       return 0;
-}
-static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
-                        show_priority, store_priority);
-
-static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return br_show_bridge_id(buf, &p->designated_root);
-#else
-       return sprintf(buf, "0000.010203040506\n");
-#endif
-}
-static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
-
-static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return br_show_bridge_id(buf, &p->designated_bridge);
-#else
-       return sprintf(buf, "0000.060504030201\n");
-#endif
-}
-static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
-
-static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->designated_port);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
-
-static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->designated_cost);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
-
-static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "0x%x\n", p->port_id);
-#else
-       return sprintf(buf, "0x%x\n", 0);
-#endif
-}
-static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
-
-static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
-{
-       return sprintf(buf, "0x%x\n", p->port_no);
-}
-
-static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
-
-static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->topology_change_ack);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
-
-static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->config_pending);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
-
-static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
-{
-#if 0
-       return sprintf(buf, "%d\n", p->state);
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
-
-static ssize_t show_message_age_timer(struct net_bridge_port *p,
-                                           char *buf)
-{
-#if 0
-       return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
-
-static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
-                                           char *buf)
-{
-#if 0
-       return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
-
-static ssize_t show_hold_timer(struct net_bridge_port *p,
-                                           char *buf)
-{
-#if 0
-       return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
-#else
-       return sprintf(buf, "%d\n", 0);
-#endif
-}
-static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
-
-static struct brport_attribute *brport_attrs[] = {
-       &brport_attr_path_cost,
-       &brport_attr_priority,
-       &brport_attr_port_id,
-       &brport_attr_port_no,
-       &brport_attr_designated_root,
-       &brport_attr_designated_bridge,
-       &brport_attr_designated_port,
-       &brport_attr_designated_cost,
-       &brport_attr_state,
-       &brport_attr_change_ack,
-       &brport_attr_config_pending,
-       &brport_attr_message_age_timer,
-       &brport_attr_forward_delay_timer,
-       &brport_attr_hold_timer,
-       NULL
-};
-
-#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
-#define to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
-
-static ssize_t brport_show(struct kobject * kobj,
-                          struct attribute * attr, char * buf)
-{
-       struct brport_attribute * brport_attr = to_brport_attr(attr);
-       struct net_bridge_port * p = to_brport(kobj);
-
-       return brport_attr->show(p, buf);
-}
-
-static ssize_t brport_store(struct kobject * kobj,
-                           struct attribute * attr,
-                           const char * buf, size_t count)
-{
-       struct net_bridge_port * p = to_brport(kobj);
-#if 0
-       struct brport_attribute * brport_attr = to_brport_attr(attr);
-       char *endp;
-       unsigned long val;
-#endif
-       ssize_t ret = -EINVAL;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-#if 0
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp != buf) {
-               rtnl_lock();
-               if (p->dev && p->br && brport_attr->store) {
-                       spin_lock_bh(&p->br->lock);
-                       ret = brport_attr->store(p, val);
-                       spin_unlock_bh(&p->br->lock);
-                       if (ret == 0)
-                               ret = count;
-               }
-               rtnl_unlock();
-       }
-#else
-       printk("%s: xxx writing port parms not supported yet!\n", 
-              dp_name(p->dp));
-#endif
-       return ret;
-}
-
-struct sysfs_ops brport_sysfs_ops = {
-       .show = brport_show,
-       .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)
-{
-       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);
-       if (err)
-               goto err;
-
-       err = sysfs_create_link(&p->kobj,
-                               &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj,
-                               SYSFS_BRIDGE_PORT_LINK);
-       if (err)
-               goto err_del;
-
-       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)
-       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;
-
-       kobject_uevent(&p->kobj, KOBJ_ADD);
-
-       return err;
-
-err_del:
-       kobject_del(&p->kobj);
-       kobject_put(&p->kobj);
-err:
-       return err;
-}
-
-int brc_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);
-
-       return 0;
-}
-#endif /* CONFIG_SYSFS */
index d9255e6398e4afe3f38d26711858c8017b1b6de7..92fcecc216719dce8eb274b96ffb5210c95491ae 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 926f278f952509abb201ab8cdbce8da31f75f2a1..de607e8bec6443fc8925e2ef4058de991f8eae22 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 c6ec86a3993f6c043761c5982428639284be383e..b5200848b10b39acc51bd34f8474a4f6dd817f10 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 9caf65af7772561b0906b52df478c99a75a0d87b..069127e0a2033004be5fc7bcc4e4683d0d15cdde 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 5b8cf17126ade11a00438e731bed8f193fef8394..f22d8b342f1b1b3d88d19132a2ad88d83feaec56 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 */
+
diff --git a/datapath/dp_sysfs_dp.c b/datapath/dp_sysfs_dp.c
new file mode 100644 (file)
index 0000000..fafd9a9
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * 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.
+ */
+
+#include <linux/version.h>
+
+/*
+ *     Sysfs attributes of bridge for Open vSwitch
+ *
+ *  This has been shamelessly copied from the kernel sources.
+ */
+
+#include <linux/capability.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include <linux/times.h>
+#include <linux/version.h>
+
+#include "dp_sysfs.h"
+#include "datapath.h"
+#include "dp_dev.h"
+
+#ifdef CONFIG_SYSFS
+#define to_dev(obj)    container_of(obj, struct device, kobj)
+
+/* Hack to attempt to build on more platforms. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+#define 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 DP_DEVICE_ATTR DEVICE_ATTR
+#define DEVICE_PARAMS struct device *d, struct device_attribute *attr
+#define DEVICE_ARGS d, attr
+#define DEV_ATTR(NAME) dev_attr_##NAME
+#endif
+
+/*
+ * Common code for storing bridge parameters.
+ */
+static ssize_t store_bridge_parm(DEVICE_PARAMS,
+                                const char *buf, size_t len,
+                                void (*set)(struct datapath *, unsigned long))
+{
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       char *endp;
+       unsigned long val;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       val = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EINVAL;
+
+#if 0
+       spin_lock_bh(&br->lock);
+       (*set)(br, val);
+       spin_unlock_bh(&br->lock);
+#else
+       /* xxx We use a default value of 0 for all fields.  If the caller is
+        * xxx attempting to set the value to our default, just silently
+        * xxx ignore the request. 
+        */
+       if (val != 0) {
+               printk("%s: xxx writing dp parms not supported yet!\n", 
+                      dp_name(dp));
+       }
+#endif
+       return len;
+}
+
+
+static ssize_t show_forward_delay(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+
+static void set_forward_delay(struct datapath *dp, unsigned long val)
+{
+#if 0
+       unsigned long delay = clock_t_to_jiffies(val);
+       br->forward_delay = delay;
+       if (br_is_root_bridge(br))
+               br->bridge_forward_delay = delay;
+#else
+       printk("%s: xxx attempt to set_forward_delay()\n", dp_name(dp));
+#endif
+}
+
+static ssize_t store_forward_delay(DEVICE_PARAMS,
+                                  const char *buf, size_t len)
+{
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay);
+}
+static DP_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
+                  show_forward_delay, store_forward_delay);
+
+static ssize_t show_hello_time(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       return sprintf(buf, "%lu\n",
+                      jiffies_to_clock_t(to_bridge(d)->hello_time));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+
+static void set_hello_time(struct datapath *dp, unsigned long val)
+{
+#if 0
+       unsigned long t = clock_t_to_jiffies(val);
+       br->hello_time = t;
+       if (br_is_root_bridge(br))
+               br->bridge_hello_time = t;
+#else
+       printk("%s: xxx attempt to set_hello_time()\n", dp_name(dp));
+#endif
+}
+
+static ssize_t store_hello_time(DEVICE_PARAMS,
+                               const char *buf,
+                               size_t len)
+{
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time);
+}
+static DP_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
+                  store_hello_time);
+
+static ssize_t show_max_age(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       return sprintf(buf, "%lu\n",
+                      jiffies_to_clock_t(to_bridge(d)->max_age));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+
+static void set_max_age(struct datapath *dp, unsigned long val)
+{
+#if 0
+       unsigned long t = clock_t_to_jiffies(val);
+       br->max_age = t;
+       if (br_is_root_bridge(br))
+               br->bridge_max_age = t;
+#else
+       printk("%s: xxx attempt to set_max_age()\n", dp_name(dp));
+#endif
+}
+
+static ssize_t store_max_age(DEVICE_PARAMS,
+                            const char *buf, size_t len)
+{
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_max_age);
+}
+static DP_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
+
+static ssize_t show_ageing_time(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+
+static void set_ageing_time(struct datapath *dp, unsigned long val)
+{
+#if 0
+       br->ageing_time = clock_t_to_jiffies(val);
+#else
+       printk("%s: xxx attempt to set_ageing_time()\n", dp_name(dp));
+#endif
+}
+
+static ssize_t store_ageing_time(DEVICE_PARAMS,
+                                const char *buf, size_t len)
+{
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time);
+}
+static DP_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
+                  store_ageing_time);
+
+static ssize_t show_stp_state(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%d\n", br->stp_enabled);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+
+
+static ssize_t store_stp_state(DEVICE_PARAMS,
+                              const char *buf,
+                              size_t len)
+{
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+#if 0
+       char *endp;
+       unsigned long val;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       val = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EINVAL;
+
+       rtnl_lock();
+       br_stp_set_enabled(br, val);
+       rtnl_unlock();
+#else
+       printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
+#endif
+
+       return len;
+}
+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)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%d\n",
+                      (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+
+static void set_priority(struct datapath *dp, unsigned long val)
+{
+#if 0
+       br_stp_set_bridge_priority(br, (u16) val);
+#else
+       printk("%s: xxx attempt to set_priority()\n", dp_name(dp));
+#endif
+}
+
+static ssize_t store_priority(DEVICE_PARAMS,
+                              const char *buf, size_t len)
+{
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority);
+}
+static DP_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
+
+static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
+#else
+       return sprintf(buf, "0000.010203040506\n");
+#endif
+}
+static DP_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
+
+static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
+{
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr;
+
+       /* xxx Do we need a lock of some sort? */
+       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 DP_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
+
+static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", to_bridge(d)->root_port);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
+
+static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
+
+static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
+
+static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%d\n", br->topology_change_detected);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(topology_change_detected, S_IRUGO,
+                  show_topology_change_detected, NULL);
+
+static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
+
+static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
+
+static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
+                  NULL);
+
+static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static DP_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+
+static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
+{
+#if 0
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+       return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
+                      br->group_addr[0], br->group_addr[1],
+                      br->group_addr[2], br->group_addr[3],
+                      br->group_addr[4], br->group_addr[5]);
+#else
+       return sprintf(buf, "00:01:02:03:04:05\n");
+#endif
+}
+
+static ssize_t store_group_addr(DEVICE_PARAMS,
+                               const char *buf, size_t len)
+{
+       struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
+#if 0
+       unsigned new_addr[6];
+       int i;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
+                  &new_addr[0], &new_addr[1], &new_addr[2],
+                  &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
+               return -EINVAL;
+
+       /* Must be 01:80:c2:00:00:0X */
+       for (i = 0; i < 5; i++)
+               if (new_addr[i] != br_group_address[i])
+                       return -EINVAL;
+
+       if (new_addr[5] & ~0xf)
+               return -EINVAL;
+
+       if (new_addr[5] == 1    /* 802.3x Pause address */
+           || new_addr[5] == 2 /* 802.3ad Slow protocols */
+           || new_addr[5] == 3) /* 802.1X PAE address */
+               return -EINVAL;
+
+       spin_lock_bh(&br->lock);
+       for (i = 0; i < 6; i++)
+               br->group_addr[i] = new_addr[i];
+       spin_unlock_bh(&br->lock);
+#else
+       printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
+#endif
+       return len;
+}
+
+static DP_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+                  show_group_addr, store_group_addr);
+
+static struct attribute *bridge_attrs[] = {
+       &DEV_ATTR(forward_delay).attr,
+       &DEV_ATTR(hello_time).attr,
+       &DEV_ATTR(max_age).attr,
+       &DEV_ATTR(ageing_time).attr,
+       &DEV_ATTR(stp_state).attr,
+       &DEV_ATTR(priority).attr,
+       &DEV_ATTR(bridge_id).attr,
+       &DEV_ATTR(root_id).attr,
+       &DEV_ATTR(root_path_cost).attr,
+       &DEV_ATTR(root_port).attr,
+       &DEV_ATTR(topology_change).attr,
+       &DEV_ATTR(topology_change_detected).attr,
+       &DEV_ATTR(hello_timer).attr,
+       &DEV_ATTR(tcn_timer).attr,
+       &DEV_ATTR(topology_change_timer).attr,
+       &DEV_ATTR(gc_timer).attr,
+       &DEV_ATTR(group_addr).attr,
+       NULL
+};
+
+static struct attribute_group bridge_group = {
+       .name = SYSFS_BRIDGE_ATTR,
+       .attrs = bridge_attrs,
+};
+
+/*
+ * Add entries in sysfs onto the existing network class device
+ * for the bridge.
+ *   Adds a attribute group "bridge" containing tuning parameters.
+ *   Sub directory to hold links to interfaces.
+ *
+ * Note: the ifobj exists only to be a subdirectory
+ *   to hold links.  The ifobj exists in the same data structure
+ *   as its parent the bridge so reference counting works.
+ */
+int dp_sysfs_add_dp(struct datapath *dp)
+{
+       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
+       int err;
+
+       err = sysfs_create_group(kobj, &bridge_group);
+       if (err) {
+               pr_info("%s: can't create group %s/%s\n",
+                       __func__, dp_name(dp), bridge_group.name);
+               goto out1;
+       }
+
+       /* 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;
+       }
+       kobject_uevent(&dp->ifobj, KOBJ_ADD);
+       return 0;
+
+ out2:
+       sysfs_remove_group(kobj, &bridge_group);
+ out1:
+       return err;
+}
+
+int dp_sysfs_del_dp(struct datapath *dp)
+{
+       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
+
+       kobject_del(&dp->ifobj);
+       sysfs_remove_group(kobj, &bridge_group);
+
+       return 0;
+}
+#else /* !CONFIG_SYSFS */
+int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
+int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
+int dp_sysfs_add_if(struct net_bridge_port *p) { return 0; }
+int dp_sysfs_del_if(struct net_bridge_port *p) { return 0; }
+#endif /* !CONFIG_SYSFS */
diff --git a/datapath/dp_sysfs_if.c b/datapath/dp_sysfs_if.c
new file mode 100644 (file)
index 0000000..95c26dc
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ */
+
+/*
+ *     Sysfs attributes of bridge ports for Open vSwitch
+ *
+ *  This has been shamelessly copied from the kernel sources.
+ */
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include "dp_sysfs.h"
+#include "datapath.h"
+
+#ifdef CONFIG_SYSFS
+
+struct brport_attribute {
+       struct attribute        attr;
+       ssize_t (*show)(struct net_bridge_port *, char *);
+       ssize_t (*store)(struct net_bridge_port *, unsigned long);
+};
+
+#define BRPORT_ATTR(_name,_mode,_show,_store)                  \
+struct brport_attribute brport_attr_##_name = {                \
+       .attr = {.name = __stringify(_name),                    \
+                .mode = _mode,                                 \
+                .owner = THIS_MODULE, },                       \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->path_cost);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v)
+{
+#if 0
+       br_stp_set_path_cost(p, v);
+#endif
+       return 0;
+}
+static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
+                  show_path_cost, store_path_cost);
+
+static ssize_t show_priority(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->priority);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static ssize_t store_priority(struct net_bridge_port *p, unsigned long v)
+{
+#if 0
+       if (v >= (1<<(16-BR_PORT_BITS)))
+               return -ERANGE;
+       br_stp_set_port_priority(p, v);
+#endif
+       return 0;
+}
+static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
+                        show_priority, store_priority);
+
+static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return br_show_bridge_id(buf, &p->designated_root);
+#else
+       return sprintf(buf, "0000.010203040506\n");
+#endif
+}
+static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
+
+static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return br_show_bridge_id(buf, &p->designated_bridge);
+#else
+       return sprintf(buf, "0000.060504030201\n");
+#endif
+}
+static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
+
+static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->designated_port);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
+
+static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->designated_cost);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
+
+static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "0x%x\n", p->port_id);
+#else
+       return sprintf(buf, "0x%x\n", 0);
+#endif
+}
+static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
+
+static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
+{
+       return sprintf(buf, "0x%x\n", p->port_no);
+}
+
+static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
+
+static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->topology_change_ack);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
+
+static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->config_pending);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
+
+static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
+{
+#if 0
+       return sprintf(buf, "%d\n", p->state);
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
+
+static ssize_t show_message_age_timer(struct net_bridge_port *p,
+                                           char *buf)
+{
+#if 0
+       return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
+
+static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
+                                           char *buf)
+{
+#if 0
+       return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
+
+static ssize_t show_hold_timer(struct net_bridge_port *p,
+                                           char *buf)
+{
+#if 0
+       return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
+#else
+       return sprintf(buf, "%d\n", 0);
+#endif
+}
+static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
+
+static struct brport_attribute *brport_attrs[] = {
+       &brport_attr_path_cost,
+       &brport_attr_priority,
+       &brport_attr_port_id,
+       &brport_attr_port_no,
+       &brport_attr_designated_root,
+       &brport_attr_designated_bridge,
+       &brport_attr_designated_port,
+       &brport_attr_designated_cost,
+       &brport_attr_state,
+       &brport_attr_change_ack,
+       &brport_attr_config_pending,
+       &brport_attr_message_age_timer,
+       &brport_attr_forward_delay_timer,
+       &brport_attr_hold_timer,
+       NULL
+};
+
+#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
+#define to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
+
+static ssize_t brport_show(struct kobject * kobj,
+                          struct attribute * attr, char * buf)
+{
+       struct brport_attribute * brport_attr = to_brport_attr(attr);
+       struct net_bridge_port * p = to_brport(kobj);
+
+       return brport_attr->show(p, buf);
+}
+
+static ssize_t brport_store(struct kobject * kobj,
+                           struct attribute * attr,
+                           const char * buf, size_t count)
+{
+       struct net_bridge_port * p = to_brport(kobj);
+#if 0
+       struct brport_attribute * brport_attr = to_brport_attr(attr);
+       char *endp;
+       unsigned long val;
+#endif
+       ssize_t ret = -EINVAL;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+#if 0
+       val = simple_strtoul(buf, &endp, 0);
+       if (endp != buf) {
+               rtnl_lock();
+               if (p->dev && p->br && brport_attr->store) {
+                       spin_lock_bh(&p->br->lock);
+                       ret = brport_attr->store(p, val);
+                       spin_unlock_bh(&p->br->lock);
+                       if (ret == 0)
+                               ret = count;
+               }
+               rtnl_unlock();
+       }
+#else
+       printk("%s: xxx writing port parms not supported yet!\n", 
+              dp_name(p->dp));
+#endif
+       return ret;
+}
+
+struct sysfs_ops brport_sysfs_ops = {
+       .show = brport_show,
+       .store = brport_store,
+};
+
+/*
+ * 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 dp_sysfs_add_if(struct net_bridge_port *p)
+{
+       struct datapath *dp = p->dp;
+       struct brport_attribute **a;
+       int err;
+
+       /* 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); /* "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;
+       }
+
+       /* 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);
+       if (err)
+               goto err_del;
+       strcpy(p->linkname, p->dev->name);
+
+       kobject_uevent(&p->kobj, KOBJ_ADD);
+
+       return 0;
+
+err_del:
+       kobject_del(&p->kobj);
+err:
+       p->linkname[0] = 0;
+       return err;
+}
+
+int dp_sysfs_del_if(struct net_bridge_port *p)
+{
+       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 af5821a223264e4e594f751595d2eaa1f8536cd0..aa10e66af6a5e49aae0fa1eb8e1ac5d51d441e98 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 e7359a46325992ff3a01a41d7f00d278f594a0b1..e5aa51da64821590e71847c7c2cbc9fecb98b7a5 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 7dbb010c2c6b19ebe4427cea252a01a519408aa2..4cf797e36c5711ff7ade7597490f628f3cb83b57 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 d29151339be6c377c7eb9203f3de0d1b87fad715..b7182832999dd9da3a44207d72a2c89327ad2fcb 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 f06d4a035c85099266167ea42d8909fcc7dfbc55..44f9210c867ecee67624965aeca32cbb22025fd2 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 694bdcc506a1611766a14e84cd52433eed9cc27b..7d5ac4cfe932d3174b364bce733fe1f7e9676786 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 ae363827a46a183d82903461434fa9c6e35a4600..868c85421d72dca7181417df82822313cecb79e1 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 433d7a0fac56ba6cb47e402fe573ed909941e8ed..225827ef5d226936191c600f6b488d8e3182261a 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 42345f86b155a4b07badf415541396f728a5d4fc..e159244ebbf5bf8e705ebdd6d1c96bf1bd353df0 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 4ad4af4c607a9eca9fa961750d79ac36eae165a5..1e3f0029514ee474b7e07b07eb5696e593fd1759 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 a54aa5204aa2b2616ba8a0f809fcede9452a9c48..d0c324cfc3906ffb9a8ef5df6981a7be3043806e 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 4ab65680680a449f54fb2db7cbe798aa4c0a9292..ea0561dafd36b0553ecbdcd7fe9b982e371a1462 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 c8ae00e061eb3499a3be3c8101f768c360c452f7..4f90781334f80aeaf22fb51f667e40d97ca3c65c 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 07452c91f8fe866d08966add0b27344a3ff64861..96696a2452817f03e12e01a66225fbbb8791bcdb 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 1e0f0aa09ddb35d140f506b9a799d4864b4e6361..63b59ddb0770d97d694a15d3e75de501c738909a 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 2c9548b326bdf3d0e744f2bcffc577b567f3780f..a362a65a1a4e59fae5fe0a3cfe028e54df1b7b96 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 181cae59940b89c2390ddc37f5edb97de698b938..4c6c9e955a5e0358c3381e9376408e63e16e006b 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 7d8777fa8cc5f884a14e09873cb73a034ac6c6cb..e1736bc6c399b5932265ee12c18d65f055443507 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 97a930aca5d1c8fad65b615b2c344fa89aec4964..1b95d96c1cbf37ea4ed5347f4b1d0e023ee8bb8f 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 0e88729375f32a8a5e2e8a88e8136fab6376fda9..60890d496c4878c809f239721931b73f6339a585 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 e867c0ebc5f210fdd1f7d3f33d1b8752e7323d1e..0162c45ab16249342d17b01930593ac725a5f3b9 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 55eb2c28af34021c4178969882667a602603d758..c26cdc2c0af6870a85595d1969badf3efa73992c 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 f4c1b4098681cb65976a7ea70ed8a1966b49b6fd..398cac4fd4401216c2da96806c1e79d50dd1522c 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 df942f5be57ac03435b526719f2df7ee125df5e9..1b52a7bcba3aac72e13ae68dab47837ff96f5b29 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 fcb579ed8336803ae82e60ba94cb5615a5067bde..61e4b123ff23c58205062ae6baf79da48611afee 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 8c83cac9ef223efc779675859e322522b09c114d..dc91bce3d3d23d9c2958cc27f6e332b7fee9337a 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 3d8854b57996077a8a0faa23afd6669be35f4455..dc4d4568182180fe4adbb2413e306d7e0e96bf39 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 270281832d94362ba81e8d7de4dcb5ef671db164..5a0da820c2fbe8a06c8f3b091fa23550ea542d32 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 4d1a8582213932a3b1f3f19dfae1e98531a9bb0c..3d255746d16d537d1b91b4a38ba3f9262ed2ae12 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 5dd77c056e64f941694f1eae16005db9ba910a2f..603e2587ba5c7f085e913a8a1ecd3acbc4eb5b8d 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 22fe19a0427ed1520bde0247d648d487bde591b1..ea0641ef0523aac234f4d295319d64d53e5a9ab4 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 45c3580243d39c721de193d02f2323677b3b7253..e6e7d4ef6ea7eb1458fcc93cb8aeb504f2f92e26 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 70570e925ec42f1969f0813bf592ac47c1f98202..39844f69f2420c5b3dcff0da44d73153dbe3f197 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 a7b43f7b4f34535e3ce429e0f416bb579c8e5a20..28491fc6c17f5a9d6261e6b4bf4672c09c4a8ee0 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 665d3d0419589dc9d721952ed16085ad6f4e9cdf..0dbf94dc267b1330c9ab96647587ef3de13b6748 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 8e8dd237db8e0f17e93b4679543306e8521aa63a..7a59526536e51f53ad8676453be12db7c79638f2 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 a5b3196164066438f31742031028f8a9e382e9dc..82d550f5c1b6796e1e2c88316289be0011744268 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 2344835209a0230fdd2441f0eb2453148d8c27ac..6c91e9413a0994be48236e2b098df68375df1697 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 225b870724fa30c552dddb8d3dafe6c568a808ee..2fe1289c64344636d8135d9e52b33a47f9bcb87d 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 eba4baf0f3d408b19dfd520fed3d09030802b0e8..462c2a6f9e985e04f2020abcd79f27c3e8f07c94 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 cd13b59151a1384b6513952ca5f45bc4f9838998..789d61ab13950347d62e6caf3bad9625ec26634f 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 aebb4ccdac59771dbf03b81b66f5a6f6de173070..c3baba9e0d0c8eb7614b68642b7034e065f4024a 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 5f1ca8258e5759b01f0581a5e00f35d57363f16e..98bcf4c3e707556d4d81947ec9e7ef15e7bda00f 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 cf741386c6954142a7e411aef65928ebd787f37e..94bd916d0c1c30bf4780cf6f81365a64a559ec26 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