Date: Fri, 21 Feb 2025 01:57:25 GMT From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 3ff5faee9e75 - stable/14 - tools: Add a small program to demonstrate FIB handling in bind(2) Message-ID: <202502210157.51L1vPfJ067693@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=3ff5faee9e753e70191bb17489600dceaee0424a commit 3ff5faee9e753e70191bb17489600dceaee0424a Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2025-02-04 16:45:21 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2025-02-21 01:04:50 +0000 tools: Add a small program to demonstrate FIB handling in bind(2) MFC after: 2 weeks Sponsored by: Klara, Inc. Sponsored by: Stormshield (cherry picked from commit 3fa552149885766b009d95d20bdf651786fac7b7) --- tools/tools/fib_multibind/Makefile | 4 + tools/tools/fib_multibind/sink.c | 237 +++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+) diff --git a/tools/tools/fib_multibind/Makefile b/tools/tools/fib_multibind/Makefile new file mode 100644 index 000000000000..1d447e788a4f --- /dev/null +++ b/tools/tools/fib_multibind/Makefile @@ -0,0 +1,4 @@ +PROG= sink +MAN= + +.include <bsd.prog.mk> diff --git a/tools/tools/fib_multibind/sink.c b/tools/tools/fib_multibind/sink.c new file mode 100644 index 000000000000..fe93a66fe266 --- /dev/null +++ b/tools/tools/fib_multibind/sink.c @@ -0,0 +1,237 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Klara, Inc. + */ + +/* + * A program to demonstrate the effects of the net.inet.tcp.bind_all_fibs and + * net.inet.udp.bind_all_fibs sysctls when they are set to 0. + * + * The program accepts TCP connections (default) or UDP datagrams (-u flag) and + * prints the FIB on which they were received, then discards them. If -a is + * specific, the program accepts data from all FIBs, otherwise it only accepts + * data from the FIB specified by the -f option. + */ + +#include <sys/event.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <netinet/in.h> + +#include <err.h> +#include <netdb.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct sink_softc { + struct sockaddr_storage ss; + enum { SINK_TCP, SINK_UDP } type; + int nfibs; + int kq; + int *fds; +}; + +static void _Noreturn +usage(void) +{ + fprintf(stderr, + "usage: sink [-au] [-f <fib>] [<listen addr>] <listen port>\n"); + exit(1); +} + +static void +check_multibind(struct sink_softc *sc) +{ + const char *sysctl; + size_t len; + int error, val; + + sysctl = sc->type == SINK_TCP ? "net.inet.tcp.bind_all_fibs" : + "net.inet.udp.bind_all_fibs"; + len = sizeof(val); + error = sysctlbyname(sysctl, &val, &len, NULL, 0); + if (error != 0) + err(1, "sysctlbyname(%s)", sysctl); + if (val != 0) + errx(1, "multibind is disabled, set %s=0 to enable", sysctl); +} + +static void +addrinfo(struct sink_softc *sc, const char *addr, int port) +{ + struct addrinfo hints, *res, *res1; + char portstr[8]; + int error; + + memset(&sc->ss, 0, sizeof(sc->ss)); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = sc->type == SINK_TCP ? SOCK_STREAM : SOCK_DGRAM; + snprintf(portstr, sizeof(portstr), "%d", port); + error = getaddrinfo(addr, portstr, &hints, &res); + if (error != 0) + errx(1, "%s", gai_strerror(error)); + for (res1 = res; res != NULL; res = res->ai_next) { + if ((res->ai_protocol == IPPROTO_TCP && sc->type == SINK_TCP) || + (res->ai_protocol == IPPROTO_UDP && sc->type == SINK_UDP)) { + memcpy(&sc->ss, res->ai_addr, res->ai_addrlen); + break; + } + } + if (res == NULL) { + errx(1, "no %s address found for '%s'", + sc->type == SINK_TCP ? "TCP" : "UDP", addr); + } + freeaddrinfo(res1); +} + +int +main(int argc, char **argv) +{ + struct sink_softc sc; + const char *laddr; + int ch, error, fib, lport; + bool all; + + all = false; + sc.type = SINK_TCP; + fib = -1; + while ((ch = getopt(argc, argv, "af:u")) != -1) { + switch (ch) { + case 'a': + all = true; + break; + case 'f': + fib = atoi(optarg); + break; + case 'u': + sc.type = SINK_UDP; + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (all && fib != -1) + errx(1, "-a and -f are mutually exclusive"); + if (fib == -1) { + size_t len; + + error = sysctlbyname("net.my_fibnum", &fib, &len, NULL, 0); + if (error != 0) + err(1, "sysctlbyname(net.my_fibnum)"); + } + + if (argc == 2) { + laddr = argv[0]; + lport = atoi(argv[1]); + } else if (argc == 1) { + laddr = NULL; + lport = atoi(argv[0]); + } else { + usage(); + } + addrinfo(&sc, laddr, lport); + + check_multibind(&sc); + + sc.kq = kqueue(); + if (sc.kq == -1) + err(1, "kqueue"); + + if (all) { + size_t len; + + len = sizeof(sc.nfibs); + error = sysctlbyname("net.fibs", &sc.nfibs, &len, NULL, 0); + if (error != 0) + err(1, "sysctlbyname(net.fibs)"); + } else { + sc.nfibs = 1; + } + + sc.fds = calloc(all ? sc.nfibs : 1, sizeof(int)); + if (sc.fds == NULL) + err(1, "calloc"); + for (int i = 0; i < sc.nfibs; i++) { + struct kevent kev; + int s; + + if (sc.type == SINK_TCP) + s = socket(sc.ss.ss_family, SOCK_STREAM, 0); + else + s = socket(sc.ss.ss_family, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket"); + error = setsockopt(s, SOL_SOCKET, SO_SETFIB, + all ? &i : &fib, sizeof(int)); + if (error != 0) + err(1, "setsockopt(SO_SETFIB)"); + + error = bind(s, (struct sockaddr *)&sc.ss, sc.ss.ss_len); + if (error != 0) + err(1, "bind"); + + if (sc.type == SINK_TCP) { + error = listen(s, 5); + if (error != 0) + err(1, "listen"); + } + + EV_SET(&kev, s, EVFILT_READ, EV_ADD, 0, 0, NULL); + error = kevent(sc.kq, &kev, 1, NULL, 0, NULL); + if (error != 0) + err(1, "kevent"); + + sc.fds[i] = s; + } + + for (;;) { + struct kevent kev; + socklen_t optlen; + int n; + + n = kevent(sc.kq, NULL, 0, &kev, 1, NULL); + if (n == -1) + err(1, "kevent"); + if (n == 0) + continue; + + optlen = sizeof(fib); + error = getsockopt((int)kev.ident, SOL_SOCKET, SO_FIB, + &fib, &optlen); + if (error == -1) + err(1, "getsockopt(SO_FIB)"); + + if (sc.type == SINK_TCP) { + int cs; + + printf("accepting connection from FIB %d\n", fib); + + cs = accept((int)kev.ident, NULL, NULL); + if (cs == -1) + err(1, "accept"); + close(cs); + } else { + char buf[1024]; + ssize_t nb; + + printf("receiving datagram from FIB %d\n", fib); + + nb = recvfrom((int)kev.ident, buf, sizeof(buf), 0, + NULL, NULL); + if (nb == -1) + err(1, "recvfrom"); + } + } + + return (0); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502210157.51L1vPfJ067693>