Skip to content

Commit 6089970

Browse files
author
Paolo Abeni
committed
Merge branch 'eth-fbnic-add-xdp-support-for-fbnic'
Mohsin Bashir says: ==================== eth: fbnic: Add XDP support for fbnic This patch series introduces basic XDP support for fbnic. To enable this, it also includes preparatory changes such as making the HDS threshold configurable via ethtool, updating headroom for fbnic, tracking frag state in shinfo, and prefetching the first cacheline of data. V3: https://lore.kernel.org/netdev/20250812220150.161848-1-mohsin.bashr@gmail.com/ V2: https://lore.kernel.org/netdev/20250811211338.857992-1-mohsin.bashr@gmail.com/ V1: https://lore.kernel.org/netdev/20250723145926.4120434-1-mohsin.bashr@gmail.com/ ==================== Link: https://patch.msgid.link/20250813221319.3367670-1-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents 38e1467 + 7fedb8f commit 6089970

File tree

6 files changed

+576
-82
lines changed

6 files changed

+576
-82
lines changed

Documentation/networking/device_drivers/ethernet/meta/fbnic.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,14 @@ behavior and potential performance bottlenecks.
160160
credit exhaustion
161161
- ``pcie_ob_rd_no_np_cred``: Read requests dropped due to non-posted
162162
credit exhaustion
163+
164+
XDP Length Error:
165+
~~~~~~~~~~~~~~~~~
166+
167+
For XDP programs without frags support, fbnic tries to make sure that MTU fits
168+
into a single buffer. If an oversized frame is received and gets fragmented,
169+
it is dropped and the following netlink counters are updated
170+
171+
- ``rx-length``: number of frames dropped due to lack of fragmentation
172+
support in the attached XDP program
173+
- ``rx-errors``: total number of packets with errors received on the interface

drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
33

44
#include <linux/ethtool.h>
5+
#include <linux/ethtool_netlink.h>
56
#include <linux/netdevice.h>
67
#include <linux/pci.h>
78
#include <net/ipv6.h>
@@ -111,6 +112,20 @@ static const struct fbnic_stat fbnic_gstrings_hw_q_stats[] = {
111112
FBNIC_HW_RXB_DEQUEUE_STATS_LEN * FBNIC_RXB_DEQUEUE_INDICES + \
112113
FBNIC_HW_Q_STATS_LEN * FBNIC_MAX_QUEUES)
113114

115+
#define FBNIC_QUEUE_STAT(name, stat) \
116+
FBNIC_STAT_FIELDS(fbnic_ring, name, stat)
117+
118+
static const struct fbnic_stat fbnic_gstrings_xdp_stats[] = {
119+
FBNIC_QUEUE_STAT("xdp_tx_queue_%u_packets", stats.packets),
120+
FBNIC_QUEUE_STAT("xdp_tx_queue_%u_bytes", stats.bytes),
121+
FBNIC_QUEUE_STAT("xdp_tx_queue_%u_dropped", stats.dropped),
122+
};
123+
124+
#define FBNIC_XDP_STATS_LEN ARRAY_SIZE(fbnic_gstrings_xdp_stats)
125+
126+
#define FBNIC_STATS_LEN \
127+
(FBNIC_HW_STATS_LEN + FBNIC_XDP_STATS_LEN * FBNIC_MAX_XDPQS)
128+
114129
static void
115130
fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
116131
{
@@ -160,6 +175,7 @@ static void fbnic_clone_swap_cfg(struct fbnic_net *orig,
160175
swap(clone->num_rx_queues, orig->num_rx_queues);
161176
swap(clone->num_tx_queues, orig->num_tx_queues);
162177
swap(clone->num_napi, orig->num_napi);
178+
swap(clone->hds_thresh, orig->hds_thresh);
163179
}
164180

165181
static void fbnic_aggregate_vector_counters(struct fbnic_net *fbn,
@@ -277,15 +293,21 @@ fbnic_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
277293
ring->rx_mini_pending = fbn->hpq_size;
278294
ring->rx_jumbo_pending = fbn->ppq_size;
279295
ring->tx_pending = fbn->txq_size;
296+
297+
kernel_ring->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
298+
kernel_ring->hds_thresh_max = FBNIC_HDS_THRESH_MAX;
299+
kernel_ring->hds_thresh = fbn->hds_thresh;
280300
}
281301

282302
static void fbnic_set_rings(struct fbnic_net *fbn,
283-
struct ethtool_ringparam *ring)
303+
struct ethtool_ringparam *ring,
304+
struct kernel_ethtool_ringparam *kernel_ring)
284305
{
285306
fbn->rcq_size = ring->rx_pending;
286307
fbn->hpq_size = ring->rx_mini_pending;
287308
fbn->ppq_size = ring->rx_jumbo_pending;
288309
fbn->txq_size = ring->tx_pending;
310+
fbn->hds_thresh = kernel_ring->hds_thresh;
289311
}
290312

291313
static int
@@ -316,16 +338,32 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
316338
return -EINVAL;
317339
}
318340

341+
if (kernel_ring->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED) {
342+
NL_SET_ERR_MSG_MOD(extack, "Cannot disable TCP data split");
343+
return -EINVAL;
344+
}
345+
346+
/* If an XDP program is attached, we should check for potential frame
347+
* splitting. If the new HDS threshold can cause splitting, we should
348+
* only allow if the attached XDP program can handle frags.
349+
*/
350+
if (fbnic_check_split_frames(fbn->xdp_prog, netdev->mtu,
351+
kernel_ring->hds_thresh)) {
352+
NL_SET_ERR_MSG_MOD(extack,
353+
"Use higher HDS threshold or multi-buf capable program");
354+
return -EINVAL;
355+
}
356+
319357
if (!netif_running(netdev)) {
320-
fbnic_set_rings(fbn, ring);
358+
fbnic_set_rings(fbn, ring, kernel_ring);
321359
return 0;
322360
}
323361

324362
clone = fbnic_clone_create(fbn);
325363
if (!clone)
326364
return -ENOMEM;
327365

328-
fbnic_set_rings(clone, ring);
366+
fbnic_set_rings(clone, ring, kernel_ring);
329367

330368
err = fbnic_alloc_napi_vectors(clone);
331369
if (err)
@@ -398,6 +436,16 @@ static void fbnic_get_rxb_dequeue_strings(u8 **data, unsigned int idx)
398436
ethtool_sprintf(data, stat->string, idx);
399437
}
400438

439+
static void fbnic_get_xdp_queue_strings(u8 **data, unsigned int idx)
440+
{
441+
const struct fbnic_stat *stat;
442+
int i;
443+
444+
stat = fbnic_gstrings_xdp_stats;
445+
for (i = 0; i < FBNIC_XDP_STATS_LEN; i++, stat++)
446+
ethtool_sprintf(data, stat->string, idx);
447+
}
448+
401449
static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data)
402450
{
403451
const struct fbnic_stat *stat;
@@ -423,6 +471,9 @@ static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data)
423471
for (i = 0; i < FBNIC_HW_Q_STATS_LEN; i++, stat++)
424472
ethtool_sprintf(&data, stat->string, idx);
425473
}
474+
475+
for (i = 0; i < FBNIC_MAX_XDPQS; i++)
476+
fbnic_get_xdp_queue_strings(&data, i);
426477
break;
427478
}
428479
}
@@ -440,6 +491,24 @@ static void fbnic_report_hw_stats(const struct fbnic_stat *stat,
440491
}
441492
}
442493

494+
static void fbnic_get_xdp_queue_stats(struct fbnic_ring *ring, u64 **data)
495+
{
496+
const struct fbnic_stat *stat;
497+
int i;
498+
499+
if (!ring) {
500+
*data += FBNIC_XDP_STATS_LEN;
501+
return;
502+
}
503+
504+
stat = fbnic_gstrings_xdp_stats;
505+
for (i = 0; i < FBNIC_XDP_STATS_LEN; i++, stat++, (*data)++) {
506+
u8 *p = (u8 *)ring + stat->offset;
507+
508+
**data = *(u64 *)p;
509+
}
510+
}
511+
443512
static void fbnic_get_ethtool_stats(struct net_device *dev,
444513
struct ethtool_stats *stats, u64 *data)
445514
{
@@ -487,13 +556,16 @@ static void fbnic_get_ethtool_stats(struct net_device *dev,
487556
FBNIC_HW_Q_STATS_LEN, &data);
488557
}
489558
spin_unlock(&fbd->hw_stats_lock);
559+
560+
for (i = 0; i < FBNIC_MAX_XDPQS; i++)
561+
fbnic_get_xdp_queue_stats(fbn->tx[i + FBNIC_MAX_TXQS], &data);
490562
}
491563

492564
static int fbnic_get_sset_count(struct net_device *dev, int sset)
493565
{
494566
switch (sset) {
495567
case ETH_SS_STATS:
496-
return FBNIC_HW_STATS_LEN;
568+
return FBNIC_STATS_LEN;
497569
default:
498570
return -EOPNOTSUPP;
499571
}
@@ -1678,6 +1750,8 @@ fbnic_get_rmon_stats(struct net_device *netdev,
16781750
static const struct ethtool_ops fbnic_ethtool_ops = {
16791751
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
16801752
ETHTOOL_COALESCE_RX_MAX_FRAMES,
1753+
.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT |
1754+
ETHTOOL_RING_USE_HDS_THRS,
16811755
.rxfh_max_num_contexts = FBNIC_RPC_RSS_TBL_COUNT,
16821756
.get_drvinfo = fbnic_get_drvinfo,
16831757
.get_regs_len = fbnic_get_regs_len,

drivers/net/ethernet/meta/fbnic/fbnic_netdev.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,12 @@ static void fbnic_get_stats64(struct net_device *dev,
407407
struct rtnl_link_stats64 *stats64)
408408
{
409409
u64 rx_bytes, rx_packets, rx_dropped = 0, rx_errors = 0;
410+
u64 rx_over = 0, rx_missed = 0, rx_length = 0;
410411
u64 tx_bytes, tx_packets, tx_dropped = 0;
411412
struct fbnic_net *fbn = netdev_priv(dev);
412413
struct fbnic_dev *fbd = fbn->fbd;
413414
struct fbnic_queue_stats *stats;
414-
u64 rx_over = 0, rx_missed = 0;
415+
415416
unsigned int start, i;
416417

417418
fbnic_get_hw_stats(fbd);
@@ -489,6 +490,7 @@ static void fbnic_get_stats64(struct net_device *dev,
489490
stats64->rx_missed_errors = rx_missed;
490491

491492
for (i = 0; i < fbn->num_rx_queues; i++) {
493+
struct fbnic_ring *xdpr = fbn->tx[FBNIC_MAX_TXQS + i];
492494
struct fbnic_ring *rxr = fbn->rx[i];
493495

494496
if (!rxr)
@@ -500,14 +502,66 @@ static void fbnic_get_stats64(struct net_device *dev,
500502
rx_bytes = stats->bytes;
501503
rx_packets = stats->packets;
502504
rx_dropped = stats->dropped;
505+
rx_length = stats->rx.length_errors;
503506
} while (u64_stats_fetch_retry(&stats->syncp, start));
504507

505508
stats64->rx_bytes += rx_bytes;
506509
stats64->rx_packets += rx_packets;
507510
stats64->rx_dropped += rx_dropped;
511+
stats64->rx_errors += rx_length;
512+
stats64->rx_length_errors += rx_length;
513+
514+
if (!xdpr)
515+
continue;
516+
517+
stats = &xdpr->stats;
518+
do {
519+
start = u64_stats_fetch_begin(&stats->syncp);
520+
tx_bytes = stats->bytes;
521+
tx_packets = stats->packets;
522+
tx_dropped = stats->dropped;
523+
} while (u64_stats_fetch_retry(&stats->syncp, start));
524+
525+
stats64->tx_bytes += tx_bytes;
526+
stats64->tx_packets += tx_packets;
527+
stats64->tx_dropped += tx_dropped;
508528
}
509529
}
510530

531+
bool fbnic_check_split_frames(struct bpf_prog *prog, unsigned int mtu,
532+
u32 hds_thresh)
533+
{
534+
if (!prog)
535+
return false;
536+
537+
if (prog->aux->xdp_has_frags)
538+
return false;
539+
540+
return mtu + ETH_HLEN > hds_thresh;
541+
}
542+
543+
static int fbnic_bpf(struct net_device *netdev, struct netdev_bpf *bpf)
544+
{
545+
struct bpf_prog *prog = bpf->prog, *prev_prog;
546+
struct fbnic_net *fbn = netdev_priv(netdev);
547+
548+
if (bpf->command != XDP_SETUP_PROG)
549+
return -EINVAL;
550+
551+
if (fbnic_check_split_frames(prog, netdev->mtu,
552+
fbn->hds_thresh)) {
553+
NL_SET_ERR_MSG_MOD(bpf->extack,
554+
"MTU too high, or HDS threshold is too low for single buffer XDP");
555+
return -EOPNOTSUPP;
556+
}
557+
558+
prev_prog = xchg(&fbn->xdp_prog, prog);
559+
if (prev_prog)
560+
bpf_prog_put(prev_prog);
561+
562+
return 0;
563+
}
564+
511565
static const struct net_device_ops fbnic_netdev_ops = {
512566
.ndo_open = fbnic_open,
513567
.ndo_stop = fbnic_stop,
@@ -517,6 +571,7 @@ static const struct net_device_ops fbnic_netdev_ops = {
517571
.ndo_set_mac_address = fbnic_set_mac,
518572
.ndo_set_rx_mode = fbnic_set_rx_mode,
519573
.ndo_get_stats64 = fbnic_get_stats64,
574+
.ndo_bpf = fbnic_bpf,
520575
.ndo_hwtstamp_get = fbnic_hwtstamp_get,
521576
.ndo_hwtstamp_set = fbnic_hwtstamp_set,
522577
};
@@ -568,6 +623,7 @@ static void fbnic_get_queue_stats_tx(struct net_device *dev, int idx,
568623
struct fbnic_ring *txr = fbn->tx[idx];
569624
struct fbnic_queue_stats *stats;
570625
u64 stop, wake, csum, lso;
626+
struct fbnic_ring *xdpr;
571627
unsigned int start;
572628
u64 bytes, packets;
573629

@@ -591,6 +647,19 @@ static void fbnic_get_queue_stats_tx(struct net_device *dev, int idx,
591647
tx->hw_gso_wire_packets = lso;
592648
tx->stop = stop;
593649
tx->wake = wake;
650+
651+
xdpr = fbn->tx[FBNIC_MAX_TXQS + idx];
652+
if (xdpr) {
653+
stats = &xdpr->stats;
654+
do {
655+
start = u64_stats_fetch_begin(&stats->syncp);
656+
bytes = stats->bytes;
657+
packets = stats->packets;
658+
} while (u64_stats_fetch_retry(&stats->syncp, start));
659+
660+
tx->bytes += bytes;
661+
tx->packets += packets;
662+
}
594663
}
595664

596665
static void fbnic_get_base_stats(struct net_device *dev,
@@ -695,6 +764,10 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
695764
fbn->rx_usecs = FBNIC_RX_USECS_DEFAULT;
696765
fbn->rx_max_frames = FBNIC_RX_FRAMES_DEFAULT;
697766

767+
/* Initialize the hds_thresh */
768+
netdev->cfg->hds_thresh = FBNIC_HDS_THRESH_DEFAULT;
769+
fbn->hds_thresh = FBNIC_HDS_THRESH_DEFAULT;
770+
698771
default_queues = netif_get_num_default_rss_queues();
699772
if (default_queues > fbd->max_num_queues)
700773
default_queues = fbd->max_num_queues;

drivers/net/ethernet/meta/fbnic/fbnic_netdev.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
#define FBNIC_TUN_GSO_FEATURES NETIF_F_GSO_IPXIP6
1919

2020
struct fbnic_net {
21-
struct fbnic_ring *tx[FBNIC_MAX_TXQS];
21+
struct bpf_prog *xdp_prog;
22+
23+
struct fbnic_ring *tx[FBNIC_MAX_TXQS + FBNIC_MAX_XDPQS];
2224
struct fbnic_ring *rx[FBNIC_MAX_RXQS];
2325

2426
struct fbnic_napi_vector *napi[FBNIC_MAX_NAPI_VECTORS];
@@ -31,6 +33,8 @@ struct fbnic_net {
3133
u32 ppq_size;
3234
u32 rcq_size;
3335

36+
u32 hds_thresh;
37+
3438
u16 rx_usecs;
3539
u16 tx_usecs;
3640

@@ -102,4 +106,7 @@ int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev,
102106
int fbnic_phylink_get_fecparam(struct net_device *netdev,
103107
struct ethtool_fecparam *fecparam);
104108
int fbnic_phylink_init(struct net_device *netdev);
109+
110+
bool fbnic_check_split_frames(struct bpf_prog *prog,
111+
unsigned int mtu, u32 hds_threshold);
105112
#endif /* _FBNIC_NETDEV_H_ */

0 commit comments

Comments
 (0)