From: Thomas Graf Date: Thu, 25 Apr 2013 12:28:15 +0000 (+0200) Subject: datapath: Use openvswitch_handle_frame hook in >=RHEL6.4 to live side by side with... X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=f285d3e715512571c4b2f92a4d1c65022bbcc9d5 datapath: Use openvswitch_handle_frame hook in >=RHEL6.4 to live side by side with bridging Due to the missing register rx_handler API in the kernel RHEL6 is based on, the datapath currently falls back to using the bridging hook with the consequence that bridging and OVS cannot be used in parallel on any RHEL6 release. For this purpose, >=RHEL6.4 releases provide a special rx frame hook to be used by OVS. It captures frames at the same location in the stack as the rx_handler would do in more recent kernel releases. In order to store the vport pointer, the net_device's ax25_ptr field is utilized under the assumption that an AX25 device will never be attached to an OVS bridge. Signed-off-by: Thomas Graf Signed-off-by: Jesse Gross --- diff --git a/acinclude.m4 b/acinclude.m4 index 911a23d54..2703bc460 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -273,6 +273,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/linux/if_vlan.h], [ADD_ALL_VLANS_CMD], [OVS_DEFINE([HAVE_VLAN_BUG_WORKAROUND])]) + OVS_GREP_IFELSE([$KSRC/include/linux/openvswitch.h], [openvswitch_handle_frame_hook], + [OVS_DEFINE([HAVE_RHEL_OVS_HOOK])]) + OVS_CHECK_LOG2_H if cmp -s datapath/linux/kcompat.h.new \ diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index f8948fa79..808ec34e2 100644 --- a/datapath/vport-netdev.c +++ b/datapath/vport-netdev.c @@ -45,6 +45,12 @@ MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets"); #define vlan_tso true #endif +#ifdef HAVE_RHEL_OVS_HOOK +static atomic_t nr_bridges = ATOMIC_INIT(0); + +extern struct sk_buff *(*openvswitch_handle_frame_hook)(struct sk_buff *skb); +#endif + static void netdev_port_receive(struct vport *vport, struct sk_buff *skb); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) @@ -63,7 +69,8 @@ static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb) return RX_HANDLER_CONSUMED; } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \ + defined HAVE_RHEL_OVS_HOOK /* Called with rcu_read_lock and bottom-halves disabled. */ static struct sk_buff *netdev_frame_hook(struct sk_buff *skb) { @@ -105,7 +112,8 @@ static int netdev_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) #error #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \ + defined HAVE_RHEL_OVS_HOOK static int netdev_init(void) { return 0; } static void netdev_exit(void) { } #else @@ -153,10 +161,16 @@ static struct vport *netdev_create(const struct vport_parms *parms) } rtnl_lock(); +#ifdef HAVE_RHEL_OVS_HOOK + rcu_assign_pointer(netdev_vport->dev->ax25_ptr, vport); + atomic_inc(&nr_bridges); + rcu_assign_pointer(openvswitch_handle_frame_hook, netdev_frame_hook); +#else err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_unlock; +#endif dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) @@ -167,7 +181,9 @@ static struct vport *netdev_create(const struct vport_parms *parms) return vport; +#ifndef HAVE_RHEL_OVS_HOOK error_unlock: +#endif rtnl_unlock(); error_put: dev_put(netdev_vport->dev); @@ -182,6 +198,12 @@ static void free_port_rcu(struct rcu_head *rcu) struct netdev_vport *netdev_vport = container_of(rcu, struct netdev_vport, rcu); +#ifdef HAVE_RHEL_OVS_HOOK + rcu_assign_pointer(netdev_vport->dev->ax25_ptr, NULL); + + if (atomic_dec_and_test(&nr_bridges)) + rcu_assign_pointer(openvswitch_handle_frame_hook, NULL); +#endif dev_put(netdev_vport->dev); ovs_vport_free(vport_from_priv(netdev_vport)); } @@ -351,13 +373,18 @@ error: /* Returns null if this device is not attached to a datapath. */ struct vport *ovs_netdev_get_vport(struct net_device *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \ + defined HAVE_RHEL_OVS_HOOK #if IFF_OVS_DATAPATH != 0 if (likely(dev->priv_flags & IFF_OVS_DATAPATH)) #else if (likely(rcu_access_pointer(dev->rx_handler) == netdev_frame_hook)) #endif +#ifdef HAVE_RHEL_OVS_HOOK + return (struct vport *)rcu_dereference_rtnl(dev->ax25_ptr); +#else return (struct vport *)rcu_dereference_rtnl(dev->rx_handler_data); +#endif else return NULL; #else @@ -377,7 +404,8 @@ const struct vport_ops ovs_netdev_vport_ops = { .send = netdev_send, }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && \ + !defined HAVE_RHEL_OVS_HOOK /* * Enforces, mutual exclusion with the Linux bridge module, by declaring and * exporting br_should_route_hook. Because the bridge module also exports the