datapath: Add vlan acceleration field for older kernels.
authorJesse Gross <jesse@nicira.com>
Fri, 31 Dec 2010 04:48:38 +0000 (20:48 -0800)
committerJesse Gross <jesse@nicira.com>
Mon, 7 Feb 2011 21:49:00 +0000 (13:49 -0800)
Kernels prior to 2.6.27 did not have a vlan_tci field in struct
sk_buff for vlan acceleration.  It's very convenient to use this
field for manipulating vlan tags, so we would like to use it as
the primary mechanism.  To enable this, this commit adds similar
infrastructure to the OVS_CB on the kernels that need it and a
set of functions to use the correct location.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
datapath/Modules.mk
datapath/datapath.h
datapath/vlan.c [new file with mode: 0644]
datapath/vlan.h [new file with mode: 0644]
datapath/vport-internal_dev.c
datapath/vport-netdev.c

index c4afae2014c243aacd14aa299d483a28c282d4e9..dbeec8fb1261b365a62abbcb8968150cc338f0e1 100644 (file)
@@ -20,6 +20,7 @@ openvswitch_sources = \
        loop_counter.c \
        table.c \
        tunnel.c \
+       vlan.c \
        vport.c \
        vport-capwap.c \
        vport-generic.c \
@@ -37,6 +38,7 @@ openvswitch_headers = \
        loop_counter.h \
        table.h \
        tunnel.h \
+       vlan.h \
        vport.h \
        vport-generic.h \
        vport-internal_dev.h \
index befa55cbe78583f73520bddd89464b66934c4a51..a7795105f37ad3fc0f6c307584eb0b0c7bcdb471 100644 (file)
@@ -22,6 +22,7 @@
 #include "checksum.h"
 #include "flow.h"
 #include "dp_sysfs.h"
+#include "vlan.h"
 
 struct vport;
 
@@ -104,6 +105,8 @@ struct datapath {
  * kernel versions.
  * @tun_id: ID of the tunnel that encapsulated this packet.  It is 0 if the
  * packet was not received on a tunnel.
+ * @vlan_tci: Provides a substitute for the skb->vlan_tci field on kernels
+ * before 2.6.27.
  */
 struct ovs_skb_cb {
        struct vport            *vport;
@@ -112,6 +115,9 @@ struct ovs_skb_cb {
        enum csum_type          ip_summed;
 #endif
        __be64                  tun_id;
+#ifdef NEED_VLAN_FIELD
+       u16                     vlan_tci;
+#endif
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
diff --git a/datapath/vlan.c b/datapath/vlan.c
new file mode 100644 (file)
index 0000000..9aebecd
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/if_vlan.h>
+#include <linux/skbuff.h>
+
+#include "datapath.h"
+#include "vlan.h"
+
+#ifdef NEED_VLAN_FIELD
+void vlan_copy_skb_tci(struct sk_buff *skb)
+{
+       OVS_CB(skb)->vlan_tci = 0;
+}
+
+u16 vlan_get_tci(struct sk_buff *skb)
+{
+       return OVS_CB(skb)->vlan_tci;
+}
+
+void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci)
+{
+       OVS_CB(skb)->vlan_tci = vlan_tci;
+}
+
+bool vlan_tx_tag_present(struct sk_buff *skb)
+{
+       return OVS_CB(skb)->vlan_tci & VLAN_TAG_PRESENT;
+}
+
+u16 vlan_tx_tag_get(struct sk_buff *skb)
+{
+       return OVS_CB(skb)->vlan_tci & ~VLAN_TAG_PRESENT;
+}
+
+struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci)
+{
+       OVS_CB(skb)->vlan_tci = vlan_tci | VLAN_TAG_PRESENT;
+       return skb;
+}
+#endif /* NEED_VLAN_FIELD */
diff --git a/datapath/vlan.h b/datapath/vlan.h
new file mode 100644 (file)
index 0000000..dc90018
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#ifndef VLAN_H
+#define VLAN_H 1
+
+#include <linux/if_vlan.h>
+#include <linux/skbuff.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+#define NEED_VLAN_FIELD
+#endif
+
+#ifndef NEED_VLAN_FIELD
+static inline void vlan_copy_skb_tci(struct sk_buff *skb) { }
+
+static inline u16 vlan_get_tci(struct sk_buff *skb)
+{
+       return skb->vlan_tci;
+}
+
+static inline void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci)
+{
+       skb->vlan_tci = vlan_tci;
+}
+#else
+void vlan_copy_skb_tci(struct sk_buff *skb);
+u16 vlan_get_tci(struct sk_buff *skb);
+void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci);
+
+#undef vlan_tx_tag_present
+bool vlan_tx_tag_present(struct sk_buff *skb);
+
+#undef vlan_tx_tag_get
+u16 vlan_tx_tag_get(struct sk_buff *skb);
+
+#define __vlan_hwaccel_put_tag rpl__vlan_hwaccel_put_tag
+struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci);
+#endif /* NEED_VLAN_FIELD */
+#endif /* vlan.h */
index 1df61801179a0871f46072dbfce71a236f5cf7ce..be2907454ebe5fe4870522036d1884f76326829f 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "checksum.h"
 #include "datapath.h"
+#include "vlan.h"
 #include "vport-generic.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
@@ -72,6 +73,7 @@ static int internal_dev_mac_addr(struct net_device *dev, void *p)
 static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        compute_ip_summed(skb, true);
+       vlan_copy_skb_tci(skb);
        OVS_CB(skb)->flow = NULL;
 
        vport_receive(internal_dev_priv(netdev)->vport, skb);
index e45e22fbb870e87fa0d974c413515673aefaaa9f..85e0eb9a26a259b8ad662fa0e6717bd033230abb 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "checksum.h"
 #include "datapath.h"
+#include "vlan.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
@@ -252,6 +253,7 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
 
        skb_push(skb, ETH_HLEN);
        compute_ip_summed(skb, false);
+       vlan_copy_skb_tci(skb);
 
        vport_receive(vport, skb);
 }