From: Ben Pfaff Date: Wed, 19 Aug 2009 20:03:46 +0000 (-0700) Subject: Merge citrix into master. X-Git-Tag: v0.99.0~133 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=8fef8c7121222233075a03d57db7e0b48d5f6be5 Merge citrix into master. 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. --- 8fef8c7121222233075a03d57db7e0b48d5f6be5 diff --cc datapath/datapath.c index bf8043b60,926f278f9..de607e8be --- a/datapath/datapath.c +++ b/datapath/datapath.c @@@ -222,13 -225,6 +223,11 @@@ static int create_dp(int dp_idx, const skb_queue_head_init(&dp->queues[i]); init_waitqueue_head(&dp->waitqueue); + /* Initialize kobject for bridge. This will be added as + * /sys/class/net//bridge later, if sysfs is enabled. */ - kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); /* "bridge" */ + dp->ifobj.kset = NULL; - dp->ifobj.parent = NULL; + kobject_init(&dp->ifobj, &dp_ktype); + /* Allocate table. */ err = -ENOMEM; rcu_assign_pointer(dp->table, dp_table_create(DP_L1_SIZE)); @@@ -256,9 -252,8 +255,7 @@@ mutex_unlock(&dp_mutex); rtnl_unlock(); - #ifdef SUPPORT_SYSFS - if (dp_add_dp_hook) - dp_add_dp_hook(dp); + dp_sysfs_add_dp(dp); - #endif return 0; @@@ -286,9 -281,8 +283,7 @@@ static void do_destroy_dp(struct datapa if (p->port_no != ODPP_LOCAL) dp_del_port(p); - #ifdef SUPPORT_SYSFS - if (dp_del_dp_hook) - dp_del_dp_hook(dp); + dp_sysfs_del_dp(dp); - #endif rcu_assign_pointer(dps[dp->dp_idx], NULL); @@@ -326,19 -320,6 +321,19 @@@ err_unlock return err; } +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 SUPPORT_SYSFS ++#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) { @@@ -368,13 -349,6 +363,11 @@@ list_add_rcu(&p->node, &dp->port_list); dp->n_ports++; + /* Initialize kobject for bridge. This will be added as + * /sys/class/net//brport later, if sysfs is enabled. */ - kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); /* "brport" */ + p->kobj.kset = NULL; - p->kobj.parent = &p->dev->NETDEV_DEV_MEMBER.kobj; + kobject_init(&p->kobj, &brport_ktype); + dp_ifinfo_notify(RTM_NEWLINK, p); return 0; @@@ -430,9 -402,10 +421,9 @@@ got_port_no if (err) goto out_put; - #ifdef SUPPORT_SYSFS - if (dp_add_if_hook) - dp_add_if_hook(dp->ports[port_no]); + dp_sysfs_add_if(dp->ports[port_no]); - #endif + + err = __put_user(port_no, &port.port); out_put: dev_put(dev); @@@ -448,10 -421,13 +439,8 @@@ int dp_del_port(struct net_bridge_port { ASSERT_RTNL(); - #ifdef SUPPORT_SYSFS - if (p->port_no != ODPP_LOCAL && dp_del_if_hook) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - sysfs_remove_link(&p->dp->ifobj, p->dev->name); -#else - sysfs_remove_link(p->dp->ifobj, p->dev->name); -#endif - } + if (p->port_no != ODPP_LOCAL) + dp_sysfs_del_if(p); - #endif dp_ifinfo_notify(RTM_DELLINK, p); p->dp->n_ports--; diff --cc datapath/datapath.h index 62c79d43b,c6ec86a39..b5200848b --- a/datapath/datapath.h +++ b/datapath/datapath.h @@@ -18,8 -18,9 +18,9 @@@ #include #include #include + #include #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. */ diff --cc datapath/dp_sysfs.h index c0ac01b95,000000000..be044eaf2 mode 100644,000000..100644 --- a/datapath/dp_sysfs.h +++ b/datapath/dp_sysfs.h @@@ -1,37 -1,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); + - #include - #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) - #define SUPPORT_SYSFS 1 - #else - /* We only support sysfs on Linux 2.6.18 because that's the only place we - * really need it (on Xen, for brcompat) and it's a big pain to try to support - * multiple versions. */ - #endif - - #ifdef SUPPORT_SYSFS ++#ifdef CONFIG_SYSFS +extern struct sysfs_ops brport_sysfs_ops; +#endif + +#endif /* dp_sysfs.h */ + diff --cc datapath/dp_sysfs_dp.c index 9699a0760,c1e82eb6f..fafd9a9cd --- a/datapath/dp_sysfs_dp.c +++ b/datapath/dp_sysfs_dp.c @@@ -33,11 -33,15 +33,15 @@@ /* Hack to attempt to build on more platforms. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) - #define to_kobj(d) &(d)->class_dev.kobj -#define BRC_DEVICE_ATTR CLASS_DEVICE_ATTR +#define DP_DEVICE_ATTR CLASS_DEVICE_ATTR + #define DEVICE_PARAMS struct class_device *d + #define DEVICE_ARGS d + #define DEV_ATTR(NAME) class_device_attr_##NAME #else - #define to_kobj(d) &(d)->dev.kobj -#define BRC_DEVICE_ATTR DEVICE_ATTR +#define DP_DEVICE_ATTR DEVICE_ATTR + #define DEVICE_PARAMS struct device *d, struct device_attribute *attr + #define DEVICE_ARGS d, attr + #define DEV_ATTR(NAME) dev_attr_##NAME #endif /* @@@ -99,15 -102,15 +102,15 @@@ static void set_forward_delay(struct da #endif } - static ssize_t store_forward_delay(struct class_device *d, + static ssize_t store_forward_delay(DEVICE_PARAMS, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_forward_delay); + return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay); } -static BRC_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, +static DP_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, show_forward_delay, store_forward_delay); - static ssize_t show_hello_time(struct class_device *d, char *buf) + static ssize_t show_hello_time(DEVICE_PARAMS, char *buf) { #if 0 return sprintf(buf, "%lu\n", @@@ -133,13 -136,12 +136,12 @@@ static ssize_t store_hello_time(DEVICE_ const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_hello_time); + return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time); } -static BRC_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, +static DP_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, store_hello_time); - static ssize_t show_max_age(struct class_device *d, - char *buf) + static ssize_t show_max_age(DEVICE_PARAMS, char *buf) { #if 0 return sprintf(buf, "%lu\n", @@@ -161,15 -163,14 +163,14 @@@ static void set_max_age(struct datapat #endif } - static ssize_t store_max_age(struct class_device *d, + static ssize_t store_max_age(DEVICE_PARAMS, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_max_age); + return store_bridge_parm(DEVICE_ARGS, buf, len, set_max_age); } -static BRC_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); +static DP_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); - static ssize_t show_ageing_time(struct class_device *d, - char *buf) + static ssize_t show_ageing_time(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -188,16 -189,15 +189,15 @@@ static void set_ageing_time(struct data #endif } - static ssize_t store_ageing_time(struct class_device *d, + static ssize_t store_ageing_time(DEVICE_PARAMS, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_ageing_time); + return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time); } -static BRC_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, +static DP_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, store_ageing_time); - static ssize_t show_stp_state(struct class_device *d, - char *buf) + static ssize_t show_stp_state(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -233,11 -233,10 +233,10 @@@ static ssize_t store_stp_state(DEVICE_P return len; } -static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, +static DP_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, store_stp_state); - static ssize_t show_priority(struct class_device *d, - char *buf) + static ssize_t show_priority(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -257,15 -256,14 +256,14 @@@ static void set_priority(struct datapat #endif } - static ssize_t store_priority(struct class_device *d, + static ssize_t store_priority(DEVICE_PARAMS, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_priority); + return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority); } -static BRC_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority); +static DP_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority); - static ssize_t show_root_id(struct class_device *d, - char *buf) + static ssize_t show_root_id(DEVICE_PARAMS, char *buf) { #if 0 return br_show_bridge_id(buf, &to_bridge(d)->designated_root); @@@ -273,10 -271,9 +271,9 @@@ return sprintf(buf, "0000.010203040506\n"); #endif } -static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); +static DP_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); - static ssize_t show_bridge_id(struct class_device *d, - char *buf) + static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf) { struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr; @@@ -285,10 -282,9 +282,9 @@@ return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n", 0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); } -static BRC_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); +static DP_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); - static ssize_t show_root_port(struct class_device *d, - char *buf) + static ssize_t show_root_port(DEVICE_PARAMS, char *buf) { #if 0 return sprintf(buf, "%d\n", to_bridge(d)->root_port); @@@ -296,10 -292,9 +292,9 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); +static DP_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); - static ssize_t show_root_path_cost(struct class_device *d, - char *buf) + static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf) { #if 0 return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); @@@ -307,10 -302,9 +302,9 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); +static DP_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); - static ssize_t show_topology_change(struct class_device *d, - char *buf) + static ssize_t show_topology_change(DEVICE_PARAMS, char *buf) { #if 0 return sprintf(buf, "%d\n", to_bridge(d)->topology_change); @@@ -318,10 -312,9 +312,9 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); +static DP_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); - static ssize_t show_topology_change_detected(struct class_device *d, - char *buf) + static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -330,11 -323,10 +323,10 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO, +static DP_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL); - static ssize_t show_hello_timer(struct class_device *d, - char *buf) + static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -343,10 -335,9 +335,9 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); +static DP_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); - static ssize_t show_tcn_timer(struct class_device *d, - char *buf) + static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -355,10 -346,9 +346,9 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); +static DP_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); - static ssize_t show_topology_change_timer(struct class_device *d, - char *buf) + static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -367,11 -357,10 +357,10 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, +static DP_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL); - static ssize_t show_gc_timer(struct class_device *d, - char *buf) + static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -380,10 -369,9 +369,9 @@@ return sprintf(buf, "%d\n", 0); #endif } -static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); +static DP_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); - static ssize_t show_group_addr(struct class_device *d, - char *buf) + static ssize_t show_group_addr(DEVICE_PARAMS, char *buf) { #if 0 struct datapath *dp = dp_dev_get_dp(to_net_dev(d)); @@@ -474,9 -462,9 +462,9 @@@ static struct attribute_group bridge_gr * to hold links. The ifobj exists in the same data structure * as its parent the bridge so reference counting works. */ -int brc_sysfs_add_dp(struct datapath *dp) +int dp_sysfs_add_dp(struct datapath *dp) { - struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev); + struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj; int err; err = sysfs_create_group(kobj, &bridge_group); @@@ -486,15 -474,26 +474,14 @@@ goto out1; } - /* Create /sys/class/net//bridge directory. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); - dp->ifobj.ktype = NULL; - dp->ifobj.kset = NULL; -- dp->ifobj.parent = kobj; - err = kobject_add(&dp->ifobj); - - err = kobject_register(&dp->ifobj); ++ /* Create /sys/class/net//brif directory. */ ++ err = kobject_add(&dp->ifobj, kobj, SYSFS_BRIDGE_PORT_SUBDIR); if (err) { pr_info("%s: can't add kobject (directory) %s/%s\n", - __FUNCTION__, dp_name(dp), dp->ifobj.name); + __FUNCTION__, dp_name(dp), kobject_name(&dp->ifobj)); goto out2; } -#else - dp->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, kobj); - if (!dp->ifobj) { - pr_info("%s: can't add kobject (directory) %s/%s\n", - __func__, dp_name(dp), SYSFS_BRIDGE_PORT_SUBDIR); - goto out2; - } -#endif + kobject_uevent(&dp->ifobj, KOBJ_ADD); return 0; out2: @@@ -503,23 -502,27 +490,18 @@@ return err; } -int brc_sysfs_del_dp(struct datapath *dp) +int dp_sysfs_del_dp(struct datapath *dp) { - struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev); + struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - kobject_unregister(&dp->ifobj); -#else - kobject_put(dp->ifobj); -#endif + kobject_del(&dp->ifobj); sysfs_remove_group(kobj, &bridge_group); return 0; } - #else /* !SUPPORT_SYSFS */ + #else /* !CONFIG_SYSFS */ -int brc_sysfs_add_dp(struct datapath *dp) { return 0; } -int brc_sysfs_del_dp(struct datapath *dp) { return 0; } -int brc_sysfs_add_if(struct net_bridge_port *p) { return 0; } -int brc_sysfs_del_if(struct net_bridge_port *p) -{ - dev_put(p->dev); - kfree(p); - return 0; -} +int dp_sysfs_add_dp(struct datapath *dp) { return 0; } +int dp_sysfs_del_dp(struct datapath *dp) { return 0; } +int dp_sysfs_add_if(struct net_bridge_port *p) { return 0; } - int dp_sysfs_del_if(struct net_bridge_port *p) - { - dev_put(p->dev); - kfree(p); - return 0; - } - #endif /* !SUPPORT_SYSFS */ ++int dp_sysfs_del_if(struct net_bridge_port *p) { return 0; } + #endif /* !CONFIG_SYSFS */ diff --cc datapath/dp_sysfs_if.c index ab928f6c6,7a9b8b895..95c26dc42 --- a/datapath/dp_sysfs_if.c +++ b/datapath/dp_sysfs_if.c @@@ -18,10 -18,10 +18,10 @@@ #include #include #include -#include "brc_sysfs.h" +#include "dp_sysfs.h" #include "datapath.h" - #ifdef SUPPORT_SYSFS + #ifdef CONFIG_SYSFS struct brport_attribute { struct attribute attr; @@@ -277,16 -289,15 +277,17 @@@ int dp_sysfs_add_if(struct net_bridge_p struct brport_attribute **a; int err; - err = kobject_init_and_add(&p->kobj, &brport_ktype, - &(p->dev->NETDEV_DEV_MEMBER.kobj), - SYSFS_BRIDGE_PORT_ATTR); + /* Create /sys/class/net//brport directory. */ - err = kobject_add(&p->kobj); ++ err = kobject_add(&p->kobj, &p->dev->NETDEV_DEV_MEMBER.kobj, ++ SYSFS_BRIDGE_PORT_ATTR); if (err) - goto err_put; + goto err; + /* Create symlink from /sys/class/net//brport/bridge to + * /sys/class/net/. */ err = sysfs_create_link(&p->kobj, &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj, - SYSFS_BRIDGE_PORT_LINK); + SYSFS_BRIDGE_PORT_LINK); /* "bridge" */ if (err) goto err_del; @@@ -306,28 -317,26 +307,23 @@@ kobject_uevent(&p->kobj, KOBJ_ADD); -- return err; ++ return 0; err_del: kobject_del(&p->kobj); - err_put: -- kobject_put(&p->kobj); - - /* Ensure that dp_sysfs_del_if becomes a no-op. */ - p->kobj.dentry = NULL; + err: ++ p->linkname[0] = 0; return err; } -int brc_sysfs_del_if(struct net_bridge_port *p) +int dp_sysfs_del_if(struct net_bridge_port *p) { - struct net_device *dev = p->dev; - - kobject_uevent(&p->kobj, KOBJ_REMOVE); - kobject_del(&p->kobj); - - dev_put(dev); - - kobject_put(&p->kobj); - + if (p->linkname[0]) { + sysfs_remove_link(&p->dp->ifobj, p->linkname); - p->linkname[0] = '\0'; - } - if (p->kobj.dentry) { + kobject_uevent(&p->kobj, KOBJ_REMOVE); + kobject_del(&p->kobj); ++ p->linkname[0] = '\0'; + } return 0; } - #endif /* SUPPORT_SYSFS */ + #endif /* CONFIG_SYSFS */ diff --cc datapath/linux-2.6/compat-2.6/include/linux/kobject.h index c0de3d2ea,7dbb010c2..4cf797e36 --- a/datapath/linux-2.6/compat-2.6/include/linux/kobject.h +++ b/datapath/linux-2.6/compat-2.6/include/linux/kobject.h @@@ -4,13 -4,20 +4,27 @@@ #include_next #include ++ #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 */ diff --cc debian/openvswitch-switch.template index 69f1de607,f06d4a035..44f9210c8 --- a/debian/openvswitch-switch.template +++ b/debian/openvswitch-switch.template @@@ -133,17 -133,17 +133,17 @@@ MGMT_VCONNS="punix:/var/run/ovs-openflo #RATE_LIMIT=1000 # INACTIVITY_PROBE: The maximum number of seconds of inactivity on the - # controller connection before secchan sends an inactivity probe + # controller connection before ovs-openflowd sends an inactivity probe # message to the controller. The valid range is 5 and up. If unset, - # secchan defaults to 5 seconds. -# ovs-openflowd defaults to 15 seconds. ++# ovs-openflowd defaults to 5 seconds. #INACTIVITY_PROBE=5 - # MAX_BACKOFF: The maximum time that secchan will wait between + # MAX_BACKOFF: The maximum time that ovs-openflowd will wait between # attempts to connect to the controller. The valid range is 1 and up. - # If unset, secchan defaults to 8 seconds. -# If unset, ovs-openflowd defaults to 15 seconds. -#MAX_BACKOFF=15 ++# If unset, ovs-openflowd defaults to 8 seconds. +#MAX_BACKOFF=8 - # DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open" + # DAEMON_OPTS: Additional options to pass to ovs-openflowd, e.g. "--fail=open" DAEMON_OPTS="" # CORE_LIMIT: Maximum size for core dumps. diff --cc lib/dhcp-client.c index 9057121d0,c8ae00e06..4f9078133 --- a/lib/dhcp-client.c +++ b/lib/dhcp-client.c @@@ -923,10 -927,9 +927,9 @@@ do_receive_msg(struct dhclient *cli, st flow_extract(&b, 0, &flow); if (flow.dl_type != htons(ETH_TYPE_IP) || flow.nw_proto != IP_TYPE_UDP - || flow.tp_dst != htons(68) + || flow.tp_dst != htons(DHCP_CLIENT_PORT) || !(eth_addr_is_broadcast(flow.dl_dst) - || eth_addr_equals(flow.dl_dst, - netdev_get_etheraddr(cli->netdev)))) { + || eth_addr_equals(flow.dl_dst, cli_mac))) { continue; } diff --cc ofproto/ofproto.c index efa5c9b9e,55eb2c28a..c26cdc2c0 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@@ -1218,27 -1219,45 +1222,27 @@@ update_port(struct ofproto *p, const ch int error; COVERAGE_INC(ofproto_update_port); - ofport = shash_find_data(&p->port_by_name, devname); + + /* Query the datapath for port information. */ - error = dpif_port_query_by_name(&p->dpif, devname, &odp_port); + error = dpif_port_query_by_name(p->dpif, devname, &odp_port); - if (!error) { - if (!ofport) { - /* New port. */ - if (!ofport_conflicts(p, &odp_port)) { - ofport = make_ofport(&odp_port); - if (ofport) { - ofport_install(p, ofport); - send_port_status(p, ofport, OFPPR_ADD); - } - } - } else { - /* Modified port. */ - struct ofport *new_ofport = make_ofport(&odp_port); - if (!new_ofport) { - return; - } - new_ofport->opp.config &= OFPPC_PORT_DOWN; - new_ofport->opp.config |= ofport->opp.config & ~OFPPC_PORT_DOWN; - if (ofport_equal(ofport, new_ofport)) { - /* False alarm--no change. */ - ofport_free(new_ofport); - } else { - ofport_remove(p, ofport); - ofport_install(p, new_ofport); - ofport_free(ofport); - send_port_status(p, new_ofport, OFPPR_MODIFY); - } - } - } else if (error == ENOENT || error == ENODEV) { - /* Deleted port. */ - if (ofport) { - send_port_status(p, ofport, OFPPR_DELETE); - ofport_remove(p, ofport); - ofport_free(ofport); + /* Find the old ofport. */ + old_ofport = shash_find_data(&p->port_by_name, devname); + if (!error) { + if (!old_ofport) { + /* There's no port named 'devname' but there might be a port with + * the same port number. This could happen if a port is deleted + * and then a new one added in its place very quickly, or if a port + * is renamed. In the former case we want to send an OFPPR_DELETE + * and an OFPPR_ADD, and in the latter case we want to send a + * single OFPPR_MODIFY. We can distinguish the cases by comparing + * the old port's ifindex against the new port, or perhaps less + * reliably but more portably by comparing the old port's MAC + * against the new port's MAC. However, this code isn't that smart + * and always sends an OFPPR_MODIFY (XXX). */ + old_ofport = port_array_get(&p->ports, odp_port.port); } - } else { + } else if (error != ENOENT && error != ENODEV) { VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error " "%s", strerror(error)); return; diff --cc utilities/ovs-dpctl.c index 886cdb3ac,270281832..5a0da820c --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@@ -467,35 -428,6 +430,30 @@@ do_show(int argc, 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; - char dpif_name[IF_NAMESIZE]; - - if (dpif_open(all_dps.names[i], &dpif)) { - continue; - } - if (!dpif_get_name(&dpif, dpif_name, sizeof dpif_name)) { - printf("%s\n", dpif_name); ++ struct dpif *dpif; ++ if (!dpif_open(all_dps.names[i], &dpif)) { ++ printf("%s\n", dpif_name(dpif)); ++ dpif_close(dpif); + } - dpif_close(&dpif); + } + + svec_destroy(&all_dps); + if (error) { + exit(EXIT_FAILURE); + } +} + static void do_dump_flows(int argc UNUSED, char *argv[]) { diff --cc utilities/ovs-openflowd.8.in index 2ad50ae50,4d1a85822..3d255746d --- a/utilities/ovs-openflowd.8.in +++ b/utilities/ovs-openflowd.8.in @@@ -248,13 -248,13 +248,13 @@@ set up flows on its own when the contro .TP \fB--inactivity-probe=\fIsecs\fR - When the secure channel is connected to the controller, the secure - channel waits for a message to be received from the controller for + When the OpenFlow switch is connected to the controller, the + switch waits for a message to be received from the controller for \fIsecs\fR seconds before it sends a inactivity probe to the controller. After sending the inactivity probe, if no response is - received for an additional \fIsecs\fR seconds, the secure channel + received for an additional \fIsecs\fR seconds, the switch assumes that the connection has been broken and attempts to reconnect. -The default is 15 seconds, and the minimum value is 5 seconds. +The default and the minimum value are both 5 seconds. When fail-open mode is configured, changing the inactivity probe interval also changes the interval before entering fail-open mode (see diff --cc utilities/ovs-openflowd.c index ee29f27be,5dd77c056..603e2587b --- a/utilities/ovs-openflowd.c +++ b/utilities/ovs-openflowd.c @@@ -538,9 -540,9 +539,9 @@@ usage(void " closed: drop all packets\n" " open (default): act as learning switch\n" " --inactivity-probe=SECS time between inactivity probes\n" - " --max-idle=SECS max idle for flows set up by secchan\n" + " --max-idle=SECS max idle for flows set up by switch\n" " --max-backoff=SECS max time between controller connection\n" - " attempts (default: 15 seconds)\n" + " attempts (default: 8 seconds)\n" " -l, --listen=METHOD allow management connections on METHOD\n" " (a passive OpenFlow connection method)\n" " --snoop=METHOD allow controller snooping on METHOD\n" diff --cc vswitchd/bridge.c index 7ec774aca,22fe19a04..ea0641ef0 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@@ -305,8 -311,7 +313,9 @@@ bridge_init(void } } + unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows); + + bond_init(); bridge_reconfigure(); } @@@ -457,42 -524,20 +528,34 @@@ bridge_reconfigure(void bridge_get_all_ifaces(br, &want_ifaces); svec_diff(&want_ifaces, &cur_ifaces, &add_ifaces, NULL, NULL); - next_port_no = 1; for (i = 0; i < add_ifaces.n; i++) { const char *if_name = add_ifaces.names[i]; - for (;;) { - bool internal; - int error; - - /* It's an internal interface if it's marked that way, or if - * it's a bonded interface for which we're faking up a network - * device. */ - internal = cfg_get_bool(0, "iface.%s.internal", if_name); - if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) { - struct port *port = port_lookup(br, if_name); - if (port && port->n_ifaces > 1) { - internal = true; - } - } - int internal = cfg_get_bool(0, "iface.%s.internal", if_name); - int flags = internal ? ODP_PORT_INTERNAL : 0; - int error = dpif_port_add(br->dpif, if_name, flags, NULL); ++ bool internal; ++ int error; + - /* Add to datapath. */ - error = dpif_port_add(&br->dpif, if_name, next_port_no++, - internal ? ODP_PORT_INTERNAL : 0); - if (error != EEXIST) { - if (next_port_no >= 256) { - VLOG_ERR("ran out of valid port numbers on dp%u", - dpif_id(&br->dpif)); - goto out; - } - if (error) { - VLOG_ERR("failed to add %s interface to dp%u: %s", - if_name, dpif_id(&br->dpif), strerror(error)); - } - break; ++ /* It's an internal interface if it's marked that way, or if ++ * it's a bonded interface for which we're faking up a network ++ * device. */ ++ internal = cfg_get_bool(0, "iface.%s.internal", if_name); ++ if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) { ++ struct port *port = port_lookup(br, if_name); ++ if (port && port->n_ifaces > 1) { ++ internal = true; + } + } ++ ++ /* Add to datapath. */ ++ error = dpif_port_add(br->dpif, if_name, ++ internal ? ODP_PORT_INTERNAL : 0, NULL); + if (error == EXFULL) { + VLOG_ERR("ran out of valid port numbers on %s", + dpif_name(br->dpif)); + break; + } else if (error) { + VLOG_ERR("failed to add %s interface to %s: %s", + if_name, dpif_name(br->dpif), strerror(error)); + } } - out: svec_destroy(&cur_ifaces); svec_destroy(&want_ifaces); svec_destroy(&add_ifaces); @@@ -639,67 -660,28 +683,66 @@@ bridge_pick_local_hw_addr(struct bridg if (port->is_mirror_output_port) { continue; } - for (j = 0; j < port->n_ifaces; j++) { - struct iface *iface = port->ifaces[j]; - uint8_t iface_ea[ETH_ADDR_LEN]; + + /* Choose the MAC address to represent the port. */ + iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name); + if (iface_ea_u64) { + /* User specified explicitly. */ + eth_addr_from_uint64(iface_ea_u64, iface_ea); + + /* Find the interface with this Ethernet address (if any) so that + * we can provide the correct devname to the caller. */ + iface = NULL; + for (j = 0; j < port->n_ifaces; j++) { + struct iface *candidate = port->ifaces[j]; + uint8_t candidate_ea[ETH_ADDR_LEN]; - if (!netdev_nodev_get_etheraddr(candidate->name, candidate_ea) ++ if (!netdev_get_etheraddr(candidate->netdev, candidate_ea) + && eth_addr_equals(iface_ea, candidate_ea)) { + iface = candidate; + } + } + } else { + /* Choose the interface whose MAC address will represent the port. + * The Linux kernel bonding code always chooses the MAC address of + * the first slave added to a bond, and the Fedora networking + * scripts always add slaves to a bond in alphabetical order, so + * for compatibility we choose the interface with the name that is + * first in alphabetical order. */ + iface = port->ifaces[0]; + for (j = 1; j < port->n_ifaces; j++) { + struct iface *candidate = port->ifaces[j]; + if (strcmp(candidate->name, iface->name) < 0) { + iface = candidate; + } + } + + /* The local port doesn't count (since we're trying to choose its + * MAC address anyway). Other internal ports don't count because + * we really want a physical MAC if we can get it, and internal + * ports typically have randomly generated MACs. */ if (iface->dp_ifidx == ODPP_LOCAL || cfg_get_bool(0, "iface.%s.internal", iface->name)) { continue; } + + /* Grab MAC. */ - error = netdev_nodev_get_etheraddr(iface->name, iface_ea); + 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) + { - memcpy(ea, iface_ea, ETH_ADDR_LEN); - *devname = iface ? iface->name : NULL; ++ *hw_addr_iface = iface; + } } if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) { memcpy(ea, br->default_ea, ETH_ADDR_LEN); @@@ -2980,9 -2931,8 +3042,9 @@@ port_update_bond_compat(struct port *po if (slave->up) { bond.up = true; } - memcpy(slave->mac, iface->mac, ETH_ADDR_LEN); + netdev_get_etheraddr(iface->netdev, slave->mac); } + proc_net_compat_update_bond(port->name, &bond); free(bond.slaves); } diff --cc vswitchd/ovs-vswitchd.c index 01645adf9,a7b43f7b4..28491fc6c --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@@ -80,13 -81,9 +81,12 @@@ main(int argc, char *argv[] } unixctl_command_register("vswitchd/reload", reload); - cfg_read(); + retval = cfg_read(); + if (retval) { + ovs_fatal(retval, "could not read config file"); + } mgmt_init(); bridge_init(); - port_init(); mgmt_reconfigure(); need_reconfigure = false; diff --cc xenserver/opt_xensource_libexec_interface-reconfigure index 0ae8e70a8,5f1ca8258..98bcf4c3e --- a/xenserver/opt_xensource_libexec_interface-reconfigure +++ b/xenserver/opt_xensource_libexec_interface-reconfigure @@@ -62,8 -62,8 +62,9 @@@ import syslo import traceback import time import re - import pickle +import random + from xml.dom.minidom import getDOMImplementation + from xml.dom.minidom import parse as parseXML output_directory = None @@@ -249,34 -249,212 +250,239 @@@ def check_allowed(pif) def interface_exists(i): return os.path.exists("/sys/class/net/" + i) +def get_netdev_mac(device): + try: + return read_first_line_of_file("/sys/class/net/%s/address" % device) + except: + # Probably no such device. + return None + +def get_netdev_tx_queue_len(device): + try: + return int(read_first_line_of_file("/sys/class/net/%s/tx_queue_len" + % device)) + except: + # Probably no such device. + return None + +def get_netdev_by_mac(mac): + maybe = None + for device in os.listdir("/sys/class/net"): + dev_mac = get_netdev_mac(device) + if dev_mac and mac.lower() == dev_mac.lower(): + if get_netdev_tx_queue_len(device): + return device + if not maybe: + # Probably a datapath internal port. + maybe = device + return maybe + + # + # Helper functions for encoding/decoding database attributes to/from XML. + # + def str_to_xml(xml, parent, tag, val): + e = xml.createElement(tag) + parent.appendChild(e) + v = xml.createTextNode(val) + e.appendChild(v) + def str_from_xml(n): + def getText(nodelist): + rc = "" + for node in nodelist: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc + return getText(n.childNodes).strip() + + + def bool_to_xml(xml, parent, tag, val): + if val: + str_to_xml(xml, parent, tag, "True") + else: + str_to_xml(xml, parent, tag, "False") + def bool_from_xml(n): + s = str_from_xml(n) + if s == "True": + return True + elif s == "False": + return False + else: + raise Error("Unknown boolean value %s" % s); + + def strlist_to_xml(xml, parent, ltag, itag, val): + e = xml.createElement(ltag) + parent.appendChild(e) + for v in val: + c = xml.createElement(itag) + e.appendChild(c) + cv = xml.createTextNode(v) + c.appendChild(cv) + def strlist_from_xml(n, ltag, itag): + ret = [] + for n in n.childNodes: + if n.nodeName == itag: + ret.append(str_from_xml(n)) + return ret + + def otherconfig_to_xml(xml, parent, val, attrs): + otherconfig = xml.createElement("other_config") + parent.appendChild(otherconfig) + for n,v in val.items(): + if not n in attrs: + raise Error("Unknown other-config attribute: %s" % n) + str_to_xml(xml, otherconfig, n, v) + def otherconfig_from_xml(n, attrs): + ret = {} + for n in n.childNodes: + if n.nodeName in attrs: + ret[n.nodeName] = str_from_xml(n) + return ret + + # + # Definitions of the database objects (and their attributes) used by interface-reconfigure. + # + # Each object is defined by a dictionary mapping an attribute name in + # the xapi database to a tuple containing two items: + # - a function which takes this attribute and encodes it as XML. + # - a function which takes XML and decocdes it into a value. + # + # other-config attributes are specified as a simple array of strings + + PIF_XML_TAG = "pif" + VLAN_XML_TAG = "vlan" + BOND_XML_TAG = "bond" + NETWORK_XML_TAG = "network" + + ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ] + + PIF_ATTRS = { 'uuid': (str_to_xml,str_from_xml), + 'management': (bool_to_xml,bool_from_xml), + 'network': (str_to_xml,str_from_xml), + 'device': (str_to_xml,str_from_xml), + 'bond_master_of': (lambda x, p, t, v: strlist_to_xml(x, p, 'bond_master_of', 'slave', v), + lambda n: strlist_from_xml(n, 'bond_master_of', 'slave')), + 'bond_slave_of': (str_to_xml,str_from_xml), + 'VLAN': (str_to_xml,str_from_xml), + 'VLAN_master_of': (str_to_xml,str_from_xml), + 'VLAN_slave_of': (lambda x, p, t, v: strlist_to_xml(x, p, 'VLAN_slave_of', 'master', v), + lambda n: strlist_from_xml(n, 'VLAN_slave_Of', 'master')), + 'ip_configuration_mode': (str_to_xml,str_from_xml), + 'IP': (str_to_xml,str_from_xml), + 'netmask': (str_to_xml,str_from_xml), + 'gateway': (str_to_xml,str_from_xml), + 'DNS': (str_to_xml,str_from_xml), + 'MAC': (str_to_xml,str_from_xml), + 'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, PIF_OTHERCONFIG_ATTRS), + lambda n: otherconfig_from_xml(n, PIF_OTHERCONFIG_ATTRS)), + } + + PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 'static-routes' ] + \ + [ 'bond-%s' % x for x in 'mode', 'miimon', 'downdelay', 'updelay', 'use_carrier' ] + \ + ETHTOOL_OTHERCONFIG_ATTRS + + VLAN_ATTRS = { 'uuid': (str_to_xml,str_from_xml), + 'tagged_PIF': (str_to_xml,str_from_xml), + 'untagged_PIF': (str_to_xml,str_from_xml), + } + + BOND_ATTRS = { 'uuid': (str_to_xml,str_from_xml), + 'master': (str_to_xml,str_from_xml), + 'slaves': (lambda x, p, t, v: strlist_to_xml(x, p, 'slaves', 'slave', v), + lambda n: strlist_from_xml(n, 'slaves', 'slave')), + } + + NETWORK_ATTRS = { 'uuid': (str_to_xml,str_from_xml), + 'bridge': (str_to_xml,str_from_xml), + 'PIFs': (lambda x, p, t, v: strlist_to_xml(x, p, 'PIFs', 'PIF', v), + lambda n: strlist_from_xml(n, 'PIFs', 'PIF')), + 'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, NETWORK_OTHERCONFIG_ATTRS), + lambda n: otherconfig_from_xml(n, NETWORK_OTHERCONFIG_ATTRS)), + } + + NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + ETHTOOL_OTHERCONFIG_ATTRS + class DatabaseCache(object): + def __read_xensource_inventory(self): + filename = "/etc/xensource-inventory" + f = open(filename, "r") + lines = [x.strip("\n") for x in f.readlines()] + f.close() + + defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ] + defs = [ (a, b.strip("'")) for (a,b) in defs ] + + return dict(defs) + def __pif_on_host(self,pif): + return self.__pifs.has_key(pif) + + def __get_pif_records_from_xapi(self, session, host): + self.__pifs = {} + for (p,rec) in session.xenapi.PIF.get_all_records().items(): + if rec['host'] != host: + continue + self.__pifs[p] = {} + for f in PIF_ATTRS: + self.__pifs[p][f] = rec[f] + self.__pifs[p]['other_config'] = {} + for f in PIF_OTHERCONFIG_ATTRS: + if not rec['other_config'].has_key(f): continue + self.__pifs[p]['other_config'][f] = rec['other_config'][f] + + def __get_vlan_records_from_xapi(self, session): + self.__vlans = {} + for v in session.xenapi.VLAN.get_all(): + rec = session.xenapi.VLAN.get_record(v) + if not self.__pif_on_host(rec['untagged_PIF']): + continue + self.__vlans[v] = {} + for f in VLAN_ATTRS: + self.__vlans[v][f] = rec[f] + + def __get_bond_records_from_xapi(self, session): + self.__bonds = {} + for b in session.xenapi.Bond.get_all(): + rec = session.xenapi.Bond.get_record(b) + if not self.__pif_on_host(rec['master']): + continue + self.__bonds[b] = {} + for f in BOND_ATTRS: + self.__bonds[b][f] = rec[f] + + def __get_network_records_from_xapi(self, session): + self.__networks = {} + for n in session.xenapi.network.get_all(): + rec = session.xenapi.network.get_record(n) + self.__networks[n] = {} + for f in NETWORK_ATTRS: + self.__networks[n][f] = rec[f] + self.__networks[n]['other_config'] = {} + for f in NETWORK_OTHERCONFIG_ATTRS: + if not rec['other_config'].has_key(f): continue + self.__networks[n]['other_config'][f] = rec['other_config'][f] + + def __to_xml(self, xml, parent, key, ref, rec, attrs): + """Encode a database object as XML""" + e = xml.createElement(key) + parent.appendChild(e) + if ref: + e.setAttribute('ref', ref) + + for n,v in rec.items(): + if attrs.has_key(n): + h,_ = attrs[n] + h(xml, e, n, v) + else: + raise Error("Unknown attribute %s" % n) + def __from_xml(self, e, attrs): + """Decode a database object from XML""" + ref = e.attributes['ref'].value + rec = {} + for n in e.childNodes: + if n.nodeName in attrs: + _,h = attrs[n.nodeName] + rec[n.nodeName] = h(n) + return (ref,rec) + def __init__(self, session_ref=None, cache_file=None): if session_ref and cache_file: raise Error("can't specify session reference and cache file") @@@ -461,13 -653,12 +681,12 @@@ The ipdev name is the same as the bridg pifrec = db.get_pif_record(pif) return bridge_name(pif) -def physdev_names(pif): - """Return the name(s) of the physical network device(s) associated with pif. -For a VLAN PIF, the physical devices are the VLAN slave's physical devices. -For a bond master PIF, the physical devices are the bond slaves. -For a non-VLAN, non-bond master PIF, the physical device is the PIF itself. +def get_physdev_pifs(pif): + """Return the PIFs for the physical network device(s) associated with pif. +For a VLAN PIF, this is the VLAN slave's physical device PIF. +For a bond master PIF, these are the bond slave PIFs. +For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF. """ - pifrec = db.get_pif_record(pif) if pifrec['VLAN'] != '-1':