Page MenuHomeFreeBSD

D39269.diff
No OneTemporary

D39269.diff

diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4424,10 +4424,12 @@
netipsec/xform_tcp.c optional ipsec inet tcp_signature | \
ipsec inet6 tcp_signature | ipsec_support inet tcp_signature | \
ipsec_support inet6 tcp_signature
+netlink/netlink_generic_kpi.c standard
+netlink/netlink_glue.c standard
+netlink/netlink_message_parser.c standard
netlink/netlink_domain.c optional netlink
netlink/netlink_generic.c optional netlink
netlink/netlink_io.c optional netlink
-netlink/netlink_message_parser.c optional netlink
netlink/netlink_message_writer.c optional netlink
netlink/netlink_module.c optional netlink
netlink/netlink_route.c optional netlink
diff --git a/sys/conf/options b/sys/conf/options
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -463,7 +463,7 @@
MBUF_STRESS_TEST
MROUTING opt_mrouting.h
NFSLOCKD
-NETLINK
+NETLINK opt_netlink.h
PF_DEFAULT_TO_DROP opt_pf.h
ROUTE_MPATH opt_route.h
ROUTETABLES opt_route.h
diff --git a/sys/modules/carp/Makefile b/sys/modules/carp/Makefile
--- a/sys/modules/carp/Makefile
+++ b/sys/modules/carp/Makefile
@@ -6,6 +6,6 @@
KMOD= carp
SRCS= ip_carp.c sha1.c
SRCS+= device_if.h bus_if.h vnode_if.h
-SRCS+= opt_carp.h opt_bpf.h opt_inet.h opt_inet6.h opt_ofed.h
+SRCS+= opt_carp.h opt_bpf.h opt_inet.h opt_inet6.h opt_ofed.h opt_netlink.h
.include <bsd.kmod.mk>
diff --git a/sys/modules/netlink/Makefile b/sys/modules/netlink/Makefile
--- a/sys/modules/netlink/Makefile
+++ b/sys/modules/netlink/Makefile
@@ -2,10 +2,12 @@
KMOD= netlink
SRCS = netlink_module.c netlink_domain.c netlink_io.c \
- netlink_message_parser.c netlink_message_writer.c netlink_generic.c \
+ netlink_message_writer.c netlink_generic.c \
netlink_route.c route/iface.c route/iface_drivers.c route/neigh.c \
route/nexthop.c route/rt.c
-SRCS+= opt_inet.h opt_inet6.h opt_route.h
+SRCS+= opt_inet.h opt_inet6.h opt_route.h opt_netlink.h
+
+CFLAGS+= -DNETLINK_MODULE
EXPORT_SYMS=
EXPORT_SYMS+= nlmsg_get_chain_writer
diff --git a/sys/net/route.c b/sys/net/route.c
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -703,22 +703,3 @@
netlink_callback_p->ifmsg_f(ifp, if_flags_mask);
}
-/* Netlink-related callbacks needed to glue rtsock, netlink and linuxolator */
-static void
-ignore_route_event(uint32_t fibnum, const struct rib_cmd_info *rc)
-{
-}
-
-static void
-ignore_ifmsg_event(struct ifnet *ifp, int if_flags_mask)
-{
-}
-
-static struct rtbridge ignore_cb = {
- .route_f = ignore_route_event,
- .ifmsg_f = ignore_ifmsg_event,
-};
-
-void *linux_netlink_p = NULL; /* Callback pointer for Linux translator functions */
-struct rtbridge *rtsock_callback_p = &ignore_cb;
-struct rtbridge *netlink_callback_p = &ignore_cb;
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -28,6 +28,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/sys/netlink/netlink_ctl.h b/sys/netlink/netlink_ctl.h
--- a/sys/netlink/netlink_ctl.h
+++ b/sys/netlink/netlink_ctl.h
@@ -33,6 +33,7 @@
* This file provides headers for the public KPI of the netlink
* subsystem
*/
+#include <sys/_eventhandler.h>
MALLOC_DECLARE(M_NETLINK);
@@ -81,6 +82,7 @@
bool nl_has_listeners(int netlink_family, uint32_t groups_mask);
bool nlp_has_priv(struct nlpcb *nlp, int priv);
struct ucred *nlp_get_cred(struct nlpcb *nlp);
+uint32_t nlp_get_pid(const struct nlpcb *nlp);
bool nlp_unconstrained_vnet(const struct nlpcb *nlp);
/* netlink_generic.c */
@@ -99,8 +101,12 @@
int count);
uint32_t genl_register_group(const char *family_name, const char *group_name);
-/* Debug */
-uint32_t nlp_get_pid(const struct nlpcb *nlp);
+struct genl_family;
+const char *genl_get_family_name(const struct genl_family *gf);
+uint32_t genl_get_family_id(const struct genl_family *gf);
+
+typedef void (*genl_family_event_handler_t)(void *arg, const struct genl_family *gf, int action);
+EVENTHANDLER_DECLARE(genl_family_event, genl_family_event_handler_t);
#endif
#endif
diff --git a/sys/netlink/netlink_domain.c b/sys/netlink/netlink_domain.c
--- a/sys/netlink/netlink_domain.c
+++ b/sys/netlink/netlink_domain.c
@@ -84,12 +84,6 @@
sysctl_handle_nl_maxsockbuf, "LU",
"Maximum Netlink socket buffer size");
-uint32_t
-nlp_get_pid(const struct nlpcb *nlp)
-{
- return (nlp->nl_process_id);
-}
-
/*
* Looks up a nlpcb struct based on the @portid. Need to claim nlsock_mtx.
* Returns nlpcb pointer if present else NULL
@@ -211,24 +205,6 @@
return (V_nl_ctl != NULL);
}
-bool
-nlp_has_priv(struct nlpcb *nlp, int priv)
-{
- return (priv_check_cred(nlp->nl_cred, priv) == 0);
-}
-
-bool
-nlp_unconstrained_vnet(const struct nlpcb *nlp)
-{
- return (nlp->nl_unconstrained_vnet);
-}
-
-struct ucred *
-nlp_get_cred(struct nlpcb *nlp)
-{
- return (nlp->nl_cred);
-}
-
static uint32_t
nl_find_port(void)
{
diff --git a/sys/netlink/netlink_generic.c b/sys/netlink/netlink_generic.c
--- a/sys/netlink/netlink_generic.c
+++ b/sys/netlink/netlink_generic.c
@@ -25,11 +25,14 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/ck.h>
#include <sys/epoch.h>
+#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/jail.h>
#include <sys/lock.h>
@@ -41,242 +44,15 @@
#include <netlink/netlink.h>
#include <netlink/netlink_ctl.h>
#include <netlink/netlink_generic.h>
+#include <netlink/netlink_var.h>
#define DEBUG_MOD_NAME nl_generic
#define DEBUG_MAX_LEVEL LOG_DEBUG3
#include <netlink/netlink_debug.h>
_DECLARE_DEBUG(LOG_DEBUG);
-#define CTRL_FAMILY_NAME "nlctrl"
-
-#define MAX_FAMILIES 20
-#define MAX_GROUPS 64
-
-#define MIN_GROUP_NUM 48
-
-static struct sx sx_lock;
-
-#define GENL_LOCK_INIT() sx_init(&sx_lock, "genetlink lock")
-#define GENL_LOCK_DESTROY() sx_destroy(&sx_lock)
-#define GENL_LOCK() sx_xlock(&sx_lock)
-#define GENL_UNLOCK() sx_xunlock(&sx_lock)
-
-struct genl_family {
- const char *family_name;
- uint16_t family_hdrsize;
- uint16_t family_id;
- uint16_t family_version;
- uint16_t family_attr_max;
- uint16_t family_cmd_size;
- uint16_t family_num_groups;
- struct genl_cmd *family_cmds;
-};
-
-static struct genl_family families[MAX_FAMILIES];
-
-
-struct genl_group {
- struct genl_family *group_family;
- const char *group_name;
-};
-static struct genl_group groups[MAX_GROUPS];
-
-
static int dump_family(struct nlmsghdr *hdr, struct genlmsghdr *ghdr,
const struct genl_family *gf, struct nl_writer *nw);
-static void nlctrl_notify(const struct genl_family *gf, int action);
-
-static struct genl_family *
-find_family(const char *family_name)
-{
- for (int i = 0; i < MAX_FAMILIES; i++) {
- struct genl_family *gf = &families[i];
- if (gf->family_name != NULL && !strcmp(gf->family_name, family_name))
- return (gf);
- }
-
- return (NULL);
-}
-
-static struct genl_family *
-find_empty_family_id(const char *family_name)
-{
- struct genl_family *gf = NULL;
-
- if (!strcmp(family_name, CTRL_FAMILY_NAME)) {
- gf = &families[0];
- gf->family_id = GENL_MIN_ID;
- } else {
- /* Index 0 is reserved for the control family */
- for (int i = 1; i < MAX_FAMILIES; i++) {
- struct genl_family *gf = &families[i];
- if (gf->family_name == NULL) {
- gf->family_id = GENL_MIN_ID + i;
- break;
- }
- }
- }
-
- return (gf);
-}
-
-uint32_t
-genl_register_family(const char *family_name, size_t hdrsize, int family_version,
- int max_attr_idx)
-{
- uint32_t family_id = 0;
-
- MPASS(family_name != NULL);
- if (find_family(family_name) != NULL)
- return (0);
-
- GENL_LOCK();
-
- struct genl_family *gf = find_empty_family_id(family_name);
- MPASS(gf != NULL);
-
- gf->family_name = family_name;
- gf->family_version = family_version;
- gf->family_hdrsize = hdrsize;
- gf->family_attr_max = max_attr_idx;
- NL_LOG(LOG_DEBUG2, "Registered family %s id %d", gf->family_name, gf->family_id);
- family_id = gf->family_id;
- nlctrl_notify(gf, CTRL_CMD_NEWFAMILY);
-
- GENL_UNLOCK();
-
- return (family_id);
-}
-
-static void
-free_family(struct genl_family *gf)
-{
- if (gf->family_cmds != NULL)
- free(gf->family_cmds, M_NETLINK);
-}
-
-/*
- * unregister groups of a given family
- */
-static void
-unregister_groups(const struct genl_family *gf)
-{
-
- for (int i = 0; i < MAX_GROUPS; i++) {
- struct genl_group *gg = &groups[i];
- if (gg->group_family == gf && gg->group_name != NULL) {
- gg->group_family = NULL;
- gg->group_name = NULL;
- }
- }
-}
-
-/*
- * Can sleep, I guess
- */
-bool
-genl_unregister_family(const char *family_name)
-{
- bool found = false;
-
- GENL_LOCK();
- struct genl_family *gf = find_family(family_name);
-
- if (gf != NULL) {
- nlctrl_notify(gf, CTRL_CMD_DELFAMILY);
- found = true;
- unregister_groups(gf);
- /* TODO: zero pointer first */
- free_family(gf);
- bzero(gf, sizeof(*gf));
- }
- GENL_UNLOCK();
-
- return (found);
-}
-
-bool
-genl_register_cmds(const char *family_name, const struct genl_cmd *cmds, int count)
-{
- GENL_LOCK();
- struct genl_family *gf = find_family(family_name);
- if (gf == NULL) {
- GENL_UNLOCK();
- return (false);
- }
-
- int cmd_size = gf->family_cmd_size;
-
- for (int i = 0; i < count; i++) {
- MPASS(cmds[i].cmd_cb != NULL);
- if (cmds[i].cmd_num >= cmd_size)
- cmd_size = cmds[i].cmd_num + 1;
- }
-
- if (cmd_size > gf->family_cmd_size) {
- /* need to realloc */
- size_t sz = cmd_size * sizeof(struct genl_cmd);
- void *data = malloc(sz, M_NETLINK, M_WAITOK | M_ZERO);
-
- memcpy(data, gf->family_cmds, gf->family_cmd_size * sizeof(struct genl_cmd));
- void *old_data = gf->family_cmds;
- gf->family_cmds = data;
- gf->family_cmd_size = cmd_size;
- free(old_data, M_NETLINK);
- }
-
- for (int i = 0; i < count; i++) {
- const struct genl_cmd *cmd = &cmds[i];
- MPASS(gf->family_cmds[cmd->cmd_num].cmd_cb == NULL);
- gf->family_cmds[cmd->cmd_num] = cmds[i];
- NL_LOG(LOG_DEBUG2, "Adding cmd %s(%d) to family %s",
- cmd->cmd_name, cmd->cmd_num, gf->family_name);
- }
- GENL_UNLOCK();
- return (true);
-}
-
-static struct genl_group *
-find_group(const struct genl_family *gf, const char *group_name)
-{
- for (int i = 0; i < MAX_GROUPS; i++) {
- struct genl_group *gg = &groups[i];
- if (gg->group_family == gf && !strcmp(gg->group_name, group_name))
- return (gg);
- }
- return (NULL);
-}
-
-uint32_t
-genl_register_group(const char *family_name, const char *group_name)
-{
- uint32_t group_id = 0;
-
- MPASS(family_name != NULL);
- MPASS(group_name != NULL);
-
- GENL_LOCK();
- struct genl_family *gf = find_family(family_name);
-
- if (gf == NULL || find_group(gf, group_name) != NULL) {
- GENL_UNLOCK();
- return (0);
- }
-
- for (int i = 0; i < MAX_GROUPS; i++) {
- struct genl_group *gg = &groups[i];
- if (gg->group_family == NULL) {
- gf->family_num_groups++;
- gg->group_family = gf;
- gg->group_name = group_name;
- group_id = i + MIN_GROUP_NUM;
- break;
- }
- }
- GENL_UNLOCK();
-
- return (group_id);
-}
/*
* Handler called by netlink subsystem when matching netlink message is received
@@ -285,11 +61,12 @@
genl_handle_message(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct nlpcb *nlp = npt->nlp;
+ struct genl_family *gf = NULL;
int error = 0;
int family_id = (int)hdr->nlmsg_type - GENL_MIN_ID;
- if (__predict_false(family_id < 0 || family_id >= MAX_FAMILIES)) {
+ if (__predict_false(family_id < 0 || (gf = genl_get_family(family_id)) == NULL)) {
NLP_LOG(LOG_DEBUG, nlp, "invalid message type: %d", hdr->nlmsg_type);
return (ENOTSUP);
}
@@ -299,8 +76,6 @@
return (EINVAL);
}
- struct genl_family *gf = &families[family_id];
-
struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
if (ghdr->cmd >= gf->family_cmd_size || gf->family_cmds[ghdr->cmd].cmd_cb == NULL) {
@@ -375,8 +150,8 @@
if (off == 0)
goto enomem;
for (int i = 0, cnt = 0; i < MAX_GROUPS; i++) {
- struct genl_group *gg = &groups[i];
- if (gg->group_family != gf)
+ struct genl_group *gg = genl_get_group(i);
+ if (gg == NULL || gg->group_family != gf)
continue;
int cmd_off = nlattr_add_nested(nw, ++cnt);
@@ -398,6 +173,8 @@
/* Declare ourself as a user */
+static void nlctrl_notify(void *arg, const struct genl_family *gf, int action);
+static eventhandler_tag family_event_tag;
static uint32_t ctrl_family_id;
static uint32_t ctrl_group_id;
@@ -451,8 +228,8 @@
if (attrs.family_id != 0 || attrs.family_name != NULL) {
/* Resolve request */
for (int i = 0; i < MAX_FAMILIES; i++) {
- struct genl_family *gf = &families[i];
- if (match_family(gf, &attrs)) {
+ struct genl_family *gf = genl_get_family(i);
+ if (gf != NULL && match_family(gf, &attrs)) {
error = dump_family(hdr, &ghdr, gf, npt->nw);
return (error);
}
@@ -462,8 +239,8 @@
hdr->nlmsg_flags = hdr->nlmsg_flags | NLM_F_MULTI;
for (int i = 0; i < MAX_FAMILIES; i++) {
- struct genl_family *gf = &families[i];
- if (match_family(gf, &attrs)) {
+ struct genl_family *gf = genl_get_family(i);
+ if (gf != NULL && match_family(gf, &attrs)) {
error = dump_family(hdr, &ghdr, gf, npt->nw);
if (error != 0)
break;
@@ -479,7 +256,7 @@
}
static void
-nlctrl_notify(const struct genl_family *gf, int cmd)
+nlctrl_notify(void *arg __unused, const struct genl_family *gf, int cmd)
{
struct nlmsghdr hdr = {.nlmsg_type = NETLINK_GENERIC };
struct genlmsghdr ghdr = { .cmd = cmd };
@@ -502,37 +279,26 @@
},
};
-static void
-genl_nlctrl_init(void)
-{
- ctrl_family_id = genl_register_family(CTRL_FAMILY_NAME, 0, 2, CTRL_ATTR_MAX);
- genl_register_cmds(CTRL_FAMILY_NAME, nlctrl_cmds, NL_ARRAY_LEN(nlctrl_cmds));
- ctrl_group_id = genl_register_group(CTRL_FAMILY_NAME, "notify");
-}
-
-static void
-genl_nlctrl_destroy(void)
-{
- genl_unregister_family(CTRL_FAMILY_NAME);
-}
-
static const struct nlhdr_parser *all_parsers[] = { &genl_parser };
static void
-genl_load(void *u __unused)
+genl_load_all(void *u __unused)
{
- GENL_LOCK_INIT();
NL_VERIFY_PARSERS(all_parsers);
+ ctrl_family_id = genl_register_family(CTRL_FAMILY_NAME, 0, 2, CTRL_ATTR_MAX);
+ genl_register_cmds(CTRL_FAMILY_NAME, nlctrl_cmds, NL_ARRAY_LEN(nlctrl_cmds));
+ ctrl_group_id = genl_register_group(CTRL_FAMILY_NAME, "notify");
+ family_event_tag = EVENTHANDLER_REGISTER(genl_family_event, nlctrl_notify, NULL,
+ EVENTHANDLER_PRI_ANY);
netlink_register_proto(NETLINK_GENERIC, "NETLINK_GENERIC", genl_handle_message);
- genl_nlctrl_init();
}
-SYSINIT(genl_load, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, genl_load, NULL);
+SYSINIT(genl_load_all, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, genl_load_all, NULL);
static void
genl_unload(void *u __unused)
{
- genl_nlctrl_destroy();
- GENL_LOCK_DESTROY();
+ EVENTHANDLER_DEREGISTER(genl_family_event, family_event_tag);
+ genl_unregister_family(CTRL_FAMILY_NAME);
NET_EPOCH_WAIT();
}
SYSUNINIT(genl_unload, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, genl_unload, NULL);
diff --git a/sys/netlink/netlink_generic_kpi.c b/sys/netlink/netlink_generic_kpi.c
new file mode 100644
--- /dev/null
+++ b/sys/netlink/netlink_generic_kpi.c
@@ -0,0 +1,279 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/ck.h>
+#include <sys/epoch.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/sx.h>
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_ctl.h>
+#include <netlink/netlink_generic.h>
+#include <netlink/netlink_var.h>
+
+#define DEBUG_MOD_NAME nl_generic_kpi
+#define DEBUG_MAX_LEVEL LOG_DEBUG3
+#include <netlink/netlink_debug.h>
+_DECLARE_DEBUG(LOG_DEBUG3);
+
+
+/*
+ * NETLINK_GENERIC families/groups registration logic
+ */
+
+#define GENL_LOCK() sx_xlock(&sx_lock)
+#define GENL_UNLOCK() sx_xunlock(&sx_lock)
+static struct sx sx_lock;
+SX_SYSINIT(genl_lock, &sx_lock, "genetlink lock");
+
+static struct genl_family families[MAX_FAMILIES];
+static struct genl_group groups[MAX_GROUPS];
+
+static struct genl_family *
+find_family(const char *family_name)
+{
+ for (int i = 0; i < MAX_FAMILIES; i++) {
+ struct genl_family *gf = &families[i];
+ if (gf->family_name != NULL && !strcmp(gf->family_name, family_name))
+ return (gf);
+ }
+
+ return (NULL);
+}
+
+static struct genl_family *
+find_empty_family_id(const char *family_name)
+{
+ struct genl_family *gf = NULL;
+
+ if (!strcmp(family_name, CTRL_FAMILY_NAME)) {
+ gf = &families[0];
+ gf->family_id = GENL_MIN_ID;
+ } else {
+ /* Index 0 is reserved for the control family */
+ for (int i = 1; i < MAX_FAMILIES; i++) {
+ gf = &families[i];
+ if (gf->family_name == NULL) {
+ gf->family_id = GENL_MIN_ID + i;
+ break;
+ }
+ }
+ }
+
+ return (gf);
+}
+
+uint32_t
+genl_register_family(const char *family_name, size_t hdrsize, int family_version,
+ int max_attr_idx)
+{
+ uint32_t family_id = 0;
+
+ MPASS(family_name != NULL);
+ if (find_family(family_name) != NULL)
+ return (0);
+
+ GENL_LOCK();
+
+ struct genl_family *gf = find_empty_family_id(family_name);
+ MPASS(gf != NULL);
+
+ gf->family_name = family_name;
+ gf->family_version = family_version;
+ gf->family_hdrsize = hdrsize;
+ gf->family_attr_max = max_attr_idx;
+ NL_LOG(LOG_DEBUG2, "Registered family %s id %d", gf->family_name, gf->family_id);
+ family_id = gf->family_id;
+ EVENTHANDLER_INVOKE(genl_family_event, gf, CTRL_CMD_NEWFAMILY);
+
+ GENL_UNLOCK();
+
+ return (family_id);
+}
+
+static void
+free_family(struct genl_family *gf)
+{
+ if (gf->family_cmds != NULL)
+ free(gf->family_cmds, M_NETLINK);
+}
+
+/*
+ * unregister groups of a given family
+ */
+static void
+unregister_groups(const struct genl_family *gf)
+{
+
+ for (int i = 0; i < MAX_GROUPS; i++) {
+ struct genl_group *gg = &groups[i];
+ if (gg->group_family == gf && gg->group_name != NULL) {
+ gg->group_family = NULL;
+ gg->group_name = NULL;
+ }
+ }
+}
+
+/*
+ * Can sleep, I guess
+ */
+bool
+genl_unregister_family(const char *family_name)
+{
+ bool found = false;
+
+ GENL_LOCK();
+ struct genl_family *gf = find_family(family_name);
+
+ if (gf != NULL) {
+ EVENTHANDLER_INVOKE(genl_family_event, gf, CTRL_CMD_DELFAMILY);
+ found = true;
+ unregister_groups(gf);
+ /* TODO: zero pointer first */
+ free_family(gf);
+ bzero(gf, sizeof(*gf));
+ }
+ GENL_UNLOCK();
+
+ return (found);
+}
+
+bool
+genl_register_cmds(const char *family_name, const struct genl_cmd *cmds, int count)
+{
+ GENL_LOCK();
+ struct genl_family *gf = find_family(family_name);
+ if (gf == NULL) {
+ GENL_UNLOCK();
+ return (false);
+ }
+
+ int cmd_size = gf->family_cmd_size;
+
+ for (int i = 0; i < count; i++) {
+ MPASS(cmds[i].cmd_cb != NULL);
+ if (cmds[i].cmd_num >= cmd_size)
+ cmd_size = cmds[i].cmd_num + 1;
+ }
+
+ if (cmd_size > gf->family_cmd_size) {
+ /* need to realloc */
+ size_t sz = cmd_size * sizeof(struct genl_cmd);
+ void *data = malloc(sz, M_NETLINK, M_WAITOK | M_ZERO);
+
+ memcpy(data, gf->family_cmds, gf->family_cmd_size * sizeof(struct genl_cmd));
+ void *old_data = gf->family_cmds;
+ gf->family_cmds = data;
+ gf->family_cmd_size = cmd_size;
+ free(old_data, M_NETLINK);
+ }
+
+ for (int i = 0; i < count; i++) {
+ const struct genl_cmd *cmd = &cmds[i];
+ MPASS(gf->family_cmds[cmd->cmd_num].cmd_cb == NULL);
+ gf->family_cmds[cmd->cmd_num] = cmds[i];
+ NL_LOG(LOG_DEBUG2, "Adding cmd %s(%d) to family %s",
+ cmd->cmd_name, cmd->cmd_num, gf->family_name);
+ }
+ GENL_UNLOCK();
+ return (true);
+}
+
+static struct genl_group *
+find_group(const struct genl_family *gf, const char *group_name)
+{
+ for (int i = 0; i < MAX_GROUPS; i++) {
+ struct genl_group *gg = &groups[i];
+ if (gg->group_family == gf && !strcmp(gg->group_name, group_name))
+ return (gg);
+ }
+ return (NULL);
+}
+
+uint32_t
+genl_register_group(const char *family_name, const char *group_name)
+{
+ uint32_t group_id = 0;
+
+ MPASS(family_name != NULL);
+ MPASS(group_name != NULL);
+
+ GENL_LOCK();
+ struct genl_family *gf = find_family(family_name);
+
+ if (gf == NULL || find_group(gf, group_name) != NULL) {
+ GENL_UNLOCK();
+ return (0);
+ }
+
+ for (int i = 0; i < MAX_GROUPS; i++) {
+ struct genl_group *gg = &groups[i];
+ if (gg->group_family == NULL) {
+ gf->family_num_groups++;
+ gg->group_family = gf;
+ gg->group_name = group_name;
+ group_id = i + MIN_GROUP_NUM;
+ break;
+ }
+ }
+ GENL_UNLOCK();
+
+ return (group_id);
+}
+
+/* accessors */
+struct genl_family *
+genl_get_family(uint32_t family_id)
+{
+ return ((family_id < MAX_FAMILIES) ? &families[family_id] : NULL);
+}
+
+const char *
+genl_get_family_name(const struct genl_family *gf)
+{
+ return (gf->family_name);
+}
+
+uint32_t
+genl_get_family_id(const struct genl_family *gf)
+{
+ return (gf->family_id);
+}
+
+struct genl_group *
+genl_get_group(uint32_t group_id)
+{
+ return ((group_id < MAX_GROUPS) ? &groups[group_id] : NULL);
+}
+
diff --git a/sys/netlink/netlink_io.c b/sys/netlink/netlink_io.c
--- a/sys/netlink/netlink_io.c
+++ b/sys/netlink/netlink_io.c
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
diff --git a/sys/netlink/netlink_message_writer.h b/sys/netlink/netlink_message_writer.h
--- a/sys/netlink/netlink_message_writer.h
+++ b/sys/netlink/netlink_message_writer.h
@@ -68,6 +68,7 @@
#define NS_WRITER_TYPE_BUF 1
#define NS_WRITER_TYPE_LBUF 2
#define NS_WRITER_TYPE_MBUFC 3
+#define NS_WRITER_TYPE_STUB 4
#define NLMSG_SMALL 128
@@ -76,6 +77,89 @@
/* Message and attribute writing */
struct nlpcb;
+
+#if defined(NETLINK) || defined(NETLINK_MODULE)
+/* Provide optimized calls to the functions inside the same linking unit */
+
+bool _nlmsg_get_unicast_writer(struct nl_writer *nw, int expected_size, struct nlpcb *nlp);
+bool _nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id);
+bool _nlmsg_get_chain_writer(struct nl_writer *nw, int expected_size, struct mbuf **pm);
+bool _nlmsg_flush(struct nl_writer *nw);
+void _nlmsg_ignore_limit(struct nl_writer *nw);
+
+bool _nlmsg_refill_buffer(struct nl_writer *nw, int required_size);
+bool _nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
+ uint16_t flags, uint32_t len);
+bool _nlmsg_end(struct nl_writer *nw);
+void _nlmsg_abort(struct nl_writer *nw);
+
+bool _nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr);
+
+
+static inline bool
+nlmsg_get_unicast_writer(struct nl_writer *nw, int expected_size, struct nlpcb *nlp)
+{
+ return (_nlmsg_get_unicast_writer(nw, expected_size, nlp));
+}
+
+static inline bool
+nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id)
+{
+ return (_nlmsg_get_group_writer(nw, expected_size, proto, group_id));
+}
+
+static inline bool
+nlmsg_get_chain_writer(struct nl_writer *nw, int expected_size, struct mbuf **pm)
+{
+ return (_nlmsg_get_chain_writer(nw, expected_size, pm));
+}
+
+static inline bool
+nlmsg_flush(struct nl_writer *nw)
+{
+ return (_nlmsg_flush(nw));
+}
+
+static inline void
+nlmsg_ignore_limit(struct nl_writer *nw)
+{
+ _nlmsg_ignore_limit(nw);
+}
+
+static inline bool
+nlmsg_refill_buffer(struct nl_writer *nw, int required_size)
+{
+ return (_nlmsg_refill_buffer(nw, required_size));
+}
+
+static inline bool
+nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
+ uint16_t flags, uint32_t len)
+{
+ return (_nlmsg_add(nw, portid, seq, type, flags, len));
+}
+
+static inline bool
+nlmsg_end(struct nl_writer *nw)
+{
+ return (_nlmsg_end(nw));
+}
+
+static inline void
+nlmsg_abort(struct nl_writer *nw)
+{
+ return (_nlmsg_abort(nw));
+}
+
+static inline bool
+nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)
+{
+ return (_nlmsg_end_dump(nw, error, hdr));
+}
+
+#else
+/* Provide access to the functions via netlink_glue.c */
+
bool nlmsg_get_unicast_writer(struct nl_writer *nw, int expected_size, struct nlpcb *nlp);
bool nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id);
bool nlmsg_get_chain_writer(struct nl_writer *nw, int expected_size, struct mbuf **pm);
@@ -90,6 +174,8 @@
bool nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr);
+#endif /* defined(NETLINK) || defined(NETLINK_MODULE) */
+
static inline bool
nlmsg_reply(struct nl_writer *nw, const struct nlmsghdr *hdr, int payload_len)
{
diff --git a/sys/netlink/netlink_message_writer.c b/sys/netlink/netlink_message_writer.c
--- a/sys/netlink/netlink_message_writer.c
+++ b/sys/netlink/netlink_message_writer.c
@@ -25,6 +25,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
@@ -434,7 +436,7 @@
}
bool
-nlmsg_get_unicast_writer(struct nl_writer *nw, int size, struct nlpcb *nlp)
+_nlmsg_get_unicast_writer(struct nl_writer *nw, int size, struct nlpcb *nlp)
{
if (!nlmsg_get_buf(nw, size, false, nlp->nl_linux))
return (false);
@@ -445,7 +447,7 @@
}
bool
-nlmsg_get_group_writer(struct nl_writer *nw, int size, int protocol, int group_id)
+_nlmsg_get_group_writer(struct nl_writer *nw, int size, int protocol, int group_id)
{
if (!nlmsg_get_buf(nw, size, false, false))
return (false);
@@ -456,7 +458,7 @@
}
bool
-nlmsg_get_chain_writer(struct nl_writer *nw, int size, struct mbuf **pm)
+_nlmsg_get_chain_writer(struct nl_writer *nw, int size, struct mbuf **pm)
{
if (!nlmsg_get_buf(nw, size, false, false))
return (false);
@@ -469,13 +471,13 @@
}
void
-nlmsg_ignore_limit(struct nl_writer *nw)
+_nlmsg_ignore_limit(struct nl_writer *nw)
{
nw->ignore_limit = true;
}
bool
-nlmsg_flush(struct nl_writer *nw)
+_nlmsg_flush(struct nl_writer *nw)
{
if (__predict_false(nw->hdr != NULL)) {
@@ -503,7 +505,7 @@
* Return true on success.
*/
bool
-nlmsg_refill_buffer(struct nl_writer *nw, int required_len)
+_nlmsg_refill_buffer(struct nl_writer *nw, int required_len)
{
struct nl_writer ns_new = {};
int completed_len, new_len;
@@ -561,7 +563,7 @@
}
bool
-nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
+_nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
uint16_t flags, uint32_t len)
{
struct nlmsghdr *hdr;
@@ -589,7 +591,7 @@
}
bool
-nlmsg_end(struct nl_writer *nw)
+_nlmsg_end(struct nl_writer *nw)
{
MPASS(nw->hdr != NULL);
@@ -609,7 +611,7 @@
}
void
-nlmsg_abort(struct nl_writer *nw)
+_nlmsg_abort(struct nl_writer *nw)
{
if (nw->hdr != NULL) {
nw->offset = (uint32_t)((char *)nw->hdr - nw->data);
@@ -670,7 +672,7 @@
}
bool
-nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)
+_nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)
{
if (!nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, NLMSG_DONE, 0, sizeof(int))) {
NL_LOG(LOG_DEBUG, "Error finalizing table dump");
diff --git a/sys/netlink/netlink_module.c b/sys/netlink/netlink_module.c
--- a/sys/netlink/netlink_module.c
+++ b/sys/netlink/netlink_module.c
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
@@ -44,7 +46,6 @@
#include <machine/atomic.h>
-MALLOC_DEFINE(M_NETLINK, "netlink", "Memory used for netlink packets");
FEATURE(netlink, "Netlink support");
#define DEBUG_MOD_NAME nl_mod
@@ -52,8 +53,6 @@
#include <netlink/netlink_debug.h>
_DECLARE_DEBUG(LOG_DEBUG);
-SYSCTL_NODE(_net, OID_AUTO, netlink, CTLFLAG_RD, 0, "");
-SYSCTL_NODE(_net_netlink, OID_AUTO, debug, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
#define NL_MAX_HANDLERS 20
struct nl_proto_handler _nl_handlers[NL_MAX_HANDLERS];
@@ -175,6 +174,21 @@
return (true);
}
+#if !defined(NETLINK) && defined(NETLINK_MODULE)
+/* Non-stub function provider */
+const static struct nl_function_wrapper nl_module = {
+ .nlmsg_add = _nlmsg_add,
+ .nlmsg_refill_buffer = _nlmsg_refill_buffer,
+ .nlmsg_flush = _nlmsg_flush,
+ .nlmsg_end = _nlmsg_end,
+ .nlmsg_abort = _nlmsg_abort,
+ .nlmsg_get_unicast_writer = _nlmsg_get_unicast_writer,
+ .nlmsg_get_group_writer = _nlmsg_get_group_writer,
+ .nlmsg_get_chain_writer = _nlmsg_get_chain_writer,
+ .nlmsg_end_dump = _nlmsg_end_dump,
+};
+#endif
+
static bool
can_unload(void)
{
@@ -205,6 +219,9 @@
switch (what) {
case MOD_LOAD:
NL_LOG(LOG_DEBUG2, "Loading");
+#if !defined(NETLINK) && defined(NETLINK_MODULE)
+ nl_set_functions(&nl_module);
+#endif
break;
case MOD_UNLOAD:
@@ -212,6 +229,9 @@
if (can_unload()) {
NL_LOG(LOG_WARNING, "unloading");
netlink_unloading = 1;
+#if !defined(NETLINK) && defined(NETLINK_MODULE)
+ nl_set_functions(NULL);
+#endif
} else
ret = EBUSY;
break;
diff --git a/sys/netlink/netlink_var.h b/sys/netlink/netlink_var.h
--- a/sys/netlink/netlink_var.h
+++ b/sys/netlink/netlink_var.h
@@ -90,6 +90,7 @@
#define NLF_STRICT 0x04 /* Perform strict header checks */
SYSCTL_DECL(_net_netlink);
+SYSCTL_DECL(_net_netlink_debug);
struct nl_io {
struct callout callout;
@@ -144,5 +145,48 @@
int nl_receive_async(struct mbuf *m, struct socket *so);
void nl_process_receive_locked(struct nlpcb *nlp);
+/* netlink_generic.c */
+struct genl_family {
+ const char *family_name;
+ uint16_t family_hdrsize;
+ uint16_t family_id;
+ uint16_t family_version;
+ uint16_t family_attr_max;
+ uint16_t family_cmd_size;
+ uint16_t family_num_groups;
+ struct genl_cmd *family_cmds;
+};
+
+struct genl_group {
+ struct genl_family *group_family;
+ const char *group_name;
+};
+
+struct genl_family *genl_get_family(uint32_t family_id);
+struct genl_group *genl_get_group(uint32_t group_id);
+
+#define MAX_FAMILIES 20
+#define MAX_GROUPS 64
+
+#define MIN_GROUP_NUM 48
+
+#define CTRL_FAMILY_NAME "nlctrl"
+
+/* Function map */
+struct nl_function_wrapper {
+ bool (*nlmsg_add)(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
+ uint16_t flags, uint32_t len);
+ bool (*nlmsg_refill_buffer)(struct nl_writer *nw, int required_len);
+ bool (*nlmsg_flush)(struct nl_writer *nw);
+ bool (*nlmsg_end)(struct nl_writer *nw);
+ void (*nlmsg_abort)(struct nl_writer *nw);
+ void (*nlmsg_ignore_limit)(struct nl_writer *nw);
+ bool (*nlmsg_get_unicast_writer)(struct nl_writer *nw, int size, struct nlpcb *nlp);
+ bool (*nlmsg_get_group_writer)(struct nl_writer *nw, int size, int protocol, int group_id);
+ bool (*nlmsg_get_chain_writer)(struct nl_writer *nw, int size, struct mbuf **pm);
+ bool (*nlmsg_end_dump)(struct nl_writer *nw, int error, struct nlmsghdr *hdr);
+};
+void nl_set_functions(const struct nl_function_wrapper *nl);
+
#endif
#endif
diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c
--- a/sys/netlink/route/iface.c
+++ b/sys/netlink/route/iface.c
@@ -25,6 +25,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
diff --git a/sys/netlink/route/neigh.c b/sys/netlink/route/neigh.c
--- a/sys/netlink/route/neigh.c
+++ b/sys/netlink/route/neigh.c
@@ -25,6 +25,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
diff --git a/sys/netlink/route/nexthop.c b/sys/netlink/route/nexthop.c
--- a/sys/netlink/route/nexthop.c
+++ b/sys/netlink/route/nexthop.c
@@ -25,6 +25,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c
--- a/sys/netlink/route/rt.c
+++ b/sys/netlink/route/rt.c
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "opt_netlink.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 4, 1:03 AM (20 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16445707
Default Alt Text
D39269.diff (32 KB)

Event Timeline