socsvn commit: r337265 - soc2018/sduo/netmap_utils

sduo at FreeBSD.org sduo at FreeBSD.org
Wed Jun 27 16:17:27 UTC 2018


Author: sduo
Date: Wed Jun 27 16:17:21 2018
New Revision: 337265
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=337265

Log:
  functional.c can request netmap interface file descriptors from fd_server.

Added:
  soc2018/sduo/netmap_utils/functional.c
Modified:
  soc2018/sduo/netmap_utils/fd_server.c
  soc2018/sduo/netmap_utils/fd_server.h

Modified: soc2018/sduo/netmap_utils/fd_server.c
==============================================================================
--- soc2018/sduo/netmap_utils/fd_server.c	Wed Jun 27 15:52:47 2018	(r337264)
+++ soc2018/sduo/netmap_utils/fd_server.c	Wed Jun 27 16:17:21 2018	(r337265)
@@ -1,5 +1,7 @@
 #include <errno.h>
 #include <fcntl.h>
+#include <net/if.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -10,17 +12,22 @@
 #include <sys/un.h>
 #include <sys/wait.h>
 #include <syslog.h>
-#include <unistd.h>
+
+#include <net/netmap.h>
+#define NETMAP_WITH_LIBS
+#include <net/netmap_user.h>
 
 #include "fd_server.h"
 
 struct nmd_entry {
+	char if_name[NETMAP_REQ_IFNAMSIZ];
 	struct nm_desc *nmd;
 	uint8_t is_in_use;
 	uint8_t is_open;
 };
 
-#define SOCKET_NAME "/tmp/my_unix_socket"
+#define printf(format, ...) syslog(LOG_NOTICE, format, ##__VA_ARGS__)
+
 #define MAX_OPEN_IF 128
 struct nmd_entry entries[MAX_OPEN_IF];
 int num_entries = 0;
@@ -29,13 +36,13 @@
 print_request(struct fd_request *req)
 {
 
-	syslog(LOG_NOTICE, "d action: %s, if_name: %s\n",
+	printf("action: %s, if_name: '%s'\n",
 	       req->action == FD_GET
-		       ? "FD_GET"
-		       : req->action == FD_RELEASE
-				 ? "FD_RELEASE"
-				 : req->action == FD_CLOSE ? "FD_CLOSE"
-							   : "FD_STOP",
+	               ? "FD_GET"
+	               : req->action == FD_RELEASE
+	                         ? "FD_RELEASE"
+	                         : req->action == FD_CLOSE ? "FD_CLOSE"
+	                                                   : "FD_STOP",
 	       req->if_name);
 }
 
@@ -44,32 +51,34 @@
 {
 	int i;
 
+	// printf("searching %s\n", if_name);
 	for (i = 0; i < num_entries; ++i) {
 		struct nmd_entry *entry = &entries[i];
-		struct nm_desc *nmd     = entry->nmd;
+
+		// printf("i=%d, is_open=%d, is_in_use=%d, if_name=%s\n",
+		// 	i, entry->is_open, entry->is_in_use, entry->if_name);
 
 		if (entry->is_open == 0) {
 			continue;
 		}
 
-		if (strcmp(nmd->req.nr_name, if_name) == 0) {
+		if (strncmp(entry->if_name, if_name, IFNAMSIZ) == 0) {
+			// printf("finished searching with a match\n");
 			return entry;
 		}
 	}
 
+	// printf("finished searching without a match\n");
 	return NULL;
 }
 
 struct nmd_entry *
-get_free_des(int *ret)
+get_free_des(void)
 {
-
 	if (num_entries == MAX_OPEN_IF) {
-		*ret = -1;
 		return NULL;
 	}
 
-	*ret = 0;
 	return &entries[num_entries++];
 }
 
@@ -77,12 +86,11 @@
 get_fd(const char *if_name, struct fd_response *res)
 {
 	struct nmd_entry *entry;
-	int ret;
 
 	entry = search_des(if_name);
 	if (entry != NULL) {
 		if (entry->is_in_use == 1) {
-			syslog(LOG_NOTICE, "if_name %s is in use\n", if_name);
+			printf("if_name %s is in use\n", if_name);
 			res->result = EBUSY;
 			return -1;
 		}
@@ -90,20 +98,21 @@
 		return entry->nmd->fd;
 	}
 
-	entry = get_free_des(&ret);
-	if (ret == -1) {
-		syslog(LOG_NOTICE, "Out of memory\n");
+	entry = get_free_des();
+	if (entry == NULL) {
+		printf("Out of memory\n");
 		res->result = ENOMEM;
 		return -1;
 	}
 
 	entry->nmd = nm_open(if_name, NULL, 0, NULL);
 	if (entry->nmd == NULL) {
-		syslog(LOG_NOTICE, "Failed to nm_open(%s) with error %d\n",
-		       if_name, errno);
+		printf("Failed to nm_open(%s) with error %d\n", if_name, errno);
 		res->result = errno;
 		return -1;
 	}
+	strncpy(entry->if_name, if_name, sizeof(entry->if_name));
+	entry->if_name[sizeof(entry->if_name) - 1] = '\0';
 
 	memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
 	entry->is_in_use = 1;
@@ -118,7 +127,7 @@
 
 	entry = search_des(if_name);
 	if (entry == NULL) {
-		syslog(LOG_NOTICE, "if_name %s isn't open\n", if_name);
+		printf("if_name %s isn't open\n", if_name);
 		res->result = ENOENT;
 		return;
 	}
@@ -132,7 +141,7 @@
 	struct nmd_entry *entry;
 	int ret;
 
-	if (if_name == NULL || strnlen(if_name, IFNAMSIZ) == 0) {
+	if (if_name == NULL || strnlen(if_name, NETMAP_REQ_IFNAMSIZ) == 0) {
 		res->result = EINVAL;
 		return;
 	}
@@ -140,14 +149,14 @@
 	entry = search_des(if_name);
 	if (entry == NULL) {
 		res->result = ENOENT;
-		syslog(LOG_NOTICE, "if_name %s hasn't been opened\n", if_name);
+		printf("if_name %s hasn't been opened\n", if_name);
 		return;
 	}
 
-	ret	 = nm_close(entry->nmd);
+	ret         = nm_close(entry->nmd);
 	res->result = ret;
 	if (ret != 0) {
-		syslog(LOG_NOTICE, "error while close interface %s\n", if_name);
+		printf("error while close interface %s\n", if_name);
 		return;
 	}
 	entry->is_in_use = 0;
@@ -164,10 +173,10 @@
 	struct cmsghdr *cmsg;
 	struct iovec iov[1];
 	struct msghdr msg;
+	int ret;
 
 	iov[0].iov_base = buf;
 	iov[0].iov_len  = buf_size;
-
 	memset(&msg, 0, sizeof(struct msghdr));
 	msg.msg_iov    = iov;
 	msg.msg_iovlen = 1;
@@ -176,17 +185,18 @@
 		/* We need the ancillary data only when we're sending a file
 		 * descriptor, and a file descriptor cannot be negative.
 		 */
-		msg.msg_control    = ancillary.buf;
-		msg.msg_controllen = sizeof(ancillary.buf);
-
-		cmsg			= CMSG_FIRSTHDR(&msg);
-		cmsg->cmsg_level	= SOL_SOCKET;
-		cmsg->cmsg_type		= SCM_RIGHTS;
-		cmsg->cmsg_len		= CMSG_LEN(sizeof(int));
+		printf("sending a file descriptor\n");
+		msg.msg_control         = ancillary.buf;
+		msg.msg_controllen      = sizeof(ancillary.buf);
+		cmsg                    = CMSG_FIRSTHDR(&msg);
+		cmsg->cmsg_level        = SOL_SOCKET;
+		cmsg->cmsg_type         = SCM_RIGHTS;
+		cmsg->cmsg_len          = CMSG_LEN(sizeof(int));
 		*(int *)CMSG_DATA(cmsg) = fd;
 	}
 
-	return sendmsg(socket, &msg, 0);
+	ret = sendmsg(socket, &msg, 0);
+	return ret;
 }
 
 int
@@ -194,15 +204,14 @@
 {
 	struct fd_response res;
 	struct fd_request req;
-	int amount;
 	int fd = -1;
+	int amount;
+	int ret;
 
-	memset(&res, 0, sizeof(res));
 	memset(&req, 0, sizeof(req));
-
 	amount = recv(socket, &req, sizeof(struct fd_request), 0);
 	if (amount == -1) {
-		syslog(LOG_NOTICE, "error during recv()");
+		printf("error while receiving the request\n");
 		return -1;
 	}
 
@@ -219,14 +228,18 @@
 		close_fd(req.if_name, &res);
 		return 0;
 	case FD_STOP:
-		syslog(LOG_NOTICE, "shutting down");
+		printf("shutting down\n");
 		exit(EXIT_SUCCESS);
 		break;
 	default:
 		res.result = EOPNOTSUPP;
 	}
 
-	return send_fd(socket, fd, &res, sizeof(struct fd_response));
+	ret = send_fd(socket, fd, &res, sizeof(struct fd_response));
+	if (ret == -1) {
+		printf("error while sending the reponse\n");
+	}
+	return ret;
 }
 
 void
@@ -236,42 +249,48 @@
 	int socket_fd;
 	int ret;
 
+	printf("starting up.\n");
+	if (unlink(SOCKET_NAME) == -1 && errno != ENOENT) {
+		printf("error %d during unlink()", errno);
+		exit(EXIT_FAILURE);
+	}
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
-		syslog(LOG_NOTICE, "error during socket()");
+		printf("error during socket()\n");
 		exit(EXIT_FAILURE);
 	}
 
-	unlink(SOCKET_NAME);
 	memset(&name, 0, sizeof(struct sockaddr_un));
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	ret = bind(socket_fd, (const struct sockaddr *)&name,
-		   sizeof(struct sockaddr_un));
+	           sizeof(struct sockaddr_un));
 	if (ret == -1) {
-		syslog(LOG_NOTICE, "error during bind()");
+		printf("error during bind()\n");
 		exit(EXIT_FAILURE);
 	}
 
 	ret = listen(socket_fd, 2);
 	if (ret == -1) {
-		syslog(LOG_NOTICE, "error during listen()");
+		printf("error during listen()");
 		exit(EXIT_FAILURE);
 	}
 
+	printf("listening\n");
 	for (;;) {
 		int conn_fd;
 		int ret;
 
 		conn_fd = accept(socket_fd, NULL, NULL);
 		if (conn_fd == -1) {
-			syslog(LOG_NOTICE,
-			       "error during accept(), shutting down");
+			printf("error during accept(), shutting down\n");
 			exit(EXIT_FAILURE);
 		}
 
-		syslog(LOG_NOTICE, "handling a request");
 		ret = handle_request(conn_fd);
+		if (ret == -1) {
+			printf("error while handling a request\n");
+		}
 		(void)ret;
 		close(conn_fd);
 	}
@@ -291,7 +310,7 @@
 		exit(EXIT_SUCCESS);
 	}
 
-	if (setsid() < 0) {
+	if (setsid() == -1) {
 		exit(EXIT_FAILURE);
 	}
 
@@ -307,10 +326,11 @@
 	}
 
 	umask(0);
+
 	if (chdir("/") == -1) {
-		perror("chdir()");
 		exit(EXIT_FAILURE);
 	}
+
 	for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
 		close(i);
 	}
@@ -321,7 +341,6 @@
 int
 main()
 {
-
 	daemonize();
 	main_loop();
 	return 0;

Modified: soc2018/sduo/netmap_utils/fd_server.h
==============================================================================
--- soc2018/sduo/netmap_utils/fd_server.h	Wed Jun 27 15:52:47 2018	(r337264)
+++ soc2018/sduo/netmap_utils/fd_server.h	Wed Jun 27 16:17:21 2018	(r337265)
@@ -1,14 +1,7 @@
 #ifndef FD_LIB_H
 #define FD_LIB_H
 
-#include <errno.h>
-#include <net/if.h>
-#include <stdint.h>
-#include <sys/socket.h>
-
-#include <net/netmap.h>
-#define NETMAP_WITH_LIBS
-#include <net/netmap_user.h>
+#define SOCKET_NAME "/tmp/my_unix_socket"
 
 struct fd_request {
 #define FD_GET 1
@@ -16,7 +9,7 @@
 #define FD_CLOSE 3
 #define FD_STOP 4
 	uint8_t action;
-	char if_name[IFNAMSIZ];
+	char if_name[NETMAP_REQ_IFNAMSIZ];
 };
 
 struct fd_response {

Added: soc2018/sduo/netmap_utils/functional.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2018/sduo/netmap_utils/functional.c	Wed Jun 27 16:17:21 2018	(r337265)
@@ -0,0 +1,1245 @@
+/*
+ * A tool for functional testing netmap transmission and reception.
+ *
+ * Copyright (C) 2018 Vincenzo Maffione. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/netmap.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#define NETMAP_WITH_LIBS
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <net/netmap_user.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include "fd_server.h"
+
+#define ETH_ADDR_LEN 6
+
+struct Event {
+	unsigned evtype;
+#define EVENT_TYPE_RX 0x1
+#define EVENT_TYPE_TX 0x2
+#define EVENT_TYPE_PAUSE 0x3
+	unsigned num; /* > 1 if repeated event */
+
+	/* Tx and Rx event. */
+	unsigned pkt_len;
+	char filler;
+
+	/* Pause event. */
+	unsigned long long usecs;
+};
+
+struct Global {
+	struct nm_desc nmd;
+	const char *ifname;
+	unsigned wait_link_secs;    /* wait for link */
+	unsigned timeout_secs;      /* transmit/receive timeout */
+	int ignore_if_not_matching; /* ignore certain received packets */
+	int success_if_no_receive;  /* exit status 0 if we receive no packets */
+	int
+	        sequential_fill; /* increment fill char for multi-packets
+	                            operations */
+	int request_from_fd_server;
+	int verbose;
+
+#define MAX_PKT_SIZE 65536
+	char pktm[MAX_PKT_SIZE]; /* packet model */
+	unsigned pktm_len;       /* packet model length */
+	char pktr[MAX_PKT_SIZE]; /* packet received */
+	unsigned pktr_len;       /* length of received packet */
+	unsigned max_frag_size;  /* max bytes per netmap TX slot */
+
+	char src_mac[ETH_ADDR_LEN];
+	char dst_mac[ETH_ADDR_LEN];
+	uint32_t src_ip;
+	uint32_t dst_ip;
+	uint16_t src_port;
+	uint16_t dst_port;
+	char filler;
+
+#define MAX_EVENTS 64
+	unsigned num_events;
+	struct Event events[MAX_EVENTS];
+	unsigned num_loops;
+};
+
+void release_if_fd(struct Global *, const char *);
+
+void
+clean_exit(struct Global *g)
+{
+
+	release_if_fd(g, g->ifname);
+	exit(EXIT_FAILURE);
+}
+
+static void
+fill_packet_field(struct Global *g, unsigned offset, const char *content,
+                  unsigned content_len)
+{
+	if (offset + content_len > sizeof(g->pktm)) {
+		printf("Packet layout overflow: %u + %u > %lu\n", offset,
+		       content_len, sizeof(g->pktm));
+		clean_exit(g);
+	}
+
+	memcpy(g->pktm + offset, content, content_len);
+}
+
+static void
+fill_packet_8bit(struct Global *g, unsigned offset, uint8_t val)
+{
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_16bit(struct Global *g, unsigned offset, uint16_t val)
+{
+	val = htons(val);
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_32bit(struct Global *g, unsigned offset, uint32_t val)
+{
+	val = htonl(val);
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+/* Compute the checksum of the given ip header. */
+static uint32_t
+checksum(const void *data, uint16_t len, uint32_t sum /* host endianness */)
+{
+	const uint8_t *addr = data;
+	uint32_t i;
+
+	/* Checksum all the pairs of bytes first... */
+	for (i = 0; i < (len & ~1U); i += 2) {
+		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
+		if (sum > 0xFFFF) {
+			sum -= 0xFFFF;
+		}
+	}
+	/*
+	 * If there's a single byte left over, checksum it, too.
+	 * Network byte order is big-endian, so the remaining byte is
+	 * the high byte.
+	 */
+	if (i < len) {
+		sum += addr[i] << 8;
+		if (sum > 0xFFFF) {
+			sum -= 0xFFFF;
+		}
+	}
+	return sum;
+}
+
+static uint16_t
+wrapsum(uint32_t sum /* host endianness */)
+{
+	sum = ~sum & 0xFFFF;
+	return sum; /* host endianness */
+}
+
+static void
+build_packet(struct Global *g)
+{
+	unsigned ofs = 0;
+	unsigned ethofs;
+	unsigned ipofs;
+	unsigned udpofs;
+	unsigned pldofs;
+
+	memset(g->pktm, 0, sizeof(g->pktm));
+	if (g->verbose) {
+		printf("%s: starting at ofs %u\n", __func__, ofs);
+	}
+
+	ethofs = ofs;
+	(void)ethofs;
+	/* Ethernet destination and source MAC address plus ethertype. */
+	fill_packet_field(g, ofs, g->dst_mac, ETH_ADDR_LEN);
+	ofs += ETH_ADDR_LEN;
+	fill_packet_field(g, ofs, g->src_mac, ETH_ADDR_LEN);
+	ofs += ETH_ADDR_LEN;
+	fill_packet_16bit(g, ofs, ETHERTYPE_IP);
+	ofs += 2;
+	if (g->verbose) {
+		printf("%s: eth done, ofs %u\n", __func__, ofs);
+	}
+
+	ipofs = ofs;
+	/* First byte of IP header. */
+	fill_packet_8bit(g, ofs,
+	                 (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
+	ofs += 1;
+	/* Skip QoS byte. */
+	ofs += 1;
+	/* Total length. */
+	fill_packet_16bit(g, ofs, g->pktm_len - ipofs);
+	ofs += 2;
+	/* Skip identification field. */
+	ofs += 2;
+	/* Offset (and flags) field. */
+	fill_packet_16bit(g, ofs, IP_DF);
+	ofs += 2;
+	/* TTL. */
+	fill_packet_8bit(g, ofs, IPDEFTTL);
+	ofs += 1;
+	/* Protocol. */
+	fill_packet_8bit(g, ofs, IPPROTO_UDP);
+	ofs += 1;
+	/* Skip checksum for now. */
+	ofs += 2;
+	/* Source IP address. */
+	fill_packet_32bit(g, ofs, g->src_ip);
+	ofs += 4;
+	/* Dst IP address. */
+	fill_packet_32bit(g, ofs, g->dst_ip);
+	ofs += 4;
+	/* Now put the checksum. */
+	fill_packet_16bit(
+	        g, ipofs + 10,
+	        wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
+	if (g->verbose) {
+		printf("%s: ip done, ofs %u\n", __func__, ofs);
+	}
+
+	udpofs = ofs;
+	/* UDP source port. */
+	fill_packet_16bit(g, ofs, g->src_port);
+	ofs += 2;
+	/* UDP source port. */
+	fill_packet_16bit(g, ofs, g->dst_port);
+	ofs += 2;
+	/* UDP length (UDP header + data). */
+	fill_packet_16bit(g, ofs, g->pktm_len - udpofs);
+	ofs += 2;
+	/* Skip the UDP checksum for now. */
+	ofs += 2;
+	if (g->verbose) {
+		printf("%s: udp done, ofs %u\n", __func__, ofs);
+	}
+
+	/* Fill UDP payload. */
+	pldofs = ofs;
+	for (; ofs < g->pktm_len; ofs++) {
+		fill_packet_8bit(g, ofs, g->filler);
+	}
+	if (g->verbose) {
+		printf("%s: payload done, ofs %u\n", __func__, ofs);
+	}
+
+	/* Put the UDP checksum now.
+	 * Magic: taken from sbin/dhclient/packet.c */
+	fill_packet_16bit(
+	        g, udpofs + 6,
+	        wrapsum(checksum(
+	                /* udp header */ g->pktm + udpofs,
+	                sizeof(struct udphdr),
+	                checksum(/* udp payload */ g->pktm + pldofs,
+	                         g->pktm_len - pldofs,
+	                         checksum(/* pseudo header */ g->pktm + ipofs +
+	                                          12,
+	                                  2 * sizeof(g->src_ip),
+	                                  IPPROTO_UDP + (uint32_t)(g->pktm_len -
+	                                                           udpofs))))));
+}
+
+// static unsigned
+// tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
+// {
+// 	unsigned avail_per_slot = ring->nr_buf_size;
+
+// 	if (max_frag_size < avail_per_slot) {
+// 		avail_per_slot = max_frag_size;
+// 	}
+
+// 	return nm_ring_space(ring) * avail_per_slot;
+// }
+
+static int
+tx_flush(struct Global *g)
+{
+	struct nm_desc *nmd = &g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	int i;
+
+	for (;;) {
+		int pending = 0;
+		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+			pending += nm_tx_pending(ring);
+		}
+
+		if (!pending) {
+			return 0;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+}
+
+uint64_t
+ring_avail_packets(struct netmap_ring *ring, unsigned pkt_len)
+{
+	uint64_t slot_per_packet;
+
+	slot_per_packet = ceil((double)pkt_len / (double)ring->nr_buf_size);
+	return nm_ring_space(ring) / slot_per_packet;
+}
+
+uint64_t
+adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t sends_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+		sends_available += ring_avail_packets(ring, pkt_len);
+	}
+
+	return sends_available;
+}
+
+void
+put_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+	unsigned head  = ring->head;
+	unsigned frags = 0;
+	unsigned ofs   = 0;
+
+	for (;;) {
+		struct netmap_slot *slot = &ring->slot[head];
+		char *buf                = NETMAP_BUF(ring, slot->buf_idx);
+		unsigned copysize        = g->pktm_len - ofs;
+
+		if (copysize > ring->nr_buf_size) {
+			copysize = ring->nr_buf_size;
+		}
+		if (copysize > g->max_frag_size) {
+			copysize = g->max_frag_size;
+		}
+
+		memcpy(buf, g->pktm + ofs, copysize);
+		ofs += copysize;
+		slot->len   = copysize;
+		slot->flags = NS_MOREFRAG;
+		head        = nm_ring_next(ring, head);
+		frags++;
+		if (ofs >= g->pktm_len) {
+			/* Last fragment. */
+			assert(ofs == g->pktm_len);
+			slot->flags = NS_REPORT;
+			break;
+		}
+	}
+
+	ring->head = ring->cur = head;
+	printf("packet (%u bytes, %u frags) placed to TX\n", g->pktm_len,
+	       frags);
+}
+
+char
+next_fill(char cur_fill)
+{
+	if (cur_fill == 'z')
+		return 'a';
+	if (cur_fill == 'Z')
+		return 'A';
+	return ++cur_fill;
+}
+
+/* Transmit packets_num packets using any combination of TX rings. */
+static int
+tx(struct Global *g, unsigned packets_num)
+{
+	struct nm_desc *nmd = &g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	unsigned int i;
+
+	/* We cycle here until either we timeout or we find enough space. */
+	for (;;) {
+		if (adapter_avail_sends(nmd, g->pktm_len) >= packets_num) {
+			break;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		/* Retry after a short while. */
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+
+	/* Once we have enough space, we start filling slots. We might use
+	 * multiple rings.
+	 */
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+		uint64_t ring_sends_num;
+
+		for (ring_sends_num = ring_avail_packets(ring, g->pktm_len);
+		     ring_sends_num > 0 && packets_num > 0;
+		     --ring_sends_num, --packets_num) {
+			put_one_packet(g, ring);
+
+			if (g->sequential_fill == 1) {
+				g->filler = next_fill(g->filler);
+				build_packet(g);
+			}
+		}
+
+		if (packets_num == 0) {
+			break;
+		}
+	}
+
+	assert(packets_num == 0);
+	/* Once we're done we sync, sending all packets at once. */
+	ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	return 0;
+}
+
+/* If -I option is specified, we want to ignore frames that don't match
+ * our expected ethernet header.
+ * This function currently assumes that Ethernet header starts from
+ * the beginning of the packet buffers. */
+static int
+ignore_received_frame(struct Global *g)
+{
+	if (!g->ignore_if_not_matching) {
+		return 0; /* don't ignore */
+	}
+
+	if (g->pktr_len < 14 || memcmp(g->pktm, g->pktr, 14) != 0) {
+		return 1; /* ignore */
+	}
+
+	return 0; /* don't ignore */
+}
+
+uint64_t
+adapter_avail_receives(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t receives_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+
+		receives_available += ring_avail_packets(ring, pkt_len);
+	}
+
+	return receives_available;
+}
+
+static int
+rx_check(struct Global *g)
+{
+	unsigned i;
+
+	if (g->pktr_len != g->pktm_len) {
+		printf("Received packet length (%u) different from "
+		       "expected (%u bytes)\n",
+		       g->pktr_len, g->pktm_len);
+		return -1;
+	}
+
+	for (i = 0; i < g->pktr_len; i++) {
+		if (g->pktr[i] != g->pktm[i]) {
+			printf("Received packet differs from model at "
+			       "offset %u (0x%02x!=0x%02x)\n",
+			       i, g->pktr[i], (uint8_t)g->pktm[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int
+read_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+	unsigned head = ring->head;
+	int frags     = 0;
+
+	g->pktr_len = 0;
+	for (;;) {
+		struct netmap_slot *slot = &ring->slot[head];
+		char *buf                = NETMAP_BUF(ring, slot->buf_idx);
+
+		if (g->pktr_len + slot->len > sizeof(g->pktr)) {
+			/* Sanity check. */
+			printf("Error: received packet too "
+			       "large "
+			       "(>= %u bytes) ",
+			       g->pktr_len + slot->len);
+			clean_exit(g);
+		}
+
+		memcpy(g->pktr + g->pktr_len, buf, slot->len);
+		g->pktr_len += slot->len;
+		head = nm_ring_next(ring, head);
+		frags++;
+		if (!(slot->flags & NS_MOREFRAG)) {
+			break;
+		}
+
+		if (head == ring->tail) {
+			printf("warning: truncated packet "
+			       "(len=%u)\n",
+			       g->pktr_len);
+			frags = -1;
+			break;
+		}
+	}
+
+	ring->head = ring->cur = head;
+	printf("packet (%u bytes, %d frags) received "
+	       "from RX\n",
+	       g->pktr_len, frags);
+	return frags;
+}
+
+/* Receive packets_num packets from any combination of RX rings. */
+static int
+rx(struct Global *g, unsigned packets_num)
+{
+	struct nm_desc *nmd = &g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	unsigned int i;
+
+	/* We cycle here until either we timeout or we find enough space. */
+	for (;;) {
+	again:
+		if (adapter_avail_receives(nmd, g->pktm_len) >= packets_num) {
+			break;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			/* -n flag */
+			return g->success_if_no_receive == 1 ? 0 : -1;
+		}
+
+		/* Retry after a short while. */
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+		ioctl(nmd->fd, NIOCRXSYNC, NULL);
+	}
+
+	/* Once we have enough space, we start reading packets. We might use
+	 * multiple rings.
+	 */
+	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+		uint64_t ring_receives_num;
+
+		for (ring_receives_num = ring_avail_packets(ring, g->pktm_len);
+		     ring_receives_num > 0 && packets_num > 0;
+		     --ring_receives_num, --packets_num) {
+			int frags = 0;
+
+			frags = read_one_packet(g, ring);
+			if (frags == -1) {
+				break; /* Truncated packet, skip this ring. */
+			}
+
+			if (ignore_received_frame(g)) {
+				if (g->verbose) {
+					printf("(ignoring packet with %u bytes "
+					       "and "
+					       "%d frags received from RX ring "
+					       "#%d)\n",
+					       g->pktr_len, frags, i);
+				}
+				elapsed_ms = 0;
+				/* We can go back there, because we're
+				 * decrementing packets_num each time, therefore
+				 * the we will wait only for the remaining
+				 * packets.
+				 */
+				goto again;
+			}
+
+			/* As soon as we find a packet wich doesn't match our
+			 * packet model we exit with status EXIT_FAILURE.
+			 */
+			if (rx_check(g)) {
+				clean_exit(g);
+			}
+
+			if (g->sequential_fill == 1) {
+				g->filler = next_fill(g->filler);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-soc-all mailing list