From 3f6256afdcf7021b0ce85dfe0c4afb62b967bef4 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 30 Dec 2010 12:28:10 -0800 Subject: [PATCH] datapath: Add module parameter to allow TSO with vlans. 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 Acked-by: Ben Pfaff --- INSTALL.Linux | 11 +++++++++++ datapath/vport-netdev.c | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/INSTALL.Linux b/INSTALL.Linux index e950c0519..f80e1c645 100644 --- a/INSTALL.Linux +++ b/INSTALL.Linux @@ -227,6 +227,17 @@ Prerequisites section, follow the procedure below to build. module loading, please include the output from the "dmesg" and "modinfo" commands mentioned above. + There is an optional module parameter to openvswitch_mod.ko called + vlan_tso that enables TCP segmentation offload over VLANs on NICs + that support it. Many drivers do not expose support for TSO on VLANs + in a way that Open vSwitch can use but there is no way to detect + whether this is the case. If you know that your particular driver can + handle it (for example by testing sending large TCP packets over VLANs) + then passing in a value of 1 may improve performance. Modules built for + Linux kernels 2.6.37 and later do not need this and do not have this + parameter. If you do not understand what this means or do not know if + your driver will work, do not set this. + 7. Initialize the configuration database using ovsdb-tool, e.g.: % ovsdb-tool create /usr/local/etc/ovs-vswitchd.conf.db vswitchd/vswitch.ovsschema diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index 3693004c6..21fa6a0e1 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 + +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,27 @@ 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))) { + kfree_skb(skb); + return 0; + } + + skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY; + goto tag; + } + kfree_skb(skb); skb = nskb; if (IS_ERR(skb)) @@ -301,12 +327,13 @@ 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; - vlan_set_tci(skb, 0); } + +tag: + skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb)); + if (unlikely(!skb)) + return 0; + vlan_set_tci(skb, 0); } #endif -- 2.43.0