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,
mohsin.bashr@gmail.com, Willem de Bruijn <willemb@google.com>
Subject: [PATCH net-next v3 7/7] net: pktgen: add support for SO_TXTIME
Date: Sun, 26 Jul 2026 16:28:51 -0400 [thread overview]
Message-ID: <20260726202902.760552-8-willemdebruijn.kernel@gmail.com> (raw)
In-Reply-To: <20260726202902.760552-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.
Changes
v1 -> v2
- avoid data race on txtime_delay
- same on flags
- (minor) style: avoid two >80 column warnings (checkpatch)
v1: https://lore.kernel.org/netdev/20260706133433.3142805-8-willemdebruijn.kernel@gmail.com/
fixup pktgen: txtime_delay READ_ONCE
---
net/core/pktgen.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 1 deletion(-)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 5b4dd04d6124..7897e4220513 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,50 @@ 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;
+
+ WRITE_ONCE(pkt_dev->txtime_delay, (u64)value);
+ sprintf(pg_result, "OK: txtime_delay=%llu",
+ (unsigned long long)value);
+ 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 +1298,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 && READ_ONCE(pkt_dev->txtime_delay))
+ return -EINVAL;
pkt_dev->clone_skb = value;
@@ -2321,6 +2383,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;
@@ -3510,7 +3587,8 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
static void pktgen_xmit(struct pktgen_dev *pkt_dev)
{
- bool skb_shared = !!(READ_ONCE(pkt_dev->flags) & F_SHARED);
+ u32 flags = READ_ONCE(pkt_dev->flags);
+ bool skb_shared = !!(flags & F_SHARED);
struct net_device *odev = pkt_dev->odev;
struct netdev_queue *txq;
unsigned int burst = 1;
@@ -3545,6 +3623,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
/* If no skb or clone count exhausted then get new one */
if (!pkt_dev->skb || (pkt_dev->last_ok &&
++pkt_dev->clone_count >= clone_skb)) {
+ u64 txtime_delay;
+
/* build a new pkt */
kfree_skb(pkt_dev->skb);
@@ -3557,6 +3637,16 @@ 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 */
+
+ txtime_delay = READ_ONCE(pkt_dev->txtime_delay);
+ if (flags & F_TXTIME && txtime_delay) {
+ clockid_t clk = READ_ONCE(pkt_dev->txtime_clockid);
+ ktime_t txtime = ktime_add_ns(ktime_get_clock(clk),
+ txtime_delay);
+
+ skb_set_delivery_type_by_clockid(pkt_dev->skb, txtime,
+ clk);
+ }
}
if (pkt_dev->delay && pkt_dev->last_ok)
@@ -3869,6 +3959,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.229.g6434b31f56-goog
prev parent reply other threads:[~2026-07-26 20:29 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-26 20:28 [PATCH net-next v3 0/7] hardware pacing offload Willem de Bruijn
2026-07-26 20:28 ` [PATCH net-next v3 1/7] net: ethtool: add hardware pacing offload support to rings Willem de Bruijn
2026-07-26 20:28 ` [PATCH net-next v3 2/7] net_sched: sch_fq: clear past skb->tstamp if offloading pacing Willem de Bruijn
2026-07-26 20:28 ` [PATCH net-next v3 3/7] idpf: support pacing offload Willem de Bruijn
2026-07-26 20:28 ` [PATCH net-next v3 4/7] selftests: drv-net: refactor so_txtime errqueue handling Willem de Bruijn
2026-07-26 20:28 ` [PATCH net-next v3 5/7] selftests: drv-net: in so_txtime tell apart sw from hw pacing Willem de Bruijn
2026-07-26 20:28 ` [PATCH net-next v3 6/7] selftests: drv-net: extend so_txtime with hw offload Willem de Bruijn
2026-07-26 20:28 ` 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=20260726202902.760552-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=mohsin.bashr@gmail.com \
--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