netlink: refactor writer initialization KPI

o Allow callers to initialize a writer that will malloc(9) with M_WAITOK.
o Use size_t for expected malloc size.
o Use correct types to initialize a group writer.
o Rename functions into nl_writer_ namespace instead of nlmsg_, cause
  they are working on nl_writer, not on nlmsg.
o Make the KPI responsible to sparsely initialize the writer structure.
o Garbage collect chain writer.  Fixes 17083b94a9.

All current consumers are left as is, however some may benefit from
M_WAITOK allocation as well as supplying a correct expected size.

Reviewed by:		melifaro
Differential Revision:	https://reviews.freebsd.org/D47549
This commit is contained in:
Gleb Smirnoff
2024-12-03 12:04:18 -08:00
parent edf5608bfe
commit a034c0aecc
13 changed files with 76 additions and 79 deletions
-1
View File
@@ -10,7 +10,6 @@ SRCS+= opt_inet.h opt_inet6.h opt_route.h
CFLAGS+= -DNETLINK_MODULE
EXPORT_SYMS=
EXPORT_SYMS+= nlmsg_get_chain_writer
EXPORT_SYMS+= nlmsg_refill_buffer
EXPORT_SYMS+= nlmsg_end
EXPORT_SYMS+= nlmsg_flush
+7 -5
View File
@@ -256,14 +256,16 @@ nlctrl_notify(void *arg __unused, const struct genl_family *gf, int cmd)
{
struct nlmsghdr hdr = {.nlmsg_type = NETLINK_GENERIC };
struct genlmsghdr ghdr = { .cmd = cmd };
struct nl_writer nw = {};
struct nl_writer nw;
if (nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_GENERIC, ctrl_group_id)) {
dump_family(&hdr, &ghdr, gf, &nw);
nlmsg_flush(&nw);
if (!nl_writer_group(&nw, NLMSG_SMALL, NETLINK_GENERIC, ctrl_group_id,
false)) {
NL_LOG(LOG_DEBUG, "error allocating group writer");
return;
}
NL_LOG(LOG_DEBUG, "error allocating group writer");
dump_family(&hdr, &ghdr, gf, &nw);
nlmsg_flush(&nw);
}
static const struct genl_cmd nlctrl_cmds[] = {
+12 -30
View File
@@ -110,28 +110,15 @@ nlp_unconstrained_vnet(const struct nlpcb *nlp)
/* Stub implementations for the loadable functions */
static bool
get_stub_writer(struct nl_writer *nw)
{
bzero(nw, sizeof(*nw));
nw->enomem = true;
return (false);
}
static bool
nlmsg_get_unicast_writer_stub(struct nl_writer *nw, int size, struct nlpcb *nlp)
nl_writer_unicast_stub(struct nl_writer *nw, size_t size, struct nlpcb *nlp,
bool waitok)
{
return (get_stub_writer(nw));
}
static bool
nlmsg_get_group_writer_stub(struct nl_writer *nw, int size, int protocol, int group_id)
{
return (get_stub_writer(nw));
}
static bool
nlmsg_get_chain_writer_stub(struct nl_writer *nw, int size, struct mbuf **pm)
nl_writer_group_stub(struct nl_writer *nw, size_t size, uint16_t protocol,
uint16_t group_id, bool waitok)
{
return (get_stub_writer(nw));
}
@@ -203,9 +190,8 @@ const static struct nl_function_wrapper nl_stub = {
.nlmsg_end = nlmsg_end_stub,
.nlmsg_abort = nlmsg_abort_stub,
.nlmsg_ignore_limit = nlmsg_ignore_limit_stub,
.nlmsg_get_unicast_writer = nlmsg_get_unicast_writer_stub,
.nlmsg_get_group_writer = nlmsg_get_group_writer_stub,
.nlmsg_get_chain_writer = nlmsg_get_chain_writer_stub,
.nl_writer_unicast = nl_writer_unicast_stub,
.nl_writer_group = nl_writer_group_stub,
.nlmsg_end_dump = nlmsg_end_dump_stub,
.nl_modify_ifp_generic = nl_modify_ifp_generic_stub,
.nl_store_ifp_cookie = nl_store_ifp_cookie_stub,
@@ -226,21 +212,17 @@ nl_set_functions(const struct nl_function_wrapper *nl)
/* Function wrappers */
bool
nlmsg_get_unicast_writer(struct nl_writer *nw, int size, struct nlpcb *nlp)
nl_writer_unicast(struct nl_writer *nw, size_t size, struct nlpcb *nlp,
bool waitok)
{
return (_nl->nlmsg_get_unicast_writer(nw, size, nlp));
return (_nl->nl_writer_unicast(nw, size, nlp, waitok));
}
bool
nlmsg_get_group_writer(struct nl_writer *nw, int size, int protocol, int group_id)
nl_writer_group(struct nl_writer *nw, size_t size, uint16_t protocol,
uint16_t group_id, bool waitok)
{
return (_nl->nlmsg_get_group_writer(nw, size, protocol, group_id));
}
bool
nlmsg_get_chain_writer(struct nl_writer *nw, int size, struct mbuf **pm)
{
return (_nl->nlmsg_get_chain_writer(nw, size, pm));
return (_nl->nl_writer_group(nw, size, protocol, group_id, waitok));
}
bool
+2 -2
View File
@@ -317,13 +317,13 @@ npt_clear(struct nl_pstate *npt)
static bool
nl_process_nbuf(struct nl_buf *nb, struct nlpcb *nlp)
{
struct nl_writer nw;
struct nlmsghdr *hdr;
int error;
NL_LOG(LOG_DEBUG3, "RX netlink buf %p on %p", nb, nlp->nl_socket);
struct nl_writer nw = {};
if (!nlmsg_get_unicast_writer(&nw, NLMSG_SMALL, nlp)) {
if (!nl_writer_unicast(&nw, NLMSG_SMALL, nlp, false)) {
NL_LOG(LOG_DEBUG, "error allocating socket writer");
return (true);
}
+15 -9
View File
@@ -73,22 +73,28 @@ nl_send_one(struct nl_writer *nw)
}
bool
_nlmsg_get_unicast_writer(struct nl_writer *nw, int size, struct nlpcb *nlp)
_nl_writer_unicast(struct nl_writer *nw, size_t size, struct nlpcb *nlp,
bool waitok)
{
nw->nlp = nlp;
nw->cb = nl_send_one;
*nw = (struct nl_writer){
.nlp = nlp,
.cb = nl_send_one,
};
return (nlmsg_get_buf(nw, size, false));
return (nlmsg_get_buf(nw, size, waitok));
}
bool
_nlmsg_get_group_writer(struct nl_writer *nw, int size, int protocol, int group_id)
_nl_writer_group(struct nl_writer *nw, size_t size, uint16_t protocol,
uint16_t group_id, bool waitok)
{
nw->group.proto = protocol;
nw->group.id = group_id;
nw->cb = nl_send_group;
*nw = (struct nl_writer){
.group.proto = protocol,
.group.id = group_id,
.cb = nl_send_group,
};
return (nlmsg_get_buf(nw, size, false));
return (nlmsg_get_buf(nw, size, waitok));
}
void
+11 -9
View File
@@ -66,8 +66,8 @@ struct nl_writer {
#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 _nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *nlp, bool);
bool _nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, bool);
bool _nlmsg_flush(struct nl_writer *nw);
void _nlmsg_ignore_limit(struct nl_writer *nw);
@@ -81,15 +81,17 @@ 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)
nl_writer_unicast(struct nl_writer *nw, size_t size, struct nlpcb *nlp,
bool waitok)
{
return (_nlmsg_get_unicast_writer(nw, expected_size, nlp));
return (_nl_writer_unicast(nw, size, nlp, waitok));
}
static inline bool
nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id)
nl_writer_group(struct nl_writer *nw, size_t size, uint16_t proto,
uint16_t group_id, bool waitok)
{
return (_nlmsg_get_group_writer(nw, expected_size, proto, group_id));
return (_nl_writer_group(nw, size, proto, group_id, waitok));
}
static inline bool
@@ -138,9 +140,9 @@ nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *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);
bool nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *, bool waitok);
bool nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t,
bool waitok);
bool nlmsg_flush(struct nl_writer *nw);
void nlmsg_ignore_limit(struct nl_writer *nw);
+2 -2
View File
@@ -179,8 +179,8 @@ const static struct nl_function_wrapper nl_module = {
.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,
.nl_writer_unicast = _nl_writer_unicast,
.nl_writer_group = _nl_writer_group,
.nlmsg_end_dump = _nlmsg_end_dump,
.nl_modify_ifp_generic = _nl_modify_ifp_generic,
.nl_store_ifp_cookie = _nl_store_ifp_cookie,
+3 -2
View File
@@ -80,9 +80,10 @@ static void
sysevent_write(struct sysevent_group *se, const char *subsystem, const char *type,
const char *data)
{
struct nl_writer nw = {};
struct nl_writer nw;
if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_GENERIC, se->id)) {
if (!nl_writer_group(&nw, NLMSG_LARGE, NETLINK_GENERIC, se->id,
false)) {
NL_LOG(LOG_DEBUG, "error allocating group writer");
return;
}
+4 -3
View File
@@ -184,9 +184,10 @@ struct nl_function_wrapper {
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 (*nl_writer_unicast)(struct nl_writer *nw, size_t size,
struct nlpcb *nlp, bool waitok);
bool (*nl_writer_group)(struct nl_writer *nw, size_t size,
uint16_t protocol, uint16_t group_id, bool waitok);
bool (*nlmsg_end_dump)(struct nl_writer *nw, int error, struct nlmsghdr *hdr);
int (*nl_modify_ifp_generic)(struct ifnet *ifp, struct nl_parsed_link *lattrs,
const struct nlattr_bmask *bm, struct nl_pstate *npt);
+6 -5
View File
@@ -1363,7 +1363,7 @@ static void
rtnl_handle_ifaddr(void *arg __unused, struct ifaddr *ifa, int cmd)
{
struct nlmsghdr hdr = {};
struct nl_writer nw = {};
struct nl_writer nw;
uint32_t group = 0;
switch (ifa->ifa_addr->sa_family) {
@@ -1386,7 +1386,7 @@ rtnl_handle_ifaddr(void *arg __unused, struct ifaddr *ifa, int cmd)
if (!nl_has_listeners(NETLINK_ROUTE, group))
return;
if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_ROUTE, group)) {
if (!nl_writer_group(&nw, NLMSG_LARGE, NETLINK_ROUTE, group, false)) {
NL_LOG(LOG_DEBUG, "error allocating group writer");
return;
}
@@ -1401,13 +1401,14 @@ static void
rtnl_handle_ifevent(if_t ifp, int nlmsg_type, int if_flags_mask)
{
struct nlmsghdr hdr = { .nlmsg_type = nlmsg_type };
struct nl_writer nw = {};
struct nl_writer nw;
if (!nl_has_listeners(NETLINK_ROUTE, RTNLGRP_LINK))
return;
if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_ROUTE, RTNLGRP_LINK)) {
NL_LOG(LOG_DEBUG, "error allocating mbuf");
if (!nl_writer_group(&nw, NLMSG_LARGE, NETLINK_ROUTE, RTNLGRP_LINK,
false)) {
NL_LOG(LOG_DEBUG, "error allocating group writer");
return;
}
dump_iface(&nw, ifp, &hdr, if_flags_mask);
+3 -2
View File
@@ -552,6 +552,7 @@ static const struct rtnl_cmd_handler cmd_handlers[] = {
static void
rtnl_lle_event(void *arg __unused, struct llentry *lle, int evt)
{
struct nl_writer nw;
if_t ifp;
int family;
@@ -565,8 +566,8 @@ rtnl_lle_event(void *arg __unused, struct llentry *lle, int evt)
int nlmsgs_type = evt == LLENTRY_RESOLVED ? NL_RTM_NEWNEIGH : NL_RTM_DELNEIGH;
struct nl_writer nw = {};
if (!nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEIGH)) {
if (!nl_writer_group(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEIGH,
false)) {
NL_LOG(LOG_DEBUG, "error allocating group writer");
return;
}
+6 -5
View File
@@ -506,7 +506,7 @@ static int
delete_unhop(struct unhop_ctl *ctl, struct nlmsghdr *hdr, uint32_t uidx)
{
struct user_nhop *unhop_ret, *unhop_base, *unhop_chain;
struct nl_writer nw;
struct user_nhop key = { .un_idx = uidx };
UN_WLOCK(ctl);
@@ -553,8 +553,8 @@ delete_unhop(struct unhop_ctl *ctl, struct nlmsghdr *hdr, uint32_t uidx)
.hdr.nlmsg_type = NL_RTM_DELNEXTHOP,
};
struct nl_writer nw = {};
if (!nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEXTHOP)) {
if (!nl_writer_group(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEXTHOP,
false)) {
NL_LOG(LOG_DEBUG, "error allocating message writer");
return (ENOMEM);
}
@@ -881,6 +881,7 @@ static int
rtnl_handle_newnhop(struct nlmsghdr *hdr, struct nlpcb *nlp,
struct nl_pstate *npt)
{
struct nl_writer nw;
struct user_nhop *unhop;
int error;
@@ -947,8 +948,8 @@ rtnl_handle_newnhop(struct nlmsghdr *hdr, struct nlpcb *nlp,
.hdr.nlmsg_type = NL_RTM_NEWNEXTHOP,
};
struct nl_writer nw = {};
if (!nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEXTHOP)) {
if (!nl_writer_group(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEXTHOP,
false)) {
NL_LOG(LOG_DEBUG, "error allocating message writer");
return (ENOMEM);
}
+5 -4
View File
@@ -350,10 +350,10 @@ static void
report_operation(uint32_t fibnum, struct rib_cmd_info *rc,
struct nlpcb *nlp, struct nlmsghdr *hdr)
{
struct nl_writer nw = {};
struct nl_writer nw;
uint32_t group_id = family_to_group(rt_get_family(rc->rc_rt));
if (nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, group_id)) {
if (nl_writer_group(&nw, NLMSG_SMALL, NETLINK_ROUTE, group_id, false)) {
struct route_nhop_data rnd = {
.rnd_nhop = rc_get_nhop(rc),
.rnd_weight = rc->rc_nh_weight,
@@ -1043,7 +1043,7 @@ rtnl_handle_getroute(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *
void
rtnl_handle_route_event(uint32_t fibnum, const struct rib_cmd_info *rc)
{
struct nl_writer nw = {};
struct nl_writer nw;
int family, nlm_flags = 0;
family = rt_get_family(rc->rc_rt);
@@ -1082,7 +1082,8 @@ rtnl_handle_route_event(uint32_t fibnum, const struct rib_cmd_info *rc)
};
uint32_t group_id = family_to_group(family);
if (!nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, group_id)) {
if (!nl_writer_group(&nw, NLMSG_SMALL, NETLINK_ROUTE, group_id,
false)) {
NL_LOG(LOG_DEBUG, "error allocating event buffer");
return;
}