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 B3847FD4F05 for ; Tue, 10 Mar 2026 16:15:58 +0000 (UTC) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id F317240E72; Tue, 10 Mar 2026 17:14:18 +0100 (CET) Received: from mail-ot1-f49.google.com (mail-ot1-f49.google.com [209.85.210.49]) by mails.dpdk.org (Postfix) with ESMTP id 63C1940E54 for ; Tue, 10 Mar 2026 17:14:15 +0100 (CET) Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-7d73be007a1so3106033a34.0 for ; Tue, 10 Mar 2026 09:14:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1773159255; x=1773764055; darn=dpdk.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=PsjXHssacRP1X0BLF0TeN30c5Fwa+GOCOCVbr7267JM=; b=Lt52Z3Hwj5DIlQweoHyFe1maLRtL3Fom1MRKzfB2efdJRoEBV4Kj+EHaoR1tzr5R19 o1neCx3ax9tnEH+0Cb3NreyR1spnzv38fHEQJQoRzxYHWG8lOv19oxVi98GYfVJDlqzP jSmzi7XxMk+jURIzq220jDxlwbtT9N+H+bAvtJMSLjSgbw8YhbGRFdWtmu3NEvHDvSn4 eW6x3UDZR/XVXEUsklyPfsr4/5FTs18u14GFDELvs+MrPp0mAsoZCgRDx9yT34fdAeZN Gay6sBipGiEJ62cC9HL7e0wpZWHohLCHyCnS+MkfVE5gJKSUD07Y9/XwnCOQllAcy+1E DHPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773159255; x=1773764055; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=PsjXHssacRP1X0BLF0TeN30c5Fwa+GOCOCVbr7267JM=; b=Wm3o0eXFFDRsVRKmdMfVka5T1wfDiWXmoSDCzoCr12K/ERZ74x2KrkL8NJIt6c0S9U 4cpyEKK2zT73k5JqY6aAwh1EkGyD6qa8bLHuRnXl2tYT2NCVrPyZ8eUnNHQPZOUAsfYq q2CSbWEe59KWiL2tI75xKhuc5SH6hIZS4FVrZ+2AixDuG4kTDY6SMp79lFaQz9Qp7ZZL oS6KieoDoboPpnqS0LxbWo1qgTeb19vNqIjMs6l0RadDxmkuW+bdCV/d3roXBR8P528y 0Gkl54GSS9BvcZA5y0Pn4mcYPjhWvgZzfwFB3bDlc7pnTi8gaC6Nc8oqrJkPjNWNUTTa r3JQ== X-Gm-Message-State: AOJu0YwQzMC4U1BYhFXHQjWHfJPPDTSBGtkQkquQZGROfIhz4xD1MnC5 Hx6yzywjUr1W0RKrxiII6mp/YXe5dsz3wHX1B3aSRGJTHrxah4AC8kRscmrqd8EwU5nkDeq0JNH LMEjNkOQ= X-Gm-Gg: ATEYQzzIyV0giFBrh1Y94IDVsiayG/HFuEwzxUjLrTqMWoB41VPnhNX9V5EfEMnM0CA jIxURby0y2SG4wBnXHtTr90W+TqhGjvcS/79YUQSu0KPcI++Tg7M14goYLu2eT23ck2Ac5uSeZg EPSHOiGXd3oS0swqmLOytSYoeonbYoUKn7HBQKruUI56YXKRAvRvRzPrrxnkYFVcrmK+AxX81DN dPibRt7ZKKUibI03kqOCqp3BJv0zypQEO07ZWrYE7sclS2ysfAlxcjHwEDvrcTShMOBm0SxaWst Bdt8O4fCVMKtX4NTBT3BZD+J+u4aoFTv6Xju88RZrIkuib9ClZ3ktyDk0XO1RAg95HQERLtJavk tjr9QKZwhFVtWtKcIRFKquKOFR3QO2GcLdMQ/fOTE3fW1rzoQCtDhT15mlxwRE6JI0WArlF61VF T8m6g9DmLzFbYpB+GQHZ0B2YzUzCCwxKAK X-Received: by 2002:a05:6830:2784:b0:7d1:4e51:e45 with SMTP id 46e09a7af769-7d72700afa9mr10944526a34.17.1773159254561; Tue, 10 Mar 2026 09:14:14 -0700 (PDT) Received: from phoenix.lan ([104.202.29.139]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7d738e3f421sm7304004a34.25.2026.03.10.09.14.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 09:14:14 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v20 13/25] net/pcap: add link status for interface mode Date: Tue, 10 Mar 2026 09:09:51 -0700 Message-ID: <20260310161356.194553-14-stephen@networkplumber.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260310161356.194553-1-stephen@networkplumber.org> References: <20260106182823.192350-1-stephen@networkplumber.org> <20260310161356.194553-1-stephen@networkplumber.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 When the PCAP PMD is used in pass-through mode with a physical interface (iface=X), the link status was always reported with hardcoded values regardless of the actual interface state. Add OS-dependent function to query the real link state from the underlying interface. Linux and FreeBSD use SIOCGIFFLAGS to check IFF_UP and IFF_RUNNING. Windows uses GetAdaptersAddresses() to check OperStatus. Signed-off-by: Stephen Hemminger --- doc/guides/rel_notes/release_26_03.rst | 1 + drivers/net/pcap/pcap_ethdev.c | 38 +++++++++----- drivers/net/pcap/pcap_osdep.h | 12 +++++ drivers/net/pcap/pcap_osdep_freebsd.c | 31 ++++++++++++ drivers/net/pcap/pcap_osdep_linux.c | 27 ++++++++++ drivers/net/pcap/pcap_osdep_windows.c | 68 +++++++++++++++++++++----- 6 files changed, 154 insertions(+), 23 deletions(-) diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst index 6aef623bf8..35a191b45f 100644 --- a/doc/guides/rel_notes/release_26_03.rst +++ b/doc/guides/rel_notes/release_26_03.rst @@ -121,6 +121,7 @@ New Features * **Updated PCAP ethernet driver.** * Added support for VLAN insertion and stripping. + * Added support for reporting link state in ``iface`` mode. Removed Items diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c index c49ca7fa2b..232b8fa4b1 100644 --- a/drivers/net/pcap/pcap_ethdev.c +++ b/drivers/net/pcap/pcap_ethdev.c @@ -150,13 +150,6 @@ static const char *valid_arguments[] = { NULL }; -static struct rte_eth_link pmd_link = { - .link_speed = RTE_ETH_SPEED_NUM_10G, - .link_duplex = RTE_ETH_LINK_FULL_DUPLEX, - .link_status = RTE_ETH_LINK_DOWN, - .link_autoneg = RTE_ETH_LINK_FIXED, -}; - RTE_LOG_REGISTER_DEFAULT(eth_pcap_logtype, NOTICE); static struct queue_missed_stat* @@ -945,10 +938,28 @@ eth_dev_close(struct rte_eth_dev *dev) } static int -eth_link_update(struct rte_eth_dev *dev __rte_unused, - int wait_to_complete __rte_unused) +eth_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused) { - return 0; + struct pmd_internals *internals = dev->data->dev_private; + struct rte_eth_link link = { + .link_speed = RTE_ETH_SPEED_NUM_10G, + .link_duplex = RTE_ETH_LINK_FULL_DUPLEX, + .link_autoneg = RTE_ETH_LINK_FIXED, + }; + + /* + * For pass-through mode (single_iface), query whether the + * underlying interface is up. Otherwise use default values. + */ + if (internals->single_iface) { + link.link_status = (osdep_iface_link_status(internals->rx_queue[0].name) > 0) ? + RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN; + } else { + link.link_status = dev->data->dev_started ? + RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN; + } + + return rte_eth_linkstatus_set(dev, &link); } static int @@ -1363,7 +1374,12 @@ pmd_init_internals(struct rte_vdev_device *vdev, data = (*eth_dev)->data; data->nb_rx_queues = (uint16_t)nb_rx_queues; data->nb_tx_queues = (uint16_t)nb_tx_queues; - data->dev_link = pmd_link; + data->dev_link = (struct rte_eth_link) { + .link_speed = RTE_ETH_SPEED_NUM_NONE, + .link_duplex = RTE_ETH_LINK_FULL_DUPLEX, + .link_status = RTE_ETH_LINK_DOWN, + .link_autoneg = RTE_ETH_LINK_FIXED, + }; data->mac_addrs = &(*internals)->eth_addr; data->promiscuous = 1; data->all_multicast = 1; diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h index fe7399ff9f..18e63c6f2b 100644 --- a/drivers/net/pcap/pcap_osdep.h +++ b/drivers/net/pcap/pcap_osdep.h @@ -10,6 +10,7 @@ #define PMD_LOG(level, ...) \ RTE_LOG_LINE_PREFIX(level, ETH_PCAP, "%s(): ", __func__, __VA_ARGS__) + extern int eth_pcap_logtype; #define RTE_LOGTYPE_ETH_PCAP eth_pcap_logtype @@ -30,4 +31,15 @@ extern int eth_pcap_logtype; int osdep_iface_index_get(const char *name); int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac); +/** + * Get link status for a network interface. + * + * @param name + * Interface name (e.g., "eth0" on Linux, "{GUID}" on Windows). + * @return + * 1 if link is up, 0 if link is down, -1 on error. + */ +int osdep_iface_link_status(const char *name); + + #endif diff --git a/drivers/net/pcap/pcap_osdep_freebsd.c b/drivers/net/pcap/pcap_osdep_freebsd.c index 0185665f0b..9c4186aadc 100644 --- a/drivers/net/pcap/pcap_osdep_freebsd.c +++ b/drivers/net/pcap/pcap_osdep_freebsd.c @@ -5,8 +5,13 @@ */ #include +#include +#include #include #include +#include +#include +#include #include #include "pcap_osdep.h" @@ -55,3 +60,29 @@ osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac) free(buf); return 0; } + +int +osdep_iface_link_status(const char *if_name) +{ + struct ifmediareq ifmr; + int fd, status = 0; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) + return -1; + + memset(&ifmr, 0, sizeof(ifmr)); + strlcpy(ifmr.ifm_name, if_name, sizeof(ifmr.ifm_name)); + + if (ioctl(fd, SIOCGIFMEDIA, &ifmr) == 0) { + /* IFM_AVALID means status is valid, IFM_ACTIVE means link up */ + if ((ifmr.ifm_status & IFM_AVALID) && + (ifmr.ifm_status & IFM_ACTIVE)) + status = 1; + } else { + status = -1; + } + + close(fd); + return status; +} diff --git a/drivers/net/pcap/pcap_osdep_linux.c b/drivers/net/pcap/pcap_osdep_linux.c index df976417cb..f61b7bd146 100644 --- a/drivers/net/pcap/pcap_osdep_linux.c +++ b/drivers/net/pcap/pcap_osdep_linux.c @@ -40,3 +40,30 @@ osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac) close(if_fd); return 0; } + +int +osdep_iface_link_status(const char *if_name) +{ + struct ifreq ifr; + int fd, status = 0; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) + return -1; + + rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) { + /* + * IFF_UP means administratively up. + * IFF_RUNNING means operationally up (carrier detected). + * Both must be set for link to be considered up. + */ + if ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)) + status = 1; + } else { + status = -1; + } + + close(fd); + return status; +} diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c index 0965c2f5c9..e7a49c47e0 100644 --- a/drivers/net/pcap/pcap_osdep_windows.c +++ b/drivers/net/pcap/pcap_osdep_windows.c @@ -61,38 +61,56 @@ osdep_iface_index_get(const char *device_name) } /* - * libpcap takes device names like "\Device\NPF_{GUID}", - * GetAdaptersAddresses() returns names in "{GUID}" form. - * Try to extract GUID from device name, fall back to original device name. + * Helper function to get adapter information by name. + * Returns adapter info on success, NULL on failure. + * Caller must free the returned buffer. */ -int -osdep_iface_mac_get(const char *device_name, struct rte_ether_addr *mac) +static IP_ADAPTER_ADDRESSES * +get_adapter_addresses(void) { - IP_ADAPTER_ADDRESSES *info = NULL, *cur = NULL; - ULONG size, sys_ret; - const char *adapter_name; - int ret = -1; + IP_ADAPTER_ADDRESSES *info = NULL; + ULONG size; + DWORD sys_ret; sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size); if (sys_ret != ERROR_BUFFER_OVERFLOW) { PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu", sys_ret, ERROR_BUFFER_OVERFLOW); - return -1; + return NULL; } info = (IP_ADAPTER_ADDRESSES *)malloc(size); if (info == NULL) { PMD_LOG(ERR, "Cannot allocate adapter address info"); - return -1; + return NULL; } sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size); if (sys_ret != ERROR_SUCCESS) { PMD_LOG(ERR, "GetAdapterAddresses() = %lu", sys_ret); free(info); - return -1; + return NULL; } + return info; +} + +/* + * libpcap takes device names like "\Device\NPF_{GUID}", + * GetAdaptersAddresses() returns names in "{GUID}" form. + * Try to extract GUID from device name, fall back to original device name. + */ +int +osdep_iface_mac_get(const char *device_name, struct rte_ether_addr *mac) +{ + IP_ADAPTER_ADDRESSES *info = NULL, *cur = NULL; + const char *adapter_name; + int ret = -1; + + info = get_adapter_addresses(); + if (info == NULL) + return -1; + adapter_name = iface_guid(device_name); if (adapter_name == NULL) adapter_name = device_name; @@ -116,3 +134,29 @@ osdep_iface_mac_get(const char *device_name, struct rte_ether_addr *mac) free(info); return ret; } + +int +osdep_iface_link_status(const char *device_name) +{ + IP_ADAPTER_ADDRESSES *info, *cur; + const char *adapter_name; + int ret = -1; + + info = get_adapter_addresses(); + if (info == NULL) + return -1; + + adapter_name = iface_guid(device_name); + if (adapter_name == NULL) + adapter_name = device_name; + + for (cur = info; cur != NULL; cur = cur->Next) { + if (strcmp(cur->AdapterName, adapter_name) == 0) { + ret = (cur->OperStatus == IfOperStatusUp) ? 1 : 0; + break; + } + } + + free(info); + return ret; +} -- 2.51.0