171082faaSDavid Wei // SPDX-License-Identifier: GPL-2.0 271082faaSDavid Wei #include <assert.h> 371082faaSDavid Wei #include <errno.h> 471082faaSDavid Wei #include <error.h> 571082faaSDavid Wei #include <fcntl.h> 671082faaSDavid Wei #include <limits.h> 771082faaSDavid Wei #include <stdbool.h> 871082faaSDavid Wei #include <stdint.h> 971082faaSDavid Wei #include <stdio.h> 1071082faaSDavid Wei #include <stdlib.h> 1171082faaSDavid Wei #include <string.h> 1271082faaSDavid Wei #include <unistd.h> 1371082faaSDavid Wei 1471082faaSDavid Wei #include <arpa/inet.h> 1571082faaSDavid Wei #include <linux/errqueue.h> 1671082faaSDavid Wei #include <linux/if_packet.h> 1771082faaSDavid Wei #include <linux/ipv6.h> 1871082faaSDavid Wei #include <linux/socket.h> 1971082faaSDavid Wei #include <linux/sockios.h> 2071082faaSDavid Wei #include <net/ethernet.h> 2171082faaSDavid Wei #include <net/if.h> 2271082faaSDavid Wei #include <netinet/in.h> 2371082faaSDavid Wei #include <netinet/ip.h> 2471082faaSDavid Wei #include <netinet/ip6.h> 2571082faaSDavid Wei #include <netinet/tcp.h> 2671082faaSDavid Wei #include <netinet/udp.h> 2771082faaSDavid Wei #include <sys/epoll.h> 2871082faaSDavid Wei #include <sys/ioctl.h> 2971082faaSDavid Wei #include <sys/mman.h> 3071082faaSDavid Wei #include <sys/resource.h> 3171082faaSDavid Wei #include <sys/socket.h> 3271082faaSDavid Wei #include <sys/stat.h> 3371082faaSDavid Wei #include <sys/time.h> 3471082faaSDavid Wei #include <sys/types.h> 3571082faaSDavid Wei #include <sys/un.h> 3671082faaSDavid Wei #include <sys/wait.h> 3771082faaSDavid Wei 3871082faaSDavid Wei #include <liburing.h> 3971082faaSDavid Wei 4071082faaSDavid Wei #define PAGE_SIZE (4096) 4171082faaSDavid Wei #define AREA_SIZE (8192 * PAGE_SIZE) 4271082faaSDavid Wei #define SEND_SIZE (512 * 4096) 4371082faaSDavid Wei #define min(a, b) \ 4471082faaSDavid Wei ({ \ 4571082faaSDavid Wei typeof(a) _a = (a); \ 4671082faaSDavid Wei typeof(b) _b = (b); \ 4771082faaSDavid Wei _a < _b ? _a : _b; \ 4871082faaSDavid Wei }) 4971082faaSDavid Wei #define min_t(t, a, b) \ 5071082faaSDavid Wei ({ \ 5171082faaSDavid Wei t _ta = (a); \ 5271082faaSDavid Wei t _tb = (b); \ 5371082faaSDavid Wei min(_ta, _tb); \ 5471082faaSDavid Wei }) 5571082faaSDavid Wei 5671082faaSDavid Wei #define ALIGN_UP(v, align) (((v) + (align) - 1) & ~((align) - 1)) 5771082faaSDavid Wei 5871082faaSDavid Wei static int cfg_server; 5971082faaSDavid Wei static int cfg_client; 6071082faaSDavid Wei static int cfg_port = 8000; 6171082faaSDavid Wei static int cfg_payload_len; 6271082faaSDavid Wei static const char *cfg_ifname; 6371082faaSDavid Wei static int cfg_queue_id = -1; 64*89baa22dSDavid Wei static bool cfg_oneshot; 65*89baa22dSDavid Wei static int cfg_oneshot_recvs; 66*89baa22dSDavid Wei static int cfg_send_size = SEND_SIZE; 6771082faaSDavid Wei static struct sockaddr_in6 cfg_addr; 6871082faaSDavid Wei 6971082faaSDavid Wei static char payload[SEND_SIZE] __attribute__((aligned(PAGE_SIZE))); 7071082faaSDavid Wei static void *area_ptr; 7171082faaSDavid Wei static void *ring_ptr; 7271082faaSDavid Wei static size_t ring_size; 7371082faaSDavid Wei static struct io_uring_zcrx_rq rq_ring; 7471082faaSDavid Wei static unsigned long area_token; 7571082faaSDavid Wei static int connfd; 7671082faaSDavid Wei static bool stop; 7771082faaSDavid Wei static size_t received; 7871082faaSDavid Wei 7971082faaSDavid Wei static unsigned long gettimeofday_ms(void) 8071082faaSDavid Wei { 8171082faaSDavid Wei struct timeval tv; 8271082faaSDavid Wei 8371082faaSDavid Wei gettimeofday(&tv, NULL); 8471082faaSDavid Wei return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 8571082faaSDavid Wei } 8671082faaSDavid Wei 8771082faaSDavid Wei static int parse_address(const char *str, int port, struct sockaddr_in6 *sin6) 8871082faaSDavid Wei { 8971082faaSDavid Wei int ret; 9071082faaSDavid Wei 9171082faaSDavid Wei sin6->sin6_family = AF_INET6; 9271082faaSDavid Wei sin6->sin6_port = htons(port); 9371082faaSDavid Wei 9471082faaSDavid Wei ret = inet_pton(sin6->sin6_family, str, &sin6->sin6_addr); 9571082faaSDavid Wei if (ret != 1) { 9671082faaSDavid Wei /* fallback to plain IPv4 */ 9771082faaSDavid Wei ret = inet_pton(AF_INET, str, &sin6->sin6_addr.s6_addr32[3]); 9871082faaSDavid Wei if (ret != 1) 9971082faaSDavid Wei return -1; 10071082faaSDavid Wei 10171082faaSDavid Wei /* add ::ffff prefix */ 10271082faaSDavid Wei sin6->sin6_addr.s6_addr32[0] = 0; 10371082faaSDavid Wei sin6->sin6_addr.s6_addr32[1] = 0; 10471082faaSDavid Wei sin6->sin6_addr.s6_addr16[4] = 0; 10571082faaSDavid Wei sin6->sin6_addr.s6_addr16[5] = 0xffff; 10671082faaSDavid Wei } 10771082faaSDavid Wei 10871082faaSDavid Wei return 0; 10971082faaSDavid Wei } 11071082faaSDavid Wei 11171082faaSDavid Wei static inline size_t get_refill_ring_size(unsigned int rq_entries) 11271082faaSDavid Wei { 11371082faaSDavid Wei size_t size; 11471082faaSDavid Wei 11571082faaSDavid Wei ring_size = rq_entries * sizeof(struct io_uring_zcrx_rqe); 11671082faaSDavid Wei /* add space for the header (head/tail/etc.) */ 11771082faaSDavid Wei ring_size += PAGE_SIZE; 11871082faaSDavid Wei return ALIGN_UP(ring_size, 4096); 11971082faaSDavid Wei } 12071082faaSDavid Wei 12171082faaSDavid Wei static void setup_zcrx(struct io_uring *ring) 12271082faaSDavid Wei { 12371082faaSDavid Wei unsigned int ifindex; 12471082faaSDavid Wei unsigned int rq_entries = 4096; 12571082faaSDavid Wei int ret; 12671082faaSDavid Wei 12771082faaSDavid Wei ifindex = if_nametoindex(cfg_ifname); 12871082faaSDavid Wei if (!ifindex) 12971082faaSDavid Wei error(1, 0, "bad interface name: %s", cfg_ifname); 13071082faaSDavid Wei 13171082faaSDavid Wei area_ptr = mmap(NULL, 13271082faaSDavid Wei AREA_SIZE, 13371082faaSDavid Wei PROT_READ | PROT_WRITE, 13471082faaSDavid Wei MAP_ANONYMOUS | MAP_PRIVATE, 13571082faaSDavid Wei 0, 13671082faaSDavid Wei 0); 13771082faaSDavid Wei if (area_ptr == MAP_FAILED) 13871082faaSDavid Wei error(1, 0, "mmap(): zero copy area"); 13971082faaSDavid Wei 14071082faaSDavid Wei ring_size = get_refill_ring_size(rq_entries); 14171082faaSDavid Wei ring_ptr = mmap(NULL, 14271082faaSDavid Wei ring_size, 14371082faaSDavid Wei PROT_READ | PROT_WRITE, 14471082faaSDavid Wei MAP_ANONYMOUS | MAP_PRIVATE, 14571082faaSDavid Wei 0, 14671082faaSDavid Wei 0); 14771082faaSDavid Wei 14871082faaSDavid Wei struct io_uring_region_desc region_reg = { 14971082faaSDavid Wei .size = ring_size, 15071082faaSDavid Wei .user_addr = (__u64)(unsigned long)ring_ptr, 15171082faaSDavid Wei .flags = IORING_MEM_REGION_TYPE_USER, 15271082faaSDavid Wei }; 15371082faaSDavid Wei 15471082faaSDavid Wei struct io_uring_zcrx_area_reg area_reg = { 15571082faaSDavid Wei .addr = (__u64)(unsigned long)area_ptr, 15671082faaSDavid Wei .len = AREA_SIZE, 15771082faaSDavid Wei .flags = 0, 15871082faaSDavid Wei }; 15971082faaSDavid Wei 16071082faaSDavid Wei struct io_uring_zcrx_ifq_reg reg = { 16171082faaSDavid Wei .if_idx = ifindex, 16271082faaSDavid Wei .if_rxq = cfg_queue_id, 16371082faaSDavid Wei .rq_entries = rq_entries, 16471082faaSDavid Wei .area_ptr = (__u64)(unsigned long)&area_reg, 16571082faaSDavid Wei .region_ptr = (__u64)(unsigned long)®ion_reg, 16671082faaSDavid Wei }; 16771082faaSDavid Wei 16871082faaSDavid Wei ret = io_uring_register_ifq(ring, ®); 16971082faaSDavid Wei if (ret) 17071082faaSDavid Wei error(1, 0, "io_uring_register_ifq(): %d", ret); 17171082faaSDavid Wei 17271082faaSDavid Wei rq_ring.khead = (unsigned int *)((char *)ring_ptr + reg.offsets.head); 17371082faaSDavid Wei rq_ring.ktail = (unsigned int *)((char *)ring_ptr + reg.offsets.tail); 17471082faaSDavid Wei rq_ring.rqes = (struct io_uring_zcrx_rqe *)((char *)ring_ptr + reg.offsets.rqes); 17571082faaSDavid Wei rq_ring.rq_tail = 0; 17671082faaSDavid Wei rq_ring.ring_entries = reg.rq_entries; 17771082faaSDavid Wei 17871082faaSDavid Wei area_token = area_reg.rq_area_token; 17971082faaSDavid Wei } 18071082faaSDavid Wei 18171082faaSDavid Wei static void add_accept(struct io_uring *ring, int sockfd) 18271082faaSDavid Wei { 18371082faaSDavid Wei struct io_uring_sqe *sqe; 18471082faaSDavid Wei 18571082faaSDavid Wei sqe = io_uring_get_sqe(ring); 18671082faaSDavid Wei 18771082faaSDavid Wei io_uring_prep_accept(sqe, sockfd, NULL, NULL, 0); 18871082faaSDavid Wei sqe->user_data = 1; 18971082faaSDavid Wei } 19071082faaSDavid Wei 19171082faaSDavid Wei static void add_recvzc(struct io_uring *ring, int sockfd) 19271082faaSDavid Wei { 19371082faaSDavid Wei struct io_uring_sqe *sqe; 19471082faaSDavid Wei 19571082faaSDavid Wei sqe = io_uring_get_sqe(ring); 19671082faaSDavid Wei 19771082faaSDavid Wei io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, sockfd, NULL, 0, 0); 19871082faaSDavid Wei sqe->ioprio |= IORING_RECV_MULTISHOT; 19971082faaSDavid Wei sqe->user_data = 2; 20071082faaSDavid Wei } 20171082faaSDavid Wei 202*89baa22dSDavid Wei static void add_recvzc_oneshot(struct io_uring *ring, int sockfd, size_t len) 203*89baa22dSDavid Wei { 204*89baa22dSDavid Wei struct io_uring_sqe *sqe; 205*89baa22dSDavid Wei 206*89baa22dSDavid Wei sqe = io_uring_get_sqe(ring); 207*89baa22dSDavid Wei 208*89baa22dSDavid Wei io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, sockfd, NULL, len, 0); 209*89baa22dSDavid Wei sqe->ioprio |= IORING_RECV_MULTISHOT; 210*89baa22dSDavid Wei sqe->user_data = 2; 211*89baa22dSDavid Wei } 212*89baa22dSDavid Wei 21371082faaSDavid Wei static void process_accept(struct io_uring *ring, struct io_uring_cqe *cqe) 21471082faaSDavid Wei { 21571082faaSDavid Wei if (cqe->res < 0) 21671082faaSDavid Wei error(1, 0, "accept()"); 21771082faaSDavid Wei if (connfd) 21871082faaSDavid Wei error(1, 0, "Unexpected second connection"); 21971082faaSDavid Wei 22071082faaSDavid Wei connfd = cqe->res; 221*89baa22dSDavid Wei if (cfg_oneshot) 222*89baa22dSDavid Wei add_recvzc_oneshot(ring, connfd, PAGE_SIZE); 223*89baa22dSDavid Wei else 22471082faaSDavid Wei add_recvzc(ring, connfd); 22571082faaSDavid Wei } 22671082faaSDavid Wei 22771082faaSDavid Wei static void process_recvzc(struct io_uring *ring, struct io_uring_cqe *cqe) 22871082faaSDavid Wei { 22971082faaSDavid Wei unsigned rq_mask = rq_ring.ring_entries - 1; 23071082faaSDavid Wei struct io_uring_zcrx_cqe *rcqe; 23171082faaSDavid Wei struct io_uring_zcrx_rqe *rqe; 23271082faaSDavid Wei struct io_uring_sqe *sqe; 23371082faaSDavid Wei uint64_t mask; 23471082faaSDavid Wei char *data; 23571082faaSDavid Wei ssize_t n; 23671082faaSDavid Wei int i; 23771082faaSDavid Wei 238*89baa22dSDavid Wei if (cqe->res == 0 && cqe->flags == 0 && cfg_oneshot_recvs == 0) { 23971082faaSDavid Wei stop = true; 24071082faaSDavid Wei return; 24171082faaSDavid Wei } 24271082faaSDavid Wei 24371082faaSDavid Wei if (cqe->res < 0) 24471082faaSDavid Wei error(1, 0, "recvzc(): %d", cqe->res); 24571082faaSDavid Wei 246*89baa22dSDavid Wei if (cfg_oneshot) { 247*89baa22dSDavid Wei if (cqe->res == 0 && cqe->flags == 0 && cfg_oneshot_recvs) { 248*89baa22dSDavid Wei add_recvzc_oneshot(ring, connfd, PAGE_SIZE); 249*89baa22dSDavid Wei cfg_oneshot_recvs--; 250*89baa22dSDavid Wei } 251*89baa22dSDavid Wei } else if (!(cqe->flags & IORING_CQE_F_MORE)) { 25271082faaSDavid Wei add_recvzc(ring, connfd); 253*89baa22dSDavid Wei } 25471082faaSDavid Wei 25571082faaSDavid Wei rcqe = (struct io_uring_zcrx_cqe *)(cqe + 1); 25671082faaSDavid Wei 25771082faaSDavid Wei n = cqe->res; 25871082faaSDavid Wei mask = (1ULL << IORING_ZCRX_AREA_SHIFT) - 1; 25971082faaSDavid Wei data = (char *)area_ptr + (rcqe->off & mask); 26071082faaSDavid Wei 26171082faaSDavid Wei for (i = 0; i < n; i++) { 26271082faaSDavid Wei if (*(data + i) != payload[(received + i)]) 263*89baa22dSDavid Wei error(1, 0, "payload mismatch at ", i); 26471082faaSDavid Wei } 26571082faaSDavid Wei received += n; 26671082faaSDavid Wei 26771082faaSDavid Wei rqe = &rq_ring.rqes[(rq_ring.rq_tail & rq_mask)]; 26871082faaSDavid Wei rqe->off = (rcqe->off & ~IORING_ZCRX_AREA_MASK) | area_token; 26971082faaSDavid Wei rqe->len = cqe->res; 27071082faaSDavid Wei io_uring_smp_store_release(rq_ring.ktail, ++rq_ring.rq_tail); 27171082faaSDavid Wei } 27271082faaSDavid Wei 27371082faaSDavid Wei static void server_loop(struct io_uring *ring) 27471082faaSDavid Wei { 27571082faaSDavid Wei struct io_uring_cqe *cqe; 27671082faaSDavid Wei unsigned int count = 0; 27771082faaSDavid Wei unsigned int head; 27871082faaSDavid Wei int i, ret; 27971082faaSDavid Wei 28071082faaSDavid Wei io_uring_submit_and_wait(ring, 1); 28171082faaSDavid Wei 28271082faaSDavid Wei io_uring_for_each_cqe(ring, head, cqe) { 28371082faaSDavid Wei if (cqe->user_data == 1) 28471082faaSDavid Wei process_accept(ring, cqe); 28571082faaSDavid Wei else if (cqe->user_data == 2) 28671082faaSDavid Wei process_recvzc(ring, cqe); 28771082faaSDavid Wei else 28871082faaSDavid Wei error(1, 0, "unknown cqe"); 28971082faaSDavid Wei count++; 29071082faaSDavid Wei } 29171082faaSDavid Wei io_uring_cq_advance(ring, count); 29271082faaSDavid Wei } 29371082faaSDavid Wei 29471082faaSDavid Wei static void run_server(void) 29571082faaSDavid Wei { 29671082faaSDavid Wei unsigned int flags = 0; 29771082faaSDavid Wei struct io_uring ring; 29871082faaSDavid Wei int fd, enable, ret; 29971082faaSDavid Wei uint64_t tstop; 30071082faaSDavid Wei 30171082faaSDavid Wei fd = socket(AF_INET6, SOCK_STREAM, 0); 30271082faaSDavid Wei if (fd == -1) 30371082faaSDavid Wei error(1, 0, "socket()"); 30471082faaSDavid Wei 30571082faaSDavid Wei enable = 1; 30671082faaSDavid Wei ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); 30771082faaSDavid Wei if (ret < 0) 30871082faaSDavid Wei error(1, 0, "setsockopt(SO_REUSEADDR)"); 30971082faaSDavid Wei 31071082faaSDavid Wei ret = bind(fd, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr)); 31171082faaSDavid Wei if (ret < 0) 31271082faaSDavid Wei error(1, 0, "bind()"); 31371082faaSDavid Wei 31471082faaSDavid Wei if (listen(fd, 1024) < 0) 31571082faaSDavid Wei error(1, 0, "listen()"); 31671082faaSDavid Wei 31771082faaSDavid Wei flags |= IORING_SETUP_COOP_TASKRUN; 31871082faaSDavid Wei flags |= IORING_SETUP_SINGLE_ISSUER; 31971082faaSDavid Wei flags |= IORING_SETUP_DEFER_TASKRUN; 32071082faaSDavid Wei flags |= IORING_SETUP_SUBMIT_ALL; 32171082faaSDavid Wei flags |= IORING_SETUP_CQE32; 32271082faaSDavid Wei 32371082faaSDavid Wei io_uring_queue_init(512, &ring, flags); 32471082faaSDavid Wei 32571082faaSDavid Wei setup_zcrx(&ring); 32671082faaSDavid Wei 32771082faaSDavid Wei add_accept(&ring, fd); 32871082faaSDavid Wei 32971082faaSDavid Wei tstop = gettimeofday_ms() + 5000; 33071082faaSDavid Wei while (!stop && gettimeofday_ms() < tstop) 33171082faaSDavid Wei server_loop(&ring); 33271082faaSDavid Wei 33371082faaSDavid Wei if (!stop) 33471082faaSDavid Wei error(1, 0, "test failed\n"); 33571082faaSDavid Wei } 33671082faaSDavid Wei 33771082faaSDavid Wei static void run_client(void) 33871082faaSDavid Wei { 339*89baa22dSDavid Wei ssize_t to_send = cfg_send_size; 34071082faaSDavid Wei ssize_t sent = 0; 34171082faaSDavid Wei ssize_t chunk, res; 34271082faaSDavid Wei int fd; 34371082faaSDavid Wei 34471082faaSDavid Wei fd = socket(AF_INET6, SOCK_STREAM, 0); 34571082faaSDavid Wei if (fd == -1) 34671082faaSDavid Wei error(1, 0, "socket()"); 34771082faaSDavid Wei 34871082faaSDavid Wei if (connect(fd, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr))) 34971082faaSDavid Wei error(1, 0, "connect()"); 35071082faaSDavid Wei 35171082faaSDavid Wei while (to_send) { 35271082faaSDavid Wei void *src = &payload[sent]; 35371082faaSDavid Wei 35471082faaSDavid Wei chunk = min_t(ssize_t, cfg_payload_len, to_send); 35571082faaSDavid Wei res = send(fd, src, chunk, 0); 35671082faaSDavid Wei if (res < 0) 35771082faaSDavid Wei error(1, 0, "send(): %d", sent); 35871082faaSDavid Wei sent += res; 35971082faaSDavid Wei to_send -= res; 36071082faaSDavid Wei } 36171082faaSDavid Wei 36271082faaSDavid Wei close(fd); 36371082faaSDavid Wei } 36471082faaSDavid Wei 36571082faaSDavid Wei static void usage(const char *filepath) 36671082faaSDavid Wei { 36771082faaSDavid Wei error(1, 0, "Usage: %s (-4|-6) (-s|-c) -h<server_ip> -p<port> " 36871082faaSDavid Wei "-l<payload_size> -i<ifname> -q<rxq_id>", filepath); 36971082faaSDavid Wei } 37071082faaSDavid Wei 37171082faaSDavid Wei static void parse_opts(int argc, char **argv) 37271082faaSDavid Wei { 37371082faaSDavid Wei const int max_payload_len = sizeof(payload) - 37471082faaSDavid Wei sizeof(struct ipv6hdr) - 37571082faaSDavid Wei sizeof(struct tcphdr) - 37671082faaSDavid Wei 40 /* max tcp options */; 37771082faaSDavid Wei struct sockaddr_in6 *addr6 = (void *) &cfg_addr; 37871082faaSDavid Wei char *addr = NULL; 37971082faaSDavid Wei int ret; 38071082faaSDavid Wei int c; 38171082faaSDavid Wei 38271082faaSDavid Wei if (argc <= 1) 38371082faaSDavid Wei usage(argv[0]); 38471082faaSDavid Wei cfg_payload_len = max_payload_len; 38571082faaSDavid Wei 386*89baa22dSDavid Wei while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:")) != -1) { 38771082faaSDavid Wei switch (c) { 38871082faaSDavid Wei case 's': 38971082faaSDavid Wei if (cfg_client) 39071082faaSDavid Wei error(1, 0, "Pass one of -s or -c"); 39171082faaSDavid Wei cfg_server = 1; 39271082faaSDavid Wei break; 39371082faaSDavid Wei case 'c': 39471082faaSDavid Wei if (cfg_server) 39571082faaSDavid Wei error(1, 0, "Pass one of -s or -c"); 39671082faaSDavid Wei cfg_client = 1; 39771082faaSDavid Wei break; 39871082faaSDavid Wei case 'h': 39971082faaSDavid Wei addr = optarg; 40071082faaSDavid Wei break; 40171082faaSDavid Wei case 'p': 40271082faaSDavid Wei cfg_port = strtoul(optarg, NULL, 0); 40371082faaSDavid Wei break; 40471082faaSDavid Wei case 'l': 40571082faaSDavid Wei cfg_payload_len = strtoul(optarg, NULL, 0); 40671082faaSDavid Wei break; 40771082faaSDavid Wei case 'i': 40871082faaSDavid Wei cfg_ifname = optarg; 40971082faaSDavid Wei break; 41071082faaSDavid Wei case 'q': 41171082faaSDavid Wei cfg_queue_id = strtoul(optarg, NULL, 0); 41271082faaSDavid Wei break; 413*89baa22dSDavid Wei case 'o': { 414*89baa22dSDavid Wei cfg_oneshot = true; 415*89baa22dSDavid Wei cfg_oneshot_recvs = strtoul(optarg, NULL, 0); 416*89baa22dSDavid Wei break; 417*89baa22dSDavid Wei } 418*89baa22dSDavid Wei case 'z': 419*89baa22dSDavid Wei cfg_send_size = strtoul(optarg, NULL, 0); 420*89baa22dSDavid Wei break; 42171082faaSDavid Wei } 42271082faaSDavid Wei } 42371082faaSDavid Wei 42471082faaSDavid Wei if (cfg_server && addr) 42571082faaSDavid Wei error(1, 0, "Receiver cannot have -h specified"); 42671082faaSDavid Wei 42771082faaSDavid Wei memset(addr6, 0, sizeof(*addr6)); 42871082faaSDavid Wei addr6->sin6_family = AF_INET6; 42971082faaSDavid Wei addr6->sin6_port = htons(cfg_port); 43071082faaSDavid Wei addr6->sin6_addr = in6addr_any; 43171082faaSDavid Wei if (addr) { 43271082faaSDavid Wei ret = parse_address(addr, cfg_port, addr6); 43371082faaSDavid Wei if (ret) 43471082faaSDavid Wei error(1, 0, "receiver address parse error: %s", addr); 43571082faaSDavid Wei } 43671082faaSDavid Wei 43771082faaSDavid Wei if (cfg_payload_len > max_payload_len) 43871082faaSDavid Wei error(1, 0, "-l: payload exceeds max (%d)", max_payload_len); 43971082faaSDavid Wei } 44071082faaSDavid Wei 44171082faaSDavid Wei int main(int argc, char **argv) 44271082faaSDavid Wei { 44371082faaSDavid Wei const char *cfg_test = argv[argc - 1]; 44471082faaSDavid Wei int i; 44571082faaSDavid Wei 44671082faaSDavid Wei parse_opts(argc, argv); 44771082faaSDavid Wei 44871082faaSDavid Wei for (i = 0; i < SEND_SIZE; i++) 44971082faaSDavid Wei payload[i] = 'a' + (i % 26); 45071082faaSDavid Wei 45171082faaSDavid Wei if (cfg_server) 45271082faaSDavid Wei run_server(); 45371082faaSDavid Wei else if (cfg_client) 45471082faaSDavid Wei run_client(); 45571082faaSDavid Wei 45671082faaSDavid Wei return 0; 45771082faaSDavid Wei } 458