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[])