Skip to content

Commit 0efac27

Browse files
jasowangdavem330
authored andcommitted
tap: accept an array of XDP buffs through sendmsg()
This patch implement TUN_MSG_PTR msg_control type. This type allows the caller to pass an array of XDP buffs to tuntap through ptr field of the tun_msg_control. Tap will build skb through those XDP buffers. This will avoid lots of indirect calls thus improves the icache utilization and allows to do XDP batched flushing when doing XDP redirection. Signed-off-by: Jason Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 043d222 commit 0efac27

File tree

1 file changed

+72
-2
lines changed

1 file changed

+72
-2
lines changed

drivers/net/tap.c

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,14 +1146,84 @@ static const struct file_operations tap_fops = {
11461146
#endif
11471147
};
11481148

1149+
static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
1150+
{
1151+
struct tun_xdp_hdr *hdr = xdp->data_hard_start;
1152+
struct virtio_net_hdr *gso = &hdr->gso;
1153+
int buflen = hdr->buflen;
1154+
int vnet_hdr_len = 0;
1155+
struct tap_dev *tap;
1156+
struct sk_buff *skb;
1157+
int err, depth;
1158+
1159+
if (q->flags & IFF_VNET_HDR)
1160+
vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
1161+
1162+
skb = build_skb(xdp->data_hard_start, buflen);
1163+
if (!skb) {
1164+
err = -ENOMEM;
1165+
goto err;
1166+
}
1167+
1168+
skb_reserve(skb, xdp->data - xdp->data_hard_start);
1169+
skb_put(skb, xdp->data_end - xdp->data);
1170+
1171+
skb_set_network_header(skb, ETH_HLEN);
1172+
skb_reset_mac_header(skb);
1173+
skb->protocol = eth_hdr(skb)->h_proto;
1174+
1175+
if (vnet_hdr_len) {
1176+
err = virtio_net_hdr_to_skb(skb, gso, tap_is_little_endian(q));
1177+
if (err)
1178+
goto err_kfree;
1179+
}
1180+
1181+
skb_probe_transport_header(skb, ETH_HLEN);
1182+
1183+
/* Move network header to the right position for VLAN tagged packets */
1184+
if ((skb->protocol == htons(ETH_P_8021Q) ||
1185+
skb->protocol == htons(ETH_P_8021AD)) &&
1186+
__vlan_get_protocol(skb, skb->protocol, &depth) != 0)
1187+
skb_set_network_header(skb, depth);
1188+
1189+
rcu_read_lock();
1190+
tap = rcu_dereference(q->tap);
1191+
if (tap) {
1192+
skb->dev = tap->dev;
1193+
dev_queue_xmit(skb);
1194+
} else {
1195+
kfree_skb(skb);
1196+
}
1197+
rcu_read_unlock();
1198+
1199+
return 0;
1200+
1201+
err_kfree:
1202+
kfree_skb(skb);
1203+
err:
1204+
rcu_read_lock();
1205+
tap = rcu_dereference(q->tap);
1206+
if (tap && tap->count_tx_dropped)
1207+
tap->count_tx_dropped(tap);
1208+
rcu_read_unlock();
1209+
return err;
1210+
}
1211+
11491212
static int tap_sendmsg(struct socket *sock, struct msghdr *m,
11501213
size_t total_len)
11511214
{
11521215
struct tap_queue *q = container_of(sock, struct tap_queue, sock);
11531216
struct tun_msg_ctl *ctl = m->msg_control;
1217+
struct xdp_buff *xdp;
1218+
int i;
11541219

1155-
if (ctl && ctl->type != TUN_MSG_UBUF)
1156-
return -EINVAL;
1220+
if (ctl && (ctl->type == TUN_MSG_PTR)) {
1221+
for (i = 0; i < ctl->num; i++) {
1222+
xdp = &((struct xdp_buff *)ctl->ptr)[i];
1223+
tap_get_user_xdp(q, xdp);
1224+
}
1225+
return 0;
1226+
}
11571227

11581228
return tap_get_user(q, ctl ? ctl->ptr : NULL, &m->msg_iter,
11591229
m->msg_flags & MSG_DONTWAIT);

0 commit comments

Comments
 (0)