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

selftests/net: expand cmsg_ip with MSG_MORE

UDP send with MSG_MORE takes a slightly different path than the
lockless fast path.

For completeness, add coverage to this case too.

Pass MSG_MORE on the initial sendmsg, then follow up with a zero byte
write to unplug the cork.

Unrelated: also add two missing endlines in usage().

Signed-off-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250307033620.411611-4-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Willem de Bruijn and committed by
Jakub Kicinski
0922cb68 a18dfa99

+26 -9
+7 -4
tools/testing/selftests/net/cmsg_ip.sh
··· 50 50 # IPV6_DONTFRAG 51 51 for ovr in setsock cmsg both diff; do 52 52 for df in 0 1; do 53 - for p in u i r; do 53 + for p in u U i r; do 54 54 [ $p == "u" ] && prot=UDP 55 + [ $p == "U" ] && prot=UDP 55 56 [ $p == "i" ] && prot=ICMP 56 57 [ $p == "r" ] && prot=RAW 57 58 ··· 82 81 ip $IPVER -netns $NS route add table 300 prohibit any 83 82 84 83 for ovr in setsock cmsg both diff; do 85 - for p in u i r; do 84 + for p in u U i r; do 86 85 [ $p == "u" ] && prot=UDP 86 + [ $p == "U" ] && prot=UDP 87 87 [ $p == "i" ] && prot=ICMP 88 88 [ $p == "r" ] && prot=RAW 89 89 ··· 136 134 local -r LIM=4 137 135 138 136 for ovr in setsock cmsg both diff; do 139 - for p in u i r; do 137 + for p in u U i r; do 140 138 [ $p == "u" ] && prot=UDP 139 + [ $p == "U" ] && prot=UDP 141 140 [ $p == "i" ] && prot=ICMP 142 141 [ $p == "r" ] && prot=RAW 143 142 ··· 169 166 test_ttl_hoplimit -6 $TGT6 hlim 170 167 171 168 # IPV6 exthdr 172 - for p in u i r; do 169 + for p in u U i r; do 173 170 # Very basic "does it crash" test 174 171 for h in h d r; do 175 172 $NSEXE ./cmsg_sender -p $p -6 -H $h $TGT6 1234
+19 -5
tools/testing/selftests/net/cmsg_sender.c
··· 33 33 ERN_RECVERR, 34 34 ERN_CMSG_RD, 35 35 ERN_CMSG_RCV, 36 + ERN_SEND_MORE, 36 37 }; 37 38 38 39 struct option_cmsg_u32 { ··· 47 46 const char *service; 48 47 unsigned int size; 49 48 unsigned int num_pkt; 49 + bool msg_more; 50 50 struct { 51 51 unsigned int mark; 52 52 unsigned int dontfrag; ··· 96 94 "\t\t-S send() size\n" 97 95 "\t\t-4/-6 Force IPv4 / IPv6 only\n" 98 96 "\t\t-p prot Socket protocol\n" 99 - "\t\t (u = UDP (default); i = ICMP; r = RAW)\n" 97 + "\t\t (u = UDP (default); i = ICMP; r = RAW;\n" 98 + "\t\t U = UDP with MSG_MORE)\n" 100 99 "\n" 101 100 "\t\t-m val Set SO_MARK with given value\n" 102 101 "\t\t-M val Set SO_MARK via setsockopt\n" ··· 112 109 "\t\t-l val Set TTL/HOPLIMIT via cmsg\n" 113 110 "\t\t-L val Set TTL/HOPLIMIT via setsockopt\n" 114 111 "\t\t-H type Add an IPv6 header option\n" 115 - "\t\t (h = HOP; d = DST; r = RTDST)" 116 - ""); 112 + "\t\t (h = HOP; d = DST; r = RTDST)\n" 113 + "\n"); 117 114 exit(ERN_HELP); 118 115 } 119 116 ··· 136 133 opt.sock.family = AF_INET6; 137 134 break; 138 135 case 'p': 139 - if (*optarg == 'u' || *optarg == 'U') { 136 + if (*optarg == 'u') { 140 137 opt.sock.proto = IPPROTO_UDP; 138 + } else if (*optarg == 'U') { 139 + opt.sock.proto = IPPROTO_UDP; 140 + opt.msg_more = true; 141 141 } else if (*optarg == 'i' || *optarg == 'I') { 142 142 opt.sock.proto = IPPROTO_ICMP; 143 143 } else if (*optarg == 'r') { ··· 537 531 cs_write_cmsg(fd, &msg, cbuf, sizeof(cbuf)); 538 532 539 533 for (i = 0; i < opt.num_pkt; i++) { 540 - err = sendmsg(fd, &msg, 0); 534 + err = sendmsg(fd, &msg, opt.msg_more ? MSG_MORE : 0); 541 535 if (err < 0) { 542 536 if (!opt.silent_send) 543 537 fprintf(stderr, "send failed: %s\n", strerror(errno)); ··· 547 541 fprintf(stderr, "short send\n"); 548 542 err = ERN_SEND_SHORT; 549 543 goto err_out; 544 + } 545 + if (opt.msg_more) { 546 + err = write(fd, NULL, 0); 547 + if (err < 0) { 548 + fprintf(stderr, "send more: %s\n", strerror(errno)); 549 + err = ERN_SEND_MORE; 550 + goto err_out; 551 + } 550 552 } 551 553 } 552 554 err = ERN_SUCCESS;