diff options
| author | Ben Pfaff <blp@nicira.com> | 2011-03-16 14:39:17 -0700 |
|---|---|---|
| committer | Ben Pfaff <blp@nicira.com> | 2011-03-16 14:39:17 -0700 |
| commit | 431488e6638d3fbb53d215fa10d2ff2d8f1c2824 (patch) | |
| tree | 0bf2a0c44cd5fbd2fa3718acaab4b5d8e91644ef /datapath | |
| parent | 21dcb94fd5fbfda3b281cfcf124ab57802d77c23 (diff) | |
| download | openvswitch-431488e6638d3fbb53d215fa10d2ff2d8f1c2824.tar.gz | |
Support vlan_group workaround implemented in XenServer kernels.
Some Linux network drivers support a feature called "VLAN acceleration",
associated with a data structure called a "vlan_group". A vlan_group is,
abstractly, a dictionary that maps from a VLAN ID (in the range 0...4095)
to a VLAN device, that is, a Linux network device associated with a
particular VLAN, e.g. "eth0.9" for VLAN 9 on eth0.
Some drivers that support VLAN acceleration have bugs that fall roughly
into the following categories:
* Some NICs strip VLAN tags on receive if no vlan_group is registered,
so that the tag is completely lost.
* Some drivers size their receive buffers based on whether a vlan_group
is enabled, meaning that a maximum size packet with a VLAN tag will
not fit if a vlan_group is not configured.
* On transmit some drivers expect that VLAN acceleration will be used
if it is available (which can only be done if a vlan_group is
configured). In these cases, the driver may fail to parse the packet
and correctly setup checksum offloading and/or TSO.
The correct long term solution is to fix these driver bugs. To cope until
then, we have prepared a patch to the Linux kernel network stack that works
around these problems. This commit adds support for the workaround
implemented by that patch.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'datapath')
| -rw-r--r-- | datapath/vport-netdev.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index 11faf8ad1..2583566b1 100644 --- a/datapath/vport-netdev.c +++ b/datapath/vport-netdev.c @@ -22,12 +22,15 @@ #include "vport-internal_dev.h" #include "vport-netdev.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \ + !defined(HAVE_VLAN_BUG_WORKAROUND) #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"); +#else +#define vlan_tso true #endif /* If the native device stats aren't 64 bit use the vport stats tracking instead. */ @@ -266,6 +269,19 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) vport_receive(vport, skb); } +static bool dev_supports_vlan_tx(struct net_device *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) + /* Software fallback means every device supports vlan_tci on TX. */ + return true; +#elif defined(HAVE_VLAN_BUG_WORKAROUND) + return dev->features & NETIF_F_HW_VLAN_TX; +#else + /* Assume that the driver is buggy. */ + return false; +#endif +} + static int netdev_send(struct vport *vport, struct sk_buff *skb) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); @@ -274,8 +290,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb) skb->dev = netdev_vport->dev; forward_ip_summed(skb); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) - if (vlan_tx_tag_present(skb)) { + if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) { int err; int features = 0; @@ -339,7 +354,6 @@ tag: return 0; vlan_set_tci(skb, 0); } -#endif len = skb->len; dev_queue_xmit(skb); |
