diff options
author | Jason Wang <jasowang@redhat.com> | 2018-09-11 23:17:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-09-13 12:25:40 -0400 |
commit | 043d222f93ab8c76b56a3b315cd8692e35affb6c (patch) | |
tree | a801e9d961ce25b29b1a00603e8662735cefd525 /drivers/net/tun.c | |
parent | fe8dd45bb7556246c6b76277b1ba4296c91c2505 (diff) |
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 <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.c | 117 |
1 files changed, 114 insertions, 3 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 89779b58c7ca..2a2cd35853b7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -2426,22 +2426,133 @@ static void tun_sock_write_space(struct sock *sk) | |||
2426 | kill_fasync(&tfile->fasync, SIGIO, POLL_OUT); | 2426 | kill_fasync(&tfile->fasync, SIGIO, POLL_OUT); |
2427 | } | 2427 | } |
2428 | 2428 | ||
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 | |||
2429 | static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) | 2519 | static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) |
2430 | { | 2520 | { |
2431 | int ret; | 2521 | int ret, i; |
2432 | struct tun_file *tfile = container_of(sock, struct tun_file, socket); | 2522 | struct tun_file *tfile = container_of(sock, struct tun_file, socket); |
2433 | struct tun_struct *tun = tun_get(tfile); | 2523 | struct tun_struct *tun = tun_get(tfile); |
2434 | struct tun_msg_ctl *ctl = m->msg_control; | 2524 | struct tun_msg_ctl *ctl = m->msg_control; |
2525 | struct xdp_buff *xdp; | ||
2435 | 2526 | ||
2436 | if (!tun) | 2527 | if (!tun) |
2437 | return -EBADFD; | 2528 | return -EBADFD; |
2438 | 2529 | ||
2439 | if (ctl && ctl->type != TUN_MSG_UBUF) | 2530 | if (ctl && (ctl->type == TUN_MSG_PTR)) { |
2440 | return -EINVAL; | 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 | } | ||
2441 | 2551 | ||
2442 | ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter, | 2552 | ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter, |
2443 | m->msg_flags & MSG_DONTWAIT, | 2553 | m->msg_flags & MSG_DONTWAIT, |
2444 | m->msg_flags & MSG_MORE); | 2554 | m->msg_flags & MSG_MORE); |
2555 | out: | ||
2445 | tun_put(tun); | 2556 | tun_put(tun); |
2446 | return ret; | 2557 | return ret; |
2447 | } | 2558 | } |