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 c4afae2..dbeec8f 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 befa55c..a779510 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 1df6180..be29074 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 e45e22f..85e0eb9 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);
 }