Skip site navigation (1)Skip section navigation (2)
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>