From: Ben Pfaff Date: Fri, 23 Oct 2009 00:43:28 +0000 (-0700) Subject: Merge "citrix" into "master". X-Git-Tag: v0.99.0~50 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=3f355f47f8e7343e909ccfa854454d667baf3c38;hp=-c;p=sliver-openvswitch.git Merge "citrix" into "master". This merge took a little bit of care due to two issues: - Crossport of "interface-reconfigure" fixes from master back to citrix that had happened and needed to be canceled out of the merge. - New script "refresh-xs-network-uuids" added on citrix branch that needed to be moved from /root/vswitch/scripts to /usr/share/vswitch/scripts. --- 3f355f47f8e7343e909ccfa854454d667baf3c38 diff --combined acinclude.m4 index 2f38997ff,d5d7c0959..6ba647ab9 --- a/acinclude.m4 +++ b/acinclude.m4 @@@ -14,6 -14,20 +14,6 @@@ # See the License for the specific language governing permissions and # limitations under the License. -dnl Checks for --disable-userspace. -AC_DEFUN([OVS_CHECK_USERSPACE], - [AC_ARG_ENABLE( - [userspace], - [AC_HELP_STRING([--disable-userspace], - [Disable building userspace components.])], - [case "${enableval}" in - (yes) build_userspace=true ;; - (no) build_userspace=false ;; - (*) AC_MSG_ERROR([bad value ${enableval} for --enable-userspace]) ;; - esac], - [build_userspace=true]) - AM_CONDITIONAL([ENABLE_USERSPACE], [$build_userspace])]) - dnl OVS_CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL) dnl dnl Configure linux kernel source tree @@@ -119,6 -133,10 +119,10 @@@ AC_DEFUN([OVS_CHECK_LINUX26_COMPAT], [OVS_DEFINE([HAVE_NLA_NUL_STRING])]) OVS_GREP_IFELSE([$KSRC26/include/linux/err.h], [ERR_CAST], [OVS_DEFINE([HAVE_ERR_CAST])]) + OVS_GREP_IFELSE([$KSRC26/include/net/checksum.h], [csum_unfold], + [OVS_DEFINE([HAVE_CSUM_UNFOLD])]) + OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_cow], + [OVS_DEFINE([HAVE_SKB_COW])]) OVS_CHECK_LOG2_H OVS_CHECK_VETH if cmp -s datapath/linux-2.6/kcompat.h.new \ diff --combined configure.ac index 400ea7869,edfe0f75b..c8eed7c97 --- a/configure.ac +++ b/configure.ac @@@ -12,14 -12,13 +12,14 @@@ # See the License for the specific language governing permissions and # limitations under the License. -AC_PREREQ(2.60) +AC_PREREQ(2.63) - AC_INIT(openvswitch, 0.90.5, ovs-bugs@openvswitch.org) + AC_INIT(openvswitch, 0.90.6, ovs-bugs@openvswitch.org) NX_BUILDNR AC_CONFIG_SRCDIR([datapath/datapath.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_TESTDIR([tests]) AM_INIT_AUTOMAKE AC_PROG_CC @@@ -38,7 -37,7 +38,7 @@@ AC_USE_SYSTEM_EXTENSION AC_C_BIGENDIAN AC_SYS_LARGEFILE -OVS_CHECK_USERSPACE +OVS_CHECK_COVERAGE OVS_CHECK_NDEBUG OVS_CHECK_NETLINK OVS_CHECK_OPENSSL @@@ -46,35 -45,36 +46,35 @@@ OVS_CHECK_LOGDI OVS_CHECK_CURSES OVS_CHECK_LINUX_VT_H OVS_CHECK_PCRE +OVS_CHECK_PYTHON OVS_CHECK_IF_PACKET OVS_CHECK_STRTOK_R -if $build_userspace; then - OVS_CHECK_PKIDIR - OVS_CHECK_RUNDIR - OVS_CHECK_MALLOC_HOOKS - OVS_CHECK_VALGRIND - OVS_CHECK_TTY_LOCK_DIR - OVS_CHECK_SOCKET_LIBS - OVS_CHECK_FAULT_LIBS +OVS_CHECK_PKIDIR +OVS_CHECK_RUNDIR +OVS_CHECK_MALLOC_HOOKS +OVS_CHECK_VALGRIND +OVS_CHECK_TTY_LOCK_DIR +OVS_CHECK_SOCKET_LIBS +OVS_CHECK_FAULT_LIBS - AC_CHECK_FUNCS([strsignal]) +AC_CHECK_FUNCS([strsignal]) - OVS_ENABLE_OPTION([-Wall]) - OVS_ENABLE_OPTION([-Wno-sign-compare]) - OVS_ENABLE_OPTION([-Wpointer-arith]) - OVS_ENABLE_OPTION([-Wdeclaration-after-statement]) - OVS_ENABLE_OPTION([-Wformat-security]) - OVS_ENABLE_OPTION([-Wswitch-enum]) - OVS_ENABLE_OPTION([-Wunused-parameter]) - OVS_ENABLE_OPTION([-Wstrict-aliasing]) - OVS_ENABLE_OPTION([-Wbad-function-cast]) - OVS_ENABLE_OPTION([-Wcast-align]) - OVS_ENABLE_OPTION([-Wstrict-prototypes]) - OVS_ENABLE_OPTION([-Wold-style-definition]) - OVS_ENABLE_OPTION([-Wmissing-prototypes]) - OVS_ENABLE_OPTION([-Wmissing-field-initializers]) - OVS_ENABLE_OPTION([-Wno-override-init]) -fi +OVS_ENABLE_OPTION([-Wall]) +OVS_ENABLE_OPTION([-Wno-sign-compare]) +OVS_ENABLE_OPTION([-Wpointer-arith]) +OVS_ENABLE_OPTION([-Wdeclaration-after-statement]) +OVS_ENABLE_OPTION([-Wformat-security]) +OVS_ENABLE_OPTION([-Wswitch-enum]) +OVS_ENABLE_OPTION([-Wunused-parameter]) +OVS_ENABLE_OPTION([-Wstrict-aliasing]) +OVS_ENABLE_OPTION([-Wbad-function-cast]) +OVS_ENABLE_OPTION([-Wcast-align]) +OVS_ENABLE_OPTION([-Wstrict-prototypes]) +OVS_ENABLE_OPTION([-Wold-style-definition]) +OVS_ENABLE_OPTION([-Wmissing-prototypes]) +OVS_ENABLE_OPTION([-Wmissing-field-initializers]) +OVS_ENABLE_OPTION([-Wno-override-init]) AC_ARG_VAR(KARCH, [Kernel Architecture String]) AC_SUBST(KARCH) @@@ -84,7 -84,6 +84,7 @@@ AC_CONFIG_FILES([Makefil datapath/Makefile datapath/linux-2.6/Kbuild datapath/linux-2.6/Makefile -datapath/linux-2.6/Makefile.main]) +datapath/linux-2.6/Makefile.main +tests/atlocal]) AC_OUTPUT diff --combined datapath/datapath.c index b8ef104aa,aea8cc95c..1ae1d771a --- a/datapath/datapath.c +++ b/datapath/datapath.c @@@ -56,7 -56,9 +56,7 @@@ int (*dp_ioctl_hook)(struct net_device EXPORT_SYMBOL(dp_ioctl_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 - * exclusion too. + * by dp_mutex. * * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL * lock first. @@@ -223,7 -225,9 +223,7 @@@ static int create_dp(int dp_idx, const /* Initialize kobject for bridge. This will be added as * /sys/class/net//brif later, if sysfs is enabled. */ - kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); /* "brif" */ dp->ifobj.kset = NULL; - dp->ifobj.parent = NULL; kobject_init(&dp->ifobj, &dp_ktype); /* Allocate table. */ @@@ -253,7 -257,9 +253,7 @@@ mutex_unlock(&dp_mutex); rtnl_unlock(); -#ifdef SUPPORT_SYSFS dp_sysfs_add_dp(dp); -#endif return 0; @@@ -281,7 -287,9 +281,7 @@@ static void do_destroy_dp(struct datapa if (p->port_no != ODPP_LOCAL) dp_del_port(p); -#ifdef SUPPORT_SYSFS dp_sysfs_del_dp(dp); -#endif rcu_assign_pointer(dps[dp->dp_idx], NULL); @@@ -326,7 -334,7 +326,7 @@@ static void release_nbp(struct kobject } struct kobj_type brport_ktype = { -#ifdef SUPPORT_SYSFS +#ifdef CONFIG_SYSFS .sysfs_ops = &brport_sysfs_ops, #endif .release = release_nbp @@@ -363,7 -371,9 +363,7 @@@ static int new_nbp(struct datapath *dp /* 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); @@@ -383,6 -393,11 +383,6 @@@ static int add_port(int dp_idx, struct if (copy_from_user(&port, portp, sizeof port)) goto out; port.devname[IFNAMSIZ - 1] = '\0'; - port_no = port.port; - - err = -EINVAL; - if (port_no < 0 || port_no >= DP_MAX_PORTS) - goto out; rtnl_lock(); dp = get_dp_locked(dp_idx); @@@ -390,13 -405,10 +390,13 @@@ if (!dp) goto out_unlock_rtnl; - err = -EEXIST; - if (dp->ports[port_no]) - goto out_unlock_dp; + for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) + if (!dp->ports[port_no]) + goto got_port_no; + err = -EFBIG; + goto out_unlock_dp; +got_port_no: if (!(port.flags & ODP_PORT_INTERNAL)) { err = -ENODEV; dev = dev_get_by_name(&init_net, port.devname); @@@ -419,9 -431,9 +419,9 @@@ if (err) goto out_put; -#ifdef SUPPORT_SYSFS dp_sysfs_add_if(dp->ports[port_no]); -#endif + + err = __put_user(port_no, &port.port); out_put: dev_put(dev); @@@ -437,8 -449,10 +437,8 @@@ int dp_del_port(struct net_bridge_port { ASSERT_RTNL(); -#ifdef SUPPORT_SYSFS if (p->port_no != ODPP_LOCAL) dp_sysfs_del_if(p); -#endif dp_ifinfo_notify(RTM_DELLINK, p); p->dp->n_ports--; @@@ -574,7 -588,7 +574,7 @@@ static int dp_frame_hook(struct net_bri #error #endif -#ifdef CONFIG_XEN +#if defined(CONFIG_XEN) && LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) /* This code is copied verbatim from net/dev/core.c in Xen's * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644. We can't call those functions * directly because they aren't exported. */ @@@ -590,7 -604,7 +590,7 @@@ static int skb_pull_up_to(struct sk_buf } } -int skb_checksum_setup(struct sk_buff *skb) +int vswitch_skb_checksum_setup(struct sk_buff *skb) { if (skb->proto_csum_blank) { if (skb->protocol != htons(ETH_P_IP)) @@@ -621,97 -635,15 +621,97 @@@ out: return -EPROTO; } +#else +int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; } +#endif /* CONFIG_XEN && linux == 2.6.18 */ + +/* Append each packet in 'skb' list to 'queue'. There will be only one packet + * unless we broke up a GSO packet. */ +static int +queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue, + int queue_no, u32 arg) +{ + struct sk_buff *nskb; + int port_no; + int err; + + port_no = ODPP_LOCAL; + if (skb->dev) { + if (skb->dev->br_port) + port_no = skb->dev->br_port->port_no; + else if (is_dp_dev(skb->dev)) + port_no = dp_dev_priv(skb->dev)->port_no; + } + + do { + struct odp_msg *header; + + nskb = skb->next; + skb->next = NULL; + + /* If a checksum-deferred packet is forwarded to the + * controller, correct the pointers and checksum. This happens + * on a regular basis only on Xen, on which VMs can pass up + * packets that do not have their checksum computed. + */ + err = vswitch_skb_checksum_setup(skb); + if (err) + goto err_kfree_skbs; +#ifndef CHECKSUM_HW + if (skb->ip_summed == CHECKSUM_PARTIAL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + /* Until 2.6.22, the start of the transport header was + * also the start of data to be checksummed. Linux + * 2.6.22 introduced the csum_start field for this + * purpose, but we should point the transport header to + * it anyway for backward compatibility, as + * dev_queue_xmit() does even in 2.6.28. */ + skb_set_transport_header(skb, skb->csum_start - + skb_headroom(skb)); +#endif + err = skb_checksum_help(skb); + if (err) + goto err_kfree_skbs; + } +#else + if (skb->ip_summed == CHECKSUM_HW) { + err = skb_checksum_help(skb, 0); + if (err) + goto err_kfree_skbs; + } #endif + err = skb_cow(skb, sizeof *header); + if (err) + goto err_kfree_skbs; + + header = (struct odp_msg*)__skb_push(skb, sizeof *header); + header->type = queue_no; + header->length = skb->len; + header->port = port_no; + header->reserved = 0; + header->arg = arg; + skb_queue_tail(queue, skb); + + skb = nskb; + } while (skb); + return 0; + +err_kfree_skbs: + kfree_skb(skb); + while ((skb = nskb) != NULL) { + nskb = skb->next; + kfree_skb(skb); + } + return err; +} + int dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, u32 arg) { struct dp_stats_percpu *stats; struct sk_buff_head *queue; - int port_no; int err; WARN_ON_ONCE(skb_shared(skb)); @@@ -722,6 -654,40 +722,6 @@@ if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN) goto err_kfree_skb; - /* If a checksum-deferred packet is forwarded to the controller, - * correct the pointers and checksum. This happens on a regular basis - * only on Xen (the CHECKSUM_HW case), on which VMs can pass up packets - * that do not have their checksum computed. We also implement it for - * the non-Xen case, but it is difficult to trigger or test this case - * there, hence the WARN_ON_ONCE(). - */ - err = skb_checksum_setup(skb); - if (err) - goto err_kfree_skb; -#ifndef CHECKSUM_HW - if (skb->ip_summed == CHECKSUM_PARTIAL) { - WARN_ON_ONCE(1); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) - /* Until 2.6.22, the start of the transport header was also the - * start of data to be checksummed. Linux 2.6.22 introduced - * the csum_start field for this purpose, but we should point - * the transport header to it anyway for backward - * compatibility, as dev_queue_xmit() does even in 2.6.28. */ - skb_set_transport_header(skb, skb->csum_start - - skb_headroom(skb)); -#endif - err = skb_checksum_help(skb); - if (err) - goto err_kfree_skb; - } -#else - if (skb->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(skb, 0); - if (err) - goto err_kfree_skb; - } -#endif - /* Break apart GSO packets into their component pieces. Otherwise * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */ if (skb_is_gso(skb)) { @@@ -739,9 -705,45 +739,9 @@@ } } - /* Figure out port number. */ - port_no = ODPP_LOCAL; - if (skb->dev) { - if (skb->dev->br_port) - port_no = skb->dev->br_port->port_no; - else if (is_dp_dev(skb->dev)) - port_no = dp_dev_priv(skb->dev)->port_no; - } - - /* Append each packet to queue. There will be only one packet unless - * we broke up a GSO packet above. */ - do { - struct odp_msg *header; - struct sk_buff *nskb = skb->next; - skb->next = NULL; - - err = skb_cow(skb, sizeof *header); - if (err) { - while (nskb) { - kfree_skb(skb); - skb = nskb; - nskb = skb->next; - } - goto err_kfree_skb; - } - - header = (struct odp_msg*)__skb_push(skb, sizeof *header); - header->type = queue_no; - header->length = skb->len; - header->port = port_no; - header->reserved = 0; - header->arg = arg; - skb_queue_tail(queue, skb); - - skb = nskb; - } while (skb); - + err = queue_control_packets(skb, queue, queue_no, arg); wake_up_interruptible(&dp->waitqueue); - return 0; + return err; err_kfree_skb: kfree_skb(skb); @@@ -782,7 -784,8 +782,8 @@@ static int validate_actions(const struc break; case ODPAT_SET_VLAN_PCP: - if (a->vlan_pcp.vlan_pcp & ~VLAN_PCP_MASK) + if (a->vlan_pcp.vlan_pcp + & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) return -EINVAL; break; @@@ -835,7 -838,6 +836,7 @@@ static void get_stats(struct sw_flow *f stats->n_bytes = flow->byte_count; stats->ip_tos = flow->ip_tos; stats->tcp_flags = flow->tcp_flags; + stats->error = 0; } static void clear_stats(struct sw_flow *flow) @@@ -963,6 -965,8 +964,6 @@@ static int put_actions(const struct sw_ if (!n_actions) return 0; - if (ufp->n_actions > INT_MAX / sizeof(union odp_action)) - return -EINVAL; sf_acts = rcu_dereference(flow->sf_acts); if (__put_user(sf_acts->n_actions, &ufp->n_actions) || @@@ -988,7 -992,9 +989,7 @@@ static int answer_query(struct sw_flow return put_actions(flow, ufp); } -static int del_or_query_flow(struct datapath *dp, - struct odp_flow __user *ufp, - unsigned int cmd) +static int del_flow(struct datapath *dp, struct odp_flow __user *ufp) { struct dp_table *table = rcu_dereference(dp->table); struct odp_flow uf; @@@ -1005,24 -1011,29 +1006,24 @@@ if (!flow) goto error; - if (cmd == ODP_FLOW_DEL) { - /* XXX redundant lookup */ - error = dp_table_delete(table, flow); - if (error) - goto error; + /* XXX redundant lookup */ + error = dp_table_delete(table, flow); + if (error) + goto error; - /* XXX These statistics might lose a few packets, since other - * CPUs can be using this flow. We used to synchronize_rcu() - * to make sure that we get completely accurate stats, but that - * blows our performance, badly. */ - dp->n_flows--; - error = answer_query(flow, ufp); - flow_deferred_free(flow); - } else { - error = answer_query(flow, ufp); - } + /* XXX These statistics might lose a few packets, since other CPUs can + * be using this flow. We used to synchronize_rcu() to make sure that + * we get completely accurate stats, but that blows our performance, + * badly. */ + dp->n_flows--; + error = answer_query(flow, ufp); + flow_deferred_free(flow); error: return error; } -static int query_multiple_flows(struct datapath *dp, - const struct odp_flowvec *flowvec) +static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec) { struct dp_table *table = rcu_dereference(dp->table); int i; @@@ -1038,7 -1049,7 +1039,7 @@@ flow = dp_table_lookup(table, &uf.key); if (!flow) - error = __clear_user(&ufp->stats, sizeof ufp->stats); + error = __put_user(ENOENT, &ufp->stats.error); else error = answer_query(flow, ufp); if (error) @@@ -1183,7 -1194,8 +1184,7 @@@ error return err; } -static int -get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) +static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) { struct odp_stats stats; int i; @@@ -1298,7 -1310,7 +1299,7 @@@ list_ports(struct datapath *dp, struct break; } } - return put_user(idx, &pvp->n_ports); + return put_user(dp->n_ports, &pvp->n_ports); } /* RCU callback for freeing a dp_port_group */ @@@ -1371,6 -1383,16 +1372,16 @@@ get_port_group(struct datapath *dp, str return 0; } + static int get_listen_mask(const struct file *f) + { + return (long)f->private_data; + } + + static void set_listen_mask(struct file *f, int listen_mask) + { + f->private_data = (void*)(long)listen_mask; + } + static long openvswitch_ioctl(struct file *f, unsigned int cmd, unsigned long argp) { @@@ -1382,28 -1404,24 +1393,28 @@@ /* Handle commands with special locking requirements up front. */ switch (cmd) { case ODP_DP_CREATE: - return create_dp(dp_idx, (char __user *)argp); + err = create_dp(dp_idx, (char __user *)argp); + goto exit; case ODP_DP_DESTROY: - return destroy_dp(dp_idx); + err = destroy_dp(dp_idx); + goto exit; case ODP_PORT_ADD: - return add_port(dp_idx, (struct odp_port __user *)argp); + err = add_port(dp_idx, (struct odp_port __user *)argp); + goto exit; case ODP_PORT_DEL: err = get_user(port_no, (int __user *)argp); - if (err) - break; - return del_port(dp_idx, port_no); + if (!err) + err = del_port(dp_idx, port_no); + goto exit; } dp = get_dp_locked(dp_idx); + err = -ENODEV; if (!dp) - return -ENODEV; + goto exit; switch (cmd) { case ODP_DP_STATS: @@@ -1426,7 -1444,7 +1437,7 @@@ break; case ODP_GET_LISTEN_MASK: - err = put_user((int)f->private_data, (int __user *)argp); + err = put_user(get_listen_mask(f), (int __user *)argp); break; case ODP_SET_LISTEN_MASK: @@@ -1437,7 -1455,7 +1448,7 @@@ if (listeners & ~ODPL_ALL) break; err = 0; - f->private_data = (void*)listeners; + set_listen_mask(f, listeners); break; case ODP_PORT_QUERY: @@@ -1465,11 -1483,13 +1476,11 @@@ break; case ODP_FLOW_DEL: - case ODP_FLOW_GET: - err = del_or_query_flow(dp, (struct odp_flow __user *)argp, - cmd); + err = del_flow(dp, (struct odp_flow __user *)argp); break; - case ODP_FLOW_GET_MULTIPLE: - err = do_flowvec_ioctl(dp, argp, query_multiple_flows); + case ODP_FLOW_GET: + err = do_flowvec_ioctl(dp, argp, query_flows); break; case ODP_FLOW_LIST: @@@ -1485,7 -1505,6 +1496,7 @@@ break; } mutex_unlock(&dp->mutex); +exit: return err; } @@@ -1503,7 -1522,7 +1514,7 @@@ ssize_t openvswitch_read(struct file *f loff_t *ppos) { /* XXX is there sufficient synchronization here? */ - int listeners = (int) f->private_data; + int listeners = get_listen_mask(f); int dp_idx = iminor(f->f_dentry->d_inode); struct datapath *dp = get_dp(dp_idx); struct sk_buff *skb; @@@ -1543,7 -1562,7 +1554,7 @@@ } } success: - copy_bytes = min(skb->len, nbytes); + copy_bytes = min_t(size_t, skb->len, nbytes); iov.iov_base = buf; iov.iov_len = copy_bytes; retval = skb_copy_datagram_iovec(skb, 0, &iov, iov.iov_len); @@@ -1565,7 -1584,7 +1576,7 @@@ static unsigned int openvswitch_poll(st if (dp) { mask = 0; poll_wait(file, &dp->waitqueue, wait); - if (dp_has_packet_of_interest(dp, (int)file->private_data)) + if (dp_has_packet_of_interest(dp, get_listen_mask(file))) mask |= POLLIN | POLLRDNORM; } else { mask = POLLIN | POLLRDNORM | POLLHUP; @@@ -1582,8 -1601,6 +1593,8 @@@ struct file_operations openvswitch_fop }; static int major; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) static struct llc_sap *dp_stp_sap; static int dp_stp_rcv(struct sk_buff *skb, struct net_device *dev, @@@ -1596,8 -1613,12 +1607,8 @@@ return 0; } -static int __init dp_init(void) +static int dp_avoid_bridge_init(void) { - int err; - - printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR); - /* Register to receive STP packets because the bridge module also * attempts to do so. Since there can only be a single listener for a * given protocol, this provides mutual exclusion against the bridge @@@ -1608,43 -1629,6 +1619,43 @@@ printk(KERN_ERR "openvswitch: can't register sap for STP (probably the bridge module is loaded)\n"); return -EADDRINUSE; } + return 0; +} + +static void dp_avoid_bridge_exit(void) +{ + llc_sap_put(dp_stp_sap); +} +#else /* Linux 2.6.27 or later. */ +static int dp_avoid_bridge_init(void) +{ + /* Linux 2.6.27 introduces a way for multiple clients to register for + * STP packets, which interferes with what we try to do above. + * Instead, just check whether there's a bridge hook defined. This is + * not as safe--the bridge module is willing to load over the top of + * us--but it provides a little bit of protection. */ + if (br_handle_frame_hook) { + printk(KERN_ERR "openvswitch: bridge module is loaded, cannot load over it\n"); + return -EADDRINUSE; + } + return 0; +} + +static void dp_avoid_bridge_exit(void) +{ + /* Nothing to do. */ +} +#endif /* Linux 2.6.27 or later */ + +static int __init dp_init(void) +{ + int err; + + printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR); + + err = dp_avoid_bridge_init(); + if (err) + return err; err = flow_init(); if (err) @@@ -1679,7 -1663,7 +1690,7 @@@ static void dp_cleanup(void unregister_netdevice_notifier(&dp_device_notifier); flow_exit(); br_handle_frame_hook = NULL; - llc_sap_put(dp_stp_sap); + dp_avoid_bridge_exit(); } module_init(dp_init); diff --combined datapath/datapath.h index d28250a12,88bdbc657..9b4c4386b --- a/datapath/datapath.h +++ b/datapath/datapath.h @@@ -14,16 -14,17 +14,17 @@@ #include #include #include -#include #include #include #include +#include #include "flow.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. */ #define VLAN_PCP_MASK 0xe000 + #define VLAN_PCP_SHIFT 13 #define DP_MAX_PORTS 1024 #define DP_MAX_GROUPS 16 @@@ -167,6 -168,4 +168,6 @@@ static inline int skb_checksum_setup(st } #endif +int vswitch_skb_checksum_setup(struct sk_buff *skb); + #endif /* datapath.h */ diff --combined datapath/dp_dev.c index 008f3f6ce,5417114fd..284a6b520 --- a/datapath/dp_dev.c +++ b/datapath/dp_dev.c @@@ -118,7 -118,7 +118,7 @@@ static void dp_getinfo(struct net_devic { struct dp_dev *dp_dev = dp_dev_priv(netdev); strcpy(info->driver, "openvswitch"); - sprintf(info->bus_info, "%d", dp_dev->dp->dp_idx); + sprintf(info->bus_info, "%d.%d", dp_dev->dp->dp_idx, dp_dev->port_no); } static struct ethtool_ops dp_ethtool_ops = { @@@ -157,22 -157,47 +157,47 @@@ static void dp_dev_free(struct net_devi free_netdev(netdev); } + static int dp_dev_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { + if (dp_ioctl_hook) + return dp_ioctl_hook(dev, ifr, cmd); + return -EOPNOTSUPP; + } + + #ifdef HAVE_NET_DEVICE_OPS + static const struct net_device_ops dp_dev_netdev_ops = { + .ndo_init = dp_dev_init, + .ndo_open = dp_dev_open, + .ndo_stop = dp_dev_stop, + .ndo_start_xmit = dp_dev_xmit, + .ndo_set_mac_address = dp_dev_mac_addr, + .ndo_do_ioctl = dp_dev_do_ioctl, + .ndo_change_mtu = dp_dev_change_mtu, + .ndo_get_stats = dp_dev_get_stats, + }; + #endif + static void do_setup(struct net_device *netdev) { ether_setup(netdev); - netdev->do_ioctl = dp_ioctl_hook; + #ifdef HAVE_NET_DEVICE_OPS + netdev->netdev_ops = &dp_dev_netdev_ops; + #else + netdev->do_ioctl = dp_dev_do_ioctl; netdev->get_stats = dp_dev_get_stats; netdev->hard_start_xmit = dp_dev_xmit; netdev->open = dp_dev_open; - SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops); 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; + #endif + netdev->destructor = dp_dev_free; + SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops); + netdev->tx_queue_len = 0; netdev->flags = IFF_BROADCAST | IFF_MULTICAST; netdev->features = NETIF_F_LLTX; /* XXX other features? */ @@@ -233,5 -258,9 +258,9 @@@ void dp_dev_destroy(struct net_device * int is_dp_dev(struct net_device *netdev) { + #ifdef HAVE_NET_DEVICE_OPS + return netdev->netdev_ops == &dp_dev_netdev_ops; + #else return netdev->open == dp_dev_open; + #endif } diff --combined ofproto/ofproto.c index f31794f9a,94c4bfe3f..eb8a7a911 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@@ -135,7 -135,7 +135,7 @@@ rule_is_hidden(const struct rule *rule return true; } - /* Rules with priority higher than UINT16_MAX are set up by secchan itself + /* Rules with priority higher than UINT16_MAX are set up by ofproto itself * (e.g. by in-band control) and are intentionally hidden from the * controller. */ if (rule->cr.priority > UINT16_MAX) { @@@ -194,8 -194,8 +194,8 @@@ struct ofproto char *serial; /* Serial number. */ /* Datapath. */ - struct dpif dpif; - struct dpifmon *dpifmon; + struct dpif *dpif; + struct netdev_monitor *netdev_monitor; struct port_array ports; /* Index is ODP port nr; ofport->opp.port_no is * OFP port nr. */ struct shash port_by_name; @@@ -237,7 -237,7 +237,7 @@@ static struct vlog_rate_limit rl = VLOG static const struct ofhooks default_ofhooks; -static uint64_t pick_datapath_id(struct dpif *, uint64_t fallback_dpid); +static uint64_t pick_datapath_id(const struct ofproto *); static uint64_t pick_fallback_dpid(void); static void send_packet_in_miss(struct ofpbuf *, void *ofproto); static void send_packet_in_action(struct ofpbuf *, void *ofproto); @@@ -261,9 -261,10 +261,9 @@@ in ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, struct ofproto **ofprotop) { - struct dpifmon *dpifmon; struct odp_stats stats; struct ofproto *p; - struct dpif dpif; + struct dpif *dpif; int error; *ofprotop = NULL; @@@ -274,27 -275,37 +274,27 @@@ VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error)); return error; } - error = dpif_get_dp_stats(&dpif, &stats); + error = dpif_get_dp_stats(dpif, &stats); if (error) { VLOG_ERR("failed to obtain stats for datapath %s: %s", datapath, strerror(error)); - dpif_close(&dpif); + dpif_close(dpif); return error; } - error = dpif_set_listen_mask(&dpif, ODPL_MISS | ODPL_ACTION); + error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION); if (error) { VLOG_ERR("failed to listen on datapath %s: %s", datapath, strerror(error)); - dpif_close(&dpif); - return error; - } - dpif_flow_flush(&dpif); - dpif_purge(&dpif); - - /* Start monitoring datapath ports for status changes. */ - error = dpifmon_create(datapath, &dpifmon); - if (error) { - VLOG_ERR("failed to starting monitoring datapath %s: %s", - datapath, strerror(error)); - dpif_close(&dpif); + dpif_close(dpif); return error; } + dpif_flow_flush(dpif); + dpif_recv_purge(dpif); /* Initialize settings. */ p = xcalloc(1, sizeof *p); p->fallback_dpid = pick_fallback_dpid(); - p->datapath_id = pick_datapath_id(&dpif, p->fallback_dpid); - VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id); + p->datapath_id = p->fallback_dpid; p->manufacturer = xstrdup("Nicira Networks, Inc."); p->hardware = xstrdup("Reference Implementation"); p->software = xstrdup(VERSION BUILDNR); @@@ -302,7 -313,7 +302,7 @@@ /* Initialize datapath. */ p->dpif = dpif; - p->dpifmon = dpifmon; + p->netdev_monitor = netdev_monitor_create(); port_array_init(&p->ports); shash_init(&p->port_by_name); p->max_ports = stats.max_ports; @@@ -354,10 -365,6 +354,10 @@@ return error; } + /* Pick final datapath ID. */ + p->datapath_id = pick_datapath_id(p); + VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id); + *ofprotop = p; return 0; } @@@ -366,7 -373,9 +366,7 @@@ voi ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id) { uint64_t old_dpid = p->datapath_id; - p->datapath_id = (datapath_id - ? datapath_id - : pick_datapath_id(&p->dpif, p->fallback_dpid)); + p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p); if (p->datapath_id != old_dpid) { VLOG_INFO("datapath ID changed to %012"PRIx64, p->datapath_id); rconn_reconnect(p->controller->rconn); @@@ -424,8 -433,9 +424,8 @@@ ofproto_set_in_band(struct ofproto *p, { if (in_band != (p->in_band != NULL)) { if (in_band) { - in_band_create(p, &p->dpif, p->switch_status, - p->controller->rconn, &p->in_band); - return 0; + return in_band_create(p, p->dpif, p->switch_status, + p->controller->rconn, &p->in_band); } else { ofproto_set_discovery(p, false, NULL, true); in_band_destroy(p->in_band); @@@ -447,7 -457,7 +447,7 @@@ ofproto_set_discovery(struct ofproto *p return error; } error = discovery_create(re, update_resolv_conf, - &p->dpif, p->switch_status, + p->dpif, p->switch_status, &p->discovery); if (error) { return error; @@@ -704,8 -714,8 +704,8 @@@ ofproto_destroy(struct ofproto *p ofconn_destroy(ofconn, p); } - dpif_close(&p->dpif); - dpifmon_destroy(p->dpifmon); + dpif_close(p->dpif); + netdev_monitor_destroy(p->netdev_monitor); PORT_ARRAY_FOR_EACH (ofport, &p->ports, port_no) { ofport_free(ofport); } @@@ -747,17 -757,6 +747,17 @@@ ofproto_run(struct ofproto *p return error; } +static void +process_port_change(struct ofproto *ofproto, int error, char *devname) +{ + if (error == ENOBUFS) { + reinit_ports(ofproto); + } else if (!error) { + update_port(ofproto, devname); + free(devname); + } +} + int ofproto_run1(struct ofproto *p) { @@@ -770,15 -769,15 +770,15 @@@ struct ofpbuf *buf; int error; - error = dpif_recv(&p->dpif, &buf); + error = dpif_recv(p->dpif, &buf); if (error) { if (error == ENODEV) { /* Someone destroyed the datapath behind our back. The caller * better destroy us and give up, because we're just going to * spin from here on out. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_ERR_RL(&rl, "dp%u: datapath was destroyed externally", - dpif_id(&p->dpif)); + VLOG_ERR_RL(&rl, "%s: datapath was destroyed externally", + dpif_name(p->dpif)); return ENODEV; } break; @@@ -787,12 -786,13 +787,12 @@@ handle_odp_msg(p, buf); } - while ((error = dpifmon_poll(p->dpifmon, &devname)) != EAGAIN) { - if (error == ENOBUFS) { - reinit_ports(p); - } else if (!error) { - update_port(p, devname); - free(devname); - } + while ((error = dpif_port_poll(p->dpif, &devname)) != EAGAIN) { + process_port_change(p, error, devname); + } + while ((error = netdev_monitor_poll(p->netdev_monitor, + &devname)) != EAGAIN) { + process_port_change(p, error, devname); } if (p->in_band) { @@@ -907,9 -907,8 +907,9 @@@ ofproto_wait(struct ofproto *p struct ofconn *ofconn; size_t i; - dpif_recv_wait(&p->dpif); - dpifmon_wait(p->dpifmon); + dpif_recv_wait(p->dpif); + dpif_port_poll_wait(p->dpif); + netdev_monitor_poll_wait(p->netdev_monitor); LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) { ofconn_wait(ofconn); } @@@ -979,7 -978,7 +979,7 @@@ ofproto_send_packet(struct ofproto *p, /* XXX Should we translate the dpif_execute() errno value into an OpenFlow * error code? */ - dpif_execute(&p->dpif, flow->in_port, odp_actions.actions, + dpif_execute(p->dpif, flow->in_port, odp_actions.actions, odp_actions.n_actions, packet); return 0; } @@@ -1031,7 -1030,7 +1031,7 @@@ ofproto_flush_flows(struct ofproto *ofp { COVERAGE_INC(ofproto_flush); classifier_for_each(&ofproto->cls, CLS_INC_ALL, destroy_rule, ofproto); - dpif_flow_flush(&ofproto->dpif); + dpif_flow_flush(ofproto->dpif); if (ofproto->in_band) { in_band_flushed(ofproto->in_band); } @@@ -1054,7 -1053,7 +1054,7 @@@ reinit_ports(struct ofproto *p PORT_ARRAY_FOR_EACH (ofport, &p->ports, port_no) { svec_add (&devnames, (char *) ofport->opp.name); } - dpif_port_list(&p->dpif, &odp_ports, &n_odp_ports); + dpif_port_list(p->dpif, &odp_ports, &n_odp_ports); for (i = 0; i < n_odp_ports; i++) { svec_add (&devnames, odp_ports[i].devname); } @@@ -1084,7 -1083,7 +1084,7 @@@ refresh_port_group(struct ofproto *p, u ports[n_ports++] = port_no; } } - dpif_port_group_set(&p->dpif, group, ports, n_ports); + dpif_port_group_set(p->dpif, group, ports, n_ports); free(ports); } @@@ -1116,7 -1115,7 +1116,7 @@@ make_ofport(const struct odp_port *odp_ ofport = xmalloc(sizeof *ofport); ofport->netdev = netdev; ofport->opp.port_no = odp_port_to_ofp_port(odp_port->port); - memcpy(ofport->opp.hw_addr, netdev_get_etheraddr(netdev), ETH_ALEN); + netdev_get_etheraddr(netdev, ofport->opp.hw_addr); memcpy(ofport->opp.name, odp_port->devname, MIN(sizeof ofport->opp.name, sizeof odp_port->devname)); ofport->opp.name[sizeof ofport->opp.name - 1] = '\0'; @@@ -1191,7 -1190,6 +1191,7 @@@ send_port_status(struct ofproto *p, con static void ofport_install(struct ofproto *p, struct ofport *ofport) { + netdev_monitor_add(p->netdev_monitor, ofport->netdev); port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no), ofport); shash_add(&p->port_by_name, (char *) ofport->opp.name, ofport); @@@ -1200,7 -1198,6 +1200,7 @@@ static void ofport_remove(struct ofproto *p, struct ofport *ofport) { + netdev_monitor_remove(p->netdev_monitor, ofport->netdev); port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no), NULL); shash_delete(&p->port_by_name, shash_find(&p->port_by_name, (char *) ofport->opp.name)); @@@ -1226,7 -1223,7 +1226,7 @@@ update_port(struct ofproto *p, const ch COVERAGE_INC(ofproto_update_port); /* 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); /* Find the old ofport. */ old_ofport = shash_find_data(&p->port_by_name, devname); @@@ -1295,7 -1292,7 +1295,7 @@@ init_ports(struct ofproto *p size_t i; int error; - error = dpif_port_list(&p->dpif, &ports, &n_ports); + error = dpif_port_list(p->dpif, &ports, &n_ports); if (error) { return error; } @@@ -1500,7 -1497,7 +1500,7 @@@ rule_execute(struct ofproto *ofproto, s } /* Execute the ODP actions. */ - if (!dpif_execute(&ofproto->dpif, flow->in_port, + if (!dpif_execute(ofproto->dpif, flow->in_port, actions, n_actions, packet)) { struct odp_flow_stats stats; flow_extract_stats(flow, packet, &stats); @@@ -1609,7 -1606,7 +1609,7 @@@ do_put_flow(struct ofproto *ofproto, st put->flow.actions = rule->odp_actions; put->flow.n_actions = rule->n_odp_actions; put->flags = flags; - return dpif_flow_put(&ofproto->dpif, put); + return dpif_flow_put(ofproto->dpif, put); } static void @@@ -1690,7 -1687,7 +1690,7 @@@ rule_uninstall(struct ofproto *p, struc odp_flow.key = rule->cr.flow; odp_flow.actions = NULL; odp_flow.n_actions = 0; - if (!dpif_flow_del(&p->dpif, &odp_flow)) { + if (!dpif_flow_del(p->dpif, &odp_flow)) { update_stats(rule, &odp_flow.stats); } rule->installed = false; @@@ -1838,7 -1835,7 +1838,7 @@@ handle_get_config_request(struct ofprot bool drop_frags; /* Figure out flags. */ - dpif_get_drop_frags(&p->dpif, &drop_frags); + dpif_get_drop_frags(p->dpif, &drop_frags); flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL; if (ofconn->send_flow_exp) { flags |= OFPC_SEND_FLOW_EXP; @@@ -1871,10 -1868,10 +1871,10 @@@ handle_set_config(struct ofproto *p, st if (ofconn == p->controller) { switch (flags & OFPC_FRAG_MASK) { case OFPC_FRAG_NORMAL: - dpif_set_drop_frags(&p->dpif, false); + dpif_set_drop_frags(p->dpif, false); break; case OFPC_FRAG_DROP: - dpif_set_drop_frags(&p->dpif, true); + dpif_set_drop_frags(p->dpif, true); break; default: VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")", @@@ -2198,7 -2195,7 +2198,7 @@@ handle_packet_out(struct ofproto *p, st return error; } - dpif_execute(&p->dpif, flow.in_port, actions.actions, actions.n_actions, + dpif_execute(p->dpif, flow.in_port, actions.actions, actions.n_actions, &payload); ofpbuf_delete(buffer); @@@ -2341,7 -2338,7 +2341,7 @@@ handle_table_stats_request(struct ofpro n_wild = classifier_count(&p->cls) - classifier_count_exact(&p->cls); /* Hash table. */ - dpif_get_dp_stats(&p->dpif, &dpstats); + dpif_get_dp_stats(p->dpif, &dpstats); ots = append_stats_reply(sizeof *ots, ofconn, &msg); memset(ots, 0, sizeof *ots); ots->table_id = TABLEID_HASH; @@@ -2423,20 -2420,23 +2423,25 @@@ query_stats(struct ofproto *p, struct r struct odp_flow *odp_flows; size_t n_odp_flows; + packet_count = rule->packet_count; + byte_count = rule->byte_count; + n_odp_flows = rule->cr.wc.wildcards ? list_size(&rule->list) : 1; odp_flows = xcalloc(1, n_odp_flows * sizeof *odp_flows); if (rule->cr.wc.wildcards) { size_t i = 0; LIST_FOR_EACH (subrule, struct rule, list, &rule->list) { odp_flows[i++].key = subrule->cr.flow; + packet_count += subrule->packet_count; + byte_count += subrule->byte_count; } } else { odp_flows[0].key = rule->cr.flow; } - if (!dpif_flow_get_multiple(&p->dpif, odp_flows, n_odp_flows)) { + packet_count = rule->packet_count; + byte_count = rule->byte_count; + if (!dpif_flow_get_multiple(p->dpif, odp_flows, n_odp_flows)) { size_t i; for (i = 0; i < n_odp_flows; i++) { struct odp_flow *odp_flow = &odp_flows[i]; @@@ -3060,7 -3060,7 +3065,7 @@@ handle_odp_msg(struct ofproto *p, struc memset(&action, 0, sizeof(action)); action.output.type = ODPAT_OUTPUT; action.output.port = ODPP_LOCAL; - dpif_execute(&p->dpif, flow.in_port, &action, 1, &payload); + dpif_execute(p->dpif, flow.in_port, &action, 1, &payload); } rule = lookup_valid_rule(p, &flow); @@@ -3182,7 -3182,7 +3187,7 @@@ send_flow_exp(struct ofproto *p, struc { struct ofconn *ofconn; struct ofconn *prev; - struct ofpbuf *buf; + struct ofpbuf *buf = NULL; /* We limit the maximum number of queued flow expirations it by accounting * them under the counter for replies. That works because preventing @@@ -3274,7 -3274,7 +3279,7 @@@ update_used(struct ofproto *p size_t i; int error; - error = dpif_flow_list_all(&p->dpif, &flows, &n_flows); + error = dpif_flow_list_all(p->dpif, &flows, &n_flows); if (error) { return; } @@@ -3287,7 -3287,7 +3292,7 @@@ classifier_find_rule_exactly(&p->cls, &f->key, 0, UINT16_MAX)); if (!rule || !rule->installed) { COVERAGE_INC(ofproto_unexpected_rule); - dpif_flow_del(&p->dpif, f); + dpif_flow_del(p->dpif, f); continue; } @@@ -3362,23 -3362,23 +3367,23 @@@ send_packet_in_miss(struct ofpbuf *pack } static uint64_t -pick_datapath_id(struct dpif *dpif, uint64_t fallback_dpid) +pick_datapath_id(const struct ofproto *ofproto) { - char local_name[IF_NAMESIZE]; - uint8_t ea[ETH_ADDR_LEN]; - int error; + const struct ofport *port; - error = dpif_get_name(dpif, local_name, sizeof local_name); - if (!error) { - error = netdev_nodev_get_etheraddr(local_name, ea); + port = port_array_get(&ofproto->ports, ODPP_LOCAL); + if (port) { + uint8_t ea[ETH_ADDR_LEN]; + int error; + + error = netdev_get_etheraddr(port->netdev, ea); if (!error) { return eth_addr_to_uint64(ea); } VLOG_WARN("could not get MAC address for %s (%s)", - local_name, strerror(error)); + netdev_get_name(port->netdev), strerror(error)); } - - return fallback_dpid; + return ofproto->fallback_dpid; } static uint64_t diff --combined utilities/ovs-ofctl.c index e873ed7ba,761141597..665a2c7a6 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@@ -251,7 -251,7 +251,7 @@@ static void run(int retval, const char static void open_vconn(const char *name, struct vconn **vconnp) { - struct dpif dpif; + struct dpif *dpif; struct stat s; if (strstr(name, ":")) { @@@ -268,9 -268,9 +268,9 @@@ char *socket_name; char *vconn_name; - run(dpif_get_name(&dpif, dpif_name, sizeof dpif_name), + run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name), "obtaining name of %s", dpif_name); - dpif_close(&dpif); + dpif_close(dpif); if (strcmp(dpif_name, name)) { VLOG_INFO("datapath %s is named %s", name, dpif_name); } @@@ -617,8 -617,6 +617,8 @@@ str_to_action(char *str, struct ofpbuf * packet to the controller. */ if (arg && (strspn(act, "0123456789") == strlen(act))) { oao->max_len = htons(str_to_u32(arg)); + } else { + oao->max_len = htons(UINT16_MAX); } } else if (parse_port_name(act, &port)) { put_output_action(b, port); @@@ -918,11 -916,15 +918,15 @@@ do_mod_flows(const struct settings *s, struct vconn *vconn; struct ofpbuf *buffer; struct ofp_flow_mod *ofm; + struct ofp_match match; - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argv[2], &ofm->match, buffer, + /* Parse and send. str_to_flow() will expand and reallocate the data in + * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ + make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argv[2], &match, buffer, NULL, NULL, &priority, &idle_timeout, &hard_timeout); + ofm = buffer->data; + ofm->match = match; if (s->strict) { ofm->command = htons(OFPFC_MODIFY_STRICT); } else { diff --combined vswitchd/bridge.c index bece25220,05003e1c1..b2c051d03 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@@ -43,12 -43,12 +43,12 @@@ #include "odp-util.h" #include "ofp-print.h" #include "ofpbuf.h" +#include "ofproto/ofproto.h" #include "packets.h" #include "poll-loop.h" #include "port-array.h" #include "proc-net-compat.h" #include "process.h" -#include "secchan/ofproto.h" #include "socket-util.h" #include "stp.h" #include "svec.h" @@@ -71,18 -71,17 +71,18 @@@ struct dst extern uint64_t mgmt_id; struct iface { + /* These members are always valid. */ struct port *port; /* Containing port. */ size_t port_ifidx; /* Index within containing port. */ - char *name; /* Host network device name. */ - int dp_ifidx; /* Index within kernel datapath. */ - - uint8_t mac[ETH_ADDR_LEN]; /* Ethernet address (all zeros if unknowns). */ - tag_type tag; /* Tag associated with this interface. */ - bool enabled; /* May be chosen for flows? */ long long delay_expires; /* Time after which 'enabled' may change. */ + + /* These members are valid only after bridge_reconfigure() causes them to + * be initialized.*/ + int dp_ifidx; /* Index within kernel datapath. */ + struct netdev *netdev; /* Network device. */ + bool enabled; /* May be chosen for flows? */ }; #define BOND_MASK 0xff @@@ -160,7 -159,7 +160,7 @@@ struct bridge struct ofproto *ofproto; /* OpenFlow switch. */ /* Kernel datapath information. */ - struct dpif dpif; /* Kernel datapath. */ + struct dpif *dpif; /* Datapath. */ struct port_array ifaces; /* Indexed by kernel datapath port number. */ /* Bridge ports. */ @@@ -203,11 -202,10 +203,11 @@@ static void bridge_fetch_dp_ifaces(stru static void bridge_flush(struct bridge *); static void bridge_pick_local_hw_addr(struct bridge *, uint8_t ea[ETH_ADDR_LEN], - const char **devname); + struct iface **hw_addr_iface); static uint64_t bridge_pick_datapath_id(struct bridge *, const uint8_t bridge_ea[ETH_ADDR_LEN], - const char *devname); + struct iface *hw_addr_iface); +static struct iface *bridge_get_local_iface(struct bridge *); static uint64_t dpid_from_hash(const void *, size_t nbytes); static void bridge_unixctl_fdb_show(struct unixctl_conn *, const char *args); @@@ -227,7 -225,6 +227,7 @@@ static struct port *port_from_dp_ifidx( uint16_t dp_ifidx); static void port_update_bond_compat(struct port *); static void port_update_vlan_compat(struct port *); +static void port_update_bonding(struct port *); static void mirror_create(struct bridge *, const char *name); static void mirror_destroy(struct mirror *); @@@ -268,8 -265,8 +268,8 @@@ bridge_get_ifaces(struct svec *svec for (j = 0; j < port->n_ifaces; j++) { struct iface *iface = port->ifaces[j]; if (iface->dp_ifidx < 0) { - VLOG_ERR("%s interface not in dp%u, ignoring", - iface->name, dpif_id(&br->dpif)); + VLOG_ERR("%s interface not in datapath %s, ignoring", + iface->name, dpif_name(br->dpif)); } else { if (iface->dp_ifidx != ODPP_LOCAL) { svec_add(svec, iface->name); @@@ -284,41 -281,34 +284,41 @@@ void bridge_init(void) { - int retval; - int i; - - bond_init(); + struct svec dpif_names; + size_t i; unixctl_command_register("fdb/show", bridge_unixctl_fdb_show); - for (i = 0; i < DP_MAX; i++) { - struct dpif dpif; - char devname[16]; + svec_init(&dpif_names); + dp_enumerate(&dpif_names); + for (i = 0; i < dpif_names.n; i++) { + const char *dpif_name = dpif_names.names[i]; + struct dpif *dpif; + int retval; - sprintf(devname, "dp%d", i); - retval = dpif_open(devname, &dpif); + retval = dpif_open(dpif_name, &dpif); if (!retval) { - char dpif_name[IF_NAMESIZE]; - if (dpif_get_name(&dpif, dpif_name, sizeof dpif_name) - || !cfg_has("bridge.%s.port", dpif_name)) { - dpif_delete(&dpif); + struct svec all_names; + size_t j; + + svec_init(&all_names); + dpif_get_all_names(dpif, &all_names); + for (j = 0; j < all_names.n; j++) { + if (cfg_has("bridge.%s.port", all_names.names[j])) { + goto found; + } } - dpif_close(&dpif); - } else if (retval != ENODEV) { - VLOG_ERR("failed to delete datapath dp%d: %s", - i, strerror(retval)); + dpif_delete(dpif); + found: + svec_destroy(&all_names); + dpif_close(dpif); } } + svec_destroy(&dpif_names); unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows); + bond_init(); bridge_reconfigure(); } @@@ -360,116 -350,43 +360,116 @@@ bridge_configure_ssl(void * the old certificate will still be trusted until vSwitch is * restarted. We may want to address this in vconn's SSL library. */ if (config_string_change("ssl.ca-cert", &cacert_file) - || (stat(cacert_file, &s) && errno == ENOENT)) { + || (cacert_file && stat(cacert_file, &s) && errno == ENOENT)) { vconn_ssl_set_ca_cert_file(cacert_file, cfg_get_bool(0, "ssl.bootstrap-ca-cert")); } } #endif +/* iterate_and_prune_ifaces() callback function that opens the network device + * for 'iface', if it is not already open, and retrieves the interface's MAC + * address and carrier status. */ +static bool +init_iface_netdev(struct bridge *br UNUSED, struct iface *iface, + void *aux UNUSED) +{ + if (iface->netdev) { + return true; + } else if (!netdev_open(iface->name, NETDEV_ETH_TYPE_NONE, + &iface->netdev)) { + netdev_get_carrier(iface->netdev, &iface->enabled); + return true; + } else { + /* If the network device can't be opened, then we're not going to try + * to do anything with this interface. */ + return false; + } +} + +static bool +check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED) +{ + if (iface->dp_ifidx >= 0) { + VLOG_DBG("%s has interface %s on port %d", + dpif_name(br->dpif), + iface->name, iface->dp_ifidx); + return true; + } else { + VLOG_ERR("%s interface not in %s, dropping", + iface->name, dpif_name(br->dpif)); + return false; + } +} + +static bool +set_iface_properties(struct bridge *br UNUSED, struct iface *iface, + void *aux UNUSED) +{ + int rate, burst; + + /* Set policing attributes. */ + rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name); + burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name); + netdev_set_policing(iface->netdev, rate, burst); + + /* Set MAC address of internal interfaces other than the local + * interface. */ + if (iface->dp_ifidx != ODPP_LOCAL + && iface_is_internal(br, iface->name)) { + iface_set_mac(iface); + } + + return true; +} + +/* Calls 'cb' for each interfaces in 'br', passing along the 'aux' argument. + * Deletes from 'br' all the interfaces for which 'cb' returns false, and then + * deletes from 'br' any ports that no longer have any interfaces. */ +static void +iterate_and_prune_ifaces(struct bridge *br, + bool (*cb)(struct bridge *, struct iface *, + void *aux), + void *aux) +{ + size_t i, j; + + for (i = 0; i < br->n_ports; ) { + struct port *port = br->ports[i]; + for (j = 0; j < port->n_ifaces; ) { + struct iface *iface = port->ifaces[j]; + if (cb(br, iface, aux)) { + j++; + } else { + iface_destroy(iface); + } + } + + if (port->n_ifaces) { + i++; + } else { + VLOG_ERR("%s port has no interfaces, dropping", port->name); + port_destroy(port); + } + } +} + void bridge_reconfigure(void) { - struct svec old_br, new_br, raw_new_br; + struct svec old_br, new_br; struct bridge *br, *next; - size_t i, j; + size_t i; COVERAGE_INC(bridge_reconfigure); - /* Collect old bridges. */ + /* Collect old and new bridges. */ svec_init(&old_br); + svec_init(&new_br); LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { svec_add(&old_br, br->name); } - - /* Collect new bridges. */ - svec_init(&raw_new_br); - cfg_get_subsections(&raw_new_br, "bridge"); - svec_init(&new_br); - for (i = 0; i < raw_new_br.n; i++) { - const char *name = raw_new_br.names[i]; - if ((!strncmp(name, "dp", 2) && isdigit(name[2])) || - (!strncmp(name, "nl:", 3) && isdigit(name[3]))) { - VLOG_ERR("%s is not a valid bridge name (bridges may not be " - "named \"dp\" or \"nl:\" followed by a digit)", name); - } else { - svec_add(&new_br, name); - } - } - svec_destroy(&raw_new_br); + cfg_get_subsections(&new_br, "bridge"); /* Get rid of deleted bridges and add new bridges. */ svec_sort(&old_br); @@@ -510,17 -427,16 +510,17 @@@ size_t n_dpif_ports; struct svec want_ifaces; - dpif_port_list(&br->dpif, &dpif_ports, &n_dpif_ports); + dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports); bridge_get_all_ifaces(br, &want_ifaces); for (i = 0; i < n_dpif_ports; i++) { const struct odp_port *p = &dpif_ports[i]; if (!svec_contains(&want_ifaces, p->devname) && strcmp(p->devname, br->name)) { - int retval = dpif_port_del(&br->dpif, p->port); + int retval = dpif_port_del(br->dpif, p->port); if (retval) { - VLOG_ERR("failed to remove %s interface from dp%u: %s", - p->devname, dpif_id(&br->dpif), strerror(retval)); + VLOG_ERR("failed to remove %s interface from %s: %s", + p->devname, dpif_name(br->dpif), + strerror(retval)); } } } @@@ -531,8 -447,9 +531,8 @@@ struct odp_port *dpif_ports; size_t n_dpif_ports; struct svec cur_ifaces, want_ifaces, add_ifaces; - int next_port_no; - dpif_port_list(&br->dpif, &dpif_ports, &n_dpif_ports); + dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports); svec_init(&cur_ifaces); for (i = 0; i < n_dpif_ports; i++) { svec_add(&cur_ifaces, dpif_ports[i].devname); @@@ -542,24 -459,32 +542,24 @@@ 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; - - /* Add to datapath. */ - internal = iface_is_internal(br, if_name); - 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; - } + bool internal; + int error; + + /* Add to datapath. */ + internal = iface_is_internal(br, if_name); + error = dpif_port_add(br->dpif, if_name, + internal ? ODP_PORT_INTERNAL : 0, NULL); + if (error == EFBIG) { + 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); @@@ -567,22 -492,44 +567,22 @@@ LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { uint8_t ea[8]; uint64_t dpid; - struct iface *local_iface = NULL; - const char *devname; - uint8_t engine_type = br->dpif.minor; - uint8_t engine_id = br->dpif.minor; + struct iface *local_iface; + struct iface *hw_addr_iface; + uint8_t engine_type, engine_id; bool add_id_to_iface = false; struct svec nf_hosts; bridge_fetch_dp_ifaces(br); - for (i = 0; i < br->n_ports; ) { - struct port *port = br->ports[i]; + iterate_and_prune_ifaces(br, init_iface_netdev, NULL); - for (j = 0; j < port->n_ifaces; ) { - struct iface *iface = port->ifaces[j]; - if (iface->dp_ifidx < 0) { - VLOG_ERR("%s interface not in dp%u, dropping", - iface->name, dpif_id(&br->dpif)); - iface_destroy(iface); - } else { - if (iface->dp_ifidx == ODPP_LOCAL) { - local_iface = iface; - } - VLOG_DBG("dp%u has interface %s on port %d", - dpif_id(&br->dpif), iface->name, iface->dp_ifidx); - j++; - } - } - if (!port->n_ifaces) { - VLOG_ERR("%s port has no interfaces, dropping", port->name); - port_destroy(port); - continue; - } - i++; - } + iterate_and_prune_ifaces(br, check_iface_dp_ifidx, NULL); /* Pick local port hardware address, datapath ID. */ - bridge_pick_local_hw_addr(br, ea, &devname); + bridge_pick_local_hw_addr(br, ea, &hw_addr_iface); + local_iface = bridge_get_local_iface(br); if (local_iface) { - int error = netdev_nodev_set_etheraddr(local_iface->name, ea); + int error = netdev_set_etheraddr(local_iface->netdev, ea); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge " @@@ -591,11 -538,10 +591,11 @@@ } } - dpid = bridge_pick_datapath_id(br, ea, devname); + dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface); ofproto_set_datapath_id(br->ofproto, dpid); /* Set NetFlow configuration on this bridge. */ + dpif_get_netflow_ids(br->dpif, &engine_type, &engine_id); if (cfg_has("netflow.%s.engine-type", br->name)) { engine_type = cfg_get_int(0, "netflow.%s.engine-type", br->name); @@@ -642,24 -588,30 +642,24 @@@ struct port *port = br->ports[i]; port_update_vlan_compat(port); - - for (j = 0; j < port->n_ifaces; j++) { - struct iface *iface = port->ifaces[j]; - if (iface->dp_ifidx != ODPP_LOCAL - && iface_is_internal(br, iface->name)) { - iface_set_mac(iface); - } - } + port_update_bonding(port); } } LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { brstp_reconfigure(br); + iterate_and_prune_ifaces(br, set_iface_properties, NULL); } } static void bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN], - const char **devname) + struct iface **hw_addr_iface) { uint64_t requested_ea; size_t i, j; int error; - *devname = NULL; + *hw_addr_iface = NULL; /* Did the user request a particular MAC? */ requested_ea = cfg_get_mac(0, "bridge.%s.mac", br->name); @@@ -702,7 -654,7 +702,7 @@@ 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; } @@@ -732,7 -684,7 +732,7 @@@ } /* Grab MAC. */ - error = netdev_nodev_get_etheraddr(iface->name, iface_ea); + error = netdev_get_etheraddr(iface->netdev, iface_ea); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s", @@@ -748,12 -700,12 +748,12 @@@ 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); - *devname = NULL; + *hw_addr_iface = NULL; VLOG_WARN("bridge %s: using default bridge Ethernet " "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea)); } else { @@@ -764,13 -716,13 +764,13 @@@ /* Choose and returns the datapath ID for bridge 'br' given that the bridge * Ethernet address is 'bridge_ea'. If 'bridge_ea' is the Ethernet address of - * a network device, then that network device's name must be passed in as - * 'devname'; if 'bridge_ea' was derived some other way, then 'devname' must be - * passed in as a null pointer. */ + * an interface on 'br', then that interface must be passed in as + * 'hw_addr_iface'; if 'bridge_ea' was derived some other way, then + * 'hw_addr_iface' must be passed in as a null pointer. */ static uint64_t bridge_pick_datapath_id(struct bridge *br, const uint8_t bridge_ea[ETH_ADDR_LEN], - const char *devname) + struct iface *hw_addr_iface) { /* * The procedure for choosing a bridge MAC address will, in the most @@@ -791,9 -743,9 +791,9 @@@ return dpid; } - if (devname) { + if (hw_addr_iface) { int vlan; - if (!netdev_get_vlan_vid(devname, &vlan)) { + if (!netdev_get_vlan_vid(hw_addr_iface->netdev, &vlan)) { /* * A bridge whose MAC address is taken from a VLAN network device * (that is, a network device created with vconfig(8) or similar @@@ -903,26 -855,6 +903,26 @@@ bridge_flush(struct bridge *br mac_learning_flush(br->ml); } } + +/* Returns the 'br' interface for the ODPP_LOCAL port, or null if 'br' has no + * such interface. */ +static struct iface * +bridge_get_local_iface(struct bridge *br) +{ + size_t i, j; + + for (i = 0; i < br->n_ports; i++) { + struct port *port = br->ports[i]; + for (j = 0; j < port->n_ifaces; j++) { + struct iface *iface = port->ifaces[j]; + if (iface->dp_ifidx == ODPP_LOCAL) { + return iface; + } + } + } + + return NULL; +} /* Bridge unixctl user interface functions. */ static void @@@ -965,7 -897,7 +965,7 @@@ bridge_create(const char *name br = xcalloc(1, sizeof *br); error = dpif_create(name, &br->dpif); - if (error == EEXIST) { + if (error == EEXIST || error == EBUSY) { error = dpif_open(name, &br->dpif); if (error) { VLOG_ERR("datapath %s already exists but cannot be opened: %s", @@@ -973,7 -905,7 +973,7 @@@ free(br); return NULL; } - dpif_flow_flush(&br->dpif); + dpif_flow_flush(br->dpif); } else if (error) { VLOG_ERR("failed to create datapath %s: %s", name, strerror(error)); free(br); @@@ -983,8 -915,8 +983,8 @@@ error = ofproto_create(name, &bridge_ofhooks, br, &br->ofproto); if (error) { VLOG_ERR("failed to create switch %s: %s", name, strerror(error)); - dpif_delete(&br->dpif); - dpif_close(&br->dpif); + dpif_delete(br->dpif); + dpif_close(br->dpif); free(br); return NULL; } @@@ -1001,7 -933,7 +1001,7 @@@ list_push_back(&all_bridges, &br->node); - VLOG_INFO("created bridge %s on dp%u", br->name, dpif_id(&br->dpif)); + VLOG_INFO("created bridge %s on %s", br->name, dpif_name(br->dpif)); return br; } @@@ -1016,12 -948,12 +1016,12 @@@ bridge_destroy(struct bridge *br port_destroy(br->ports[br->n_ports - 1]); } list_remove(&br->node); - error = dpif_delete(&br->dpif); + error = dpif_delete(br->dpif); if (error && error != ENOENT) { - VLOG_ERR("failed to delete dp%u: %s", - dpif_id(&br->dpif), strerror(error)); + VLOG_ERR("failed to delete %s: %s", + dpif_name(br->dpif), strerror(error)); } - dpif_close(&br->dpif); + dpif_close(br->dpif); ofproto_destroy(br->ofproto); free(br->controller); mac_learning_destroy(br->ml); @@@ -1113,29 -1045,13 +1113,29 @@@ bridge_get_controller(const struct brid return controller && controller[0] ? controller : NULL; } +static bool +check_duplicate_ifaces(struct bridge *br, struct iface *iface, void *ifaces_) +{ + struct svec *ifaces = ifaces_; + if (!svec_contains(ifaces, iface->name)) { + svec_add(ifaces, iface->name); + svec_sort(ifaces); + return true; + } else { + VLOG_ERR("bridge %s: %s interface is on multiple ports, " + "removing from %s", + br->name, iface->name, iface->port->name); + return false; + } +} + static void bridge_reconfigure_one(struct bridge *br) { struct svec old_ports, new_ports, ifaces; struct svec listeners, old_listeners; struct svec snoops, old_snoops; - size_t i, j; + size_t i; /* Collect old ports. */ svec_init(&old_ports); @@@ -1149,16 -1065,9 +1149,16 @@@ svec_init(&new_ports); cfg_get_all_keys(&new_ports, "bridge.%s.port", br->name); svec_sort(&new_ports); - if (bridge_get_controller(br) && !svec_contains(&new_ports, br->name)) { - svec_add(&new_ports, br->name); - svec_sort(&new_ports); + if (bridge_get_controller(br)) { + char local_name[IF_NAMESIZE]; + int error; + + error = dpif_port_get_name(br->dpif, ODPP_LOCAL, + local_name, sizeof local_name); + if (!error && !svec_contains(&new_ports, local_name)) { + svec_add(&new_ports, local_name); + svec_sort(&new_ports); + } } if (!svec_is_unique(&new_ports)) { VLOG_WARN("bridge %s: %s specified twice as bridge port", @@@ -1193,7 -1102,28 +1193,7 @@@ /* Check and delete duplicate interfaces. */ svec_init(&ifaces); - for (i = 0; i < br->n_ports; ) { - struct port *port = br->ports[i]; - for (j = 0; j < port->n_ifaces; ) { - struct iface *iface = port->ifaces[j]; - if (svec_contains(&ifaces, iface->name)) { - VLOG_ERR("bridge %s: %s interface is on multiple ports, " - "removing from %s", - br->name, iface->name, port->name); - iface_destroy(iface); - } else { - svec_add(&ifaces, iface->name); - svec_sort(&ifaces); - j++; - } - } - if (!port->n_ifaces) { - VLOG_ERR("%s port has no interfaces, dropping", port->name); - port_destroy(port); - } else { - i++; - } - } + iterate_and_prune_ifaces(br, check_duplicate_ifaces, &ifaces); svec_destroy(&ifaces); /* Delete all flows if we're switching from connected to standalone or vice @@@ -1274,8 -1204,9 +1274,8 @@@ bridge_reconfigure_controller(struct br cfg_get_string(0, "%s.accept-regex", pfx), update_resolv_conf); } else { - struct netdev *netdev; + struct iface *local_iface; bool in_band; - int error; in_band = (!cfg_is_valid(CFG_BOOL | CFG_REQUIRED, "%s.in-band", pfx) @@@ -1283,32 -1214,33 +1283,32 @@@ ofproto_set_discovery(br->ofproto, false, NULL, NULL); ofproto_set_in_band(br->ofproto, in_band); - error = netdev_open(br->name, NETDEV_ETH_TYPE_NONE, &netdev); - if (!error) { - if (cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) { - struct in_addr ip, mask, gateway; - ip.s_addr = cfg_get_ip(0, "%s.ip", pfx); - mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx); - gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx); - - netdev_turn_flags_on(netdev, NETDEV_UP, true); - if (!mask.s_addr) { - mask.s_addr = guess_netmask(ip.s_addr); - } - if (!netdev_set_in4(netdev, ip, mask)) { - VLOG_INFO("bridge %s: configured IP address "IP_FMT", " - "netmask "IP_FMT, - br->name, IP_ARGS(&ip.s_addr), - IP_ARGS(&mask.s_addr)); - } + local_iface = bridge_get_local_iface(br); + if (local_iface + && cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) { + struct netdev *netdev = local_iface->netdev; + struct in_addr ip, mask, gateway; + ip.s_addr = cfg_get_ip(0, "%s.ip", pfx); + mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx); + gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx); + + netdev_turn_flags_on(netdev, NETDEV_UP, true); + if (!mask.s_addr) { + mask.s_addr = guess_netmask(ip.s_addr); + } + if (!netdev_set_in4(netdev, ip, mask)) { + VLOG_INFO("bridge %s: configured IP address "IP_FMT", " + "netmask "IP_FMT, + br->name, IP_ARGS(&ip.s_addr), + IP_ARGS(&mask.s_addr)); + } - if (gateway.s_addr) { - if (!netdev_add_router(gateway)) { - VLOG_INFO("bridge %s: configured gateway "IP_FMT, - br->name, IP_ARGS(&gateway.s_addr)); - } + if (gateway.s_addr) { + if (!netdev_add_router(netdev, gateway)) { + VLOG_INFO("bridge %s: configured gateway "IP_FMT, + br->name, IP_ARGS(&gateway.s_addr)); } } - netdev_close(netdev); } } @@@ -1438,17 -1370,17 +1438,17 @@@ bridge_fetch_dp_ifaces(struct bridge *b } port_array_clear(&br->ifaces); - dpif_port_list(&br->dpif, &dpif_ports, &n_dpif_ports); + dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports); for (i = 0; i < n_dpif_ports; i++) { struct odp_port *p = &dpif_ports[i]; struct iface *iface = iface_lookup(br, p->devname); if (iface) { if (iface->dp_ifidx >= 0) { - VLOG_WARN("dp%u reported interface %s twice", - dpif_id(&br->dpif), p->devname); + VLOG_WARN("%s reported interface %s twice", + dpif_name(br->dpif), p->devname); } else if (iface_from_dp_ifidx(br, p->port)) { - VLOG_WARN("dp%u reported interface %"PRIu16" twice", - dpif_id(&br->dpif), p->port); + VLOG_WARN("%s reported interface %"PRIu16" twice", + dpif_name(br->dpif), p->port); } else { port_array_set(&br->ifaces, p->port, iface); iface->dp_ifidx = p->port; @@@ -1783,14 -1715,26 +1783,26 @@@ compose_dsts(const struct bridge *br, c if (port_includes_vlan(port, m->out_vlan) && set_dst(dst, flow, in_port, port, tags)) { + int flow_vlan; + if (port->vlan < 0) { dst->vlan = m->out_vlan; } if (dst_is_duplicate(dsts, dst - dsts, dst)) { continue; } - if (dst->dp_ifidx == flow->in_port - && dst->vlan == vlan) { + + /* Use the vlan tag on the original flow instead of + * the one passed in the vlan parameter. This ensures + * that we compare the vlan from before any implicit + * tagging tags place. This is necessary because + * dst->vlan is the final vlan, after removing implicit + * tags. */ + flow_vlan = ntohs(flow->dl_vlan); + if (flow_vlan == 0) { + flow_vlan = OFP_VLAN_NONE; + } + if (port == in_port && dst->vlan == flow_vlan) { /* Don't send out input port on same VLAN. */ continue; } @@@ -1953,33 -1897,27 +1965,27 @@@ process_flow(struct bridge *br, const f goto done; } - /* Multicast (and broadcast) packets on bonds need special attention, to - * avoid receiving duplicates. */ - if (in_port->n_ifaces > 1 && eth_addr_is_multicast(flow->dl_dst)) { - *tags |= in_port->active_iface_tag; - if (in_port->active_iface != in_iface->port_ifidx) { - /* Drop all multicast packets on inactive slaves. */ - goto done; - } else { - /* Drop all multicast packets for which we have learned a different - * input port, because we probably sent the packet on one slave - * and got it back on the active slave. Broadcast ARP replies are - * an exception to this rule: the host has moved to another - * switch. */ - int src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan); - if (src_idx != -1 && src_idx != in_port->port_idx) { - if (packet) { - if (!is_bcast_arp_reply(flow, packet)) { - goto done; - } - } else { - /* No way to know whether it's an ARP reply, because the - * flow entry doesn't include enough information and we - * don't have a packet. Punt. */ - return false; - } + /* Packets received on bonds need special attention to avoid duplicates. */ + if (in_port->n_ifaces > 1) { + int src_idx; + + if (eth_addr_is_multicast(flow->dl_dst)) { + *tags |= in_port->active_iface_tag; + if (in_port->active_iface != in_iface->port_ifidx) { + /* Drop all multicast packets on inactive slaves. */ + goto done; } } + + /* Drop all packets for which we have learned a different input + * port, because we probably sent the packet on one slave and got + * it back on the other. Broadcast ARP replies are an exception + * to this rule: the host has moved to another switch. */ + src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan); + if (src_idx != -1 && src_idx != in_port->port_idx && + (!packet || !is_bcast_arp_reply(flow, packet))) { + goto done; + } } /* MAC learning. */ @@@ -2009,6 -1947,11 +2015,11 @@@ tags); if (out_port_idx >= 0 && out_port_idx < br->n_ports) { out_port = br->ports[out_port_idx]; + } else if (!packet) { + /* If we are revalidating but don't have a learning entry then + * eject the flow. Installing a flow that floods packets will + * prevent us from seeing future packets and learning properly. */ + return false; } } @@@ -2061,6 -2004,7 +2072,6 @@@ bridge_port_changed_ofhook_cb(enum ofp_ bridge_flush(br); } else { - memcpy(iface->mac, opp->hw_addr, ETH_ADDR_LEN); if (port->n_ifaces > 1) { bool up = !(opp->state & OFPPS_LINK_DOWN); bond_link_status_update(iface, up); @@@ -2259,8 -2203,9 +2270,9 @@@ log_bals(const struct slave_balance *ba /* Shifts 'hash' from 'from' to 'to' within 'port'. */ static void bond_shift_load(struct slave_balance *from, struct slave_balance *to, - struct bond_entry *hash) + int hash_idx) { + struct bond_entry *hash = from->hashes[hash_idx]; struct port *port = from->iface->port; uint64_t delta = hash->tx_bytes; @@@ -2278,12 -2223,11 +2290,11 @@@ * it require more work, the only purpose it would be to allow that hash to * be migrated to another slave in this rebalancing run, and there is no * point in doing that. */ - if (from->hashes[0] == hash) { + if (hash_idx == 0) { from->hashes++; } else { - int i = hash - from->hashes[0]; - memmove(from->hashes + i, from->hashes + i + 1, - (from->n_hashes - (i + 1)) * sizeof *from->hashes); + memmove(from->hashes + hash_idx, from->hashes + hash_idx + 1, + (from->n_hashes - (hash_idx + 1)) * sizeof *from->hashes); } from->n_hashes--; @@@ -2368,22 -2312,60 +2379,60 @@@ bond_rebalance_port(struct port *port /* 'from' is carrying significantly more load than 'to', and that * load is split across at least two different hashes. Pick a hash * to migrate to 'to' (the least-loaded slave), given that doing so - * must not cause 'to''s load to exceed 'from''s load. + * must decrease the ratio of the load on the two slaves by at + * least 0.1. * * The sort order we use means that we prefer to shift away the * smallest hashes instead of the biggest ones. There is little * reason behind this decision; we could use the opposite sort * order to shift away big hashes ahead of small ones. */ size_t i; + bool order_swapped; for (i = 0; i < from->n_hashes; i++) { + double old_ratio, new_ratio; uint64_t delta = from->hashes[i]->tx_bytes; - if (to->tx_bytes + delta < from->tx_bytes - delta) { + + if (delta == 0 || from->tx_bytes - delta == 0) { + /* Pointless move. */ + continue; + } + + order_swapped = from->tx_bytes - delta < to->tx_bytes + delta; + + if (to->tx_bytes == 0) { + /* Nothing on the new slave, move it. */ + break; + } + + old_ratio = (double)from->tx_bytes / to->tx_bytes; + new_ratio = (double)(from->tx_bytes - delta) / + (to->tx_bytes + delta); + + if (new_ratio == 0) { + /* Should already be covered but check to prevent division + * by zero. */ + continue; + } + + if (new_ratio < 1) { + new_ratio = 1 / new_ratio; + } + + if (old_ratio - new_ratio > 0.1) { + /* Would decrease the ratio, move it. */ break; } } if (i < from->n_hashes) { - bond_shift_load(from, to, from->hashes[i]); + bond_shift_load(from, to, i); + port->bond_compat_is_stale = true; + + /* If the result of the migration changed the relative order of + * 'from' and 'to' swap them back to maintain invariants. */ + if (order_swapped) { + swap_bals(from, to); + } /* Re-sort 'bals'. Note that this may make 'from' and 'to' * point to different slave_balance structures. It is only @@@ -2394,7 -2376,6 +2443,6 @@@ } else { from++; } - port->bond_compat_is_stale = true; } } @@@ -2739,25 -2720,6 +2787,25 @@@ bond_unixctl_disable_slave(struct unixc enable_slave(conn, args, false); } +static void +bond_unixctl_hash(struct unixctl_conn *conn, const char *args) +{ + uint8_t mac[ETH_ADDR_LEN]; + uint8_t hash; + char *hash_cstr; + + if (sscanf(args, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac)) + == ETH_ADDR_SCAN_COUNT) { + hash = bond_hash(mac); + + hash_cstr = xasprintf("%u", hash); + unixctl_command_reply(conn, 200, hash_cstr); + free(hash_cstr); + } else { + unixctl_command_reply(conn, 501, "invalid mac"); + } +} + static void bond_init(void) { @@@ -2768,7 -2730,6 +2816,7 @@@ bond_unixctl_set_active_slave); unixctl_command_register("bond/enable-slave", bond_unixctl_enable_slave); unixctl_command_register("bond/disable-slave", bond_unixctl_disable_slave); + unixctl_command_register("bond/hash", bond_unixctl_hash); } /* Port functions. */ @@@ -3067,7 -3028,7 +3115,7 @@@ 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); } if (cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) { @@@ -3111,8 -3072,7 +3159,8 @@@ port_update_vlan_compat(struct port *po && p->n_ifaces && (!vlandev_name || strcmp(p->name, vlandev_name) <= 0)) { - const uint8_t *ea = p->ifaces[0]->mac; + uint8_t ea[ETH_ADDR_LEN]; + netdev_get_etheraddr(p->ifaces[0]->netdev, ea); if (!eth_addr_is_multicast(ea) && !eth_addr_is_reserved(ea) && !eth_addr_is_zero(ea)) { @@@ -3138,7 -3098,18 +3186,7 @@@ iface_create(struct port *port, const c iface->dp_ifidx = -1; iface->tag = tag_create_random(); iface->delay_expires = LLONG_MAX; - - if (!cfg_get_bool(0, "iface.%s.internal", iface->name)) { - netdev_nodev_get_etheraddr(name, iface->mac); - netdev_nodev_get_carrier(name, &iface->enabled); - } else { - /* Internal interfaces are created later by the call to dpif_port_add() - * in bridge_reconfigure(). Until then, we can't obtain any - * information about them. (There's no real value in doing so, anyway, - * because the 'mac' and 'enabled' values are only used for interfaces - * that are bond slaves, and it doesn't normally make sense to bond an - * internal interface.) */ - } + iface->netdev = NULL; if (port->n_ifaces >= port->allocated_ifaces) { port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces, @@@ -3151,6 -3122,7 +3199,6 @@@ VLOG_DBG("attached network device %s to port %s", iface->name, port->name); - port_update_bonding(port); bridge_flush(port->bridge); } @@@ -3170,7 -3142,6 +3218,7 @@@ iface_destroy(struct iface *iface del = port->ifaces[iface->port_ifidx] = port->ifaces[--port->n_ifaces]; del->port_ifidx = iface->port_ifidx; + netdev_close(iface->netdev); free(iface->name); free(iface); @@@ -3180,6 -3151,7 +3228,6 @@@ bond_send_learning_packets(port); } - port_update_bonding(port); bridge_flush(port->bridge); } } @@@ -3252,7 -3224,7 +3300,7 @@@ iface_set_mac(struct iface *iface VLOG_ERR("ignoring iface.%s.mac; use bridge.%s.mac instead", iface->name, iface->name); } else { - int error = netdev_nodev_set_etheraddr(iface->name, ea); + int error = netdev_set_etheraddr(iface->netdev, ea); if (error) { VLOG_ERR("interface %s: setting MAC failed (%s)", iface->name, strerror(error)); @@@ -3581,25 -3553,23 +3629,25 @@@ brstp_send_bpdu(struct ofpbuf *pkt, in if (!iface) { VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown port %d", br->name, port_no); - } else if (eth_addr_is_zero(iface->mac)) { - VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d with unknown MAC", - br->name, port_no); } else { - union ofp_action action; struct eth_header *eth = pkt->l2; - flow_t flow; - memcpy(eth->eth_src, iface->mac, ETH_ADDR_LEN); + netdev_get_etheraddr(iface->netdev, eth->eth_src); + if (eth_addr_is_zero(eth->eth_src)) { + VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d " + "with unknown MAC", br->name, port_no); + } else { + union ofp_action action; + flow_t flow; - memset(&action, 0, sizeof action); - action.type = htons(OFPAT_OUTPUT); - action.output.len = htons(sizeof action); - action.output.port = htons(port_no); + memset(&action, 0, sizeof action); + action.type = htons(OFPAT_OUTPUT); + action.output.len = htons(sizeof action); + action.output.port = htons(port_no); - flow_extract(pkt, ODPP_NONE, &flow); - ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt); + flow_extract(pkt, ODPP_NONE, &flow); + ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt); + } } ofpbuf_delete(pkt); } diff --combined xenserver/README index 276cd6c2a,5407aac9d..ff692fd3f --- a/xenserver/README +++ b/xenserver/README @@@ -50,6 -50,12 +50,12 @@@ files are needed by the controller. This is called by the "vif" script, which is run when virtual interfaces are added and removed. - root_vswitch_scripts_refresh-xs-network-uuids ++ usr_share_vswitch_scripts_refresh-xs-network-uuids + + Script to refresh bridge..xs-network-uuids keys, which + can get out-of-sync following a pool join. Running this script + is an alternative to rebooting the host. + root_vswitch_scripts_sysconfig.template Template for vswitch's /etc/sysconfig/vswitch configuration diff --combined xenserver/automake.mk index 327543419,4c9c0a979..221925cda --- a/xenserver/automake.mk +++ b/xenserver/automake.mk @@@ -14,9 -14,10 +14,10 @@@ EXTRA_DIST += xenserver/etc_xapi.d_plugins_vswitch-cfg-update \ xenserver/etc_xensource_scripts_vif \ xenserver/opt_xensource_libexec_interface-reconfigure \ - xenserver/root_vswitch_scripts_sysconfig.template \ - xenserver/root_vswitch_scripts_dump-vif-details \ - xenserver/root_vswitch_scripts_refresh-xs-network-uuids \ xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \ xenserver/usr_sbin_brctl \ xenserver/usr_sbin_xen-bugtool \ + xenserver/usr_share_vswitch_scripts_sysconfig.template \ + xenserver/usr_share_vswitch_scripts_dump-vif-details \ ++ xenserver/usr_share_vswitch_scripts_refresh-xs-network-uuids \ xenserver/vswitch-xen.spec diff --combined xenserver/usr_share_vswitch_scripts_refresh-xs-network-uuids index 000000000,34fe1e7e9..34fe1e7e9 mode 000000,100755..100755 --- a/xenserver/usr_share_vswitch_scripts_refresh-xs-network-uuids +++ b/xenserver/usr_share_vswitch_scripts_refresh-xs-network-uuids @@@ -1,0 -1,12 +1,12 @@@ + #! /bin/sh + + . /etc/xensource-inventory + + for pif in $(xe pif-list --minimal host-uuid=${INSTALLATION_UUID} currently-attached=true VLAN=-1 | sed 's/,/ /g'); do + printf "Refreshing PIF %s... " $pif + if /opt/xensource/libexec/interface-reconfigure --pif-uuid=$pif up; then + printf "done\n" + else + printf "error!\n" + fi + done diff --combined xenserver/vswitch-xen.spec index d9a18bd98,c79309d22..d8e32e48f --- a/xenserver/vswitch-xen.spec +++ b/xenserver/vswitch-xen.spec @@@ -14,6 -14,7 +14,6 @@@ # rpmbuild -D "vswitch_version 0.8.9~1+build123" -D "xen_version 2.6.18-128.1.1.el5.xs5.1.0.483.1000xen" -D "build_number --with-build-number=123" -bb /usr/src/redhat/SPECS/vswitch-xen.spec # %define version %{vswitch_version}-%{xen_version} -%define _prefix /root/vswitch Name: vswitch Summary: Virtual switch @@@ -27,13 -28,6 +27,13 @@@ Release: Source: openvswitch-%{vswitch_version}.tar.gz Buildroot: /tmp/vswitch-xen-rpm Requires: kernel-xen = %(echo '%{xen_version}' | sed 's/xen$//') +# The following Conflicts prevents the "vswitch" package generated by +# this spec file from installing at the same time as the "openvswitch" +# package shipped with XenServer 5.5.900. In fact, the packages +# contain some files with identical names anyhow, so they will not +# coexist, but adding an explicit Conflicts makes this conflict more +# obvious. +Conflicts: openvswitch %description The vswitch provides standard network bridging functions augmented with @@@ -44,12 -38,12 +44,12 @@@ traffic %setup -q -n openvswitch-%{vswitch_version} %build -./configure --prefix=%{_prefix} --localstatedir=%{_localstatedir} --with-l26=/lib/modules/%{xen_version}/build --enable-ssl %{build_number} +./configure --prefix=/usr --sysconfdir=/etc --localstatedir=%{_localstatedir} --with-l26=/lib/modules/%{xen_version}/build --enable-ssl %{build_number} make %{_smp_mflags} %install rm -rf $RPM_BUILD_ROOT -make install DESTDIR=$RPM_BUILD_ROOT prefix=%{_prefix} +make install DESTDIR=$RPM_BUILD_ROOT install -d -m 755 $RPM_BUILD_ROOT/etc install -d -m 755 $RPM_BUILD_ROOT/etc/init.d install -m 755 xenserver/etc_init.d_vswitch \ @@@ -66,45 -60,45 +66,47 @@@ install -m 755 xenserver/etc_profile.d_ install -d -m 755 $RPM_BUILD_ROOT/etc/xapi.d/plugins install -m 755 xenserver/etc_xapi.d_plugins_vswitch-cfg-update \ $RPM_BUILD_ROOT/etc/xapi.d/plugins/vswitch-cfg-update -install -d -m 755 $RPM_BUILD_ROOT%{_prefix}/scripts +install -d -m 755 $RPM_BUILD_ROOT/usr/share/vswitch/scripts install -m 755 xenserver/opt_xensource_libexec_interface-reconfigure \ - $RPM_BUILD_ROOT%{_prefix}/scripts/interface-reconfigure + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/interface-reconfigure 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/root_vswitch_scripts_refresh-xs-network-uuids \ - $RPM_BUILD_ROOT%{_prefix}/scripts/refresh-xs-network-uuids + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/vif +install -m 755 xenserver/usr_share_vswitch_scripts_dump-vif-details \ + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/dump-vif-details ++install -m 755 xenserver/usr_share_vswitch_scripts_refresh-xs-network-uuids \ ++ $RPM_BUILD_ROOT/usr/share/vswitch/scripts/refresh-xs-network-uuids install -m 755 xenserver/usr_sbin_xen-bugtool \ - $RPM_BUILD_ROOT%{_prefix}/scripts/xen-bugtool + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/xen-bugtool install -m 755 xenserver/usr_sbin_brctl \ - $RPM_BUILD_ROOT%{_prefix}/scripts/brctl -install -m 755 xenserver/root_vswitch_scripts_sysconfig.template \ - $RPM_BUILD_ROOT/root/vswitch/scripts/sysconfig.template + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/brctl +install -m 755 xenserver/usr_share_vswitch_scripts_sysconfig.template \ + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/sysconfig.template install -m 644 \ xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \ - $RPM_BUILD_ROOT%{_prefix}/scripts/XSFeatureVSwitch.py + $RPM_BUILD_ROOT/usr/share/vswitch/scripts/XSFeatureVSwitch.py -install -d -m 755 $RPM_BUILD_ROOT%{_prefix}/kernel_modules -find datapath/linux-2.6 -name *.ko -exec install -m 755 \{\} $RPM_BUILD_ROOT%{_prefix}/kernel_modules/ \; +install -d -m 755 $RPM_BUILD_ROOT/lib/modules/%{xen_version}/kernel/net/vswitch +find datapath/linux-2.6 -name *.ko -exec install -m 755 \{\} $RPM_BUILD_ROOT/lib/modules/%{xen_version}/kernel/net/vswitch \; # Get rid of stuff we don't want to make RPM happy. -rm -rf \ - $RPM_BUILD_ROOT/root/vswitch/bin/ezio-term \ - $RPM_BUILD_ROOT/root/vswitch/bin/ovs-controller \ - $RPM_BUILD_ROOT/root/vswitch/bin/ovs-discover \ - $RPM_BUILD_ROOT/root/vswitch/bin/ovs-kill \ - $RPM_BUILD_ROOT/root/vswitch/bin/ovs-pki \ - $RPM_BUILD_ROOT/root/vswitch/bin/ovs-switchui \ - $RPM_BUILD_ROOT/root/vswitch/bin/ovs-wdt \ - $RPM_BUILD_ROOT/root/vswitch/bin/secchan \ - $RPM_BUILD_ROOT/root/vswitch/sbin/ovs-monitor \ - $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-controller.8 \ - $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-discover.8 \ - $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-kill.8 \ - $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-pki.8 \ - $RPM_BUILD_ROOT/root/vswitch/share/man/man8/secchan.8 \ - $RPM_BUILD_ROOT/root/vswitch/share/openvswitch +rm \ + $RPM_BUILD_ROOT/usr/bin/ovs-controller \ + $RPM_BUILD_ROOT/usr/bin/ovs-discover \ + $RPM_BUILD_ROOT/usr/bin/ovs-kill \ + $RPM_BUILD_ROOT/usr/bin/ovs-openflowd \ + $RPM_BUILD_ROOT/usr/bin/ovs-pki \ + $RPM_BUILD_ROOT/usr/bin/ovs-wdt \ + $RPM_BUILD_ROOT/usr/sbin/ovs-monitor \ + $RPM_BUILD_ROOT/usr/share/man/man8/ovs-controller.8 \ + $RPM_BUILD_ROOT/usr/share/man/man8/ovs-discover.8 \ + $RPM_BUILD_ROOT/usr/share/man/man8/ovs-kill.8 \ + $RPM_BUILD_ROOT/usr/share/man/man8/ovs-openflowd.8 \ + $RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8 +rm -f $RPM_BUILD_ROOT/lib/modules/%{xen_version}/kernel/net/vswitch/veth_mod.ko +rm -r \ + $RPM_BUILD_ROOT/usr/share/openvswitch/commands + +install -d -m 755 $RPM_BUILD_ROOT/var/lib/openvswitch %clean rm -rf $RPM_BUILD_ROOT @@@ -116,31 -110,34 +118,31 @@@ if [ ! -f /etc/xensource-inventory ]; t fi if [ "$1" = "1" ]; then - if ! md5sum -c --status </dev/null 2>&1; then :; else cat >>/etc/sysctl.conf <