From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC85CC55171 for ; Sat, 1 Aug 2026 03:25:53 +0000 (UTC) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5C4D2402ED; Sat, 1 Aug 2026 05:25:45 +0200 (CEST) Received: from mail-yw1-f198.google.com (mail-yw1-f198.google.com [209.85.128.198]) by mails.dpdk.org (Postfix) with ESMTP id 7E3E1402A7 for ; Sat, 1 Aug 2026 05:25:43 +0200 (CEST) Received: by mail-yw1-f198.google.com with SMTP id 00721157ae682-7f5b54da461so29301217b3.3 for ; Fri, 31 Jul 2026 20:25:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1785554743; x=1786159543; darn=dpdk.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=K6ujN3YOGnDiIX1rtl79pcr+b1Vc4o4doGh3KsJJCfs=; b=mOM0HfThnu9RDZxQXXJitXYumeDH6eH7pZzOv55QZFoALEZ816pYeFitPH4Pziolra 08fO7G4eUA9/qfQlQ53XMAXgstFDa7qIP2XjfaJbF1D4RQml70M+pOsbsRcfPE1Oat2K nsJtD1nIczChojrMiZ3DeIQZCdjQBRQ3Q8EY2FeyJNSTUf/lRdLlXAKS72PMfyl12SRO JvpZUgMlWNaOIfAcabpfwC7MGrPkjdLAyovAobHCGzPUDj+OFLq8FnLxRouSKvo/b+lF OT6Gz2zc6fUFfZQlneAsjXpSX6aaapYur3q3K1Oa4q/t0L7il0dX7nh3qbLs9LfYz62E kSNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785554743; x=1786159543; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=K6ujN3YOGnDiIX1rtl79pcr+b1Vc4o4doGh3KsJJCfs=; b=IpuztmAXqrxlooE1xagEfpJjO1gteGvcM5HZ8YRGNvc9ZebBim95kObBxEK1M1hR28 6rlz0q4eWD1aOZr4yzHPA7KGvlUTr1upuVPmEZyhZqD9V/QHjAPGHCG3OAV6U4VtUckI hW70taHh9Jilm4MDyNpI2T8MJICTnTasmUcuq6Ytw15H9rEUlVMmhuTdJ6A4ERHvJH2r rFNoA+TgdB03nYHCbg9mpFCI3BT/l87ktyNTaQAHgZBbdgNRKcM8wR1Gk0rwrfvvmwYk c3c0tkLi4QsjYbrGczI3qTX73eOFMa62kfWYRccUGOnuyxsf3I50LzcXiZNLhHJAvmfC 8Odw== X-Gm-Message-State: AOJu0Yw+c2BZYNWTAXg3TnwtYxN1Q1NhPXC1xjH5NArn8zNHTVq9Ksgz sT/znWx4e+4GUefFiCH+9sLNmUpLEhKK1i6vv5fauxGdXXV2H29EGZChCBodgbRtGQ5FPwi0KYR bxQpcVJl2VYX67gXuk8U9GAHCVC6RjVdQqaZi3mnC/Stl3aWt1uvnJ9h/OwixHwvFGkKUkGPph+ /EhtU0yYmil/DWsR2VOlL4Qb4= X-Received: from yxuu12.prod.google.com ([2002:a05:690e:24c:b0:668:2e46:41bc]) (user=blasko job=prod-delivery.src-stubby-dispatcher) by 2002:a05:690c:6e02:b0:7f2:9d64:9943 with SMTP id 00721157ae682-81fd4b1e024mr34049257b3.23.1785554742566; Fri, 31 Jul 2026 20:25:42 -0700 (PDT) Date: Sat, 1 Aug 2026 03:25:33 +0000 In-Reply-To: <20260801032534.2865192-1-blasko@google.com> Mime-Version: 1.0 References: <20260623215325.814776-1-blasko@google.com> <20260801032534.2865192-1-blasko@google.com> X-Mailer: git-send-email 2.55.0.508.g3f0d502094-goog Message-ID: <20260801032534.2865192-3-blasko@google.com> Subject: [PATCH v4 2/2] net/af_xdp: add read_clock support to AF_XDP PMD From: Mark Blasko To: dev@dpdk.org, Ciara Loftus , Maryam Tahhan Cc: joshwash@google.com, jtranoleary@google.com, blasko@google.com Content-Type: text/plain; charset="UTF-8" X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Implement the ethdev read_clock operation in the AF_XDP Poll Mode Driver. This allows DPDK applications to query the current time of the NIC hardware clock. At device start, the PMD queries ethtool for the interface's PTP Hardware Clock index and opens the corresponding PTP device node. The read_clock operation queries the current time via clock_gettime. Signed-off-by: Mark Blasko Reviewed-by: Joshua Washington --- v4: - Move ptp_fd into pmd_process_private for multi-process safety. - Decouple /dev/ptpX opening from RTE_ETH_RX_OFFLOAD_TIMESTAMP. - Move read_clock documentation out of "Options" into its own section in af_xdp.rst. - Add #ifndef guards around CLOCKFD and FD_TO_CLOCKID macro definitions. - Replace (caddr_t) cast with (void *). v3: - Add feature description and PTP hardware clock prerequisites in doc/guides/nics/af_xdp.rst. - Add release notes entry in doc/guides/rel_notes/release_26_07.rst. - Add PTP file descriptor cleanup in eth_dev_start(), eth_dev_stop(), and eth_dev_close(). - Return -errno on clock_gettime() failure. - Add strerror(errno) error logging on PTP device open failure. v2: - New patch introduced in v2 to support read_clock ethdev operation. --- doc/guides/nics/af_xdp.rst | 11 +++ doc/guides/rel_notes/release_26_07.rst | 1 + drivers/net/af_xdp/rte_eth_af_xdp.c | 99 ++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/doc/guides/nics/af_xdp.rst b/doc/guides/nics/af_xdp.rst index b48f7fb9f0..c8495decc5 100644 --- a/doc/guides/nics/af_xdp.rst +++ b/doc/guides/nics/af_xdp.rst @@ -37,6 +37,9 @@ Prerequisites header is used to determine the kernel version at compile time. * A kernel with version 5.4 or later is required for 32-bit OS. * The busy polling feature requires kernel version >= v5.11. +* The ``read_clock`` feature requires a network interface with PTP + Hardware Clock support (capable of exposing a ``/dev/ptpX`` device via + ethtool ``ETHTOOL_GET_TS_INFO``). Options @@ -247,6 +250,14 @@ netdev interface via ``SIOCSHWTSTAMP`` (which requires ``CAP_NET_ADMIN``). This hardware filter setting persists on the netdev interface after the DPDK application exits. +read_clock +---------- + +The PMD supports querying the underlying PTP hardware clock time via +``rte_eth_read_clock()``. During device start, the PMD automatically discovers +the hardware PHC index via ethtool and opens the PTP character device +(``/dev/ptpX``). + Limitations ----------- diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 8af0b8d615..326c35243b 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -140,6 +140,7 @@ New Features * Added support for RX metadata hardware timestamping via vdev devargs ``xdp_meta_rx_ts_offset``, ``xdp_meta_valid_hint_offset``, and ``xdp_meta_rx_ts_valid_mask``. + * Added ``read_clock`` operation to query the PTP hardware clock. * **Updated Google gve driver.** diff --git a/drivers/net/af_xdp/rte_eth_af_xdp.c b/drivers/net/af_xdp/rte_eth_af_xdp.c index b75c87b641..c8f7a26716 100644 --- a/drivers/net/af_xdp/rte_eth_af_xdp.c +++ b/drivers/net/af_xdp/rte_eth_af_xdp.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +201,7 @@ struct pmd_internals { struct pmd_process_private { int rxq_xsk_fds[RTE_MAX_QUEUES_PER_PORT]; + int ptp_fd; }; #define ETH_AF_XDP_IFACE_ARG "iface" @@ -834,10 +838,35 @@ eth_af_xdp_enable_hw_timestamping(const char *if_name) return 0; } +static int +eth_af_xdp_get_ptp_index(const char *if_name) +{ + struct ethtool_ts_info info = {0}; + struct ifreq ifr = {0}; + int fd, ret; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return -1; + + ifr.ifr_data = (void *)&info; + info.cmd = ETHTOOL_GET_TS_INFO; + strlcpy(ifr.ifr_name, if_name, IFNAMSIZ); + + ret = ioctl(fd, SIOCETHTOOL, &ifr); + close(fd); + + if (ret < 0) + return -1; + + return info.phc_index; +} + static int eth_dev_start(struct rte_eth_dev *dev) { struct pmd_internals *internals = dev->data->dev_private; + struct pmd_process_private *process_private = dev->process_private; uint16_t i; if (dev->data->dev_conf.rxmode.offloads & @@ -870,6 +899,28 @@ eth_dev_start(struct rte_eth_dev *dev) } } + if (process_private != NULL) { + int phc_index = eth_af_xdp_get_ptp_index(internals->if_name); + if (phc_index >= 0) { + char ptp_dev[32]; + snprintf(ptp_dev, sizeof(ptp_dev), "/dev/ptp%d", phc_index); + if (process_private->ptp_fd >= 0) { + close(process_private->ptp_fd); + process_private->ptp_fd = -1; + } + process_private->ptp_fd = open(ptp_dev, O_RDONLY); + if (process_private->ptp_fd >= 0) { + AF_XDP_LOG_LINE(INFO, + "Opened PTP device %s for read_clock", + ptp_dev); + } else { + AF_XDP_LOG_LINE(WARNING, + "Failed to open PTP device %s for read_clock: %s", + ptp_dev, strerror(errno)); + } + } + } + dev->data->dev_link.link_status = RTE_ETH_LINK_UP; for (i = 0; i < dev->data->nb_rx_queues; i++) { dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED; @@ -883,6 +934,7 @@ eth_dev_start(struct rte_eth_dev *dev) static int eth_dev_stop(struct rte_eth_dev *dev) { + struct pmd_process_private *process_private = dev->process_private; uint16_t i; dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN; @@ -891,6 +943,11 @@ eth_dev_stop(struct rte_eth_dev *dev) dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED; } + if (process_private != NULL && process_private->ptp_fd >= 0) { + close(process_private->ptp_fd); + process_private->ptp_fd = -1; + } + return 0; } @@ -1227,6 +1284,14 @@ eth_dev_close(struct rte_eth_dev *dev) } } + if (dev->process_private != NULL) { + struct pmd_process_private *process_private = dev->process_private; + if (process_private->ptp_fd >= 0) { + close(process_private->ptp_fd); + process_private->ptp_fd = -1; + } + } + out: rte_free(dev->process_private); @@ -2097,6 +2162,35 @@ eth_dev_promiscuous_disable(struct rte_eth_dev *dev) return eth_dev_change_flags(internals->if_name, 0, ~IFF_PROMISC); } +/* + * In Linux, dynamic POSIX clock IDs from file descriptors (such as /dev/ptpX) + * are encoded with CLOCKFD (3) in the lower 3 bits and ~fd in the upper bits. + * As this is not defined in user-space UAPI headers, define the macro here. + */ +#ifndef CLOCKFD +#define CLOCKFD 3 +#endif +#ifndef FD_TO_CLOCKID +#define FD_TO_CLOCKID(fd) ((clockid_t)(~(unsigned int)(fd) << 3 | CLOCKFD)) +#endif + +static int +eth_af_xdp_read_clock(struct rte_eth_dev *dev, uint64_t *timestamp) +{ + struct pmd_process_private *process_private = dev->process_private; + struct timespec ts; + + if (process_private == NULL || process_private->ptp_fd < 0) + return -ENOTSUP; + + clockid_t clkid = FD_TO_CLOCKID(process_private->ptp_fd); + if (clock_gettime(clkid, &ts) < 0) + return -errno; + + *timestamp = rte_timespec_to_ns(&ts); + return 0; +} + static const struct eth_dev_ops ops = { .dev_start = eth_dev_start, .dev_stop = eth_dev_stop, @@ -2112,6 +2206,7 @@ static const struct eth_dev_ops ops = { .stats_get = eth_stats_get, .stats_reset = eth_stats_reset, .get_monitor_addr = eth_get_monitor_addr, + .read_clock = eth_af_xdp_read_clock, }; /* AF_XDP Device Plugin option works in unprivileged @@ -2133,6 +2228,7 @@ static const struct eth_dev_ops ops_afxdp_dp = { .stats_get = eth_stats_get, .stats_reset = eth_stats_reset, .get_monitor_addr = eth_get_monitor_addr, + .read_clock = eth_af_xdp_read_clock, }; /** parse busy_budget argument */ @@ -2526,6 +2622,7 @@ init_internals(struct rte_vdev_device *dev, const char *if_name, eth_dev->tx_pkt_burst = eth_af_xdp_tx; eth_dev->process_private = process_private; + process_private->ptp_fd = -1; for (i = 0; i < queue_cnt; i++) process_private->rxq_xsk_fds[i] = -1; @@ -2681,6 +2778,8 @@ rte_pmd_af_xdp_probe(struct rte_vdev_device *dev) return -ENOMEM; } + ((struct pmd_process_private *)eth_dev->process_private)->ptp_fd = -1; + /* Obtain the xsk fds from the primary process. */ if (afxdp_mp_request_fds(name, eth_dev)) return -1; -- 2.55.0.508.g3f0d502094-goog