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