netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg
@ 2022-02-17  1:21 Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 1/5] " Jakub Kicinski
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Jakub Kicinski @ 2022-02-17  1:21 UTC (permalink / raw)
  To: davem
  Cc: netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest, Jakub Kicinski

Support for IPV6_HOPLIMIT, IPV6_TCLASS, IPV6_DONTFRAG on ICMPv6
sockets and associated tests. I have no immediate plans to
implement IPV6_FLOWINFO and all the extension header stuff.

Jakub Kicinski (5):
  net: ping6: support setting basic SOL_IPV6 options via cmsg
  selftests: net: test IPV6_DONTFRAG
  selftests: net: test IPV6_TCLASS
  selftests: net: test IPV6_HOPLIMIT
  selftests: net: basic test for IPV6_2292*

 net/ipv6/ip6_output.c                     |   1 +
 net/ipv6/ping.c                           |  21 ++-
 tools/testing/selftests/net/cmsg_ipv6.sh  | 156 ++++++++++++++++++++
 tools/testing/selftests/net/cmsg_sender.c | 170 +++++++++++++++++++---
 4 files changed, 320 insertions(+), 28 deletions(-)
 create mode 100755 tools/testing/selftests/net/cmsg_ipv6.sh

-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net-next 1/5] net: ping6: support setting basic SOL_IPV6 options via cmsg
  2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
@ 2022-02-17  1:21 ` Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 2/5] selftests: net: test IPV6_DONTFRAG Jakub Kicinski
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Kicinski @ 2022-02-17  1:21 UTC (permalink / raw)
  To: davem
  Cc: netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest, Jakub Kicinski

Support setting IPV6_HOPLIMIT, IPV6_TCLASS, IPV6_DONTFRAG
during sendmsg via SOL_IPV6 cmsgs.

tclass and dontfrag are init'ed from struct ipv6_pinfo in
ipcm6_init_sk(), while hlimit is inited to -1, so we need
to handle it being populated via cmsg explicitly.

Leave extension headers and flowlabel unimplemented.
Those are slightly more laborious to test and users
seem to primarily care about IPV6_TCLASS.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/ipv6/ip6_output.c |  1 +
 net/ipv6/ping.c       | 21 ++++++++++++++++-----
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 0c6c971ce0a5..3286b64ec03d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1487,6 +1487,7 @@ static int __ip6_append_data(struct sock *sk,
 
 	if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
 	    (sk->sk_protocol == IPPROTO_UDP ||
+	     sk->sk_protocol == IPPROTO_ICMPV6 ||
 	     sk->sk_protocol == IPPROTO_RAW)) {
 		ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
 				sizeof(struct ipv6hdr));
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index d5544cf67ffe..ff033d16549e 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -101,11 +101,21 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	ipc6.sockc.tsflags = sk->sk_tsflags;
 	ipc6.sockc.mark = sk->sk_mark;
 
-	err = sock_cmsg_send(sk, msg, &ipc6.sockc);
-	if (err)
-		return err;
+	if (msg->msg_controllen) {
+		struct ipv6_txoptions opt = {};
+
+		opt.tot_len = sizeof(opt);
+		ipc6.opt = &opt;
 
-	/* TODO: use ip6_datagram_send_ctl to get options from cmsg */
+		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6);
+		if (err < 0)
+			return err;
+
+		/* Changes to txoptions and flow info are not implemented, yet.
+		 * Drop the options, fl6 is wiped below.
+		 */
+		ipc6.opt = NULL;
+	}
 
 	memset(&fl6, 0, sizeof(fl6));
 
@@ -140,7 +150,8 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	pfh.wcheck = 0;
 	pfh.family = AF_INET6;
 
-	ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	if (ipc6.hlimit < 0)
+		ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
 	lock_sock(sk);
 	err = ip6_append_data(sk, ping_getfrag, &pfh, len,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 2/5] selftests: net: test IPV6_DONTFRAG
  2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 1/5] " Jakub Kicinski
@ 2022-02-17  1:21 ` Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 3/5] selftests: net: test IPV6_TCLASS Jakub Kicinski
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Kicinski @ 2022-02-17  1:21 UTC (permalink / raw)
  To: davem
  Cc: netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest, Jakub Kicinski

Test setting IPV6_DONTFRAG via setsockopt and cmsg
across socket types.

Output without the kernel support (this series):

    Case DONTFRAG ICMP setsock returned 0, expected 1
    Case DONTFRAG ICMP cmsg returned 0, expected 1
    Case DONTFRAG ICMP both returned 0, expected 1
    Case DONTFRAG ICMP diff returned 0, expected 1
  FAIL - 4/24 cases failed

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/testing/selftests/net/cmsg_ipv6.sh  |  65 ++++++++++++++
 tools/testing/selftests/net/cmsg_sender.c | 105 +++++++++++++++++-----
 2 files changed, 147 insertions(+), 23 deletions(-)
 create mode 100755 tools/testing/selftests/net/cmsg_ipv6.sh

diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh
new file mode 100755
index 000000000000..fb5a8ab7c909
--- /dev/null
+++ b/tools/testing/selftests/net/cmsg_ipv6.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+NS=ns
+IP6=2001:db8:1::1/64
+TGT6=2001:db8:1::2
+
+cleanup()
+{
+    ip netns del $NS
+}
+
+trap cleanup EXIT
+
+NSEXE="ip netns exec $NS"
+
+# Namespaces
+ip netns add $NS
+
+$NSEXE sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null
+
+# Connectivity
+ip -netns $NS link add type dummy
+ip -netns $NS link set dev dummy0 up
+ip -netns $NS addr add $IP6 dev dummy0
+
+# Test
+BAD=0
+TOTAL=0
+
+check_result() {
+    ((TOTAL++))
+    if [ $1 -ne $2 ]; then
+	echo "  Case $3 returned $1, expected $2"
+	((BAD++))
+    fi
+}
+
+# IPV6_DONTFRAG
+for ovr in setsock cmsg both diff; do
+    for df in 0 1; do
+	for p in u i r; do
+	    [ $p == "u" ] && prot=UDP
+	    [ $p == "i" ] && prot=ICMP
+	    [ $p == "r" ] && prot=RAW
+
+	    [ $ovr == "setsock" ] && m="-F $df"
+	    [ $ovr == "cmsg" ]    && m="-f $df"
+	    [ $ovr == "both" ]    && m="-F $df -f $df"
+	    [ $ovr == "diff" ]    && m="-F $((1 - df)) -f $df"
+
+	    $NSEXE ./cmsg_sender -s -S 2000 -6 -p $p $m $TGT6 1234
+	    check_result $? $df "DONTFRAG $prot $ovr"
+	done
+    done
+done
+
+# Summary
+if [ $BAD -ne 0 ]; then
+    echo "FAIL - $BAD/$TOTAL cases failed"
+    exit 1
+else
+    echo "OK"
+    exit 0
+fi
diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c
index efa617bd34e2..844ca6134662 100644
--- a/tools/testing/selftests/net/cmsg_sender.c
+++ b/tools/testing/selftests/net/cmsg_sender.c
@@ -33,22 +33,26 @@ enum {
 	ERN_CMSG_RCV,
 };
 
+struct option_cmsg_u32 {
+	bool ena;
+	unsigned int val;
+};
+
 struct options {
 	bool silent_send;
 	const char *host;
 	const char *service;
+	unsigned int size;
 	struct {
 		unsigned int mark;
+		unsigned int dontfrag;
 	} sockopt;
 	struct {
 		unsigned int family;
 		unsigned int type;
 		unsigned int proto;
 	} sock;
-	struct {
-		bool ena;
-		unsigned int val;
-	} mark;
+	struct option_cmsg_u32 mark;
 	struct {
 		bool ena;
 		unsigned int delay;
@@ -56,7 +60,11 @@ struct options {
 	struct {
 		bool ena;
 	} ts;
+	struct {
+		struct option_cmsg_u32 dontfrag;
+	} v6;
 } opt = {
+	.size = 13,
 	.sock = {
 		.family	= AF_UNSPEC,
 		.type	= SOCK_DGRAM,
@@ -72,6 +80,7 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
 	printf("Usage: %s [opts] <dst host> <dst port / service>\n", bin);
 	printf("Options:\n"
 	       "\t\t-s      Silent send() failures\n"
+	       "\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"
@@ -80,6 +89,8 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
 	       "\t\t-M val  Set SO_MARK via setsockopt\n"
 	       "\t\t-d val  Set SO_TXTIME with given delay (usec)\n"
 	       "\t\t-t      Enable time stamp reporting\n"
+	       "\t\t-f val  Set don't fragment via cmsg\n"
+	       "\t\t-F val  Set don't fragment via setsockopt\n"
 	       "");
 	exit(ERN_HELP);
 }
@@ -88,11 +99,14 @@ static void cs_parse_args(int argc, char *argv[])
 {
 	char o;
 
-	while ((o = getopt(argc, argv, "46sp:m:M:d:t")) != -1) {
+	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:")) != -1) {
 		switch (o) {
 		case 's':
 			opt.silent_send = true;
 			break;
+		case 'S':
+			opt.size = atoi(optarg);
+			break;
 		case '4':
 			opt.sock.family = AF_INET;
 			break;
@@ -126,6 +140,13 @@ static void cs_parse_args(int argc, char *argv[])
 		case 't':
 			opt.ts.ena = true;
 			break;
+		case 'f':
+			opt.v6.dontfrag.ena = true;
+			opt.v6.dontfrag.val = atoi(optarg);
+			break;
+		case 'F':
+			opt.sockopt.dontfrag = atoi(optarg);
+			break;
 		}
 	}
 
@@ -136,6 +157,38 @@ static void cs_parse_args(int argc, char *argv[])
 	opt.service = argv[optind + 1];
 }
 
+static void memrnd(void *s, size_t n)
+{
+	int *dword = s;
+	char *byte;
+
+	for (; n >= 4; n -= 4)
+		*dword++ = rand();
+	byte = (void *)dword;
+	while (n--)
+		*byte++ = rand();
+}
+
+static void
+ca_write_cmsg_u32(char *cbuf, size_t cbuf_sz, size_t *cmsg_len,
+		  int level, int optname, struct option_cmsg_u32 *uopt)
+{
+	struct cmsghdr *cmsg;
+
+	if (!uopt->ena)
+		return;
+
+	cmsg = (struct cmsghdr *)(cbuf + *cmsg_len);
+	*cmsg_len += CMSG_SPACE(sizeof(__u32));
+	if (cbuf_sz < *cmsg_len)
+		error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
+
+	cmsg->cmsg_level = level;
+	cmsg->cmsg_type = optname;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(__u32));
+	*(__u32 *)CMSG_DATA(cmsg) = uopt->val;
+}
+
 static void
 cs_write_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 {
@@ -145,17 +198,11 @@ cs_write_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 	msg->msg_control = cbuf;
 	cmsg_len = 0;
 
-	if (opt.mark.ena) {
-		cmsg = (struct cmsghdr *)(cbuf + cmsg_len);
-		cmsg_len += CMSG_SPACE(sizeof(__u32));
-		if (cbuf_sz < cmsg_len)
-			error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
+	ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
+			  SOL_SOCKET, SO_MARK, &opt.mark);
+	ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
+			  SOL_IPV6, IPV6_DONTFRAG, &opt.v6.dontfrag);
 
-		cmsg->cmsg_level = SOL_SOCKET;
-		cmsg->cmsg_type = SO_MARK;
-		cmsg->cmsg_len = CMSG_LEN(sizeof(__u32));
-		*(__u32 *)CMSG_DATA(cmsg) = opt.mark.val;
-	}
 	if (opt.txtime.ena) {
 		struct sock_txtime so_txtime = {
 			.clockid = CLOCK_MONOTONIC,
@@ -286,18 +333,33 @@ cs_read_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 	}
 }
 
+static void ca_set_sockopts(int fd)
+{
+	if (opt.sockopt.mark &&
+	    setsockopt(fd, SOL_SOCKET, SO_MARK,
+		       &opt.sockopt.mark, sizeof(opt.sockopt.mark)))
+		error(ERN_SOCKOPT, errno, "setsockopt SO_MARK");
+	if (opt.sockopt.dontfrag &&
+	    setsockopt(fd, SOL_IPV6, IPV6_DONTFRAG,
+		       &opt.sockopt.dontfrag, sizeof(opt.sockopt.dontfrag)))
+		error(ERN_SOCKOPT, errno, "setsockopt IPV6_DONTFRAG");
+}
+
 int main(int argc, char *argv[])
 {
-	char buf[] = "blablablabla";
 	struct addrinfo hints, *ai;
 	struct iovec iov[1];
 	struct msghdr msg;
 	char cbuf[1024];
+	char *buf;
 	int err;
 	int fd;
 
 	cs_parse_args(argc, argv);
 
+	buf = malloc(opt.size);
+	memrnd(buf, opt.size);
+
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family = opt.sock.family;
 
@@ -326,17 +388,14 @@ int main(int argc, char *argv[])
 		buf[0] = ICMPV6_ECHO_REQUEST;
 		buf[1] = 0;
 	} else if (opt.sock.type == SOCK_RAW) {
-		struct udphdr hdr = { 1, 2, htons(sizeof(buf)), 0 };
+		struct udphdr hdr = { 1, 2, htons(opt.size), 0 };
 		struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;;
 
 		memcpy(buf, &hdr, sizeof(hdr));
 		sin6->sin6_port = htons(opt.sock.proto);
 	}
 
-	if (opt.sockopt.mark &&
-	    setsockopt(fd, SOL_SOCKET, SO_MARK,
-		       &opt.sockopt.mark, sizeof(opt.sockopt.mark)))
-		error(ERN_SOCKOPT, errno, "setsockopt SO_MARK");
+	ca_set_sockopts(fd);
 
 	if (clock_gettime(CLOCK_REALTIME, &time_start_real))
 		error(ERN_GETTIME, errno, "gettime REALTIME");
@@ -344,7 +403,7 @@ int main(int argc, char *argv[])
 		error(ERN_GETTIME, errno, "gettime MONOTONIC");
 
 	iov[0].iov_base = buf;
-	iov[0].iov_len = sizeof(buf);
+	iov[0].iov_len = opt.size;
 
 	memset(&msg, 0, sizeof(msg));
 	msg.msg_name = ai->ai_addr;
@@ -360,7 +419,7 @@ int main(int argc, char *argv[])
 			fprintf(stderr, "send failed: %s\n", strerror(errno));
 		err = ERN_SEND;
 		goto err_out;
-	} else if (err != sizeof(buf)) {
+	} else if (err != (int)opt.size) {
 		fprintf(stderr, "short send\n");
 		err = ERN_SEND_SHORT;
 		goto err_out;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 3/5] selftests: net: test IPV6_TCLASS
  2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 1/5] " Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 2/5] selftests: net: test IPV6_DONTFRAG Jakub Kicinski
@ 2022-02-17  1:21 ` Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 4/5] selftests: net: test IPV6_HOPLIMIT Jakub Kicinski
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Kicinski @ 2022-02-17  1:21 UTC (permalink / raw)
  To: davem
  Cc: netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest, Jakub Kicinski

Test setting IPV6_TCLASS via setsockopt and cmsg
across socket types.

Output without the kernel support (this series):

  Case TCLASS ICMP cmsg - packet data returned 1, expected 0
  Case TCLASS ICMP cmsg - rejection returned 0, expected 1
  Case TCLASS ICMP diff - pass returned 1, expected 0
  Case TCLASS ICMP diff - packet data returned 1, expected 0
  Case TCLASS ICMP diff - rejection returned 0, expected 1

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/testing/selftests/net/cmsg_ipv6.sh  | 51 +++++++++++++++++++++++
 tools/testing/selftests/net/cmsg_sender.c | 19 ++++++++-
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh
index fb5a8ab7c909..f7bb6ce68c88 100755
--- a/tools/testing/selftests/net/cmsg_ipv6.sh
+++ b/tools/testing/selftests/net/cmsg_ipv6.sh
@@ -1,12 +1,16 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+ksft_skip=4
+
 NS=ns
 IP6=2001:db8:1::1/64
 TGT6=2001:db8:1::2
+TMPF=`mktemp`
 
 cleanup()
 {
+    rm -f $TMPF
     ip netns del $NS
 }
 
@@ -14,6 +18,12 @@ trap cleanup EXIT
 
 NSEXE="ip netns exec $NS"
 
+tcpdump -h | grep immediate-mode >> /dev/null
+if [ $? -ne 0 ]; then
+    echo "SKIP - tcpdump with --immediate-mode option required"
+    exit $ksft_skip
+fi
+
 # Namespaces
 ip netns add $NS
 
@@ -55,6 +65,47 @@ for ovr in setsock cmsg both diff; do
     done
 done
 
+# IPV6_TCLASS
+TOS=0x10
+TOS2=0x20
+
+ip -6 -netns $NS rule add tos $TOS lookup 300
+ip -6 -netns $NS route add table 300 prohibit any
+
+for ovr in setsock cmsg both diff; do
+    for p in u i r; do
+	[ $p == "u" ] && prot=UDP
+	[ $p == "i" ] && prot=ICMP
+	[ $p == "r" ] && prot=RAW
+
+	[ $ovr == "setsock" ] && m="-C"
+	[ $ovr == "cmsg" ]    && m="-c"
+	[ $ovr == "both" ]    && m="-C $((TOS2)) -c"
+	[ $ovr == "diff" ]    && m="-C $((TOS )) -c"
+
+	$NSEXE nohup tcpdump --immediate-mode -p -ni dummy0 -w $TMPF -c 4 2> /dev/null &
+	BG=$!
+	sleep 0.05
+
+	$NSEXE ./cmsg_sender -6 -p $p $m $((TOS2)) $TGT6 1234
+	check_result $? 0 "TCLASS $prot $ovr - pass"
+
+	while [ -d /proc/$BG ]; do
+	    $NSEXE ./cmsg_sender -6 -p u $TGT6 1234
+	done
+
+	tcpdump -r $TMPF -v 2>&1 | grep "class $TOS2" >> /dev/null
+	check_result $? 0 "TCLASS $prot $ovr - packet data"
+	rm $TMPF
+
+	[ $ovr == "both" ]    && m="-C $((TOS )) -c"
+	[ $ovr == "diff" ]    && m="-C $((TOS2)) -c"
+
+	$NSEXE ./cmsg_sender -6 -p $p $m $((TOS)) -s $TGT6 1234
+	check_result $? 1 "TCLASS $prot $ovr - rejection"
+    done
+done
+
 # Summary
 if [ $BAD -ne 0 ]; then
     echo "FAIL - $BAD/$TOTAL cases failed"
diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c
index 844ca6134662..4033cf93eabf 100644
--- a/tools/testing/selftests/net/cmsg_sender.c
+++ b/tools/testing/selftests/net/cmsg_sender.c
@@ -46,6 +46,7 @@ struct options {
 	struct {
 		unsigned int mark;
 		unsigned int dontfrag;
+		unsigned int tclass;
 	} sockopt;
 	struct {
 		unsigned int family;
@@ -62,6 +63,7 @@ struct options {
 	} ts;
 	struct {
 		struct option_cmsg_u32 dontfrag;
+		struct option_cmsg_u32 tclass;
 	} v6;
 } opt = {
 	.size = 13,
@@ -91,6 +93,8 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
 	       "\t\t-t      Enable time stamp reporting\n"
 	       "\t\t-f val  Set don't fragment via cmsg\n"
 	       "\t\t-F val  Set don't fragment via setsockopt\n"
+	       "\t\t-c val  Set TCLASS via cmsg\n"
+	       "\t\t-C val  Set TCLASS via setsockopt\n"
 	       "");
 	exit(ERN_HELP);
 }
@@ -99,7 +103,7 @@ static void cs_parse_args(int argc, char *argv[])
 {
 	char o;
 
-	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:")) != -1) {
+	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:")) != -1) {
 		switch (o) {
 		case 's':
 			opt.silent_send = true;
@@ -147,6 +151,13 @@ static void cs_parse_args(int argc, char *argv[])
 		case 'F':
 			opt.sockopt.dontfrag = atoi(optarg);
 			break;
+		case 'c':
+			opt.v6.tclass.ena = true;
+			opt.v6.tclass.val = atoi(optarg);
+			break;
+		case 'C':
+			opt.sockopt.tclass = atoi(optarg);
+			break;
 		}
 	}
 
@@ -202,6 +213,8 @@ cs_write_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 			  SOL_SOCKET, SO_MARK, &opt.mark);
 	ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
 			  SOL_IPV6, IPV6_DONTFRAG, &opt.v6.dontfrag);
+	ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
+			  SOL_IPV6, IPV6_TCLASS, &opt.v6.tclass);
 
 	if (opt.txtime.ena) {
 		struct sock_txtime so_txtime = {
@@ -343,6 +356,10 @@ static void ca_set_sockopts(int fd)
 	    setsockopt(fd, SOL_IPV6, IPV6_DONTFRAG,
 		       &opt.sockopt.dontfrag, sizeof(opt.sockopt.dontfrag)))
 		error(ERN_SOCKOPT, errno, "setsockopt IPV6_DONTFRAG");
+	if (opt.sockopt.tclass &&
+	    setsockopt(fd, SOL_IPV6, IPV6_TCLASS,
+		       &opt.sockopt.tclass, sizeof(opt.sockopt.tclass)))
+		error(ERN_SOCKOPT, errno, "setsockopt IPV6_TCLASS");
 }
 
 int main(int argc, char *argv[])
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 4/5] selftests: net: test IPV6_HOPLIMIT
  2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
                   ` (2 preceding siblings ...)
  2022-02-17  1:21 ` [PATCH net-next 3/5] selftests: net: test IPV6_TCLASS Jakub Kicinski
@ 2022-02-17  1:21 ` Jakub Kicinski
  2022-02-17  1:21 ` [PATCH net-next 5/5] selftests: net: basic test for IPV6_2292* Jakub Kicinski
  2022-02-17 14:30 ` [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg patchwork-bot+netdevbpf
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Kicinski @ 2022-02-17  1:21 UTC (permalink / raw)
  To: davem
  Cc: netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest, Jakub Kicinski

Test setting IPV6_HOPLIMIT via setsockopt and cmsg
across socket types.

Output without the kernel support (this series):

  Case HOPLIMIT ICMP cmsg - packet data returned 1, expected 0
  Case HOPLIMIT ICMP diff - packet data returned 1, expected 0

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/testing/selftests/net/cmsg_ipv6.sh  | 31 +++++++++++++++++++++++
 tools/testing/selftests/net/cmsg_sender.c | 19 +++++++++++++-
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh
index f7bb6ce68c88..e42c36e0d741 100755
--- a/tools/testing/selftests/net/cmsg_ipv6.sh
+++ b/tools/testing/selftests/net/cmsg_ipv6.sh
@@ -106,6 +106,37 @@ for ovr in setsock cmsg both diff; do
     done
 done
 
+# IPV6_HOPLIMIT
+LIM=4
+
+for ovr in setsock cmsg both diff; do
+    for p in u i r; do
+	[ $p == "u" ] && prot=UDP
+	[ $p == "i" ] && prot=ICMP
+	[ $p == "r" ] && prot=RAW
+
+	[ $ovr == "setsock" ] && m="-L"
+	[ $ovr == "cmsg" ]    && m="-l"
+	[ $ovr == "both" ]    && m="-L $LIM -l"
+	[ $ovr == "diff" ]    && m="-L $((LIM + 1)) -l"
+
+	$NSEXE nohup tcpdump --immediate-mode -p -ni dummy0 -w $TMPF -c 4 2> /dev/null &
+	BG=$!
+	sleep 0.05
+
+	$NSEXE ./cmsg_sender -6 -p $p $m $LIM $TGT6 1234
+	check_result $? 0 "HOPLIMIT $prot $ovr - pass"
+
+	while [ -d /proc/$BG ]; do
+	    $NSEXE ./cmsg_sender -6 -p u $TGT6 1234
+	done
+
+	tcpdump -r $TMPF -v 2>&1 | grep "hlim $LIM[^0-9]" >> /dev/null
+	check_result $? 0 "HOPLIMIT $prot $ovr - packet data"
+	rm $TMPF
+    done
+done
+
 # Summary
 if [ $BAD -ne 0 ]; then
     echo "FAIL - $BAD/$TOTAL cases failed"
diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c
index 4033cf93eabf..6136aa7df1c4 100644
--- a/tools/testing/selftests/net/cmsg_sender.c
+++ b/tools/testing/selftests/net/cmsg_sender.c
@@ -47,6 +47,7 @@ struct options {
 		unsigned int mark;
 		unsigned int dontfrag;
 		unsigned int tclass;
+		unsigned int hlimit;
 	} sockopt;
 	struct {
 		unsigned int family;
@@ -64,6 +65,7 @@ struct options {
 	struct {
 		struct option_cmsg_u32 dontfrag;
 		struct option_cmsg_u32 tclass;
+		struct option_cmsg_u32 hlimit;
 	} v6;
 } opt = {
 	.size = 13,
@@ -95,6 +97,8 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
 	       "\t\t-F val  Set don't fragment via setsockopt\n"
 	       "\t\t-c val  Set TCLASS via cmsg\n"
 	       "\t\t-C val  Set TCLASS via setsockopt\n"
+	       "\t\t-l val  Set HOPLIMIT via cmsg\n"
+	       "\t\t-L val  Set HOPLIMIT via setsockopt\n"
 	       "");
 	exit(ERN_HELP);
 }
@@ -103,7 +107,7 @@ static void cs_parse_args(int argc, char *argv[])
 {
 	char o;
 
-	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:")) != -1) {
+	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:l:L:")) != -1) {
 		switch (o) {
 		case 's':
 			opt.silent_send = true;
@@ -158,6 +162,13 @@ static void cs_parse_args(int argc, char *argv[])
 		case 'C':
 			opt.sockopt.tclass = atoi(optarg);
 			break;
+		case 'l':
+			opt.v6.hlimit.ena = true;
+			opt.v6.hlimit.val = atoi(optarg);
+			break;
+		case 'L':
+			opt.sockopt.hlimit = atoi(optarg);
+			break;
 		}
 	}
 
@@ -215,6 +226,8 @@ cs_write_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 			  SOL_IPV6, IPV6_DONTFRAG, &opt.v6.dontfrag);
 	ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
 			  SOL_IPV6, IPV6_TCLASS, &opt.v6.tclass);
+	ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
+			  SOL_IPV6, IPV6_HOPLIMIT, &opt.v6.hlimit);
 
 	if (opt.txtime.ena) {
 		struct sock_txtime so_txtime = {
@@ -360,6 +373,10 @@ static void ca_set_sockopts(int fd)
 	    setsockopt(fd, SOL_IPV6, IPV6_TCLASS,
 		       &opt.sockopt.tclass, sizeof(opt.sockopt.tclass)))
 		error(ERN_SOCKOPT, errno, "setsockopt IPV6_TCLASS");
+	if (opt.sockopt.hlimit &&
+	    setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS,
+		       &opt.sockopt.hlimit, sizeof(opt.sockopt.hlimit)))
+		error(ERN_SOCKOPT, errno, "setsockopt IPV6_HOPLIMIT");
 }
 
 int main(int argc, char *argv[])
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 5/5] selftests: net: basic test for IPV6_2292*
  2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
                   ` (3 preceding siblings ...)
  2022-02-17  1:21 ` [PATCH net-next 4/5] selftests: net: test IPV6_HOPLIMIT Jakub Kicinski
@ 2022-02-17  1:21 ` Jakub Kicinski
  2022-02-17 14:30 ` [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg patchwork-bot+netdevbpf
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Kicinski @ 2022-02-17  1:21 UTC (permalink / raw)
  To: davem
  Cc: netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest, Jakub Kicinski

Add a basic test to make sure ping sockets don't crash
with IPV6_2292* options.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/testing/selftests/net/cmsg_ipv6.sh  |  9 +++++++
 tools/testing/selftests/net/cmsg_sender.c | 33 ++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh
index e42c36e0d741..2d89cb0ad288 100755
--- a/tools/testing/selftests/net/cmsg_ipv6.sh
+++ b/tools/testing/selftests/net/cmsg_ipv6.sh
@@ -137,6 +137,15 @@ for ovr in setsock cmsg both diff; do
     done
 done
 
+# IPV6 exthdr
+for p in 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
+	check_result $? 0 "ExtHdr $prot $ovr - pass"
+    done
+done
+
 # Summary
 if [ $BAD -ne 0 ]; then
     echo "FAIL - $BAD/$TOTAL cases failed"
diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c
index 6136aa7df1c4..aed7845c08a8 100644
--- a/tools/testing/selftests/net/cmsg_sender.c
+++ b/tools/testing/selftests/net/cmsg_sender.c
@@ -66,6 +66,7 @@ struct options {
 		struct option_cmsg_u32 dontfrag;
 		struct option_cmsg_u32 tclass;
 		struct option_cmsg_u32 hlimit;
+		struct option_cmsg_u32 exthdr;
 	} v6;
 } opt = {
 	.size = 13,
@@ -99,6 +100,8 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
 	       "\t\t-C val  Set TCLASS via setsockopt\n"
 	       "\t\t-l val  Set HOPLIMIT via cmsg\n"
 	       "\t\t-L val  Set HOPLIMIT via setsockopt\n"
+	       "\t\t-H type Add an IPv6 header option\n"
+	       "\t\t        (h = HOP; d = DST; r = RTDST)"
 	       "");
 	exit(ERN_HELP);
 }
@@ -107,7 +110,7 @@ static void cs_parse_args(int argc, char *argv[])
 {
 	char o;
 
-	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:l:L:")) != -1) {
+	while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:l:L:H:")) != -1) {
 		switch (o) {
 		case 's':
 			opt.silent_send = true;
@@ -169,6 +172,23 @@ static void cs_parse_args(int argc, char *argv[])
 		case 'L':
 			opt.sockopt.hlimit = atoi(optarg);
 			break;
+		case 'H':
+			opt.v6.exthdr.ena = true;
+			switch (optarg[0]) {
+			case 'h':
+				opt.v6.exthdr.val = IPV6_HOPOPTS;
+				break;
+			case 'd':
+				opt.v6.exthdr.val = IPV6_DSTOPTS;
+				break;
+			case 'r':
+				opt.v6.exthdr.val = IPV6_RTHDRDSTOPTS;
+				break;
+			default:
+				printf("Error: hdr type: %s\n", optarg);
+				break;
+			}
+			break;
 		}
 	}
 
@@ -272,6 +292,17 @@ cs_write_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 		*(__u32 *)CMSG_DATA(cmsg) = SOF_TIMESTAMPING_TX_SCHED |
 					    SOF_TIMESTAMPING_TX_SOFTWARE;
 	}
+	if (opt.v6.exthdr.ena) {
+		cmsg = (struct cmsghdr *)(cbuf + cmsg_len);
+		cmsg_len += CMSG_SPACE(8);
+		if (cbuf_sz < cmsg_len)
+			error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
+
+		cmsg->cmsg_level = SOL_IPV6;
+		cmsg->cmsg_type = opt.v6.exthdr.val;
+		cmsg->cmsg_len = CMSG_LEN(8);
+		*(__u64 *)CMSG_DATA(cmsg) = 0;
+	}
 
 	if (cmsg_len)
 		msg->msg_controllen = cmsg_len;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg
  2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
                   ` (4 preceding siblings ...)
  2022-02-17  1:21 ` [PATCH net-next 5/5] selftests: net: basic test for IPV6_2292* Jakub Kicinski
@ 2022-02-17 14:30 ` patchwork-bot+netdevbpf
  5 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2022-02-17 14:30 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, willemb, lorenzo, maze, dsahern, yoshfuji, shuah,
	linux-kselftest

Hello:

This series was applied to netdev/net-next.git (master)
by David S. Miller <davem@davemloft.net>:

On Wed, 16 Feb 2022 17:21:15 -0800 you wrote:
> Support for IPV6_HOPLIMIT, IPV6_TCLASS, IPV6_DONTFRAG on ICMPv6
> sockets and associated tests. I have no immediate plans to
> implement IPV6_FLOWINFO and all the extension header stuff.
> 
> Jakub Kicinski (5):
>   net: ping6: support setting basic SOL_IPV6 options via cmsg
>   selftests: net: test IPV6_DONTFRAG
>   selftests: net: test IPV6_TCLASS
>   selftests: net: test IPV6_HOPLIMIT
>   selftests: net: basic test for IPV6_2292*
> 
> [...]

Here is the summary with links:
  - [net-next,1/5] net: ping6: support setting basic SOL_IPV6 options via cmsg
    https://git.kernel.org/netdev/net-next/c/13651224c00b
  - [net-next,2/5] selftests: net: test IPV6_DONTFRAG
    https://git.kernel.org/netdev/net-next/c/6f97c7c605d6
  - [net-next,3/5] selftests: net: test IPV6_TCLASS
    https://git.kernel.org/netdev/net-next/c/9657ad09e1fa
  - [net-next,4/5] selftests: net: test IPV6_HOPLIMIT
    https://git.kernel.org/netdev/net-next/c/05ae83d5a4a2
  - [net-next,5/5] selftests: net: basic test for IPV6_2292*
    https://git.kernel.org/netdev/net-next/c/a22982c39eb1

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-02-17 14:30 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-17  1:21 [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg Jakub Kicinski
2022-02-17  1:21 ` [PATCH net-next 1/5] " Jakub Kicinski
2022-02-17  1:21 ` [PATCH net-next 2/5] selftests: net: test IPV6_DONTFRAG Jakub Kicinski
2022-02-17  1:21 ` [PATCH net-next 3/5] selftests: net: test IPV6_TCLASS Jakub Kicinski
2022-02-17  1:21 ` [PATCH net-next 4/5] selftests: net: test IPV6_HOPLIMIT Jakub Kicinski
2022-02-17  1:21 ` [PATCH net-next 5/5] selftests: net: basic test for IPV6_2292* Jakub Kicinski
2022-02-17 14:30 ` [PATCH net-next 0/5] net: ping6: support setting basic SOL_IPV6 options via cmsg patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).