[ovs-dev] [PATCH 4/4] datapath: Add module parameter to allow TSO with vlans.

Jesse Gross jesse at nicira.com
Sun Feb 6 00:14:49 UTC 2011


We currently perform GSO on packets before adding a vlan tag,
which is reliable but hurts performance.  Even NICs that support
TSO on vlan tagged packets typically expect vlan acceleration to
be used.  Before 2.6.37 we can't use vlan acceleration and must
place the tag in the packet itself, which is risky when used with
TSO.  However, if the driver is known to work with internally
tagged packets and TSO this exposes a module parameter to enable it.

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 datapath/vport-netdev.c |   37 +++++++++++++++++++++++++++++++------
 1 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index 23ec1a5..6a165b0 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -22,6 +22,14 @@
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#include <linux/module.h>
+
+static int vlan_tso __read_mostly = 0;
+module_param(vlan_tso, int, 0644);
+MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets");
+#endif
+
 /* 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))
 
@@ -269,6 +277,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
 	if (vlan_tx_tag_present(skb)) {
 		int err;
+		int features = skb->dev->features & skb->dev->vlan_features;
 
 		err = vswitch_skb_checksum_setup(skb);
 		if (unlikely(err)) {
@@ -276,10 +285,25 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
 			return 0;
 		}
 
-		if (skb_is_gso(skb)) {
+		if (!vlan_tso)
+			features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
+				      NETIF_F_UFO | NETIF_F_FSO);
+
+		if (skb_is_gso(skb) &&
+		    (!skb_gso_ok(skb, features) ||
+		     unlikely(skb->ip_summed != CHECKSUM_PARTIAL))) {
 			struct sk_buff *nskb;
 
-			nskb = skb_gso_segment(skb, 0);
+			nskb = skb_gso_segment(skb, features);
+			if (!nskb) {
+				if (unlikely(skb_cloned(skb) &&
+				    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+					return 0;
+
+				skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY;
+				goto tag;
+			}
+
 			kfree_skb(skb);
 			skb = nskb;
 			if (IS_ERR(skb))
@@ -300,11 +324,12 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
 			} while (skb);
 
 			return len;
-		} else {
-			skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
-			if (unlikely(!skb))
-				return 0;
 		}
+
+tag:
+		skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+		if (unlikely(!skb))
+			return 0;
 	}
 #endif
 
-- 
1.7.1





More information about the dev mailing list