aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2023-05-30 11:31:04 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2023-05-30 11:36:43 +0000
commitcb1fc924d2c0b87ad27e3741aabf641d35797e2e (patch)
tree89b6d26d68e27ce618d5ef59f25740e9e409e5f5
parentb71f278465ed680019532b8388a163f1d428cc00 (diff)
downloadsrc-cb1fc924d2c0b87ad27e3741aabf641d35797e2e.tar.gz
src-cb1fc924d2c0b87ad27e3741aabf641d35797e2e.zip
genl: add new command to list genetlink(4)
This commands list genetlink protocols and its operations and capabilities Name: nlctrl ID: 0x10, Version: 00, header size: 2, max attributes: 10 supported operations: - ID: 0x3, Capabilities: 0xe (can modify; can get/dump; has policy) multicast groups: - ID: 0x30, Name: notify Name: carp ID: 0x11, Version: 00, header size: 2, max attributes: 2 supported operations: - ID: 0x1, Capabilities: 0xe (can modify; can get/dump; has policy) - ID: 0x2, Capabilities: 0xb (requires admin permission; can modify; has policy) Reviewed by: melifaro Differential Revision: https://reviews.freebsd.org/D40330
-rw-r--r--share/mk/src.opts.mk1
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc5
-rw-r--r--tools/build/options/WITHOUT_NETLINK4
-rw-r--r--tools/build/options/WITH_NETLINK4
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/genl/Makefile3
-rw-r--r--usr.bin/genl/genl.146
-rw-r--r--usr.bin/genl/genl.c181
8 files changed, 245 insertions, 0 deletions
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index f828bdc0151b..7b67a55f34b4 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -145,6 +145,7 @@ __DEFAULT_YES_OPTIONS = \
MLX5TOOL \
NETCAT \
NETGRAPH \
+ NETLINK \
NETLINK_SUPPORT \
NLS_CATALOGS \
NS_CACHING \
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 9c7e40ee563a..20654515cfd1 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -5639,6 +5639,11 @@ OLD_FILES+=var/yp/Makefile.dist
OLD_DIRS+=var/yp
.endif
+.if ${MK_NETLINK} == no
+OLD_FILES+=usr.bin/genl
+OLD_FILES+=usr/share/man/man1/genl.1.gz
+.endif
+
.if ${MK_NLS} == no
OLD_DIRS+=usr/share/nls/
OLD_DIRS+=usr/share/nls/C
diff --git a/tools/build/options/WITHOUT_NETLINK b/tools/build/options/WITHOUT_NETLINK
new file mode 100644
index 000000000000..3ff4b66f1900
--- /dev/null
+++ b/tools/build/options/WITHOUT_NETLINK
@@ -0,0 +1,4 @@
+.\" $FreeBSD$
+Do not build
+.Xr genl 1
+utility.
diff --git a/tools/build/options/WITH_NETLINK b/tools/build/options/WITH_NETLINK
new file mode 100644
index 000000000000..321e9856b2b5
--- /dev/null
+++ b/tools/build/options/WITH_NETLINK
@@ -0,0 +1,4 @@
+.\" $FreeBSD$
+Build the
+.Xr genl 1
+utility.
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 19988d35c7ba..e027eaf81f24 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -235,6 +235,7 @@ SUBDIR.${MK_MAIL}+= msgs
SUBDIR.${MK_MAKE}+= bmake
SUBDIR.${MK_MAN_UTILS}+= man
SUBDIR.${MK_NETCAT}+= nc
+SUBDIR.${MK_NETLINK}+= genl
SUBDIR.${MK_NIS}+= ypcat
SUBDIR.${MK_NIS}+= ypmatch
SUBDIR.${MK_NIS}+= ypwhich
diff --git a/usr.bin/genl/Makefile b/usr.bin/genl/Makefile
new file mode 100644
index 000000000000..15e60300de02
--- /dev/null
+++ b/usr.bin/genl/Makefile
@@ -0,0 +1,3 @@
+PROG= genl
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/genl/genl.1 b/usr.bin/genl/genl.1
new file mode 100644
index 000000000000..44ce4feaea48
--- /dev/null
+++ b/usr.bin/genl/genl.1
@@ -0,0 +1,46 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+.\"
+.\" Copyright (c) 2023 Baptiste Daroussin <bapt@nours.eu>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd May 20, 2023
+.Dt GENL 1
+.Os
+.Sh NAME
+.Nm genl
+.Nd "generic netlink list"
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+lists all available generic netlink protocols, and presents its details:
+.Bl -tag -width "multicast groups"
+.It operations
+Id of the operation if any and associated capabilities
+.It multicast groups
+If of the available multicast group if any and it associated name
+.El
+.Sh SEE ALSO
+.Xr genetlink 4 ,
+.Xr netlink 4
diff --git a/usr.bin/genl/genl.c b/usr.bin/genl/genl.c
new file mode 100644
index 000000000000..8e8e18a7f8e2
--- /dev/null
+++ b/usr.bin/genl/genl.c
@@ -0,0 +1,181 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2023 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions~
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/module.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_generic.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_generic.h>
+
+struct genl_ctrl_op {
+ uint32_t id;
+ uint32_t flags;
+};
+
+struct genl_ctrl_ops {
+ uint32_t num_ops;
+ struct genl_ctrl_op **ops;
+};
+
+#define _OUT(_field) offsetof(struct genl_ctrl_op, _field)
+static struct snl_attr_parser _nla_p_getops[] = {
+ { .type = CTRL_ATTR_OP_ID, .off = _OUT(id), .cb = snl_attr_get_uint32},
+ { .type = CTRL_ATTR_OP_FLAGS, .off = _OUT(flags), .cb = snl_attr_get_uint32 },
+};
+#undef _OUT
+SNL_DECLARE_ATTR_PARSER_EXT(genl_ctrl_op_parser,
+ sizeof(struct genl_ctrl_op),
+ _nla_p_getops, NULL);
+
+struct genl_family {
+ uint16_t id;
+ char *name;
+ uint32_t version;
+ uint32_t hdrsize;
+ uint32_t max_attr;
+ struct snl_genl_ctrl_mcast_groups mcast_groups;
+ struct genl_ctrl_ops ops;
+};
+
+#define _OUT(_field) offsetof(struct genl_family, _field)
+static struct snl_attr_parser _nla_p_getfamily[] = {
+ { .type = CTRL_ATTR_FAMILY_ID , .off = _OUT(id), .cb = snl_attr_get_uint16 },
+ { .type = CTRL_ATTR_FAMILY_NAME, .off = _OUT(name), .cb = snl_attr_get_string },
+ { .type = CTRL_ATTR_VERSION, .off = _OUT(version), .cb = snl_attr_get_uint32 },
+ { .type = CTRL_ATTR_VERSION, .off = _OUT(hdrsize), .cb = snl_attr_get_uint32 },
+ { .type = CTRL_ATTR_MAXATTR, .off = _OUT(max_attr), .cb = snl_attr_get_uint32 },
+ {
+ .type = CTRL_ATTR_OPS,
+ .off = _OUT(ops),
+ .cb = snl_attr_get_parray,
+ .arg = &genl_ctrl_op_parser,
+ },
+ {
+ .type = CTRL_ATTR_MCAST_GROUPS,
+ .off = _OUT(mcast_groups),
+ .cb = snl_attr_get_parray,
+ .arg = &_genl_ctrl_mc_parser,
+ },
+};
+#undef _OUT
+SNL_DECLARE_GENL_PARSER(genl_family_parser, _nla_p_getfamily);
+
+static struct op_capability {
+ uint32_t flag;
+ const char *str;
+} op_caps[] = {
+ { GENL_ADMIN_PERM, "requires admin permission" },
+ { GENL_CMD_CAP_DO, "can modify" },
+ { GENL_CMD_CAP_DUMP, "can get/dump" },
+ { GENL_CMD_CAP_HASPOL, "has policy" },
+};
+
+static void
+dump_operations(struct genl_ctrl_ops *ops)
+{
+ if (ops->num_ops == 0)
+ return;
+ printf("\tsupported operations: \n");
+ for (uint32_t i = 0; i < ops->num_ops; i++) {
+ printf("\t - ID: %#02x, Capabilities: %#02x (",
+ ops->ops[i]->id,
+ ops->ops[i]->flags);
+ for (size_t j = 0; j < nitems(op_caps); j++)
+ if ((ops->ops[i]->flags & op_caps[j].flag) == op_caps[j].flag)
+ printf("%s; ", op_caps[j].str);
+ printf("\b\b)\n");
+ }
+}
+
+static void
+dump_mcast_groups( struct snl_genl_ctrl_mcast_groups *mcast_groups)
+{
+ if (mcast_groups->num_groups == 0)
+ return;
+ printf("\tmulticast groups: \n");
+ for (uint32_t i = 0; i < mcast_groups->num_groups; i++)
+ printf("\t - ID: %#02x, Name: %s\n",
+ mcast_groups->groups[i]->mcast_grp_id,
+ mcast_groups->groups[i]->mcast_grp_name);
+}
+
+
+static void
+dump_family(struct genl_family *family)
+{
+ printf("Name: %s\n\tID: %#02hx, Version: %#02x, "
+ "header size: %d, max attributes: %d\n",
+ family->name, family->id, family->version,
+ family->hdrsize, family->max_attr);
+ dump_operations(&family->ops);
+ dump_mcast_groups(&family->mcast_groups);
+}
+
+int
+main(int argc, char **argv __unused)
+{
+ struct snl_state ss;
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
+ struct snl_errmsg_data e = {};
+ uint32_t seq_id;
+
+ if (argc > 1)
+ errx(EXIT_FAILURE, "usage: genl does not accept any argument");
+ if (modfind("netlink") == -1)
+ err(EXIT_FAILURE, "require netlink module to be loaded");
+
+ if (!snl_init(&ss, NETLINK_GENERIC))
+ err(EXIT_FAILURE, "snl_init()");
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, GENL_ID_CTRL, CTRL_CMD_GETFAMILY);
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ err(EXIT_FAILURE, "snl_finalize_msg");
+ seq_id = hdr->nlmsg_seq;
+ if (!snl_send_message(&ss, hdr))
+ err(EXIT_FAILURE, "snl_send_message");
+
+ while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) {
+ if (e.error != 0) {
+ err(EXIT_FAILURE, "Error reading generic netlink");
+ }
+ struct genl_family family = {};
+ if (snl_parse_nlmsg(&ss, hdr, &genl_family_parser, &family))
+ dump_family(&family);
+ }
+
+ return (EXIT_SUCCESS);
+}