* [PATCH v3 net-next 0/3] Implement PTP support in netdevsim
@ 2026-02-25 15:38 Maciek Machnikowski
2026-02-25 15:38 ` [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers Maciek Machnikowski
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: Maciek Machnikowski @ 2026-02-25 15:38 UTC (permalink / raw)
To: netdev
Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel,
andrew, vadim.fedorenko, horms
This patchset adds support to the PTP HW timestamping emulation in the
netdevsim. It uses existing binding between netdevsim and ptp_mock
driver to generate transmit and receive timestamps.
It also adds the selftest to verify the hw timestamping functionality
running over netdevsim.
v2:
- Added selftest/net/ptp.sh
- Modified ptp_mock to use spin_lock_bh
- Populate ethtool defaults using ethtool_op_get_ts_info
v3:
- Fixed shellcheck issues in the selftest/net/ptp.sh
- Added selftest/net/ptp.sh to the selftest/net/Makefile
- Modified ptp_mock to use spin_lock_irqsave
Maciek Machnikowski (3):
ptp_mock: Expose ptp_clock_info to external drivers
netdevsim: Implement basic ptp support
selftests:net: Implement ptp4l sync test using netdevsim
drivers/net/netdevsim/ethtool.c | 11 +++
drivers/net/netdevsim/netdev.c | 90 +++++++++++++++++++++++
drivers/net/netdevsim/netdevsim.h | 1 +
drivers/ptp/ptp_mock.c | 22 ++++--
include/linux/ptp_mock.h | 5 ++
tools/testing/selftests/net/Makefile | 1 +
tools/testing/selftests/net/ptp.sh | 105 +++++++++++++++++++++++++++
7 files changed, 227 insertions(+), 8 deletions(-)
create mode 100755 tools/testing/selftests/net/ptp.sh
--
2.53.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers 2026-02-25 15:38 [PATCH v3 net-next 0/3] Implement PTP support in netdevsim Maciek Machnikowski @ 2026-02-25 15:38 ` Maciek Machnikowski 2026-02-26 1:57 ` Jakub Kicinski 2026-02-25 15:38 ` [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski 2026-02-25 15:38 ` [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim Maciek Machnikowski 2 siblings, 1 reply; 14+ messages in thread From: Maciek Machnikowski @ 2026-02-25 15:38 UTC (permalink / raw) To: netdev Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms Allow exposing the ptp_clock_info of the ptp_mock to the external drivers. Convert spinlocks to SLIS to allow gettime to be called from the netdevsim. This is a prerequisite for implementing ptp support on netdevsim. Co-developed-by: Milena Olech <milena.olech@intel.com> Signed-off-by: Milena Olech <milena.olech@intel.com> Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> --- drivers/ptp/ptp_mock.c | 22 ++++++++++++++-------- include/linux/ptp_mock.h | 5 +++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/ptp/ptp_mock.c b/drivers/ptp/ptp_mock.c index bbd14ce24..8e48317b1 100644 --- a/drivers/ptp/ptp_mock.c +++ b/drivers/ptp/ptp_mock.c @@ -54,10 +54,10 @@ static int mock_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm) adj = (s64)scaled_ppm << MOCK_PHC_FADJ_SHIFT; adj = div_s64(adj, MOCK_PHC_FADJ_DENOMINATOR); - spin_lock(&phc->lock); + spin_lock_irqsave(&phc->lock); timecounter_read(&phc->tc); phc->cc.mult = MOCK_PHC_CC_MULT + adj; - spin_unlock(&phc->lock); + spin_unlock_irqsave(&phc->lock); return 0; } @@ -66,9 +66,9 @@ static int mock_phc_adjtime(struct ptp_clock_info *info, s64 delta) { struct mock_phc *phc = info_to_phc(info); - spin_lock(&phc->lock); + spin_lock_irqsave(&phc->lock); timecounter_adjtime(&phc->tc, delta); - spin_unlock(&phc->lock); + spin_unlock_irqsave(&phc->lock); return 0; } @@ -79,9 +79,9 @@ static int mock_phc_settime64(struct ptp_clock_info *info, struct mock_phc *phc = info_to_phc(info); u64 ns = timespec64_to_ns(ts); - spin_lock(&phc->lock); + spin_lock_irqsave(&phc->lock); timecounter_init(&phc->tc, &phc->cc, ns); - spin_unlock(&phc->lock); + spin_unlock_irqsave(&phc->lock); return 0; } @@ -91,9 +91,9 @@ static int mock_phc_gettime64(struct ptp_clock_info *info, struct timespec64 *ts struct mock_phc *phc = info_to_phc(info); u64 ns; - spin_lock(&phc->lock); + spin_lock_irqsave(&phc->lock); ns = timecounter_read(&phc->tc); - spin_unlock(&phc->lock); + spin_unlock_irqsave(&phc->lock); *ts = ns_to_timespec64(ns); @@ -171,5 +171,11 @@ void mock_phc_destroy(struct mock_phc *phc) } EXPORT_SYMBOL_GPL(mock_phc_destroy); +struct ptp_clock_info *mock_phc_get_ptp_info(struct mock_phc *phc) +{ + return &phc->info; +} +EXPORT_SYMBOL_GPL(mock_phc_get_ptp_info); + MODULE_DESCRIPTION("Mock-up PTP Hardware Clock driver"); MODULE_LICENSE("GPL"); diff --git a/include/linux/ptp_mock.h b/include/linux/ptp_mock.h index 72eb40103..e33188dec 100644 --- a/include/linux/ptp_mock.h +++ b/include/linux/ptp_mock.h @@ -16,6 +16,7 @@ struct mock_phc; struct mock_phc *mock_phc_create(struct device *dev); void mock_phc_destroy(struct mock_phc *phc); int mock_phc_index(struct mock_phc *phc); +struct ptp_clock_info *mock_phc_get_ptp_info(struct mock_phc *phc); #else @@ -33,6 +34,10 @@ static inline int mock_phc_index(struct mock_phc *phc) return -1; } +static inline struct ptp_clock_info *mock_phc_get_ptp_info(struct mock_phc *phc) +{ + return NULL; +} #endif #endif /* _PTP_MOCK_H_ */ -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers 2026-02-25 15:38 ` [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers Maciek Machnikowski @ 2026-02-26 1:57 ` Jakub Kicinski 0 siblings, 0 replies; 14+ messages in thread From: Jakub Kicinski @ 2026-02-26 1:57 UTC (permalink / raw) To: Maciek Machnikowski Cc: netdev, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms On Wed, 25 Feb 2026 16:38:56 +0100 Maciek Machnikowski wrote: > Allow exposing the ptp_clock_info of the ptp_mock to the external drivers. > Convert spinlocks to SLIS to allow gettime to be called from the netdevsim. > This is a prerequisite for implementing ptp support on netdevsim. Slight build error here: drivers/ptp/ptp_mock.c:57:9: error: ‘spin_lock_irqsave’ undeclared (first use in this function); did you mean ‘ss_lock_irqsave’? 57 | spin_lock_irqsave(&phc->lock); | ^~~~~~~~~~~~~~~~~ | ss_lock_irqsave -- pw-bot: cr ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support 2026-02-25 15:38 [PATCH v3 net-next 0/3] Implement PTP support in netdevsim Maciek Machnikowski 2026-02-25 15:38 ` [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers Maciek Machnikowski @ 2026-02-25 15:38 ` Maciek Machnikowski 2026-02-25 16:32 ` Sai Krishna Gajula ` (2 more replies) 2026-02-25 15:38 ` [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim Maciek Machnikowski 2 siblings, 3 replies; 14+ messages in thread From: Maciek Machnikowski @ 2026-02-25 15:38 UTC (permalink / raw) To: netdev Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms Add support for virtual timestamping inside the netdevsim driver. The implementation uses two attached ptp_mock clocks, reads the timestamps of the ones attached either to the netdevsim or its peer and returns timestamps using standard timestamps APIs. This implementation enables running ptp4l on netdevsim adapters and introduces a new ptp selftest. Co-developed-by: Milena Olech <milena.olech@intel.com> Signed-off-by: Milena Olech <milena.olech@intel.com> Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> --- drivers/net/netdevsim/ethtool.c | 11 ++++ drivers/net/netdevsim/netdev.c | 90 +++++++++++++++++++++++++++++++ drivers/net/netdevsim/netdevsim.h | 1 + 3 files changed, 102 insertions(+) diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index 36a201533..5b709033c 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -200,7 +200,18 @@ static int nsim_get_ts_info(struct net_device *dev, { struct netdevsim *ns = netdev_priv(dev); + ethtool_op_get_ts_info(dev, info); + 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 6285fbefe..b1161c1ca 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -30,6 +30,8 @@ #include <net/rtnetlink.h> #include <net/udp_tunnel.h> #include <net/busy_poll.h> +#include <linux/ptp_clock_kernel.h> +#include <linux/timecounter.h> #include "netdevsim.h" @@ -119,12 +121,17 @@ static int nsim_forward_skb(struct net_device *tx_dev, static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) { + struct skb_shared_hwtstamps shhwtstamps = {}; struct netdevsim *ns = netdev_priv(dev); + struct ptp_clock_info *ptp_info; + struct timespec64 tx_ts, rx_ts; + struct sk_buff *skb_orig = skb; struct skb_ext *psp_ext = NULL; struct net_device *peer_dev; unsigned int len = skb->len; struct netdevsim *peer_ns; struct netdev_config *cfg; + bool gen_tx_tstamp = false; struct nsim_rq *rq; int rxq; int dr; @@ -161,6 +168,27 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_linearize(skb); skb_tx_timestamp(skb); + gen_tx_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; + if (gen_tx_tstamp) { + ptp_info = mock_phc_get_ptp_info(ns->phc); + + /* Create a copy of tx skb to keep the tx reference */ + skb_orig = skb; + skb = skb_copy(skb_orig, GFP_ATOMIC); + skb_shinfo(skb_orig)->tx_flags |= SKBTX_IN_PROGRESS; + + /* Timestamp as late as possible */ + if (ptp_info) + ptp_info->gettime64(ptp_info, &tx_ts); + } + + /* Generate Rx tstamp based on the peer clock */ + ptp_info = mock_phc_get_ptp_info(peer_ns->phc); + if (ptp_info) { + ptp_info->gettime64(ptp_info, &rx_ts); + skb_hwtstamps(skb)->hwtstamp = timespec64_to_ktime(rx_ts); + } + if (unlikely(nsim_forward_skb(dev, peer_dev, skb, rq, psp_ext) == NET_RX_DROP)) goto out_drop_cnt; @@ -168,6 +196,13 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!hrtimer_active(&rq->napi_timer)) hrtimer_start(&rq->napi_timer, us_to_ktime(5), HRTIMER_MODE_REL); + /* only timestamp the outbound packet if user requested it */ + if (gen_tx_tstamp) { + shhwtstamps.hwtstamp = timespec64_to_ktime(tx_ts); + skb_tstamp_tx(skb_orig, &shhwtstamps); + dev_kfree_skb_any(skb_orig); + } + rcu_read_unlock(); dev_dstats_tx_add(dev, len); return NETDEV_TX_OK; @@ -182,6 +217,59 @@ 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); + + if (!ns->phc) + return -EOPNOTSUPP; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + ns->tstamp_config.tx_type = HWTSTAMP_TX_OFF; + break; + case HWTSTAMP_TX_ON: + ns->tstamp_config.tx_type = HWTSTAMP_TX_ON; + break; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + ns->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: + case HWTSTAMP_FILTER_ALL: + ns->tstamp_config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + default: + return -ERANGE; + } + + return 0; +} + +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; +} + static void nsim_set_rx_mode(struct net_device *dev) { } @@ -660,6 +748,8 @@ static const struct net_device_ops nsim_netdev_ops = { .ndo_open = nsim_open, .ndo_stop = nsim_stop, .net_shaper_ops = &nsim_shaper_ops, + .ndo_hwtstamp_get = nsim_get_ts_config, + .ndo_hwtstamp_set = nsim_set_ts_config, }; static const struct net_device_ops nsim_vf_netdev_ops = { diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index f767fc8a7..6d3e8700c 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -103,6 +103,7 @@ struct netdevsim { struct net_device *netdev; struct nsim_dev *nsim_dev; struct nsim_dev_port *nsim_dev_port; + struct kernel_hwtstamp_config tstamp_config; struct mock_phc *phc; struct nsim_rq **rq; -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* RE: [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support 2026-02-25 15:38 ` [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski @ 2026-02-25 16:32 ` Sai Krishna Gajula 2026-02-26 2:01 ` Jakub Kicinski 2026-03-04 15:19 ` Willem de Bruijn 2 siblings, 0 replies; 14+ messages in thread From: Sai Krishna Gajula @ 2026-02-25 16:32 UTC (permalink / raw) To: Maciek Machnikowski, netdev@vger.kernel.org Cc: kuba@kernel.org, richardcochran@gmail.com, milena.olech@intel.com, willemdebruijn.kernel@gmail.com, andrew@lunn.ch, vadim.fedorenko@linux.dev, horms@kernel.org > -----Original Message----- > From: Maciek Machnikowski <maciek@machnikowski.net> > Sent: Wednesday, February 25, 2026 9:09 PM > To: netdev@vger.kernel.org > Cc: kuba@kernel.org; maciek@machnikowski.net; > richardcochran@gmail.com; milena.olech@intel.com; > willemdebruijn.kernel@gmail.com; andrew@lunn.ch; > vadim.fedorenko@linux.dev; horms@kernel.org > Subject: [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp > support > > Add support for virtual timestamping inside the netdevsim driver. The > implementation uses two attached ptp_mock clocks, reads the timestamps of > the ones attached either to the netdevsim or its peer and returns timestamps > using standard timestamps > Add support for virtual timestamping inside the netdevsim driver. > The implementation uses two attached ptp_mock clocks, reads the > timestamps of the ones attached either to the netdevsim or its peer and > returns timestamps using standard timestamps APIs. > > This implementation enables running ptp4l on netdevsim adapters and > introduces a new ptp selftest. > > Co-developed-by: Milena Olech <milena.olech@intel.com> > Signed-off-by: Milena Olech <milena.olech@intel.com> > Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> > --- > drivers/net/netdevsim/ethtool.c | 11 ++++ > drivers/net/netdevsim/netdev.c | 90 +++++++++++++++++++++++++++++++ > drivers/net/netdevsim/netdevsim.h | 1 + > 3 files changed, 102 insertions(+) > > diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c > index 36a201533..5b709033c 100644 > --- a/drivers/net/netdevsim/ethtool.c > +++ b/drivers/net/netdevsim/ethtool.c > @@ -200,7 +200,18 @@ static int nsim_get_ts_info(struct net_device *dev, { > struct netdevsim *ns = netdev_priv(dev); > > + ethtool_op_get_ts_info(dev, info); > + > 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 6285fbefe..b1161c1ca 100644 > --- a/drivers/net/netdevsim/netdev.c > +++ b/drivers/net/netdevsim/netdev.c > @@ -30,6 +30,8 @@ > #include <net/rtnetlink.h> > #include <net/udp_tunnel.h> > #include <net/busy_poll.h> > +#include <linux/ptp_clock_kernel.h> > +#include <linux/timecounter.h> > > #include "netdevsim.h" > > @@ -119,12 +121,17 @@ static int nsim_forward_skb(struct net_device > *tx_dev, > > static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device > *dev) { > + struct skb_shared_hwtstamps shhwtstamps = {}; > struct netdevsim *ns = netdev_priv(dev); > + struct ptp_clock_info *ptp_info; > + struct timespec64 tx_ts, rx_ts; > + struct sk_buff *skb_orig = skb; > struct skb_ext *psp_ext = NULL; > struct net_device *peer_dev; > unsigned int len = skb->len; > struct netdevsim *peer_ns; > struct netdev_config *cfg; > + bool gen_tx_tstamp = false; > struct nsim_rq *rq; > int rxq; > int dr; > @@ -161,6 +168,27 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff > *skb, struct net_device *dev) > skb_linearize(skb); > > skb_tx_timestamp(skb); > + gen_tx_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; > + if (gen_tx_tstamp) { > + ptp_info = mock_phc_get_ptp_info(ns->phc); > + > + /* Create a copy of tx skb to keep the tx reference */ > + skb_orig = skb; > + skb = skb_copy(skb_orig, GFP_ATOMIC); Minor nit, check for failure condition. skb = skb_copy(skb_orig, GFP_ATOMIC); if (!skb) { dev_kfree_skb_any(skb_orig); ... return NETDEV_TX_OK; } > + skb_shinfo(skb_orig)->tx_flags |= SKBTX_IN_PROGRESS; > + > + /* Timestamp as late as possible */ > + if (ptp_info) > + ptp_info->gettime64(ptp_info, &tx_ts); > + } > + > + /* Generate Rx tstamp based on the peer clock */ > + ptp_info = mock_phc_get_ptp_info(peer_ns->phc); > + if (ptp_info) { > + ptp_info->gettime64(ptp_info, &rx_ts); > + skb_hwtstamps(skb)->hwtstamp = > timespec64_to_ktime(rx_ts); > + } > + > if (unlikely(nsim_forward_skb(dev, peer_dev, > skb, rq, psp_ext) == NET_RX_DROP)) > goto out_drop_cnt; > @@ -168,6 +196,13 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff > *skb, struct net_device *dev) > if (!hrtimer_active(&rq->napi_timer)) > hrtimer_start(&rq->napi_timer, us_to_ktime(5), > HRTIMER_MODE_REL); > > + /* only timestamp the outbound packet if user requested it */ > + if (gen_tx_tstamp) { > + shhwtstamps.hwtstamp = timespec64_to_ktime(tx_ts); > + skb_tstamp_tx(skb_orig, &shhwtstamps); > + dev_kfree_skb_any(skb_orig); > + } > + > rcu_read_unlock(); > dev_dstats_tx_add(dev, len); > return NETDEV_TX_OK; > @@ -182,6 +217,59 @@ 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); > + > + if (!ns->phc) > + return -EOPNOTSUPP; > + > + switch (config->tx_type) { > + case HWTSTAMP_TX_OFF: > + ns->tstamp_config.tx_type = HWTSTAMP_TX_OFF; > + break; > + case HWTSTAMP_TX_ON: > + ns->tstamp_config.tx_type = HWTSTAMP_TX_ON; > + break; > + default: > + return -ERANGE; > + } > + > + switch (config->rx_filter) { > + case HWTSTAMP_FILTER_NONE: > + ns->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; > + break; > + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: > + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: > + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: > + case HWTSTAMP_FILTER_PTP_V2_EVENT: > + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: > + case HWTSTAMP_FILTER_PTP_V2_SYNC: > + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: > + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: > + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: > + case HWTSTAMP_FILTER_NTP_ALL: > + case HWTSTAMP_FILTER_ALL: > + ns->tstamp_config.rx_filter = HWTSTAMP_FILTER_ALL; > + break; > + default: > + return -ERANGE; > + } > + > + return 0; > +} > + > +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; > +} > + > static void nsim_set_rx_mode(struct net_device *dev) { } @@ -660,6 +748,8 > @@ static const struct net_device_ops nsim_netdev_ops = { > .ndo_open = nsim_open, > .ndo_stop = nsim_stop, > .net_shaper_ops = &nsim_shaper_ops, > + .ndo_hwtstamp_get = nsim_get_ts_config, > + .ndo_hwtstamp_set = nsim_set_ts_config, > }; > > static const struct net_device_ops nsim_vf_netdev_ops = { diff --git > a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h > index f767fc8a7..6d3e8700c 100644 > --- a/drivers/net/netdevsim/netdevsim.h > +++ b/drivers/net/netdevsim/netdevsim.h > @@ -103,6 +103,7 @@ struct netdevsim { > struct net_device *netdev; > struct nsim_dev *nsim_dev; > struct nsim_dev_port *nsim_dev_port; > + struct kernel_hwtstamp_config tstamp_config; > struct mock_phc *phc; > struct nsim_rq **rq; > > -- > 2.53.0 > Reviewed-by: Sai Krishna <saikrishnag@marvell.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support 2026-02-25 15:38 ` [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski 2026-02-25 16:32 ` Sai Krishna Gajula @ 2026-02-26 2:01 ` Jakub Kicinski 2026-03-04 12:41 ` Maciek Machnikowski 2026-03-04 15:19 ` Willem de Bruijn 2 siblings, 1 reply; 14+ messages in thread From: Jakub Kicinski @ 2026-02-26 2:01 UTC (permalink / raw) To: Maciek Machnikowski Cc: netdev, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms On Wed, 25 Feb 2026 16:38:57 +0100 Maciek Machnikowski wrote: > diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c > index 6285fbefe..b1161c1ca 100644 > --- a/drivers/net/netdevsim/netdev.c > +++ b/drivers/net/netdevsim/netdev.c > @@ -30,6 +30,8 @@ > #include <net/rtnetlink.h> > #include <net/udp_tunnel.h> > #include <net/busy_poll.h> > +#include <linux/ptp_clock_kernel.h> > +#include <linux/timecounter.h> Alphabetical sort please > struct netdevsim *peer_ns; > struct netdev_config *cfg; > + bool gen_tx_tstamp = false; > struct nsim_rq *rq; reverse xmas tree > + gen_tx_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; > + if (gen_tx_tstamp) { > + ptp_info = mock_phc_get_ptp_info(ns->phc); > + > + /* Create a copy of tx skb to keep the tx reference */ > + skb_orig = skb; > + skb = skb_copy(skb_orig, GFP_ATOMIC); > + skb_shinfo(skb_orig)->tx_flags |= SKBTX_IN_PROGRESS; > + > + /* Timestamp as late as possible */ > + if (ptp_info) > + ptp_info->gettime64(ptp_info, &tx_ts); > + } Do we have to copy the packet? We can't deliver the timestamp before we run Rx, on the original skb? > if (unlikely(nsim_forward_skb(dev, peer_dev, > skb, rq, psp_ext) == NET_RX_DROP)) > goto out_drop_cnt; 'Cause I think this leaks skb_orig now. > + /* Generate Rx tstamp based on the peer clock */ > + ptp_info = mock_phc_get_ptp_info(peer_ns->phc); > + if (ptp_info) { we can still gate this on whether timestamps are enabled, no? > + ptp_info->gettime64(ptp_info, &rx_ts); > + skb_hwtstamps(skb)->hwtstamp = timespec64_to_ktime(rx_ts); ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support 2026-02-26 2:01 ` Jakub Kicinski @ 2026-03-04 12:41 ` Maciek Machnikowski 0 siblings, 0 replies; 14+ messages in thread From: Maciek Machnikowski @ 2026-03-04 12:41 UTC (permalink / raw) To: Jakub Kicinski Cc: netdev, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms On 26/02/2026 03:01, Jakub Kicinski wrote: > On Wed, 25 Feb 2026 16:38:57 +0100 Maciek Machnikowski wrote: >> diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c >> index 6285fbefe..b1161c1ca 100644 >> --- a/drivers/net/netdevsim/netdev.c >> +++ b/drivers/net/netdevsim/netdev.c >> @@ -30,6 +30,8 @@ >> #include <net/rtnetlink.h> >> #include <net/udp_tunnel.h> >> #include <net/busy_poll.h> >> +#include <linux/ptp_clock_kernel.h> >> +#include <linux/timecounter.h> > > Alphabetical sort please > >> struct netdevsim *peer_ns; >> struct netdev_config *cfg; >> + bool gen_tx_tstamp = false; >> struct nsim_rq *rq; > > reverse xmas tree > >> + gen_tx_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; >> + if (gen_tx_tstamp) { >> + ptp_info = mock_phc_get_ptp_info(ns->phc); >> + >> + /* Create a copy of tx skb to keep the tx reference */ >> + skb_orig = skb; >> + skb = skb_copy(skb_orig, GFP_ATOMIC); >> + skb_shinfo(skb_orig)->tx_flags |= SKBTX_IN_PROGRESS; >> + >> + /* Timestamp as late as possible */ >> + if (ptp_info) >> + ptp_info->gettime64(ptp_info, &tx_ts); >> + } > > Do we have to copy the packet? We can't deliver the timestamp before > we run Rx, on the original skb? If we don't we'll get the same timestamps for Rx and Tx side. There's a single hwtstamps field inside the skb and it's used to deliver tx and rx tstamp. If I use a single skb I'll get the same tstamp on the transmitter side and the receiver one. > >> if (unlikely(nsim_forward_skb(dev, peer_dev, >> skb, rq, psp_ext) == NET_RX_DROP)) >> goto out_drop_cnt; > > 'Cause I think this leaks skb_orig now. Will address that (and formatting comments above) > >> + /* Generate Rx tstamp based on the peer clock */ >> + ptp_info = mock_phc_get_ptp_info(peer_ns->phc); >> + if (ptp_info) { > > we can still gate this on whether timestamps are enabled, no? Hmmm... that'd need to be gated by the peer's timestamping features - will check if there's reasonably easy way to add it. > >> + ptp_info->gettime64(ptp_info, &rx_ts); >> + skb_hwtstamps(skb)->hwtstamp = timespec64_to_ktime(rx_ts); > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support 2026-02-25 15:38 ` [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski 2026-02-25 16:32 ` Sai Krishna Gajula 2026-02-26 2:01 ` Jakub Kicinski @ 2026-03-04 15:19 ` Willem de Bruijn 2026-03-04 15:48 ` Willem de Bruijn 2 siblings, 1 reply; 14+ messages in thread From: Willem de Bruijn @ 2026-03-04 15:19 UTC (permalink / raw) To: Maciek Machnikowski, netdev Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms Maciek Machnikowski wrote: > Add support for virtual timestamping inside the netdevsim driver. > The implementation uses two attached ptp_mock clocks, reads the timestamps > of the ones attached either to the netdevsim or its peer and returns > timestamps using standard timestamps APIs. > > This implementation enables running ptp4l on netdevsim adapters and > introduces a new ptp selftest. > > Co-developed-by: Milena Olech <milena.olech@intel.com> > Signed-off-by: Milena Olech <milena.olech@intel.com> > Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> > --- > drivers/net/netdevsim/ethtool.c | 11 ++++ > drivers/net/netdevsim/netdev.c | 90 +++++++++++++++++++++++++++++++ > drivers/net/netdevsim/netdevsim.h | 1 + > 3 files changed, 102 insertions(+) > > diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c > index 36a201533..5b709033c 100644 > --- a/drivers/net/netdevsim/ethtool.c > +++ b/drivers/net/netdevsim/ethtool.c > @@ -200,7 +200,18 @@ static int nsim_get_ts_info(struct net_device *dev, > { > struct netdevsim *ns = netdev_priv(dev); > > + ethtool_op_get_ts_info(dev, info); > + > 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 6285fbefe..b1161c1ca 100644 > --- a/drivers/net/netdevsim/netdev.c > +++ b/drivers/net/netdevsim/netdev.c > @@ -30,6 +30,8 @@ > #include <net/rtnetlink.h> > #include <net/udp_tunnel.h> > #include <net/busy_poll.h> > +#include <linux/ptp_clock_kernel.h> > +#include <linux/timecounter.h> > > #include "netdevsim.h" > > @@ -119,12 +121,17 @@ static int nsim_forward_skb(struct net_device *tx_dev, > > static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) > { > + struct skb_shared_hwtstamps shhwtstamps = {}; > struct netdevsim *ns = netdev_priv(dev); > + struct ptp_clock_info *ptp_info; > + struct timespec64 tx_ts, rx_ts; > + struct sk_buff *skb_orig = skb; > struct skb_ext *psp_ext = NULL; > struct net_device *peer_dev; > unsigned int len = skb->len; > struct netdevsim *peer_ns; > struct netdev_config *cfg; > + bool gen_tx_tstamp = false; > struct nsim_rq *rq; > int rxq; > int dr; > @@ -161,6 +168,27 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) > skb_linearize(skb); > > skb_tx_timestamp(skb); > + gen_tx_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; > + if (gen_tx_tstamp) { > + ptp_info = mock_phc_get_ptp_info(ns->phc); > + > + /* Create a copy of tx skb to keep the tx reference */ > + skb_orig = skb; > + skb = skb_copy(skb_orig, GFP_ATOMIC); > + skb_shinfo(skb_orig)->tx_flags |= SKBTX_IN_PROGRESS; > + > + /* Timestamp as late as possible */ > + if (ptp_info) > + ptp_info->gettime64(ptp_info, &tx_ts); > + } > + > + /* Generate Rx tstamp based on the peer clock */ > + ptp_info = mock_phc_get_ptp_info(peer_ns->phc); > + if (ptp_info) { > + ptp_info->gettime64(ptp_info, &rx_ts); > + skb_hwtstamps(skb)->hwtstamp = timespec64_to_ktime(rx_ts); > + } > + > if (unlikely(nsim_forward_skb(dev, peer_dev, > skb, rq, psp_ext) == NET_RX_DROP)) > goto out_drop_cnt; > @@ -168,6 +196,13 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) > if (!hrtimer_active(&rq->napi_timer)) > hrtimer_start(&rq->napi_timer, us_to_ktime(5), HRTIMER_MODE_REL); > > + /* only timestamp the outbound packet if user requested it */ > + if (gen_tx_tstamp) { > + shhwtstamps.hwtstamp = timespec64_to_ktime(tx_ts); > + skb_tstamp_tx(skb_orig, &shhwtstamps); > + dev_kfree_skb_any(skb_orig); > + } > + I still don't understand this tx timestamp path, which is non-standard. The comment says timestamp as late as possible, which would be calling gettime64 in the second branch, rather than the first. That would mean that the tx timestamp is taken after the rx timestamp at the peer. Confusing, but something that may actually happen on real NICs too in some cases (e.g., PCI backpressure). If goal is to maintain ordering between the two, remove the comment about as late as possible. More importantly, since skb_tstamp_tx internally will call alloc_skb or skb_clone, why is this skb_copy here needed? I probably should have replied to your previous response: > If I queue the tx timestamp before forwarding - the same skb would > be freed when the timestamp is delivered. That is not the case since it is a clone or separate skb that is queued to the error queue? ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support 2026-03-04 15:19 ` Willem de Bruijn @ 2026-03-04 15:48 ` Willem de Bruijn 0 siblings, 0 replies; 14+ messages in thread From: Willem de Bruijn @ 2026-03-04 15:48 UTC (permalink / raw) To: Willem de Bruijn, Maciek Machnikowski, netdev Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms Willem de Bruijn wrote: > Maciek Machnikowski wrote: > > Add support for virtual timestamping inside the netdevsim driver. > > The implementation uses two attached ptp_mock clocks, reads the timestamps > > of the ones attached either to the netdevsim or its peer and returns > > timestamps using standard timestamps APIs. > > > > This implementation enables running ptp4l on netdevsim adapters and > > introduces a new ptp selftest. > > > > Co-developed-by: Milena Olech <milena.olech@intel.com> > > Signed-off-by: Milena Olech <milena.olech@intel.com> > > Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> > > --- > > drivers/net/netdevsim/ethtool.c | 11 ++++ > > drivers/net/netdevsim/netdev.c | 90 +++++++++++++++++++++++++++++++ > > drivers/net/netdevsim/netdevsim.h | 1 + > > 3 files changed, 102 insertions(+) > > > > diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c > > index 36a201533..5b709033c 100644 > > --- a/drivers/net/netdevsim/ethtool.c > > +++ b/drivers/net/netdevsim/ethtool.c > > @@ -200,7 +200,18 @@ static int nsim_get_ts_info(struct net_device *dev, > > { > > struct netdevsim *ns = netdev_priv(dev); > > > > + ethtool_op_get_ts_info(dev, info); > > + > > 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 6285fbefe..b1161c1ca 100644 > > --- a/drivers/net/netdevsim/netdev.c > > +++ b/drivers/net/netdevsim/netdev.c > > @@ -30,6 +30,8 @@ > > #include <net/rtnetlink.h> > > #include <net/udp_tunnel.h> > > #include <net/busy_poll.h> > > +#include <linux/ptp_clock_kernel.h> > > +#include <linux/timecounter.h> > > > > #include "netdevsim.h" > > > > @@ -119,12 +121,17 @@ static int nsim_forward_skb(struct net_device *tx_dev, > > > > static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) > > { > > + struct skb_shared_hwtstamps shhwtstamps = {}; > > struct netdevsim *ns = netdev_priv(dev); > > + struct ptp_clock_info *ptp_info; > > + struct timespec64 tx_ts, rx_ts; > > + struct sk_buff *skb_orig = skb; > > struct skb_ext *psp_ext = NULL; > > struct net_device *peer_dev; > > unsigned int len = skb->len; > > struct netdevsim *peer_ns; > > struct netdev_config *cfg; > > + bool gen_tx_tstamp = false; > > struct nsim_rq *rq; > > int rxq; > > int dr; > > @@ -161,6 +168,27 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) > > skb_linearize(skb); > > > > skb_tx_timestamp(skb); > > + gen_tx_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; > > + if (gen_tx_tstamp) { > > + ptp_info = mock_phc_get_ptp_info(ns->phc); > > + > > + /* Create a copy of tx skb to keep the tx reference */ > > + skb_orig = skb; > > + skb = skb_copy(skb_orig, GFP_ATOMIC); > > + skb_shinfo(skb_orig)->tx_flags |= SKBTX_IN_PROGRESS; > > + > > + /* Timestamp as late as possible */ > > + if (ptp_info) > > + ptp_info->gettime64(ptp_info, &tx_ts); > > + } > > + > > + /* Generate Rx tstamp based on the peer clock */ > > + ptp_info = mock_phc_get_ptp_info(peer_ns->phc); > > + if (ptp_info) { > > + ptp_info->gettime64(ptp_info, &rx_ts); > > + skb_hwtstamps(skb)->hwtstamp = timespec64_to_ktime(rx_ts); > > + } > > + > > if (unlikely(nsim_forward_skb(dev, peer_dev, > > skb, rq, psp_ext) == NET_RX_DROP)) > > goto out_drop_cnt; > > @@ -168,6 +196,13 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) > > if (!hrtimer_active(&rq->napi_timer)) > > hrtimer_start(&rq->napi_timer, us_to_ktime(5), HRTIMER_MODE_REL); > > > > + /* only timestamp the outbound packet if user requested it */ > > + if (gen_tx_tstamp) { > > + shhwtstamps.hwtstamp = timespec64_to_ktime(tx_ts); > > + skb_tstamp_tx(skb_orig, &shhwtstamps); > > + dev_kfree_skb_any(skb_orig); > > + } > > + > > I still don't understand this tx timestamp path, which is > non-standard. > > The comment says timestamp as late as possible, which would be calling > gettime64 in the second branch, rather than the first. That would mean > that the tx timestamp is taken after the rx timestamp at the peer. > Confusing, but something that may actually happen on real NICs too in > some cases (e.g., PCI backpressure). > > If goal is to maintain ordering between the two, remove the comment > about as late as possible. > > More importantly, since skb_tstamp_tx internally will call alloc_skb > or skb_clone, why is this skb_copy here needed? > > I probably should have replied to your previous response: > > > If I queue the tx timestamp before forwarding - the same skb would > > be freed when the timestamp is delivered. > > That is not the case since it is a clone or separate skb that is > queued to the error queue? Let me ask differently: why not queue the tx timestamp directly in that first branch? ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim 2026-02-25 15:38 [PATCH v3 net-next 0/3] Implement PTP support in netdevsim Maciek Machnikowski 2026-02-25 15:38 ` [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers Maciek Machnikowski 2026-02-25 15:38 ` [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski @ 2026-02-25 15:38 ` Maciek Machnikowski 2026-02-25 16:45 ` Sai Krishna Gajula ` (2 more replies) 2 siblings, 3 replies; 14+ messages in thread From: Maciek Machnikowski @ 2026-02-25 15:38 UTC (permalink / raw) To: netdev Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms Add PTP synchronization test using ptp4l and netdevsim. The test creates two netdevsim adapters, links them together and runs the ptp4l leader and ptp4l follower on two ends of the netdevsim link and waits for the follower to report the synchronized state (s2) in its output log. This implementation runs the test runs over IPv4 link. Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/ptp.sh | 105 +++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100755 tools/testing/selftests/net/ptp.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index afdea6d95..db576ea96 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -64,6 +64,7 @@ TEST_PROGS := \ nl_netdev.py \ pmtu.sh \ psock_snd.sh \ + ptp.sh \ reuseaddr_ports_exhausted.sh \ reuseport_addr_any.sh \ route_hint.sh \ diff --git a/tools/testing/selftests/net/ptp.sh b/tools/testing/selftests/net/ptp.sh new file mode 100755 index 000000000..8e5b3e1e4 --- /dev/null +++ b/tools/testing/selftests/net/ptp.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only +# shellcheck disable=SC2329 +# +# By Maciek Machnikowski <maciek@machnikowski.net> (c) 2026, +# +# Self-tests for HW timestamping and 1588 synchronization on the netdevsim +# emulation with ptp_mock. +# +# This test: +# - Creates two netdevsim instances in two separate namespaces +# - Assigns IPv4 addresses to those instances +# - Runs ptp4l leader in the nssv namespace using IPv4 traffic +# - Runs ptp4l follower in the nscl namespace using IPv4 traffic +# - Waits for the follower to reach synchronized state (s2) or the timeout + +source lib.sh + +NSIM_DEV_1_ID=$((256 + RANDOM % 256)) +NSIM_DEV_2_ID=$((512 + RANDOM % 256)) + +NSIM_DEV_SYS_LINK=/sys/bus/netdevsim/link_device +NSIM_DEV_SYS_UNLINK=/sys/bus/netdevsim/unlink_device +PTP4L_SYNC_TIMEOUT=20 + +setup_netdevsim() +{ + set -e + ip netns add nssv + ip netns add nscl + + NSIM_DEV_1_NAME=$(create_netdevsim "$NSIM_DEV_1_ID" "nssv") + NSIM_DEV_2_NAME=$(create_netdevsim "$NSIM_DEV_2_ID" "nscl") + + ip netns exec nssv ip addr add '192.168.1.1/24' dev "$NSIM_DEV_1_NAME" + ip netns exec nscl ip addr add '192.168.1.2/24' dev "$NSIM_DEV_2_NAME" + + set +e +} + +cleanup() +{ + [ -n "${PTP4L_LEADER_PID-}" ] && { + kill "$PTP4L_LEADER_PID" "$PTP4L_FOLLOWER_PID" 2>/dev/null + wait "$PTP4L_LEADER_PID" "$PTP4L_FOLLOWER_PID" 2>/dev/null + rm -f "$PTP4L_LEADER_LOG" "$PTP4L_FOLLOWER_LOG" + } + + [ -n "${NSIM_DEV_1_FD-}" ] && [ -n "${NSIM_DEV_1_IFIDX-}" ] && \ + echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX" > "$NSIM_DEV_SYS_UNLINK" 2>/dev/null + cleanup_netdevsim "${NSIM_DEV_2_ID-}" 2>/dev/null + cleanup_netdevsim "${NSIM_DEV_1_ID-}" 2>/dev/null + + ip netns del nscl 2>/dev/null + ip netns del nssv 2>/dev/null + + modprobe -r netdevsim 2>/dev/null +} + +if [ ! -x "$(command -v ptp4l)" ]; then + echo "ptp4l command not found. Skipping PTP sync test" + exit 4 +fi + +trap cleanup EXIT + +setup_netdevsim + +# Link netdevsim1 with netdevsim2 +NSIM_DEV_1_FD=$((256 + RANDOM % 256)) +exec {NSIM_DEV_1_FD}</var/run/netns/nssv +NSIM_DEV_1_IFIDX=$(ip netns exec nssv cat "/sys/class/net/$NSIM_DEV_1_NAME/ifindex") + +NSIM_DEV_2_FD=$((512 + RANDOM % 256)) +exec {NSIM_DEV_2_FD}</var/run/netns/nscl +NSIM_DEV_2_IFIDX=$(ip netns exec nscl cat "/sys/class/net/$NSIM_DEV_2_NAME/ifindex") + +if ! echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX" \ + "$NSIM_DEV_2_FD:$NSIM_DEV_2_IFIDX" > "$NSIM_DEV_SYS_LINK"; then + echo "linking netdevsim1 with netdevsim2 failed" + exit 1 +fi + +# PTP synchronization test: run ptp4l leader in nssv and follower in nscl, +# then parse follower output to verify they synchronized (servo state s2 = locked). +PTP4L_LEADER_LOG=$(mktemp) +PTP4L_FOLLOWER_LOG=$(mktemp) +ip netns exec nssv ptp4l -i "$NSIM_DEV_1_NAME" -m -4 -P \ + > "$PTP4L_LEADER_LOG" 2>&1 & +PTP4L_LEADER_PID=$! + +ip netns exec nscl ptp4l -i "$NSIM_DEV_2_NAME" -s -m -4 -P \ + > "$PTP4L_FOLLOWER_LOG" 2>&1 & +PTP4L_FOLLOWER_PID=$! + + +for _ in $(seq 1 "$PTP4L_SYNC_TIMEOUT"); do + if grep -q ' s2 ' "$PTP4L_FOLLOWER_LOG" 2>/dev/null; then + exit 0 + fi + sleep 1 +done + +echo "ptp4l follower did not reach locked state (s2) within ${PTP4L_SYNC_TIMEOUT}s" +exit 1 -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* RE: [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim 2026-02-25 15:38 ` [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim Maciek Machnikowski @ 2026-02-25 16:45 ` Sai Krishna Gajula 2026-03-04 12:44 ` Maciek Machnikowski 2026-02-26 2:41 ` Jakub Kicinski 2026-03-04 15:21 ` Willem de Bruijn 2 siblings, 1 reply; 14+ messages in thread From: Sai Krishna Gajula @ 2026-02-25 16:45 UTC (permalink / raw) To: Maciek Machnikowski, netdev@vger.kernel.org Cc: kuba@kernel.org, richardcochran@gmail.com, milena.olech@intel.com, willemdebruijn.kernel@gmail.com, andrew@lunn.ch, vadim.fedorenko@linux.dev, horms@kernel.org > -----Original Message----- > From: Maciek Machnikowski <maciek@machnikowski.net> > Sent: Wednesday, February 25, 2026 9:09 PM > To: netdev@vger.kernel.org > Cc: kuba@kernel.org; maciek@machnikowski.net; > richardcochran@gmail.com; milena.olech@intel.com; > willemdebruijn.kernel@gmail.com; andrew@lunn.ch; > vadim.fedorenko@linux.dev; horms@kernel.org > Subject: [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l > sync test using netdevsim > > Add PTP synchronization test using ptp4l and netdevsim. The test creates two > netdevsim adapters, links them together and runs the ptp4l leader and ptp4l > follower on two ends of the netdevsim link and waits for the follower to > report the synchronized > Add PTP synchronization test using ptp4l and netdevsim. > > The test creates two netdevsim adapters, links them together and runs the > ptp4l leader and ptp4l follower on two ends of the netdevsim link and waits > for the follower to report the synchronized state (s2) in its output log. > > This implementation runs the test runs over IPv4 link. > > Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> > --- > tools/testing/selftests/net/Makefile | 1 + > tools/testing/selftests/net/ptp.sh | 105 +++++++++++++++++++++++++++ > 2 files changed, 106 insertions(+) > create mode 100755 tools/testing/selftests/net/ptp.sh > > diff --git a/tools/testing/selftests/net/Makefile > b/tools/testing/selftests/net/Makefile > index afdea6d95..db576ea96 100644 > --- a/tools/testing/selftests/net/Makefile > +++ b/tools/testing/selftests/net/Makefile > @@ -64,6 +64,7 @@ TEST_PROGS := \ > nl_netdev.py \ > pmtu.sh \ > psock_snd.sh \ > + ptp.sh \ > reuseaddr_ports_exhausted.sh \ > reuseport_addr_any.sh \ > route_hint.sh \ > diff --git a/tools/testing/selftests/net/ptp.sh > b/tools/testing/selftests/net/ptp.sh > new file mode 100755 > index 000000000..8e5b3e1e4 > --- /dev/null > +++ b/tools/testing/selftests/net/ptp.sh > @@ -0,0 +1,105 @@ > +#!/bin/bash > +# SPDX-License-Identifier: GPL-2.0-only # shellcheck disable=SC2329 # # > +By Maciek Machnikowski <maciek@machnikowski.net> (c) 2026, # # > +Self-tests for HW timestamping and 1588 synchronization on the > +netdevsim # emulation with ptp_mock. > +# > +# This test: > +# - Creates two netdevsim instances in two separate namespaces # - > +Assigns IPv4 addresses to those instances # - Runs ptp4l leader in the > +nssv namespace using IPv4 traffic # - Runs ptp4l follower in the nscl > +namespace using IPv4 traffic # - Waits for the follower to reach > +synchronized state (s2) or the timeout > + > +source lib.sh > + > +NSIM_DEV_1_ID=$((256 + RANDOM % 256)) > +NSIM_DEV_2_ID=$((512 + RANDOM % 256)) > + > +NSIM_DEV_SYS_LINK=/sys/bus/netdevsim/link_device > +NSIM_DEV_SYS_UNLINK=/sys/bus/netdevsim/unlink_device > +PTP4L_SYNC_TIMEOUT=20 > + > +setup_netdevsim() > +{ > + set -e > + ip netns add nssv > + ip netns add nscl > + > + NSIM_DEV_1_NAME=$(create_netdevsim "$NSIM_DEV_1_ID" "nssv") > + NSIM_DEV_2_NAME=$(create_netdevsim "$NSIM_DEV_2_ID" "nscl") > + > + ip netns exec nssv ip addr add '192.168.1.1/24' dev > "$NSIM_DEV_1_NAME" > + ip netns exec nscl ip addr add '192.168.1.2/24' dev > "$NSIM_DEV_2_NAME" > + > + set +e > +} > + > +cleanup() > +{ > + [ -n "${PTP4L_LEADER_PID-}" ] && { > + kill "$PTP4L_LEADER_PID" "$PTP4L_FOLLOWER_PID" > 2>/dev/null > + wait "$PTP4L_LEADER_PID" "$PTP4L_FOLLOWER_PID" > 2>/dev/null > + rm -f "$PTP4L_LEADER_LOG" "$PTP4L_FOLLOWER_LOG" > + } > + > + [ -n "${NSIM_DEV_1_FD-}" ] && [ -n "${NSIM_DEV_1_IFIDX-}" ] && \ > + echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX" > > "$NSIM_DEV_SYS_UNLINK" 2>/dev/null > + cleanup_netdevsim "${NSIM_DEV_2_ID-}" 2>/dev/null > + cleanup_netdevsim "${NSIM_DEV_1_ID-}" 2>/dev/null > + > + ip netns del nscl 2>/dev/null > + ip netns del nssv 2>/dev/null > + > + modprobe -r netdevsim 2>/dev/null > +} > + > +if [ ! -x "$(command -v ptp4l)" ]; then > + echo "ptp4l command not found. Skipping PTP sync test" > + exit 4 > +fi > + > +trap cleanup EXIT > + > +setup_netdevsim > + > +# Link netdevsim1 with netdevsim2 > +NSIM_DEV_1_FD=$((256 + RANDOM % 256)) > +exec {NSIM_DEV_1_FD}</var/run/netns/nssv > +NSIM_DEV_1_IFIDX=$(ip netns exec nssv cat > +"/sys/class/net/$NSIM_DEV_1_NAME/ifindex") > + > +NSIM_DEV_2_FD=$((512 + RANDOM % 256)) > +exec {NSIM_DEV_2_FD}</var/run/netns/nscl > +NSIM_DEV_2_IFIDX=$(ip netns exec nscl cat > +"/sys/class/net/$NSIM_DEV_2_NAME/ifindex") > + > +if ! echo "$NSIM_DEV_1_FD:$NSIM_DEV_1_IFIDX" \ > + "$NSIM_DEV_2_FD:$NSIM_DEV_2_IFIDX" > "$NSIM_DEV_SYS_LINK"; > then > + echo "linking netdevsim1 with netdevsim2 failed" > + exit 1 > +fi > + > +# PTP synchronization test: run ptp4l leader in nssv and follower in > +nscl, # then parse follower output to verify they synchronized (servo state s2 > = locked). > +PTP4L_LEADER_LOG=$(mktemp) > +PTP4L_FOLLOWER_LOG=$(mktemp) > +ip netns exec nssv ptp4l -i "$NSIM_DEV_1_NAME" -m -4 -P \ > + > "$PTP4L_LEADER_LOG" 2>&1 & > +PTP4L_LEADER_PID=$! > + > +ip netns exec nscl ptp4l -i "$NSIM_DEV_2_NAME" -s -m -4 -P \ > + > "$PTP4L_FOLLOWER_LOG" 2>&1 & > +PTP4L_FOLLOWER_PID=$! Minor nit, ptp4l master, ptp4l slave started back-to-back. Better practice is to Start master Sleep 1 Then start follower Otherwise initial announce might be missed, causing unnecessary delay. > + > + > +for _ in $(seq 1 "$PTP4L_SYNC_TIMEOUT"); do > + if grep -q ' s2 ' "$PTP4L_FOLLOWER_LOG" 2>/dev/null; then > + exit 0 > + fi > + sleep 1 > +done > + > +echo "ptp4l follower did not reach locked state (s2) within > ${PTP4L_SYNC_TIMEOUT}s" > +exit 1 > -- > 2.53.0 > Reviewed-by: Sai Krishna <saikrishnag@marvell.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim 2026-02-25 16:45 ` Sai Krishna Gajula @ 2026-03-04 12:44 ` Maciek Machnikowski 0 siblings, 0 replies; 14+ messages in thread From: Maciek Machnikowski @ 2026-03-04 12:44 UTC (permalink / raw) To: Sai Krishna Gajula, netdev@vger.kernel.org Cc: kuba@kernel.org, richardcochran@gmail.com, milena.olech@intel.com, willemdebruijn.kernel@gmail.com, andrew@lunn.ch, vadim.fedorenko@linux.dev, horms@kernel.org On 25/02/2026 17:45, Sai Krishna Gajula wrote: >> -----Original Message----- >> From: Maciek Machnikowski <maciek@machnikowski.net> >> Sent: Wednesday, February 25, 2026 9:09 PM >> To: netdev@vger.kernel.org >> Cc: kuba@kernel.org; maciek@machnikowski.net; >> richardcochran@gmail.com; milena.olech@intel.com; >> willemdebruijn.kernel@gmail.com; andrew@lunn.ch; >> vadim.fedorenko@linux.dev; horms@kernel.org >> Subject: [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l >> sync test using netdevsim >> >> Add PTP synchronization test using ptp4l and netdevsim. The test creates two >> netdevsim adapters, links them together and runs the ptp4l leader and ptp4l >> follower on two ends of the netdevsim link and waits for the follower to >> report the synchronized >> Add PTP synchronization test using ptp4l and netdevsim. >> >> The test creates two netdevsim adapters, links them together and runs the >> ptp4l leader and ptp4l follower on two ends of the netdevsim link and waits >> for the follower to report the synchronized state (s2) in its output log. >> >> This implementation runs the test runs over IPv4 link. >> >> Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> >> --- >> tools/testing/selftests/net/Makefile | 1 + >> tools/testing/selftests/net/ptp.sh | 105 +++++++++++++++++++++++++++ >> 2 files changed, 106 insertions(+) >> create mode 100755 tools/testing/selftests/net/ptp.sh >> >> + >> +# PTP synchronization test: run ptp4l leader in nssv and follower in >> +nscl, # then parse follower output to verify they synchronized (servo state s2 >> = locked). >> +PTP4L_LEADER_LOG=$(mktemp) >> +PTP4L_FOLLOWER_LOG=$(mktemp) >> +ip netns exec nssv ptp4l -i "$NSIM_DEV_1_NAME" -m -4 -P \ >> + > "$PTP4L_LEADER_LOG" 2>&1 & >> +PTP4L_LEADER_PID=$! >> + >> +ip netns exec nscl ptp4l -i "$NSIM_DEV_2_NAME" -s -m -4 -P \ >> + > "$PTP4L_FOLLOWER_LOG" 2>&1 & >> +PTP4L_FOLLOWER_PID=$! > Minor nit, > ptp4l master, ptp4l slave started back-to-back. > Better practice is to > Start master > Sleep 1 > Then start follower > > Otherwise initial announce might be missed, causing unnecessary delay. Hmm not sure how would a sleep 1 help here - the leaders starts first, runs its BMCA anyway, and the follower starts with the -s flag. If anything, adding the sleep 1 would actually cause the initial announce to be missed (unless I'm missing sth there). >> + >> + >> +for _ in $(seq 1 "$PTP4L_SYNC_TIMEOUT"); do >> + if grep -q ' s2 ' "$PTP4L_FOLLOWER_LOG" 2>/dev/null; then >> + exit 0 >> + fi >> + sleep 1 >> +done >> + >> +echo "ptp4l follower did not reach locked state (s2) within >> ${PTP4L_SYNC_TIMEOUT}s" >> +exit 1 >> -- >> 2.53.0 >> > Reviewed-by: Sai Krishna <saikrishnag@marvell.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim 2026-02-25 15:38 ` [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim Maciek Machnikowski 2026-02-25 16:45 ` Sai Krishna Gajula @ 2026-02-26 2:41 ` Jakub Kicinski 2026-03-04 15:21 ` Willem de Bruijn 2 siblings, 0 replies; 14+ messages in thread From: Jakub Kicinski @ 2026-02-26 2:41 UTC (permalink / raw) To: Maciek Machnikowski Cc: netdev, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms On Wed, 25 Feb 2026 16:38:58 +0100 Maciek Machnikowski wrote: > Add PTP synchronization test using ptp4l and netdevsim. > > The test creates two netdevsim adapters, links them together > and runs the ptp4l leader and ptp4l follower on two ends > of the netdevsim link and waits for the follower to report the > synchronized state (s2) in its output log. Please make this a Python test using the wrappers we have so that the test can run both against netdevsim and real devices. Is ptp4l going to be stable as a selftest? And will it give us solid coverage (vs doing some fallbacks and pass even for broken drivers)? We generally test Vadim, WDYT? ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim 2026-02-25 15:38 ` [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim Maciek Machnikowski 2026-02-25 16:45 ` Sai Krishna Gajula 2026-02-26 2:41 ` Jakub Kicinski @ 2026-03-04 15:21 ` Willem de Bruijn 2 siblings, 0 replies; 14+ messages in thread From: Willem de Bruijn @ 2026-03-04 15:21 UTC (permalink / raw) To: Maciek Machnikowski, netdev Cc: kuba, maciek, richardcochran, milena.olech, willemdebruijn.kernel, andrew, vadim.fedorenko, horms Maciek Machnikowski wrote: > Add PTP synchronization test using ptp4l and netdevsim. > > The test creates two netdevsim adapters, links them together > and runs the ptp4l leader and ptp4l follower on two ends > of the netdevsim link and waits for the follower to report the > synchronized state (s2) in its output log. > > This implementation runs the test runs over IPv4 link. > > Signed-off-by: Maciek Machnikowski <maciek@machnikowski.net> > +if [ ! -x "$(command -v ptp4l)" ]; then > + echo "ptp4l command not found. Skipping PTP sync test" > + exit 4 Prefer to include ktap_helpers.sh and use named exit code KSFT_SKIP ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-03-04 15:48 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-02-25 15:38 [PATCH v3 net-next 0/3] Implement PTP support in netdevsim Maciek Machnikowski 2026-02-25 15:38 ` [PATCH v3 net-next 1/3] ptp_mock: Expose ptp_clock_info to external drivers Maciek Machnikowski 2026-02-26 1:57 ` Jakub Kicinski 2026-02-25 15:38 ` [PATCH v3 net-next 2/3] netdevsim: Implement basic ptp support Maciek Machnikowski 2026-02-25 16:32 ` Sai Krishna Gajula 2026-02-26 2:01 ` Jakub Kicinski 2026-03-04 12:41 ` Maciek Machnikowski 2026-03-04 15:19 ` Willem de Bruijn 2026-03-04 15:48 ` Willem de Bruijn 2026-02-25 15:38 ` [PATCH v3 net-next 3/3] selftests:net: Implement ptp4l sync test using netdevsim Maciek Machnikowski 2026-02-25 16:45 ` Sai Krishna Gajula 2026-03-04 12:44 ` Maciek Machnikowski 2026-02-26 2:41 ` Jakub Kicinski 2026-03-04 15:21 ` Willem de Bruijn
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox