1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 5 #include <stddef.h> 6 #include <arpa/inet.h> 7 #include <error.h> 8 #include <errno.h> 9 #include <net/if.h> 10 #include <linux/in.h> 11 #include <linux/netlink.h> 12 #include <linux/rtnetlink.h> 13 #include <netinet/if_ether.h> 14 #include <netinet/ip.h> 15 #include <netinet/ip6.h> 16 #include <netinet/udp.h> 17 #include <stdbool.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <sys/ioctl.h> 22 #include <sys/socket.h> 23 #include <sys/stat.h> 24 #include <sys/time.h> 25 #include <sys/types.h> 26 #include <unistd.h> 27 28 #ifndef ETH_MAX_MTU 29 #define ETH_MAX_MTU 0xFFFFU 30 #endif 31 32 #ifndef UDP_SEGMENT 33 #define UDP_SEGMENT 103 34 #endif 35 36 #ifndef UDP_MAX_SEGMENTS 37 #define UDP_MAX_SEGMENTS (1 << 7UL) 38 #endif 39 40 #define CONST_MTU_TEST 1500 41 42 #define CONST_HDRLEN_V4 (sizeof(struct iphdr) + sizeof(struct udphdr)) 43 #define CONST_HDRLEN_V6 (sizeof(struct ip6_hdr) + sizeof(struct udphdr)) 44 45 #define CONST_MSS_V4 (CONST_MTU_TEST - CONST_HDRLEN_V4) 46 #define CONST_MSS_V6 (CONST_MTU_TEST - CONST_HDRLEN_V6) 47 48 #define CONST_MAX_SEGS_V4 (ETH_MAX_MTU / CONST_MSS_V4) 49 #define CONST_MAX_SEGS_V6 (ETH_MAX_MTU / CONST_MSS_V6) 50 51 static bool cfg_do_ipv4; 52 static bool cfg_do_ipv6; 53 static bool cfg_do_connected; 54 static bool cfg_do_connectionless; 55 static bool cfg_do_msgmore; 56 static bool cfg_do_recv = true; 57 static bool cfg_do_setsockopt; 58 static int cfg_specific_test_id = -1; 59 60 static unsigned short cfg_port = 9000; 61 62 static char buf[ETH_MAX_MTU]; 63 64 struct testcase { 65 int tlen; /* send() buffer size, may exceed mss */ 66 bool tfail; /* send() call is expected to fail */ 67 int gso_len; /* mss after applying gso */ 68 int r_num_mss; /* recv(): number of calls of full mss */ 69 int r_len_last; /* recv(): size of last non-mss dgram, if any */ 70 }; 71 72 const struct in6_addr addr6 = { 73 { { 0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } }, /* fd00::1 */ 74 }; 75 76 const struct in_addr addr4 = { 77 __constant_htonl(0x0a000001), /* 10.0.0.1 */ 78 }; 79 80 struct testcase testcases_v4[] = { 81 { 82 /* no GSO: send a single byte */ 83 .tlen = 1, 84 .r_len_last = 1, 85 }, 86 { 87 /* no GSO: send a single MSS */ 88 .tlen = CONST_MSS_V4, 89 .r_num_mss = 1, 90 }, 91 { 92 /* no GSO: send a single MSS + 1B: fail */ 93 .tlen = CONST_MSS_V4 + 1, 94 .tfail = true, 95 }, 96 { 97 /* send a single MSS: will fall back to no GSO */ 98 .tlen = CONST_MSS_V4, 99 .gso_len = CONST_MSS_V4, 100 .r_num_mss = 1, 101 }, 102 { 103 /* send a single MSS + 1B */ 104 .tlen = CONST_MSS_V4 + 1, 105 .gso_len = CONST_MSS_V4, 106 .r_num_mss = 1, 107 .r_len_last = 1, 108 }, 109 { 110 /* send exactly 2 MSS */ 111 .tlen = CONST_MSS_V4 * 2, 112 .gso_len = CONST_MSS_V4, 113 .r_num_mss = 2, 114 }, 115 { 116 /* send 2 MSS + 1B */ 117 .tlen = (CONST_MSS_V4 * 2) + 1, 118 .gso_len = CONST_MSS_V4, 119 .r_num_mss = 2, 120 .r_len_last = 1, 121 }, 122 { 123 /* send MAX segs */ 124 .tlen = (ETH_MAX_MTU / CONST_MSS_V4) * CONST_MSS_V4, 125 .gso_len = CONST_MSS_V4, 126 .r_num_mss = (ETH_MAX_MTU / CONST_MSS_V4), 127 }, 128 129 { 130 /* send MAX bytes */ 131 .tlen = ETH_MAX_MTU - CONST_HDRLEN_V4, 132 .gso_len = CONST_MSS_V4, 133 .r_num_mss = CONST_MAX_SEGS_V4, 134 .r_len_last = ETH_MAX_MTU - CONST_HDRLEN_V4 - 135 (CONST_MAX_SEGS_V4 * CONST_MSS_V4), 136 }, 137 { 138 /* send MAX + 1: fail */ 139 .tlen = ETH_MAX_MTU - CONST_HDRLEN_V4 + 1, 140 .gso_len = CONST_MSS_V4, 141 .tfail = true, 142 }, 143 { 144 /* send a single 1B MSS: will fall back to no GSO */ 145 .tlen = 1, 146 .gso_len = 1, 147 .r_num_mss = 1, 148 }, 149 { 150 /* send 2 1B segments */ 151 .tlen = 2, 152 .gso_len = 1, 153 .r_num_mss = 2, 154 }, 155 { 156 /* send 2B + 2B + 1B segments */ 157 .tlen = 5, 158 .gso_len = 2, 159 .r_num_mss = 2, 160 .r_len_last = 1, 161 }, 162 { 163 /* send max number of min sized segments */ 164 .tlen = UDP_MAX_SEGMENTS, 165 .gso_len = 1, 166 .r_num_mss = UDP_MAX_SEGMENTS, 167 }, 168 { 169 /* send max number + 1 of min sized segments: fail */ 170 .tlen = UDP_MAX_SEGMENTS + 1, 171 .gso_len = 1, 172 .tfail = true, 173 }, 174 { 175 /* EOL */ 176 } 177 }; 178 179 #ifndef IP6_MAX_MTU 180 #define IP6_MAX_MTU (ETH_MAX_MTU + sizeof(struct ip6_hdr)) 181 #endif 182 183 struct testcase testcases_v6[] = { 184 { 185 /* no GSO: send a single byte */ 186 .tlen = 1, 187 .r_len_last = 1, 188 }, 189 { 190 /* no GSO: send a single MSS */ 191 .tlen = CONST_MSS_V6, 192 .r_num_mss = 1, 193 }, 194 { 195 /* no GSO: send a single MSS + 1B: fail */ 196 .tlen = CONST_MSS_V6 + 1, 197 .tfail = true, 198 }, 199 { 200 /* send a single MSS: will fall back to no GSO */ 201 .tlen = CONST_MSS_V6, 202 .gso_len = CONST_MSS_V6, 203 .r_num_mss = 1, 204 }, 205 { 206 /* send a single MSS + 1B */ 207 .tlen = CONST_MSS_V6 + 1, 208 .gso_len = CONST_MSS_V6, 209 .r_num_mss = 1, 210 .r_len_last = 1, 211 }, 212 { 213 /* send exactly 2 MSS */ 214 .tlen = CONST_MSS_V6 * 2, 215 .gso_len = CONST_MSS_V6, 216 .r_num_mss = 2, 217 }, 218 { 219 /* send 2 MSS + 1B */ 220 .tlen = (CONST_MSS_V6 * 2) + 1, 221 .gso_len = CONST_MSS_V6, 222 .r_num_mss = 2, 223 .r_len_last = 1, 224 }, 225 { 226 /* send MAX segs */ 227 .tlen = (IP6_MAX_MTU / CONST_MSS_V6) * CONST_MSS_V6, 228 .gso_len = CONST_MSS_V6, 229 .r_num_mss = (IP6_MAX_MTU / CONST_MSS_V6), 230 }, 231 232 { 233 /* send MAX bytes */ 234 .tlen = IP6_MAX_MTU - CONST_HDRLEN_V6, 235 .gso_len = CONST_MSS_V6, 236 .r_num_mss = CONST_MAX_SEGS_V6, 237 .r_len_last = IP6_MAX_MTU - CONST_HDRLEN_V6 - 238 (CONST_MAX_SEGS_V6 * CONST_MSS_V6), 239 }, 240 { 241 /* send MAX + 1: fail */ 242 .tlen = IP6_MAX_MTU - CONST_HDRLEN_V6 + 1, 243 .gso_len = CONST_MSS_V6, 244 .tfail = true, 245 }, 246 { 247 /* send a single 1B MSS: will fall back to no GSO */ 248 .tlen = 1, 249 .gso_len = 1, 250 .r_num_mss = 1, 251 }, 252 { 253 /* send 2 1B segments */ 254 .tlen = 2, 255 .gso_len = 1, 256 .r_num_mss = 2, 257 }, 258 { 259 /* send 2B + 2B + 1B segments */ 260 .tlen = 5, 261 .gso_len = 2, 262 .r_num_mss = 2, 263 .r_len_last = 1, 264 }, 265 { 266 /* send max number of min sized segments */ 267 .tlen = UDP_MAX_SEGMENTS, 268 .gso_len = 1, 269 .r_num_mss = UDP_MAX_SEGMENTS, 270 }, 271 { 272 /* send max number + 1 of min sized segments: fail */ 273 .tlen = UDP_MAX_SEGMENTS + 1, 274 .gso_len = 1, 275 .tfail = true, 276 }, 277 { 278 /* EOL */ 279 } 280 }; 281 282 static void set_pmtu_discover(int fd, bool is_ipv4) 283 { 284 int level, name, val; 285 286 if (is_ipv4) { 287 level = SOL_IP; 288 name = IP_MTU_DISCOVER; 289 val = IP_PMTUDISC_DO; 290 } else { 291 level = SOL_IPV6; 292 name = IPV6_MTU_DISCOVER; 293 val = IPV6_PMTUDISC_DO; 294 } 295 296 if (setsockopt(fd, level, name, &val, sizeof(val))) 297 error(1, errno, "setsockopt path mtu"); 298 } 299 300 static unsigned int get_path_mtu(int fd, bool is_ipv4) 301 { 302 socklen_t vallen; 303 unsigned int mtu; 304 int ret; 305 306 vallen = sizeof(mtu); 307 if (is_ipv4) 308 ret = getsockopt(fd, SOL_IP, IP_MTU, &mtu, &vallen); 309 else 310 ret = getsockopt(fd, SOL_IPV6, IPV6_MTU, &mtu, &vallen); 311 312 if (ret) 313 error(1, errno, "getsockopt mtu"); 314 315 316 fprintf(stderr, "path mtu (read): %u\n", mtu); 317 return mtu; 318 } 319 320 static bool __send_one(int fd, struct msghdr *msg, int flags) 321 { 322 int ret; 323 324 ret = sendmsg(fd, msg, flags); 325 if (ret == -1 && 326 (errno == EMSGSIZE || errno == ENOMEM || errno == EINVAL)) 327 return false; 328 if (ret == -1) 329 error(1, errno, "sendmsg"); 330 if (ret != msg->msg_iov->iov_len) 331 error(1, 0, "sendto: %d != %llu", ret, 332 (unsigned long long)msg->msg_iov->iov_len); 333 if (msg->msg_flags) 334 error(1, 0, "sendmsg: return flags 0x%x\n", msg->msg_flags); 335 336 return true; 337 } 338 339 static bool send_one(int fd, int len, int gso_len, 340 struct sockaddr *addr, socklen_t alen) 341 { 342 char control[CMSG_SPACE(sizeof(uint16_t))] = {0}; 343 struct msghdr msg = {0}; 344 struct iovec iov = {0}; 345 struct cmsghdr *cm; 346 347 iov.iov_base = buf; 348 iov.iov_len = len; 349 350 msg.msg_iov = &iov; 351 msg.msg_iovlen = 1; 352 353 msg.msg_name = addr; 354 msg.msg_namelen = alen; 355 356 if (gso_len && !cfg_do_setsockopt) { 357 msg.msg_control = control; 358 msg.msg_controllen = sizeof(control); 359 360 cm = CMSG_FIRSTHDR(&msg); 361 cm->cmsg_level = SOL_UDP; 362 cm->cmsg_type = UDP_SEGMENT; 363 cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); 364 *((uint16_t *) CMSG_DATA(cm)) = gso_len; 365 } 366 367 /* If MSG_MORE, send 1 byte followed by remainder */ 368 if (cfg_do_msgmore && len > 1) { 369 iov.iov_len = 1; 370 if (!__send_one(fd, &msg, MSG_MORE)) 371 error(1, 0, "send 1B failed"); 372 373 iov.iov_base++; 374 iov.iov_len = len - 1; 375 } 376 377 return __send_one(fd, &msg, 0); 378 } 379 380 static int recv_one(int fd, int flags) 381 { 382 int ret; 383 384 ret = recv(fd, buf, sizeof(buf), flags); 385 if (ret == -1 && errno == EAGAIN && (flags & MSG_DONTWAIT)) 386 return 0; 387 if (ret == -1) 388 error(1, errno, "recv"); 389 390 return ret; 391 } 392 393 static void run_one(struct testcase *test, int fdt, int fdr, 394 struct sockaddr *addr, socklen_t alen) 395 { 396 int i, ret, val, mss; 397 bool sent; 398 399 fprintf(stderr, "ipv%d tx:%d gso:%d %s\n", 400 addr->sa_family == AF_INET ? 4 : 6, 401 test->tlen, test->gso_len, 402 test->tfail ? "(fail)" : ""); 403 404 val = test->gso_len; 405 if (cfg_do_setsockopt) { 406 if (setsockopt(fdt, SOL_UDP, UDP_SEGMENT, &val, sizeof(val))) 407 error(1, errno, "setsockopt udp segment"); 408 } 409 410 sent = send_one(fdt, test->tlen, test->gso_len, addr, alen); 411 if (sent && test->tfail) 412 error(1, 0, "send succeeded while expecting failure"); 413 if (!sent && !test->tfail) 414 error(1, 0, "send failed while expecting success"); 415 if (!sent) 416 return; 417 418 if (!cfg_do_recv) 419 return; 420 421 if (test->gso_len) 422 mss = test->gso_len; 423 else 424 mss = addr->sa_family == AF_INET ? CONST_MSS_V4 : CONST_MSS_V6; 425 426 427 /* Recv all full MSS datagrams */ 428 for (i = 0; i < test->r_num_mss; i++) { 429 ret = recv_one(fdr, 0); 430 if (ret != mss) 431 error(1, 0, "recv.%d: %d != %d", i, ret, mss); 432 } 433 434 /* Recv the non-full last datagram, if tlen was not a multiple of mss */ 435 if (test->r_len_last) { 436 ret = recv_one(fdr, 0); 437 if (ret != test->r_len_last) 438 error(1, 0, "recv.%d: %d != %d (last)", 439 i, ret, test->r_len_last); 440 } 441 442 /* Verify received all data */ 443 ret = recv_one(fdr, MSG_DONTWAIT); 444 if (ret) 445 error(1, 0, "recv: unexpected datagram"); 446 } 447 448 static void run_all(int fdt, int fdr, struct sockaddr *addr, socklen_t alen) 449 { 450 struct testcase *tests, *test; 451 452 tests = addr->sa_family == AF_INET ? testcases_v4 : testcases_v6; 453 454 for (test = tests; test->tlen; test++) { 455 /* if a specific test is given, then skip all others */ 456 if (cfg_specific_test_id == -1 || 457 cfg_specific_test_id == test - tests) 458 run_one(test, fdt, fdr, addr, alen); 459 } 460 } 461 462 static void run_test(struct sockaddr *addr, socklen_t alen) 463 { 464 struct timeval tv = { .tv_usec = 100 * 1000 }; 465 int fdr, fdt, val; 466 467 fdr = socket(addr->sa_family, SOCK_DGRAM, 0); 468 if (fdr == -1) 469 error(1, errno, "socket r"); 470 471 if (cfg_do_recv) { 472 if (bind(fdr, addr, alen)) 473 error(1, errno, "bind"); 474 } 475 476 /* Have tests fail quickly instead of hang */ 477 if (setsockopt(fdr, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) 478 error(1, errno, "setsockopt rcv timeout"); 479 480 fdt = socket(addr->sa_family, SOCK_DGRAM, 0); 481 if (fdt == -1) 482 error(1, errno, "socket t"); 483 484 /* Do not fragment these datagrams: only succeed if GSO works */ 485 set_pmtu_discover(fdt, addr->sa_family == AF_INET); 486 487 if (cfg_do_connectionless) 488 run_all(fdt, fdr, addr, alen); 489 490 if (cfg_do_connected) { 491 if (connect(fdt, addr, alen)) 492 error(1, errno, "connect"); 493 494 val = get_path_mtu(fdt, addr->sa_family == AF_INET); 495 if (val != CONST_MTU_TEST) 496 error(1, 0, "bad path mtu %u\n", val); 497 498 run_all(fdt, fdr, addr, 0 /* use connected addr */); 499 } 500 501 if (close(fdt)) 502 error(1, errno, "close t"); 503 if (close(fdr)) 504 error(1, errno, "close r"); 505 } 506 507 static void run_test_v4(void) 508 { 509 struct sockaddr_in addr = {0}; 510 511 addr.sin_family = AF_INET; 512 addr.sin_port = htons(cfg_port); 513 addr.sin_addr = addr4; 514 515 run_test((void *)&addr, sizeof(addr)); 516 } 517 518 static void run_test_v6(void) 519 { 520 struct sockaddr_in6 addr = {0}; 521 522 addr.sin6_family = AF_INET6; 523 addr.sin6_port = htons(cfg_port); 524 addr.sin6_addr = addr6; 525 526 run_test((void *)&addr, sizeof(addr)); 527 } 528 529 static void parse_opts(int argc, char **argv) 530 { 531 int c; 532 533 while ((c = getopt(argc, argv, "46cCmRst:")) != -1) { 534 switch (c) { 535 case '4': 536 cfg_do_ipv4 = true; 537 break; 538 case '6': 539 cfg_do_ipv6 = true; 540 break; 541 case 'c': 542 cfg_do_connected = true; 543 break; 544 case 'C': 545 cfg_do_connectionless = true; 546 break; 547 case 'm': 548 cfg_do_msgmore = true; 549 break; 550 case 'R': 551 cfg_do_recv = false; 552 break; 553 case 's': 554 cfg_do_setsockopt = true; 555 break; 556 case 't': 557 cfg_specific_test_id = strtoul(optarg, NULL, 0); 558 break; 559 default: 560 error(1, 0, "%s: parse error", argv[0]); 561 } 562 } 563 } 564 565 int main(int argc, char **argv) 566 { 567 parse_opts(argc, argv); 568 569 if (cfg_do_ipv4) 570 run_test_v4(); 571 if (cfg_do_ipv6) 572 run_test_v6(); 573 574 fprintf(stderr, "OK\n"); 575 return 0; 576 } 577