From: Simon Horman <horms@kernel.org>
To: maciek@machnikowski.net
Cc: Simon Horman <horms@kernel.org>,
netdev@vger.kernel.org, kuba@kernel.org,
richardcochran@gmail.com, milena.olech@intel.com,
willemdebruijn.kernel@gmail.com, andrew@lunn.ch,
vadim.fedorenko@linux.dev
Subject: Re: [PATCH v10 net-next 2/3] netdevsim: Implement basic ptp support
Date: Tue, 18 Aug 2026 14:58:00 +0100 [thread overview]
Message-ID: <20260818135800.629288-1-horms@kernel.org> (raw)
In-Reply-To: <20260815063148.2952-3-maciek@machnikowski.net>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260815063148.2952-1-maciek@machnikowski.net?part=2
---
--- Patch [2]: [PATCH v10 net-next 2/3] netdevsim: Implement basic ptp support ---
commit ef2b7171af287d8c3a8f5064008830a7dd8f4db3
Author: Maciek Machnikowski <maciek@machnikowski.net>
netdevsim: Implement basic ptp support
Adds virtual hardware timestamping to netdevsim by reading the mock PHC
attached to the transmitting netdevsim and to its peer, reporting a TX
timestamp to the socket and stamping the forwarded skb for the RX side.
Also wires up ndo_hwtstamp_get / ndo_hwtstamp_set and extends
nsim_get_ts_info().
A few questions on the timestamping path below.
> diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c
> index 025ea79879f3a..24e7d5592e799 100644
> --- a/drivers/net/netdevsim/ethtool.c
> +++ b/drivers/net/netdevsim/ethtool.c
> @@ -200,7 +200,22 @@ static int nsim_get_ts_info(struct net_device *dev,
> {
> struct netdevsim *ns = netdev_priv(dev);
>
> + ethtool_op_get_ts_info(dev, info);
> + if (!ns->phc) {
> + info->phc_index = -1;
> + return 0;
> + }
> +
[Severity: High]
[Finding: main-1-1]
[Sources: opus-5]
This isn't a bug introduced by this patch, but the new !ns->phc guard looks
like it silently fixes a NULL pointer dereference that exists today, without
a mention in the changelog or a Fixes: tag.
Before this patch nsim_get_ts_info() did:
info->phc_index = mock_phc_index(ns->phc);
and nsim_ethtool_init() installs the shared nsim_ethtool_ops (including
.get_ts_info = nsim_get_ts_info) on every netdevsim netdev, while only
nsim_init_netdevsim() calls mock_phc_create(). nsim_init_netdevsim_vf()
just assigns nsim_vf_netdev_ops and registers the netdev, so ns->phc stays
NULL for VF netdevs.
With CONFIG_PTP_1588_CLOCK_MOCK=y, mock_phc_index() is the real function:
drivers/ptp/ptp_mock.c:mock_phc_index() {
return ptp_clock_index(phc->clock);
}
so ethtool -T on a netdevsim VF netdev dereferences NULL. Would it make
sense to split this guard into its own patch with a Fixes: tag so that
stable tooling can pick it up?
Also, adding ethtool_op_get_ts_info() here changes ethtool -T output for all
netdevsim devices by advertising SOF_TIMESTAMPING_TX_SOFTWARE,
SOF_TIMESTAMPING_RX_SOFTWARE and SOF_TIMESTAMPING_SOFTWARE. Could the
changelog mention that behaviour change?
> info->phc_index = mock_phc_index(ns->phc);
> + if (info->phc_index < 0)
> + return 0;
> +
> + info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
> + SOF_TIMESTAMPING_RX_HARDWARE |
> + SOF_TIMESTAMPING_RAW_HARDWARE;
> +
> + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
> + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
>
> return 0;
> }
> diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
> index 4e9d7e10b527e..e586fd8f3bc37 100644
> --- a/drivers/net/netdevsim/netdev.c
> +++ b/drivers/net/netdevsim/netdev.c
[ ... ]
> @@ -164,6 +171,44 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
> skb_linearize(skb);
>
> skb_tx_timestamp(skb);
> +
> + if (unlikely(READ_ONCE(peer_ns->tstamp_config.rx_filter) !=
> + HWTSTAMP_FILTER_NONE))
> + ptp_info_rx = mock_phc_get_ptp_info(peer_ns->phc);
> +
> + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
> + READ_ONCE(ns->tstamp_config.tx_type) == HWTSTAMP_TX_ON)
> + ptp_info_tx = mock_phc_get_ptp_info(ns->phc);
> +
> + if (unlikely(ptp_info_tx || ptp_info_rx)) {
> + /* Capture both timestamps closely */
> + if (ptp_info_tx)
> + ptp_info_tx->gettime64(ptp_info_tx, &tx_ts);
> + if (ptp_info_rx)
> + ptp_info_rx->gettime64(ptp_info_rx, &rx_ts);
> +
> + /* If TX hardware timestamping is enabled report TX timestamp */
> + if (ptp_info_tx) {
> + shhwtstamps.hwtstamp = timespec64_to_ktime(tx_ts);
> + skb_tstamp_tx(skb_orig, &shhwtstamps);
> + }
[Severity: Medium]
[Finding: gpt-5-6-sol-3-10]
[Sources: gpt-5-6-sol, opus-5]
Can a socket receive two SCM_TSTAMP_SND reports for the same packet here?
The hardware report is emitted after skb_tx_timestamp(), which already
delivered the software one:
include/linux/skbuff.h:skb_tx_timestamp() {
skb_clone_tx_timestamp(skb);
if (skb_shinfo(skb)->tx_flags & (SKBTX_SW_TSTAMP | SKBTX_BPF))
skb_tstamp_tx(skb, NULL);
}
The only suppression of the software report lives in __skb_tstamp_tx():
net/core/skbuff.c:__skb_tstamp_tx() {
if (!hwtstamps && !(tsflags & SOF_TIMESTAMPING_OPT_TX_SWHW) &&
skb_shinfo(orig_skb)->tx_flags & SKBTX_IN_PROGRESS)
return;
netdevsim never sets SKBTX_IN_PROGRESS anywhere - the new code only tests
SKBTX_HW_TSTAMP - so for a socket that enabled both
SOF_TIMESTAMPING_TX_SOFTWARE and SOF_TIMESTAMPING_TX_HARDWARE without
SOF_TIMESTAMPING_OPT_TX_SWHW both reports are delivered.
Would following the usual driver sequence work here, i.e. test
SKBTX_HW_TSTAMP and set SKBTX_IN_PROGRESS before calling
skb_tx_timestamp()?
> +
> + /* Unshare the skb, stamping it must not corrupt cloned copies
> + * and prevents returning single tstamp for Tx and Rx
> + */
> + skb = skb_unshare(skb_orig, GFP_ATOMIC);
> + if (unlikely(!skb)) {
> + if (psp_ext)
> + __skb_ext_put(psp_ext);
> + goto out_drop_cnt;
> + }
[Severity: Low]
[Finding: main-3-8]
[Sources: opus-5]
Should this skb_unshare() be gated on ptp_info_rx?
The enclosing condition is ptp_info_tx || ptp_info_rx, but the only write
into the skb below is guarded by if (ptp_info_rx). On the TX-only path
(peer rx_filter == HWTSTAMP_FILTER_NONE) every timestamped frame gets copied
by skb_copy() for nothing, which also linearizes the buffer that the
hds_config logic just above deliberately left non-linear, and does not carry
queue_mapping.
If the GFP_ATOMIC copy then fails, the frame is dropped via out_drop_cnt
even though nothing needed to be written into it, and after the TX
timestamp was already handed to the socket by skb_tstamp_tx(skb_orig, ...).
[Severity: Low]
[Finding: main-5-12]
[Sources: opus-5]
Does skb_unshare() cover the case this comment describes?
include/linux/skbuff.h:skb_unshare() {
might_sleep_if(gfpflags_allow_blocking(pri));
if (skb_cloned(skb)) {
...
}
The copy is made only for clones, so an skb with skb->users > 1 and
cloned == 0 is returned unchanged. pktgen does
refcount_add(burst, &pkt_dev->skb->users) and resubmits the same skb, so the
skb_hwtstamps(skb) write below touches skb_shared_info that the other
reference holder still owns, and that the peer's NAPI path may read
concurrently after nsim_forward_skb() -> nsim_napi_rx() queues it on
rq->skb_queue. Should the driver check skb_shared() as well, or stamp a
private copy?
> +
> + /* If RX hardware timestamping is enabled report RX timestamp */
> + if (ptp_info_rx)
> + skb_hwtstamps(skb)->hwtstamp =
> + timespec64_to_ktime(rx_ts);
> + }
> +
[Severity: Critical]
[Finding: main-6-13]
[Sources: opus-5]
Can this write corrupt kernel memory for AF_XDP TX skbs?
skb_hwtstamps() returns a pointer into a union in skb_shared_info:
include/linux/skbuff.h:struct skb_shared_info {
union {
struct skb_shared_hwtstamps hwtstamps;
struct xsk_tx_metadata_compl xsk_meta;
};
struct xsk_tx_metadata_compl has a single member, u64 *tx_timestamp, and the
AF_XDP destructor dereferences it with only a NULL check:
net/xdp/xsk.c:xsk_destruct_skb() {
struct xsk_tx_metadata_compl *compl = &skb_shinfo(skb)->xsk_meta;
if (compl->tx_timestamp) {
/* sw completion timestamp, not a real one */
*compl->tx_timestamp = ktime_get_tai_fast_ns();
}
Every generic-xmit AF_XDP skb carries that destructor
(xsk_skb_init_misc() sets skb->destructor = xsk_destruct_skb), and it is
freshly allocated and not cloned, so skb_unshare() above returns the same
skb with the destructor and the overwritten shinfo intact.
__dev_forward_skb() -> skb_scrub_packet() does not orphan the skb or reset
skb_shinfo(), so the value survives to the destructor.
The RX branch is gated only on the peer's setting:
if (unlikely(READ_ONCE(peer_ns->tstamp_config.rx_filter) !=
HWTSTAMP_FILTER_NONE))
ptp_info_rx = mock_phc_get_ptp_info(peer_ns->phc);
so any AF_XDP frame forwarded while the peer has RX timestamping enabled
gets a non-NULL, PHC-derived value in xsk_meta.tx_timestamp, and the
destructor performs an 8-byte write to that address. The mock PHC value is
settable from userspace through clock_settime() on /dev/ptpN via
mock_phc_settime64().
Real NICs avoid this because they only stamp skbs they allocated for RX.
Since netdevsim reuses the TX skb as the RX skb, should it orphan the skb
(clearing skb->destructor) or stamp a private copy before touching
skb_shinfo()->hwtstamps?
> if (unlikely(nsim_forward_skb(dev, peer_dev,
> skb, rq, psp_ext) == NET_RX_DROP))
> goto out_drop_cnt;
> @@ -185,6 +230,63 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
> return NETDEV_TX_OK;
> }
>
> +static int nsim_set_ts_config(struct net_device *netdev,
> + struct kernel_hwtstamp_config *config,
> + struct netlink_ext_ack *extack)
> +{
> + struct netdevsim *ns = netdev_priv(netdev);
> + int rx_filter;
> +
> + if (!ns->phc)
> + return -EOPNOTSUPP;
> +
[ ... ]
> +static int nsim_get_ts_config(struct net_device *netdev,
> + struct kernel_hwtstamp_config *config)
> +{
> + struct netdevsim *ns = netdev_priv(netdev);
> +
> + *config = ns->tstamp_config;
> + return 0;
> +}
[Severity: Low]
[Finding: gpt-5-6-sol-2-6]
[Sources: gpt-5-6-sol, opus-5]
Should nsim_get_ts_config() carry the same !ns->phc check as
nsim_set_ts_config()?
drivers/net/Kconfig allows netdevsim without the mock clock:
depends on PTP_1588_CLOCK_MOCK || PTP_1588_CLOCK_MOCK=n
and with CONFIG_PTP_1588_CLOCK_MOCK=n the stub is used:
include/linux/ptp_mock.h {
static inline struct mock_phc *mock_phc_create(struct device *dev)
{
return NULL;
}
nsim_init_netdevsim() only rejects IS_ERR(), so ns->phc stays NULL. In that
configuration SIOCGHWTSTAMP succeeds and reports tx_type =
HWTSTAMP_TX_OFF / rx_filter = HWTSTAMP_FILTER_NONE, i.e. "hardware
timestamping present but disabled", while nsim_get_ts_info() reports
phc_index = -1 with no hardware so_timestamping and every set attempt is
rejected with -EOPNOTSUPP. Other converted drivers keep the get/set pair
symmetric here.
[ ... ]
next prev parent reply other threads:[~2026-08-18 13:58 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-15 6:31 [PATCH v10 net-next 0/3] Implement PTP support in netdevsim Maciek Machnikowski
2026-08-15 6:31 ` [PATCH v10 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers Maciek Machnikowski
2026-08-15 6:31 ` [PATCH v10 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski
2026-08-18 13:58 ` Simon Horman [this message]
2026-08-18 22:03 ` Maciek Machnikowski
2026-08-15 6:31 ` [PATCH v10 net-next 3/3] selftests: drivers/net: Implement ptp4l sync test using netdevsim Maciek Machnikowski
2026-08-18 22:45 ` [PATCH v10 net-next 0/3] Implement PTP support in netdevsim Jakub Kicinski
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=20260818135800.629288-1-horms@kernel.org \
--to=horms@kernel.org \
--cc=andrew@lunn.ch \
--cc=kuba@kernel.org \
--cc=maciek@machnikowski.net \
--cc=milena.olech@intel.com \
--cc=netdev@vger.kernel.org \
--cc=richardcochran@gmail.com \
--cc=vadim.fedorenko@linux.dev \
--cc=willemdebruijn.kernel@gmail.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.