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
prev parent reply other threads:[~2026-07-06 13:34 UTC|newest]
Thread overview: 8+ 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-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-06 13:34 ` Willem de Bruijn [this message]
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox