* [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout
@ 2026-11-03 23:51 Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags Stanislav Fomichev
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
TX bindings use PAGE_SIZE net_iovs, so a frag covers at most a page.
A 64KB skb needs 16 frags, and MAX_SKB_FRAGS caps devmem skbs at about
68KB, which makes BIG TCP ineffective for devmem TX.
This series picks the TX net_iov size from the dmabuf sg table instead:
the largest power of 2, up to 2MB, which aligns every DMA segment. With
a 2MB hugepage-backed udmabuf a BIG TCP skb takes a few frags. There's
no UAPI change since TX addresses are dmabuf offsets.
TCP still bounds skbs by size_goal, so frags get larger, skbs don't.
A single frag can now be as large as the skb, which matters for
NETMEM_TX drivers with tso_max_size above 64KB:
- mlx5: 32-bit length per data segment
- gve: splits frags into 16KB descriptors
- fbnic: keeps the default 64KB tso_max_size
- bnxt: 16-bit BD length, devmem TX frags are capped at 32KB by a new
per-device limit
Tested on two mlx5 400Gb/s hosts with kperf (udmabuf, 32KB RX
net_iovs, 2MB hugepage-backed TX buffer), series backported to a 7.1
kernel on the sender only. 1 flow, MTU 4200, receiver tcp_rmem capped
at 16MB so it doesn't drop, median of 5 x 60s runs:
before after
frags per skb (sender) 16-17 1-2
throughput (Gb/s) 208.6 211.2
sender sendmsg CPU (sys) 40.8% 19.5% (-52%)
The receiver's CPU is the bottleneck, so the gain is CPU, not
throughput. More of the transmit runs from the ACK path, so the
sender's softirq grows (52% -> 59%), but sys + sirq still drops by 16%.
kperf output (sender side) of runs near the median, before:
client: == Source <sender>
client: Tx213.826 Gbps (1603901849600 bytes in 60007723 usec)
client: Rx 0.000 Gbps (0 bytes in 60007723 usec)
client: TCP retrans reord rtt rttvar d_ce snd_wnd cwnd
client: 0 0 633 2 0 15556608 7657
client: net CPU 49: usr: 0.01% sys: 0.10% idle:44.13% iow: 0.00% irq: 3.21% sirq:52.53%
client: app CPU 50: usr: 0.05% sys:41.55% idle:53.88% iow: 0.00% irq: 1.40% sirq: 3.10%
after:
client: == Source <sender>
client: Tx211.242 Gbps (1584440279040 bytes in 60004741 usec)
client: Rx 0.000 Gbps (0 bytes in 60004741 usec)
client: TCP retrans reord rtt rttvar d_ce snd_wnd cwnd
client: 0 0 556 3 0 15499264 7650
client: net CPU 13: usr: 0.01% sys: 0.08% idle:37.75% iow: 0.00% irq: 3.87% sirq:58.26%
client: app CPU 14: usr: 0.06% sys:19.48% idle:77.23% iow: 0.00% irq: 1.19% sirq: 2.02%
The bnxt patches (1 and 5) were tested on two 50Gb/s bnxt hosts with
CONFIG_MAX_SKB_FRAGS=45 (with 17 the check in patch 1 compiles out).
kperf devmem TX from a 2MB hugepage-backed udmabuf runs at line rate
(46.4Gb/s, payload validated) with 2-3 frags per skb, none above 32KB.
ncdevmem sending 1KB chunks builds skbs with up to 45 frags, the stack
segments them and the data arrives intact.
Patches:
- 1: bnxt: segment GSO skbs with too many frags in the stack
- 2-3: devmem TX prep (truesize, niov_shift in the TX lookup)
- 4-5: per-device netmem TX frag size limit, 32KB for bnxt
- 6: pick the TX net_iov size from the sg table
- 7: selftest for TX from a hugepage-backed dmabuf
v2:
- reword the TX truesize commit message (Mina)
- use 1 flow results in the cover letter (Mina)
v1: https://lore.kernel.org/netdev/20261102191438.1059771-1-sdf@fomichev.me/
Stanislav Fomichev (7):
bnxt_en: let the stack segment GSO skbs with too many frags
net: devmem: charge the frag length to TX skb truesize
net: devmem: use niov_shift in net_devmem_get_niov_at()
net: devmem: add a per-device netmem TX frag size limit
bnxt_en: limit netmem TX frags to 32KB
net: devmem: size TX net_iovs from the dmabuf sg table
selftests: drv-net: devmem: TX from a hugepage-backed dmabuf
.../networking/net_cachelines/net_device.rst | 1 +
Documentation/networking/netmem.rst | 6 +++
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++
include/linux/netdevice.h | 2 +
net/core/datagram.c | 3 +-
net/core/dev.c | 1 +
net/core/devmem.c | 37 +++++++++++++---
net/core/devmem.h | 1 +
net/core/netdev-genl.c | 2 +-
.../selftests/drivers/net/hw/devmem.py | 10 ++++-
.../selftests/drivers/net/hw/devmem_lib.py | 43 +++++++++++++++++--
.../selftests/drivers/net/hw/ncdevmem.c | 8 +++-
.../selftests/drivers/net/hw/nk_devmem.py | 11 ++++-
13 files changed, 115 insertions(+), 16 deletions(-)
--
2.53.0-Meta
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-04 16:47 ` Breno Leitao
2026-11-04 17:31 ` Michael Chan
2026-11-03 23:51 ` [PATCH net-next v2 2/7] net: devmem: charge the frag length to TX skb truesize Stanislav Fomichev
` (6 subsequent siblings)
7 siblings, 2 replies; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
With MAX_SKB_FRAGS > TX_MAX_FRAGS, the xmit path linearizes skbs with
more frags than a packet can have BDs. For GSO skbs, linearizing needs a
large allocation, can produce a head which doesn't fit in a BD with BIG
TCP, and always fails for unreadable skbs. Clear the GSO features of
such skbs in ndo_features_check instead, so that the stack segments
them. Non-GSO skbs are still linearized.
Suggested-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/all/CANn89i+ps_CozfOyRnKav0_LUmSekJ9ExB5JkDbTAVf_ss_98g@mail.gmail.com/
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 757c7266ce15..e7a4190a8c78 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -14300,6 +14300,11 @@ static netdev_features_t bnxt_features_check(struct sk_buff *skb,
skb_shinfo(skb)->gso_size))
features &= ~NETIF_F_GSO_MASK;
+#if (MAX_SKB_FRAGS > TX_MAX_FRAGS)
+ if (skb_shinfo(skb)->nr_frags > TX_MAX_FRAGS)
+ features &= ~NETIF_F_GSO_MASK;
+#endif
+
switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
if (!skb->encapsulation)
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v2 2/7] net: devmem: charge the frag length to TX skb truesize
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 3/7] net: devmem: use niov_shift in net_devmem_get_niov_at() Stanislav Fomichev
` (5 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
Devmem TX charges each frag the net_iov size, PAGE_SIZE today:
zerocopy_fill_skb_from_devmem() adds PAGE_SIZE to skb->truesize per
frag and __zerocopy_sg_from_iter() charges it to sk_wmem_queued. TCP
uncharges in bytes as acked data is trimmed from the skb
(tcp_trim_head()) and uncharges the rest when the skb is freed. A frag
shorter than a page leaves the difference charged until then, which is
small with PAGE_SIZE net_iovs.
TX net_iovs are about to grow up to 2MB, while frags stay bounded by
the skb and many frags share a net_iov. Charging the net_iov size would
charge up to 2MB per frag: a 64KB skb with two frags would charge 4MB
and fill the default 4MB send buffer on its own.
Charge the frag length instead, which also matches what TCP uncharges.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
net/core/datagram.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/datagram.c b/net/core/datagram.c
index ecc30a6f8302..489d92fe6dae 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -737,7 +737,7 @@ zerocopy_fill_skb_from_devmem(struct sk_buff *skb, struct iov_iter *from,
netmem_inc_ref(net_iov_to_netmem(niov));
skb_add_rx_frag_netmem(skb, i, net_iov_to_netmem(niov), off,
- size, PAGE_SIZE);
+ size, size);
iov_iter_advance(from, size);
length -= size;
i++;
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v2 3/7] net: devmem: use niov_shift in net_devmem_get_niov_at()
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 2/7] net: devmem: charge the frag length to TX skb truesize Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 4/7] net: devmem: add a per-device netmem TX frag size limit Stanislav Fomichev
` (4 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
TX bindings use PAGE_SIZE net_iovs, and the TX lookup hard-codes it.
Derive the index and offset from binding->niov_shift instead, so TX
bindings can use larger net_iovs. No functional change, TX bindings are
still created with PAGE_SHIFT.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Mina Almasry <almasrymina@google.com>
---
net/core/devmem.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/core/devmem.c b/net/core/devmem.c
index 32fafbfa1359..6339f221bc82 100644
--- a/net/core/devmem.c
+++ b/net/core/devmem.c
@@ -455,13 +455,15 @@ struct net_iov *
net_devmem_get_niov_at(struct net_devmem_dmabuf_binding *binding,
size_t virt_addr, size_t *off, size_t *size)
{
+ size_t niov_size = 1UL << binding->niov_shift;
+
if (virt_addr >= binding->dmabuf->size)
return NULL;
- *off = virt_addr % PAGE_SIZE;
- *size = PAGE_SIZE - *off;
+ *off = virt_addr & (niov_size - 1);
+ *size = niov_size - *off;
- return binding->tx_vec[virt_addr / PAGE_SIZE];
+ return binding->tx_vec[virt_addr >> binding->niov_shift];
}
/*** "Dmabuf devmem memory provider" ***/
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v2 4/7] net: devmem: add a per-device netmem TX frag size limit
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
` (2 preceding siblings ...)
2026-11-03 23:51 ` [PATCH net-next v2 3/7] net: devmem: use niov_shift in net_devmem_get_niov_at() Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-04 15:41 ` Mina Almasry
2026-11-03 23:51 ` [PATCH net-next v2 5/7] bnxt_en: limit netmem TX frags to 32KB Stanislav Fomichev
` (3 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
Devmem TX frags are bounded only by the net_iov size, which is about
to grow up to 2MB, more than some devices can describe in a single TX
descriptor.
Add netmem_tx_max_frag_size, U32_MAX by default, and cap devmem TX
frags to the limit of the device the binding is attached to.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
Documentation/networking/net_cachelines/net_device.rst | 1 +
Documentation/networking/netmem.rst | 6 ++++++
include/linux/netdevice.h | 2 ++
net/core/datagram.c | 1 +
net/core/dev.c | 1 +
net/core/devmem.c | 1 +
net/core/devmem.h | 1 +
7 files changed, 13 insertions(+)
diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
index 8eceaa80b686..4f5fd5b99154 100644
--- a/Documentation/networking/net_cachelines/net_device.rst
+++ b/Documentation/networking/net_cachelines/net_device.rst
@@ -76,6 +76,7 @@ unsigned_short dev_id
unsigned_short dev_port
spinlock_t addr_list_lock
int irq
+u32 netmem_tx_max_frag_size
struct netdev_hw_addr_list uc
struct netdev_hw_addr_list mc
struct netdev_hw_addr_list dev_addrs
diff --git a/Documentation/networking/netmem.rst b/Documentation/networking/netmem.rst
index 6871dcdd700c..04861c60cfa1 100644
--- a/Documentation/networking/netmem.rst
+++ b/Documentation/networking/netmem.rst
@@ -155,3 +155,9 @@ Driver TX Requirements
- `NETMEM_TX_NO_DMA`: for virtual or passthrough devices that do
not DMA, but still support handling of netmem-backed skbs.
+
+3. Drivers which limit the size of a single TX buffer should set
+ `netdev->netmem_tx_max_frag_size` to that limit. Devmem TX frags are
+ capped at it, otherwise a frag can span a whole net_iov, which may be
+ much larger than a page. The default is U32_MAX, the value is read when
+ the dmabuf binding is created.
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c0ae442c4344..4453b80bf7ea 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1845,6 +1845,7 @@ enum netdev_reg_state {
* drivers. Mainly used by logical interfaces, such as
* bonding and tunnels
* @netmem_tx: device netmem TX mode
+ * @netmem_tx_max_frag_size: max size of a netmem TX frag
* @pacing_offload: enable EDT pacing offload.
*
* @name: This is the first field of the "visible" part of this structure
@@ -2342,6 +2343,7 @@ struct net_device {
unsigned short dev_port;
int irq;
u32 priv_len;
+ u32 netmem_tx_max_frag_size;
spinlock_t addr_list_lock;
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 489d92fe6dae..a8d3f87d38c5 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -734,6 +734,7 @@ zerocopy_fill_skb_from_devmem(struct sk_buff *skb, struct iov_iter *from,
size = min_t(size_t, size, length);
size = min_t(size_t, size, iter_iov_len(from));
+ size = min_t(size_t, size, binding->tx_max_frag_size);
netmem_inc_ref(net_iov_to_netmem(niov));
skb_add_rx_frag_netmem(skb, i, net_iov_to_netmem(niov), off,
diff --git a/net/core/dev.c b/net/core/dev.c
index 3ac700d37e59..ba2f887dcd39 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12350,6 +12350,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
dev->gro_ipv4_max_size = GRO_LEGACY_MAX_SIZE;
dev->tso_max_size = TSO_LEGACY_MAX_SIZE;
dev->tso_max_segs = TSO_MAX_SEGS;
+ dev->netmem_tx_max_frag_size = U32_MAX;
dev->upper_level = 1;
dev->lower_level = 1;
#ifdef CONFIG_LOCKDEP
diff --git a/net/core/devmem.c b/net/core/devmem.c
index 6339f221bc82..19c039ed2cb2 100644
--- a/net/core/devmem.c
+++ b/net/core/devmem.c
@@ -218,6 +218,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
binding->dev = dev;
binding->vdev = vdev;
+ binding->tx_max_frag_size = dev->netmem_tx_max_frag_size;
write_pnet(&binding->net, sock_net(nl_sk));
binding->uid = sk_uid(nl_sk);
binding->niov_shift = niov_shift;
diff --git a/net/core/devmem.h b/net/core/devmem.h
index 8fa089776610..97ff1f13fb84 100644
--- a/net/core/devmem.h
+++ b/net/core/devmem.h
@@ -79,6 +79,7 @@ struct net_devmem_dmabuf_binding {
struct net_iov **tx_vec;
unsigned int niov_shift;
+ u32 tx_max_frag_size;
struct work_struct unbind_w;
};
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v2 5/7] bnxt_en: limit netmem TX frags to 32KB
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
` (3 preceding siblings ...)
2026-11-03 23:51 ` [PATCH net-next v2 4/7] net: devmem: add a per-device netmem TX frag size limit Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-04 17:35 ` Michael Chan
2026-11-03 23:51 ` [PATCH net-next v2 6/7] net: devmem: size TX net_iovs from the dmabuf sg table Stanislav Fomichev
` (2 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
The TX BD length field is 16 bits wide. Limit netmem TX frags to the
largest power of 2 which fits, which keeps 4K aligned frags 4K aligned.
With 64K pages this already applies to PAGE_SIZE net_iovs, whose 64KB
frags would otherwise wrap the BD length to 0 with BIG TCP.
Tested on a 50Gb/s NIC: devmem TX from a 2MB hugepage-backed udmabuf
runs at line rate with 2-3 frags per 64KB skb, none above 32KB.
kperf output (sender side, 1 flow):
client: == Source <sender>
client: Tx 46.358 Gbps (174483046400 bytes in 30110590 usec)
client: Rx 0.000 Gbps (0 bytes in 30110590 usec)
client: TCP retrans reord rtt rttvar d_ce snd_wnd cwnd
client: 729 153 599 48 0 13893632 3147
client: net CPU 71: usr: 0.03% sys: 0.06% idle:67.62% iow: 0.00% irq: 1.12% sirq:31.14%
client: app CPU 72: usr: 0.16% sys: 6.01% idle:90.66% iow: 0.00% irq: 0.83% sirq: 2.32%
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Acked-by: Mina Almasry <almasrymina@google.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index e7a4190a8c78..c8a887facc20 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -17439,6 +17439,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (BNXT_SUPPORTS_QUEUE_API(bp))
dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops;
dev->netmem_tx = NETMEM_TX_DMA;
+ dev->netmem_tx_max_frag_size = SZ_32K;
rc = register_netdev(dev);
if (rc)
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v2 6/7] net: devmem: size TX net_iovs from the dmabuf sg table
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
` (4 preceding siblings ...)
2026-11-03 23:51 ` [PATCH net-next v2 5/7] bnxt_en: limit netmem TX frags to 32KB Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 7/7] selftests: drv-net: devmem: TX from a hugepage-backed dmabuf Stanislav Fomichev
2026-11-04 0:14 ` [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Mina Almasry
7 siblings, 0 replies; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
PAGE_SIZE TX net_iovs cap devmem skbs at MAX_SKB_FRAGS pages (~68KB),
which makes BIG TCP ineffective.
TX net_iovs only need to be DMA contiguous. Use the largest power of 2,
from PAGE_SIZE up to 2MB, which aligns every DMA segment of the dmabuf:
- 2MB hugepage-backed udmabufs get 2MB net_iovs
- no UAPI change, TX addresses are dmabuf offsets
- skbs are still bounded by TCP's size_goal, only frags get larger
The net_iov size doesn't depend on the device: frags are capped to the
device limit when they are built, and many frags share a net_iov.
Capping the net_iov instead would only split frags at net_iov
boundaries and allocate more net_iovs.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Mina Almasry <almasrymina@google.com>
---
net/core/devmem.c | 28 ++++++++++++++++++++++++++--
net/core/netdev-genl.c | 2 +-
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/net/core/devmem.c b/net/core/devmem.c
index 19c039ed2cb2..98c9594dbf99 100644
--- a/net/core/devmem.c
+++ b/net/core/devmem.c
@@ -181,6 +181,20 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx,
return err;
}
+static bool net_devmem_sgt_aligned(struct sg_table *sgt, size_t size)
+{
+ struct scatterlist *sg;
+ unsigned int i;
+
+ for_each_sgtable_dma_sg(sgt, sg, i) {
+ if (!IS_ALIGNED(sg_dma_address(sg), size) ||
+ !IS_ALIGNED(sg_dma_len(sg), size))
+ return false;
+ }
+ return true;
+}
+
+/* niov_shift == 0 picks the net_iov size from the dmabuf, TX only */
struct net_devmem_dmabuf_binding *
net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
struct device *dma_dev,
@@ -191,11 +205,11 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
struct netlink_ext_ack *extack)
{
struct net_devmem_dmabuf_binding *binding;
- size_t niov_size = 1UL << niov_shift;
static u32 id_alloc_next;
struct scatterlist *sg;
struct dma_buf *dmabuf;
unsigned int sg_idx;
+ size_t niov_size;
size_t niov_idx;
size_t i;
long err;
@@ -221,7 +235,6 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
binding->tx_max_frag_size = dev->netmem_tx_max_frag_size;
write_pnet(&binding->net, sock_net(nl_sk));
binding->uid = sk_uid(nl_sk);
- binding->niov_shift = niov_shift;
xa_init_flags(&binding->bound_rxqs, XA_FLAGS_ALLOC);
err = percpu_ref_init(&binding->ref,
@@ -266,6 +279,17 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
goto err_unmap;
}
+ if (!niov_shift) {
+ niov_size = SZ_2M;
+ while (niov_size > PAGE_SIZE &&
+ (!IS_ALIGNED(dmabuf->size, niov_size) ||
+ !net_devmem_sgt_aligned(binding->sgt, niov_size)))
+ niov_size /= 2;
+ niov_shift = ilog2(niov_size);
+ }
+ binding->niov_shift = niov_shift;
+ niov_size = 1UL << niov_shift;
+
if (!IS_ALIGNED(dmabuf->size, niov_size)) {
err = -EINVAL;
NL_SET_ERR_MSG_FMT(extack,
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index 384fdc5ae514..bfd229bd31ca 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -1261,7 +1261,7 @@ int netdev_nl_bind_tx_doit(struct sk_buff *skb, struct genl_info *info)
binding = net_devmem_bind_dmabuf(bind_dev,
bind_dev != netdev ? netdev : NULL,
dma_dev, DMA_TO_DEVICE, dmabuf_fd,
- PAGE_SHIFT, priv, NETLINK_CB(skb).sk,
+ 0, priv, NETLINK_CB(skb).sk,
info->extack);
if (IS_ERR(binding)) {
err = PTR_ERR(binding);
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v2 7/7] selftests: drv-net: devmem: TX from a hugepage-backed dmabuf
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
` (5 preceding siblings ...)
2026-11-03 23:51 ` [PATCH net-next v2 6/7] net: devmem: size TX net_iovs from the dmabuf sg table Stanislav Fomichev
@ 2026-11-03 23:51 ` Stanislav Fomichev
2026-11-04 14:43 ` Dragos Tatulea
2026-11-04 0:14 ` [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Mina Almasry
7 siblings, 1 reply; 14+ messages in thread
From: Stanislav Fomichev @ 2026-11-03 23:51 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
TX net_iovs are now sized from the dmabuf layout, but the TX tests
use a regular memfd, which usually keeps them small. Add -H to ncdevmem
to back the udmabuf with 2MB hugepages and a TX test which sends a 3MB
buffer from it, so that frags end at and continue past the 2MB net_iov
boundary. The payload has a 7 byte period to catch offset errors.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Acked-by: Mina Almasry <almasrymina@google.com>
---
.../selftests/drivers/net/hw/devmem.py | 10 ++++-
.../selftests/drivers/net/hw/devmem_lib.py | 43 +++++++++++++++++--
.../selftests/drivers/net/hw/ncdevmem.c | 8 +++-
.../selftests/drivers/net/hw/nk_devmem.py | 11 ++++-
4 files changed, 63 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/hw/devmem.py b/tools/testing/selftests/drivers/net/hw/devmem.py
index 82c11ffc4add..aa7141fb36f7 100755
--- a/tools/testing/selftests/drivers/net/hw/devmem.py
+++ b/tools/testing/selftests/drivers/net/hw/devmem.py
@@ -3,7 +3,7 @@
from os import path
from devmem_lib import (setup_test, run_rx, run_tx, run_tx_chunks, run_rx_hds,
- run_rx_large_niov)
+ run_rx_large_niov, run_tx_large_niov)
from lib.py import ksft_run, ksft_exit, ksft_disruptive
from lib.py import NetDrvEpEnv
@@ -36,12 +36,18 @@ from lib.py import NetDrvEpEnv
run_rx_large_niov(cfg)
+@ksft_disruptive
+def check_tx_large_niov(cfg) -> None:
+ """Run the devmem TX test from a hugepage-backed dmabuf."""
+ run_tx_large_niov(cfg)
+
+
def main() -> None:
"""Run the devmem test cases."""
with NetDrvEpEnv(__file__) as cfg:
setup_test(cfg, path.abspath(path.dirname(__file__) + "/ncdevmem"))
ksft_run([check_rx, check_tx, check_tx_chunks, check_rx_hds,
- check_rx_large_niov],
+ check_rx_large_niov, check_tx_large_niov],
args=(cfg,))
ksft_exit()
diff --git a/tools/testing/selftests/drivers/net/hw/devmem_lib.py b/tools/testing/selftests/drivers/net/hw/devmem_lib.py
index 71b916c16196..8058fd1ddd50 100644
--- a/tools/testing/selftests/drivers/net/hw/devmem_lib.py
+++ b/tools/testing/selftests/drivers/net/hw/devmem_lib.py
@@ -2,6 +2,7 @@
# pylint: disable=invalid-name,too-many-arguments
"""Shared helpers for devmem TCP selftests."""
+import hashlib
import os
import re
@@ -42,15 +43,17 @@ NR_HUGEPAGES_FILE = "/proc/sys/vm/nr_hugepages"
defer(_restore_nr_hugepages, nr_hugepages)
-def _probe_devmem(cfg, rx_page_size):
+def _probe_devmem(cfg, rx_page_size, hugepages=False):
"""Return True if ncdevmem can bind cfg.ifname at @rx_page_size."""
probe_command = f"{cfg.bin_local} -f {cfg.ifname}"
if rx_page_size != RX_PAGE_SIZE_DEFAULT:
probe_command += f" -b {rx_page_size}"
+ if hugepages:
+ probe_command += " -H"
return cmd(probe_command, fail=False, shell=True).ret == 0
-def require_devmem(cfg, rx_page_size=RX_PAGE_SIZE_DEFAULT):
+def require_devmem(cfg, rx_page_size=RX_PAGE_SIZE_DEFAULT, hugepages=False):
"""Probe ncdevmem on cfg.ifname and SKIP the test if devmem isn't supported."""
if rx_page_size not in PROBE_RX_PAGE_SIZES:
raise RuntimeError(
@@ -63,10 +66,15 @@ NR_HUGEPAGES_FILE = "/proc/sys/vm/nr_hugepages"
# ncdevmem's queue range and cause the probe to fail.
cfg.devmem_supported = {size: _probe_devmem(cfg, size)
for size in PROBE_RX_PAGE_SIZES}
+ cfg.devmem_hugepages = _probe_devmem(cfg, RX_PAGE_SIZE_DEFAULT,
+ hugepages=True)
if not cfg.devmem_supported[RX_PAGE_SIZE_DEFAULT]:
raise KsftSkipEx("Test requires devmem support")
+ if hugepages and not cfg.devmem_hugepages:
+ raise KsftSkipEx("Test requires a 2MB hugepage-backed dmabuf")
+
if rx_page_size != RX_PAGE_SIZE_DEFAULT:
page_size = os.sysconf("SC_PAGE_SIZE")
if not _is_aligned(rx_page_size, page_size):
@@ -169,7 +177,7 @@ def ncdevmem_rx(cfg, port, verify=True, fail_on_linear=False, flow_steer=False,
return " ".join(parts)
-def ncdevmem_tx(cfg, port, chunk_size=0):
+def ncdevmem_tx(cfg, port, chunk_size=0, hugepages=False):
"""Build the ncdevmem TX send command."""
if hasattr(cfg, 'netns'):
ifname = cfg.nk_guest_ifname
@@ -182,6 +190,8 @@ def ncdevmem_rx(cfg, port, verify=True, fail_on_linear=False, flow_steer=False,
if chunk_size:
extras.append(f"-z {chunk_size}")
+ if hugepages:
+ extras.append("-H")
parts = [cfg.bin_local, f"-f {ifname}", f"-s {addr}",
f"-p {port}", *extras]
@@ -269,6 +279,33 @@ def ncdevmem_rx(cfg, port, verify=True, fail_on_linear=False, flow_steer=False,
ksft_eq(socat.stdout.strip(), "hello\nworld")
+def run_tx_large_niov(cfg):
+ """Run the devmem TX test from a 2MB hugepage-backed dmabuf.
+
+ The kernel sizes TX niovs from the dmabuf layout. Send a single buffer
+ larger than a hugepage so that frags end at and continue past the niov
+ boundary.
+ """
+ require_devmem(cfg, hugepages=True)
+ _reserve_hugepages()
+ configure_nic(cfg)
+ netns = getattr(cfg, "netns", None)
+ port = rand_port()
+ size = 3 * 1024 * 1024
+ pattern = "abcdefg"
+ expected = (pattern * (size // len(pattern) + 1))[:size]
+ tx_cmd = ncdevmem_tx(cfg, port, hugepages=True)
+ # Hash on the remote, bkg() only drains stdout once the command exits.
+ listen_cmd = f"{socat_listen(cfg, port)} | sha256sum"
+
+ with bkg(listen_cmd, host=cfg.remote, exit_wait=True) as socat:
+ wait_port_listen(port, host=cfg.remote)
+ cmd(f"bash -c 'yes {pattern} | tr -d \"\\n\" | head -c {size} | {tx_cmd}'",
+ ns=netns, shell=True)
+ ksft_eq(socat.stdout.split()[0],
+ hashlib.sha256(expected.encode()).hexdigest())
+
+
def run_rx_large_niov(cfg):
"""Run the devmem RX test with a large niov (rx-page-size > PAGE_SIZE).
diff --git a/tools/testing/selftests/drivers/net/hw/ncdevmem.c b/tools/testing/selftests/drivers/net/hw/ncdevmem.c
index 918e3b51f3b8..e29ff27087e7 100644
--- a/tools/testing/selftests/drivers/net/hw/ncdevmem.c
+++ b/tools/testing/selftests/drivers/net/hw/ncdevmem.c
@@ -104,6 +104,7 @@ static uint32_t tx_dmabuf_id;
static int waittime_ms = 500;
static bool fail_on_linear;
static uint32_t rx_page_size;
+static bool use_hugepages;
/* System state loaded by current_config_load() */
#define MAX_FLOWS 8
@@ -162,7 +163,7 @@ static struct memory_buffer *udmabuf_alloc(size_t size)
}
memfd_flags = MFD_ALLOW_SEALING;
- if (rx_page_size > getpagesize())
+ if (use_hugepages || rx_page_size > getpagesize())
memfd_flags |= MFD_HUGETLB | MFD_HUGE_2MB;
ctx->memfd = memfd_create("udmabuf-test", memfd_flags);
@@ -1428,11 +1429,14 @@ int main(int argc, char *argv[])
int is_server = 0, opt;
int ret, err = 1;
- while ((opt = getopt(argc, argv, "Lls:c:p:v:q:t:f:z:nb:")) != -1) {
+ while ((opt = getopt(argc, argv, "Lls:c:p:v:q:t:f:z:nb:H")) != -1) {
switch (opt) {
case 'L':
fail_on_linear = true;
break;
+ case 'H':
+ use_hugepages = true;
+ break;
case 'l':
is_server = 1;
break;
diff --git a/tools/testing/selftests/drivers/net/hw/nk_devmem.py b/tools/testing/selftests/drivers/net/hw/nk_devmem.py
index 61c6f31f01e5..799030db7c12 100755
--- a/tools/testing/selftests/drivers/net/hw/nk_devmem.py
+++ b/tools/testing/selftests/drivers/net/hw/nk_devmem.py
@@ -4,7 +4,7 @@
import os
from devmem_lib import (setup_test, run_rx, run_tx, run_tx_chunks, run_rx_hds,
- run_rx_large_niov)
+ run_rx_large_niov, run_tx_large_niov)
from lib.py import ksft_run, ksft_exit, ksft_disruptive
from lib.py import NetDrvContEnv
@@ -37,6 +37,12 @@ from lib.py import NetDrvContEnv
run_rx_large_niov(cfg)
+@ksft_disruptive
+def check_nk_tx_large_niov(cfg) -> None:
+ """Run the devmem TX large-niov test through netkit."""
+ run_tx_large_niov(cfg)
+
+
def main() -> None:
"""Run the netkit devmem test cases."""
with NetDrvContEnv(__file__, rxqueues=2, primary_rx_redirect=True) as cfg:
@@ -44,7 +50,8 @@ from lib.py import NetDrvContEnv
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ncdevmem"))
ksft_run([check_nk_rx, check_nk_tx, check_nk_tx_chunks,
- check_nk_rx_hds, check_nk_rx_large_niov], args=(cfg,))
+ check_nk_rx_hds, check_nk_rx_large_niov,
+ check_nk_tx_large_niov], args=(cfg,))
ksft_exit()
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
` (6 preceding siblings ...)
2026-11-03 23:51 ` [PATCH net-next v2 7/7] selftests: drv-net: devmem: TX from a hugepage-backed dmabuf Stanislav Fomichev
@ 2026-11-04 0:14 ` Mina Almasry
7 siblings, 0 replies; 14+ messages in thread
From: Mina Almasry @ 2026-11-04 0:14 UTC (permalink / raw)
To: Stanislav Fomichev, netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
On Tue, Nov 3, 2026 at 3:51 PM Stanislav Fomichev <sdf.kernel@gmail.com> wrote:
>
> TX bindings use PAGE_SIZE net_iovs, so a frag covers at most a page.
> A 64KB skb needs 16 frags, and MAX_SKB_FRAGS caps devmem skbs at about
> 68KB, which makes BIG TCP ineffective for devmem TX.
>
> This series picks the TX net_iov size from the dmabuf sg table instead:
> the largest power of 2, up to 2MB, which aligns every DMA segment. With
> a 2MB hugepage-backed udmabuf a BIG TCP skb takes a few frags. There's
> no UAPI change since TX addresses are dmabuf offsets.
>
> TCP still bounds skbs by size_goal, so frags get larger, skbs don't.
> A single frag can now be as large as the skb, which matters for
> NETMEM_TX drivers with tso_max_size above 64KB:
> - mlx5: 32-bit length per data segment
> - gve: splits frags into 16KB descriptors
> - fbnic: keeps the default 64KB tso_max_size
> - bnxt: 16-bit BD length, devmem TX frags are capped at 32KB by a new
> per-device limit
Reviewed-by: Mina Almasry <almasrymina@google.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v2 7/7] selftests: drv-net: devmem: TX from a hugepage-backed dmabuf
2026-11-03 23:51 ` [PATCH net-next v2 7/7] selftests: drv-net: devmem: TX from a hugepage-backed dmabuf Stanislav Fomichev
@ 2026-11-04 14:43 ` Dragos Tatulea
0 siblings, 0 replies; 14+ messages in thread
From: Dragos Tatulea @ 2026-11-04 14:43 UTC (permalink / raw)
To: Stanislav Fomichev, netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
On 04.11.26 00:51, Stanislav Fomichev wrote:
> TX net_iovs are now sized from the dmabuf layout, but the TX tests
> use a regular memfd, which usually keeps them small. Add -H to ncdevmem
> to back the udmabuf with 2MB hugepages and a TX test which sends a 3MB
> buffer from it, so that frags end at and continue past the 2MB net_iov
> boundary. The payload has a 7 byte period to catch offset errors.
>
Why not add a test with a BIG TCP GSO test as well?
Nice improvement btw. FWIW for the series:
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Thanks,
Dragos
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v2 4/7] net: devmem: add a per-device netmem TX frag size limit
2026-11-03 23:51 ` [PATCH net-next v2 4/7] net: devmem: add a per-device netmem TX frag size limit Stanislav Fomichev
@ 2026-11-04 15:41 ` Mina Almasry
0 siblings, 0 replies; 14+ messages in thread
From: Mina Almasry @ 2026-11-04 15:41 UTC (permalink / raw)
To: Stanislav Fomichev, netdev
Cc: davem, edumazet, kuba, pabeni, andrew+netdev, edumazet, horms,
corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel, leitao,
linux-doc, linux-kernel, linux-kselftest
On Tue, Nov 3, 2026 at 3:51 PM Stanislav Fomichev <sdf.kernel@gmail.com> wrote:
>
> Devmem TX frags are bounded only by the net_iov size, which is about
> to grow up to 2MB, more than some devices can describe in a single TX
> descriptor.
>
> Add netmem_tx_max_frag_size, U32_MAX by default, and cap devmem TX
> frags to the limit of the device the binding is attached to.
>
> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
> ---
> Documentation/networking/net_cachelines/net_device.rst | 1 +
> Documentation/networking/netmem.rst | 6 ++++++
> include/linux/netdevice.h | 2 ++
> net/core/datagram.c | 1 +
> net/core/dev.c | 1 +
> net/core/devmem.c | 1 +
> net/core/devmem.h | 1 +
> 7 files changed, 13 insertions(+)
>
...
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 3ac700d37e59..ba2f887dcd39 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -12350,6 +12350,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
> dev->gro_ipv4_max_size = GRO_LEGACY_MAX_SIZE;
> dev->tso_max_size = TSO_LEGACY_MAX_SIZE;
> dev->tso_max_segs = TSO_MAX_SEGS;
> + dev->netmem_tx_max_frag_size = U32_MAX;
I wonder if netmem_tx_max_frag_size should default to PAGE_SIZE instead
of U32_MAX, and have drivers opt in by raising it after verification
(e.g. SZ_32K for bnxt and U32_MAX for mlx5 in this series)?
With U32_MAX as the default, large frags are enabled on all NETMEM_TX
drivers unless they opt out. For example, fbnic also has a 16-bit TX
descriptor length (FBNIC_TWD_LEN_MASK) and only avoids hitting
dma_error here because its tso_max_size happens to be 64KB today, and
gve hasn't been tested with >PAGE_SIZE devmem TX frags yet. Defaulting
to PAGE_SIZE (similar to tso_max_size = TSO_LEGACY_MAX_SIZE above) seems
safer for existing and future drivers.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags
2026-11-03 23:51 ` [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags Stanislav Fomichev
@ 2026-11-04 16:47 ` Breno Leitao
2026-11-04 17:31 ` Michael Chan
1 sibling, 0 replies; 14+ messages in thread
From: Breno Leitao @ 2026-11-04 16:47 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: netdev, davem, edumazet, kuba, pabeni, andrew+netdev, edumazet,
horms, corbet, skhan, rdunlap, michael.chan, pavan.chebbi, sdf,
almasrymina, bobbyeshleman, asml.silence, razor, daniel,
linux-doc, linux-kernel, linux-kselftest
On Tue, Nov 03, 2026 at 03:51:46PM -0800, Stanislav Fomichev wrote:
> With MAX_SKB_FRAGS > TX_MAX_FRAGS, the xmit path linearizes skbs with
> more frags than a packet can have BDs. For GSO skbs, linearizing needs a
> large allocation, can produce a head which doesn't fit in a BD with BIG
> TCP, and always fails for unreadable skbs. Clear the GSO features of
> such skbs in ndo_features_check instead, so that the stack segments
> them. Non-GSO skbs are still linearized.
>
> Suggested-by: Eric Dumazet <edumazet@google.com>
> Link: https://lore.kernel.org/all/CANn89i+ps_CozfOyRnKav0_LUmSekJ9ExB5JkDbTAVf_ss_98g@mail.gmail.com/
> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags
2026-11-03 23:51 ` [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags Stanislav Fomichev
2026-11-04 16:47 ` Breno Leitao
@ 2026-11-04 17:31 ` Michael Chan
1 sibling, 0 replies; 14+ messages in thread
From: Michael Chan @ 2026-11-04 17:31 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: netdev, davem, edumazet, kuba, pabeni, andrew+netdev, edumazet,
horms, corbet, skhan, rdunlap, pavan.chebbi, sdf, almasrymina,
bobbyeshleman, asml.silence, razor, daniel, leitao, linux-doc,
linux-kernel, linux-kselftest
[-- Attachment #1: Type: text/plain, Size: 769 bytes --]
On Tue, Nov 3, 2026 at 3:51 PM Stanislav Fomichev <sdf.kernel@gmail.com> wrote:
>
> With MAX_SKB_FRAGS > TX_MAX_FRAGS, the xmit path linearizes skbs with
> more frags than a packet can have BDs. For GSO skbs, linearizing needs a
> large allocation, can produce a head which doesn't fit in a BD with BIG
> TCP, and always fails for unreadable skbs. Clear the GSO features of
> such skbs in ndo_features_check instead, so that the stack segments
> them. Non-GSO skbs are still linearized.
>
> Suggested-by: Eric Dumazet <edumazet@google.com>
> Link: https://lore.kernel.org/all/CANn89i+ps_CozfOyRnKav0_LUmSekJ9ExB5JkDbTAVf_ss_98g@mail.gmail.com/
> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v2 5/7] bnxt_en: limit netmem TX frags to 32KB
2026-11-03 23:51 ` [PATCH net-next v2 5/7] bnxt_en: limit netmem TX frags to 32KB Stanislav Fomichev
@ 2026-11-04 17:35 ` Michael Chan
0 siblings, 0 replies; 14+ messages in thread
From: Michael Chan @ 2026-11-04 17:35 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: netdev, davem, edumazet, kuba, pabeni, andrew+netdev, edumazet,
horms, corbet, skhan, rdunlap, pavan.chebbi, sdf, almasrymina,
bobbyeshleman, asml.silence, razor, daniel, leitao, linux-doc,
linux-kernel, linux-kselftest
[-- Attachment #1: Type: text/plain, Size: 1197 bytes --]
On Tue, Nov 3, 2026 at 3:52 PM Stanislav Fomichev <sdf.kernel@gmail.com> wrote:
>
> The TX BD length field is 16 bits wide. Limit netmem TX frags to the
> largest power of 2 which fits, which keeps 4K aligned frags 4K aligned.
>
> With 64K pages this already applies to PAGE_SIZE net_iovs, whose 64KB
> frags would otherwise wrap the BD length to 0 with BIG TCP.
>
> Tested on a 50Gb/s NIC: devmem TX from a 2MB hugepage-backed udmabuf
> runs at line rate with 2-3 frags per 64KB skb, none above 32KB.
>
> kperf output (sender side, 1 flow):
>
> client: == Source <sender>
> client: Tx 46.358 Gbps (174483046400 bytes in 30110590 usec)
> client: Rx 0.000 Gbps (0 bytes in 30110590 usec)
> client: TCP retrans reord rtt rttvar d_ce snd_wnd cwnd
> client: 729 153 599 48 0 13893632 3147
> client: net CPU 71: usr: 0.03% sys: 0.06% idle:67.62% iow: 0.00% irq: 1.12% sirq:31.14%
> client: app CPU 72: usr: 0.16% sys: 6.01% idle:90.66% iow: 0.00% irq: 0.83% sirq: 2.32%
>
> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
> Acked-by: Mina Almasry <almasrymina@google.com>
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-11-04 17:35 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-03 23:51 [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 1/7] bnxt_en: let the stack segment GSO skbs with too many frags Stanislav Fomichev
2026-11-04 16:47 ` Breno Leitao
2026-11-04 17:31 ` Michael Chan
2026-11-03 23:51 ` [PATCH net-next v2 2/7] net: devmem: charge the frag length to TX skb truesize Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 3/7] net: devmem: use niov_shift in net_devmem_get_niov_at() Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 4/7] net: devmem: add a per-device netmem TX frag size limit Stanislav Fomichev
2026-11-04 15:41 ` Mina Almasry
2026-11-03 23:51 ` [PATCH net-next v2 5/7] bnxt_en: limit netmem TX frags to 32KB Stanislav Fomichev
2026-11-04 17:35 ` Michael Chan
2026-11-03 23:51 ` [PATCH net-next v2 6/7] net: devmem: size TX net_iovs from the dmabuf sg table Stanislav Fomichev
2026-11-03 23:51 ` [PATCH net-next v2 7/7] selftests: drv-net: devmem: TX from a hugepage-backed dmabuf Stanislav Fomichev
2026-11-04 14:43 ` Dragos Tatulea
2026-11-04 0:14 ` [PATCH net-next v2 0/7] net: devmem: size TX net_iovs from the dmabuf layout Mina Almasry
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox