datapath: Simplify vport-netdev-hook compatibility code.
[sliver-openvswitch.git] / datapath / linux / compat / dev-openvswitch.c
index 5b7444b..1035fe8 100644 (file)
@@ -1,6 +1,8 @@
-#ifndef HAVE_DEV_DISABLE_LRO
-
+#include <linux/if_bridge.h>
 #include <linux/netdevice.h>
+#include <linux/version.h>
+
+#ifndef HAVE_DEV_DISABLE_LRO
 
 #ifdef NETIF_F_LRO
 #include <linux/ethtool.h>
@@ -30,3 +32,60 @@ void dev_disable_lro(struct net_device *dev) { }
 #endif /* NETIF_F_LRO */
 
 #endif /* HAVE_DEV_DISABLE_LRO */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) || \
+    defined HAVE_RHEL_OVS_HOOK
+
+static int nr_bridges;
+
+#ifdef HAVE_RHEL_OVS_HOOK
+int netdev_rx_handler_register(struct net_device *dev,
+                              openvswitch_handle_frame_hook_t *hook,
+                              void *rx_handler_data)
+{
+       nr_bridges++;
+       rcu_assign_pointer(dev->ax25_ptr, rx_handler_data);
+
+       if (nr_bridges == 1)
+               rcu_assign_pointer(openvswitch_handle_frame_hook, hook);
+       return 0;
+}
+#else
+
+int netdev_rx_handler_register(struct net_device *dev,
+                              struct sk_buff *(*hook)(struct net_bridge_port *p,
+                                                      struct sk_buff *skb),
+                              void *rx_handler_data)
+{
+       nr_bridges++;
+       if (dev->br_port)
+               return -EBUSY;
+
+       rcu_assign_pointer(dev->br_port, rx_handler_data);
+
+       if (nr_bridges == 1)
+               br_handle_frame_hook = hook;
+       return 0;
+}
+#endif
+
+void netdev_rx_handler_unregister(struct net_device *dev)
+{
+       nr_bridges--;
+#ifdef HAVE_RHEL_OVS_HOOK
+       rcu_assign_pointer(dev->ax25_ptr, NULL);
+
+       if (nr_bridges)
+               return;
+
+       rcu_assign_pointer(openvswitch_handle_frame_hook, NULL);
+#else
+       rcu_assign_pointer(dev->br_port, NULL);
+
+       if (nr_bridges)
+               return;
+
+       br_handle_frame_hook = NULL;
+#endif
+}
+#endif