diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
| -rw-r--r-- | drivers/net/virtio_net.c | 171 |
1 files changed, 124 insertions, 47 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8fadd8eaf601..4cfceb789eea 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
| @@ -57,6 +57,8 @@ module_param(napi_tx, bool, 0644); | |||
| 57 | #define VIRTIO_XDP_TX BIT(0) | 57 | #define VIRTIO_XDP_TX BIT(0) |
| 58 | #define VIRTIO_XDP_REDIR BIT(1) | 58 | #define VIRTIO_XDP_REDIR BIT(1) |
| 59 | 59 | ||
| 60 | #define VIRTIO_XDP_FLAG BIT(0) | ||
| 61 | |||
| 60 | /* RX packet size EWMA. The average packet size is used to determine the packet | 62 | /* RX packet size EWMA. The average packet size is used to determine the packet |
| 61 | * buffer size when refilling RX rings. As the entire RX ring may be refilled | 63 | * buffer size when refilling RX rings. As the entire RX ring may be refilled |
| 62 | * at once, the weight is chosen so that the EWMA will be insensitive to short- | 64 | * at once, the weight is chosen so that the EWMA will be insensitive to short- |
| @@ -252,6 +254,21 @@ struct padded_vnet_hdr { | |||
| 252 | char padding[4]; | 254 | char padding[4]; |
| 253 | }; | 255 | }; |
| 254 | 256 | ||
| 257 | static bool is_xdp_frame(void *ptr) | ||
| 258 | { | ||
| 259 | return (unsigned long)ptr & VIRTIO_XDP_FLAG; | ||
| 260 | } | ||
| 261 | |||
| 262 | static void *xdp_to_ptr(struct xdp_frame *ptr) | ||
| 263 | { | ||
| 264 | return (void *)((unsigned long)ptr | VIRTIO_XDP_FLAG); | ||
| 265 | } | ||
| 266 | |||
| 267 | static struct xdp_frame *ptr_to_xdp(void *ptr) | ||
| 268 | { | ||
| 269 | return (struct xdp_frame *)((unsigned long)ptr & ~VIRTIO_XDP_FLAG); | ||
| 270 | } | ||
| 271 | |||
| 255 | /* Converting between virtqueue no. and kernel tx/rx queue no. | 272 | /* Converting between virtqueue no. and kernel tx/rx queue no. |
| 256 | * 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq | 273 | * 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq |
| 257 | */ | 274 | */ |
| @@ -462,7 +479,8 @@ static int __virtnet_xdp_xmit_one(struct virtnet_info *vi, | |||
| 462 | 479 | ||
| 463 | sg_init_one(sq->sg, xdpf->data, xdpf->len); | 480 | sg_init_one(sq->sg, xdpf->data, xdpf->len); |
| 464 | 481 | ||
| 465 | err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdpf, GFP_ATOMIC); | 482 | err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdp_to_ptr(xdpf), |
| 483 | GFP_ATOMIC); | ||
| 466 | if (unlikely(err)) | 484 | if (unlikely(err)) |
| 467 | return -ENOSPC; /* Caller handle free/refcnt */ | 485 | return -ENOSPC; /* Caller handle free/refcnt */ |
| 468 | 486 | ||
| @@ -482,36 +500,47 @@ static int virtnet_xdp_xmit(struct net_device *dev, | |||
| 482 | { | 500 | { |
| 483 | struct virtnet_info *vi = netdev_priv(dev); | 501 | struct virtnet_info *vi = netdev_priv(dev); |
| 484 | struct receive_queue *rq = vi->rq; | 502 | struct receive_queue *rq = vi->rq; |
| 485 | struct xdp_frame *xdpf_sent; | ||
| 486 | struct bpf_prog *xdp_prog; | 503 | struct bpf_prog *xdp_prog; |
| 487 | struct send_queue *sq; | 504 | struct send_queue *sq; |
| 488 | unsigned int len; | 505 | unsigned int len; |
| 506 | int packets = 0; | ||
| 507 | int bytes = 0; | ||
| 489 | int drops = 0; | 508 | int drops = 0; |
| 490 | int kicks = 0; | 509 | int kicks = 0; |
| 491 | int ret, err; | 510 | int ret, err; |
| 511 | void *ptr; | ||
| 492 | int i; | 512 | int i; |
| 493 | 513 | ||
| 494 | sq = virtnet_xdp_sq(vi); | ||
| 495 | |||
| 496 | if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) { | ||
| 497 | ret = -EINVAL; | ||
| 498 | drops = n; | ||
| 499 | goto out; | ||
| 500 | } | ||
| 501 | |||
| 502 | /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this | 514 | /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this |
| 503 | * indicate XDP resources have been successfully allocated. | 515 | * indicate XDP resources have been successfully allocated. |
| 504 | */ | 516 | */ |
| 505 | xdp_prog = rcu_dereference(rq->xdp_prog); | 517 | xdp_prog = rcu_dereference(rq->xdp_prog); |
| 506 | if (!xdp_prog) { | 518 | if (!xdp_prog) |
| 507 | ret = -ENXIO; | 519 | return -ENXIO; |
| 520 | |||
| 521 | sq = virtnet_xdp_sq(vi); | ||
| 522 | |||
| 523 | if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) { | ||
| 524 | ret = -EINVAL; | ||
| 508 | drops = n; | 525 | drops = n; |
| 509 | goto out; | 526 | goto out; |
| 510 | } | 527 | } |
| 511 | 528 | ||
| 512 | /* Free up any pending old buffers before queueing new ones. */ | 529 | /* Free up any pending old buffers before queueing new ones. */ |
| 513 | while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) | 530 | while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) { |
| 514 | xdp_return_frame(xdpf_sent); | 531 | if (likely(is_xdp_frame(ptr))) { |
| 532 | struct xdp_frame *frame = ptr_to_xdp(ptr); | ||
| 533 | |||
| 534 | bytes += frame->len; | ||
| 535 | xdp_return_frame(frame); | ||
| 536 | } else { | ||
| 537 | struct sk_buff *skb = ptr; | ||
| 538 | |||
| 539 | bytes += skb->len; | ||
| 540 | napi_consume_skb(skb, false); | ||
| 541 | } | ||
| 542 | packets++; | ||
| 543 | } | ||
| 515 | 544 | ||
| 516 | for (i = 0; i < n; i++) { | 545 | for (i = 0; i < n; i++) { |
| 517 | struct xdp_frame *xdpf = frames[i]; | 546 | struct xdp_frame *xdpf = frames[i]; |
| @@ -530,6 +559,8 @@ static int virtnet_xdp_xmit(struct net_device *dev, | |||
| 530 | } | 559 | } |
| 531 | out: | 560 | out: |
| 532 | u64_stats_update_begin(&sq->stats.syncp); | 561 | u64_stats_update_begin(&sq->stats.syncp); |
| 562 | sq->stats.bytes += bytes; | ||
| 563 | sq->stats.packets += packets; | ||
| 533 | sq->stats.xdp_tx += n; | 564 | sq->stats.xdp_tx += n; |
| 534 | sq->stats.xdp_tx_drops += drops; | 565 | sq->stats.xdp_tx_drops += drops; |
| 535 | sq->stats.kicks += kicks; | 566 | sq->stats.kicks += kicks; |
| @@ -1332,18 +1363,26 @@ static int virtnet_receive(struct receive_queue *rq, int budget, | |||
| 1332 | 1363 | ||
| 1333 | static void free_old_xmit_skbs(struct send_queue *sq, bool in_napi) | 1364 | static void free_old_xmit_skbs(struct send_queue *sq, bool in_napi) |
| 1334 | { | 1365 | { |
| 1335 | struct sk_buff *skb; | ||
| 1336 | unsigned int len; | 1366 | unsigned int len; |
| 1337 | unsigned int packets = 0; | 1367 | unsigned int packets = 0; |
| 1338 | unsigned int bytes = 0; | 1368 | unsigned int bytes = 0; |
| 1369 | void *ptr; | ||
| 1339 | 1370 | ||
| 1340 | while ((skb = virtqueue_get_buf(sq->vq, &len)) != NULL) { | 1371 | while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) { |
| 1341 | pr_debug("Sent skb %p\n", skb); | 1372 | if (likely(!is_xdp_frame(ptr))) { |
| 1373 | struct sk_buff *skb = ptr; | ||
| 1342 | 1374 | ||
| 1343 | bytes += skb->len; | 1375 | pr_debug("Sent skb %p\n", skb); |
| 1344 | packets++; | 1376 | |
| 1377 | bytes += skb->len; | ||
| 1378 | napi_consume_skb(skb, in_napi); | ||
| 1379 | } else { | ||
| 1380 | struct xdp_frame *frame = ptr_to_xdp(ptr); | ||
| 1345 | 1381 | ||
| 1346 | napi_consume_skb(skb, in_napi); | 1382 | bytes += frame->len; |
| 1383 | xdp_return_frame(frame); | ||
| 1384 | } | ||
| 1385 | packets++; | ||
| 1347 | } | 1386 | } |
| 1348 | 1387 | ||
| 1349 | /* Avoid overhead when no packets have been processed | 1388 | /* Avoid overhead when no packets have been processed |
| @@ -1358,6 +1397,16 @@ static void free_old_xmit_skbs(struct send_queue *sq, bool in_napi) | |||
| 1358 | u64_stats_update_end(&sq->stats.syncp); | 1397 | u64_stats_update_end(&sq->stats.syncp); |
| 1359 | } | 1398 | } |
| 1360 | 1399 | ||
| 1400 | static bool is_xdp_raw_buffer_queue(struct virtnet_info *vi, int q) | ||
| 1401 | { | ||
| 1402 | if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs)) | ||
| 1403 | return false; | ||
| 1404 | else if (q < vi->curr_queue_pairs) | ||
| 1405 | return true; | ||
| 1406 | else | ||
| 1407 | return false; | ||
| 1408 | } | ||
| 1409 | |||
| 1361 | static void virtnet_poll_cleantx(struct receive_queue *rq) | 1410 | static void virtnet_poll_cleantx(struct receive_queue *rq) |
| 1362 | { | 1411 | { |
| 1363 | struct virtnet_info *vi = rq->vq->vdev->priv; | 1412 | struct virtnet_info *vi = rq->vq->vdev->priv; |
| @@ -1365,7 +1414,7 @@ static void virtnet_poll_cleantx(struct receive_queue *rq) | |||
| 1365 | struct send_queue *sq = &vi->sq[index]; | 1414 | struct send_queue *sq = &vi->sq[index]; |
| 1366 | struct netdev_queue *txq = netdev_get_tx_queue(vi->dev, index); | 1415 | struct netdev_queue *txq = netdev_get_tx_queue(vi->dev, index); |
| 1367 | 1416 | ||
| 1368 | if (!sq->napi.weight) | 1417 | if (!sq->napi.weight || is_xdp_raw_buffer_queue(vi, index)) |
| 1369 | return; | 1418 | return; |
| 1370 | 1419 | ||
| 1371 | if (__netif_tx_trylock(txq)) { | 1420 | if (__netif_tx_trylock(txq)) { |
| @@ -1442,8 +1491,16 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) | |||
| 1442 | { | 1491 | { |
| 1443 | struct send_queue *sq = container_of(napi, struct send_queue, napi); | 1492 | struct send_queue *sq = container_of(napi, struct send_queue, napi); |
| 1444 | struct virtnet_info *vi = sq->vq->vdev->priv; | 1493 | struct virtnet_info *vi = sq->vq->vdev->priv; |
| 1445 | struct netdev_queue *txq = netdev_get_tx_queue(vi->dev, vq2txq(sq->vq)); | 1494 | unsigned int index = vq2txq(sq->vq); |
| 1495 | struct netdev_queue *txq; | ||
| 1446 | 1496 | ||
| 1497 | if (unlikely(is_xdp_raw_buffer_queue(vi, index))) { | ||
| 1498 | /* We don't need to enable cb for XDP */ | ||
| 1499 | napi_complete_done(napi, 0); | ||
| 1500 | return 0; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | txq = netdev_get_tx_queue(vi->dev, index); | ||
| 1447 | __netif_tx_lock(txq, raw_smp_processor_id()); | 1504 | __netif_tx_lock(txq, raw_smp_processor_id()); |
| 1448 | free_old_xmit_skbs(sq, true); | 1505 | free_old_xmit_skbs(sq, true); |
| 1449 | __netif_tx_unlock(txq); | 1506 | __netif_tx_unlock(txq); |
| @@ -2395,6 +2452,10 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, | |||
| 2395 | return -ENOMEM; | 2452 | return -ENOMEM; |
| 2396 | } | 2453 | } |
| 2397 | 2454 | ||
| 2455 | old_prog = rtnl_dereference(vi->rq[0].xdp_prog); | ||
| 2456 | if (!prog && !old_prog) | ||
| 2457 | return 0; | ||
| 2458 | |||
| 2398 | if (prog) { | 2459 | if (prog) { |
| 2399 | prog = bpf_prog_add(prog, vi->max_queue_pairs - 1); | 2460 | prog = bpf_prog_add(prog, vi->max_queue_pairs - 1); |
| 2400 | if (IS_ERR(prog)) | 2461 | if (IS_ERR(prog)) |
| @@ -2402,36 +2463,62 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, | |||
| 2402 | } | 2463 | } |
| 2403 | 2464 | ||
| 2404 | /* Make sure NAPI is not using any XDP TX queues for RX. */ | 2465 | /* Make sure NAPI is not using any XDP TX queues for RX. */ |
| 2405 | if (netif_running(dev)) | 2466 | if (netif_running(dev)) { |
| 2406 | for (i = 0; i < vi->max_queue_pairs; i++) | 2467 | for (i = 0; i < vi->max_queue_pairs; i++) { |
| 2407 | napi_disable(&vi->rq[i].napi); | 2468 | napi_disable(&vi->rq[i].napi); |
| 2469 | virtnet_napi_tx_disable(&vi->sq[i].napi); | ||
| 2470 | } | ||
| 2471 | } | ||
| 2472 | |||
| 2473 | if (!prog) { | ||
| 2474 | for (i = 0; i < vi->max_queue_pairs; i++) { | ||
| 2475 | rcu_assign_pointer(vi->rq[i].xdp_prog, prog); | ||
| 2476 | if (i == 0) | ||
| 2477 | virtnet_restore_guest_offloads(vi); | ||
| 2478 | } | ||
| 2479 | synchronize_net(); | ||
| 2480 | } | ||
| 2408 | 2481 | ||
| 2409 | netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp); | ||
| 2410 | err = _virtnet_set_queues(vi, curr_qp + xdp_qp); | 2482 | err = _virtnet_set_queues(vi, curr_qp + xdp_qp); |
| 2411 | if (err) | 2483 | if (err) |
| 2412 | goto err; | 2484 | goto err; |
| 2485 | netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp); | ||
| 2413 | vi->xdp_queue_pairs = xdp_qp; | 2486 | vi->xdp_queue_pairs = xdp_qp; |
| 2414 | 2487 | ||
| 2415 | for (i = 0; i < vi->max_queue_pairs; i++) { | 2488 | if (prog) { |
| 2416 | old_prog = rtnl_dereference(vi->rq[i].xdp_prog); | 2489 | for (i = 0; i < vi->max_queue_pairs; i++) { |
| 2417 | rcu_assign_pointer(vi->rq[i].xdp_prog, prog); | 2490 | rcu_assign_pointer(vi->rq[i].xdp_prog, prog); |
| 2418 | if (i == 0) { | 2491 | if (i == 0 && !old_prog) |
| 2419 | if (!old_prog) | ||
| 2420 | virtnet_clear_guest_offloads(vi); | 2492 | virtnet_clear_guest_offloads(vi); |
| 2421 | if (!prog) | ||
| 2422 | virtnet_restore_guest_offloads(vi); | ||
| 2423 | } | 2493 | } |
| 2494 | } | ||
| 2495 | |||
| 2496 | for (i = 0; i < vi->max_queue_pairs; i++) { | ||
| 2424 | if (old_prog) | 2497 | if (old_prog) |
| 2425 | bpf_prog_put(old_prog); | 2498 | bpf_prog_put(old_prog); |
| 2426 | if (netif_running(dev)) | 2499 | if (netif_running(dev)) { |
| 2427 | virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); | 2500 | virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); |
| 2501 | virtnet_napi_tx_enable(vi, vi->sq[i].vq, | ||
| 2502 | &vi->sq[i].napi); | ||
| 2503 | } | ||
| 2428 | } | 2504 | } |
| 2429 | 2505 | ||
| 2430 | return 0; | 2506 | return 0; |
| 2431 | 2507 | ||
| 2432 | err: | 2508 | err: |
| 2433 | for (i = 0; i < vi->max_queue_pairs; i++) | 2509 | if (!prog) { |
| 2434 | virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); | 2510 | virtnet_clear_guest_offloads(vi); |
| 2511 | for (i = 0; i < vi->max_queue_pairs; i++) | ||
| 2512 | rcu_assign_pointer(vi->rq[i].xdp_prog, old_prog); | ||
| 2513 | } | ||
| 2514 | |||
| 2515 | if (netif_running(dev)) { | ||
| 2516 | for (i = 0; i < vi->max_queue_pairs; i++) { | ||
| 2517 | virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); | ||
| 2518 | virtnet_napi_tx_enable(vi, vi->sq[i].vq, | ||
| 2519 | &vi->sq[i].napi); | ||
| 2520 | } | ||
| 2521 | } | ||
| 2435 | if (prog) | 2522 | if (prog) |
| 2436 | bpf_prog_sub(prog, vi->max_queue_pairs - 1); | 2523 | bpf_prog_sub(prog, vi->max_queue_pairs - 1); |
| 2437 | return err; | 2524 | return err; |
| @@ -2613,16 +2700,6 @@ static void free_receive_page_frags(struct virtnet_info *vi) | |||
| 2613 | put_page(vi->rq[i].alloc_frag.page); | 2700 | put_page(vi->rq[i].alloc_frag.page); |
| 2614 | } | 2701 | } |
| 2615 | 2702 | ||
| 2616 | static bool is_xdp_raw_buffer_queue(struct virtnet_info *vi, int q) | ||
| 2617 | { | ||
| 2618 | if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs)) | ||
| 2619 | return false; | ||
| 2620 | else if (q < vi->curr_queue_pairs) | ||
| 2621 | return true; | ||
| 2622 | else | ||
| 2623 | return false; | ||
| 2624 | } | ||
| 2625 | |||
| 2626 | static void free_unused_bufs(struct virtnet_info *vi) | 2703 | static void free_unused_bufs(struct virtnet_info *vi) |
| 2627 | { | 2704 | { |
| 2628 | void *buf; | 2705 | void *buf; |
| @@ -2631,10 +2708,10 @@ static void free_unused_bufs(struct virtnet_info *vi) | |||
| 2631 | for (i = 0; i < vi->max_queue_pairs; i++) { | 2708 | for (i = 0; i < vi->max_queue_pairs; i++) { |
| 2632 | struct virtqueue *vq = vi->sq[i].vq; | 2709 | struct virtqueue *vq = vi->sq[i].vq; |
| 2633 | while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { | 2710 | while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { |
| 2634 | if (!is_xdp_raw_buffer_queue(vi, i)) | 2711 | if (!is_xdp_frame(buf)) |
| 2635 | dev_kfree_skb(buf); | 2712 | dev_kfree_skb(buf); |
| 2636 | else | 2713 | else |
| 2637 | put_page(virt_to_head_page(buf)); | 2714 | xdp_return_frame(ptr_to_xdp(buf)); |
| 2638 | } | 2715 | } |
| 2639 | } | 2716 | } |
| 2640 | 2717 | ||
