datapath: dont use non-existent receive hooks
authorSimon Horman <horms@verge.net.au>
Mon, 23 Aug 2010 06:30:06 +0000 (15:30 +0900)
committerJesse Gross <jesse@nicira.com>
Mon, 23 Aug 2010 18:37:44 +0000 (14:37 -0400)
This adds compatibility with kernel changeset
of changeset "net: add rx_handler data pointer"
and thus "net: replace hooks in __netif_receive_skb V5",
which were added between 2.6.35 and 2.6.36-rc1

Signed-off-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Jesse Gross <jesse@nicira.com>
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h
datapath/vport-netdev.c

index 1e354e72740464279f74bada3d5aea7a229512e8..379c1a9c70b16fe65c7668d511acb05e1ec443b9 100644 (file)
@@ -89,4 +89,14 @@ dev_get_stats(struct net_device *dev)
 #define skb_checksum_help(skb) skb_checksum_help((skb), 0)
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
+static inline int netdev_rx_handler_register(struct net_device *dev,
+                                            void *rx_handler,
+                                            void *rx_handler_data)
+{
+       return 0;
+}
+static inline void netdev_rx_handler_unregister(struct net_device *dev) { }
+#endif
+
 #endif
index 1773a09b98ce6418062b3220fd9b1d741be71300..a85a9b5fa557c092427af27493b627ee5e3079f0 100644 (file)
 /* If the native device stats aren't 64 bit use the vport stats tracking instead. */
 #define USE_VPORT_STATS (sizeof(((struct net_device_stats *)0)->rx_bytes) < sizeof(u64))
 
-static void netdev_port_receive(struct net_bridge_port *, struct sk_buff *);
+static void netdev_port_receive(struct vport *vport, struct sk_buff *skb);
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+/* Called with rcu_read_lock and bottom-halves disabled. */
+static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
+{
+       struct vport *vport;
+
+       if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
+               return skb;
+
+       vport = (struct vport *)rcu_dereference(skb->dev->br_port);
+
+       netdev_port_receive(vport, skb);
+
+       return NULL;
+}
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
 /*
  * Used as br_handle_frame_hook.  (Cannot run bridge at the same time, even on
  * different set of devices!)
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
 /* Called with rcu_read_lock and bottom-halves disabled. */
 static struct sk_buff *netdev_frame_hook(struct net_bridge_port *p,
                                         struct sk_buff *skb)
 {
-       netdev_port_receive(p, skb);
+       netdev_port_receive((struct vport *)p, skb);
        return NULL;
 }
 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+/*
+ * Used as br_handle_frame_hook.  (Cannot run bridge at the same time, even on
+ * different set of devices!)
+ */
 /* Called with rcu_read_lock and bottom-halves disabled. */
 static int netdev_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb)
 {
-       netdev_port_receive(p, *pskb);
+       netdev_port_receive((struct vport *)p, *pskb);
        return 1;
 }
 #else
 #error
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+static int netdev_init(void) { return 0; }
+static void netdev_exit(void) { }
+#else
 static int netdev_init(void)
 {
        /* Hook into callback used by the bridge to intercept packets.
@@ -63,6 +86,7 @@ static void netdev_exit(void)
 {
        br_handle_frame_hook = NULL;
 }
+#endif
 
 static struct vport *netdev_create(const char *name, const void __user *config)
 {
@@ -129,10 +153,17 @@ static int netdev_destroy(struct vport *vport)
 static int netdev_attach(struct vport *vport)
 {
        struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+       int err;
+
+       rcu_assign_pointer(netdev_vport->dev->br_port,
+                          (struct net_bridge_port *)vport);
+       err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook,
+                                        NULL);
+       if (err)
+               return err;
 
        dev_set_promiscuity(netdev_vport->dev, 1);
        dev_disable_lro(netdev_vport->dev);
-       rcu_assign_pointer(netdev_vport->dev->br_port, (struct net_bridge_port *)vport);
 
        return 0;
 }
@@ -141,6 +172,7 @@ static int netdev_detach(struct vport *vport)
 {
        struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
 
+       netdev_rx_handler_unregister(netdev_vport->dev);
        rcu_assign_pointer(netdev_vport->dev->br_port, NULL);
        dev_set_promiscuity(netdev_vport->dev, -1);
 
@@ -242,10 +274,8 @@ int netdev_get_mtu(const struct vport *vport)
 }
 
 /* Must be called with rcu_read_lock. */
-static void netdev_port_receive(struct net_bridge_port *p, struct sk_buff *skb)
+static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
 {
-       struct vport *vport = (struct vport *)p;
-
        /* Make our own copy of the packet.  Otherwise we will mangle the
         * packet for anyone who came before us (e.g. tcpdump via AF_PACKET).
         * (No one comes after us, since we tell handle_bridge() that we took