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 F0356FCC9AE for ; Tue, 10 Mar 2026 02:51:07 +0000 (UTC) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id EAD8940DD1; Tue, 10 Mar 2026 03:49:47 +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 92DCC40A6B for ; Tue, 10 Mar 2026 03:49:43 +0100 (CET) Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-7d556c1a79eso13585040a34.3 for ; Mon, 09 Mar 2026 19:49:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1773110983; x=1773715783; 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=DsMXRvwYP9h+Abm/+TQkPnPxVGMyN0BStL5KvBPguz0=; b=FI+LFqrcKG/ysYabpl/pPKhp3g0uI8OqJVmhn+r8o/Ol4QsRKle2okVY4FZR6G+9hm zE2I5v6jrVMkU17dCqKdlNaXIs4kdV+aaXQXW/hsKntQqPCGizAwmT2CxHeVy+hinT/0 SjMTmPF0bdSeQDkDNIYa+TG4geCE/iYFwmGSm+0KGy0PVSZPnc6v/9yx0BtvQ8aCSaKH yXtQR/WyxAyXXVSbpTx9UQvKV9nIlNiHIy6eryH2UahEHRddxZkzs7QIgZGQ2Wc1A4M+ C3jYM36c8OIov2fNNAWwBudMFGjVChGt4LxrZP19zD3KVv6toAuTLDZv9VFPFuCFhPwg 7oTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773110983; x=1773715783; 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=DsMXRvwYP9h+Abm/+TQkPnPxVGMyN0BStL5KvBPguz0=; b=MsLLZtJGUZcqWkuLftRoqeTi9//RW/THWfxLFcGhTjomSgxzaYTScUq2j9kU4Xia/C z8e5oKBPc/ZcT5Dvh33xcr1TzTazY9zrF9x3GF/au1JLNXvvhy2/wlypNk141umimuHb 195az8+96lHXORz1VCTEsLU22NpbCFX4/nLlkIo5pYt4kC7lATsdmaA7phQP0Kq4KH8/ PMSscZlJwENh0WMeb5dw5Gvgd728hqWr0XoK9MqPbrHYy2tpOLqa8loIHi7JqVp0xtcc KhSsPEaSpGenDoXRJ9qb7LtZQRRkqLx9DMX/b82ahtZZ2Vdvv046BGpIitoUUhaJi5WO mztQ== X-Gm-Message-State: AOJu0Yye/S0NeOT8Nj9NH+FR4ecnL+9Dbv0Cn7KcWpDa8xTqirU4aVrx E6b7bhUlZ1Kdc+1dcrq+fsLp8ry4Es1+AA+gODMu8yWZtIWjJ32rVYmAhyiV9Zkm6KiKPXDcv69 rVK3poPQ= X-Gm-Gg: ATEYQzxUhgrnLj/7FV4cxdbxbIno82IB0fgmNgu/etnN/bFOZg26T8xgDVbxlGFskC+ W1M7BPMG+CpBmLCM4izTZtsbueKZNar8QbBKsGMt9/XsnPHiA88Y+9/tlTuJ07esUyxW8EI9f+4 0g23Oqk1Ax1SuWNUpKNAFu0Thfx5Sn6H5J3pF9ob3bsMuCjgYzRy4YGz4Wq0DHH9A1z/CoX5ZG3 Jz8WJuHrpognyi2KH1W6t4AMYyFdB9kYzxKeOlClw+dK/LyEWF63m8uCS86kHoRJ8Q6ExeIAEAo 5zSr4kzgQDVjoY87VlkS154BDaCD9C34B937hOayIBxtjNTLoObufO5rvu+DOlN5VufifDyfRIi uoc2Cd2NU5pUX+l9IzFVH5b6YBqSo7ZjXQ1Z4/2atn2lELYdXCAn/8XdDHjgkdU86J2r+Be5UzH 0lG9su2ELmPcDBHs4bBEifzuqD3bSpsSkC0zj2y6wUfew= X-Received: by 2002:a05:6830:6610:b0:7d1:4f4c:532a with SMTP id 46e09a7af769-7d726f38960mr8749130a34.20.1773110982823; Mon, 09 Mar 2026 19:49:42 -0700 (PDT) Received: from phoenix.lan ([104.202.29.139]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7d728d1238csm7808572a34.15.2026.03.09.19.49.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2026 19:49:42 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v19 13/25] net/pcap: add link status for interface mode Date: Mon, 9 Mar 2026 19:47:48 -0700 Message-ID: <20260310024925.476543-14-stephen@networkplumber.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260310024925.476543-1-stephen@networkplumber.org> References: <20260106182823.192350-1-stephen@networkplumber.org> <20260310024925.476543-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 63f554878d..f117c4975e 100644 --- a/doc/guides/rel_notes/release_26_03.rst +++ b/doc/guides/rel_notes/release_26_03.rst @@ -109,6 +109,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