git: 3fade68cfdf9 - main - iflib: accurately count bytes/segments for TSO
Date: Fri, 17 Apr 2026 17:35:06 UTC
The branch main has been updated by gallatin:
URL: https://cgit.FreeBSD.org/src/commit/?id=3fade68cfdf95ee0b517b5d69b270bd8da633404
commit 3fade68cfdf95ee0b517b5d69b270bd8da633404
Author: Andrew Gallatin <gallatin@FreeBSD.org>
AuthorDate: 2026-04-17 15:45:22 +0000
Commit: Andrew Gallatin <gallatin@FreeBSD.org>
CommitDate: 2026-04-17 17:34:27 +0000
iflib: accurately count bytes/segments for TSO
When using software based ifnet counters, iflib has not factored
TSO into account when reporting the segments and bytes sent.
So it will underreport NIC bandwidth by a small percent,
and will undercount sent segments by a large factor.
Fix this by calculating the number of added segments the NIC
will send, and add header size multiplied by that number
to arrive at a correct accounting of segments and bytes sent.
This makes these software counters directly comparable to
hardware counters.
Doing this requires moving the calculation into iflib_encap() where
we have already parsed the packet and know the header size, MSS, etc.
Differential Revision: https://reviews.freebsd.org/D56338
Sponsored by: Netflix
---
sys/net/iflib.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 085b69b62553..1fd8d57f4ee9 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -3478,7 +3478,7 @@ iflib_ether_pad(device_t dev, struct mbuf **m_head, uint16_t min_frame_size)
}
static int
-iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
+iflib_encap(iflib_txq_t txq, struct mbuf **m_headp, int *obytes, int *opkts)
{
if_ctx_t ctx;
if_shared_ctx_t sctx;
@@ -3663,6 +3663,20 @@ defrag:
*/
txq->ift_pidx = pi.ipi_new_pidx;
txq->ift_npending += pi.ipi_ndescs;
+
+ /*
+ * Update packets / bytes sent
+ */
+ if (flags & IFLIB_TSO) {
+ int hlen = pi.ipi_ehdrlen + pi.ipi_ip_hlen + pi.ipi_tcp_hlen;
+ int tsolen = pi.ipi_len - hlen;
+ int nsegs = (tsolen + pi.ipi_tso_segsz - 1) / pi.ipi_tso_segsz;
+ *obytes += tsolen + nsegs * hlen;
+ *opkts += nsegs;
+ } else {
+ *obytes += pi.ipi_len;
+ *opkts += 1;
+ }
} else {
*m_headp = m_head = iflib_remove_mbuf(txq);
if (err == EFBIG) {
@@ -3918,7 +3932,7 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
skipped++;
continue;
}
- err = iflib_encap(txq, mp);
+ err = iflib_encap(txq, mp, &bytes_sent, &pkt_sent);
if (__predict_false(err)) {
/* no room - bail out */
if (err == ENOBUFS)
@@ -3927,10 +3941,8 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx)
/* we can't send this packet - skip it */
continue;
}
- pkt_sent++;
m = *mp;
DBG_COUNTER_INC(tx_sent);
- bytes_sent += m->m_pkthdr.len;
mcast_sent += !!(m->m_flags & M_MCAST);
if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)))
@@ -7136,6 +7148,8 @@ iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
if_ctx_t ctx;
iflib_txq_t txq;
int error;
+ int bytes_sent = 0;
+ int pkt_sent = 0;
ctx = if_getsoftc(ifp);
if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
@@ -7143,7 +7157,7 @@ iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
return (EBUSY);
txq = &ctx->ifc_txqs[0];
- error = iflib_encap(txq, &m);
+ error = iflib_encap(txq, &m, &bytes_sent, &pkt_sent);
if (error == 0)
(void)iflib_txd_db_check(txq, true);
return (error);
@@ -7209,10 +7223,8 @@ iflib_simple_transmit(if_t ifp, struct mbuf *m)
txq = iflib_simple_select_queue(ctx, m);
mtx_lock(&txq->ift_mtx);
- error = iflib_encap(txq, &m);
+ error = iflib_encap(txq, &m, &bytes_sent, &pkt_sent);
if (error == 0) {
- pkt_sent++;
- bytes_sent += m->m_pkthdr.len;
mcast_sent += !!(m->m_flags & M_MCAST);
(void)iflib_txd_db_check(txq, true);
} else {