Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : #include <linux/skbuff.h> 3 : : #include <linux/slab.h> 4 : : #include <linux/netdevice.h> 5 : : #include <net/gro_cells.h> 6 : : 7 : : struct gro_cell { 8 : : struct sk_buff_head napi_skbs; 9 : : struct napi_struct napi; 10 : : }; 11 : : 12 : 0 : int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb) 13 : : { 14 : 0 : struct net_device *dev = skb->dev; 15 : 0 : struct gro_cell *cell; 16 : 0 : int res; 17 : : 18 : 0 : rcu_read_lock(); 19 [ # # ]: 0 : if (unlikely(!(dev->flags & IFF_UP))) 20 : 0 : goto drop; 21 : : 22 [ # # # # : 0 : if (!gcells->cells || skb_cloned(skb) || netif_elide_gro(dev)) { # # ] 23 : 0 : res = netif_rx(skb); 24 : 0 : goto unlock; 25 : : } 26 : : 27 : 0 : cell = this_cpu_ptr(gcells->cells); 28 : : 29 [ # # ]: 0 : if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) { 30 : 0 : drop: 31 : 0 : atomic_long_inc(&dev->rx_dropped); 32 : 0 : kfree_skb(skb); 33 : 0 : res = NET_RX_DROP; 34 : 0 : goto unlock; 35 : : } 36 : : 37 [ # # ]: 0 : __skb_queue_tail(&cell->napi_skbs, skb); 38 [ # # ]: 0 : if (skb_queue_len(&cell->napi_skbs) == 1) 39 : 0 : napi_schedule(&cell->napi); 40 : : 41 : : res = NET_RX_SUCCESS; 42 : : 43 : 0 : unlock: 44 : 0 : rcu_read_unlock(); 45 : 0 : return res; 46 : : } 47 : : EXPORT_SYMBOL(gro_cells_receive); 48 : : 49 : : /* called under BH context */ 50 : 0 : static int gro_cell_poll(struct napi_struct *napi, int budget) 51 : : { 52 : 0 : struct gro_cell *cell = container_of(napi, struct gro_cell, napi); 53 : 0 : struct sk_buff *skb; 54 : 0 : int work_done = 0; 55 : : 56 [ # # ]: 0 : while (work_done < budget) { 57 [ # # ]: 0 : skb = __skb_dequeue(&cell->napi_skbs); 58 [ # # ]: 0 : if (!skb) 59 : : break; 60 : 0 : napi_gro_receive(napi, skb); 61 : 0 : work_done++; 62 : : } 63 : : 64 [ # # ]: 0 : if (work_done < budget) 65 : 0 : napi_complete_done(napi, work_done); 66 : 0 : return work_done; 67 : : } 68 : : 69 : 13 : int gro_cells_init(struct gro_cells *gcells, struct net_device *dev) 70 : : { 71 : 13 : int i; 72 : : 73 : 13 : gcells->cells = alloc_percpu(struct gro_cell); 74 [ + - ]: 13 : if (!gcells->cells) 75 : : return -ENOMEM; 76 : : 77 [ + + ]: 26 : for_each_possible_cpu(i) { 78 : 13 : struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); 79 : : 80 : 13 : __skb_queue_head_init(&cell->napi_skbs); 81 : : 82 : 13 : set_bit(NAPI_STATE_NO_BUSY_POLL, &cell->napi.state); 83 : : 84 : 13 : netif_napi_add(dev, &cell->napi, gro_cell_poll, 85 : : NAPI_POLL_WEIGHT); 86 : 13 : napi_enable(&cell->napi); 87 : : } 88 : : return 0; 89 : : } 90 : : EXPORT_SYMBOL(gro_cells_init); 91 : : 92 : 0 : void gro_cells_destroy(struct gro_cells *gcells) 93 : : { 94 : 0 : int i; 95 : : 96 [ # # ]: 0 : if (!gcells->cells) 97 : : return; 98 [ # # ]: 0 : for_each_possible_cpu(i) { 99 : 0 : struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); 100 : : 101 : 0 : napi_disable(&cell->napi); 102 : 0 : netif_napi_del(&cell->napi); 103 : 0 : __skb_queue_purge(&cell->napi_skbs); 104 : : } 105 : 0 : free_percpu(gcells->cells); 106 : 0 : gcells->cells = NULL; 107 : : } 108 : : EXPORT_SYMBOL(gro_cells_destroy);