From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, edumazet@google.com,
pabeni@redhat.com, horms@kernel.org, andrew@lunn.ch,
Willem de Bruijn <willemb@google.com>
Subject: [PATCH net-next 7/7] net: pktgen: add support for SO_TXTIME
Date: Mon, 6 Jul 2026 09:34:09 -0400 [thread overview]
Message-ID: <20260706133433.3142805-8-willemdebruijn.kernel@gmail.com> (raw)
In-Reply-To: <20260706133433.3142805-1-willemdebruijn.kernel@gmail.com>
From: Willem de Bruijn <willemb@google.com>
Introduce support for setting the SO_TXTIME delivery txtime on
generated packets. This allows testing pacing and scheduling features
in the network stack (e.g., sch_fq, sch_taprio) and drivers.
Add a new flag 'TXTIME' to enable this feature.
Add two new configuration parameters:
- txtime_delay: offset from now in ns
- txtime_clockid: clock to use (monotonic, realtime, tai)
The queue_xmit mode can clear skb->tstamp in-flight, so this must be
used without clone_skb.
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
Sashiko: ignore data races in the control fields. Pktgen requires
superuser privileges, has many such races already, which are benign.
---
net/core/pktgen.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 8e185b318288..be4fce895b2c 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -201,6 +201,7 @@
pf(SVID_RND) /* Random SVLAN ID */ \
pf(NODE) /* Node memory alloc*/ \
pf(SHARED) /* Shared SKB */ \
+ pf(TXTIME) /* SO_TXTIME support */ \
#define pf(flag) flag##_SHIFT,
enum pkt_flags {
@@ -291,6 +292,10 @@ struct pktgen_dev {
struct page *page;
u64 delay; /* nano-seconds */
+ /* TXTIME support */
+ u64 txtime_delay; /* transmit time delay in ns */
+ clockid_t txtime_clockid; /* clockid for SO_TXTIME */
+
__u64 count; /* Default No packets to send */
__u64 sofar; /* How many pkts we've sent so far */
__u64 tx_bytes; /* How many bytes we've transmitted */
@@ -666,6 +671,17 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
if (pkt_dev->node >= 0)
seq_printf(seq, " node: %d\n", pkt_dev->node);
+ if (pkt_dev->flags & F_TXTIME) {
+ clockid_t clockid = READ_ONCE(pkt_dev->txtime_clockid);
+
+ seq_printf(seq, " txtime_delay: %llu\n",
+ (unsigned long long)pkt_dev->txtime_delay);
+ seq_printf(seq, " txtime_clockid: %s\n",
+ clockid == CLOCK_MONOTONIC ? "monotonic" :
+ clockid == CLOCK_REALTIME ? "realtime" :
+ clockid == CLOCK_TAI ? "tai" : "unknown");
+ }
+
if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
seq_puts(seq, " xmit_mode: netif_receive\n");
else if (pkt_dev->xmit_mode == M_QUEUE_XMIT)
@@ -1141,6 +1157,49 @@ static ssize_t pktgen_if_write(struct file *file,
(unsigned long long) pkt_dev->delay);
return count;
}
+ if (!strcmp(name, "txtime_delay")) {
+ max = min(10, count - i);
+ len = num_arg(&user_buffer[i], max, &value);
+ if (len < 0)
+ return len;
+
+ /* in queue_xmit mode fq may clear tstamp, do not reuse skb */
+ if (value > 0 && pkt_dev->clone_skb > 0)
+ return -EINVAL;
+
+ pkt_dev->txtime_delay = (u64)value;
+ sprintf(pg_result, "OK: txtime_delay=%llu",
+ (unsigned long long)pkt_dev->txtime_delay);
+ return count;
+ }
+ if (!strcmp(name, "txtime_clockid")) {
+ char clockstr[32];
+ clockid_t clk;
+
+ memset(clockstr, 0, sizeof(clockstr));
+ max = min(sizeof(clockstr) - 1, count - i);
+ len = strn_len(&user_buffer[i], max);
+ if (len < 0)
+ return len;
+
+ if (copy_from_user(clockstr, &user_buffer[i], len))
+ return -EFAULT;
+
+ if (!strcmp(clockstr, "monotonic")) {
+ clk = CLOCK_MONOTONIC;
+ } else if (!strcmp(clockstr, "realtime")) {
+ clk = CLOCK_REALTIME;
+ } else if (!strcmp(clockstr, "tai")) {
+ clk = CLOCK_TAI;
+ } else {
+ sprintf(pg_result, "ERROR: unknown clockid '%s'", clockstr);
+ return -EINVAL;
+ }
+
+ sprintf(pg_result, "OK: txtime_clockid=%s", clockstr);
+ WRITE_ONCE(pkt_dev->txtime_clockid, clk);
+ return count;
+ }
if (!strcmp(name, "rate")) {
max = min(10, count - i);
len = num_arg(&user_buffer[i], max, &value);
@@ -1238,6 +1297,8 @@ static ssize_t pktgen_if_write(struct file *file,
if (value > 0 && (pkt_dev->n_imix_entries > 0 ||
!(pkt_dev->flags & F_SHARED)))
return -EINVAL;
+ if (value > 0 && pkt_dev->txtime_delay)
+ return -EINVAL;
pkt_dev->clone_skb = value;
@@ -2321,6 +2382,21 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
}
+static ktime_t ktime_get_clock(clockid_t clockid)
+{
+ switch (clockid) {
+ case CLOCK_REALTIME:
+ return ktime_get_real();
+ case CLOCK_MONOTONIC:
+ return ktime_get();
+ case CLOCK_TAI:
+ return ktime_get_clocktai();
+ default:
+ WARN_ON_ONCE(1);
+ return ktime_get();
+ }
+}
+
static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
{
ktime_t start_time, end_time;
@@ -3557,6 +3633,14 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
}
pkt_dev->last_pkt_size = pkt_dev->skb->len;
pkt_dev->clone_count = 0; /* reset counter */
+
+ if (pkt_dev->flags & F_TXTIME && pkt_dev->txtime_delay) {
+ clockid_t clk = READ_ONCE(pkt_dev->txtime_clockid);
+ ktime_t txtime = ktime_add_ns(ktime_get_clock(clk),
+ pkt_dev->txtime_delay);
+
+ skb_set_delivery_type_by_clockid(pkt_dev->skb, txtime, clk);
+ }
}
if (pkt_dev->delay && pkt_dev->last_ok)
@@ -3869,6 +3953,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
pkt_dev->burst = 1;
pkt_dev->node = NUMA_NO_NODE;
pkt_dev->flags = F_SHARED; /* SKB shared by default */
+ pkt_dev->txtime_clockid = CLOCK_MONOTONIC;
err = pktgen_setup_dev(t->net, pkt_dev, ifname);
if (err)
--
2.55.0.795.g602f6c329a-goog
next prev parent reply other threads:[~2026-07-06 13:34 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 13:34 [PATCH net-next 0/7] hardware pacing offload Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 1/7] net: ethtool: add hardware pacing offload support to rings Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 2/7] net_sched: sch_fq: clear past skb->tstamp if offloading pacing Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 3/7] idpf: support pacing offload Willem de Bruijn
2026-07-10 15:04 ` Paolo Abeni
2026-07-10 21:37 ` Tony Nguyen
2026-07-11 20:13 ` Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 4/7] selftests: drv-net: refactor so_txtime errqueue handling Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 5/7] selftests: drv-net: in so_txtime tell apart sw from hw pacing Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 6/7] selftests: drv-net: extend so_txtime with hw offload Willem de Bruijn
2026-07-10 15:26 ` Paolo Abeni
2026-07-06 13:34 ` Willem de Bruijn [this message]
2026-07-10 15:20 ` [PATCH net-next 7/7] net: pktgen: add support for SO_TXTIME Paolo Abeni
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260706133433.3142805-8-willemdebruijn.kernel@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.