Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: udp gso with connected sockets

Connected sockets use path mtu instead of device mtu.

Test this path by inserting a route mtu that is lower than the device
mtu. Verify that the path mtu for the connection matches this lower
number, then run the same test as in the connectionless case.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Willem de Bruijn and committed by
David S. Miller
e5b2d91c a1607257

+122 -2
+115 -2
tools/testing/selftests/net/udpgso.c
··· 47 47 48 48 static bool cfg_do_ipv4; 49 49 static bool cfg_do_ipv6; 50 + static bool cfg_do_connected; 50 51 static bool cfg_do_connectionless; 51 52 static bool cfg_do_setsockopt; 52 53 static int cfg_specific_test_id = -1; ··· 274 273 error(1, errno, "setsockopt path mtu"); 275 274 } 276 275 276 + static unsigned int get_path_mtu(int fd, bool is_ipv4) 277 + { 278 + socklen_t vallen; 279 + unsigned int mtu; 280 + int ret; 281 + 282 + vallen = sizeof(mtu); 283 + if (is_ipv4) 284 + ret = getsockopt(fd, SOL_IP, IP_MTU, &mtu, &vallen); 285 + else 286 + ret = getsockopt(fd, SOL_IPV6, IPV6_MTU, &mtu, &vallen); 287 + 288 + if (ret) 289 + error(1, errno, "getsockopt mtu"); 290 + 291 + 292 + fprintf(stderr, "path mtu (read): %u\n", mtu); 293 + return mtu; 294 + } 295 + 296 + /* very wordy version of system("ip route add dev lo mtu 1500 127.0.0.3/32") */ 297 + static void set_route_mtu(int mtu, bool is_ipv4) 298 + { 299 + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 300 + struct nlmsghdr *nh; 301 + struct rtattr *rta; 302 + struct rtmsg *rt; 303 + char data[NLMSG_ALIGN(sizeof(*nh)) + 304 + NLMSG_ALIGN(sizeof(*rt)) + 305 + NLMSG_ALIGN(RTA_LENGTH(sizeof(addr6))) + 306 + NLMSG_ALIGN(RTA_LENGTH(sizeof(int))) + 307 + NLMSG_ALIGN(RTA_LENGTH(0) + RTA_LENGTH(sizeof(int)))]; 308 + int fd, ret, alen, off = 0; 309 + 310 + alen = is_ipv4 ? sizeof(addr4) : sizeof(addr6); 311 + 312 + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 313 + if (fd == -1) 314 + error(1, errno, "socket netlink"); 315 + 316 + memset(data, 0, sizeof(data)); 317 + 318 + nh = (void *)data; 319 + nh->nlmsg_type = RTM_NEWROUTE; 320 + nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; 321 + off += NLMSG_ALIGN(sizeof(*nh)); 322 + 323 + rt = (void *)(data + off); 324 + rt->rtm_family = is_ipv4 ? AF_INET : AF_INET6; 325 + rt->rtm_table = RT_TABLE_MAIN; 326 + rt->rtm_dst_len = alen << 3; 327 + rt->rtm_protocol = RTPROT_BOOT; 328 + rt->rtm_scope = RT_SCOPE_UNIVERSE; 329 + rt->rtm_type = RTN_UNICAST; 330 + off += NLMSG_ALIGN(sizeof(*rt)); 331 + 332 + rta = (void *)(data + off); 333 + rta->rta_type = RTA_DST; 334 + rta->rta_len = RTA_LENGTH(alen); 335 + if (is_ipv4) 336 + memcpy(RTA_DATA(rta), &addr4, alen); 337 + else 338 + memcpy(RTA_DATA(rta), &addr6, alen); 339 + off += NLMSG_ALIGN(rta->rta_len); 340 + 341 + rta = (void *)(data + off); 342 + rta->rta_type = RTA_OIF; 343 + rta->rta_len = RTA_LENGTH(sizeof(int)); 344 + *((int *)(RTA_DATA(rta))) = 1; //if_nametoindex("lo"); 345 + off += NLMSG_ALIGN(rta->rta_len); 346 + 347 + /* MTU is a subtype in a metrics type */ 348 + rta = (void *)(data + off); 349 + rta->rta_type = RTA_METRICS; 350 + rta->rta_len = RTA_LENGTH(0) + RTA_LENGTH(sizeof(int)); 351 + off += NLMSG_ALIGN(rta->rta_len); 352 + 353 + /* now fill MTU subtype. Note that it fits within above rta_len */ 354 + rta = (void *)(((char *) rta) + RTA_LENGTH(0)); 355 + rta->rta_type = RTAX_MTU; 356 + rta->rta_len = RTA_LENGTH(sizeof(int)); 357 + *((int *)(RTA_DATA(rta))) = mtu; 358 + 359 + nh->nlmsg_len = off; 360 + 361 + ret = sendto(fd, data, off, 0, (void *)&nladdr, sizeof(nladdr)); 362 + if (ret != off) 363 + error(1, errno, "send netlink: %uB != %uB\n", ret, off); 364 + 365 + if (close(fd)) 366 + error(1, errno, "close netlink"); 367 + 368 + fprintf(stderr, "route mtu (test): %u\n", mtu); 369 + } 370 + 277 371 static bool send_one(int fd, int len, int gso_len, 278 372 struct sockaddr *addr, socklen_t alen) 279 373 { ··· 487 391 static void run_test(struct sockaddr *addr, socklen_t alen) 488 392 { 489 393 struct timeval tv = { .tv_usec = 100 * 1000 }; 490 - int fdr, fdt; 394 + int fdr, fdt, val; 491 395 492 396 fdr = socket(addr->sa_family, SOCK_DGRAM, 0); 493 397 if (fdr == -1) ··· 510 414 if (cfg_do_connectionless) { 511 415 set_device_mtu(fdt, CONST_MTU_TEST); 512 416 run_all(fdt, fdr, addr, alen); 417 + } 418 + 419 + if (cfg_do_connected) { 420 + set_device_mtu(fdt, CONST_MTU_TEST + 100); 421 + set_route_mtu(CONST_MTU_TEST, addr->sa_family == AF_INET); 422 + 423 + if (connect(fdt, addr, alen)) 424 + error(1, errno, "connect"); 425 + 426 + val = get_path_mtu(fdt, addr->sa_family == AF_INET); 427 + if (val != CONST_MTU_TEST) 428 + error(1, 0, "bad path mtu %u\n", val); 429 + 430 + run_all(fdt, fdr, addr, 0 /* use connected addr */); 513 431 } 514 432 515 433 if (close(fdt)) ··· 558 448 { 559 449 int c; 560 450 561 - while ((c = getopt(argc, argv, "46Cst:")) != -1) { 451 + while ((c = getopt(argc, argv, "46cCst:")) != -1) { 562 452 switch (c) { 563 453 case '4': 564 454 cfg_do_ipv4 = true; 565 455 break; 566 456 case '6': 567 457 cfg_do_ipv6 = true; 458 + break; 459 + case 'c': 460 + cfg_do_connected = true; 568 461 break; 569 462 case 'C': 570 463 cfg_do_connectionless = true;
+7
tools/testing/selftests/net/udpgso.sh
··· 14 14 15 15 echo "ipv6 setsockopt" 16 16 ./in_netns.sh ./udpgso -6 -C -s 17 + 18 + echo "ipv4 connected" 19 + ./in_netns.sh ./udpgso -4 -c 20 + 21 + # blocked on 2nd loopback address 22 + # echo "ipv6 connected" 23 + # ./in_netns.sh ./udpgso -6 -c