Commit 0922cb68 authored by Willem de Bruijn's avatar Willem de Bruijn Committed by Jakub Kicinski
Browse files

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: default avatarWillem de Bruijn <willemb@google.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250307033620.411611-4-willemdebruijn.kernel@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a18dfa99
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -50,8 +50,9 @@ check_result() {
# IPV6_DONTFRAG
for ovr in setsock cmsg both diff; do
    for df in 0 1; do
	for p in u i r; do
	for p in u U i r; do
	    [ $p == "u" ] && prot=UDP
	    [ $p == "U" ] && prot=UDP
	    [ $p == "i" ] && prot=ICMP
	    [ $p == "r" ] && prot=RAW

@@ -81,8 +82,9 @@ test_dscp() {
    ip $IPVER -netns $NS route add table 300 prohibit any

    for ovr in setsock cmsg both diff; do
	for p in u i r; do
	for p in u U i r; do
	    [ $p == "u" ] && prot=UDP
	    [ $p == "U" ] && prot=UDP
	    [ $p == "i" ] && prot=ICMP
	    [ $p == "r" ] && prot=RAW

@@ -134,8 +136,9 @@ test_ttl_hoplimit() {
    local -r LIM=4

    for ovr in setsock cmsg both diff; do
	for p in u i r; do
	for p in u U i r; do
	    [ $p == "u" ] && prot=UDP
	    [ $p == "U" ] && prot=UDP
	    [ $p == "i" ] && prot=ICMP
	    [ $p == "r" ] && prot=RAW

@@ -166,7 +169,7 @@ test_ttl_hoplimit -4 $TGT4 ttl
test_ttl_hoplimit -6 $TGT6 hlim

# IPV6 exthdr
for p in u i r; do
for p in u U i r; do
    # Very basic "does it crash" test
    for h in h d r; do
	$NSEXE ./cmsg_sender -p $p -6 -H $h $TGT6 1234
+19 −5
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ enum {
	ERN_RECVERR,
	ERN_CMSG_RD,
	ERN_CMSG_RCV,
	ERN_SEND_MORE,
};

struct option_cmsg_u32 {
@@ -46,6 +47,7 @@ struct options {
	const char *service;
	unsigned int size;
	unsigned int num_pkt;
	bool msg_more;
	struct {
		unsigned int mark;
		unsigned int dontfrag;
@@ -94,7 +96,8 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
	       "\t\t-S      send() size\n"
	       "\t\t-4/-6   Force IPv4 / IPv6 only\n"
	       "\t\t-p prot Socket protocol\n"
	       "\t\t        (u = UDP (default); i = ICMP; r = RAW)\n"
	       "\t\t        (u = UDP (default); i = ICMP; r = RAW;\n"
	       "\t\t         U = UDP with MSG_MORE)\n"
	       "\n"
	       "\t\t-m val  Set SO_MARK with given value\n"
	       "\t\t-M val  Set SO_MARK via setsockopt\n"
@@ -109,8 +112,8 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
	       "\t\t-l val  Set TTL/HOPLIMIT via cmsg\n"
	       "\t\t-L val  Set TTL/HOPLIMIT via setsockopt\n"
	       "\t\t-H type Add an IPv6 header option\n"
	       "\t\t        (h = HOP; d = DST; r = RTDST)"
	       "");
	       "\t\t        (h = HOP; d = DST; r = RTDST)\n"
	       "\n");
	exit(ERN_HELP);
}

@@ -133,8 +136,11 @@ static void cs_parse_args(int argc, char *argv[])
			opt.sock.family = AF_INET6;
			break;
		case 'p':
			if (*optarg == 'u' || *optarg == 'U') {
			if (*optarg == 'u') {
				opt.sock.proto = IPPROTO_UDP;
			} else if (*optarg == 'U') {
				opt.sock.proto = IPPROTO_UDP;
				opt.msg_more = true;
			} else if (*optarg == 'i' || *optarg == 'I') {
				opt.sock.proto = IPPROTO_ICMP;
			} else if (*optarg == 'r') {
@@ -531,7 +537,7 @@ int main(int argc, char *argv[])
	cs_write_cmsg(fd, &msg, cbuf, sizeof(cbuf));

	for (i = 0; i < opt.num_pkt; i++) {
		err = sendmsg(fd, &msg, 0);
		err = sendmsg(fd, &msg, opt.msg_more ? MSG_MORE : 0);
		if (err < 0) {
			if (!opt.silent_send)
				fprintf(stderr, "send failed: %s\n", strerror(errno));
@@ -542,6 +548,14 @@ int main(int argc, char *argv[])
			err = ERN_SEND_SHORT;
			goto err_out;
		}
		if (opt.msg_more) {
			err = write(fd, NULL, 0);
			if (err < 0) {
				fprintf(stderr, "send more: %s\n", strerror(errno));
				err = ERN_SEND_MORE;
				goto err_out;
			}
		}
	}
	err = ERN_SUCCESS;