Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 22 Nov 2020 09:20:09 +0000 (UTC)
From:      Vincenzo Maffione <vmaffione@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r367932 - head/tools/tools/netmap
Message-ID:  <202011220920.0AM9K9E5008140@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: vmaffione
Date: Sun Nov 22 09:20:08 2020
New Revision: 367932
URL: https://svnweb.freebsd.org/changeset/base/367932

Log:
  netmap: pkt-gen: switch to libnetmap
  
  Use the newer libnetmap (included in base) rather than the older
  nm_open()/nm_close() defined in netmap_user.h

Modified:
  head/tools/tools/netmap/pkt-gen.c

Modified: head/tools/tools/netmap/pkt-gen.c
==============================================================================
--- head/tools/tools/netmap/pkt-gen.c	Sun Nov 22 09:10:12 2020	(r367931)
+++ head/tools/tools/netmap/pkt-gen.c	Sun Nov 22 09:20:08 2020	(r367932)
@@ -38,36 +38,40 @@
  */
 
 #define _GNU_SOURCE	/* for CPU_SET() */
-#include <stdio.h>
-#define NETMAP_WITH_LIBS
-#include <net/netmap_user.h>
-
-#include <ctype.h>	// isprint()
-#include <unistd.h>	// sysconf()
-#include <sys/poll.h>
 #include <arpa/inet.h>	/* ntohs */
-#ifndef _WIN32
-#include <sys/sysctl.h>	/* sysctl */
-#endif
+#include <assert.h>
+#include <ctype.h>	// isprint()
+#include <errno.h>
+#include <fcntl.h>
 #include <ifaddrs.h>	/* getifaddrs */
+#include <libnetmap.h>
+#include <math.h>
 #include <net/ethernet.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
-#include <netinet/udp.h>
 #include <netinet/ip6.h>
+#include <netinet/udp.h>
+#ifndef NO_PCAP
+#include <pcap/pcap.h>
+#endif
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#if !defined(_WIN32) && !defined(linux)
+#include <sys/sysctl.h>	/* sysctl */
+#endif
+#include <sys/types.h>
+#include <unistd.h>	// sysconf()
 #ifdef linux
 #define IPV6_VERSION	0x60
 #define IPV6_DEFHLIM	64
 #endif
-#include <assert.h>
-#include <math.h>
 
-#include <pthread.h>
-
-#ifndef NO_PCAP
-#include <pcap/pcap.h>
-#endif
-
 #include "ctrs.h"
 
 static void usage(int);
@@ -236,7 +240,8 @@ struct mac_range {
 };
 
 /* ifname can be netmap:foo-xxxx */
-#define MAX_IFNAMELEN	64	/* our buffer for ifname */
+#define MAX_IFNAMELEN	512	/* our buffer for ifname */
+//#define MAX_PKTSIZE	1536
 #define MAX_PKTSIZE	MAX_BODYSIZE	/* XXX: + IP_HDR + ETH_HDR */
 
 /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
@@ -288,7 +293,8 @@ struct glob_arg {
 
 	int affinity;
 	int main_fd;
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
+	uint32_t orig_mode;
 	int report_interval;		/* milliseconds between prints */
 	void *(*td_body)(void *);
 	int td_type;
@@ -322,7 +328,7 @@ struct targ {
 	int completed;
 	int cancel;
 	int fd;
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	/* these ought to be volatile, but they are
 	 * only sampled and errors should not accumulate
 	 */
@@ -515,17 +521,21 @@ extract_mac_range(struct mac_range *r)
 static int
 get_if_mtu(const struct glob_arg *g)
 {
-	char ifname[IFNAMSIZ];
 	struct ifreq ifreq;
 	int s, ret;
+	const char *ifname = g->nmd->hdr.nr_name;
+	size_t len;
 
-	if (!strncmp(g->ifname, "netmap:", 7) && !strchr(g->ifname, '{')
-			&& !strchr(g->ifname, '}')) {
-		/* Parse the interface name and ask the kernel for the
-		 * MTU value. */
-		strncpy(ifname, g->ifname+7, IFNAMSIZ-1);
-		ifname[strcspn(ifname, "-*^{}/@")] = '\0';
+	if (!strncmp(g->ifname, "netmap:", 7) && !strchr(ifname, '{')
+			&& !strchr(ifname, '}')) {
 
+		len = strlen(ifname);
+
+		if (len > IFNAMSIZ) {
+			D("'%s' too long, cannot ask for MTU", ifname);
+			return -1;
+		}
+
 		s = socket(AF_INET, SOCK_DGRAM, 0);
 		if (s < 0) {
 			D("socket() failed: %s", strerror(errno));
@@ -533,13 +543,15 @@ get_if_mtu(const struct glob_arg *g)
 		}
 
 		memset(&ifreq, 0, sizeof(ifreq));
-		strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
+		memcpy(ifreq.ifr_name, ifname, len);
 
 		ret = ioctl(s, SIOCGIFMTU, &ifreq);
 		if (ret) {
 			D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
 		}
 
+		close(s);
+
 		return ifreq.ifr_mtu;
 	}
 
@@ -620,7 +632,7 @@ system_ncpus(void)
  * and #rx-rings.
  */
 static int
-parse_nmr_config(const char* conf, struct nmreq *nmr)
+parse_nmr_config(const char* conf, struct nmreq_register *nmr)
 {
 	char *w, *tok;
 	int i, v;
@@ -654,9 +666,7 @@ parse_nmr_config(const char* conf, struct nmreq *nmr)
 			nmr->nr_tx_rings, nmr->nr_tx_slots,
 			nmr->nr_rx_rings, nmr->nr_rx_slots);
 	free(w);
-	return (nmr->nr_tx_rings || nmr->nr_tx_slots ||
-		nmr->nr_rx_rings || nmr->nr_rx_slots) ?
-		NM_OPEN_RING_CFG : 0;
+	return 0;
 }
 
 
@@ -1108,20 +1118,22 @@ initialize_packet(struct targ *targ)
 static void
 get_vnet_hdr_len(struct glob_arg *g)
 {
-	struct nmreq req;
+	struct nmreq_header hdr;
+	struct nmreq_port_hdr ph;
 	int err;
 
-	memset(&req, 0, sizeof(req));
-	bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
-	req.nr_version = NETMAP_API;
-	req.nr_cmd = NETMAP_VNET_HDR_GET;
-	err = ioctl(g->main_fd, NIOCREGIF, &req);
+	hdr = g->nmd->hdr; /* copy name and version */
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+	hdr.nr_options = 0;
+	memset(&ph, 0, sizeof(ph));
+	hdr.nr_body = (uintptr_t)&ph;
+	err = ioctl(g->main_fd, NIOCCTRL, &hdr);
 	if (err) {
 		D("Unable to get virtio-net header length");
 		return;
 	}
 
-	g->virt_header = req.nr_arg1;
+	g->virt_header = ph.nr_hdr_len;
 	if (g->virt_header) {
 		D("Port requires virtio-net header, length = %d",
 		  g->virt_header);
@@ -1132,17 +1144,18 @@ static void
 set_vnet_hdr_len(struct glob_arg *g)
 {
 	int err, l = g->virt_header;
-	struct nmreq req;
+	struct nmreq_header hdr;
+	struct nmreq_port_hdr ph;
 
 	if (l == 0)
 		return;
 
-	memset(&req, 0, sizeof(req));
-	bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
-	req.nr_version = NETMAP_API;
-	req.nr_cmd = NETMAP_BDG_VNET_HDR;
-	req.nr_arg1 = l;
-	err = ioctl(g->main_fd, NIOCREGIF, &req);
+	hdr = g->nmd->hdr; /* copy name and version */
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+	hdr.nr_options = 0;
+	memset(&ph, 0, sizeof(ph));
+	hdr.nr_body = (uintptr_t)&ph;
+	err = ioctl(g->main_fd, NIOCCTRL, &hdr);
 	if (err) {
 		D("Unable to set virtio-net header length %d", l);
 	}
@@ -2480,7 +2493,7 @@ usage(int errcode)
 	exit(errcode);
 }
 
-static void
+static int
 start_threads(struct glob_arg *g) {
 	int i;
 
@@ -2500,31 +2513,43 @@ start_threads(struct glob_arg *g) {
 		memcpy(t->seed, &seed, sizeof(t->seed));
 
 		if (g->dev_type == DEV_NETMAP) {
-			struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */
-			uint64_t nmd_flags = 0;
-			nmd.self = &nmd;
+			int m = -1;
 
+			/*
+			 * if the user wants both HW and SW rings, we need to
+			 * know when to switch from NR_REG_ONE_NIC to NR_REG_ONE_SW
+			 */
+			if (g->orig_mode == NR_REG_NIC_SW) {
+				m = (g->td_type == TD_TYPE_RECEIVER ?
+						g->nmd->reg.nr_rx_rings :
+						g->nmd->reg.nr_tx_rings);
+			}
+
 			if (i > 0) {
+				int j;
 				/* the first thread uses the fd opened by the main
 				 * thread, the other threads re-open /dev/netmap
 				 */
-				if (g->nthreads > 1) {
-					nmd.req.nr_flags =
-						g->nmd->req.nr_flags & ~NR_REG_MASK;
-					nmd.req.nr_flags |= NR_REG_ONE_NIC;
-					nmd.req.nr_ringid = i;
+				t->nmd = nmport_clone(g->nmd);
+				if (t->nmd == NULL)
+					return -1;
+
+				j = i;
+				if (m > 0 && j >= m) {
+					/* switch to the software rings */
+					t->nmd->reg.nr_mode = NR_REG_ONE_SW;
+					j -= m;
 				}
+				t->nmd->reg.nr_ringid = j & NETMAP_RING_MASK;
 				/* Only touch one of the rings (rx is already ok) */
 				if (g->td_type == TD_TYPE_RECEIVER)
-					nmd_flags |= NETMAP_NO_TX_POLL;
+					t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL;
 
 				/* register interface. Override ifname and ringid etc. */
-				t->nmd = nm_open(t->g->ifname, NULL, nmd_flags |
-						NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd);
-				if (t->nmd == NULL) {
-					D("Unable to open %s: %s",
-							t->g->ifname, strerror(errno));
-					continue;
+				if (nmport_open_desc(t->nmd) < 0) {
+					nmport_undo_prepare(t->nmd);
+					t->nmd = NULL;
+					return -1;
 				}
 			} else {
 				t->nmd = g->nmd;
@@ -2556,6 +2581,7 @@ start_threads(struct glob_arg *g) {
 			t->used = 0;
 		}
 	}
+	return 0;
 }
 
 static void
@@ -2655,7 +2681,7 @@ main_thread(struct glob_arg *g)
 		if (targs[i].used)
 			pthread_join(targs[i].thread, NULL); /* blocking */
 		if (g->dev_type == DEV_NETMAP) {
-			nm_close(targs[i].nmd);
+			nmport_close(targs[i].nmd);
 			targs[i].nmd = NULL;
 		} else {
 			close(targs[i].fd);
@@ -3078,21 +3104,14 @@ main(int arc, char **argv)
     } else if (g.dummy_send) { /* but DEV_NETMAP */
 	D("using a dummy send routine");
     } else {
-	struct nm_desc base_nmd;
-	char errmsg[MAXERRMSG];
-	u_int flags;
+	g.nmd = nmport_prepare(g.ifname);
+	if (g.nmd == NULL)
+		goto out;
 
-	bzero(&base_nmd, sizeof(base_nmd));
+	parse_nmr_config(g.nmr_config, &g.nmd->reg);
 
-	parse_nmr_config(g.nmr_config, &base_nmd.req);
+	g.nmd->reg.nr_flags |= NR_ACCEPT_VNET_HDR;
 
-	base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR;
-
-	if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) {
-		D("Invalid name '%s': %s", g.ifname, errmsg);
-		goto out;
-	}
-
 	/*
 	 * Open the netmap device using nm_open().
 	 *
@@ -3100,20 +3119,25 @@ main(int arc, char **argv)
 	 * which in turn may take some time for the PHY to
 	 * reconfigure. We do the open here to have time to reset.
 	 */
-	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
-		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
+	g.orig_mode = g.nmd->reg.nr_mode;
 	if (g.nthreads > 1) {
-		base_nmd.req.nr_flags &= ~NR_REG_MASK;
-		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
-		base_nmd.req.nr_ringid = 0;
+		switch (g.orig_mode) {
+		case NR_REG_ALL_NIC:
+		case NR_REG_NIC_SW:
+			g.nmd->reg.nr_mode = NR_REG_ONE_NIC;
+			break;
+		case NR_REG_SW:
+			g.nmd->reg.nr_mode = NR_REG_ONE_SW;
+			break;
+		default:
+			break;
+		}
+		g.nmd->reg.nr_ringid = 0;
 	}
-	g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd);
-	if (g.nmd == NULL) {
-		D("Unable to open %s: %s", g.ifname, strerror(errno));
+	if (nmport_open_desc(g.nmd) < 0)
 		goto out;
-	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
+	ND("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
 				g.nmd->mem);
 
 	if (g.virt_header) {
@@ -3128,9 +3152,9 @@ main(int arc, char **argv)
 
 	/* get num of queues in tx or rx */
 	if (g.td_type == TD_TYPE_SENDER)
-		devqueues = g.nmd->req.nr_tx_rings;
+		devqueues = g.nmd->reg.nr_tx_rings + g.nmd->reg.nr_host_tx_rings;
 	else
-		devqueues = g.nmd->req.nr_rx_rings;
+		devqueues = g.nmd->reg.nr_rx_rings + g.nmd->reg.nr_host_rx_rings;
 
 	/* validate provided nthreads. */
 	if (g.nthreads < 1 || g.nthreads > devqueues) {
@@ -3150,17 +3174,17 @@ main(int arc, char **argv)
 
 	if (verbose) {
 		struct netmap_if *nifp = g.nmd->nifp;
-		struct nmreq *req = &g.nmd->req;
+		struct nmreq_register *req = &g.nmd->reg;
 
-		D("nifp at offset %d, %d tx %d rx region %d",
+		D("nifp at offset %"PRIu64", %d tx %d rx region %d",
 		    req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
-		    req->nr_arg2);
-		for (i = 0; i <= req->nr_tx_rings; i++) {
+		    req->nr_mem_id);
+		for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
 			D("   TX%d at 0x%p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
 		}
-		for (i = 0; i <= req->nr_rx_rings; i++) {
+		for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
 			D("   RX%d at 0x%p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
@@ -3230,7 +3254,8 @@ out:
 	if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) {
 		D("failed to block SIGINT: %s", strerror(errno));
 	}
-	start_threads(&g);
+	if (start_threads(&g) < 0)
+		return 1;
 	/* Install the handler and re-enable SIGINT for the main thread */
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = sigint_h;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202011220920.0AM9K9E5008140>