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

net: mana: Add support of XDP_REDIRECT action

Add a handler of the XDP_REDIRECT return code from a XDP program. The
packets will be flushed at the end of each RX/CQ NAPI poll cycle.
ndo_xdp_xmit() is implemented by sharing the code in mana_xdp_tx().
Ethtool per queue counters are added for XDP redirect and xmit operations.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Haiyang Zhang and committed by
Paolo Abeni
7a8938cd 1566e7d6

+93 -2
+6
drivers/net/ethernet/microsoft/mana/mana.h
··· 53 53 u64 bytes; 54 54 u64 xdp_drop; 55 55 u64 xdp_tx; 56 + u64 xdp_redirect; 56 57 struct u64_stats_sync syncp; 57 58 }; 58 59 59 60 struct mana_stats_tx { 60 61 u64 packets; 61 62 u64 bytes; 63 + u64 xdp_xmit; 62 64 struct u64_stats_sync syncp; 63 65 }; 64 66 ··· 313 311 struct bpf_prog __rcu *bpf_prog; 314 312 struct xdp_rxq_info xdp_rxq; 315 313 struct page *xdp_save_page; 314 + bool xdp_flush; 315 + int xdp_rc; /* XDP redirect return code */ 316 316 317 317 /* MUST BE THE LAST MEMBER: 318 318 * Each receive buffer has an associated mana_recv_buf_oob. ··· 400 396 void mana_remove(struct gdma_dev *gd, bool suspending); 401 397 402 398 void mana_xdp_tx(struct sk_buff *skb, struct net_device *ndev); 399 + int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames, 400 + u32 flags); 403 401 u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, 404 402 struct xdp_buff *xdp, void *buf_va, uint pkt_len); 405 403 struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
+64
drivers/net/ethernet/microsoft/mana/mana_bpf.c
··· 32 32 ndev->stats.tx_dropped++; 33 33 } 34 34 35 + static int mana_xdp_xmit_fm(struct net_device *ndev, struct xdp_frame *frame, 36 + u16 q_idx) 37 + { 38 + struct sk_buff *skb; 39 + 40 + skb = xdp_build_skb_from_frame(frame, ndev); 41 + if (unlikely(!skb)) 42 + return -ENOMEM; 43 + 44 + skb_set_queue_mapping(skb, q_idx); 45 + 46 + mana_xdp_tx(skb, ndev); 47 + 48 + return 0; 49 + } 50 + 51 + int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames, 52 + u32 flags) 53 + { 54 + struct mana_port_context *apc = netdev_priv(ndev); 55 + struct mana_stats_tx *tx_stats; 56 + int i, count = 0; 57 + u16 q_idx; 58 + 59 + if (unlikely(!apc->port_is_up)) 60 + return 0; 61 + 62 + q_idx = smp_processor_id() % ndev->real_num_tx_queues; 63 + 64 + for (i = 0; i < n; i++) { 65 + if (mana_xdp_xmit_fm(ndev, frames[i], q_idx)) 66 + break; 67 + 68 + count++; 69 + } 70 + 71 + tx_stats = &apc->tx_qp[q_idx].txq.stats; 72 + 73 + u64_stats_update_begin(&tx_stats->syncp); 74 + tx_stats->xdp_xmit += count; 75 + u64_stats_update_end(&tx_stats->syncp); 76 + 77 + return count; 78 + } 79 + 35 80 u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, 36 81 struct xdp_buff *xdp, void *buf_va, uint pkt_len) 37 82 { 83 + struct mana_stats_rx *rx_stats; 38 84 struct bpf_prog *prog; 39 85 u32 act = XDP_PASS; 40 86 ··· 95 49 96 50 act = bpf_prog_run_xdp(prog, xdp); 97 51 52 + rx_stats = &rxq->stats; 53 + 98 54 switch (act) { 99 55 case XDP_PASS: 100 56 case XDP_TX: 101 57 case XDP_DROP: 102 58 break; 59 + 60 + case XDP_REDIRECT: 61 + rxq->xdp_rc = xdp_do_redirect(ndev, xdp, prog); 62 + if (!rxq->xdp_rc) { 63 + rxq->xdp_flush = true; 64 + 65 + u64_stats_update_begin(&rx_stats->syncp); 66 + rx_stats->packets++; 67 + rx_stats->bytes += pkt_len; 68 + rx_stats->xdp_redirect++; 69 + u64_stats_update_end(&rx_stats->syncp); 70 + 71 + break; 72 + } 73 + 74 + fallthrough; 103 75 104 76 case XDP_ABORTED: 105 77 trace_xdp_exception(ndev, prog, act);
+12 -1
drivers/net/ethernet/microsoft/mana/mana_en.c
··· 6 6 #include <linux/inetdevice.h> 7 7 #include <linux/etherdevice.h> 8 8 #include <linux/ethtool.h> 9 + #include <linux/filter.h> 9 10 #include <linux/mm.h> 10 11 11 12 #include <net/checksum.h> ··· 383 382 .ndo_validate_addr = eth_validate_addr, 384 383 .ndo_get_stats64 = mana_get_stats64, 385 384 .ndo_bpf = mana_bpf, 385 + .ndo_xdp_xmit = mana_xdp_xmit, 386 386 }; 387 387 388 388 static void mana_cleanup_port_context(struct mana_port_context *apc) ··· 1122 1120 1123 1121 act = mana_run_xdp(ndev, rxq, &xdp, buf_va, pkt_len); 1124 1122 1123 + if (act == XDP_REDIRECT && !rxq->xdp_rc) 1124 + return; 1125 + 1125 1126 if (act != XDP_PASS && act != XDP_TX) 1126 1127 goto drop_xdp; 1127 1128 ··· 1280 1275 static void mana_poll_rx_cq(struct mana_cq *cq) 1281 1276 { 1282 1277 struct gdma_comp *comp = cq->gdma_comp_buf; 1278 + struct mana_rxq *rxq = cq->rxq; 1283 1279 int comp_read, i; 1284 1280 1285 1281 comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER); 1286 1282 WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER); 1283 + 1284 + rxq->xdp_flush = false; 1287 1285 1288 1286 for (i = 0; i < comp_read; i++) { 1289 1287 if (WARN_ON_ONCE(comp[i].is_sq)) ··· 1296 1288 if (WARN_ON_ONCE(comp[i].wq_num != cq->rxq->gdma_id)) 1297 1289 return; 1298 1290 1299 - mana_process_rx_cqe(cq->rxq, cq, &comp[i]); 1291 + mana_process_rx_cqe(rxq, cq, &comp[i]); 1300 1292 } 1293 + 1294 + if (rxq->xdp_flush) 1295 + xdp_do_flush(); 1301 1296 } 1302 1297 1303 1298 static void mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
+11 -1
drivers/net/ethernet/microsoft/mana/mana_ethtool.c
··· 23 23 if (stringset != ETH_SS_STATS) 24 24 return -EINVAL; 25 25 26 - return ARRAY_SIZE(mana_eth_stats) + num_queues * 6; 26 + return ARRAY_SIZE(mana_eth_stats) + num_queues * 8; 27 27 } 28 28 29 29 static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data) ··· 50 50 p += ETH_GSTRING_LEN; 51 51 sprintf(p, "rx_%d_xdp_tx", i); 52 52 p += ETH_GSTRING_LEN; 53 + sprintf(p, "rx_%d_xdp_redirect", i); 54 + p += ETH_GSTRING_LEN; 53 55 } 54 56 55 57 for (i = 0; i < num_queues; i++) { 56 58 sprintf(p, "tx_%d_packets", i); 57 59 p += ETH_GSTRING_LEN; 58 60 sprintf(p, "tx_%d_bytes", i); 61 + p += ETH_GSTRING_LEN; 62 + sprintf(p, "tx_%d_xdp_xmit", i); 59 63 p += ETH_GSTRING_LEN; 60 64 } 61 65 } ··· 74 70 struct mana_stats_tx *tx_stats; 75 71 unsigned int start; 76 72 u64 packets, bytes; 73 + u64 xdp_redirect; 74 + u64 xdp_xmit; 77 75 u64 xdp_drop; 78 76 u64 xdp_tx; 79 77 int q, i = 0; ··· 95 89 bytes = rx_stats->bytes; 96 90 xdp_drop = rx_stats->xdp_drop; 97 91 xdp_tx = rx_stats->xdp_tx; 92 + xdp_redirect = rx_stats->xdp_redirect; 98 93 } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); 99 94 100 95 data[i++] = packets; 101 96 data[i++] = bytes; 102 97 data[i++] = xdp_drop; 103 98 data[i++] = xdp_tx; 99 + data[i++] = xdp_redirect; 104 100 } 105 101 106 102 for (q = 0; q < num_queues; q++) { ··· 112 104 start = u64_stats_fetch_begin_irq(&tx_stats->syncp); 113 105 packets = tx_stats->packets; 114 106 bytes = tx_stats->bytes; 107 + xdp_xmit = tx_stats->xdp_xmit; 115 108 } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); 116 109 117 110 data[i++] = packets; 118 111 data[i++] = bytes; 112 + data[i++] = xdp_xmit; 119 113 } 120 114 } 121 115