Skip to content

Commit 043d222

Browse files
jasowangdavem330
authored andcommitted
tuntap: 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. If an XDP program is attached, tuntap can run XDP program directly. If not, tuntap will build skb and do a fast receiving since part of the work has been done by vhost_net. 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 fe8dd45 commit 043d222

File tree

1 file changed

+114
-3
lines changed

1 file changed

+114
-3
lines changed

drivers/net/tun.c

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,22 +2426,133 @@ static void tun_sock_write_space(struct sock *sk)
24262426
kill_fasync(&tfile->fasync, SIGIO, POLL_OUT);
24272427
}
24282428

2429+
static int tun_xdp_one(struct tun_struct *tun,
2430+
struct tun_file *tfile,
2431+
struct xdp_buff *xdp, int *flush)
2432+
{
2433+
struct tun_xdp_hdr *hdr = xdp->data_hard_start;
2434+
struct virtio_net_hdr *gso = &hdr->gso;
2435+
struct tun_pcpu_stats *stats;
2436+
struct bpf_prog *xdp_prog;
2437+
struct sk_buff *skb = NULL;
2438+
u32 rxhash = 0, act;
2439+
int buflen = hdr->buflen;
2440+
int err = 0;
2441+
bool skb_xdp = false;
2442+
2443+
xdp_prog = rcu_dereference(tun->xdp_prog);
2444+
if (xdp_prog) {
2445+
if (gso->gso_type) {
2446+
skb_xdp = true;
2447+
goto build;
2448+
}
2449+
xdp_set_data_meta_invalid(xdp);
2450+
xdp->rxq = &tfile->xdp_rxq;
2451+
2452+
act = bpf_prog_run_xdp(xdp_prog, xdp);
2453+
err = tun_xdp_act(tun, xdp_prog, xdp, act);
2454+
if (err < 0) {
2455+
put_page(virt_to_head_page(xdp->data));
2456+
return err;
2457+
}
2458+
2459+
switch (err) {
2460+
case XDP_REDIRECT:
2461+
*flush = true;
2462+
/* fall through */
2463+
case XDP_TX:
2464+
return 0;
2465+
case XDP_PASS:
2466+
break;
2467+
default:
2468+
put_page(virt_to_head_page(xdp->data));
2469+
return 0;
2470+
}
2471+
}
2472+
2473+
build:
2474+
skb = build_skb(xdp->data_hard_start, buflen);
2475+
if (!skb) {
2476+
err = -ENOMEM;
2477+
goto out;
2478+
}
2479+
2480+
skb_reserve(skb, xdp->data - xdp->data_hard_start);
2481+
skb_put(skb, xdp->data_end - xdp->data);
2482+
2483+
if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {
2484+
this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
2485+
kfree_skb(skb);
2486+
err = -EINVAL;
2487+
goto out;
2488+
}
2489+
2490+
skb->protocol = eth_type_trans(skb, tun->dev);
2491+
skb_reset_network_header(skb);
2492+
skb_probe_transport_header(skb, 0);
2493+
2494+
if (skb_xdp) {
2495+
err = do_xdp_generic(xdp_prog, skb);
2496+
if (err != XDP_PASS)
2497+
goto out;
2498+
}
2499+
2500+
if (!rcu_dereference(tun->steering_prog))
2501+
rxhash = __skb_get_hash_symmetric(skb);
2502+
2503+
netif_receive_skb(skb);
2504+
2505+
stats = get_cpu_ptr(tun->pcpu_stats);
2506+
u64_stats_update_begin(&stats->syncp);
2507+
stats->rx_packets++;
2508+
stats->rx_bytes += skb->len;
2509+
u64_stats_update_end(&stats->syncp);
2510+
put_cpu_ptr(stats);
2511+
2512+
if (rxhash)
2513+
tun_flow_update(tun, rxhash, tfile);
2514+
2515+
out:
2516+
return err;
2517+
}
2518+
24292519
static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
24302520
{
2431-
int ret;
2521+
int ret, i;
24322522
struct tun_file *tfile = container_of(sock, struct tun_file, socket);
24332523
struct tun_struct *tun = tun_get(tfile);
24342524
struct tun_msg_ctl *ctl = m->msg_control;
2525+
struct xdp_buff *xdp;
24352526

24362527
if (!tun)
24372528
return -EBADFD;
24382529

2439-
if (ctl && ctl->type != TUN_MSG_UBUF)
2440-
return -EINVAL;
2530+
if (ctl && (ctl->type == TUN_MSG_PTR)) {
2531+
int n = ctl->num;
2532+
int flush = 0;
2533+
2534+
local_bh_disable();
2535+
rcu_read_lock();
2536+
2537+
for (i = 0; i < n; i++) {
2538+
xdp = &((struct xdp_buff *)ctl->ptr)[i];
2539+
tun_xdp_one(tun, tfile, xdp, &flush);
2540+
}
2541+
2542+
if (flush)
2543+
xdp_do_flush_map();
2544+
2545+
rcu_read_unlock();
2546+
local_bh_enable();
2547+
2548+
ret = total_len;
2549+
goto out;
2550+
}
24412551

24422552
ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter,
24432553
m->msg_flags & MSG_DONTWAIT,
24442554
m->msg_flags & MSG_MORE);
2555+
out:
24452556
tun_put(tun);
24462557
return ret;
24472558
}

0 commit comments

Comments
 (0)