aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-07-25 01:00:33 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-27 23:09:21 -0400
commit6680ec68eff47d36f67b4351bc9836fd6cba9532 (patch)
tree63966849a766004bb64fbc409d808ad8b5fe8bd4 /drivers/net/tun.c
parent024ec3deac33ddbd81f3c887506f132b24ea21a7 (diff)
tuntap: hardware vlan tx support
Inspired by commit f09e2249c4f5c7c13261ec73f5a7807076af0c8e (macvtap: restore vlan header on user read). This patch adds hardware vlan tx support for tuntap. This is done by copying vlan header directly into userspace in tun_put_user() instead of doing it through __vlan_put_tag() in dev_hard_start_xmit(). This eliminates one unnecessary memmove() in vlan_insert_tag() for 802.1ad and 802.1q traffic. pktgen test shows about 20% improvement for 802.1q traffic: Before: 662149pps 317Mb/sec (317831520bps) errors: 0 After: 801033pps 384Mb/sec (384495840bps) errors: 0 Cc: Basil Gor <basil.gor@gmail.com> Cc: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a72d141047cb..5dce262f538e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -60,6 +60,7 @@
60#include <linux/if_arp.h> 60#include <linux/if_arp.h>
61#include <linux/if_ether.h> 61#include <linux/if_ether.h>
62#include <linux/if_tun.h> 62#include <linux/if_tun.h>
63#include <linux/if_vlan.h>
63#include <linux/crc32.h> 64#include <linux/crc32.h>
64#include <linux/nsproxy.h> 65#include <linux/nsproxy.h>
65#include <linux/virtio_net.h> 66#include <linux/virtio_net.h>
@@ -1265,6 +1266,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1265{ 1266{
1266 struct tun_pi pi = { 0, skb->protocol }; 1267 struct tun_pi pi = { 0, skb->protocol };
1267 ssize_t total = 0; 1268 ssize_t total = 0;
1269 int vlan_offset = 0;
1268 1270
1269 if (!(tun->flags & TUN_NO_PI)) { 1271 if (!(tun->flags & TUN_NO_PI)) {
1270 if ((len -= sizeof(pi)) < 0) 1272 if ((len -= sizeof(pi)) < 0)
@@ -1328,11 +1330,40 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1328 total += tun->vnet_hdr_sz; 1330 total += tun->vnet_hdr_sz;
1329 } 1331 }
1330 1332
1331 len = min_t(int, skb->len, len); 1333 if (!vlan_tx_tag_present(skb)) {
1334 len = min_t(int, skb->len, len);
1335 } else {
1336 int copy, ret;
1337 struct {
1338 __be16 h_vlan_proto;
1339 __be16 h_vlan_TCI;
1340 } veth;
1341
1342 veth.h_vlan_proto = skb->vlan_proto;
1343 veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
1344
1345 vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
1346 len = min_t(int, skb->len + VLAN_HLEN, len);
1347
1348 copy = min_t(int, vlan_offset, len);
1349 ret = skb_copy_datagram_const_iovec(skb, 0, iv, total, copy);
1350 len -= copy;
1351 total += copy;
1352 if (ret || !len)
1353 goto done;
1354
1355 copy = min_t(int, sizeof(veth), len);
1356 ret = memcpy_toiovecend(iv, (void *)&veth, total, copy);
1357 len -= copy;
1358 total += copy;
1359 if (ret || !len)
1360 goto done;
1361 }
1332 1362
1333 skb_copy_datagram_const_iovec(skb, 0, iv, total, len); 1363 skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len);
1334 total += skb->len; 1364 total += len;
1335 1365
1366done:
1336 tun->dev->stats.tx_packets++; 1367 tun->dev->stats.tx_packets++;
1337 tun->dev->stats.tx_bytes += len; 1368 tun->dev->stats.tx_bytes += len;
1338 1369
@@ -1691,7 +1722,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
1691 tun_flow_init(tun); 1722 tun_flow_init(tun);
1692 1723
1693 dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | 1724 dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
1694 TUN_USER_FEATURES; 1725 TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
1726 NETIF_F_HW_VLAN_STAG_TX;
1695 dev->features = dev->hw_features; 1727 dev->features = dev->hw_features;
1696 dev->vlan_features = dev->features; 1728 dev->vlan_features = dev->features;
1697 1729