Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netdevsim: add NAPI support

Add NAPI support to netdevim, similar to veth.

* Add a nsim_rq rx queue structure to hold a NAPI instance and a skb
queue.
* During xmit, store the skb in the peer skb queue and schedule NAPI.
* During napi_poll(), drain the skb queue and pass up the stack.
* Add assoc between rxq and NAPI instance using netif_queue_set_napi().

Signed-off-by: David Wei <dw@davidwei.uk>
Link: https://lore.kernel.org/r/20240507163228.2066817-2-dw@davidwei.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

David Wei and committed by
Jakub Kicinski
3762ec05 1d0dc857

+205 -12
+198 -11
drivers/net/netdevsim/netdev.c
··· 28 28 29 29 #include "netdevsim.h" 30 30 31 + #define NSIM_RING_SIZE 256 32 + 33 + static int nsim_napi_rx(struct nsim_rq *rq, struct sk_buff *skb) 34 + { 35 + if (skb_queue_len(&rq->skb_queue) > NSIM_RING_SIZE) { 36 + dev_kfree_skb_any(skb); 37 + return NET_RX_DROP; 38 + } 39 + 40 + skb_queue_tail(&rq->skb_queue, skb); 41 + return NET_RX_SUCCESS; 42 + } 43 + 44 + static int nsim_forward_skb(struct net_device *dev, struct sk_buff *skb, 45 + struct nsim_rq *rq) 46 + { 47 + return __dev_forward_skb(dev, skb) ?: nsim_napi_rx(rq, skb); 48 + } 49 + 31 50 static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 32 51 { 33 52 struct netdevsim *ns = netdev_priv(dev); 53 + struct net_device *peer_dev; 34 54 unsigned int len = skb->len; 35 55 struct netdevsim *peer_ns; 56 + struct nsim_rq *rq; 57 + int rxq; 36 58 37 59 rcu_read_lock(); 38 60 if (!nsim_ipsec_tx(ns, skb)) ··· 64 42 if (!peer_ns) 65 43 goto out_drop_free; 66 44 45 + peer_dev = peer_ns->netdev; 46 + rxq = skb_get_queue_mapping(skb); 47 + if (rxq >= peer_dev->num_rx_queues) 48 + rxq = rxq % peer_dev->num_rx_queues; 49 + rq = &peer_ns->rq[rxq]; 50 + 67 51 skb_tx_timestamp(skb); 68 - if (unlikely(dev_forward_skb(peer_ns->netdev, skb) == NET_RX_DROP)) 52 + if (unlikely(nsim_forward_skb(peer_dev, skb, rq) == NET_RX_DROP)) 69 53 goto out_drop_cnt; 54 + 55 + napi_schedule(&rq->napi); 70 56 71 57 rcu_read_unlock(); 72 58 u64_stats_update_begin(&ns->syncp); ··· 330 300 return iflink; 331 301 } 332 302 303 + static int nsim_rcv(struct nsim_rq *rq, int budget) 304 + { 305 + struct sk_buff *skb; 306 + int i; 307 + 308 + for (i = 0; i < budget; i++) { 309 + if (skb_queue_empty(&rq->skb_queue)) 310 + break; 311 + 312 + skb = skb_dequeue(&rq->skb_queue); 313 + netif_receive_skb(skb); 314 + } 315 + 316 + return i; 317 + } 318 + 319 + static int nsim_poll(struct napi_struct *napi, int budget) 320 + { 321 + struct nsim_rq *rq = container_of(napi, struct nsim_rq, napi); 322 + int done; 323 + 324 + done = nsim_rcv(rq, budget); 325 + napi_complete(napi); 326 + 327 + return done; 328 + } 329 + 330 + static int nsim_create_page_pool(struct nsim_rq *rq) 331 + { 332 + struct page_pool_params p = { 333 + .order = 0, 334 + .pool_size = NSIM_RING_SIZE, 335 + .nid = NUMA_NO_NODE, 336 + .dev = &rq->napi.dev->dev, 337 + .napi = &rq->napi, 338 + .dma_dir = DMA_BIDIRECTIONAL, 339 + .netdev = rq->napi.dev, 340 + }; 341 + 342 + rq->page_pool = page_pool_create(&p); 343 + if (IS_ERR(rq->page_pool)) { 344 + int err = PTR_ERR(rq->page_pool); 345 + 346 + rq->page_pool = NULL; 347 + return err; 348 + } 349 + return 0; 350 + } 351 + 352 + static int nsim_init_napi(struct netdevsim *ns) 353 + { 354 + struct net_device *dev = ns->netdev; 355 + struct nsim_rq *rq; 356 + int err, i; 357 + 358 + for (i = 0; i < dev->num_rx_queues; i++) { 359 + rq = &ns->rq[i]; 360 + 361 + netif_napi_add(dev, &rq->napi, nsim_poll); 362 + } 363 + 364 + for (i = 0; i < dev->num_rx_queues; i++) { 365 + rq = &ns->rq[i]; 366 + 367 + err = nsim_create_page_pool(rq); 368 + if (err) 369 + goto err_pp_destroy; 370 + } 371 + 372 + return 0; 373 + 374 + err_pp_destroy: 375 + while (i--) { 376 + page_pool_destroy(ns->rq[i].page_pool); 377 + ns->rq[i].page_pool = NULL; 378 + } 379 + 380 + for (i = 0; i < dev->num_rx_queues; i++) 381 + __netif_napi_del(&ns->rq[i].napi); 382 + 383 + return err; 384 + } 385 + 386 + static void nsim_enable_napi(struct netdevsim *ns) 387 + { 388 + struct net_device *dev = ns->netdev; 389 + int i; 390 + 391 + for (i = 0; i < dev->num_rx_queues; i++) { 392 + struct nsim_rq *rq = &ns->rq[i]; 393 + 394 + netif_queue_set_napi(dev, i, NETDEV_QUEUE_TYPE_RX, &rq->napi); 395 + napi_enable(&rq->napi); 396 + } 397 + } 398 + 333 399 static int nsim_open(struct net_device *dev) 334 400 { 335 401 struct netdevsim *ns = netdev_priv(dev); 336 - struct page_pool_params pp = { 0 }; 402 + int err; 337 403 338 - pp.pool_size = 128; 339 - pp.dev = &dev->dev; 340 - pp.dma_dir = DMA_BIDIRECTIONAL; 341 - pp.netdev = dev; 404 + err = nsim_init_napi(ns); 405 + if (err) 406 + return err; 342 407 343 - ns->pp = page_pool_create(&pp); 344 - return PTR_ERR_OR_ZERO(ns->pp); 408 + nsim_enable_napi(ns); 409 + 410 + return 0; 411 + } 412 + 413 + static void nsim_del_napi(struct netdevsim *ns) 414 + { 415 + struct net_device *dev = ns->netdev; 416 + int i; 417 + 418 + for (i = 0; i < dev->num_rx_queues; i++) { 419 + struct nsim_rq *rq = &ns->rq[i]; 420 + 421 + napi_disable(&rq->napi); 422 + __netif_napi_del(&rq->napi); 423 + } 424 + synchronize_net(); 425 + 426 + for (i = 0; i < dev->num_rx_queues; i++) { 427 + page_pool_destroy(ns->rq[i].page_pool); 428 + ns->rq[i].page_pool = NULL; 429 + } 345 430 } 346 431 347 432 static int nsim_stop(struct net_device *dev) 348 433 { 349 434 struct netdevsim *ns = netdev_priv(dev); 435 + struct netdevsim *peer; 350 436 351 - page_pool_destroy(ns->pp); 437 + netif_carrier_off(dev); 438 + peer = rtnl_dereference(ns->peer); 439 + if (peer) 440 + netif_carrier_off(peer->netdev); 441 + 442 + nsim_del_napi(ns); 352 443 353 444 return 0; 354 445 } ··· 588 437 if (!netif_running(ns->netdev) && val) { 589 438 ret = -ENETDOWN; 590 439 } else if (val) { 591 - ns->page = page_pool_dev_alloc_pages(ns->pp); 440 + ns->page = page_pool_dev_alloc_pages(ns->rq[0].page_pool); 592 441 if (!ns->page) 593 442 ret = -ENOMEM; 594 443 } else { ··· 628 477 dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD; 629 478 } 630 479 480 + static int nsim_queue_init(struct netdevsim *ns) 481 + { 482 + struct net_device *dev = ns->netdev; 483 + int i; 484 + 485 + ns->rq = kvcalloc(dev->num_rx_queues, sizeof(*ns->rq), 486 + GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL); 487 + if (!ns->rq) 488 + return -ENOMEM; 489 + 490 + for (i = 0; i < dev->num_rx_queues; i++) 491 + skb_queue_head_init(&ns->rq[i].skb_queue); 492 + 493 + return 0; 494 + } 495 + 496 + static void nsim_queue_free(struct netdevsim *ns) 497 + { 498 + struct net_device *dev = ns->netdev; 499 + int i; 500 + 501 + for (i = 0; i < dev->num_rx_queues; i++) 502 + skb_queue_purge_reason(&ns->rq[i].skb_queue, 503 + SKB_DROP_REASON_QUEUE_PURGE); 504 + 505 + kvfree(ns->rq); 506 + ns->rq = NULL; 507 + } 508 + 631 509 static int nsim_init_netdevsim(struct netdevsim *ns) 632 510 { 633 511 struct mock_phc *phc; ··· 675 495 goto err_phc_destroy; 676 496 677 497 rtnl_lock(); 678 - err = nsim_bpf_init(ns); 498 + err = nsim_queue_init(ns); 679 499 if (err) 680 500 goto err_utn_destroy; 501 + 502 + err = nsim_bpf_init(ns); 503 + if (err) 504 + goto err_rq_destroy; 681 505 682 506 nsim_macsec_init(ns); 683 507 nsim_ipsec_init(ns); ··· 696 512 nsim_ipsec_teardown(ns); 697 513 nsim_macsec_teardown(ns); 698 514 nsim_bpf_uninit(ns); 515 + err_rq_destroy: 516 + nsim_queue_free(ns); 699 517 err_utn_destroy: 700 518 rtnl_unlock(); 701 519 nsim_udp_tunnels_info_destroy(ns->netdev); ··· 779 593 nsim_macsec_teardown(ns); 780 594 nsim_ipsec_teardown(ns); 781 595 nsim_bpf_uninit(ns); 596 + nsim_queue_free(ns); 782 597 } 783 598 rtnl_unlock(); 784 599 if (nsim_dev_port_is_pf(ns->nsim_dev_port))
+7 -1
drivers/net/netdevsim/netdevsim.h
··· 90 90 struct ethtool_fecparam fec; 91 91 }; 92 92 93 + struct nsim_rq { 94 + struct napi_struct napi; 95 + struct sk_buff_head skb_queue; 96 + struct page_pool *page_pool; 97 + }; 98 + 93 99 struct netdevsim { 94 100 struct net_device *netdev; 95 101 struct nsim_dev *nsim_dev; 96 102 struct nsim_dev_port *nsim_dev_port; 97 103 struct mock_phc *phc; 104 + struct nsim_rq *rq; 98 105 99 106 u64 tx_packets; 100 107 u64 tx_bytes; ··· 132 125 struct debugfs_u32_array dfs_ports[2]; 133 126 } udp_ports; 134 127 135 - struct page_pool *pp; 136 128 struct page *page; 137 129 struct dentry *pp_dfs; 138 130