xref: /linux/tools/testing/selftests/net/udpgso_bench_tx.c (revision 3327a9c46352f111697d93d6134e7bf37c6bffca)
13a687befSWillem de Bruijn // SPDX-License-Identifier: GPL-2.0
23a687befSWillem de Bruijn 
33a687befSWillem de Bruijn #define _GNU_SOURCE
43a687befSWillem de Bruijn 
53a687befSWillem de Bruijn #include <arpa/inet.h>
63a687befSWillem de Bruijn #include <errno.h>
73a687befSWillem de Bruijn #include <error.h>
83a687befSWillem de Bruijn #include <netinet/if_ether.h>
93a687befSWillem de Bruijn #include <netinet/in.h>
103a687befSWillem de Bruijn #include <netinet/ip.h>
113a687befSWillem de Bruijn #include <netinet/ip6.h>
123a687befSWillem de Bruijn #include <netinet/udp.h>
133a687befSWillem de Bruijn #include <poll.h>
143a687befSWillem de Bruijn #include <sched.h>
153a687befSWillem de Bruijn #include <signal.h>
163a687befSWillem de Bruijn #include <stdbool.h>
173a687befSWillem de Bruijn #include <stdio.h>
183a687befSWillem de Bruijn #include <stdlib.h>
193a687befSWillem de Bruijn #include <string.h>
203a687befSWillem de Bruijn #include <sys/socket.h>
213a687befSWillem de Bruijn #include <sys/time.h>
223a687befSWillem de Bruijn #include <sys/types.h>
233a687befSWillem de Bruijn #include <unistd.h>
243a687befSWillem de Bruijn 
253a687befSWillem de Bruijn #ifndef ETH_MAX_MTU
263a687befSWillem de Bruijn #define ETH_MAX_MTU 0xFFFFU
273a687befSWillem de Bruijn #endif
283a687befSWillem de Bruijn 
293a687befSWillem de Bruijn #ifndef UDP_SEGMENT
303a687befSWillem de Bruijn #define UDP_SEGMENT		103
313a687befSWillem de Bruijn #endif
323a687befSWillem de Bruijn 
333a687befSWillem de Bruijn #ifndef SO_ZEROCOPY
343a687befSWillem de Bruijn #define SO_ZEROCOPY	60
353a687befSWillem de Bruijn #endif
363a687befSWillem de Bruijn 
373a687befSWillem de Bruijn #ifndef MSG_ZEROCOPY
383a687befSWillem de Bruijn #define MSG_ZEROCOPY	0x4000000
393a687befSWillem de Bruijn #endif
403a687befSWillem de Bruijn 
413a687befSWillem de Bruijn #define NUM_PKT		100
423a687befSWillem de Bruijn 
433a687befSWillem de Bruijn static bool	cfg_cache_trash;
443a687befSWillem de Bruijn static int	cfg_cpu		= -1;
453a687befSWillem de Bruijn static int	cfg_connected	= true;
463a687befSWillem de Bruijn static int	cfg_family	= PF_UNSPEC;
473a687befSWillem de Bruijn static uint16_t	cfg_mss;
483a687befSWillem de Bruijn static int	cfg_payload_len	= (1472 * 42);
493a687befSWillem de Bruijn static int	cfg_port	= 8000;
503a687befSWillem de Bruijn static int	cfg_runtime_ms	= -1;
513a687befSWillem de Bruijn static bool	cfg_segment;
523a687befSWillem de Bruijn static bool	cfg_sendmmsg;
533a687befSWillem de Bruijn static bool	cfg_tcp;
543a687befSWillem de Bruijn static bool	cfg_zerocopy;
55*3327a9c4SPaolo Abeni static int	cfg_msg_nr;
56*3327a9c4SPaolo Abeni static uint16_t	cfg_gso_size;
573a687befSWillem de Bruijn 
583a687befSWillem de Bruijn static socklen_t cfg_alen;
593a687befSWillem de Bruijn static struct sockaddr_storage cfg_dst_addr;
603a687befSWillem de Bruijn 
613a687befSWillem de Bruijn static bool interrupted;
623a687befSWillem de Bruijn static char buf[NUM_PKT][ETH_MAX_MTU];
633a687befSWillem de Bruijn 
643a687befSWillem de Bruijn static void sigint_handler(int signum)
653a687befSWillem de Bruijn {
663a687befSWillem de Bruijn 	if (signum == SIGINT)
673a687befSWillem de Bruijn 		interrupted = true;
683a687befSWillem de Bruijn }
693a687befSWillem de Bruijn 
703a687befSWillem de Bruijn static unsigned long gettimeofday_ms(void)
713a687befSWillem de Bruijn {
723a687befSWillem de Bruijn 	struct timeval tv;
733a687befSWillem de Bruijn 
743a687befSWillem de Bruijn 	gettimeofday(&tv, NULL);
753a687befSWillem de Bruijn 	return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
763a687befSWillem de Bruijn }
773a687befSWillem de Bruijn 
783a687befSWillem de Bruijn static int set_cpu(int cpu)
793a687befSWillem de Bruijn {
803a687befSWillem de Bruijn 	cpu_set_t mask;
813a687befSWillem de Bruijn 
823a687befSWillem de Bruijn 	CPU_ZERO(&mask);
833a687befSWillem de Bruijn 	CPU_SET(cpu, &mask);
843a687befSWillem de Bruijn 	if (sched_setaffinity(0, sizeof(mask), &mask))
853a687befSWillem de Bruijn 		error(1, 0, "setaffinity %d", cpu);
863a687befSWillem de Bruijn 
873a687befSWillem de Bruijn 	return 0;
883a687befSWillem de Bruijn }
893a687befSWillem de Bruijn 
903a687befSWillem de Bruijn static void setup_sockaddr(int domain, const char *str_addr, void *sockaddr)
913a687befSWillem de Bruijn {
923a687befSWillem de Bruijn 	struct sockaddr_in6 *addr6 = (void *) sockaddr;
933a687befSWillem de Bruijn 	struct sockaddr_in *addr4 = (void *) sockaddr;
943a687befSWillem de Bruijn 
953a687befSWillem de Bruijn 	switch (domain) {
963a687befSWillem de Bruijn 	case PF_INET:
973a687befSWillem de Bruijn 		addr4->sin_family = AF_INET;
983a687befSWillem de Bruijn 		addr4->sin_port = htons(cfg_port);
993a687befSWillem de Bruijn 		if (inet_pton(AF_INET, str_addr, &(addr4->sin_addr)) != 1)
1003a687befSWillem de Bruijn 			error(1, 0, "ipv4 parse error: %s", str_addr);
1013a687befSWillem de Bruijn 		break;
1023a687befSWillem de Bruijn 	case PF_INET6:
1033a687befSWillem de Bruijn 		addr6->sin6_family = AF_INET6;
1043a687befSWillem de Bruijn 		addr6->sin6_port = htons(cfg_port);
1053a687befSWillem de Bruijn 		if (inet_pton(AF_INET6, str_addr, &(addr6->sin6_addr)) != 1)
1063a687befSWillem de Bruijn 			error(1, 0, "ipv6 parse error: %s", str_addr);
1073a687befSWillem de Bruijn 		break;
1083a687befSWillem de Bruijn 	default:
1093a687befSWillem de Bruijn 		error(1, 0, "illegal domain");
1103a687befSWillem de Bruijn 	}
1113a687befSWillem de Bruijn }
1123a687befSWillem de Bruijn 
1133a687befSWillem de Bruijn static void flush_zerocopy(int fd)
1143a687befSWillem de Bruijn {
1153a687befSWillem de Bruijn 	struct msghdr msg = {0};	/* flush */
1163a687befSWillem de Bruijn 	int ret;
1173a687befSWillem de Bruijn 
1183a687befSWillem de Bruijn 	while (1) {
1193a687befSWillem de Bruijn 		ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
1203a687befSWillem de Bruijn 		if (ret == -1 && errno == EAGAIN)
1213a687befSWillem de Bruijn 			break;
1223a687befSWillem de Bruijn 		if (ret == -1)
1233a687befSWillem de Bruijn 			error(1, errno, "errqueue");
1243a687befSWillem de Bruijn 		if (msg.msg_flags != (MSG_ERRQUEUE | MSG_CTRUNC))
1253a687befSWillem de Bruijn 			error(1, 0, "errqueue: flags 0x%x\n", msg.msg_flags);
1263a687befSWillem de Bruijn 		msg.msg_flags = 0;
1273a687befSWillem de Bruijn 	}
1283a687befSWillem de Bruijn }
1293a687befSWillem de Bruijn 
1303a687befSWillem de Bruijn static int send_tcp(int fd, char *data)
1313a687befSWillem de Bruijn {
1323a687befSWillem de Bruijn 	int ret, done = 0, count = 0;
1333a687befSWillem de Bruijn 
1343a687befSWillem de Bruijn 	while (done < cfg_payload_len) {
1353a687befSWillem de Bruijn 		ret = send(fd, data + done, cfg_payload_len - done,
1363a687befSWillem de Bruijn 			   cfg_zerocopy ? MSG_ZEROCOPY : 0);
1373a687befSWillem de Bruijn 		if (ret == -1)
1383a687befSWillem de Bruijn 			error(1, errno, "write");
1393a687befSWillem de Bruijn 
1403a687befSWillem de Bruijn 		done += ret;
1413a687befSWillem de Bruijn 		count++;
1423a687befSWillem de Bruijn 	}
1433a687befSWillem de Bruijn 
1443a687befSWillem de Bruijn 	return count;
1453a687befSWillem de Bruijn }
1463a687befSWillem de Bruijn 
1473a687befSWillem de Bruijn static int send_udp(int fd, char *data)
1483a687befSWillem de Bruijn {
1493a687befSWillem de Bruijn 	int ret, total_len, len, count = 0;
1503a687befSWillem de Bruijn 
1513a687befSWillem de Bruijn 	total_len = cfg_payload_len;
1523a687befSWillem de Bruijn 
1533a687befSWillem de Bruijn 	while (total_len) {
1543a687befSWillem de Bruijn 		len = total_len < cfg_mss ? total_len : cfg_mss;
1553a687befSWillem de Bruijn 
1563a687befSWillem de Bruijn 		ret = sendto(fd, data, len, cfg_zerocopy ? MSG_ZEROCOPY : 0,
1573a687befSWillem de Bruijn 			     cfg_connected ? NULL : (void *)&cfg_dst_addr,
1583a687befSWillem de Bruijn 			     cfg_connected ? 0 : cfg_alen);
1593a687befSWillem de Bruijn 		if (ret == -1)
1603a687befSWillem de Bruijn 			error(1, errno, "write");
1613a687befSWillem de Bruijn 		if (ret != len)
1623a687befSWillem de Bruijn 			error(1, errno, "write: %uB != %uB\n", ret, len);
1633a687befSWillem de Bruijn 
1643a687befSWillem de Bruijn 		total_len -= len;
1653a687befSWillem de Bruijn 		count++;
1663a687befSWillem de Bruijn 	}
1673a687befSWillem de Bruijn 
1683a687befSWillem de Bruijn 	return count;
1693a687befSWillem de Bruijn }
1703a687befSWillem de Bruijn 
1713a687befSWillem de Bruijn static int send_udp_sendmmsg(int fd, char *data)
1723a687befSWillem de Bruijn {
1733a687befSWillem de Bruijn 	const int max_nr_msg = ETH_MAX_MTU / ETH_DATA_LEN;
1743a687befSWillem de Bruijn 	struct mmsghdr mmsgs[max_nr_msg];
1753a687befSWillem de Bruijn 	struct iovec iov[max_nr_msg];
1763a687befSWillem de Bruijn 	unsigned int off = 0, left;
1773a687befSWillem de Bruijn 	int i = 0, ret;
1783a687befSWillem de Bruijn 
1793a687befSWillem de Bruijn 	memset(mmsgs, 0, sizeof(mmsgs));
1803a687befSWillem de Bruijn 
1813a687befSWillem de Bruijn 	left = cfg_payload_len;
1823a687befSWillem de Bruijn 	while (left) {
1833a687befSWillem de Bruijn 		if (i == max_nr_msg)
1843a687befSWillem de Bruijn 			error(1, 0, "sendmmsg: exceeds max_nr_msg");
1853a687befSWillem de Bruijn 
1863a687befSWillem de Bruijn 		iov[i].iov_base = data + off;
1873a687befSWillem de Bruijn 		iov[i].iov_len = cfg_mss < left ? cfg_mss : left;
1883a687befSWillem de Bruijn 
1893a687befSWillem de Bruijn 		mmsgs[i].msg_hdr.msg_iov = iov + i;
1903a687befSWillem de Bruijn 		mmsgs[i].msg_hdr.msg_iovlen = 1;
1913a687befSWillem de Bruijn 
1923a687befSWillem de Bruijn 		off += iov[i].iov_len;
1933a687befSWillem de Bruijn 		left -= iov[i].iov_len;
1943a687befSWillem de Bruijn 		i++;
1953a687befSWillem de Bruijn 	}
1963a687befSWillem de Bruijn 
1973a687befSWillem de Bruijn 	ret = sendmmsg(fd, mmsgs, i, cfg_zerocopy ? MSG_ZEROCOPY : 0);
1983a687befSWillem de Bruijn 	if (ret == -1)
1993a687befSWillem de Bruijn 		error(1, errno, "sendmmsg");
2003a687befSWillem de Bruijn 
2013a687befSWillem de Bruijn 	return ret;
2023a687befSWillem de Bruijn }
2033a687befSWillem de Bruijn 
2043a687befSWillem de Bruijn static void send_udp_segment_cmsg(struct cmsghdr *cm)
2053a687befSWillem de Bruijn {
2063a687befSWillem de Bruijn 	uint16_t *valp;
2073a687befSWillem de Bruijn 
2083a687befSWillem de Bruijn 	cm->cmsg_level = SOL_UDP;
2093a687befSWillem de Bruijn 	cm->cmsg_type = UDP_SEGMENT;
210*3327a9c4SPaolo Abeni 	cm->cmsg_len = CMSG_LEN(sizeof(cfg_gso_size));
2113a687befSWillem de Bruijn 	valp = (void *)CMSG_DATA(cm);
212*3327a9c4SPaolo Abeni 	*valp = cfg_gso_size;
2133a687befSWillem de Bruijn }
2143a687befSWillem de Bruijn 
2153a687befSWillem de Bruijn static int send_udp_segment(int fd, char *data)
2163a687befSWillem de Bruijn {
217*3327a9c4SPaolo Abeni 	char control[CMSG_SPACE(sizeof(cfg_gso_size))] = {0};
2183a687befSWillem de Bruijn 	struct msghdr msg = {0};
2193a687befSWillem de Bruijn 	struct iovec iov = {0};
2203a687befSWillem de Bruijn 	int ret;
2213a687befSWillem de Bruijn 
2223a687befSWillem de Bruijn 	iov.iov_base = data;
2233a687befSWillem de Bruijn 	iov.iov_len = cfg_payload_len;
2243a687befSWillem de Bruijn 
2253a687befSWillem de Bruijn 	msg.msg_iov = &iov;
2263a687befSWillem de Bruijn 	msg.msg_iovlen = 1;
2273a687befSWillem de Bruijn 
2283a687befSWillem de Bruijn 	msg.msg_control = control;
2293a687befSWillem de Bruijn 	msg.msg_controllen = sizeof(control);
2303a687befSWillem de Bruijn 	send_udp_segment_cmsg(CMSG_FIRSTHDR(&msg));
2313a687befSWillem de Bruijn 
2323a687befSWillem de Bruijn 	msg.msg_name = (void *)&cfg_dst_addr;
2333a687befSWillem de Bruijn 	msg.msg_namelen = cfg_alen;
2343a687befSWillem de Bruijn 
2353a687befSWillem de Bruijn 	ret = sendmsg(fd, &msg, cfg_zerocopy ? MSG_ZEROCOPY : 0);
2363a687befSWillem de Bruijn 	if (ret == -1)
2373a687befSWillem de Bruijn 		error(1, errno, "sendmsg");
2383a687befSWillem de Bruijn 	if (ret != iov.iov_len)
2393a687befSWillem de Bruijn 		error(1, 0, "sendmsg: %u != %lu\n", ret, iov.iov_len);
2403a687befSWillem de Bruijn 
2413a687befSWillem de Bruijn 	return 1;
2423a687befSWillem de Bruijn }
2433a687befSWillem de Bruijn 
2443a687befSWillem de Bruijn static void usage(const char *filepath)
2453a687befSWillem de Bruijn {
246*3327a9c4SPaolo Abeni 	error(1, 0, "Usage: %s [-46cmtuz] [-C cpu] [-D dst ip] [-l secs] [-m messagenr] [-p port] [-s sendsize] [-S gsosize]",
2473a687befSWillem de Bruijn 		    filepath);
2483a687befSWillem de Bruijn }
2493a687befSWillem de Bruijn 
2503a687befSWillem de Bruijn static void parse_opts(int argc, char **argv)
2513a687befSWillem de Bruijn {
2523a687befSWillem de Bruijn 	int max_len, hdrlen;
2533a687befSWillem de Bruijn 	int c;
2543a687befSWillem de Bruijn 
255*3327a9c4SPaolo Abeni 	while ((c = getopt(argc, argv, "46cC:D:l:mM:p:s:S:tuz")) != -1) {
2563a687befSWillem de Bruijn 		switch (c) {
2573a687befSWillem de Bruijn 		case '4':
2583a687befSWillem de Bruijn 			if (cfg_family != PF_UNSPEC)
2593a687befSWillem de Bruijn 				error(1, 0, "Pass one of -4 or -6");
2603a687befSWillem de Bruijn 			cfg_family = PF_INET;
2613a687befSWillem de Bruijn 			cfg_alen = sizeof(struct sockaddr_in);
2623a687befSWillem de Bruijn 			break;
2633a687befSWillem de Bruijn 		case '6':
2643a687befSWillem de Bruijn 			if (cfg_family != PF_UNSPEC)
2653a687befSWillem de Bruijn 				error(1, 0, "Pass one of -4 or -6");
2663a687befSWillem de Bruijn 			cfg_family = PF_INET6;
2673a687befSWillem de Bruijn 			cfg_alen = sizeof(struct sockaddr_in6);
2683a687befSWillem de Bruijn 			break;
2693a687befSWillem de Bruijn 		case 'c':
2703a687befSWillem de Bruijn 			cfg_cache_trash = true;
2713a687befSWillem de Bruijn 			break;
2723a687befSWillem de Bruijn 		case 'C':
2733a687befSWillem de Bruijn 			cfg_cpu = strtol(optarg, NULL, 0);
2743a687befSWillem de Bruijn 			break;
2753a687befSWillem de Bruijn 		case 'D':
2763a687befSWillem de Bruijn 			setup_sockaddr(cfg_family, optarg, &cfg_dst_addr);
2773a687befSWillem de Bruijn 			break;
2783a687befSWillem de Bruijn 		case 'l':
2793a687befSWillem de Bruijn 			cfg_runtime_ms = strtoul(optarg, NULL, 10) * 1000;
2803a687befSWillem de Bruijn 			break;
2813a687befSWillem de Bruijn 		case 'm':
2823a687befSWillem de Bruijn 			cfg_sendmmsg = true;
2833a687befSWillem de Bruijn 			break;
284*3327a9c4SPaolo Abeni 		case 'M':
285*3327a9c4SPaolo Abeni 			cfg_msg_nr = strtoul(optarg, NULL, 10);
286*3327a9c4SPaolo Abeni 			break;
2873a687befSWillem de Bruijn 		case 'p':
2883a687befSWillem de Bruijn 			cfg_port = strtoul(optarg, NULL, 0);
2893a687befSWillem de Bruijn 			break;
2903a687befSWillem de Bruijn 		case 's':
2913a687befSWillem de Bruijn 			cfg_payload_len = strtoul(optarg, NULL, 0);
2923a687befSWillem de Bruijn 			break;
2933a687befSWillem de Bruijn 		case 'S':
294*3327a9c4SPaolo Abeni 			cfg_gso_size = strtoul(optarg, NULL, 0);
2953a687befSWillem de Bruijn 			cfg_segment = true;
2963a687befSWillem de Bruijn 			break;
2973a687befSWillem de Bruijn 		case 't':
2983a687befSWillem de Bruijn 			cfg_tcp = true;
2993a687befSWillem de Bruijn 			break;
3003a687befSWillem de Bruijn 		case 'u':
3013a687befSWillem de Bruijn 			cfg_connected = false;
3023a687befSWillem de Bruijn 			break;
3033a687befSWillem de Bruijn 		case 'z':
3043a687befSWillem de Bruijn 			cfg_zerocopy = true;
3053a687befSWillem de Bruijn 			break;
3063a687befSWillem de Bruijn 		}
3073a687befSWillem de Bruijn 	}
3083a687befSWillem de Bruijn 
3093a687befSWillem de Bruijn 	if (optind != argc)
3103a687befSWillem de Bruijn 		usage(argv[0]);
3113a687befSWillem de Bruijn 
3123a687befSWillem de Bruijn 	if (cfg_family == PF_UNSPEC)
3133a687befSWillem de Bruijn 		error(1, 0, "must pass one of -4 or -6");
3143a687befSWillem de Bruijn 	if (cfg_tcp && !cfg_connected)
3153a687befSWillem de Bruijn 		error(1, 0, "connectionless tcp makes no sense");
3163a687befSWillem de Bruijn 	if (cfg_segment && cfg_sendmmsg)
3173a687befSWillem de Bruijn 		error(1, 0, "cannot combine segment offload and sendmmsg");
3183a687befSWillem de Bruijn 
3193a687befSWillem de Bruijn 	if (cfg_family == PF_INET)
3203a687befSWillem de Bruijn 		hdrlen = sizeof(struct iphdr) + sizeof(struct udphdr);
3213a687befSWillem de Bruijn 	else
3223a687befSWillem de Bruijn 		hdrlen = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
3233a687befSWillem de Bruijn 
3243a687befSWillem de Bruijn 	cfg_mss = ETH_DATA_LEN - hdrlen;
3253a687befSWillem de Bruijn 	max_len = ETH_MAX_MTU - hdrlen;
326*3327a9c4SPaolo Abeni 	if (!cfg_gso_size)
327*3327a9c4SPaolo Abeni 		cfg_gso_size = cfg_mss;
3283a687befSWillem de Bruijn 
3293a687befSWillem de Bruijn 	if (cfg_payload_len > max_len)
3303a687befSWillem de Bruijn 		error(1, 0, "payload length %u exceeds max %u",
3313a687befSWillem de Bruijn 		      cfg_payload_len, max_len);
3323a687befSWillem de Bruijn }
3333a687befSWillem de Bruijn 
3343a687befSWillem de Bruijn static void set_pmtu_discover(int fd, bool is_ipv4)
3353a687befSWillem de Bruijn {
3363a687befSWillem de Bruijn 	int level, name, val;
3373a687befSWillem de Bruijn 
3383a687befSWillem de Bruijn 	if (is_ipv4) {
3393a687befSWillem de Bruijn 		level	= SOL_IP;
3403a687befSWillem de Bruijn 		name	= IP_MTU_DISCOVER;
3413a687befSWillem de Bruijn 		val	= IP_PMTUDISC_DO;
3423a687befSWillem de Bruijn 	} else {
3433a687befSWillem de Bruijn 		level	= SOL_IPV6;
3443a687befSWillem de Bruijn 		name	= IPV6_MTU_DISCOVER;
3453a687befSWillem de Bruijn 		val	= IPV6_PMTUDISC_DO;
3463a687befSWillem de Bruijn 	}
3473a687befSWillem de Bruijn 
3483a687befSWillem de Bruijn 	if (setsockopt(fd, level, name, &val, sizeof(val)))
3493a687befSWillem de Bruijn 		error(1, errno, "setsockopt path mtu");
3503a687befSWillem de Bruijn }
3513a687befSWillem de Bruijn 
3523a687befSWillem de Bruijn int main(int argc, char **argv)
3533a687befSWillem de Bruijn {
3543a687befSWillem de Bruijn 	unsigned long num_msgs, num_sends;
3553a687befSWillem de Bruijn 	unsigned long tnow, treport, tstop;
3563a687befSWillem de Bruijn 	int fd, i, val;
3573a687befSWillem de Bruijn 
3583a687befSWillem de Bruijn 	parse_opts(argc, argv);
3593a687befSWillem de Bruijn 
3603a687befSWillem de Bruijn 	if (cfg_cpu > 0)
3613a687befSWillem de Bruijn 		set_cpu(cfg_cpu);
3623a687befSWillem de Bruijn 
3633a687befSWillem de Bruijn 	for (i = 0; i < sizeof(buf[0]); i++)
3643a687befSWillem de Bruijn 		buf[0][i] = 'a' + (i % 26);
3653a687befSWillem de Bruijn 	for (i = 1; i < NUM_PKT; i++)
3663a687befSWillem de Bruijn 		memcpy(buf[i], buf[0], sizeof(buf[0]));
3673a687befSWillem de Bruijn 
3683a687befSWillem de Bruijn 	signal(SIGINT, sigint_handler);
3693a687befSWillem de Bruijn 
3703a687befSWillem de Bruijn 	fd = socket(cfg_family, cfg_tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
3713a687befSWillem de Bruijn 	if (fd == -1)
3723a687befSWillem de Bruijn 		error(1, errno, "socket");
3733a687befSWillem de Bruijn 
3743a687befSWillem de Bruijn 	if (cfg_zerocopy) {
3753a687befSWillem de Bruijn 		val = 1;
3763a687befSWillem de Bruijn 		if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val)))
3773a687befSWillem de Bruijn 			error(1, errno, "setsockopt zerocopy");
3783a687befSWillem de Bruijn 	}
3793a687befSWillem de Bruijn 
3803a687befSWillem de Bruijn 	if (cfg_connected &&
3813a687befSWillem de Bruijn 	    connect(fd, (void *)&cfg_dst_addr, cfg_alen))
3823a687befSWillem de Bruijn 		error(1, errno, "connect");
3833a687befSWillem de Bruijn 
3843a687befSWillem de Bruijn 	if (cfg_segment)
3853a687befSWillem de Bruijn 		set_pmtu_discover(fd, cfg_family == PF_INET);
3863a687befSWillem de Bruijn 
3873a687befSWillem de Bruijn 	num_msgs = num_sends = 0;
3883a687befSWillem de Bruijn 	tnow = gettimeofday_ms();
3893a687befSWillem de Bruijn 	tstop = tnow + cfg_runtime_ms;
3903a687befSWillem de Bruijn 	treport = tnow + 1000;
3913a687befSWillem de Bruijn 
3923a687befSWillem de Bruijn 	i = 0;
3933a687befSWillem de Bruijn 	do {
3943a687befSWillem de Bruijn 		if (cfg_tcp)
3953a687befSWillem de Bruijn 			num_sends += send_tcp(fd, buf[i]);
3963a687befSWillem de Bruijn 		else if (cfg_segment)
3973a687befSWillem de Bruijn 			num_sends += send_udp_segment(fd, buf[i]);
3983a687befSWillem de Bruijn 		else if (cfg_sendmmsg)
3993a687befSWillem de Bruijn 			num_sends += send_udp_sendmmsg(fd, buf[i]);
4003a687befSWillem de Bruijn 		else
4013a687befSWillem de Bruijn 			num_sends += send_udp(fd, buf[i]);
4023a687befSWillem de Bruijn 		num_msgs++;
4033a687befSWillem de Bruijn 		if (cfg_zerocopy && ((num_msgs & 0xF) == 0))
4043a687befSWillem de Bruijn 			flush_zerocopy(fd);
4053a687befSWillem de Bruijn 
406*3327a9c4SPaolo Abeni 		if (cfg_msg_nr && num_msgs >= cfg_msg_nr)
407*3327a9c4SPaolo Abeni 			break;
408*3327a9c4SPaolo Abeni 
4093a687befSWillem de Bruijn 		tnow = gettimeofday_ms();
4103a687befSWillem de Bruijn 		if (tnow > treport) {
4113a687befSWillem de Bruijn 			fprintf(stderr,
4123a687befSWillem de Bruijn 				"%s tx: %6lu MB/s %8lu calls/s %6lu msg/s\n",
4133a687befSWillem de Bruijn 				cfg_tcp ? "tcp" : "udp",
4143a687befSWillem de Bruijn 				(num_msgs * cfg_payload_len) >> 20,
4153a687befSWillem de Bruijn 				num_sends, num_msgs);
4163a687befSWillem de Bruijn 			num_msgs = num_sends = 0;
4173a687befSWillem de Bruijn 			treport = tnow + 1000;
4183a687befSWillem de Bruijn 		}
4193a687befSWillem de Bruijn 
4203a687befSWillem de Bruijn 		/* cold cache when writing buffer */
4213a687befSWillem de Bruijn 		if (cfg_cache_trash)
4223a687befSWillem de Bruijn 			i = ++i < NUM_PKT ? i : 0;
4233a687befSWillem de Bruijn 
4243a687befSWillem de Bruijn 	} while (!interrupted && (cfg_runtime_ms == -1 || tnow < tstop));
4253a687befSWillem de Bruijn 
4263a687befSWillem de Bruijn 	if (close(fd))
4273a687befSWillem de Bruijn 		error(1, errno, "close");
4283a687befSWillem de Bruijn 
4293a687befSWillem de Bruijn 	return 0;
4303a687befSWillem de Bruijn }
431