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 | ||