[dpdk-dev] [PATCH 0/6] net/pcap: build on Windows

67 messages, 9 authors, 2021-04-21 · open the first message on its own page

[dpdk-dev] [PATCH 0/6] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:20:27

Most modern and actively maintained distribution of libpcap for Windows is Npcap
(https://nmap.org/npcap). It is free (as in "free beer") and open-source, but
Npcap redistribution with commercial products may be limited by its license.

Npcap can be installed anywhere, so a new Meson option is provided to find it:

    meson -Dpcap_sdk=C:\Npcap -Dexamples=skeleton build

Example of collecting packets from an interface to a file:

    .\build\examples\dpdk-skeleton.exe `
        --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
        --vdev "eth_pcap1,tx_pcap=capture.pcap"

Implementation in "pcap_osdep_windows.c" does some guesswork to convert
between variants of an interface name. Microsoft experts and interested
users, please take a look and/or give it a try in your environment.

There are no release notes for 21.05 yet, will send update after they appear.

Dmitry Kozlyuk (6):
  eal: add internal API for current time
  net/pcap: fix format string
  net/pcap: move OS-dependent code to separate files
  net/pcap: add libpcap wrappers
  config: discover libpcap on Windows
  net/pcap: build on Windows

 config/meson.build                            |  21 +-
 drivers/net/pcap/meson.build                  |  17 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 251 ++++++------------
 drivers/net/pcap/pcap_osdep.c                 | 122 +++++++++
 drivers/net/pcap/pcap_osdep.h                 |  72 +++++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 ++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++
 drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++
 lib/librte_eal/include/rte_time.h             |  17 ++
 lib/librte_eal/rte_eal_exports.def            |   1 +
 lib/librte_eal/unix/eal_unix_timer.c          |  13 +
 lib/librte_eal/version.map                    |   1 +
 lib/librte_eal/windows/eal_timer.c            |  20 +-
 meson_options.txt                             |   6 +-
 14 files changed, 584 insertions(+), 176 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (88%)
 create mode 100644 drivers/net/pcap/pcap_osdep.c
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

-- 
2.29.2

[dpdk-dev] [PATCH 1/6] eal: add internal API for current time

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:20:34

Many PMDs use POSIX gettimeofday(). Add rte_time_get_us() function
to obtain current time with microsecond precision on all platforms.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 lib/librte_eal/include/rte_time.h    | 17 +++++++++++++++++
 lib/librte_eal/rte_eal_exports.def   |  1 +
 lib/librte_eal/unix/eal_unix_timer.c | 13 +++++++++++++
 lib/librte_eal/version.map           |  1 +
 lib/librte_eal/windows/eal_timer.c   | 20 +++++++++++++++++++-
 5 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/lib/librte_eal/include/rte_time.h b/lib/librte_eal/include/rte_time.h
index 5ad7c8841..50fa4f889 100644
--- a/lib/librte_eal/include/rte_time.h
+++ b/lib/librte_eal/include/rte_time.h
@@ -8,6 +8,8 @@
 #include <stdint.h>
 #include <time.h>
 
+#include <rte_compat.h>
+
 #define NSEC_PER_SEC             1000000000L
 
 /**
@@ -98,4 +100,19 @@ rte_ns_to_timespec(uint64_t nsec)
 	return ts;
 }
 
+/* Point of time with microsecond precision. */
+struct rte_time_us {
+	int64_t sec;  /**< Number of whole seconds. */
+	int64_t usec; /**< Fractional part of second in [0, 999999]. */
+};
+
+/**
+ * Get current system time.
+ *
+ * @param now
+ *  Receives current system time.
+ */
+__rte_internal
+void rte_time_get_us(struct rte_time_us *now);
+
 #endif /* _RTE_TIME_H_ */
diff --git a/lib/librte_eal/rte_eal_exports.def b/lib/librte_eal/rte_eal_exports.def
index 474cf123f..cb691f7bc 100644
--- a/lib/librte_eal/rte_eal_exports.def
+++ b/lib/librte_eal/rte_eal_exports.def
@@ -334,3 +334,4 @@ EXPORTS
 	rte_mem_map
 	rte_mem_page_size
 	rte_mem_unmap
+	rte_time_get_us
diff --git a/lib/librte_eal/unix/eal_unix_timer.c b/lib/librte_eal/unix/eal_unix_timer.c
index cc5015910..5612fdebe 100644
--- a/lib/librte_eal/unix/eal_unix_timer.c
+++ b/lib/librte_eal/unix/eal_unix_timer.c
@@ -4,7 +4,10 @@
 
 #include <time.h>
 
+#include <sys/time.h>
+
 #include <rte_cycles.h>
+#include <rte_time.h>
 
 void
 rte_delay_us_sleep(unsigned int us)
@@ -27,3 +30,13 @@ rte_delay_us_sleep(unsigned int us)
 		ind = 1 - ind;
 	}
 }
+
+void
+rte_time_get_us(struct rte_time_us *now)
+{
+	struct timeval sys;
+
+	gettimeofday(&sys, NULL);
+	now->sec = sys.tv_sec;
+	now->usec = sys.tv_usec;
+}
diff --git a/lib/librte_eal/version.map b/lib/librte_eal/version.map
index fce90a112..405bed766 100644
--- a/lib/librte_eal/version.map
+++ b/lib/librte_eal/version.map
@@ -421,4 +421,5 @@ INTERNAL {
 	rte_mem_map;
 	rte_mem_page_size;
 	rte_mem_unmap;
+	rte_time_get_us;
 };
diff --git a/lib/librte_eal/windows/eal_timer.c b/lib/librte_eal/windows/eal_timer.c
index b070cb775..b5c8eaa73 100644
--- a/lib/librte_eal/windows/eal_timer.c
+++ b/lib/librte_eal/windows/eal_timer.c
@@ -9,6 +9,7 @@
 #include <rte_cycles.h>
 #include <rte_eal.h>
 #include <rte_errno.h>
+#include <rte_time.h>
 #include "eal_private.h"
 
 #define US_PER_SEC 1E6
@@ -85,10 +86,27 @@ get_tsc_freq(void)
 	return RTE_ALIGN_MUL_NEAR(tsc_hz, CYC_PER_10MHZ);
 }
 
-
 int
 rte_eal_timer_init(void)
 {
 	set_tsc_freq();
 	return 0;
 }
+
+void
+rte_time_get_us(struct rte_time_us *now)
+{
+	/* 100ns ticks from 1601-01-01 to 1970-01-01 */
+	static const uint64_t EPOCH = 116444736000000000ULL;
+	static const uint64_t TICKS_PER_USEC = 10;
+	static const uint64_t USEC_PER_SEC = 1000000;
+
+	FILETIME ft;
+	uint64_t ticks, sec;
+
+	GetSystemTimePreciseAsFileTime(&ft);
+	ticks = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+	sec = (ticks - EPOCH) / (TICKS_PER_USEC * USEC_PER_SEC);
+	now->sec = sec;
+	now->usec = (ticks - sec * USEC_PER_SEC) / TICKS_PER_USEC;
+}
-- 
2.29.2

[dpdk-dev] [PATCH 2/6] net/pcap: fix format string

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:20:42

Use PRIu32 for uint32_t (found by -Wformat with Clang on Windows).

Fixes: a3f5252e5cbd ("net/pcap: enable infinitely Rx a pcap file")
Cc: stable@dpdk.org

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/rte_eth_pcap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c
index 90f5d75ea..176928da3 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/rte_eth_pcap.c
@@ -827,7 +827,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 		pcap_pkt_count = count_packets_in_pcap(pcap, pcap_q);
 
-		snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu16,
+		snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu32,
 				ring_number);
 
 		pcap_q->pkts = rte_ring_create(ring_name,
-- 
2.29.2

[dpdk-dev] [PATCH 3/6] net/pcap: move OS-dependent code to separate files

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:20:50

PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. In preparation to add
Windows-specific part and libpcap wrapper, extract OS-independent
interface and move implementations to separate files. Rename
rte_eth_pcap.c to pcap_ethdev.c for consistency with the rest of DPDK.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/meson.build                  |  5 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 88 ++-----------------
 drivers/net/pcap/pcap_osdep.h                 | 17 ++++
 drivers/net/pcap/pcap_osdep_freebsd.c         | 59 +++++++++++++
 drivers/net/pcap/pcap_osdep_linux.c           | 42 +++++++++
 5 files changed, 130 insertions(+), 81 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index b65d91e70..26b606699 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -11,5 +11,8 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
-sources = files('rte_eth_pcap.c')
+sources = files(
+	'pcap_ethdev.c',
+	'pcap_osdep_@0@.c'.format(exec_env),
+)
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/pcap_ethdev.c
similarity index 95%
rename from drivers/net/pcap/rte_eth_pcap.c
rename to drivers/net/pcap/pcap_ethdev.c
index 176928da3..a102897e9 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -6,16 +6,6 @@
 
 #include <time.h>
 
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#if defined(RTE_EXEC_ENV_FREEBSD)
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#endif
-
 #include <pcap.h>
 
 #include <rte_cycles.h>
@@ -25,7 +15,8 @@
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_bus_vdev.h>
-#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
 
 #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
 #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
@@ -1191,84 +1182,20 @@ static int
 eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
 		const unsigned int numa_node)
 {
-#if defined(RTE_EXEC_ENV_LINUX)
 	void *mac_addrs;
-	struct ifreq ifr;
-	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-	if (if_fd == -1)
-		return -1;
+	struct rte_ether_addr mac;
 
-	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
-	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
-		close(if_fd);
+	if (osdep_iface_mac_get(if_name, &mac) < 0)
 		return -1;
-	}
 
 	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		close(if_fd);
+	if (mac_addrs == NULL)
 		return -1;
-	}
 
 	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
+	rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
 	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
-
-	close(if_fd);
-
-	return 0;
-
-#elif defined(RTE_EXEC_ENV_FREEBSD)
-	void *mac_addrs;
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	int mib[6];
-	size_t len = 0;
-	char *buf;
-
-	mib[0] = CTL_NET;
-	mib[1] = AF_ROUTE;
-	mib[2] = 0;
-	mib[3] = AF_LINK;
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = if_nametoindex(if_name);
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-
-	if (len == 0)
-		return -1;
-
-	buf = rte_malloc(NULL, len, 0);
-	if (!buf)
-		return -1;
-
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		rte_free(buf);
-		return -1;
-	}
-	ifm = (struct if_msghdr *)buf;
-	sdl = (struct sockaddr_dl *)(ifm + 1);
-
-	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		rte_free(buf);
-		return -1;
-	}
-
-	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
-	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			LLADDR(sdl), RTE_ETHER_ADDR_LEN);
-
-	rte_free(buf);
-
 	return 0;
-#else
-	return -1;
-#endif
 }
 
 static int
@@ -1330,7 +1257,8 @@ eth_from_pcaps(struct rte_vdev_device *vdev,
 	internals->single_iface = single_iface;
 
 	if (single_iface) {
-		internals->if_index = if_nametoindex(rx_queues->queue[0].name);
+		internals->if_index =
+			osdep_iface_index_get(rx_queues->queue[0].name);
 
 		/* phy_mac arg is applied only only if "iface" devarg is provided */
 		if (rx_queues->phy_mac) {
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
new file mode 100644
index 000000000..46810d86f
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#ifndef _RTE_PCAP_OSDEP_
+#define _RTE_PCAP_OSDEP_
+
+#include <rte_ether.h>
+
+/*
+ * Interface manipulation is always OS-specific.
+ */
+
+int osdep_iface_index_get(const char *name);
+int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
+
+#endif
diff --git a/drivers/net/pcap/pcap_osdep_freebsd.c b/drivers/net/pcap/pcap_osdep_freebsd.c
new file mode 100644
index 000000000..20556b3e9
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_freebsd.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/sysctl.h>
+
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	int mib[6];
+	size_t len = 0;
+	char *buf;
+
+	mib[0] = CTL_NET;
+	mib[1] = AF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_LINK;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = if_nametoindex(if_name);
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+
+	if (len == 0)
+		return -1;
+
+	buf = rte_malloc(NULL, len, 0);
+	if (!buf)
+		return -1;
+
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		rte_free(buf);
+		return -1;
+	}
+	ifm = (struct if_msghdr *)buf;
+	sdl = (struct sockaddr_dl *)(ifm + 1);
+
+	rte_memcpy(mac->addr_bytes, LLADDR(sdl), RTE_ETHER_ADDR_LEN);
+
+	rte_free(buf);
+	return 0;
+}
diff --git a/drivers/net/pcap/pcap_osdep_linux.c b/drivers/net/pcap/pcap_osdep_linux.c
new file mode 100644
index 000000000..97033f57c
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_linux.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <rte_memcpy.h>
+#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct ifreq ifr;
+	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (if_fd == -1)
+		return -1;
+
+	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
+		close(if_fd);
+		return -1;
+	}
+
+	rte_memcpy(mac->addr_bytes, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
+
+	close(if_fd);
+	return 0;
+}
-- 
2.29.2

[dpdk-dev] [PATCH 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:20:57

libpcap headers can expose OS headers. On Windows, system networking
headers are incompatible with DPDK ones, causing multiple name clashes.
API of libpcap itself involves a non-standard u_char type.

Add a limited set of trivial libpcap wrappers, so that libpcap headers
are not included directly by OS-independent PMD code. Use EAL types and
functions for time instead of POSIX ones.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/meson.build   |   1 +
 drivers/net/pcap/pcap_ethdev.c | 157 +++++++++++++++++----------------
 drivers/net/pcap/pcap_osdep.c  | 122 +++++++++++++++++++++++++
 drivers/net/pcap/pcap_osdep.h  |  50 +++++++++++
 4 files changed, 252 insertions(+), 78 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 26b606699..9ab95ec3e 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -13,6 +13,7 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
 endif
 sources = files(
 	'pcap_ethdev.c',
+	'pcap_osdep.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index a102897e9..6461213e0 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -4,17 +4,13 @@
  * All rights reserved.
  */
 
-#include <time.h>
-
-#include <pcap.h>
-
-#include <rte_cycles.h>
 #include <ethdev_driver.h>
 #include <ethdev_vdev.h>
+#include <rte_bus_vdev.h>
+#include <rte_cycles.h>
 #include <rte_kvargs.h>
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
-#include <rte_bus_vdev.h>
 
 #include "pcap_osdep.h"
 
@@ -36,8 +32,8 @@
 
 #define RTE_PMD_PCAP_MAX_QUEUES 16
 
-static char errbuf[PCAP_ERRBUF_SIZE];
-static struct timeval start_time;
+static char errbuf[OSDEP_PCAP_ERRBUF_SIZE];
+static struct rte_time_us start_time;
 static uint64_t start_cycles;
 static uint64_t hz;
 static uint8_t iface_idx;
@@ -83,16 +79,16 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	pcap_t *rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
-	pcap_t *tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
-	pcap_dumper_t *tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
+	osdep_pcap * rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
+	osdep_pcap * tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
+	osdep_pcap_dumper * tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
 };
 
 struct pmd_devargs {
 	unsigned int num_of_queue;
 	struct devargs_queue {
-		pcap_dumper_t *dumper;
-		pcap_t *pcap;
+		osdep_pcap_dumper *dumper;
+		osdep_pcap *pcap;
 		const char *name;
 		const char *type;
 	} queue[RTE_PMD_PCAP_MAX_QUEUES];
@@ -137,7 +133,7 @@ RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
 static int
 eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
-		const u_char *data, uint16_t data_len)
+		const uint8_t *data, uint16_t data_len)
 {
 	/* Copy the first segment. */
 	uint16_t len = rte_pktmbuf_tailroom(mbuf);
@@ -214,14 +210,14 @@ static uint16_t
 eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	unsigned int i;
-	struct pcap_pkthdr header;
+	struct osdep_pcap_pkthdr header;
 	struct pmd_process_private *pp;
-	const u_char *packet;
+	const uint8_t *packet;
 	struct rte_mbuf *mbuf;
 	struct pcap_rx_queue *pcap_q = queue;
 	uint16_t num_rx = 0;
 	uint32_t rx_bytes = 0;
-	pcap_t *pcap;
+	osdep_pcap *pcap;
 
 	pp = rte_eth_devices[pcap_q->port_id].process_private;
 	pcap = pp->rx_pcap[pcap_q->queue_id];
@@ -234,7 +230,7 @@ eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	 */
 	for (i = 0; i < nb_pkts; i++) {
 		/* Get the next PCAP packet */
-		packet = pcap_next(pcap, &header);
+		packet = osdep_pcap_next(pcap, &header);
 		if (unlikely(packet == NULL))
 			break;
 
@@ -261,8 +257,8 @@ eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		mbuf->pkt_len = (uint16_t)header.caplen;
 		*RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset,
 			rte_mbuf_timestamp_t *) =
-				(uint64_t)header.ts.tv_sec * 1000000 +
-				header.ts.tv_usec;
+				(uint64_t)header.ts.sec * 1000000 +
+				header.ts.usec;
 		mbuf->ol_flags |= timestamp_rx_dynflag;
 		mbuf->port = pcap_q->port_id;
 		bufs[num_rx] = mbuf;
@@ -285,20 +281,24 @@ eth_null_rx(void *queue __rte_unused,
 
 #define NSEC_PER_SEC	1000000000L
 
+/*
+ * This function stores nanoseconds in "usec" field of struct rte_time_us,
+ * because "ts" goes directly to nanosecond-precision dump.
+ */
 static inline void
-calculate_timestamp(struct timeval *ts) {
+calculate_timestamp(struct rte_time_us *ts) {
 	uint64_t cycles;
-	struct timeval cur_time;
+	struct rte_time_us cur_time;
 
 	cycles = rte_get_timer_cycles() - start_cycles;
-	cur_time.tv_sec = cycles / hz;
-	cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz;
-
-	ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
-	ts->tv_usec = start_time.tv_usec + cur_time.tv_usec;
-	if (ts->tv_usec >= NSEC_PER_SEC) {
-		ts->tv_usec -= NSEC_PER_SEC;
-		ts->tv_sec += 1;
+	cur_time.sec = cycles / hz;
+	cur_time.usec = (cycles % hz) * NSEC_PER_SEC / hz;
+
+	ts->sec = start_time.sec + cur_time.sec;
+	ts->usec = start_time.usec + cur_time.usec;
+	if (ts->usec >= NSEC_PER_SEC) {
+		ts->usec -= NSEC_PER_SEC;
+		ts->sec += 1;
 	}
 }
 
@@ -314,8 +314,8 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	struct pcap_tx_queue *dumper_q = queue;
 	uint16_t num_tx = 0;
 	uint32_t tx_bytes = 0;
-	struct pcap_pkthdr header;
-	pcap_dumper_t *dumper;
+	struct osdep_pcap_pkthdr header;
+	osdep_pcap_dumper *dumper;
 	unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
 	size_t len, caplen;
 
@@ -342,7 +342,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		 * in the mbuf (when the mbuf is contiguous) or, otherwise,
 		 * a pointer to temp_data after copying into it.
 		 */
-		pcap_dump((u_char *)dumper, &header,
+		osdep_pcap_dump((uint8_t *)dumper, &header,
 			rte_pktmbuf_read(mbuf, 0, caplen, temp_data));
 
 		num_tx++;
@@ -355,7 +355,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	 * process stops and to make sure the pcap file is actually written,
 	 * we flush the pcap dumper within each burst.
 	 */
-	pcap_dump_flush(dumper);
+	osdep_pcap_dump_flush(dumper);
 	dumper_q->tx_stat.pkts += num_tx;
 	dumper_q->tx_stat.bytes += tx_bytes;
 	dumper_q->tx_stat.err_pkts += nb_pkts - num_tx;
@@ -400,7 +400,7 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	struct pcap_tx_queue *tx_queue = queue;
 	uint16_t num_tx = 0;
 	uint32_t tx_bytes = 0;
-	pcap_t *pcap;
+	osdep_pcap *pcap;
 	unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
 	size_t len;
 
@@ -426,7 +426,7 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		 * in the mbuf (when the mbuf is contiguous) or, otherwise,
 		 * a pointer to temp_data after copying into it.
 		 */
-		ret = pcap_sendpacket(pcap,
+		ret = osdep_pcap_sendpacket(pcap,
 			rte_pktmbuf_read(mbuf, 0, len, temp_data), len);
 		if (unlikely(ret != 0))
 			break;
@@ -443,11 +443,11 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 }
 
 /*
- * pcap_open_live wrapper function
+ * osdep_pcap_open_live wrapper function
  */
 static inline int
-open_iface_live(const char *iface, pcap_t **pcap) {
-	*pcap = pcap_open_live(iface, RTE_ETH_PCAP_SNAPLEN,
+open_iface_live(const char *iface, osdep_pcap **pcap) {
+	*pcap = osdep_pcap_open_live(iface, RTE_ETH_PCAP_SNAPLEN,
 			RTE_ETH_PCAP_PROMISC, RTE_ETH_PCAP_TIMEOUT, errbuf);
 
 	if (*pcap == NULL) {
@@ -459,7 +459,7 @@ open_iface_live(const char *iface, pcap_t **pcap) {
 }
 
 static int
-open_single_iface(const char *iface, pcap_t **pcap)
+open_single_iface(const char *iface, osdep_pcap **pcap)
 {
 	if (open_iface_live(iface, pcap) < 0) {
 		PMD_LOG(ERR, "Couldn't open interface %s", iface);
@@ -470,39 +470,39 @@ open_single_iface(const char *iface, pcap_t **pcap)
 }
 
 static int
-open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper)
+open_single_tx_pcap(const char *pcap_filename, osdep_pcap_dumper **dumper)
 {
-	pcap_t *tx_pcap;
+	osdep_pcap *tx_pcap;
 
 	/*
-	 * We need to create a dummy empty pcap_t to use it
-	 * with pcap_dump_open(). We create big enough an Ethernet
+	 * We need to create a dummy empty osdep_pcap to use it
+	 * with osdep_pcap_dump_open(). We create big enough an Ethernet
 	 * pcap holder.
 	 */
-	tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
-			RTE_ETH_PCAP_SNAPSHOT_LEN, PCAP_TSTAMP_PRECISION_NANO);
+	tx_pcap = osdep_pcap_open_dead_with_tstamp_precision(OSDEP_DLT_EN10MB,
+		RTE_ETH_PCAP_SNAPSHOT_LEN, OSDEP_PCAP_TSTAMP_PRECISION_NANO);
 	if (tx_pcap == NULL) {
 		PMD_LOG(ERR, "Couldn't create dead pcap");
 		return -1;
 	}
 
-	/* The dumper is created using the previous pcap_t reference */
-	*dumper = pcap_dump_open(tx_pcap, pcap_filename);
+	/* The dumper is created using the previous osdep_pcap reference */
+	*dumper = osdep_pcap_dump_open(tx_pcap, pcap_filename);
 	if (*dumper == NULL) {
-		pcap_close(tx_pcap);
+		osdep_pcap_close(tx_pcap);
 		PMD_LOG(ERR, "Couldn't open %s for writing.",
 			pcap_filename);
 		return -1;
 	}
 
-	pcap_close(tx_pcap);
+	osdep_pcap_close(tx_pcap);
 	return 0;
 }
 
 static int
-open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
+open_single_rx_pcap(const char *pcap_filename, osdep_pcap **pcap)
 {
-	*pcap = pcap_open_offline(pcap_filename, errbuf);
+	*pcap = osdep_pcap_open_offline(pcap_filename, errbuf);
 	if (*pcap == NULL) {
 		PMD_LOG(ERR, "Couldn't open %s: %s", pcap_filename,
 			errbuf);
@@ -513,17 +513,17 @@ open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
 }
 
 static uint64_t
-count_packets_in_pcap(pcap_t **pcap, struct pcap_rx_queue *pcap_q)
+count_packets_in_pcap(osdep_pcap **pcap, struct pcap_rx_queue *pcap_q)
 {
-	const u_char *packet;
-	struct pcap_pkthdr header;
+	const uint8_t *packet;
+	struct osdep_pcap_pkthdr header;
 	uint64_t pcap_pkt_count = 0;
 
-	while ((packet = pcap_next(*pcap, &header)))
+	while ((packet = osdep_pcap_next(*pcap, &header)))
 		pcap_pkt_count++;
 
 	/* The pcap is reopened so it can be used as normal later. */
-	pcap_close(*pcap);
+	osdep_pcap_close(*pcap);
 	*pcap = NULL;
 	open_single_rx_pcap(pcap_q->name, pcap);
 
@@ -612,7 +612,7 @@ eth_dev_stop(struct rte_eth_dev *dev)
 
 	/* Special iface case. Single pcap is open and shared between tx/rx. */
 	if (internals->single_iface) {
-		pcap_close(pp->tx_pcap[0]);
+		osdep_pcap_close(pp->tx_pcap[0]);
 		pp->tx_pcap[0] = NULL;
 		pp->rx_pcap[0] = NULL;
 		goto status_down;
@@ -620,19 +620,19 @@ eth_dev_stop(struct rte_eth_dev *dev)
 
 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
 		if (pp->tx_dumper[i] != NULL) {
-			pcap_dump_close(pp->tx_dumper[i]);
+			osdep_pcap_dump_close(pp->tx_dumper[i]);
 			pp->tx_dumper[i] = NULL;
 		}
 
 		if (pp->tx_pcap[i] != NULL) {
-			pcap_close(pp->tx_pcap[i]);
+			osdep_pcap_close(pp->tx_pcap[i]);
 			pp->tx_pcap[i] = NULL;
 		}
 	}
 
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
 		if (pp->rx_pcap[i] != NULL) {
-			pcap_close(pp->rx_pcap[i]);
+			osdep_pcap_close(pp->rx_pcap[i]);
 			pp->rx_pcap[i] = NULL;
 		}
 	}
@@ -804,11 +804,11 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 	if (internals->infinite_rx) {
 		struct pmd_process_private *pp;
-		char ring_name[NAME_MAX];
+		char ring_name[RTE_RING_NAMESIZE];
 		static uint32_t ring_number;
 		uint64_t pcap_pkt_count = 0;
 		struct rte_mbuf *bufs[1];
-		pcap_t **pcap;
+		osdep_pcap **pcap;
 
 		pp = rte_eth_devices[pcap_q->port_id].process_private;
 		pcap = &pp->rx_pcap[pcap_q->queue_id];
@@ -932,7 +932,7 @@ static const struct eth_dev_ops ops = {
 
 static int
 add_queue(struct pmd_devargs *pmd, const char *name, const char *type,
-		pcap_t *pcap, pcap_dumper_t *dumper)
+		osdep_pcap *pcap, osdep_pcap_dumper *dumper)
 {
 	if (pmd->num_of_queue >= RTE_PMD_PCAP_MAX_QUEUES)
 		return -1;
@@ -955,13 +955,13 @@ open_rx_pcap(const char *key, const char *value, void *extra_args)
 {
 	const char *pcap_filename = value;
 	struct pmd_devargs *rx = extra_args;
-	pcap_t *pcap = NULL;
+	osdep_pcap *pcap = NULL;
 
 	if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
 		return -1;
 
 	if (add_queue(rx, pcap_filename, key, pcap, NULL) < 0) {
-		pcap_close(pcap);
+		osdep_pcap_close(pcap);
 		return -1;
 	}
 
@@ -977,13 +977,13 @@ open_tx_pcap(const char *key, const char *value, void *extra_args)
 {
 	const char *pcap_filename = value;
 	struct pmd_devargs *dumpers = extra_args;
-	pcap_dumper_t *dumper;
+	osdep_pcap_dumper *dumper;
 
 	if (open_single_tx_pcap(pcap_filename, &dumper) < 0)
 		return -1;
 
 	if (add_queue(dumpers, pcap_filename, key, NULL, dumper) < 0) {
-		pcap_dump_close(dumper);
+		osdep_pcap_dump_close(dumper);
 		return -1;
 	}
 
@@ -998,7 +998,7 @@ open_rx_tx_iface(const char *key, const char *value, void *extra_args)
 {
 	const char *iface = value;
 	struct pmd_devargs *tx = extra_args;
-	pcap_t *pcap = NULL;
+	osdep_pcap *pcap = NULL;
 
 	if (open_single_iface(iface, &pcap) < 0)
 		return -1;
@@ -1011,13 +1011,14 @@ open_rx_tx_iface(const char *key, const char *value, void *extra_args)
 }
 
 static inline int
-set_iface_direction(const char *iface, pcap_t *pcap,
-		pcap_direction_t direction)
+set_iface_direction(const char *iface, osdep_pcap *pcap,
+		enum osdep_pcap_direction direction)
 {
-	const char *direction_str = (direction == PCAP_D_IN) ? "IN" : "OUT";
-	if (pcap_setdirection(pcap, direction) < 0) {
+	const char *direction_str =
+		(direction == OSDEP_PCAP_D_IN) ? "IN" : "OUT";
+	if (osdep_pcap_setdirection(pcap, direction) < 0) {
 		PMD_LOG(ERR, "Setting %s pcap direction %s failed - %s\n",
-				iface, direction_str, pcap_geterr(pcap));
+				iface, direction_str, osdep_pcap_geterr(pcap));
 		return -1;
 	}
 	PMD_LOG(INFO, "Setting %s pcap direction %s\n",
@@ -1030,12 +1031,12 @@ open_iface(const char *key, const char *value, void *extra_args)
 {
 	const char *iface = value;
 	struct pmd_devargs *pmd = extra_args;
-	pcap_t *pcap = NULL;
+	osdep_pcap *pcap = NULL;
 
 	if (open_single_iface(iface, &pcap) < 0)
 		return -1;
 	if (add_queue(pmd, iface, key, pcap, NULL) < 0) {
-		pcap_close(pcap);
+		osdep_pcap_close(pcap);
 		return -1;
 	}
 
@@ -1057,7 +1058,7 @@ open_rx_iface(const char *key, const char *value, void *extra_args)
 
 		set_iface_direction(pmd->queue[qid].name,
 				pmd->queue[qid].pcap,
-				PCAP_D_IN);
+				OSDEP_PCAP_D_IN);
 	}
 
 	return 0;
@@ -1311,7 +1312,7 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
 	name = rte_vdev_device_name(dev);
 	PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
 
-	gettimeofday(&start_time, NULL);
+	rte_time_get_us(&start_time);
 	start_cycles = rte_get_timer_cycles();
 	hz = rte_get_timer_hz();
 
diff --git a/drivers/net/pcap/pcap_osdep.c b/drivers/net/pcap/pcap_osdep.c
new file mode 100644
index 000000000..5cac9bb89
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.c
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <pcap.h>
+
+#include <rte_common.h>
+
+#include "pcap_osdep.h"
+
+static inline void
+to_osdep_header(const struct pcap_pkthdr *in, struct osdep_pcap_pkthdr *out)
+{
+	out->ts.sec = in->ts.tv_sec;
+	out->ts.usec = in->ts.tv_usec;
+	out->caplen = in->caplen;
+	out->len = in->len;
+}
+
+static inline void
+to_pcap_header(const struct osdep_pcap_pkthdr *in, struct pcap_pkthdr *out)
+{
+	out->ts.tv_sec = in->ts.sec;
+	out->ts.tv_usec = in->ts.usec;
+	out->caplen = in->caplen;
+	out->len = in->len;
+}
+
+osdep_pcap *
+osdep_pcap_open_live(const char *device, int snaplen,
+	int promisc, int to_ms, char *errbuf)
+{
+	RTE_BUILD_BUG_ON(OSDEP_PCAP_ERRBUF_SIZE != PCAP_ERRBUF_SIZE);
+
+	return (osdep_pcap *)pcap_open_live(device, snaplen, promisc, to_ms,
+		errbuf);
+}
+
+osdep_pcap *
+osdep_pcap_open_offline(const char *fname, char *errbuf)
+{
+	return (osdep_pcap *)pcap_open_offline(fname, errbuf);
+}
+
+osdep_pcap *
+osdep_pcap_open_dead_with_tstamp_precision(int linktype, int snaplen,
+	unsigned int precision)
+{
+	RTE_BUILD_BUG_ON(OSDEP_DLT_EN10MB != DLT_EN10MB);
+	RTE_BUILD_BUG_ON(OSDEP_PCAP_TSTAMP_PRECISION_NANO !=
+			PCAP_TSTAMP_PRECISION_NANO);
+
+	return (osdep_pcap *)pcap_open_dead_with_tstamp_precision(linktype,
+		snaplen, precision);
+}
+
+const uint8_t *
+osdep_pcap_next(osdep_pcap *pcap, struct osdep_pcap_pkthdr *header)
+{
+	const uint8_t *data;
+	struct pcap_pkthdr pkthdr;
+
+	data = pcap_next((pcap_t *)pcap, &pkthdr);
+	to_osdep_header(&pkthdr, header);
+	return data;
+}
+
+int
+osdep_pcap_sendpacket(osdep_pcap *pcap, const uint8_t *buf, int size)
+{
+	return pcap_sendpacket((pcap_t *)pcap, buf, size);
+}
+
+void
+osdep_pcap_close(osdep_pcap *pcap)
+{
+	pcap_close((pcap_t *)pcap);
+}
+
+osdep_pcap_dumper *
+osdep_pcap_dump_open(osdep_pcap *pcap, const char *fname)
+{
+	return (osdep_pcap_dumper *)pcap_dump_open((pcap_t *)pcap, fname);
+}
+
+void
+osdep_pcap_dump(uint8_t *user, const struct osdep_pcap_pkthdr *header,
+	const uint8_t *sp)
+{
+	struct pcap_pkthdr pkthdr;
+
+	to_pcap_header(header, &pkthdr);
+	pcap_dump(user, &pkthdr, sp);
+}
+
+int
+osdep_pcap_dump_flush(osdep_pcap_dumper *p)
+{
+	return pcap_dump_flush((pcap_dumper_t *)p);
+}
+
+void
+osdep_pcap_dump_close(osdep_pcap_dumper *p)
+{
+	pcap_dump_close((pcap_dumper_t *)p);
+}
+
+int
+osdep_pcap_setdirection(osdep_pcap *pcap, enum osdep_pcap_direction dir)
+{
+	RTE_BUILD_BUG_ON((int)OSDEP_PCAP_D_INOUT != (int)PCAP_D_INOUT);
+	RTE_BUILD_BUG_ON((int)OSDEP_PCAP_D_IN != (int)PCAP_D_IN);
+	RTE_BUILD_BUG_ON((int)OSDEP_PCAP_D_OUT != (int)PCAP_D_OUT);
+
+	return pcap_setdirection((pcap_t *)pcap, (pcap_direction_t)dir);
+}
+
+const char *
+osdep_pcap_geterr(osdep_pcap *pcap)
+{
+	return pcap_geterr((pcap_t *)pcap);
+}
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index 46810d86f..bd00b728a 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -6,6 +6,7 @@
 #define _RTE_PCAP_OSDEP_
 
 #include <rte_ether.h>
+#include <rte_time.h>
 
 /*
  * Interface manipulation is always OS-specific.
@@ -14,4 +15,53 @@
 int osdep_iface_index_get(const char *name);
 int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
 
+/*
+ * On Windows, libpcap (npcap or WinPcap) exposes Win32 API which clashes
+ * with some DPDK constructs. Trivial libpcap wrappers with "osdep_" prefix
+ * are provided to isolate PMD code from Win32 API.
+ */
+
+#define OSDEP_DLT_EN10MB 1
+
+#define OSDEP_PCAP_ERRBUF_SIZE 256
+
+#define OSDEP_PCAP_TSTAMP_PRECISION_NANO 1
+
+/** Handle for an open packet capture. */
+typedef struct osdep_pcap_type osdep_pcap;
+
+/** Handle for an open packet dump. */
+typedef struct osdep_pcap_dumper_type osdep_pcap_dumper;
+
+struct osdep_pcap_pkthdr {
+	struct rte_time_us ts;
+	uint32_t caplen;
+	uint32_t len;
+};
+
+enum osdep_pcap_direction {
+	OSDEP_PCAP_D_INOUT = 0,
+	OSDEP_PCAP_D_IN,
+	OSDEP_PCAP_D_OUT
+};
+
+osdep_pcap *osdep_pcap_open_live(const char *device, int snaplen,
+	int promisc, int to_ms, char *errbuf);
+osdep_pcap *osdep_pcap_open_offline(const char *fname, char *errbuf);
+osdep_pcap *osdep_pcap_open_dead_with_tstamp_precision(int linktype,
+	int snaplen, unsigned int precision);
+const uint8_t *osdep_pcap_next(osdep_pcap *pcap,
+	struct osdep_pcap_pkthdr *header);
+int osdep_pcap_sendpacket(osdep_pcap *pcap, const uint8_t *buf, int size);
+void osdep_pcap_close(osdep_pcap *pcap);
+
+osdep_pcap_dumper *osdep_pcap_dump_open(osdep_pcap *pcap, const char *fname);
+void osdep_pcap_dump(uint8_t *user, const struct osdep_pcap_pkthdr *header,
+	const uint8_t *sp);
+int osdep_pcap_dump_flush(osdep_pcap_dumper *p);
+void osdep_pcap_dump_close(osdep_pcap_dumper *p);
+
+int osdep_pcap_setdirection(osdep_pcap *pcap, enum osdep_pcap_direction dir);
+const char *osdep_pcap_geterr(osdep_pcap *pcap);
+
 #endif
-- 
2.29.2

[dpdk-dev] [PATCH 5/6] config: discover libpcap on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:21:08

WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 config/meson.build | 21 ++++++++++++++++++---
 meson_options.txt  |  6 ++++--
 2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/config/meson.build b/config/meson.build
index 3cf560b8a..6aae8276c 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -178,9 +178,24 @@ if not pcap_dep.found()
 	# pcap got a pkg-config file only in 1.9.0
 	pcap_dep = cc.find_library('pcap', required: false)
 endif
-if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
-	dpdk_conf.set('RTE_PORT_PCAP', 1)
-	dpdk_extra_ldflags += '-lpcap'
+if is_windows
+	# npcap SDK can be installed anywhere
+	pcap_sdk = get_option('pcap_sdk')
+	if pcap_sdk != ''
+		pcap_ldflags = ['-L@0@/Lib/x64'.format(pcap_sdk), '-lwpcap']
+		pcap_dep = declare_dependency(
+			compile_args: ['-I@0@/Include'.format(pcap_sdk)],
+			link_args: pcap_ldflags)
+	endif
+	if pcap_dep.found()
+		dpdk_conf.set('RTE_PORT_PCAP', 1)
+		dpdk_extra_ldflags += pcap_ldflags
+	endif
+else
+	if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
+		dpdk_conf.set('RTE_PORT_PCAP', 1)
+		dpdk_extra_ldflags += '-lpcap'
+	endif
 endif
 
 # for clang 32-bit compiles we need libatomic for 64-bit atomic ops
diff --git a/meson_options.txt b/meson_options.txt
index 6eff62e47..d74146d3a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -10,6 +10,8 @@ option('enable_docs', type: 'boolean', value: false,
 	description: 'build documentation')
 option('enable_kmods', type: 'boolean', value: false,
 	description: 'build kernel modules')
+option('enable_trace_fp', type: 'boolean', value: false,
+	description: 'enable fast path trace points.')
 option('examples', type: 'string', value: '',
 	description: 'Comma-separated list of examples to build by default')
 option('flexran_sdk', type: 'string', value: '',
@@ -28,8 +30,8 @@ option('max_lcores', type: 'integer', value: 128,
 	description: 'maximum number of cores/threads supported by EAL')
 option('max_numa_nodes', type: 'integer', value: 32,
 	description: 'maximum number of NUMA nodes supported by EAL')
-option('enable_trace_fp', type: 'boolean', value: false,
-	description: 'enable fast path trace points.')
+option('pcap_sdk', type: 'string', value: '',
+	description: 'Path to libpcap SDK used on Windows')
 option('tests', type: 'boolean', value: true,
 	description: 'build unit tests')
 option('use_hpet', type: 'boolean', value: false,
-- 
2.29.2

[dpdk-dev] [PATCH 6/6] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 01:21:16

Implement OS-dependent functions and enable PMD build on Windows.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/meson.build          |  11 ++-
 drivers/net/pcap/pcap_ethdev.c        |   4 -
 drivers/net/pcap/pcap_osdep.h         |   5 ++
 drivers/net/pcap/pcap_osdep_windows.c | 118 ++++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 10 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 9ab95ec3e..614a4e340 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -1,19 +1,18 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-if is_windows
-	build = false
-	reason = 'not supported on Windows'
-	subdir_done()
-endif
-
 if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
+
 sources = files(
 	'pcap_ethdev.c',
 	'pcap_osdep.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
+
 ext_deps += pcap_dep
+if is_windows
+	ext_deps += cc.find_library('iphlpapi', required: true)
+endif
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 6461213e0..142533c6e 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -127,10 +127,6 @@ static struct rte_eth_link pmd_link = {
 
 RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
-#define PMD_LOG(level, fmt, args...) \
-	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
-		"%s(): " fmt "\n", __func__, ##args)
-
 static int
 eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
 		const uint8_t *data, uint16_t data_len)
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index bd00b728a..f7c311ef8 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -8,6 +8,11 @@
 #include <rte_ether.h>
 #include <rte_time.h>
 
+#define PMD_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
+		"%s(): " fmt "\n", __func__, ##args)
+extern int eth_pcap_logtype;
+
 /*
  * Interface manipulation is always OS-specific.
  */
diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c
new file mode 100644
index 000000000..d6557ff73
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_windows.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <strsafe.h>
+
+#include "pcap_osdep.h"
+
+/*
+ * Given a device name like "\Device\NPF_{GUID}" extract the "{GUID}" part.
+ * Return NULL if "{GUID}" part is not found.
+ */
+static const char *
+iface_guid(const char *name)
+{
+	static const size_t GUID_LENGTH = 32 + 4; /* 16 hex bytes + 4 dashes */
+
+	const char *ob, *cb;
+
+	ob = strchr(name, '{');
+	if (ob == NULL)
+		return NULL;
+
+	cb = strchr(ob, '}');
+	if (cb == NULL || cb - ob != GUID_LENGTH + 1) /* + 1 opening '{' */
+		return NULL;
+
+	return ob;
+}
+
+/*
+ * libpcap takes device names like "\Device\NPF_{GUID}",
+ * GetAdapterIndex() takes interface names like "\DEVICE\TCPIP_{GUID}".
+ * Try to convert, fall back to original device name.
+ */
+int
+osdep_iface_index_get(const char *device_name)
+{
+	WCHAR adapter_name[MAX_ADAPTER_NAME_LENGTH];
+	const char *guid;
+	ULONG index;
+	DWORD ret;
+
+	guid = iface_guid(device_name);
+	if (guid != NULL)
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"\\DEVICE\\TCPIP_%s", guid);
+	else
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"%s", device_name);
+
+	ret = GetAdapterIndex(adapter_name, &index);
+	if (ret != NO_ERROR) {
+		PMD_LOG(ERR, "GetAdapterIndex() = %lu\n", ret);
+		return -1;
+	}
+
+	return index;
+}
+
+/*
+ * 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;
+	ULONG size, sys_ret;
+	const char *adapter_name;
+	int ret = -1;
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+	if (sys_ret != ERROR_BUFFER_OVERFLOW) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n",
+			sys_ret, ERROR_BUFFER_OVERFLOW);
+		return -1;
+	}
+
+	info = (IP_ADAPTER_ADDRESSES *)malloc(size);
+	if (info == NULL) {
+		PMD_LOG(ERR, "Cannot allocate adapter address info\n");
+		return -1;
+	}
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size);
+	if (sys_ret != ERROR_SUCCESS) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret);
+		free(info);
+		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) {
+			if (cur->PhysicalAddressLength != RTE_ETHER_ADDR_LEN) {
+				PMD_LOG(ERR, "Physical address length: want %u, got %lu",
+					RTE_ETHER_ADDR_LEN,
+					cur->PhysicalAddressLength);
+				return -1;
+			}
+
+			memcpy(mac->addr_bytes, cur->PhysicalAddress,
+				RTE_ETHER_ADDR_LEN);
+			ret = 0;
+			break;
+		}
+	}
+
+	free(info);
+	return ret;
+}
-- 
2.29.2

[dpdk-dev] [PATCH v2 0/6] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:16:29

Most modern and actively maintained distribution of libpcap for Windows is Npcap
(https://nmap.org/npcap). It is free (as in "free beer") and open-source, but
Npcap redistribution with commercial products may be limited by its license.

Npcap can be installed anywhere, so a new Meson option is provided to find it:

    meson -Dpcap_sdk=C:\Npcap -Dexamples=skeleton build

Example of collecting packets from an interface to a file:

    .\build\examples\dpdk-skeleton.exe `
        --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
        --vdev "eth_pcap1,tx_pcap=capture.pcap"

Implementation in "pcap_osdep_windows.c" does some guesswork to convert
between variants of an interface name. Microsoft experts and interested
users, please take a look and/or give it a try in your environment.

There are no release notes for 21.05 yet, will send update after they appear.

v2: fix microsecond calculation on Windows in patch 1/6.

Dmitry Kozlyuk (6):
  eal: add internal API for current time
  net/pcap: fix format string
  net/pcap: move OS-dependent code to separate files
  net/pcap: add libpcap wrappers
  config: discover libpcap on Windows
  net/pcap: build on Windows

 config/meson.build                            |  21 +-
 drivers/net/pcap/meson.build                  |  17 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 251 ++++++------------
 drivers/net/pcap/pcap_osdep.c                 | 122 +++++++++
 drivers/net/pcap/pcap_osdep.h                 |  72 +++++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 ++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++
 drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++
 lib/librte_eal/include/rte_time.h             |  17 ++
 lib/librte_eal/rte_eal_exports.def            |   1 +
 lib/librte_eal/unix/eal_unix_timer.c          |  13 +
 lib/librte_eal/version.map                    |   1 +
 lib/librte_eal/windows/eal_timer.c            |  21 +-
 meson_options.txt                             |   6 +-
 14 files changed, 585 insertions(+), 176 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (88%)
 create mode 100644 drivers/net/pcap/pcap_osdep.c
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

-- 
2.29.2

[dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:16:34

Many PMDs use POSIX gettimeofday(). Add rte_time_get_us() function
to obtain current time with microsecond precision on all platforms.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 lib/librte_eal/include/rte_time.h    | 17 +++++++++++++++++
 lib/librte_eal/rte_eal_exports.def   |  1 +
 lib/librte_eal/unix/eal_unix_timer.c | 13 +++++++++++++
 lib/librte_eal/version.map           |  1 +
 lib/librte_eal/windows/eal_timer.c   | 21 ++++++++++++++++++++-
 5 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/lib/librte_eal/include/rte_time.h b/lib/librte_eal/include/rte_time.h
index 5ad7c8841..50fa4f889 100644
--- a/lib/librte_eal/include/rte_time.h
+++ b/lib/librte_eal/include/rte_time.h
@@ -8,6 +8,8 @@
 #include <stdint.h>
 #include <time.h>
 
+#include <rte_compat.h>
+
 #define NSEC_PER_SEC             1000000000L
 
 /**
@@ -98,4 +100,19 @@ rte_ns_to_timespec(uint64_t nsec)
 	return ts;
 }
 
+/* Point of time with microsecond precision. */
+struct rte_time_us {
+	int64_t sec;  /**< Number of whole seconds. */
+	int64_t usec; /**< Fractional part of second in [0, 999999]. */
+};
+
+/**
+ * Get current system time.
+ *
+ * @param now
+ *  Receives current system time.
+ */
+__rte_internal
+void rte_time_get_us(struct rte_time_us *now);
+
 #endif /* _RTE_TIME_H_ */
diff --git a/lib/librte_eal/rte_eal_exports.def b/lib/librte_eal/rte_eal_exports.def
index 474cf123f..cb691f7bc 100644
--- a/lib/librte_eal/rte_eal_exports.def
+++ b/lib/librte_eal/rte_eal_exports.def
@@ -334,3 +334,4 @@ EXPORTS
 	rte_mem_map
 	rte_mem_page_size
 	rte_mem_unmap
+	rte_time_get_us
diff --git a/lib/librte_eal/unix/eal_unix_timer.c b/lib/librte_eal/unix/eal_unix_timer.c
index cc5015910..5612fdebe 100644
--- a/lib/librte_eal/unix/eal_unix_timer.c
+++ b/lib/librte_eal/unix/eal_unix_timer.c
@@ -4,7 +4,10 @@
 
 #include <time.h>
 
+#include <sys/time.h>
+
 #include <rte_cycles.h>
+#include <rte_time.h>
 
 void
 rte_delay_us_sleep(unsigned int us)
@@ -27,3 +30,13 @@ rte_delay_us_sleep(unsigned int us)
 		ind = 1 - ind;
 	}
 }
+
+void
+rte_time_get_us(struct rte_time_us *now)
+{
+	struct timeval sys;
+
+	gettimeofday(&sys, NULL);
+	now->sec = sys.tv_sec;
+	now->usec = sys.tv_usec;
+}
diff --git a/lib/librte_eal/version.map b/lib/librte_eal/version.map
index fce90a112..405bed766 100644
--- a/lib/librte_eal/version.map
+++ b/lib/librte_eal/version.map
@@ -421,4 +421,5 @@ INTERNAL {
 	rte_mem_map;
 	rte_mem_page_size;
 	rte_mem_unmap;
+	rte_time_get_us;
 };
diff --git a/lib/librte_eal/windows/eal_timer.c b/lib/librte_eal/windows/eal_timer.c
index b070cb775..a5c42106a 100644
--- a/lib/librte_eal/windows/eal_timer.c
+++ b/lib/librte_eal/windows/eal_timer.c
@@ -9,6 +9,7 @@
 #include <rte_cycles.h>
 #include <rte_eal.h>
 #include <rte_errno.h>
+#include <rte_time.h>
 #include "eal_private.h"
 
 #define US_PER_SEC 1E6
@@ -85,10 +86,28 @@ get_tsc_freq(void)
 	return RTE_ALIGN_MUL_NEAR(tsc_hz, CYC_PER_10MHZ);
 }
 
-
 int
 rte_eal_timer_init(void)
 {
 	set_tsc_freq();
 	return 0;
 }
+
+void
+rte_time_get_us(struct rte_time_us *now)
+{
+	/* 100ns ticks from 1601-01-01 to 1970-01-01 */
+	static const uint64_t EPOCH = 116444736000000000ULL;
+	static const uint64_t TICKS_PER_USEC = 10;
+	static const uint64_t USEC_PER_SEC = 1000000;
+
+	FILETIME ft;
+	uint64_t ticks, sec;
+
+	GetSystemTimePreciseAsFileTime(&ft);
+	ticks = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+	ticks -= EPOCH;
+	sec = ticks / (TICKS_PER_USEC * USEC_PER_SEC);
+	now->sec = sec;
+	now->usec = ticks / TICKS_PER_USEC - sec * USEC_PER_SEC;
+}
-- 
2.29.2

[dpdk-dev] [PATCH v2 2/6] net/pcap: fix format string

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:16:42

Use PRIu32 for uint32_t (found by -Wformat with Clang on Windows).

Fixes: a3f5252e5cbd ("net/pcap: enable infinitely Rx a pcap file")
Cc: stable@dpdk.org

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/rte_eth_pcap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c
index 90f5d75ea..176928da3 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/rte_eth_pcap.c
@@ -827,7 +827,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 		pcap_pkt_count = count_packets_in_pcap(pcap, pcap_q);
 
-		snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu16,
+		snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu32,
 				ring_number);
 
 		pcap_q->pkts = rte_ring_create(ring_name,
-- 
2.29.2

[dpdk-dev] [PATCH v2 3/6] net/pcap: move OS-dependent code to separate files

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:16:53

PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. In preparation to add
Windows-specific part and libpcap wrapper, extract OS-independent
interface and move implementations to separate files. Rename
rte_eth_pcap.c to pcap_ethdev.c for consistency with the rest of DPDK.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/meson.build                  |  5 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 88 ++-----------------
 drivers/net/pcap/pcap_osdep.h                 | 17 ++++
 drivers/net/pcap/pcap_osdep_freebsd.c         | 59 +++++++++++++
 drivers/net/pcap/pcap_osdep_linux.c           | 42 +++++++++
 5 files changed, 130 insertions(+), 81 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index b65d91e70..26b606699 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -11,5 +11,8 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
-sources = files('rte_eth_pcap.c')
+sources = files(
+	'pcap_ethdev.c',
+	'pcap_osdep_@0@.c'.format(exec_env),
+)
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/pcap_ethdev.c
similarity index 95%
rename from drivers/net/pcap/rte_eth_pcap.c
rename to drivers/net/pcap/pcap_ethdev.c
index 176928da3..a102897e9 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -6,16 +6,6 @@
 
 #include <time.h>
 
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#if defined(RTE_EXEC_ENV_FREEBSD)
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#endif
-
 #include <pcap.h>
 
 #include <rte_cycles.h>
@@ -25,7 +15,8 @@
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_bus_vdev.h>
-#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
 
 #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
 #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
@@ -1191,84 +1182,20 @@ static int
 eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
 		const unsigned int numa_node)
 {
-#if defined(RTE_EXEC_ENV_LINUX)
 	void *mac_addrs;
-	struct ifreq ifr;
-	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-	if (if_fd == -1)
-		return -1;
+	struct rte_ether_addr mac;
 
-	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
-	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
-		close(if_fd);
+	if (osdep_iface_mac_get(if_name, &mac) < 0)
 		return -1;
-	}
 
 	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		close(if_fd);
+	if (mac_addrs == NULL)
 		return -1;
-	}
 
 	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
+	rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
 	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
-
-	close(if_fd);
-
-	return 0;
-
-#elif defined(RTE_EXEC_ENV_FREEBSD)
-	void *mac_addrs;
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	int mib[6];
-	size_t len = 0;
-	char *buf;
-
-	mib[0] = CTL_NET;
-	mib[1] = AF_ROUTE;
-	mib[2] = 0;
-	mib[3] = AF_LINK;
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = if_nametoindex(if_name);
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-
-	if (len == 0)
-		return -1;
-
-	buf = rte_malloc(NULL, len, 0);
-	if (!buf)
-		return -1;
-
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		rte_free(buf);
-		return -1;
-	}
-	ifm = (struct if_msghdr *)buf;
-	sdl = (struct sockaddr_dl *)(ifm + 1);
-
-	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		rte_free(buf);
-		return -1;
-	}
-
-	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
-	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			LLADDR(sdl), RTE_ETHER_ADDR_LEN);
-
-	rte_free(buf);
-
 	return 0;
-#else
-	return -1;
-#endif
 }
 
 static int
@@ -1330,7 +1257,8 @@ eth_from_pcaps(struct rte_vdev_device *vdev,
 	internals->single_iface = single_iface;
 
 	if (single_iface) {
-		internals->if_index = if_nametoindex(rx_queues->queue[0].name);
+		internals->if_index =
+			osdep_iface_index_get(rx_queues->queue[0].name);
 
 		/* phy_mac arg is applied only only if "iface" devarg is provided */
 		if (rx_queues->phy_mac) {
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
new file mode 100644
index 000000000..46810d86f
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#ifndef _RTE_PCAP_OSDEP_
+#define _RTE_PCAP_OSDEP_
+
+#include <rte_ether.h>
+
+/*
+ * Interface manipulation is always OS-specific.
+ */
+
+int osdep_iface_index_get(const char *name);
+int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
+
+#endif
diff --git a/drivers/net/pcap/pcap_osdep_freebsd.c b/drivers/net/pcap/pcap_osdep_freebsd.c
new file mode 100644
index 000000000..20556b3e9
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_freebsd.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/sysctl.h>
+
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	int mib[6];
+	size_t len = 0;
+	char *buf;
+
+	mib[0] = CTL_NET;
+	mib[1] = AF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_LINK;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = if_nametoindex(if_name);
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+
+	if (len == 0)
+		return -1;
+
+	buf = rte_malloc(NULL, len, 0);
+	if (!buf)
+		return -1;
+
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		rte_free(buf);
+		return -1;
+	}
+	ifm = (struct if_msghdr *)buf;
+	sdl = (struct sockaddr_dl *)(ifm + 1);
+
+	rte_memcpy(mac->addr_bytes, LLADDR(sdl), RTE_ETHER_ADDR_LEN);
+
+	rte_free(buf);
+	return 0;
+}
diff --git a/drivers/net/pcap/pcap_osdep_linux.c b/drivers/net/pcap/pcap_osdep_linux.c
new file mode 100644
index 000000000..97033f57c
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_linux.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <rte_memcpy.h>
+#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct ifreq ifr;
+	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (if_fd == -1)
+		return -1;
+
+	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
+		close(if_fd);
+		return -1;
+	}
+
+	rte_memcpy(mac->addr_bytes, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
+
+	close(if_fd);
+	return 0;
+}
-- 
2.29.2

[dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:17:02

libpcap headers can expose OS headers. On Windows, system networking
headers are incompatible with DPDK ones, causing multiple name clashes.
API of libpcap itself involves a non-standard u_char type.

Add a limited set of trivial libpcap wrappers, so that libpcap headers
are not included directly by OS-independent PMD code. Use EAL types and
functions for time instead of POSIX ones.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/meson.build   |   1 +
 drivers/net/pcap/pcap_ethdev.c | 157 +++++++++++++++++----------------
 drivers/net/pcap/pcap_osdep.c  | 122 +++++++++++++++++++++++++
 drivers/net/pcap/pcap_osdep.h  |  50 +++++++++++
 4 files changed, 252 insertions(+), 78 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 26b606699..9ab95ec3e 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -13,6 +13,7 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
 endif
 sources = files(
 	'pcap_ethdev.c',
+	'pcap_osdep.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index a102897e9..6461213e0 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -4,17 +4,13 @@
  * All rights reserved.
  */
 
-#include <time.h>
-
-#include <pcap.h>
-
-#include <rte_cycles.h>
 #include <ethdev_driver.h>
 #include <ethdev_vdev.h>
+#include <rte_bus_vdev.h>
+#include <rte_cycles.h>
 #include <rte_kvargs.h>
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
-#include <rte_bus_vdev.h>
 
 #include "pcap_osdep.h"
 
@@ -36,8 +32,8 @@
 
 #define RTE_PMD_PCAP_MAX_QUEUES 16
 
-static char errbuf[PCAP_ERRBUF_SIZE];
-static struct timeval start_time;
+static char errbuf[OSDEP_PCAP_ERRBUF_SIZE];
+static struct rte_time_us start_time;
 static uint64_t start_cycles;
 static uint64_t hz;
 static uint8_t iface_idx;
@@ -83,16 +79,16 @@ struct pmd_internals {
 };
 
 struct pmd_process_private {
-	pcap_t *rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
-	pcap_t *tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
-	pcap_dumper_t *tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
+	osdep_pcap * rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
+	osdep_pcap * tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
+	osdep_pcap_dumper * tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
 };
 
 struct pmd_devargs {
 	unsigned int num_of_queue;
 	struct devargs_queue {
-		pcap_dumper_t *dumper;
-		pcap_t *pcap;
+		osdep_pcap_dumper *dumper;
+		osdep_pcap *pcap;
 		const char *name;
 		const char *type;
 	} queue[RTE_PMD_PCAP_MAX_QUEUES];
@@ -137,7 +133,7 @@ RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
 static int
 eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
-		const u_char *data, uint16_t data_len)
+		const uint8_t *data, uint16_t data_len)
 {
 	/* Copy the first segment. */
 	uint16_t len = rte_pktmbuf_tailroom(mbuf);
@@ -214,14 +210,14 @@ static uint16_t
 eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	unsigned int i;
-	struct pcap_pkthdr header;
+	struct osdep_pcap_pkthdr header;
 	struct pmd_process_private *pp;
-	const u_char *packet;
+	const uint8_t *packet;
 	struct rte_mbuf *mbuf;
 	struct pcap_rx_queue *pcap_q = queue;
 	uint16_t num_rx = 0;
 	uint32_t rx_bytes = 0;
-	pcap_t *pcap;
+	osdep_pcap *pcap;
 
 	pp = rte_eth_devices[pcap_q->port_id].process_private;
 	pcap = pp->rx_pcap[pcap_q->queue_id];
@@ -234,7 +230,7 @@ eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	 */
 	for (i = 0; i < nb_pkts; i++) {
 		/* Get the next PCAP packet */
-		packet = pcap_next(pcap, &header);
+		packet = osdep_pcap_next(pcap, &header);
 		if (unlikely(packet == NULL))
 			break;
 
@@ -261,8 +257,8 @@ eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		mbuf->pkt_len = (uint16_t)header.caplen;
 		*RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset,
 			rte_mbuf_timestamp_t *) =
-				(uint64_t)header.ts.tv_sec * 1000000 +
-				header.ts.tv_usec;
+				(uint64_t)header.ts.sec * 1000000 +
+				header.ts.usec;
 		mbuf->ol_flags |= timestamp_rx_dynflag;
 		mbuf->port = pcap_q->port_id;
 		bufs[num_rx] = mbuf;
@@ -285,20 +281,24 @@ eth_null_rx(void *queue __rte_unused,
 
 #define NSEC_PER_SEC	1000000000L
 
+/*
+ * This function stores nanoseconds in "usec" field of struct rte_time_us,
+ * because "ts" goes directly to nanosecond-precision dump.
+ */
 static inline void
-calculate_timestamp(struct timeval *ts) {
+calculate_timestamp(struct rte_time_us *ts) {
 	uint64_t cycles;
-	struct timeval cur_time;
+	struct rte_time_us cur_time;
 
 	cycles = rte_get_timer_cycles() - start_cycles;
-	cur_time.tv_sec = cycles / hz;
-	cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz;
-
-	ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
-	ts->tv_usec = start_time.tv_usec + cur_time.tv_usec;
-	if (ts->tv_usec >= NSEC_PER_SEC) {
-		ts->tv_usec -= NSEC_PER_SEC;
-		ts->tv_sec += 1;
+	cur_time.sec = cycles / hz;
+	cur_time.usec = (cycles % hz) * NSEC_PER_SEC / hz;
+
+	ts->sec = start_time.sec + cur_time.sec;
+	ts->usec = start_time.usec + cur_time.usec;
+	if (ts->usec >= NSEC_PER_SEC) {
+		ts->usec -= NSEC_PER_SEC;
+		ts->sec += 1;
 	}
 }
 
@@ -314,8 +314,8 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	struct pcap_tx_queue *dumper_q = queue;
 	uint16_t num_tx = 0;
 	uint32_t tx_bytes = 0;
-	struct pcap_pkthdr header;
-	pcap_dumper_t *dumper;
+	struct osdep_pcap_pkthdr header;
+	osdep_pcap_dumper *dumper;
 	unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
 	size_t len, caplen;
 
@@ -342,7 +342,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		 * in the mbuf (when the mbuf is contiguous) or, otherwise,
 		 * a pointer to temp_data after copying into it.
 		 */
-		pcap_dump((u_char *)dumper, &header,
+		osdep_pcap_dump((uint8_t *)dumper, &header,
 			rte_pktmbuf_read(mbuf, 0, caplen, temp_data));
 
 		num_tx++;
@@ -355,7 +355,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	 * process stops and to make sure the pcap file is actually written,
 	 * we flush the pcap dumper within each burst.
 	 */
-	pcap_dump_flush(dumper);
+	osdep_pcap_dump_flush(dumper);
 	dumper_q->tx_stat.pkts += num_tx;
 	dumper_q->tx_stat.bytes += tx_bytes;
 	dumper_q->tx_stat.err_pkts += nb_pkts - num_tx;
@@ -400,7 +400,7 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	struct pcap_tx_queue *tx_queue = queue;
 	uint16_t num_tx = 0;
 	uint32_t tx_bytes = 0;
-	pcap_t *pcap;
+	osdep_pcap *pcap;
 	unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
 	size_t len;
 
@@ -426,7 +426,7 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		 * in the mbuf (when the mbuf is contiguous) or, otherwise,
 		 * a pointer to temp_data after copying into it.
 		 */
-		ret = pcap_sendpacket(pcap,
+		ret = osdep_pcap_sendpacket(pcap,
 			rte_pktmbuf_read(mbuf, 0, len, temp_data), len);
 		if (unlikely(ret != 0))
 			break;
@@ -443,11 +443,11 @@ eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 }
 
 /*
- * pcap_open_live wrapper function
+ * osdep_pcap_open_live wrapper function
  */
 static inline int
-open_iface_live(const char *iface, pcap_t **pcap) {
-	*pcap = pcap_open_live(iface, RTE_ETH_PCAP_SNAPLEN,
+open_iface_live(const char *iface, osdep_pcap **pcap) {
+	*pcap = osdep_pcap_open_live(iface, RTE_ETH_PCAP_SNAPLEN,
 			RTE_ETH_PCAP_PROMISC, RTE_ETH_PCAP_TIMEOUT, errbuf);
 
 	if (*pcap == NULL) {
@@ -459,7 +459,7 @@ open_iface_live(const char *iface, pcap_t **pcap) {
 }
 
 static int
-open_single_iface(const char *iface, pcap_t **pcap)
+open_single_iface(const char *iface, osdep_pcap **pcap)
 {
 	if (open_iface_live(iface, pcap) < 0) {
 		PMD_LOG(ERR, "Couldn't open interface %s", iface);
@@ -470,39 +470,39 @@ open_single_iface(const char *iface, pcap_t **pcap)
 }
 
 static int
-open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper)
+open_single_tx_pcap(const char *pcap_filename, osdep_pcap_dumper **dumper)
 {
-	pcap_t *tx_pcap;
+	osdep_pcap *tx_pcap;
 
 	/*
-	 * We need to create a dummy empty pcap_t to use it
-	 * with pcap_dump_open(). We create big enough an Ethernet
+	 * We need to create a dummy empty osdep_pcap to use it
+	 * with osdep_pcap_dump_open(). We create big enough an Ethernet
 	 * pcap holder.
 	 */
-	tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
-			RTE_ETH_PCAP_SNAPSHOT_LEN, PCAP_TSTAMP_PRECISION_NANO);
+	tx_pcap = osdep_pcap_open_dead_with_tstamp_precision(OSDEP_DLT_EN10MB,
+		RTE_ETH_PCAP_SNAPSHOT_LEN, OSDEP_PCAP_TSTAMP_PRECISION_NANO);
 	if (tx_pcap == NULL) {
 		PMD_LOG(ERR, "Couldn't create dead pcap");
 		return -1;
 	}
 
-	/* The dumper is created using the previous pcap_t reference */
-	*dumper = pcap_dump_open(tx_pcap, pcap_filename);
+	/* The dumper is created using the previous osdep_pcap reference */
+	*dumper = osdep_pcap_dump_open(tx_pcap, pcap_filename);
 	if (*dumper == NULL) {
-		pcap_close(tx_pcap);
+		osdep_pcap_close(tx_pcap);
 		PMD_LOG(ERR, "Couldn't open %s for writing.",
 			pcap_filename);
 		return -1;
 	}
 
-	pcap_close(tx_pcap);
+	osdep_pcap_close(tx_pcap);
 	return 0;
 }
 
 static int
-open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
+open_single_rx_pcap(const char *pcap_filename, osdep_pcap **pcap)
 {
-	*pcap = pcap_open_offline(pcap_filename, errbuf);
+	*pcap = osdep_pcap_open_offline(pcap_filename, errbuf);
 	if (*pcap == NULL) {
 		PMD_LOG(ERR, "Couldn't open %s: %s", pcap_filename,
 			errbuf);
@@ -513,17 +513,17 @@ open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
 }
 
 static uint64_t
-count_packets_in_pcap(pcap_t **pcap, struct pcap_rx_queue *pcap_q)
+count_packets_in_pcap(osdep_pcap **pcap, struct pcap_rx_queue *pcap_q)
 {
-	const u_char *packet;
-	struct pcap_pkthdr header;
+	const uint8_t *packet;
+	struct osdep_pcap_pkthdr header;
 	uint64_t pcap_pkt_count = 0;
 
-	while ((packet = pcap_next(*pcap, &header)))
+	while ((packet = osdep_pcap_next(*pcap, &header)))
 		pcap_pkt_count++;
 
 	/* The pcap is reopened so it can be used as normal later. */
-	pcap_close(*pcap);
+	osdep_pcap_close(*pcap);
 	*pcap = NULL;
 	open_single_rx_pcap(pcap_q->name, pcap);
 
@@ -612,7 +612,7 @@ eth_dev_stop(struct rte_eth_dev *dev)
 
 	/* Special iface case. Single pcap is open and shared between tx/rx. */
 	if (internals->single_iface) {
-		pcap_close(pp->tx_pcap[0]);
+		osdep_pcap_close(pp->tx_pcap[0]);
 		pp->tx_pcap[0] = NULL;
 		pp->rx_pcap[0] = NULL;
 		goto status_down;
@@ -620,19 +620,19 @@ eth_dev_stop(struct rte_eth_dev *dev)
 
 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
 		if (pp->tx_dumper[i] != NULL) {
-			pcap_dump_close(pp->tx_dumper[i]);
+			osdep_pcap_dump_close(pp->tx_dumper[i]);
 			pp->tx_dumper[i] = NULL;
 		}
 
 		if (pp->tx_pcap[i] != NULL) {
-			pcap_close(pp->tx_pcap[i]);
+			osdep_pcap_close(pp->tx_pcap[i]);
 			pp->tx_pcap[i] = NULL;
 		}
 	}
 
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
 		if (pp->rx_pcap[i] != NULL) {
-			pcap_close(pp->rx_pcap[i]);
+			osdep_pcap_close(pp->rx_pcap[i]);
 			pp->rx_pcap[i] = NULL;
 		}
 	}
@@ -804,11 +804,11 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 	if (internals->infinite_rx) {
 		struct pmd_process_private *pp;
-		char ring_name[NAME_MAX];
+		char ring_name[RTE_RING_NAMESIZE];
 		static uint32_t ring_number;
 		uint64_t pcap_pkt_count = 0;
 		struct rte_mbuf *bufs[1];
-		pcap_t **pcap;
+		osdep_pcap **pcap;
 
 		pp = rte_eth_devices[pcap_q->port_id].process_private;
 		pcap = &pp->rx_pcap[pcap_q->queue_id];
@@ -932,7 +932,7 @@ static const struct eth_dev_ops ops = {
 
 static int
 add_queue(struct pmd_devargs *pmd, const char *name, const char *type,
-		pcap_t *pcap, pcap_dumper_t *dumper)
+		osdep_pcap *pcap, osdep_pcap_dumper *dumper)
 {
 	if (pmd->num_of_queue >= RTE_PMD_PCAP_MAX_QUEUES)
 		return -1;
@@ -955,13 +955,13 @@ open_rx_pcap(const char *key, const char *value, void *extra_args)
 {
 	const char *pcap_filename = value;
 	struct pmd_devargs *rx = extra_args;
-	pcap_t *pcap = NULL;
+	osdep_pcap *pcap = NULL;
 
 	if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
 		return -1;
 
 	if (add_queue(rx, pcap_filename, key, pcap, NULL) < 0) {
-		pcap_close(pcap);
+		osdep_pcap_close(pcap);
 		return -1;
 	}
 
@@ -977,13 +977,13 @@ open_tx_pcap(const char *key, const char *value, void *extra_args)
 {
 	const char *pcap_filename = value;
 	struct pmd_devargs *dumpers = extra_args;
-	pcap_dumper_t *dumper;
+	osdep_pcap_dumper *dumper;
 
 	if (open_single_tx_pcap(pcap_filename, &dumper) < 0)
 		return -1;
 
 	if (add_queue(dumpers, pcap_filename, key, NULL, dumper) < 0) {
-		pcap_dump_close(dumper);
+		osdep_pcap_dump_close(dumper);
 		return -1;
 	}
 
@@ -998,7 +998,7 @@ open_rx_tx_iface(const char *key, const char *value, void *extra_args)
 {
 	const char *iface = value;
 	struct pmd_devargs *tx = extra_args;
-	pcap_t *pcap = NULL;
+	osdep_pcap *pcap = NULL;
 
 	if (open_single_iface(iface, &pcap) < 0)
 		return -1;
@@ -1011,13 +1011,14 @@ open_rx_tx_iface(const char *key, const char *value, void *extra_args)
 }
 
 static inline int
-set_iface_direction(const char *iface, pcap_t *pcap,
-		pcap_direction_t direction)
+set_iface_direction(const char *iface, osdep_pcap *pcap,
+		enum osdep_pcap_direction direction)
 {
-	const char *direction_str = (direction == PCAP_D_IN) ? "IN" : "OUT";
-	if (pcap_setdirection(pcap, direction) < 0) {
+	const char *direction_str =
+		(direction == OSDEP_PCAP_D_IN) ? "IN" : "OUT";
+	if (osdep_pcap_setdirection(pcap, direction) < 0) {
 		PMD_LOG(ERR, "Setting %s pcap direction %s failed - %s\n",
-				iface, direction_str, pcap_geterr(pcap));
+				iface, direction_str, osdep_pcap_geterr(pcap));
 		return -1;
 	}
 	PMD_LOG(INFO, "Setting %s pcap direction %s\n",
@@ -1030,12 +1031,12 @@ open_iface(const char *key, const char *value, void *extra_args)
 {
 	const char *iface = value;
 	struct pmd_devargs *pmd = extra_args;
-	pcap_t *pcap = NULL;
+	osdep_pcap *pcap = NULL;
 
 	if (open_single_iface(iface, &pcap) < 0)
 		return -1;
 	if (add_queue(pmd, iface, key, pcap, NULL) < 0) {
-		pcap_close(pcap);
+		osdep_pcap_close(pcap);
 		return -1;
 	}
 
@@ -1057,7 +1058,7 @@ open_rx_iface(const char *key, const char *value, void *extra_args)
 
 		set_iface_direction(pmd->queue[qid].name,
 				pmd->queue[qid].pcap,
-				PCAP_D_IN);
+				OSDEP_PCAP_D_IN);
 	}
 
 	return 0;
@@ -1311,7 +1312,7 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
 	name = rte_vdev_device_name(dev);
 	PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
 
-	gettimeofday(&start_time, NULL);
+	rte_time_get_us(&start_time);
 	start_cycles = rte_get_timer_cycles();
 	hz = rte_get_timer_hz();
 
diff --git a/drivers/net/pcap/pcap_osdep.c b/drivers/net/pcap/pcap_osdep.c
new file mode 100644
index 000000000..5cac9bb89
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.c
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <pcap.h>
+
+#include <rte_common.h>
+
+#include "pcap_osdep.h"
+
+static inline void
+to_osdep_header(const struct pcap_pkthdr *in, struct osdep_pcap_pkthdr *out)
+{
+	out->ts.sec = in->ts.tv_sec;
+	out->ts.usec = in->ts.tv_usec;
+	out->caplen = in->caplen;
+	out->len = in->len;
+}
+
+static inline void
+to_pcap_header(const struct osdep_pcap_pkthdr *in, struct pcap_pkthdr *out)
+{
+	out->ts.tv_sec = in->ts.sec;
+	out->ts.tv_usec = in->ts.usec;
+	out->caplen = in->caplen;
+	out->len = in->len;
+}
+
+osdep_pcap *
+osdep_pcap_open_live(const char *device, int snaplen,
+	int promisc, int to_ms, char *errbuf)
+{
+	RTE_BUILD_BUG_ON(OSDEP_PCAP_ERRBUF_SIZE != PCAP_ERRBUF_SIZE);
+
+	return (osdep_pcap *)pcap_open_live(device, snaplen, promisc, to_ms,
+		errbuf);
+}
+
+osdep_pcap *
+osdep_pcap_open_offline(const char *fname, char *errbuf)
+{
+	return (osdep_pcap *)pcap_open_offline(fname, errbuf);
+}
+
+osdep_pcap *
+osdep_pcap_open_dead_with_tstamp_precision(int linktype, int snaplen,
+	unsigned int precision)
+{
+	RTE_BUILD_BUG_ON(OSDEP_DLT_EN10MB != DLT_EN10MB);
+	RTE_BUILD_BUG_ON(OSDEP_PCAP_TSTAMP_PRECISION_NANO !=
+			PCAP_TSTAMP_PRECISION_NANO);
+
+	return (osdep_pcap *)pcap_open_dead_with_tstamp_precision(linktype,
+		snaplen, precision);
+}
+
+const uint8_t *
+osdep_pcap_next(osdep_pcap *pcap, struct osdep_pcap_pkthdr *header)
+{
+	const uint8_t *data;
+	struct pcap_pkthdr pkthdr;
+
+	data = pcap_next((pcap_t *)pcap, &pkthdr);
+	to_osdep_header(&pkthdr, header);
+	return data;
+}
+
+int
+osdep_pcap_sendpacket(osdep_pcap *pcap, const uint8_t *buf, int size)
+{
+	return pcap_sendpacket((pcap_t *)pcap, buf, size);
+}
+
+void
+osdep_pcap_close(osdep_pcap *pcap)
+{
+	pcap_close((pcap_t *)pcap);
+}
+
+osdep_pcap_dumper *
+osdep_pcap_dump_open(osdep_pcap *pcap, const char *fname)
+{
+	return (osdep_pcap_dumper *)pcap_dump_open((pcap_t *)pcap, fname);
+}
+
+void
+osdep_pcap_dump(uint8_t *user, const struct osdep_pcap_pkthdr *header,
+	const uint8_t *sp)
+{
+	struct pcap_pkthdr pkthdr;
+
+	to_pcap_header(header, &pkthdr);
+	pcap_dump(user, &pkthdr, sp);
+}
+
+int
+osdep_pcap_dump_flush(osdep_pcap_dumper *p)
+{
+	return pcap_dump_flush((pcap_dumper_t *)p);
+}
+
+void
+osdep_pcap_dump_close(osdep_pcap_dumper *p)
+{
+	pcap_dump_close((pcap_dumper_t *)p);
+}
+
+int
+osdep_pcap_setdirection(osdep_pcap *pcap, enum osdep_pcap_direction dir)
+{
+	RTE_BUILD_BUG_ON((int)OSDEP_PCAP_D_INOUT != (int)PCAP_D_INOUT);
+	RTE_BUILD_BUG_ON((int)OSDEP_PCAP_D_IN != (int)PCAP_D_IN);
+	RTE_BUILD_BUG_ON((int)OSDEP_PCAP_D_OUT != (int)PCAP_D_OUT);
+
+	return pcap_setdirection((pcap_t *)pcap, (pcap_direction_t)dir);
+}
+
+const char *
+osdep_pcap_geterr(osdep_pcap *pcap)
+{
+	return pcap_geterr((pcap_t *)pcap);
+}
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index 46810d86f..bd00b728a 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -6,6 +6,7 @@
 #define _RTE_PCAP_OSDEP_
 
 #include <rte_ether.h>
+#include <rte_time.h>
 
 /*
  * Interface manipulation is always OS-specific.
@@ -14,4 +15,53 @@
 int osdep_iface_index_get(const char *name);
 int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
 
+/*
+ * On Windows, libpcap (npcap or WinPcap) exposes Win32 API which clashes
+ * with some DPDK constructs. Trivial libpcap wrappers with "osdep_" prefix
+ * are provided to isolate PMD code from Win32 API.
+ */
+
+#define OSDEP_DLT_EN10MB 1
+
+#define OSDEP_PCAP_ERRBUF_SIZE 256
+
+#define OSDEP_PCAP_TSTAMP_PRECISION_NANO 1
+
+/** Handle for an open packet capture. */
+typedef struct osdep_pcap_type osdep_pcap;
+
+/** Handle for an open packet dump. */
+typedef struct osdep_pcap_dumper_type osdep_pcap_dumper;
+
+struct osdep_pcap_pkthdr {
+	struct rte_time_us ts;
+	uint32_t caplen;
+	uint32_t len;
+};
+
+enum osdep_pcap_direction {
+	OSDEP_PCAP_D_INOUT = 0,
+	OSDEP_PCAP_D_IN,
+	OSDEP_PCAP_D_OUT
+};
+
+osdep_pcap *osdep_pcap_open_live(const char *device, int snaplen,
+	int promisc, int to_ms, char *errbuf);
+osdep_pcap *osdep_pcap_open_offline(const char *fname, char *errbuf);
+osdep_pcap *osdep_pcap_open_dead_with_tstamp_precision(int linktype,
+	int snaplen, unsigned int precision);
+const uint8_t *osdep_pcap_next(osdep_pcap *pcap,
+	struct osdep_pcap_pkthdr *header);
+int osdep_pcap_sendpacket(osdep_pcap *pcap, const uint8_t *buf, int size);
+void osdep_pcap_close(osdep_pcap *pcap);
+
+osdep_pcap_dumper *osdep_pcap_dump_open(osdep_pcap *pcap, const char *fname);
+void osdep_pcap_dump(uint8_t *user, const struct osdep_pcap_pkthdr *header,
+	const uint8_t *sp);
+int osdep_pcap_dump_flush(osdep_pcap_dumper *p);
+void osdep_pcap_dump_close(osdep_pcap_dumper *p);
+
+int osdep_pcap_setdirection(osdep_pcap *pcap, enum osdep_pcap_direction dir);
+const char *osdep_pcap_geterr(osdep_pcap *pcap);
+
 #endif
-- 
2.29.2

[dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:17:12

WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 config/meson.build | 21 ++++++++++++++++++---
 meson_options.txt  |  6 ++++--
 2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/config/meson.build b/config/meson.build
index 3cf560b8a..6aae8276c 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -178,9 +178,24 @@ if not pcap_dep.found()
 	# pcap got a pkg-config file only in 1.9.0
 	pcap_dep = cc.find_library('pcap', required: false)
 endif
-if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
-	dpdk_conf.set('RTE_PORT_PCAP', 1)
-	dpdk_extra_ldflags += '-lpcap'
+if is_windows
+	# npcap SDK can be installed anywhere
+	pcap_sdk = get_option('pcap_sdk')
+	if pcap_sdk != ''
+		pcap_ldflags = ['-L@0@/Lib/x64'.format(pcap_sdk), '-lwpcap']
+		pcap_dep = declare_dependency(
+			compile_args: ['-I@0@/Include'.format(pcap_sdk)],
+			link_args: pcap_ldflags)
+	endif
+	if pcap_dep.found()
+		dpdk_conf.set('RTE_PORT_PCAP', 1)
+		dpdk_extra_ldflags += pcap_ldflags
+	endif
+else
+	if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
+		dpdk_conf.set('RTE_PORT_PCAP', 1)
+		dpdk_extra_ldflags += '-lpcap'
+	endif
 endif
 
 # for clang 32-bit compiles we need libatomic for 64-bit atomic ops
diff --git a/meson_options.txt b/meson_options.txt
index 6eff62e47..d74146d3a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -10,6 +10,8 @@ option('enable_docs', type: 'boolean', value: false,
 	description: 'build documentation')
 option('enable_kmods', type: 'boolean', value: false,
 	description: 'build kernel modules')
+option('enable_trace_fp', type: 'boolean', value: false,
+	description: 'enable fast path trace points.')
 option('examples', type: 'string', value: '',
 	description: 'Comma-separated list of examples to build by default')
 option('flexran_sdk', type: 'string', value: '',
@@ -28,8 +30,8 @@ option('max_lcores', type: 'integer', value: 128,
 	description: 'maximum number of cores/threads supported by EAL')
 option('max_numa_nodes', type: 'integer', value: 32,
 	description: 'maximum number of NUMA nodes supported by EAL')
-option('enable_trace_fp', type: 'boolean', value: false,
-	description: 'enable fast path trace points.')
+option('pcap_sdk', type: 'string', value: '',
+	description: 'Path to libpcap SDK used on Windows')
 option('tests', type: 'boolean', value: true,
 	description: 'build unit tests')
 option('use_hpet', type: 'boolean', value: false,
-- 
2.29.2

[dpdk-dev] [PATCH v2 6/6] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-14 02:17:24

Implement OS-dependent functions and enable PMD build on Windows.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 drivers/net/pcap/meson.build          |  11 ++-
 drivers/net/pcap/pcap_ethdev.c        |   4 -
 drivers/net/pcap/pcap_osdep.h         |   5 ++
 drivers/net/pcap/pcap_osdep_windows.c | 118 ++++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 10 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 9ab95ec3e..614a4e340 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -1,19 +1,18 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-if is_windows
-	build = false
-	reason = 'not supported on Windows'
-	subdir_done()
-endif
-
 if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
+
 sources = files(
 	'pcap_ethdev.c',
 	'pcap_osdep.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
+
 ext_deps += pcap_dep
+if is_windows
+	ext_deps += cc.find_library('iphlpapi', required: true)
+endif
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 6461213e0..142533c6e 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -127,10 +127,6 @@ static struct rte_eth_link pmd_link = {
 
 RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
-#define PMD_LOG(level, fmt, args...) \
-	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
-		"%s(): " fmt "\n", __func__, ##args)
-
 static int
 eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
 		const uint8_t *data, uint16_t data_len)
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index bd00b728a..f7c311ef8 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -8,6 +8,11 @@
 #include <rte_ether.h>
 #include <rte_time.h>
 
+#define PMD_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
+		"%s(): " fmt "\n", __func__, ##args)
+extern int eth_pcap_logtype;
+
 /*
  * Interface manipulation is always OS-specific.
  */
diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c
new file mode 100644
index 000000000..d6557ff73
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_windows.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <strsafe.h>
+
+#include "pcap_osdep.h"
+
+/*
+ * Given a device name like "\Device\NPF_{GUID}" extract the "{GUID}" part.
+ * Return NULL if "{GUID}" part is not found.
+ */
+static const char *
+iface_guid(const char *name)
+{
+	static const size_t GUID_LENGTH = 32 + 4; /* 16 hex bytes + 4 dashes */
+
+	const char *ob, *cb;
+
+	ob = strchr(name, '{');
+	if (ob == NULL)
+		return NULL;
+
+	cb = strchr(ob, '}');
+	if (cb == NULL || cb - ob != GUID_LENGTH + 1) /* + 1 opening '{' */
+		return NULL;
+
+	return ob;
+}
+
+/*
+ * libpcap takes device names like "\Device\NPF_{GUID}",
+ * GetAdapterIndex() takes interface names like "\DEVICE\TCPIP_{GUID}".
+ * Try to convert, fall back to original device name.
+ */
+int
+osdep_iface_index_get(const char *device_name)
+{
+	WCHAR adapter_name[MAX_ADAPTER_NAME_LENGTH];
+	const char *guid;
+	ULONG index;
+	DWORD ret;
+
+	guid = iface_guid(device_name);
+	if (guid != NULL)
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"\\DEVICE\\TCPIP_%s", guid);
+	else
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"%s", device_name);
+
+	ret = GetAdapterIndex(adapter_name, &index);
+	if (ret != NO_ERROR) {
+		PMD_LOG(ERR, "GetAdapterIndex() = %lu\n", ret);
+		return -1;
+	}
+
+	return index;
+}
+
+/*
+ * 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;
+	ULONG size, sys_ret;
+	const char *adapter_name;
+	int ret = -1;
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+	if (sys_ret != ERROR_BUFFER_OVERFLOW) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n",
+			sys_ret, ERROR_BUFFER_OVERFLOW);
+		return -1;
+	}
+
+	info = (IP_ADAPTER_ADDRESSES *)malloc(size);
+	if (info == NULL) {
+		PMD_LOG(ERR, "Cannot allocate adapter address info\n");
+		return -1;
+	}
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size);
+	if (sys_ret != ERROR_SUCCESS) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret);
+		free(info);
+		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) {
+			if (cur->PhysicalAddressLength != RTE_ETHER_ADDR_LEN) {
+				PMD_LOG(ERR, "Physical address length: want %u, got %lu",
+					RTE_ETHER_ADDR_LEN,
+					cur->PhysicalAddressLength);
+				return -1;
+			}
+
+			memcpy(mac->addr_bytes, cur->PhysicalAddress,
+				RTE_ETHER_ADDR_LEN);
+			ret = 0;
+			break;
+		}
+	}
+
+	free(info);
+	return ret;
+}
-- 
2.29.2

Re: [dpdk-dev] [PATCH v2 2/6] net/pcap: fix format string

From: Ferruh Yigit <hidden>
Date: 2021-02-25 14:45:19

On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
Use PRIu32 for uint32_t (found by -Wformat with Clang on Windows).

Fixes: a3f5252e5cbd ("net/pcap: enable infinitely Rx a pcap file")
Cc: stable@dpdk.org

Signed-off-by: Dmitry Kozlyuk <redacted>
Acked-by: Ferruh Yigit <redacted>

Re: [dpdk-dev] [PATCH v2 3/6] net/pcap: move OS-dependent code to separate files

From: Ferruh Yigit <hidden>
Date: 2021-02-25 14:51:57

On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. In preparation to add
Windows-specific part and libpcap wrapper, extract OS-independent
interface and move implementations to separate files. Rename
rte_eth_pcap.c to pcap_ethdev.c for consistency with the rest of DPDK.

Signed-off-by: Dmitry Kozlyuk <redacted>
<...>
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}

The 'osdep_iface_index_get' wrapper is not required for this patch and can be 
done in patch 6/6, but OK to have here to make the switch clear.


Reviewed-by: Ferruh Yigit <redacted>

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Ferruh Yigit <hidden>
Date: 2021-02-25 14:59:28

On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
libpcap headers can expose OS headers. On Windows, system networking
headers are incompatible with DPDK ones, causing multiple name clashes.
API of libpcap itself involves a non-standard u_char type.

Add a limited set of trivial libpcap wrappers, so that libpcap headers
are not included directly by OS-independent PMD code. Use EAL types and
functions for time instead of POSIX ones.
It is not nice to duplicate the pcap struct and macros and have dpdk versions of 
them, it may have long term maintanance issues too.

What are the clashes in question?

If they are macros, can the issue solved after undefining some after including 
'pcap.h'?

And at the end of the day, shouldn't we need to resolve these clashes globally 
since we may hit same things with other PMDs or libraries as we enable them. I 
am for a global solution instead of these changes in pcap, but I guess question 
is how possible that global solution is..
Signed-off-by: Dmitry Kozlyuk <redacted>
<...>

Re: [dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Ferruh Yigit <hidden>
Date: 2021-02-25 15:02:39

On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.
I am not sure if it is OK to add a meson option for this, can't we use the 
default path?

And does this mean we will need to add an option for each dependent library in 
Windows? If not, why pcap is special?
Signed-off-by: Dmitry Kozlyuk <redacted>
<...>

Re: [dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-25 16:04:43

2021-02-25 15:02, Ferruh Yigit:
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
quoted
WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.
  
I am not sure if it is OK to add a meson option for this, can't we use the 
default path?

And does this mean we will need to add an option for each dependent library in 
Windows? If not, why pcap is special?
There are some meson options for SDK paths already. Are they exceptions?

IMO, explicit specification is better because it allows switching
dependency versions and library distributions.
I understand that consensus it to keep build matrix size at minimum, but
options to specify SDK path don't change the number of variants what can be
found.

Re: [dpdk-dev] [PATCH v2 3/6] net/pcap: move OS-dependent code to separate files

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-25 16:05:06

2021-02-25 14:51, Ferruh Yigit:
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
quoted
PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. In preparation to add
Windows-specific part and libpcap wrapper, extract OS-independent
interface and move implementations to separate files. Rename
rte_eth_pcap.c to pcap_ethdev.c for consistency with the rest of DPDK.

Signed-off-by: Dmitry Kozlyuk <redacted>  
<...>
quoted
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}  

The 'osdep_iface_index_get' wrapper is not required for this patch and can be 
done in patch 6/6, but OK to have here to make the switch clear.
Yes, it was my intention to keep Windows patches separate.

Re: [dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Bruce Richardson <hidden>
Date: 2021-02-25 16:33:52

On Thu, Feb 25, 2021 at 07:04:38PM +0300, Dmitry Kozlyuk wrote:
2021-02-25 15:02, Ferruh Yigit:
quoted
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
quoted
WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.
  
I am not sure if it is OK to add a meson option for this, can't we use the 
default path?

And does this mean we will need to add an option for each dependent library in 
Windows? If not, why pcap is special?
There are some meson options for SDK paths already. Are they exceptions?
Right now, yes, they are exceptions, but there is work underway to remove
them and just replace them with use of pkg-config. Is there some automatic
path discovery mechanism on windows, similar to pkg-config, that can be
used rather than having to add explicit dependency paths?

/bruce

Re: [dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-25 17:42:35

2021-02-25 16:33, Bruce Richardson:
On Thu, Feb 25, 2021 at 07:04:38PM +0300, Dmitry Kozlyuk wrote:
quoted
2021-02-25 15:02, Ferruh Yigit:  
quoted
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:  
quoted
WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.
    
I am not sure if it is OK to add a meson option for this, can't we use the 
default path?

And does this mean we will need to add an option for each dependent library in 
Windows? If not, why pcap is special?  
There are some meson options for SDK paths already. Are they exceptions?
  
Right now, yes, they are exceptions, but there is work underway to remove
them and just replace them with use of pkg-config. Is there some automatic
path discovery mechanism on windows, similar to pkg-config, that can be
used rather than having to add explicit dependency paths?
pkg-config itself works on Windows if installed and given a PKG_CONFIG_PATH.

Npcap doesn't provide a .pc file, despite libpcap commit 4f6b2b99 having it.
Another quirk is that library is named libpcap.a/wpcap.lib on Unix/Windows.
I can just handle the name difference and assume it's in the search path.

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-25 19:04:44

2021-02-25 14:59, Ferruh Yigit:
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
quoted
libpcap headers can expose OS headers. On Windows, system networking
headers are incompatible with DPDK ones, causing multiple name clashes.
API of libpcap itself involves a non-standard u_char type.

Add a limited set of trivial libpcap wrappers, so that libpcap headers
are not included directly by OS-independent PMD code. Use EAL types and
functions for time instead of POSIX ones.
  
It is not nice to duplicate the pcap struct and macros and have dpdk versions of 
them, it may have long term maintanance issues too.

What are the clashes in question?

If they are macros, can the issue solved after undefining some after including 
'pcap.h'?

And at the end of the day, shouldn't we need to resolve these clashes globally 
since we may hit same things with other PMDs or libraries as we enable them. I 
am for a global solution instead of these changes in pcap, but I guess question 
is how possible that global solution is..
Your comment made me revise Windows EAL networking shims. Surprisingly, if
changed to expose Windows networking headers (specifically, <ws2tcpip.h>) with
some additions (but no hacks), they create no issues to any existing code.

The only workaround remaining is `#undef s_addr` in <rte_ether.h>.

So maybe this commit can be dropped, if Windows EAL networking headers be
reworked in the following way:

	#if defined min
	#define USER_EXPLICITLY_WANTS_WINDOWS_H
	#endif

	#include <ws2tcpip.h>

	/* hide definitions that break portable code,
	 * e.g. it had to be done once already for i40e
	 */
	#ifndef USER_EXPLICITLY_WANTS_WINDOWS_H
	#undef min, max, ...
	#endif

	#define what's missing from Windows headers, e.g. IPPROTO_SCTP

+ Windows maintainers, Nick Connolly, and Jie Zhou to discuss.

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Nick Connolly <hidden>
Date: 2021-02-25 20:31:33

Your comment made me revise Windows EAL networking shims. Surprisingly, if
changed to expose Windows networking headers (specifically, <ws2tcpip.h>) with
some additions (but no hacks), they create no issues to any existing code.

The only workaround remaining is `#undef s_addr` in <rte_ether.h>.

So maybe this commit can be dropped, if Windows EAL networking headers be
reworked in the following way:

	#if defined min
	#define USER_EXPLICITLY_WANTS_WINDOWS_H
	#endif

	#include <ws2tcpip.h>

	/* hide definitions that break portable code,
	 * e.g. it had to be done once already for i40e
	 */
	#ifndef USER_EXPLICITLY_WANTS_WINDOWS_H
	#undef min, max, ...
	#endif

	#define what's missing from Windows headers, e.g. IPPROTO_SCTP

+ Windows maintainers, Nick Connolly, and Jie Zhou to discuss.
In my opinion, there are long term maintenance issues either way round.

Wrapping the system headers hides the details and keeps the code 'clean',
but has to work with multiple compiler environments and versions of the
headers - not always straightforward.  Wrapping libpcap involves code
changes that need to be maintained.

For SPDK, changing the code wasn't really an option, so I had to go with
wrapping the headers. It's worked out ok so far. To make it a bit cleaner
I turned off as much as possible from Windows.h with #define NO*.
Supporting both clang and MinGW caused a few issues (e.g. MinGW has
mswsock.h), but they are solvable.

./inc/sys/socket.h and ./inc/wpdk/windows.h in https://github.com/wpdp/wpdk
show an example of what might need wrapping in the general case.

Regards,
Nick

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-02-25 23:10:08

2021-02-25 20:31, Nick Connolly:
quoted
Your comment made me revise Windows EAL networking shims. Surprisingly, if
changed to expose Windows networking headers (specifically, <ws2tcpip.h>) with
some additions (but no hacks), they create no issues to any existing code.

The only workaround remaining is `#undef s_addr` in <rte_ether.h>.

So maybe this commit can be dropped, if Windows EAL networking headers be
reworked in the following way:

	#if defined min
	#define USER_EXPLICITLY_WANTS_WINDOWS_H
	#endif

	#include <ws2tcpip.h>

	/* hide definitions that break portable code,
	 * e.g. it had to be done once already for i40e
	 */
	#ifndef USER_EXPLICITLY_WANTS_WINDOWS_H
	#undef min, max, ...
	#endif

	#define what's missing from Windows headers, e.g. IPPROTO_SCTP

+ Windows maintainers, Nick Connolly, and Jie Zhou to discuss.  
In my opinion, there are long term maintenance issues either way round.

Wrapping the system headers hides the details and keeps the code 'clean',
but has to work with multiple compiler environments and versions of the
headers - not always straightforward. 
You're probably right.
We had an exchange with Tyler, let me quote:

[DmitryK]
I'm pretty sure no DPDK header really needs anything beyond standard C,
but one exception: intrinsic functions for vector instructions.
Struct in_addr? An oversight, there's rte_ether_addr, should be rte_ip_addr.
Here's a complete list of offending files included from public headers,
with comments on usage:

POSIX

    netinet/in.h
    netinet/ip6.h
    netinet/ip.h
	cmdline:  struct in_addr, struct in6_addr, 6 constants
	net:      ditto
	security: ditto
    pthread.h
	eal:	not used
	ethdev:	pthread_mutex_t flow_ops_mutex;
    sched.h
	eal:       cpu_set_t
	telemetry: rte_cpuset_t (not used?)
    sys/types.h
	ehtdev:   not needed (FILE?)
	net:      not needed
	mbuf:     ditto
	pci:      ditto
	security: ditto
	sched:    ditto

Unix

    sys/queue.h
	(acl, eal, hash, lpm, mempool, pci, ring, table,
	 bus/{fslmc,pci,vdev,vmbus}, net/{memif,tap})
		multiprocessing

Thread-related stuff will go away as rte_thread.h expands.
Network headers are not much needed, as you can see above.
Other headers mostly not needed or can be replaced with standard ones.

Replacing `in_addr` with and `rte_ip_addr` will break API, but not ABI,
because it's essentially the same thing. We can define new types
conditionally, as it was done for struct cmdline, if need be.

Complete removal of non-standard dependencies in headers is within a grasp.
Then we can remove shims and include whatever needed.
Thoughts?

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Nick Connolly <hidden>
Date: 2021-03-01 21:44:01

Complete removal of non-standard dependencies in headers is within a grasp.
Then we can remove shims and include whatever needed.
Thoughts?
Sounds good. A couple of 'gotchas' that I've come across (but may not be 
an issue for DPDK):

  * Memory allocation / free that spans a dll boundary (see earlier email).
  * posix_memalign is unfortunately specified as using free(), so we'll
    either have to modify the calls to rte_posix_memalign /
    rte_free_memalign (which means code analysis to find which free
    calls need changing), or wrapper free() to distinguish the two types
    of memory somehow. I 'solved' this for SPDK by using posix_memalign
    for everything and I have a vague recollection that the mingw libc
    does something similar.
  * Sockets are unfortunately specified as using close(). This is
    probably easy to address by rte_ wrapping all socket calls.

Regards,
Nick

Re: [dpdk-dev] [PATCH 1/6] eal: add internal API for current time

From: Nick Connolly <hidden>
Date: 2021-03-01 22:31:41

Calculation of usec value is incorrect - 'ticks' is not adjusted for 
epoch, whereas 'sec' has been, also subtraction has mismatched units - 
ticks in 100ns and sec * USEC_PER_SEC in usecs.


On 14/02/2021 01:20, Dmitry Kozlyuk wrote:
+	GetSystemTimePreciseAsFileTime(&ft);
+	ticks = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+	sec = (ticks - EPOCH) / (TICKS_PER_USEC * USEC_PER_SEC);
+	now->sec = sec;
+	now->usec = (ticks - sec * USEC_PER_SEC) / TICKS_PER_USEC;

Re: [dpdk-dev] [PATCH 2/6] net/pcap: fix format string

From: Nick Connolly <hidden>
Date: 2021-03-01 22:33:28

Use PRIu32 for uint32_t (found by -Wformat with Clang on Windows).
Acked-by: Nick Connolly <redacted>

Re: [dpdk-dev] [PATCH 1/6] eal: add internal API for current time

From: Nick Connolly <hidden>
Date: 2021-03-01 22:36:05

Calculation of usec value is incorrect - 'ticks' is not adjusted for 
epoch, whereas 'sec' has been, also subtraction has mismatched units - 
ticks in 100ns and sec * USEC_PER_SEC in usecs.
Ignore - fixed in later version which I hadn't spotted.

Re: [dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Nick Connolly <hidden>
Date: 2021-03-01 22:39:21

Many PMDs use POSIX gettimeofday(). Add rte_time_get_us() function
to obtain current time with microsecond precision on all platforms.
Acked-by: Nick Connolly <redacted>

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-01 23:06:05

2021-03-01 21:43, Nick Connolly:
quoted
Complete removal of non-standard dependencies in headers is within a grasp.
Then we can remove shims and include whatever needed.
Thoughts?
Sounds good. A couple of 'gotchas' that I've come across (but may not be 
an issue for DPDK):

  * Memory allocation / free that spans a dll boundary (see earlier email).
Not sure which email you mean, could you give a link?
  * posix_memalign is unfortunately specified as using free(), so we'll
    either have to modify the calls to rte_posix_memalign /
    rte_free_memalign (which means code analysis to find which free
    calls need changing), or wrapper free() to distinguish the two types
    of memory somehow. I 'solved' this for SPDK by using posix_memalign
    for everything and I have a vague recollection that the mingw libc
    does something similar.
Is posix_memalign() used more extensively in SPDK? In DPDK, it's 2 PMDs:
  * mlx5 PMD uses _aligned_malloc/_aligned_free on Windows;
  * dpaax (PMD family) uses posix_memalign() to allocate pages.
There are "malloc" and "alloc_size" attributes that can help code analysis.
  * Sockets are unfortunately specified as using close(). This is
    probably easy to address by rte_ wrapping all socket calls.
Which public DPDK APIs operate on sockets?
I don't like the idea of wrapping APIs like sockets or files.
(Yes, we're discussing libpcap API wrappers in this thread, but we already
agreed they are a mistake and they were internal in the first place.)

I drafted what I was talking about: adding address types and removing shims:

* librte_net/rte_ip.h then includes <netinet/ip.h> or <ws2tcpip.h>
  conditionally for AF_xxx, IPPROTO_xxx, and a few other constants.
  That's probably OK, there are similar places for Linux/FreeBSD differences,
  e.g. in <rte_endian.h>.

* Some IPPROTO_xxx constants are missing on Windows, so rte_ip.h has to
  provide them. I hope Mirosoft will add them to system headers one day.

* It affects cmdline (mostly), ethdev, security, crypto/dpaax.

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-01 23:24:02

2021-03-02 02:05, Dmitry Kozlyuk:
2021-03-01 21:43, Nick Connolly:
quoted
quoted
Complete removal of non-standard dependencies in headers is within a grasp.
Then we can remove shims and include whatever needed.
Thoughts?  
Sounds good. A couple of 'gotchas' that I've come across (but may not be 
an issue for DPDK):

  * Memory allocation / free that spans a dll boundary (see earlier email).  
Not sure which email you mean, could you give a link?
There it is:

	https://mails.dpdk.org/archives/dev/2021-February/200105.html

Yes, of course malloc/free shall be both on either library or caller site.

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Nick Connolly <hidden>
Date: 2021-03-02 11:22:49

Is posix_memalign() used more extensively in SPDK? In DPDK, it's 2 PMDs:
Yes, there are about 80 references. A lot are in ISA-L where they are 
#defined to _aligned_malloc and can be ignored, but there still several 
in the rest of the code.

quoted
   * Sockets are unfortunately specified as using close(). This is
     probably easy to address by rte_ wrapping all socket calls.
Which public DPDK APIs operate on sockets?
I don't like the idea of wrapping APIs like sockets or files.
I'm not sure about use in public APIs - I'd hope none do. I was thinking 
about 'internal' use. The tricky issue here is that on Linux/FreeBSD 
socket() returns a small integer file descriptor whereas Windows returns 
a SOCKET type (which is a UINT_PTR and so larger than the 'int' that an 
fd occupies). In practice it looks as though SOCKET usually returns a 
small integer, but as far as I can see from the documentation it depends 
on the software stack that is in use. Even if it's a small integer, I 
don't think it has any correlation to the file descriptor table in the 
crt, which means that calls to read/write/close will all need to be 
handled so that they work.
(Yes, we're discussing libpcap API wrappers in this thread, but we already
agreed they are a mistake and they were internal in the first place.)

I drafted what I was talking about: adding address types and removing shims:

* librte_net/rte_ip.h then includes <netinet/ip.h> or <ws2tcpip.h>
   conditionally for AF_xxx, IPPROTO_xxx, and a few other constants.
   That's probably OK, there are similar places for Linux/FreeBSD differences,
   e.g. in <rte_endian.h>.

* Some IPPROTO_xxx constants are missing on Windows, so rte_ip.h has to
   provide them. I hope Mirosoft will add them to system headers one day.

* It affects cmdline (mostly), ethdev, security, crypto/dpaax.
Sounds good - well done!

Regards,
Nick

Re: [dpdk-dev] [dpdk-stable] [PATCH v2 2/6] net/pcap: fix format string

From: Ferruh Yigit <hidden>
Date: 2021-03-02 11:49:07

On 2/25/2021 2:45 PM, Ferruh Yigit wrote:
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:
quoted
Use PRIu32 for uint32_t (found by -Wformat with Clang on Windows).

Fixes: a3f5252e5cbd ("net/pcap: enable infinitely Rx a pcap file")
Cc: stable@dpdk.org

Signed-off-by: Dmitry Kozlyuk <redacted>
Acked-by: Ferruh Yigit <redacted>
This is trivial fix and not directly related to the patchset, let me merge it 
and get out of way, in next version you don't need to include this patch.

Applied to dpdk-next-net/main, thanks.

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-03 16:32:46

2021-03-02 11:22, Nick Connolly:
quoted
Is posix_memalign() used more extensively in SPDK? In DPDK, it's 2 PMDs:  
Yes, there are about 80 references. A lot are in ISA-L where they are 
#defined to _aligned_malloc and can be ignored, but there still several 
in the rest of the code.
I think portable code should try sticking to C11 aligned_malloc().
BTW, _aligned_malloc (with "_") only supports power-of-2 alignment.

There's a related passage in MSVC blog:

	Due to the nature of the Windows heap, aligned_alloc support is
	missing. The alternative is to use _aligned_malloc.

https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/
quoted
quoted
   * Sockets are unfortunately specified as using close(). This is
     probably easy to address by rte_ wrapping all socket calls.  
Which public DPDK APIs operate on sockets?
I don't like the idea of wrapping APIs like sockets or files.  
I'm not sure about use in public APIs - I'd hope none do. I was thinking 
about 'internal' use.
This is important (even more so for SPDK, I suspect), however, I'd like to
focus on public API first.
quoted
I drafted what I was talking about: adding address types and removing shims:

* librte_net/rte_ip.h then includes <netinet/ip.h> or <ws2tcpip.h>
   conditionally for AF_xxx, IPPROTO_xxx, and a few other constants.
   That's probably OK, there are similar places for Linux/FreeBSD differences,
   e.g. in <rte_endian.h>.

* Some IPPROTO_xxx constants are missing on Windows, so rte_ip.h has to
   provide them. I hope Mirosoft will add them to system headers one day.

* It affects cmdline (mostly), ethdev, security, crypto/dpaax.  
Sounds good - well done!
...or not :)

If we can't help including <ws2tcpip.h>/<netinet/ip.h> from public headers,
might as well use `struct in_addr`, just replace `#include <netinet/ip.h>`
with `#include <rte_ip.h>` everywhere.

The only remaining issue will be `s_addr` macro on Windows that conflicts with
`struct rte_ether_addr` field `s_addr`. I don't know a better solution than
renaming `s_addr` to `src_addr` in DPDK (OTOH, it will be consistent with
`struct rte_ipvX_hdr` field naming).

Ferruh, what do you think?

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Ferruh Yigit <hidden>
Date: 2021-03-03 16:47:34

On 3/3/2021 4:32 PM, Dmitry Kozlyuk wrote:
2021-03-02 11:22, Nick Connolly:
quoted
quoted
Is posix_memalign() used more extensively in SPDK? In DPDK, it's 2 PMDs:
Yes, there are about 80 references. A lot are in ISA-L where they are
#defined to _aligned_malloc and can be ignored, but there still several
in the rest of the code.
I think portable code should try sticking to C11 aligned_malloc().
BTW, _aligned_malloc (with "_") only supports power-of-2 alignment.

There's a related passage in MSVC blog:

	Due to the nature of the Windows heap, aligned_alloc support is
	missing. The alternative is to use _aligned_malloc.

https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/
quoted
quoted
quoted
    * Sockets are unfortunately specified as using close(). This is
      probably easy to address by rte_ wrapping all socket calls.
Which public DPDK APIs operate on sockets?
I don't like the idea of wrapping APIs like sockets or files.
I'm not sure about use in public APIs - I'd hope none do. I was thinking
about 'internal' use.
This is important (even more so for SPDK, I suspect), however, I'd like to
focus on public API first.
quoted
quoted
I drafted what I was talking about: adding address types and removing shims:

* librte_net/rte_ip.h then includes <netinet/ip.h> or <ws2tcpip.h>
    conditionally for AF_xxx, IPPROTO_xxx, and a few other constants.
    That's probably OK, there are similar places for Linux/FreeBSD differences,
    e.g. in <rte_endian.h>.

* Some IPPROTO_xxx constants are missing on Windows, so rte_ip.h has to
    provide them. I hope Mirosoft will add them to system headers one day.

* It affects cmdline (mostly), ethdev, security, crypto/dpaax.
Sounds good - well done!
...or not :)

If we can't help including <ws2tcpip.h>/<netinet/ip.h> from public headers,
might as well use `struct in_addr`, just replace `#include <netinet/ip.h>`
with `#include <rte_ip.h>` everywhere.

The only remaining issue will be `s_addr` macro on Windows that conflicts with
`struct rte_ether_addr` field `s_addr`. I don't know a better solution than
renaming `s_addr` to `src_addr` in DPDK (OTOH, it will be consistent with
`struct rte_ipvX_hdr` field naming).

Ferruh, what do you think?
No problem on the chosen name, that will work fine, but the 'struct 
rte_eth_addr' is public struct, we can't rename it without breaking the user 
applications.

Still it is possible to rename public struct, but it is a long process, need to 
send a deprecation notice and wait for next LTS, 21.11.

Ethernet header already has following, doesn't it help:
#undef s_addr /* Defined in winsock2.h included in windows.h. */

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-03 18:19:26

2021-03-03 16:47, Ferruh Yigit:
On 3/3/2021 4:32 PM, Dmitry Kozlyuk wrote:
[...]
quoted
If we can't help including <ws2tcpip.h>/<netinet/ip.h> from public headers,
might as well use `struct in_addr`, just replace `#include <netinet/ip.h>`
with `#include <rte_ip.h>` everywhere.

The only remaining issue will be `s_addr` macro on Windows that conflicts with
`struct rte_ether_addr` field `s_addr`. I don't know a better solution than
renaming `s_addr` to `src_addr` in DPDK (OTOH, it will be consistent with
`struct rte_ipvX_hdr` field naming).

Ferruh, what do you think?
  
No problem on the chosen name, that will work fine, but the 'struct 
rte_eth_addr' is public struct, we can't rename it without breaking the user 
applications.

Still it is possible to rename public struct, but it is a long process, need to 
send a deprecation notice and wait for next LTS, 21.11.

Ethernet header already has following, doesn't it help:
#undef s_addr /* Defined in winsock2.h included in windows.h. */
It helps until you do the following:

	#include <winsock2.h>	/* #define s_addr S_un.S_addr */
	#include <rte_ether.h>	/* #undef s_addr */

	struct in_addr a;
	a.s_addr = 0; /* ERROR, `s_addr` has been defined to do that */

Or the following:

	#include <rte_ether.h>
	#include <winsock2.h>

	struct rte_ether_hdr eh;
	eh.s_addr.addr_bytes[0] = 0;	/* ERROR: `addr_s` is a macro */

If you swap include order in each case, it compiles, i.e . code is fragile.
Shims redefine `struct in_addr` and we're trying to get rid of them anyway.


Here's a solution that always works, however ugly it looks. It defines
`struct rte_ether_hdr` for Windows such that `s_addr` macro works for it if
defined. We can keep it until 21.11, then remove it and rename fields. In
return, we can remove networking shims and workarounds immediately.

`S_un.S_addr` part of `struct in_addr` is documented, and thus is unlikely to
ever change:

	https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-in_addr

diff --git a/lib/librte_net/rte_ether.h b/lib/librte_net/rte_ether.h
index 060b63fc9..67d340bb2 100644
--- a/lib/librte_net/rte_ether.h
+++ b/lib/librte_net/rte_ether.h
@@ -23,10 +23,6 @@ extern "C" {
 #include <rte_mbuf.h>
 #include <rte_byteorder.h>
 
-#ifdef RTE_EXEC_ENV_WINDOWS /* Workaround conflict with rte_ether_hdr. */
-#undef s_addr /* Defined in winsock2.h included in windows.h. */
-#endif
-
 #define RTE_ETHER_ADDR_LEN  6 /**< Length of Ethernet address. */
 #define RTE_ETHER_TYPE_LEN  2 /**< Length of Ethernet type field. */
 #define RTE_ETHER_CRC_LEN   4 /**< Length of Ethernet CRC. */
@@ -257,6 +253,8 @@ __rte_experimental
 int
 rte_ether_unformat_addr(const char *str, struct rte_ether_addr *eth_addr);
 
+#if !defined RTE_EXEC_ENV_WINDOWS || defined __DOXYGEN__
+
 /**
  * Ethernet header: Contains the destination address, source address
  * and frame type.
@@ -267,6 +265,28 @@ struct rte_ether_hdr {
 	uint16_t ether_type;      /**< Frame type. */
 } __rte_aligned(2);
 
+#else
+
+#pragma push_macro("s_addr")
+#ifdef s_addr
+#undef s_addr
+#endif
+
+struct rte_ether_hdr {
+	struct rte_ether_addr d_addr; /**< Destination address. */
+	RTE_STD_C11
+	union {
+		struct rte_ether_addr s_addr; /**< Source address. */
+		struct {
+			struct rte_ether_addr S_un;
+		} S_addr;
+	};
+	uint16_t ether_type; /**< Frame type. */
+} __rte_aligned(2);
+
+#pragma pop_macro("s_addr")
+#endif
+
 /**
  * Ethernet VLAN Header.
  * Contains the 16-bit VLAN Tag Control Identifier and the Ethernet type

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Ferruh Yigit <hidden>
Date: 2021-03-03 19:30:26

On 3/3/2021 6:19 PM, Dmitry Kozlyuk wrote:
2021-03-03 16:47, Ferruh Yigit:
quoted
On 3/3/2021 4:32 PM, Dmitry Kozlyuk wrote:
[...]
quoted
quoted
If we can't help including <ws2tcpip.h>/<netinet/ip.h> from public headers,
might as well use `struct in_addr`, just replace `#include <netinet/ip.h>`
with `#include <rte_ip.h>` everywhere.

The only remaining issue will be `s_addr` macro on Windows that conflicts with
`struct rte_ether_addr` field `s_addr`. I don't know a better solution than
renaming `s_addr` to `src_addr` in DPDK (OTOH, it will be consistent with
`struct rte_ipvX_hdr` field naming).

Ferruh, what do you think?
   
No problem on the chosen name, that will work fine, but the 'struct
rte_eth_addr' is public struct, we can't rename it without breaking the user
applications.

Still it is possible to rename public struct, but it is a long process, need to
send a deprecation notice and wait for next LTS, 21.11.

Ethernet header already has following, doesn't it help:
#undef s_addr /* Defined in winsock2.h included in windows.h. */
It helps until you do the following:

	#include <winsock2.h>	/* #define s_addr S_un.S_addr */
	#include <rte_ether.h>	/* #undef s_addr */

	struct in_addr a;
	a.s_addr = 0; /* ERROR, `s_addr` has been defined to do that */

Or the following:

	#include <rte_ether.h>
	#include <winsock2.h>

	struct rte_ether_hdr eh;
	eh.s_addr.addr_bytes[0] = 0;	/* ERROR: `addr_s` is a macro */

If you swap include order in each case, it compiles, i.e . code is fragile.
Shims redefine `struct in_addr` and we're trying to get rid of them anyway.
Got it, thanks for clarification.
Here's a solution that always works, however ugly it looks. It defines
`struct rte_ether_hdr` for Windows such that `s_addr` macro works for it if
defined. We can keep it until 21.11, then remove it and rename fields. In
return, we can remove networking shims and workarounds immediately.
Agree it looks ugly :), but I am OK with above plan.
You need to send a deprecation notice for this. We can discuss there if 'd_addr' 
also should be renamed for consistency, or leave with the workaround instead of 
rename ...
quoted hunk
`S_un.S_addr` part of `struct in_addr` is documented, and thus is unlikely to
ever change:

	https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-in_addr

diff --git a/lib/librte_net/rte_ether.h b/lib/librte_net/rte_ether.h
index 060b63fc9..67d340bb2 100644
--- a/lib/librte_net/rte_ether.h
+++ b/lib/librte_net/rte_ether.h
@@ -23,10 +23,6 @@ extern "C" {
  #include <rte_mbuf.h>
  #include <rte_byteorder.h>
  
-#ifdef RTE_EXEC_ENV_WINDOWS /* Workaround conflict with rte_ether_hdr. */
-#undef s_addr /* Defined in winsock2.h included in windows.h. */
-#endif
-
  #define RTE_ETHER_ADDR_LEN  6 /**< Length of Ethernet address. */
  #define RTE_ETHER_TYPE_LEN  2 /**< Length of Ethernet type field. */
  #define RTE_ETHER_CRC_LEN   4 /**< Length of Ethernet CRC. */
@@ -257,6 +253,8 @@ __rte_experimental
  int
  rte_ether_unformat_addr(const char *str, struct rte_ether_addr *eth_addr);
  
+#if !defined RTE_EXEC_ENV_WINDOWS || defined __DOXYGEN__
+
  /**
   * Ethernet header: Contains the destination address, source address
   * and frame type.
@@ -267,6 +265,28 @@ struct rte_ether_hdr {
  	uint16_t ether_type;      /**< Frame type. */
  } __rte_aligned(2);
  
+#else
+
+#pragma push_macro("s_addr")
+#ifdef s_addr
+#undef s_addr
+#endif
I guess this needs to be as following, in case this header included before the 
windows header:

#ifdef s_addr
#pragma push_macro("s_addr")
#undef s_addr
#endif
+
+struct rte_ether_hdr {
+	struct rte_ether_addr d_addr; /**< Destination address. */
+	RTE_STD_C11
+	union {
+		struct rte_ether_addr s_addr; /**< Source address. */
+		struct {
+			struct rte_ether_addr S_un;
+		} S_addr;
+	};
+	uint16_t ether_type; /**< Frame type. */
+} __rte_aligned(2);
+
+#pragma pop_macro("s_addr")
+#endif
+
  /**
   * Ethernet VLAN Header.
   * Contains the 16-bit VLAN Tag Control Identifier and the Ethernet type

Re: [dpdk-dev] [PATCH v2 4/6] net/pcap: add libpcap wrappers

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-03 23:03:48

2021-03-03 19:30, Ferruh Yigit:
On 3/3/2021 6:19 PM, Dmitry Kozlyuk wrote:
quoted
2021-03-03 16:47, Ferruh Yigit:  
quoted
On 3/3/2021 4:32 PM, Dmitry Kozlyuk wrote:  
[...]
quoted
+#pragma push_macro("s_addr")
+#ifdef s_addr
+#undef s_addr
+#endif  
I guess this needs to be as following, in case this header included before the 
windows header:

#ifdef s_addr
#pragma push_macro("s_addr")
#undef s_addr
#endif
It actually works both ways.
I used #ifdef inside so that #pragma pop_macro doesn't need its own guard.

Re: [dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Jie Zhou <hidden>
Date: 2021-03-05 17:50:26

On Sun, Feb 14, 2021 at 05:16:11AM +0300, Dmitry Kozlyuk wrote:
Many PMDs use POSIX gettimeofday(). Add rte_time_get_us() function
to obtain current time with microsecond precision on all platforms.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 lib/librte_eal/include/rte_time.h    | 17 +++++++++++++++++
 lib/librte_eal/rte_eal_exports.def   |  1 +
 lib/librte_eal/unix/eal_unix_timer.c | 13 +++++++++++++
 lib/librte_eal/version.map           |  1 +
 lib/librte_eal/windows/eal_timer.c   | 21 ++++++++++++++++++++-
 5 files changed, 52 insertions(+), 1 deletion(-)
Acked-by: Jie Zhou <redacted>

Re: [dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Thomas Monjalon <hidden>
Date: 2021-03-16 09:16:35

25/02/2021 18:42, Dmitry Kozlyuk:
2021-02-25 16:33, Bruce Richardson:
quoted
On Thu, Feb 25, 2021 at 07:04:38PM +0300, Dmitry Kozlyuk wrote:
quoted
2021-02-25 15:02, Ferruh Yigit:  
quoted
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:  
quoted
WinPcap or Npcap, can be installed anywhere.
Add a Meson option to specify SDK path.
    
I am not sure if it is OK to add a meson option for this, can't we use the 
default path?

And does this mean we will need to add an option for each dependent library in 
Windows? If not, why pcap is special?  
There are some meson options for SDK paths already. Are they exceptions?
  
Right now, yes, they are exceptions, but there is work underway to remove
them and just replace them with use of pkg-config. Is there some automatic
path discovery mechanism on windows, similar to pkg-config, that can be
used rather than having to add explicit dependency paths?
pkg-config itself works on Windows if installed and given a PKG_CONFIG_PATH.

Npcap doesn't provide a .pc file, despite libpcap commit 4f6b2b99 having it.
Please work with them to provide a .pc.
Another quirk is that library is named libpcap.a/wpcap.lib on Unix/Windows.
I can just handle the name difference and assume it's in the search path.
Yes please avoid adding a meson option for a path.

Re: [dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Thomas Monjalon <hidden>
Date: 2021-03-16 09:18:34

14/02/2021 03:16, Dmitry Kozlyuk:
Many PMDs use POSIX gettimeofday(). Add rte_time_get_us() function
to obtain current time with microsecond precision on all platforms.
Please could you replace the current use of gettimeofday?


Re: [dpdk-dev] [PATCH v2 5/6] config: discover libpcap on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-16 09:37:41

2021-03-16 10:16 (UTC+0100), Thomas Monjalon:
25/02/2021 18:42, Dmitry Kozlyuk:
quoted
2021-02-25 16:33, Bruce Richardson:  
quoted
On Thu, Feb 25, 2021 at 07:04:38PM +0300, Dmitry Kozlyuk wrote:  
quoted
2021-02-25 15:02, Ferruh Yigit:    
quoted
On 2/14/2021 2:16 AM, Dmitry Kozlyuk wrote:    
[...]
quoted
pkg-config itself works on Windows if installed and given a PKG_CONFIG_PATH.

Npcap doesn't provide a .pc file, despite libpcap commit 4f6b2b99 having it.  
Please work with them to provide a .pc.
Good idea, but I can't tell how soon they do'll it.
quoted
Another quirk is that library is named libpcap.a/wpcap.lib on Unix/Windows.
I can just handle the name difference and assume it's in the search path.  
Yes please avoid adding a meson option for a path.
I have v3 that relies on search paths only with just a library name fixup.
It's blocked by [2] and, transitively, by [1].

[1]: http://patchwork.dpdk.org/project/dpdk/list/?series=15513
[1]: http://patchwork.dpdk.org/project/dpdk/list/?series=15640

Re: [dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2021-03-16 18:59:45

On Sun, 14 Feb 2021 05:16:11 +0300
Dmitry Kozlyuk [off-list ref] wrote:
+rte_time_get_us(struct rte_time_us *now)
+{
+	struct timeval sys;
+
+	gettimeofday(&sys, NULL);
+	now->sec = sys.tv_sec;
+	now->usec = sys.tv_usec;
+}
Why would drivers want the default (wall clock) time instead
of using monotonic clock. The wall clock gets changed by NTP
and that is rarely what you want except for the case of log messages.

Re: [dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-16 20:07:47

2021-03-16 11:59 (UTC-0700), Stephen Hemminger:
On Sun, 14 Feb 2021 05:16:11 +0300
Dmitry Kozlyuk [off-list ref] wrote:
quoted
+rte_time_get_us(struct rte_time_us *now)
+{
+	struct timeval sys;
+
+	gettimeofday(&sys, NULL);
+	now->sec = sys.tv_sec;
+	now->usec = sys.tv_usec;
+}  
Why would drivers want the default (wall clock) time instead
of using monotonic clock. The wall clock gets changed by NTP
and that is rarely what you want except for the case of log messages.
* gettimeofday() is mostly used to measure time (tests, hns3 PMD), so you're
right, monotonic clock is what that code really needs.

* ena PMD uses gettimeofday() with pthread_cond_timedwait() without calling
pthread_cond_setclock(), which is a bug, I believe.

* hns3 PMD actually uses gettimeofday() for logs.

For wall clock time there is C11 timespec_get(), so I agree this API should
be changed to monotonic, thanks.

Re: [dpdk-dev] [PATCH v2 1/6] eal: add internal API for current time

From: Morten Brørup <hidden>
Date: 2021-03-17 09:50:50

From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Dmitry Kozlyuk
Sent: Tuesday, March 16, 2021 9:08 PM

2021-03-16 11:59 (UTC-0700), Stephen Hemminger:
quoted
On Sun, 14 Feb 2021 05:16:11 +0300
Dmitry Kozlyuk [off-list ref] wrote:
quoted
+rte_time_get_us(struct rte_time_us *now)
+{
+	struct timeval sys;
+
+	gettimeofday(&sys, NULL);
+	now->sec = sys.tv_sec;
+	now->usec = sys.tv_usec;
+}
Why would drivers want the default (wall clock) time instead
of using monotonic clock. The wall clock gets changed by NTP
and that is rarely what you want except for the case of log messages.
* gettimeofday() is mostly used to measure time (tests, hns3 PMD), so
you're
right, monotonic clock is what that code really needs.
If using monotonic time here, we don't need a struct. A single 64 bit integer counting microseconds can hold thousands of years.
* ena PMD uses gettimeofday() with pthread_cond_timedwait() without
calling
pthread_cond_setclock(), which is a bug, I believe.

* hns3 PMD actually uses gettimeofday() for logs.

For wall clock time there is C11 timespec_get(), so I agree this API
should
be changed to monotonic, thanks.

[dpdk-dev] [PATCH v3 0/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-24 00:50:27

NOTE: dependency patches are requirements, CI may fail.

Most modern and actively maintained distribution of libpcap for Windows
is Npcap [1]. It currently doesn't provide a pkg-config file [2].
By default it is installed to C:\Program Files\Npcap and can be located
using standard environment variables [3]:

    $env:C_INCLUDE_PATH += ";C:\Program Files\Npcap"
    $env:LIBRARY_PATH += ";C:\Program Files\Npcap\Lib\x64"     # MinGW
    $env:LINK += ' /LIBPATH:"C:\Program Files\Npcap\Lib\x64"'  # Clang

The following libpcap.pc also works if placed in PKG_CONFIG_PATH:

    prefix="C:/Program Files/Npcap"
    Name: libpcap
    Version: 1.10
    Description: Platform-independent network traffic capture library
    Cflags: -I${prefix}/Include
    Libs: -L${prefix}/Lib/x64 -lwpcap

Example of collecting packets from an interface to a file:

    .\build\examples\dpdk-skeleton.exe `
        --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
        --vdev "eth_pcap1,tx_pcap=capture.pcap"

Interface name can be obtained as follows, with Wireshark installed:

    & "C:\Program Files\Wireshark\tshark.exe" -D

Implementation in "pcap_osdep_windows.c" does some guesswork to convert
between variants of an interface name. Microsoft experts and interested
users, please take a look and/or give it a try in your environment.

[1]: https://nmap.org/npcap
[2]: https://github.com/nmap/npcap/issues/299
[3]: https://mesonbuild.com/Reference-manual.html#compiler-object

Depends-on: series-15801 ("eal/windows: do not expose POSIX symbols")
Depends-on: patch-89639 ("[v2,3/3] meson: remove unnecessary explicit link to libpcap")

v3:
    * Use environment and pkg-config to locate libpcap (Bruce).
    * Use C11 timespec_get() instead of EAL wrapper.
    * Drop libpcap wrappers in net/pcap (Ferruh).

Dmitry Kozlyuk (3):
  eal/windows: add timespec_get shim for MinGW
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows

 config/meson.build                            |   3 +-
 doc/guides/rel_notes/release_21_05.rst        |   4 +
 drivers/net/pcap/meson.build                  |  16 +--
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 109 +++-------------
 drivers/net/pcap/pcap_osdep.h                 |  18 +++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 +++++++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
 drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++++++++++++
 .../windows/include/rte_os_internal.h         |  32 +++++
 9 files changed, 303 insertions(+), 98 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

-- 
2.29.3

[dpdk-dev] [PATCH v3 1/3] eal/windows: add timespec_get shim for MinGW

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-24 00:50:32

MinGW-w64 does not currently implement C11 timespec_get.
Add an internal shim until this is fixed on MinGW side.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 .../windows/include/rte_os_internal.h         | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)
diff --git a/lib/librte_eal/windows/include/rte_os_internal.h b/lib/librte_eal/windows/include/rte_os_internal.h
index 89ac5c9cbd..df37eb6cf7 100644
--- a/lib/librte_eal/windows/include/rte_os_internal.h
+++ b/lib/librte_eal/windows/include/rte_os_internal.h
@@ -3,7 +3,10 @@
 #ifndef _RTE_OS_INTERNAL_H_
 #define _RTE_OS_INTERNAL_H_
 
+#include <time.h>
+
 #include <rte_os.h>
+#include <rte_windows.h>
 
 /**
  * @file
@@ -33,4 +36,33 @@
 #define IPPROTO_SCTP	132
 #endif
 
+#ifdef RTE_TOOLCHAIN_GCC
+
+#define TIME_UTC 1
+
+static inline int
+rte_timespec_get(struct timespec *now, int base)
+{
+	/* 100ns ticks from 1601-01-01 to 1970-01-01 */
+	static const uint64_t EPOCH = 116444736000000000ULL;
+	static const uint64_t TICKS_PER_SEC = 10000000;
+	static const uint64_t NS_PER_TICK = 100;
+
+	FILETIME ft;
+	uint64_t ticks;
+
+	if (base != TIME_UTC)
+		return 0;
+
+	GetSystemTimePreciseAsFileTime(&ft);
+	ticks = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+	ticks -= EPOCH;
+	now->tv_sec = ticks / TICKS_PER_SEC;
+	now->tv_nsec = (ticks - now->tv_sec * TICKS_PER_SEC) * NS_PER_TICK;
+	return base;
+}
+
+#define timespec_get(ts, base) rte_timespec_get(ts, base)
+
+#endif /* RTE_TOOLCHAIN_GCC */
 #endif /* _RTE_OS_INTERNAL_H_ */
-- 
2.29.3

[dpdk-dev] [PATCH v3 2/3] net/pcap: move OS-dependent code to separate files

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-24 00:50:39

PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. This PMD also depends on
POSIX bits, namely gettimeofday() and NAME_MAX.

Move OS-dependent code to separate files.
Replace POSIX bits with DPDK equivalents.
Rename rte_eth_pcap.c to pcap_ethdev.c, like it is in most other PMDs.

Signed-off-by: Dmitry Kozlyuk <redacted>
Reviewed-by: Ferruh Yigit <redacted>
---
 drivers/net/pcap/meson.build                  |   5 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 105 ++++--------------
 drivers/net/pcap/pcap_osdep.h                 |  13 +++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 ++++++++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
 5 files changed, 137 insertions(+), 87 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index b65d91e70a..26b6066990 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -11,5 +11,8 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
-sources = files('rte_eth_pcap.c')
+sources = files(
+	'pcap_ethdev.c',
+	'pcap_osdep_@0@.c'.format(exec_env),
+)
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/pcap_ethdev.c
similarity index 95%
rename from drivers/net/pcap/rte_eth_pcap.c
rename to drivers/net/pcap/pcap_ethdev.c
index 28a5027315..1578de1204 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -6,16 +6,6 @@
 
 #include <time.h>
 
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#if defined(RTE_EXEC_ENV_FREEBSD)
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#endif
-
 #include <pcap.h>
 
 #include <rte_cycles.h>
@@ -25,7 +15,9 @@
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_bus_vdev.h>
-#include <rte_string_fns.h>
+#include <rte_os_internal.h>
+
+#include "pcap_osdep.h"
 
 #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
 #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
@@ -46,7 +38,7 @@
 #define RTE_PMD_PCAP_MAX_QUEUES 16
 
 static char errbuf[PCAP_ERRBUF_SIZE];
-static struct timeval start_time;
+static struct timespec start_time;
 static uint64_t start_cycles;
 static uint64_t hz;
 static uint8_t iface_idx;
@@ -354,17 +346,21 @@ eth_null_rx(void *queue __rte_unused,
 
 #define NSEC_PER_SEC	1000000000L
 
+/*
+ * This function stores nanoseconds in `tv_usec` field of `struct timeval`,
+ * because `ts` goes directly to nanosecond-precision dump.
+ */
 static inline void
 calculate_timestamp(struct timeval *ts) {
 	uint64_t cycles;
-	struct timeval cur_time;
+	struct timespec cur_time;
 
 	cycles = rte_get_timer_cycles() - start_cycles;
 	cur_time.tv_sec = cycles / hz;
-	cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz;
+	cur_time.tv_nsec = (cycles % hz) * NSEC_PER_SEC / hz;
 
 	ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
-	ts->tv_usec = start_time.tv_usec + cur_time.tv_usec;
+	ts->tv_usec = start_time.tv_nsec + cur_time.tv_nsec;
 	if (ts->tv_usec >= NSEC_PER_SEC) {
 		ts->tv_usec -= NSEC_PER_SEC;
 		ts->tv_sec += 1;
@@ -883,7 +879,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 	if (internals->infinite_rx) {
 		struct pmd_process_private *pp;
-		char ring_name[NAME_MAX];
+		char ring_name[RTE_RING_NAMESIZE];
 		static uint32_t ring_number;
 		uint64_t pcap_pkt_count = 0;
 		struct rte_mbuf *bufs[1];
@@ -1261,84 +1257,20 @@ static int
 eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
 		const unsigned int numa_node)
 {
-#if defined(RTE_EXEC_ENV_LINUX)
 	void *mac_addrs;
-	struct ifreq ifr;
-	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-	if (if_fd == -1)
-		return -1;
+	struct rte_ether_addr mac;
 
-	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
-	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
-		close(if_fd);
+	if (osdep_iface_mac_get(if_name, &mac) < 0)
 		return -1;
-	}
 
 	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		close(if_fd);
+	if (mac_addrs == NULL)
 		return -1;
-	}
 
 	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
+	rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
 	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
-
-	close(if_fd);
-
-	return 0;
-
-#elif defined(RTE_EXEC_ENV_FREEBSD)
-	void *mac_addrs;
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	int mib[6];
-	size_t len = 0;
-	char *buf;
-
-	mib[0] = CTL_NET;
-	mib[1] = AF_ROUTE;
-	mib[2] = 0;
-	mib[3] = AF_LINK;
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = if_nametoindex(if_name);
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-
-	if (len == 0)
-		return -1;
-
-	buf = rte_malloc(NULL, len, 0);
-	if (!buf)
-		return -1;
-
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		rte_free(buf);
-		return -1;
-	}
-	ifm = (struct if_msghdr *)buf;
-	sdl = (struct sockaddr_dl *)(ifm + 1);
-
-	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		rte_free(buf);
-		return -1;
-	}
-
-	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
-	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			LLADDR(sdl), RTE_ETHER_ADDR_LEN);
-
-	rte_free(buf);
-
 	return 0;
-#else
-	return -1;
-#endif
 }
 
 static int
@@ -1400,7 +1332,8 @@ eth_from_pcaps(struct rte_vdev_device *vdev,
 	internals->single_iface = single_iface;
 
 	if (single_iface) {
-		internals->if_index = if_nametoindex(rx_queues->queue[0].name);
+		internals->if_index =
+			osdep_iface_index_get(rx_queues->queue[0].name);
 
 		/* phy_mac arg is applied only only if "iface" devarg is provided */
 		if (rx_queues->phy_mac) {
@@ -1453,7 +1386,7 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
 	name = rte_vdev_device_name(dev);
 	PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
 
-	gettimeofday(&start_time, NULL);
+	timespec_get(&start_time, TIME_UTC);
 	start_cycles = rte_get_timer_cycles();
 	hz = rte_get_timer_hz();
 
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
new file mode 100644
index 0000000000..9de422ab8d
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#ifndef _RTE_PCAP_OSDEP_
+#define _RTE_PCAP_OSDEP_
+
+#include <rte_ether.h>
+
+int osdep_iface_index_get(const char *name);
+int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
+
+#endif
diff --git a/drivers/net/pcap/pcap_osdep_freebsd.c b/drivers/net/pcap/pcap_osdep_freebsd.c
new file mode 100644
index 0000000000..20556b3e92
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_freebsd.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/sysctl.h>
+
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	int mib[6];
+	size_t len = 0;
+	char *buf;
+
+	mib[0] = CTL_NET;
+	mib[1] = AF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_LINK;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = if_nametoindex(if_name);
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+
+	if (len == 0)
+		return -1;
+
+	buf = rte_malloc(NULL, len, 0);
+	if (!buf)
+		return -1;
+
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		rte_free(buf);
+		return -1;
+	}
+	ifm = (struct if_msghdr *)buf;
+	sdl = (struct sockaddr_dl *)(ifm + 1);
+
+	rte_memcpy(mac->addr_bytes, LLADDR(sdl), RTE_ETHER_ADDR_LEN);
+
+	rte_free(buf);
+	return 0;
+}
diff --git a/drivers/net/pcap/pcap_osdep_linux.c b/drivers/net/pcap/pcap_osdep_linux.c
new file mode 100644
index 0000000000..97033f57c5
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_linux.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <rte_memcpy.h>
+#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct ifreq ifr;
+	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (if_fd == -1)
+		return -1;
+
+	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
+		close(if_fd);
+		return -1;
+	}
+
+	rte_memcpy(mac->addr_bytes, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
+
+	close(if_fd);
+	return 0;
+}
-- 
2.29.3

[dpdk-dev] [PATCH v3 3/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-03-24 00:50:46

Implement OS-dependent functions and enable build for Windows.
Account for different library name in Windows libpcap distributions.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
 config/meson.build                     |   3 +-
 doc/guides/rel_notes/release_21_05.rst |   4 +
 drivers/net/pcap/meson.build           |  11 ++-
 drivers/net/pcap/pcap_ethdev.c         |   4 -
 drivers/net/pcap/pcap_osdep.h          |   5 ++
 drivers/net/pcap/pcap_osdep_windows.c  | 118 +++++++++++++++++++++++++
 6 files changed, 134 insertions(+), 11 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c
diff --git a/config/meson.build b/config/meson.build
index 95777cf331..a15731cfc6 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -179,7 +179,8 @@ endif
 pcap_dep = dependency('libpcap', required: false, method: 'pkg-config')
 if not pcap_dep.found()
 	# pcap got a pkg-config file only in 1.9.0
-	pcap_dep = cc.find_library('pcap', required: false)
+	pcap_lib = is_windows ? 'wpcap' : 'pcap'
+	pcap_dep = cc.find_library(pcap_lib, required: false)
 endif
 if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
 	dpdk_conf.set('RTE_PORT_PCAP', 1)
diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index 8e686cc627..ae78273075 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -101,6 +101,10 @@ New Features
   * Added command to display Rx queue used descriptor count.
     ``show port (port_id) rxq (queue_id) desc used count``
 
+* **Enabled libpcap-based PMD on Windows.**
+
+   A libpcap distribution, such as Npcap or WinPcap, is required to run the PMD.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 26b6066990..63ad3f34f0 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -1,18 +1,17 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-if is_windows
-	build = false
-	reason = 'not supported on Windows'
-	subdir_done()
-endif
-
 if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
+
 sources = files(
 	'pcap_ethdev.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
+
 ext_deps += pcap_dep
+if is_windows
+	ext_deps += cc.find_library('iphlpapi', required: true)
+endif
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 1578de1204..875b736e97 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -142,10 +142,6 @@ static struct rte_eth_link pmd_link = {
 
 RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
-#define PMD_LOG(level, fmt, args...) \
-	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
-		"%s(): " fmt "\n", __func__, ##args)
-
 static struct queue_missed_stat*
 queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
 {
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index 9de422ab8d..bf41cba982 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -7,6 +7,11 @@
 
 #include <rte_ether.h>
 
+#define PMD_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
+		"%s(): " fmt "\n", __func__, ##args)
+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);
 
diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c
new file mode 100644
index 0000000000..1d398dc7ed
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_windows.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <strsafe.h>
+
+#include "pcap_osdep.h"
+
+/*
+ * Given a device name like "\Device\NPF_{GUID}" extract the "{GUID}" part.
+ * Return NULL if "{GUID}" part is not found.
+ */
+static const char *
+iface_guid(const char *name)
+{
+	static const size_t GUID_LENGTH = 32 + 4; /* 16 hex bytes + 4 dashes */
+
+	const char *ob, *cb;
+
+	ob = strchr(name, '{');
+	if (ob == NULL)
+		return NULL;
+
+	cb = strchr(ob, '}');
+	if (cb == NULL || cb - ob != GUID_LENGTH + 1) /* + 1 opening '{' */
+		return NULL;
+
+	return ob;
+}
+
+/*
+ * libpcap takes device names like "\Device\NPF_{GUID}",
+ * GetAdapterIndex() takes interface names like "\DEVICE\TCPIP_{GUID}".
+ * Try to convert, fall back to original device name.
+ */
+int
+osdep_iface_index_get(const char *device_name)
+{
+	WCHAR adapter_name[MAX_ADAPTER_NAME_LENGTH];
+	const char *guid;
+	ULONG index;
+	DWORD ret;
+
+	guid = iface_guid(device_name);
+	if (guid != NULL)
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"\\DEVICE\\TCPIP_%S", guid);
+	else
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"%S", device_name);
+
+	ret = GetAdapterIndex(adapter_name, &index);
+	if (ret != NO_ERROR) {
+		PMD_LOG(ERR, "GetAdapterIndex(%S) = %lu\n", adapter_name, ret);
+		return -1;
+	}
+
+	return index;
+}
+
+/*
+ * 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;
+	ULONG size, sys_ret;
+	const char *adapter_name;
+	int ret = -1;
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+	if (sys_ret != ERROR_BUFFER_OVERFLOW) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n",
+			sys_ret, ERROR_BUFFER_OVERFLOW);
+		return -1;
+	}
+
+	info = (IP_ADAPTER_ADDRESSES *)malloc(size);
+	if (info == NULL) {
+		PMD_LOG(ERR, "Cannot allocate adapter address info\n");
+		return -1;
+	}
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size);
+	if (sys_ret != ERROR_SUCCESS) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret);
+		free(info);
+		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) {
+			if (cur->PhysicalAddressLength != RTE_ETHER_ADDR_LEN) {
+				PMD_LOG(ERR, "Physical address length: want %u, got %lu",
+					RTE_ETHER_ADDR_LEN,
+					cur->PhysicalAddressLength);
+				break;
+			}
+
+			memcpy(mac->addr_bytes, cur->PhysicalAddress,
+				RTE_ETHER_ADDR_LEN);
+			ret = 0;
+			break;
+		}
+	}
+
+	free(info);
+	return ret;
+}
-- 
2.29.3

Re: [dpdk-dev] [PATCH v3 0/3] net/pcap: build on Windows

From: Ferruh Yigit <hidden>
Date: 2021-04-09 10:52:00

On 3/24/2021 12:50 AM, Dmitry Kozlyuk wrote:
NOTE: dependency patches are requirements, CI may fail.

Most modern and actively maintained distribution of libpcap for Windows
is Npcap [1]. It currently doesn't provide a pkg-config file [2].
By default it is installed to C:\Program Files\Npcap and can be located
using standard environment variables [3]:

     $env:C_INCLUDE_PATH += ";C:\Program Files\Npcap"
     $env:LIBRARY_PATH += ";C:\Program Files\Npcap\Lib\x64"     # MinGW
     $env:LINK += ' /LIBPATH:"C:\Program Files\Npcap\Lib\x64"'  # Clang

The following libpcap.pc also works if placed in PKG_CONFIG_PATH:

     prefix="C:/Program Files/Npcap"
     Name: libpcap
     Version: 1.10
     Description: Platform-independent network traffic capture library
     Cflags: -I${prefix}/Include
     Libs: -L${prefix}/Lib/x64 -lwpcap

Example of collecting packets from an interface to a file:

     .\build\examples\dpdk-skeleton.exe `
         --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
         --vdev "eth_pcap1,tx_pcap=capture.pcap"

Interface name can be obtained as follows, with Wireshark installed:

     & "C:\Program Files\Wireshark\tshark.exe" -D

Implementation in "pcap_osdep_windows.c" does some guesswork to convert
between variants of an interface name. Microsoft experts and interested
users, please take a look and/or give it a try in your environment.

[1]: https://nmap.org/npcap
[2]: https://github.com/nmap/npcap/issues/299
[3]: https://mesonbuild.com/Reference-manual.html#compiler-object

Depends-on: series-15801 ("eal/windows: do not expose POSIX symbols")
Depends-on: patch-89639 ("[v2,3/3] meson: remove unnecessary explicit link to libpcap")
Hi Dmitry,

What is the status of the dependent patches, are they merged?
v3:
     * Use environment and pkg-config to locate libpcap (Bruce).
     * Use C11 timespec_get() instead of EAL wrapper.
     * Drop libpcap wrappers in net/pcap (Ferruh).

Dmitry Kozlyuk (3):
   eal/windows: add timespec_get shim for MinGW
   net/pcap: move OS-dependent code to separate files
   net/pcap: build on Windows

  config/meson.build                            |   3 +-
  doc/guides/rel_notes/release_21_05.rst        |   4 +
  drivers/net/pcap/meson.build                  |  16 +--
  .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 109 +++-------------
  drivers/net/pcap/pcap_osdep.h                 |  18 +++
  drivers/net/pcap/pcap_osdep_freebsd.c         |  59 +++++++++
  drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
  drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++++++++++++
  .../windows/include/rte_os_internal.h         |  32 +++++
  9 files changed, 303 insertions(+), 98 deletions(-)
  rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
  create mode 100644 drivers/net/pcap/pcap_osdep.h
  create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
  create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
  create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

Re: [dpdk-dev] [PATCH v3 0/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-09 11:03:41

2021-04-09 11:51 (UTC+0100), Ferruh Yigit:
On 3/24/2021 12:50 AM, Dmitry Kozlyuk wrote:
[...]
quoted
Depends-on: series-15801 ("eal/windows: do not expose POSIX symbols")
Depends-on: patch-89639 ("[v2,3/3] meson: remove unnecessary explicit link to libpcap")
  
Hi Dmitry,

What is the status of the dependent patches, are they merged?
Hi Ferruh,

Not yet, but reviews are progressing.
series-15801 has some acks and no pending changes, probably close to merge.
AFAIK, Thomas is now reviewing patch-89639 to improve its description.
This series will need a v4 for trivial rebase and to trigger a CI run.

Re: [dpdk-dev] [PATCH v3 0/3] net/pcap: build on Windows

From: Ferruh Yigit <hidden>
Date: 2021-04-09 11:25:03

On 4/9/2021 12:03 PM, Dmitry Kozlyuk wrote:
2021-04-09 11:51 (UTC+0100), Ferruh Yigit:
quoted
On 3/24/2021 12:50 AM, Dmitry Kozlyuk wrote:
[...]
quoted
quoted
Depends-on: series-15801 ("eal/windows: do not expose POSIX symbols")
Depends-on: patch-89639 ("[v2,3/3] meson: remove unnecessary explicit link to libpcap")
   
Hi Dmitry,

What is the status of the dependent patches, are they merged?
Hi Ferruh,

Not yet, but reviews are progressing.
series-15801 has some acks and no pending changes, probably close to merge.
AFAIK, Thomas is now reviewing patch-89639 to improve its description.
This series will need a v4 for trivial rebase and to trigger a CI run.
Thanks Dmitry, cc'ed Thomas.

[dpdk-dev] [PATCH v4 0/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-15 22:11:06

Most modern and actively maintained distribution of libpcap for Windows
is Npcap [1]. It currently doesn't provide a pkg-config file [2].
By default it is installed to C:\Program Files\Npcap and can be located
using standard environment variables [3]:

    $env:C_INCLUDE_PATH += ";C:\Program Files\Npcap"
    $env:LIBRARY_PATH += ";C:\Program Files\Npcap\Lib\x64"     # MinGW
    $env:LINK += ' /LIBPATH:"C:\Program Files\Npcap\Lib\x64"'  # Clang

The following libpcap.pc also works if placed in PKG_CONFIG_PATH:

    prefix="C:/Program Files/Npcap"
    Name: libpcap
    Version: 1.10
    Description: Platform-independent network traffic capture library
    Cflags: -I${prefix}/Include
    Libs: -L${prefix}/Lib/x64 -lwpcap

Example of collecting packets from an interface to a file:

    .\build\examples\dpdk-skeleton.exe `
        --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
        --vdev "eth_pcap1,tx_pcap=capture.pcap"

Interface name can be obtained as follows, with Wireshark installed:

    & "C:\Program Files\Wireshark\tshark.exe" -D

Implementation in "pcap_osdep_windows.c" does some guesswork to convert
between variants of an interface name. Microsoft experts and interested
users, please take a look and/or give it a try in your environment.

[1]: https://nmap.org/npcap
[2]: https://github.com/nmap/npcap/issues/299
[3]: https://mesonbuild.com/Reference-manual.html#compiler-object

v4:
    * Change libpcap discovery to work without dependent patch.
    * Fix memory leak in osdep_iface_mac_get (in v3, actually).
    * rte_os_internal.h -> rte_os_shim.h in patch 3/3.

Dmitry Kozlyuk (3):
  eal/windows: add timespec_get shim for MinGW
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows

 config/meson.build                            |   5 +-
 doc/guides/rel_notes/release_21_05.rst        |   4 +
 drivers/net/pcap/meson.build                  |  16 +--
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 109 +++-------------
 drivers/net/pcap/pcap_osdep.h                 |  18 +++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 +++++++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
 drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++++++++++++
 lib/librte_eal/windows/include/rte_os_shim.h  |  32 +++++
 9 files changed, 304 insertions(+), 99 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

-- 
2.29.3

[dpdk-dev] [PATCH v4 1/3] eal/windows: add timespec_get shim for MinGW

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-15 22:11:11

MinGW-w64 does not currently implement C11 timespec_get.
Add an internal shim until this is fixed on MinGW side.

Signed-off-by: Dmitry Kozlyuk <redacted>
Acked-by: Jie Zhou <redacted>
Acked-by: Nick Connolly <redacted>
---
 lib/librte_eal/windows/include/rte_os_shim.h | 32 ++++++++++++++++++++
 1 file changed, 32 insertions(+)
diff --git a/lib/librte_eal/windows/include/rte_os_shim.h b/lib/librte_eal/windows/include/rte_os_shim.h
index f40fb62d1d..e50895fd83 100644
--- a/lib/librte_eal/windows/include/rte_os_shim.h
+++ b/lib/librte_eal/windows/include/rte_os_shim.h
@@ -3,7 +3,10 @@
 #ifndef _RTE_OS_SHIM_
 #define _RTE_OS_SHIM_
 
+#include <time.h>
+
 #include <rte_os.h>
+#include <rte_windows.h>
 
 /**
  * @file
@@ -33,4 +36,33 @@
 #define IPPROTO_SCTP	132
 #endif
 
+#ifdef RTE_TOOLCHAIN_GCC
+
+#define TIME_UTC 1
+
+static inline int
+rte_timespec_get(struct timespec *now, int base)
+{
+	/* 100ns ticks from 1601-01-01 to 1970-01-01 */
+	static const uint64_t EPOCH = 116444736000000000ULL;
+	static const uint64_t TICKS_PER_SEC = 10000000;
+	static const uint64_t NS_PER_TICK = 100;
+
+	FILETIME ft;
+	uint64_t ticks;
+
+	if (base != TIME_UTC)
+		return 0;
+
+	GetSystemTimePreciseAsFileTime(&ft);
+	ticks = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+	ticks -= EPOCH;
+	now->tv_sec = ticks / TICKS_PER_SEC;
+	now->tv_nsec = (ticks - now->tv_sec * TICKS_PER_SEC) * NS_PER_TICK;
+	return base;
+}
+
+#define timespec_get(ts, base) rte_timespec_get(ts, base)
+
+#endif /* RTE_TOOLCHAIN_GCC */
 #endif /* _RTE_OS_SHIM_ */
-- 
2.29.3

[dpdk-dev] [PATCH v4 2/3] net/pcap: move OS-dependent code to separate files

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-15 22:11:17

PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. This PMD also depends on
POSIX bits, namely gettimeofday() and NAME_MAX.

Move OS-dependent code to separate files.
Replace POSIX bits with DPDK equivalents.
Rename rte_eth_pcap.c to pcap_ethdev.c, like it is in most other PMDs.

Signed-off-by: Dmitry Kozlyuk <redacted>
Reviewed-by: Ferruh Yigit <redacted>
---
 drivers/net/pcap/meson.build                  |   5 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 104 +++---------------
 drivers/net/pcap/pcap_osdep.h                 |  13 +++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 ++++++++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
 5 files changed, 136 insertions(+), 87 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index b65d91e70a..26b6066990 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -11,5 +11,8 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
-sources = files('rte_eth_pcap.c')
+sources = files(
+	'pcap_ethdev.c',
+	'pcap_osdep_@0@.c'.format(exec_env),
+)
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/pcap_ethdev.c
similarity index 95%
rename from drivers/net/pcap/rte_eth_pcap.c
rename to drivers/net/pcap/pcap_ethdev.c
index 28a5027315..4ac594eeca 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -6,16 +6,6 @@
 
 #include <time.h>
 
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#if defined(RTE_EXEC_ENV_FREEBSD)
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#endif
-
 #include <pcap.h>
 
 #include <rte_cycles.h>
@@ -25,7 +15,8 @@
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_bus_vdev.h>
-#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
 
 #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
 #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
@@ -46,7 +37,7 @@
 #define RTE_PMD_PCAP_MAX_QUEUES 16
 
 static char errbuf[PCAP_ERRBUF_SIZE];
-static struct timeval start_time;
+static struct timespec start_time;
 static uint64_t start_cycles;
 static uint64_t hz;
 static uint8_t iface_idx;
@@ -354,17 +345,21 @@ eth_null_rx(void *queue __rte_unused,
 
 #define NSEC_PER_SEC	1000000000L
 
+/*
+ * This function stores nanoseconds in `tv_usec` field of `struct timeval`,
+ * because `ts` goes directly to nanosecond-precision dump.
+ */
 static inline void
 calculate_timestamp(struct timeval *ts) {
 	uint64_t cycles;
-	struct timeval cur_time;
+	struct timespec cur_time;
 
 	cycles = rte_get_timer_cycles() - start_cycles;
 	cur_time.tv_sec = cycles / hz;
-	cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz;
+	cur_time.tv_nsec = (cycles % hz) * NSEC_PER_SEC / hz;
 
 	ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
-	ts->tv_usec = start_time.tv_usec + cur_time.tv_usec;
+	ts->tv_usec = start_time.tv_nsec + cur_time.tv_nsec;
 	if (ts->tv_usec >= NSEC_PER_SEC) {
 		ts->tv_usec -= NSEC_PER_SEC;
 		ts->tv_sec += 1;
@@ -883,7 +878,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 	if (internals->infinite_rx) {
 		struct pmd_process_private *pp;
-		char ring_name[NAME_MAX];
+		char ring_name[RTE_RING_NAMESIZE];
 		static uint32_t ring_number;
 		uint64_t pcap_pkt_count = 0;
 		struct rte_mbuf *bufs[1];
@@ -1261,84 +1256,20 @@ static int
 eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
 		const unsigned int numa_node)
 {
-#if defined(RTE_EXEC_ENV_LINUX)
 	void *mac_addrs;
-	struct ifreq ifr;
-	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-	if (if_fd == -1)
-		return -1;
+	struct rte_ether_addr mac;
 
-	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
-	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
-		close(if_fd);
+	if (osdep_iface_mac_get(if_name, &mac) < 0)
 		return -1;
-	}
 
 	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		close(if_fd);
+	if (mac_addrs == NULL)
 		return -1;
-	}
 
 	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
+	rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
 	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
-
-	close(if_fd);
-
-	return 0;
-
-#elif defined(RTE_EXEC_ENV_FREEBSD)
-	void *mac_addrs;
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	int mib[6];
-	size_t len = 0;
-	char *buf;
-
-	mib[0] = CTL_NET;
-	mib[1] = AF_ROUTE;
-	mib[2] = 0;
-	mib[3] = AF_LINK;
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = if_nametoindex(if_name);
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-
-	if (len == 0)
-		return -1;
-
-	buf = rte_malloc(NULL, len, 0);
-	if (!buf)
-		return -1;
-
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		rte_free(buf);
-		return -1;
-	}
-	ifm = (struct if_msghdr *)buf;
-	sdl = (struct sockaddr_dl *)(ifm + 1);
-
-	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		rte_free(buf);
-		return -1;
-	}
-
-	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
-	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			LLADDR(sdl), RTE_ETHER_ADDR_LEN);
-
-	rte_free(buf);
-
 	return 0;
-#else
-	return -1;
-#endif
 }
 
 static int
@@ -1400,7 +1331,8 @@ eth_from_pcaps(struct rte_vdev_device *vdev,
 	internals->single_iface = single_iface;
 
 	if (single_iface) {
-		internals->if_index = if_nametoindex(rx_queues->queue[0].name);
+		internals->if_index =
+			osdep_iface_index_get(rx_queues->queue[0].name);
 
 		/* phy_mac arg is applied only only if "iface" devarg is provided */
 		if (rx_queues->phy_mac) {
@@ -1453,7 +1385,7 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
 	name = rte_vdev_device_name(dev);
 	PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
 
-	gettimeofday(&start_time, NULL);
+	timespec_get(&start_time, TIME_UTC);
 	start_cycles = rte_get_timer_cycles();
 	hz = rte_get_timer_hz();
 
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
new file mode 100644
index 0000000000..9de422ab8d
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#ifndef _RTE_PCAP_OSDEP_
+#define _RTE_PCAP_OSDEP_
+
+#include <rte_ether.h>
+
+int osdep_iface_index_get(const char *name);
+int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
+
+#endif
diff --git a/drivers/net/pcap/pcap_osdep_freebsd.c b/drivers/net/pcap/pcap_osdep_freebsd.c
new file mode 100644
index 0000000000..20556b3e92
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_freebsd.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/sysctl.h>
+
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	int mib[6];
+	size_t len = 0;
+	char *buf;
+
+	mib[0] = CTL_NET;
+	mib[1] = AF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_LINK;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = if_nametoindex(if_name);
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+
+	if (len == 0)
+		return -1;
+
+	buf = rte_malloc(NULL, len, 0);
+	if (!buf)
+		return -1;
+
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		rte_free(buf);
+		return -1;
+	}
+	ifm = (struct if_msghdr *)buf;
+	sdl = (struct sockaddr_dl *)(ifm + 1);
+
+	rte_memcpy(mac->addr_bytes, LLADDR(sdl), RTE_ETHER_ADDR_LEN);
+
+	rte_free(buf);
+	return 0;
+}
diff --git a/drivers/net/pcap/pcap_osdep_linux.c b/drivers/net/pcap/pcap_osdep_linux.c
new file mode 100644
index 0000000000..97033f57c5
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_linux.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <rte_memcpy.h>
+#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct ifreq ifr;
+	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (if_fd == -1)
+		return -1;
+
+	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
+		close(if_fd);
+		return -1;
+	}
+
+	rte_memcpy(mac->addr_bytes, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
+
+	close(if_fd);
+	return 0;
+}
-- 
2.29.3

[dpdk-dev] [PATCH v4 3/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-15 22:11:22

Implement OS-dependent functions and enable build for Windows.
Account for different library name in Windows libpcap distributions.

Signed-off-by: Dmitry Kozlyuk <redacted>
---
Tyler, IIRC you were reviewing the code?
This patch is the most important one but surprisingly has no acks.
---
 config/meson.build                     |   5 +-
 doc/guides/rel_notes/release_21_05.rst |   4 +
 drivers/net/pcap/meson.build           |  11 ++-
 drivers/net/pcap/pcap_ethdev.c         |   5 +-
 drivers/net/pcap/pcap_osdep.h          |   5 ++
 drivers/net/pcap/pcap_osdep_windows.c  | 118 +++++++++++++++++++++++++
 6 files changed, 136 insertions(+), 12 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c
diff --git a/config/meson.build b/config/meson.build
index 6e6ef8c0e1..6737cc3e26 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -182,13 +182,14 @@ endif
 
 # check for pcap
 pcap_dep = dependency('libpcap', required: false, method: 'pkg-config')
+pcap_lib = is_windows ? 'wpcap' : 'pcap'
 if not pcap_dep.found()
 	# pcap got a pkg-config file only in 1.9.0
-	pcap_dep = cc.find_library('pcap', required: false)
+	pcap_dep = cc.find_library(pcap_lib, required: false)
 endif
 if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
 	dpdk_conf.set('RTE_PORT_PCAP', 1)
-	dpdk_extra_ldflags += '-lpcap'
+	dpdk_extra_ldflags += '-l@0@'.format(pcap_lib)
 endif
 
 # for clang 32-bit compiles we need libatomic for 64-bit atomic ops
diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index 2e3bf5c95a..ed0e23a47b 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -174,6 +174,10 @@ New Features
   * Added command to display Rx queue used descriptor count.
     ``show port (port_id) rxq (queue_id) desc used count``
 
+* **Enabled libpcap-based PMD on Windows.**
+
+   A libpcap distribution, such as Npcap or WinPcap, is required to run the PMD.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 26b6066990..63ad3f34f0 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -1,18 +1,17 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-if is_windows
-	build = false
-	reason = 'not supported on Windows'
-	subdir_done()
-endif
-
 if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
+
 sources = files(
 	'pcap_ethdev.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
+
 ext_deps += pcap_dep
+if is_windows
+	ext_deps += cc.find_library('iphlpapi', required: true)
+endif
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 4ac594eeca..3961843efc 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -15,6 +15,7 @@
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_bus_vdev.h>
+#include <rte_os_shim.h>
 
 #include "pcap_osdep.h"
 
@@ -141,10 +142,6 @@ static struct rte_eth_link pmd_link = {
 
 RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
-#define PMD_LOG(level, fmt, args...) \
-	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
-		"%s(): " fmt "\n", __func__, ##args)
-
 static struct queue_missed_stat*
 queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
 {
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index 9de422ab8d..bf41cba982 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -7,6 +7,11 @@
 
 #include <rte_ether.h>
 
+#define PMD_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
+		"%s(): " fmt "\n", __func__, ##args)
+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);
 
diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c
new file mode 100644
index 0000000000..1d398dc7ed
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_windows.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <strsafe.h>
+
+#include "pcap_osdep.h"
+
+/*
+ * Given a device name like "\Device\NPF_{GUID}" extract the "{GUID}" part.
+ * Return NULL if "{GUID}" part is not found.
+ */
+static const char *
+iface_guid(const char *name)
+{
+	static const size_t GUID_LENGTH = 32 + 4; /* 16 hex bytes + 4 dashes */
+
+	const char *ob, *cb;
+
+	ob = strchr(name, '{');
+	if (ob == NULL)
+		return NULL;
+
+	cb = strchr(ob, '}');
+	if (cb == NULL || cb - ob != GUID_LENGTH + 1) /* + 1 opening '{' */
+		return NULL;
+
+	return ob;
+}
+
+/*
+ * libpcap takes device names like "\Device\NPF_{GUID}",
+ * GetAdapterIndex() takes interface names like "\DEVICE\TCPIP_{GUID}".
+ * Try to convert, fall back to original device name.
+ */
+int
+osdep_iface_index_get(const char *device_name)
+{
+	WCHAR adapter_name[MAX_ADAPTER_NAME_LENGTH];
+	const char *guid;
+	ULONG index;
+	DWORD ret;
+
+	guid = iface_guid(device_name);
+	if (guid != NULL)
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"\\DEVICE\\TCPIP_%S", guid);
+	else
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"%S", device_name);
+
+	ret = GetAdapterIndex(adapter_name, &index);
+	if (ret != NO_ERROR) {
+		PMD_LOG(ERR, "GetAdapterIndex(%S) = %lu\n", adapter_name, ret);
+		return -1;
+	}
+
+	return index;
+}
+
+/*
+ * 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;
+	ULONG size, sys_ret;
+	const char *adapter_name;
+	int ret = -1;
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+	if (sys_ret != ERROR_BUFFER_OVERFLOW) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n",
+			sys_ret, ERROR_BUFFER_OVERFLOW);
+		return -1;
+	}
+
+	info = (IP_ADAPTER_ADDRESSES *)malloc(size);
+	if (info == NULL) {
+		PMD_LOG(ERR, "Cannot allocate adapter address info\n");
+		return -1;
+	}
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size);
+	if (sys_ret != ERROR_SUCCESS) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret);
+		free(info);
+		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) {
+			if (cur->PhysicalAddressLength != RTE_ETHER_ADDR_LEN) {
+				PMD_LOG(ERR, "Physical address length: want %u, got %lu",
+					RTE_ETHER_ADDR_LEN,
+					cur->PhysicalAddressLength);
+				break;
+			}
+
+			memcpy(mac->addr_bytes, cur->PhysicalAddress,
+				RTE_ETHER_ADDR_LEN);
+			ret = 0;
+			break;
+		}
+	}
+
+	free(info);
+	return ret;
+}
-- 
2.29.3

Re: [dpdk-dev] [PATCH v4 0/3] net/pcap: build on Windows

From: Ferruh Yigit <hidden>
Date: 2021-04-16 17:22:15

On 4/15/2021 11:10 PM, Dmitry Kozlyuk wrote:
Most modern and actively maintained distribution of libpcap for Windows
is Npcap [1]. It currently doesn't provide a pkg-config file [2].
By default it is installed to C:\Program Files\Npcap and can be located
using standard environment variables [3]:

     $env:C_INCLUDE_PATH += ";C:\Program Files\Npcap"
     $env:LIBRARY_PATH += ";C:\Program Files\Npcap\Lib\x64"     # MinGW
     $env:LINK += ' /LIBPATH:"C:\Program Files\Npcap\Lib\x64"'  # Clang

The following libpcap.pc also works if placed in PKG_CONFIG_PATH:

     prefix="C:/Program Files/Npcap"
     Name: libpcap
     Version: 1.10
     Description: Platform-independent network traffic capture library
     Cflags: -I${prefix}/Include
     Libs: -L${prefix}/Lib/x64 -lwpcap

Example of collecting packets from an interface to a file:

     .\build\examples\dpdk-skeleton.exe `
         --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
         --vdev "eth_pcap1,tx_pcap=capture.pcap"

Interface name can be obtained as follows, with Wireshark installed:

     & "C:\Program Files\Wireshark\tshark.exe" -D

Implementation in "pcap_osdep_windows.c" does some guesswork to convert
between variants of an interface name. Microsoft experts and interested
users, please take a look and/or give it a try in your environment.

[1]: https://nmap.org/npcap
[2]: https://github.com/nmap/npcap/issues/299
[3]: https://mesonbuild.com/Reference-manual.html#compiler-object

v4:
     * Change libpcap discovery to work without dependent patch.
     * Fix memory leak in osdep_iface_mac_get (in v3, actually).
     * rte_os_internal.h -> rte_os_shim.h in patch 3/3.

Dmitry Kozlyuk (3):
   eal/windows: add timespec_get shim for MinGW
   net/pcap: move OS-dependent code to separate files
   net/pcap: build on Windows

Hi Dmitry,

Since the dependent patches merged, I checked/tested the set and it looks good 
to me, pcap patch already has my review tag.

But not able to test the pcap on Windows. Because if Windows & eal part of the 
patch, I am delegating it to Thomas in patchwork.
  config/meson.build                            |   5 +-
  doc/guides/rel_notes/release_21_05.rst        |   4 +
  drivers/net/pcap/meson.build                  |  16 +--
  .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 109 +++-------------
  drivers/net/pcap/pcap_osdep.h                 |  18 +++
  drivers/net/pcap/pcap_osdep_freebsd.c         |  59 +++++++++
  drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
  drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++++++++++++
  lib/librte_eal/windows/include/rte_os_shim.h  |  32 +++++
  9 files changed, 304 insertions(+), 99 deletions(-)
  rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
  create mode 100644 drivers/net/pcap/pcap_osdep.h
  create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
  create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
  create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

Re: [dpdk-dev] [PATCH v4 3/3] net/pcap: build on Windows

From: Tyler Retzlaff <hidden>
Date: 2021-04-19 21:05:12

On Fri, Apr 16, 2021 at 01:10:55AM +0300, Dmitry Kozlyuk wrote:
Implement OS-dependent functions and enable build for Windows.
Account for different library name in Windows libpcap distributions.

Signed-off-by: Dmitry Kozlyuk <redacted>
Acked-by: Tyler Retzlaff <redacted>
quoted hunk
---
Tyler, IIRC you were reviewing the code?
This patch is the most important one but surprisingly has no acks.
---
 config/meson.build                     |   5 +-
 doc/guides/rel_notes/release_21_05.rst |   4 +
 drivers/net/pcap/meson.build           |  11 ++-
 drivers/net/pcap/pcap_ethdev.c         |   5 +-
 drivers/net/pcap/pcap_osdep.h          |   5 ++
 drivers/net/pcap/pcap_osdep_windows.c  | 118 +++++++++++++++++++++++++
 6 files changed, 136 insertions(+), 12 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c
diff --git a/config/meson.build b/config/meson.build
index 6e6ef8c0e1..6737cc3e26 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -182,13 +182,14 @@ endif
 
 # check for pcap
 pcap_dep = dependency('libpcap', required: false, method: 'pkg-config')
+pcap_lib = is_windows ? 'wpcap' : 'pcap'
 if not pcap_dep.found()
 	# pcap got a pkg-config file only in 1.9.0
-	pcap_dep = cc.find_library('pcap', required: false)
+	pcap_dep = cc.find_library(pcap_lib, required: false)
 endif
 if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
 	dpdk_conf.set('RTE_PORT_PCAP', 1)
-	dpdk_extra_ldflags += '-lpcap'
+	dpdk_extra_ldflags += '-l@0@'.format(pcap_lib)
 endif
 
 # for clang 32-bit compiles we need libatomic for 64-bit atomic ops
diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index 2e3bf5c95a..ed0e23a47b 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -174,6 +174,10 @@ New Features
   * Added command to display Rx queue used descriptor count.
     ``show port (port_id) rxq (queue_id) desc used count``
 
+* **Enabled libpcap-based PMD on Windows.**
+
+   A libpcap distribution, such as Npcap or WinPcap, is required to run the PMD.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 26b6066990..63ad3f34f0 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -1,18 +1,17 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-if is_windows
-	build = false
-	reason = 'not supported on Windows'
-	subdir_done()
-endif
-
 if not dpdk_conf.has('RTE_PORT_PCAP')
 	build = false
 	reason = 'missing dependency, "libpcap"'
 endif
+
 sources = files(
 	'pcap_ethdev.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
+
 ext_deps += pcap_dep
+if is_windows
+	ext_deps += cc.find_library('iphlpapi', required: true)
+endif
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 4ac594eeca..3961843efc 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -15,6 +15,7 @@
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_bus_vdev.h>
+#include <rte_os_shim.h>
 
 #include "pcap_osdep.h"
 
@@ -141,10 +142,6 @@ static struct rte_eth_link pmd_link = {
 
 RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
-#define PMD_LOG(level, fmt, args...) \
-	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
-		"%s(): " fmt "\n", __func__, ##args)
-
 static struct queue_missed_stat*
 queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
 {
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index 9de422ab8d..bf41cba982 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -7,6 +7,11 @@
 
 #include <rte_ether.h>
 
+#define PMD_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
+		"%s(): " fmt "\n", __func__, ##args)
+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);
 
diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c
new file mode 100644
index 0000000000..1d398dc7ed
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_windows.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <strsafe.h>
+
+#include "pcap_osdep.h"
+
+/*
+ * Given a device name like "\Device\NPF_{GUID}" extract the "{GUID}" part.
+ * Return NULL if "{GUID}" part is not found.
+ */
+static const char *
+iface_guid(const char *name)
+{
+	static const size_t GUID_LENGTH = 32 + 4; /* 16 hex bytes + 4 dashes */
+
+	const char *ob, *cb;
+
+	ob = strchr(name, '{');
+	if (ob == NULL)
+		return NULL;
+
+	cb = strchr(ob, '}');
+	if (cb == NULL || cb - ob != GUID_LENGTH + 1) /* + 1 opening '{' */
+		return NULL;
+
+	return ob;
+}
+
+/*
+ * libpcap takes device names like "\Device\NPF_{GUID}",
+ * GetAdapterIndex() takes interface names like "\DEVICE\TCPIP_{GUID}".
+ * Try to convert, fall back to original device name.
+ */
+int
+osdep_iface_index_get(const char *device_name)
+{
+	WCHAR adapter_name[MAX_ADAPTER_NAME_LENGTH];
+	const char *guid;
+	ULONG index;
+	DWORD ret;
+
+	guid = iface_guid(device_name);
+	if (guid != NULL)
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"\\DEVICE\\TCPIP_%S", guid);
+	else
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"%S", device_name);
+
+	ret = GetAdapterIndex(adapter_name, &index);
+	if (ret != NO_ERROR) {
+		PMD_LOG(ERR, "GetAdapterIndex(%S) = %lu\n", adapter_name, ret);
+		return -1;
+	}
+
+	return index;
+}
+
+/*
+ * 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;
+	ULONG size, sys_ret;
+	const char *adapter_name;
+	int ret = -1;
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+	if (sys_ret != ERROR_BUFFER_OVERFLOW) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n",
+			sys_ret, ERROR_BUFFER_OVERFLOW);
+		return -1;
+	}
+
+	info = (IP_ADAPTER_ADDRESSES *)malloc(size);
+	if (info == NULL) {
+		PMD_LOG(ERR, "Cannot allocate adapter address info\n");
+		return -1;
+	}
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size);
+	if (sys_ret != ERROR_SUCCESS) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret);
+		free(info);
+		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) {
+			if (cur->PhysicalAddressLength != RTE_ETHER_ADDR_LEN) {
+				PMD_LOG(ERR, "Physical address length: want %u, got %lu",
+					RTE_ETHER_ADDR_LEN,
+					cur->PhysicalAddressLength);
+				break;
+			}
+
+			memcpy(mac->addr_bytes, cur->PhysicalAddress,
+				RTE_ETHER_ADDR_LEN);
+			ret = 0;
+			break;
+		}
+	}
+
+	free(info);
+	return ret;
+}
-- 
2.29.3

Re: [dpdk-dev] [PATCH v4 0/3] net/pcap: build on Windows

From: Thomas Monjalon <hidden>
Date: 2021-04-20 22:20:09

Dmitry Kozlyuk (3):
  eal/windows: add timespec_get shim for MinGW
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows
Compilation is failing on FreeBSD 11:
http://mails.dpdk.org/archives/test-report/2021-April/188997.html
	implicit declaration of function 'timespec_get' is invalid in C99
	use of undeclared identifier 'TIME_UTC'

It should be fixed by including time.h

I cannot reproduce the issue with FreeBSD 12.


Re: [dpdk-dev] [PATCH v4 0/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-21 14:53:07

2021-04-21 00:20 (UTC+0200), Thomas Monjalon:
quoted
Dmitry Kozlyuk (3):
  eal/windows: add timespec_get shim for MinGW
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows  
Compilation is failing on FreeBSD 11:
http://mails.dpdk.org/archives/test-report/2021-April/188997.html
	implicit declaration of function 'timespec_get' is invalid in C99
	use of undeclared identifier 'TIME_UTC'

It should be fixed by including time.h 
No, FreeBSD 11 is missing timespec_get indeed.
I cannot reproduce the issue with FreeBSD 12.
After adding a FreeBSD 11 shim and rebasing over "main"
I get another error unrelated to the patch.
It seems FreeBSD 11 is missing pthread_setname_np() as well.

[11/1847] Compiling C object lib/librte_telemetry.a.p/telemetry_telemetry.c.o
../src/lib/telemetry/telemetry.c:445:2: warning: implicit declaration of function 'pthread_setname_np' is invalid in C99 [-Wimplicit-function-declaration]
        pthread_setname_np(t_old, "telemetry-v1");
        ^
../src/lib/telemetry/telemetry.c:474:2: warning: implicit declaration of function 'pthread_setname_np' is invalid in C99 [-Wimplicit-function-declaration]
        pthread_setname_np(t_new, "telemetry-v2");
        ^
2 warnings generated.
[60/1847] Linking target lib/librte_telemetry.so.21.2
FAILED: lib/librte_telemetry.so.21.2 
cc  -o lib/librte_telemetry.so.21.2 lib/librte_telemetry.a.p/telemetry_telemetry.c.o lib/librte_telemetry.a.p/telemetry_telemetry_data.c.o lib/librte_telemetry.a.p/telemetry_telemetry_legacy.c.o -Wl,--as-needed -Wl,--no-undefined -Wl,-O1 -shared -fPIC -Wl,--start-group -Wl,-soname,librte_telemetry.so.21 -Wl,--no-as-needed -pthread -lm -lexecinfo -Wl,--end-group -Wl,--version-script=/tmp/src/lib/telemetry/version.map
lib/librte_telemetry.a.p/telemetry_telemetry.c.o: In function `rte_telemetry_init':
telemetry.c:(.text.internal+0x15a): undefined reference to `pthread_setname_np'
telemetry.c:(.text.internal+0x24d): undefined reference to `pthread_setname_np'
cc: error: linker command failed with exit code 1 (use -v to see invocation)

Re: [dpdk-dev] [PATCH v4 0/3] net/pcap: build on Windows

From: Thomas Monjalon <hidden>
Date: 2021-04-21 18:13:05

21/04/2021 16:53, Dmitry Kozlyuk:
2021-04-21 00:20 (UTC+0200), Thomas Monjalon:
quoted
quoted
Dmitry Kozlyuk (3):
  eal/windows: add timespec_get shim for MinGW
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows  
Compilation is failing on FreeBSD 11:
http://mails.dpdk.org/archives/test-report/2021-April/188997.html
	implicit declaration of function 'timespec_get' is invalid in C99
	use of undeclared identifier 'TIME_UTC'

It should be fixed by including time.h 
No, FreeBSD 11 is missing timespec_get indeed.
quoted
I cannot reproduce the issue with FreeBSD 12.
After adding a FreeBSD 11 shim and rebasing over "main"
I get another error unrelated to the patch.
It seems FreeBSD 11 is missing pthread_setname_np() as well.

[11/1847] Compiling C object lib/librte_telemetry.a.p/telemetry_telemetry.c.o
../src/lib/telemetry/telemetry.c:445:2: warning: implicit declaration of function 'pthread_setname_np' is invalid in C99 [-Wimplicit-function-declaration]
        pthread_setname_np(t_old, "telemetry-v1");
        ^
../src/lib/telemetry/telemetry.c:474:2: warning: implicit declaration of function 'pthread_setname_np' is invalid in C99 [-Wimplicit-function-declaration]
        pthread_setname_np(t_new, "telemetry-v2");
        ^
Sorry, that's because I've merged a patch which is failing
with FreeBSD < 12.2 and I missed the CI report.

I am fixing with this patch:
https://patches.dpdk.org/project/dpdk/patch/20210421181157.1634301-1-thomas@monjalon.net/

[dpdk-dev] [PATCH v5 0/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-21 19:34:03

Most modern and actively maintained distribution of libpcap for Windows
is Npcap [1]. It currently doesn't provide a pkg-config file [2].
By default it is installed to C:\Program Files\Npcap and can be located
using standard environment variables [3]:

    $env:C_INCLUDE_PATH += ";C:\Program Files\Npcap"
    $env:LIBRARY_PATH += ";C:\Program Files\Npcap\Lib\x64"     # MinGW
    $env:LINK += ' /LIBPATH:"C:\Program Files\Npcap\Lib\x64"'  # Clang

The following libpcap.pc also works if placed in PKG_CONFIG_PATH:

    prefix="C:/Program Files/Npcap"
    Name: libpcap
    Version: 1.10
    Description: Platform-independent network traffic capture library
    Cflags: -I${prefix}/Include
    Libs: -L${prefix}/Lib/x64 -lwpcap

Example of collecting packets from an interface to a file:

    .\build\examples\dpdk-skeleton.exe `
        --vdev "eth_pcap0,iface=\Device\NPF_{DDD48985-A77C-4FC9-AF48-61E547C8797E}" `
        --vdev "eth_pcap1,tx_pcap=capture.pcap"

Interface name can be obtained as follows, with Wireshark installed:

    & "C:\Program Files\Wireshark\tshark.exe" -D

[1]: https://nmap.org/npcap
[2]: https://github.com/nmap/npcap/issues/299
[3]: https://mesonbuild.com/Reference-manual.html#compiler-object

v5:
    * Add timespec_get() shim for FreeBSD < 12.2 (CI, Thomas).   

Dmitry Kozlyuk (3):
  eal: add timespec_get shim
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows

 config/meson.build                            |   9 +-
 doc/guides/rel_notes/release_21_05.rst        |   4 +
 drivers/net/pcap/meson.build                  |  16 +--
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 109 +++-------------
 drivers/net/pcap/pcap_osdep.h                 |  18 +++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 +++++++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
 drivers/net/pcap/pcap_osdep_windows.c         | 118 ++++++++++++++++++
 lib/eal/freebsd/include/rte_os_shim.h         |  17 +++
 lib/eal/windows/include/rte_os_shim.h         |  32 +++++
 10 files changed, 323 insertions(+), 101 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c

-- 
2.29.3

[dpdk-dev] [PATCH v5 1/3] eal: add timespec_get shim

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-21 19:34:09

C11 timespec_get() is not provided on some platforms:

* MinGW-w64 does not currently implement it [1].
* FreeBSD 11 with Clang 10.0.0 does not provide it.

Add internal shims to Windows and FreeBSD EALs.
For Windows, it can be removed after [1] is fixed.

[1]: https://sourceforge.net/p/mingw-w64/mailman/message/37224689/

Signed-off-by: Dmitry Kozlyuk <redacted>
Acked-by: Jie Zhou <redacted>
Acked-by: Nick Connolly <redacted>
---
 lib/eal/freebsd/include/rte_os_shim.h | 17 ++++++++++++++
 lib/eal/windows/include/rte_os_shim.h | 32 +++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)
diff --git a/lib/eal/freebsd/include/rte_os_shim.h b/lib/eal/freebsd/include/rte_os_shim.h
index 1e85229ca9..10b51b802f 100644
--- a/lib/eal/freebsd/include/rte_os_shim.h
+++ b/lib/eal/freebsd/include/rte_os_shim.h
@@ -3,6 +3,8 @@
 #ifndef _RTE_OS_SHIM_
 #define _RTE_OS_SHIM_
 
+#include <time.h>
+
 #include <rte_os.h>
 
 /**
@@ -11,4 +13,19 @@
  * Provides semi-standard OS facilities by convenient names.
  */
 
+#ifndef TIME_UTC
+
+#define TIME_UTC 1
+
+static inline int
+rte_timespec_get(struct timespec *now, int base)
+{
+	if (base != TIME_UTC || clock_gettime(CLOCK_REALTIME, now) < 0)
+		return 0;
+	return base;
+}
+
+#define timespec_get(ts, base) rte_timespec_get(ts, base)
+
+#endif /* !defined TIME_UTC */
 #endif /* _RTE_OS_SHIM_ */
diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h
index f40fb62d1d..e50895fd83 100644
--- a/lib/eal/windows/include/rte_os_shim.h
+++ b/lib/eal/windows/include/rte_os_shim.h
@@ -3,7 +3,10 @@
 #ifndef _RTE_OS_SHIM_
 #define _RTE_OS_SHIM_
 
+#include <time.h>
+
 #include <rte_os.h>
+#include <rte_windows.h>
 
 /**
  * @file
@@ -33,4 +36,33 @@
 #define IPPROTO_SCTP	132
 #endif
 
+#ifdef RTE_TOOLCHAIN_GCC
+
+#define TIME_UTC 1
+
+static inline int
+rte_timespec_get(struct timespec *now, int base)
+{
+	/* 100ns ticks from 1601-01-01 to 1970-01-01 */
+	static const uint64_t EPOCH = 116444736000000000ULL;
+	static const uint64_t TICKS_PER_SEC = 10000000;
+	static const uint64_t NS_PER_TICK = 100;
+
+	FILETIME ft;
+	uint64_t ticks;
+
+	if (base != TIME_UTC)
+		return 0;
+
+	GetSystemTimePreciseAsFileTime(&ft);
+	ticks = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+	ticks -= EPOCH;
+	now->tv_sec = ticks / TICKS_PER_SEC;
+	now->tv_nsec = (ticks - now->tv_sec * TICKS_PER_SEC) * NS_PER_TICK;
+	return base;
+}
+
+#define timespec_get(ts, base) rte_timespec_get(ts, base)
+
+#endif /* RTE_TOOLCHAIN_GCC */
 #endif /* _RTE_OS_SHIM_ */
-- 
2.29.3

[dpdk-dev] [PATCH v5 2/3] net/pcap: move OS-dependent code to separate files

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-21 19:34:15

PCAP PMD queries interface information differently for Linux and
FreeBSD, OS-specific code is guarded by #ifdef. This PMD also depends on
POSIX bits, namely gettimeofday() and NAME_MAX.

Move OS-dependent code to separate files.
Replace POSIX bits with DPDK equivalents.
Rename rte_eth_pcap.c to pcap_ethdev.c, like it is in most other PMDs.

Signed-off-by: Dmitry Kozlyuk <redacted>
Reviewed-by: Ferruh Yigit <redacted>
---
 drivers/net/pcap/meson.build                  |   5 +-
 .../pcap/{rte_eth_pcap.c => pcap_ethdev.c}    | 104 +++---------------
 drivers/net/pcap/pcap_osdep.h                 |  13 +++
 drivers/net/pcap/pcap_osdep_freebsd.c         |  59 ++++++++++
 drivers/net/pcap/pcap_osdep_linux.c           |  42 +++++++
 5 files changed, 136 insertions(+), 87 deletions(-)
 rename drivers/net/pcap/{rte_eth_pcap.c => pcap_ethdev.c} (95%)
 create mode 100644 drivers/net/pcap/pcap_osdep.h
 create mode 100644 drivers/net/pcap/pcap_osdep_freebsd.c
 create mode 100644 drivers/net/pcap/pcap_osdep_linux.c
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index 61c0551582..d02a98b6f4 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -11,5 +11,8 @@ if not dpdk_conf.has('RTE_PORT_PCAP')
     build = false
     reason = 'missing dependency, "libpcap"'
 endif
-sources = files('rte_eth_pcap.c')
+sources = files(
+	'pcap_ethdev.c',
+	'pcap_osdep_@0@.c'.format(exec_env),
+)
 ext_deps += pcap_dep
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/pcap_ethdev.c
similarity index 95%
rename from drivers/net/pcap/rte_eth_pcap.c
rename to drivers/net/pcap/pcap_ethdev.c
index ef50d088f3..5ff7339e97 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -6,16 +6,6 @@
 
 #include <time.h>
 
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#if defined(RTE_EXEC_ENV_FREEBSD)
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#endif
-
 #include <pcap.h>
 
 #include <rte_cycles.h>
@@ -26,7 +16,8 @@
 #include <rte_mbuf.h>
 #include <rte_mbuf_dyn.h>
 #include <rte_bus_vdev.h>
-#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
 
 #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
 #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
@@ -47,7 +38,7 @@
 #define RTE_PMD_PCAP_MAX_QUEUES 16
 
 static char errbuf[PCAP_ERRBUF_SIZE];
-static struct timeval start_time;
+static struct timespec start_time;
 static uint64_t start_cycles;
 static uint64_t hz;
 static uint8_t iface_idx;
@@ -355,17 +346,21 @@ eth_null_rx(void *queue __rte_unused,
 
 #define NSEC_PER_SEC	1000000000L
 
+/*
+ * This function stores nanoseconds in `tv_usec` field of `struct timeval`,
+ * because `ts` goes directly to nanosecond-precision dump.
+ */
 static inline void
 calculate_timestamp(struct timeval *ts) {
 	uint64_t cycles;
-	struct timeval cur_time;
+	struct timespec cur_time;
 
 	cycles = rte_get_timer_cycles() - start_cycles;
 	cur_time.tv_sec = cycles / hz;
-	cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz;
+	cur_time.tv_nsec = (cycles % hz) * NSEC_PER_SEC / hz;
 
 	ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
-	ts->tv_usec = start_time.tv_usec + cur_time.tv_usec;
+	ts->tv_usec = start_time.tv_nsec + cur_time.tv_nsec;
 	if (ts->tv_usec >= NSEC_PER_SEC) {
 		ts->tv_usec -= NSEC_PER_SEC;
 		ts->tv_sec += 1;
@@ -884,7 +879,7 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
 
 	if (internals->infinite_rx) {
 		struct pmd_process_private *pp;
-		char ring_name[NAME_MAX];
+		char ring_name[RTE_RING_NAMESIZE];
 		static uint32_t ring_number;
 		uint64_t pcap_pkt_count = 0;
 		struct rte_mbuf *bufs[1];
@@ -1262,84 +1257,20 @@ static int
 eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
 		const unsigned int numa_node)
 {
-#if defined(RTE_EXEC_ENV_LINUX)
 	void *mac_addrs;
-	struct ifreq ifr;
-	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-	if (if_fd == -1)
-		return -1;
+	struct rte_ether_addr mac;
 
-	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
-	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
-		close(if_fd);
+	if (osdep_iface_mac_get(if_name, &mac) < 0)
 		return -1;
-	}
 
 	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		close(if_fd);
+	if (mac_addrs == NULL)
 		return -1;
-	}
 
 	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
+	rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
 	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
-
-	close(if_fd);
-
-	return 0;
-
-#elif defined(RTE_EXEC_ENV_FREEBSD)
-	void *mac_addrs;
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	int mib[6];
-	size_t len = 0;
-	char *buf;
-
-	mib[0] = CTL_NET;
-	mib[1] = AF_ROUTE;
-	mib[2] = 0;
-	mib[3] = AF_LINK;
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = if_nametoindex(if_name);
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-
-	if (len == 0)
-		return -1;
-
-	buf = rte_malloc(NULL, len, 0);
-	if (!buf)
-		return -1;
-
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		rte_free(buf);
-		return -1;
-	}
-	ifm = (struct if_msghdr *)buf;
-	sdl = (struct sockaddr_dl *)(ifm + 1);
-
-	mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
-	if (!mac_addrs) {
-		rte_free(buf);
-		return -1;
-	}
-
-	PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
-	eth_dev->data->mac_addrs = mac_addrs;
-	rte_memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
-			LLADDR(sdl), RTE_ETHER_ADDR_LEN);
-
-	rte_free(buf);
-
 	return 0;
-#else
-	return -1;
-#endif
 }
 
 static int
@@ -1401,7 +1332,8 @@ eth_from_pcaps(struct rte_vdev_device *vdev,
 	internals->single_iface = single_iface;
 
 	if (single_iface) {
-		internals->if_index = if_nametoindex(rx_queues->queue[0].name);
+		internals->if_index =
+			osdep_iface_index_get(rx_queues->queue[0].name);
 
 		/* phy_mac arg is applied only only if "iface" devarg is provided */
 		if (rx_queues->phy_mac) {
@@ -1454,7 +1386,7 @@ pmd_pcap_probe(struct rte_vdev_device *dev)
 	name = rte_vdev_device_name(dev);
 	PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
 
-	gettimeofday(&start_time, NULL);
+	timespec_get(&start_time, TIME_UTC);
 	start_cycles = rte_get_timer_cycles();
 	hz = rte_get_timer_hz();
 
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
new file mode 100644
index 0000000000..9de422ab8d
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#ifndef _RTE_PCAP_OSDEP_
+#define _RTE_PCAP_OSDEP_
+
+#include <rte_ether.h>
+
+int osdep_iface_index_get(const char *name);
+int osdep_iface_mac_get(const char *name, struct rte_ether_addr *mac);
+
+#endif
diff --git a/drivers/net/pcap/pcap_osdep_freebsd.c b/drivers/net/pcap/pcap_osdep_freebsd.c
new file mode 100644
index 0000000000..20556b3e92
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_freebsd.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/sysctl.h>
+
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	int mib[6];
+	size_t len = 0;
+	char *buf;
+
+	mib[0] = CTL_NET;
+	mib[1] = AF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_LINK;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = if_nametoindex(if_name);
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+
+	if (len == 0)
+		return -1;
+
+	buf = rte_malloc(NULL, len, 0);
+	if (!buf)
+		return -1;
+
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		rte_free(buf);
+		return -1;
+	}
+	ifm = (struct if_msghdr *)buf;
+	sdl = (struct sockaddr_dl *)(ifm + 1);
+
+	rte_memcpy(mac->addr_bytes, LLADDR(sdl), RTE_ETHER_ADDR_LEN);
+
+	rte_free(buf);
+	return 0;
+}
diff --git a/drivers/net/pcap/pcap_osdep_linux.c b/drivers/net/pcap/pcap_osdep_linux.c
new file mode 100644
index 0000000000..97033f57c5
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_linux.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ * All rights reserved.
+ */
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <rte_memcpy.h>
+#include <rte_string_fns.h>
+
+#include "pcap_osdep.h"
+
+int
+osdep_iface_index_get(const char *name)
+{
+	return if_nametoindex(name);
+}
+
+int
+osdep_iface_mac_get(const char *if_name, struct rte_ether_addr *mac)
+{
+	struct ifreq ifr;
+	int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (if_fd == -1)
+		return -1;
+
+	rte_strscpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+	if (ioctl(if_fd, SIOCGIFHWADDR, &ifr)) {
+		close(if_fd);
+		return -1;
+	}
+
+	rte_memcpy(mac->addr_bytes, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
+
+	close(if_fd);
+	return 0;
+}
-- 
2.29.3

[dpdk-dev] [PATCH v5 3/3] net/pcap: build on Windows

From: Dmitry Kozlyuk <hidden>
Date: 2021-04-21 19:34:21

Implement OS-dependent functions and enable build for Windows.
Account for different library name in Windows libpcap distributions.

Signed-off-by: Dmitry Kozlyuk <redacted>
Acked-by: Tyler Retzlaff <redacted>
---
 config/meson.build                     |   9 +-
 doc/guides/rel_notes/release_21_05.rst |   4 +
 drivers/net/pcap/meson.build           |  11 ++-
 drivers/net/pcap/pcap_ethdev.c         |   5 +-
 drivers/net/pcap/pcap_osdep.h          |   5 ++
 drivers/net/pcap/pcap_osdep_windows.c  | 118 +++++++++++++++++++++++++
 6 files changed, 138 insertions(+), 14 deletions(-)
 create mode 100644 drivers/net/pcap/pcap_osdep_windows.c
diff --git a/config/meson.build b/config/meson.build
index 9e49abc0f8..d31ddef4e4 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -180,13 +180,14 @@ endif
 
 # check for pcap
 pcap_dep = dependency('libpcap', required: false, method: 'pkg-config')
+pcap_lib = is_windows ? 'wpcap' : 'pcap'
 if not pcap_dep.found()
-    # pcap got a pkg-config file only in 1.9.0
-    pcap_dep = cc.find_library('pcap', required: false)
+	# pcap got a pkg-config file only in 1.9.0
+	pcap_dep = cc.find_library(pcap_lib, required: false)
 endif
 if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
-    dpdk_conf.set('RTE_PORT_PCAP', 1)
-    dpdk_extra_ldflags += '-lpcap'
+	dpdk_conf.set('RTE_PORT_PCAP', 1)
+	dpdk_extra_ldflags += '-l@0@'.format(pcap_lib)
 endif
 
 # for clang 32-bit compiles we need libatomic for 64-bit atomic ops
diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index 565e764811..3ba8e5ce7d 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -235,6 +235,10 @@ New Features
   * Added support for crypto adapter forward mode in octeontx2 event and crypto
     device driver.
 
+* **Enabled libpcap-based PMD on Windows.**
+
+   A libpcap distribution, such as Npcap or WinPcap, is required to run the PMD.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/pcap/meson.build b/drivers/net/pcap/meson.build
index d02a98b6f4..eec63a9b08 100644
--- a/drivers/net/pcap/meson.build
+++ b/drivers/net/pcap/meson.build
@@ -1,18 +1,17 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-if is_windows
-    build = false
-    reason = 'not supported on Windows'
-    subdir_done()
-endif
-
 if not dpdk_conf.has('RTE_PORT_PCAP')
     build = false
     reason = 'missing dependency, "libpcap"'
 endif
+
 sources = files(
 	'pcap_ethdev.c',
 	'pcap_osdep_@0@.c'.format(exec_env),
 )
+
 ext_deps += pcap_dep
+if is_windows
+	ext_deps += cc.find_library('iphlpapi', required: true)
+endif
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 5ff7339e97..883a0c494a 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -16,6 +16,7 @@
 #include <rte_mbuf.h>
 #include <rte_mbuf_dyn.h>
 #include <rte_bus_vdev.h>
+#include <rte_os_shim.h>
 
 #include "pcap_osdep.h"
 
@@ -142,10 +143,6 @@ static struct rte_eth_link pmd_link = {
 
 RTE_LOG_REGISTER(eth_pcap_logtype, pmd.net.pcap, NOTICE);
 
-#define PMD_LOG(level, fmt, args...) \
-	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
-		"%s(): " fmt "\n", __func__, ##args)
-
 static struct queue_missed_stat*
 queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
 {
diff --git a/drivers/net/pcap/pcap_osdep.h b/drivers/net/pcap/pcap_osdep.h
index 9de422ab8d..bf41cba982 100644
--- a/drivers/net/pcap/pcap_osdep.h
+++ b/drivers/net/pcap/pcap_osdep.h
@@ -7,6 +7,11 @@
 
 #include <rte_ether.h>
 
+#define PMD_LOG(level, fmt, args...) \
+	rte_log(RTE_LOG_ ## level, eth_pcap_logtype, \
+		"%s(): " fmt "\n", __func__, ##args)
+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);
 
diff --git a/drivers/net/pcap/pcap_osdep_windows.c b/drivers/net/pcap/pcap_osdep_windows.c
new file mode 100644
index 0000000000..1d398dc7ed
--- /dev/null
+++ b/drivers/net/pcap/pcap_osdep_windows.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 Dmitry Kozlyuk
+ */
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <strsafe.h>
+
+#include "pcap_osdep.h"
+
+/*
+ * Given a device name like "\Device\NPF_{GUID}" extract the "{GUID}" part.
+ * Return NULL if "{GUID}" part is not found.
+ */
+static const char *
+iface_guid(const char *name)
+{
+	static const size_t GUID_LENGTH = 32 + 4; /* 16 hex bytes + 4 dashes */
+
+	const char *ob, *cb;
+
+	ob = strchr(name, '{');
+	if (ob == NULL)
+		return NULL;
+
+	cb = strchr(ob, '}');
+	if (cb == NULL || cb - ob != GUID_LENGTH + 1) /* + 1 opening '{' */
+		return NULL;
+
+	return ob;
+}
+
+/*
+ * libpcap takes device names like "\Device\NPF_{GUID}",
+ * GetAdapterIndex() takes interface names like "\DEVICE\TCPIP_{GUID}".
+ * Try to convert, fall back to original device name.
+ */
+int
+osdep_iface_index_get(const char *device_name)
+{
+	WCHAR adapter_name[MAX_ADAPTER_NAME_LENGTH];
+	const char *guid;
+	ULONG index;
+	DWORD ret;
+
+	guid = iface_guid(device_name);
+	if (guid != NULL)
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"\\DEVICE\\TCPIP_%S", guid);
+	else
+		StringCbPrintfW(adapter_name, sizeof(adapter_name),
+			L"%S", device_name);
+
+	ret = GetAdapterIndex(adapter_name, &index);
+	if (ret != NO_ERROR) {
+		PMD_LOG(ERR, "GetAdapterIndex(%S) = %lu\n", adapter_name, ret);
+		return -1;
+	}
+
+	return index;
+}
+
+/*
+ * 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;
+	ULONG size, sys_ret;
+	const char *adapter_name;
+	int ret = -1;
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+	if (sys_ret != ERROR_BUFFER_OVERFLOW) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n",
+			sys_ret, ERROR_BUFFER_OVERFLOW);
+		return -1;
+	}
+
+	info = (IP_ADAPTER_ADDRESSES *)malloc(size);
+	if (info == NULL) {
+		PMD_LOG(ERR, "Cannot allocate adapter address info\n");
+		return -1;
+	}
+
+	sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size);
+	if (sys_ret != ERROR_SUCCESS) {
+		PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret);
+		free(info);
+		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) {
+			if (cur->PhysicalAddressLength != RTE_ETHER_ADDR_LEN) {
+				PMD_LOG(ERR, "Physical address length: want %u, got %lu",
+					RTE_ETHER_ADDR_LEN,
+					cur->PhysicalAddressLength);
+				break;
+			}
+
+			memcpy(mac->addr_bytes, cur->PhysicalAddress,
+				RTE_ETHER_ADDR_LEN);
+			ret = 0;
+			break;
+		}
+	}
+
+	free(info);
+	return ret;
+}
-- 
2.29.3

Re: [dpdk-dev] [PATCH v5 0/3] net/pcap: build on Windows

From: Thomas Monjalon <hidden>
Date: 2021-04-21 21:54:59

Dmitry Kozlyuk (3):
  eal: add timespec_get shim
  net/pcap: move OS-dependent code to separate files
  net/pcap: build on Windows
Unfortunately the CI testing FreeBSD 11 is not running on this series,
but I feel it's OK to be part of the 21.05-rc1.

Applied, thanks

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help