diff options
author | Jakub Kicinski <kuba@kernel.org> | 2022-02-16 17:21:17 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2022-02-17 14:22:09 +0000 |
commit | 6f97c7c605d63d8f83f102a768ddfd0ad553fa3f (patch) | |
tree | 2fba1a9f4c199bacfe1f26f1815f7d399cf06931 /tools/testing/selftests/net/cmsg_sender.c | |
parent | 13651224c00b74a02c731b7840577f14e0311c83 (diff) |
selftests: net: test IPV6_DONTFRAG
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>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/testing/selftests/net/cmsg_sender.c')
-rw-r--r-- | tools/testing/selftests/net/cmsg_sender.c | 105 |
1 files changed, 82 insertions, 23 deletions
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; |