Skip to content

Commit 6680ec6

Browse files
jasowangdavem330
authored andcommitted
tuntap: hardware vlan tx support
Inspired by commit f09e224 (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>
1 parent 024ec3d commit 6680ec6

File tree

1 file changed

+36
-4
lines changed

1 file changed

+36
-4
lines changed

drivers/net/tun.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include <linux/if_arp.h>
6161
#include <linux/if_ether.h>
6262
#include <linux/if_tun.h>
63+
#include <linux/if_vlan.h>
6364
#include <linux/crc32.h>
6465
#include <linux/nsproxy.h>
6566
#include <linux/virtio_net.h>
@@ -1265,6 +1266,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
12651266
{
12661267
struct tun_pi pi = { 0, skb->protocol };
12671268
ssize_t total = 0;
1269+
int vlan_offset = 0;
12681270

12691271
if (!(tun->flags & TUN_NO_PI)) {
12701272
if ((len -= sizeof(pi)) < 0)
@@ -1328,11 +1330,40 @@ static ssize_t tun_put_user(struct tun_struct *tun,
13281330
total += tun->vnet_hdr_sz;
13291331
}
13301332

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+
}
13321362

1333-
skb_copy_datagram_const_iovec(skb, 0, iv, total, len);
1334-
total += skb->len;
1363+
skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len);
1364+
total += len;
13351365

1366+
done:
13361367
tun->dev->stats.tx_packets++;
13371368
tun->dev->stats.tx_bytes += len;
13381369

@@ -1691,7 +1722,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
16911722
tun_flow_init(tun);
16921723

16931724
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;
16951727
dev->features = dev->hw_features;
16961728
dev->vlan_features = dev->features;
16971729

0 commit comments

Comments
 (0)