netlink: add support for dumping kernel nexthops.

MFC after:	2 weeks
This commit is contained in:
Alexander V. Chernikov 2023-04-25 11:12:18 +00:00
parent a2728a9a5b
commit b32cf15d86
2 changed files with 98 additions and 20 deletions

View File

@ -436,11 +436,9 @@ dump_nhgrp(const struct user_nhop *unhop, struct nlmsghdr *hdr,
}
static bool
dump_nhop(const struct user_nhop *unhop, struct nlmsghdr *hdr,
dump_nhop(const struct nhop_object *nh, uint32_t uidx, struct nlmsghdr *hdr,
struct nl_writer *nw)
{
struct nhop_object *nh = unhop->un_nhop_src;
if (!nlmsg_reply(nw, hdr, sizeof(struct nhmsg)))
goto enomem;
@ -448,10 +446,11 @@ dump_nhop(const struct user_nhop *unhop, struct nlmsghdr *hdr,
ENOMEM_IF_NULL(nhm);
nhm->nh_family = nhop_get_neigh_family(nh);
nhm->nh_scope = 0; // XXX: what's that?
nhm->nh_protocol = unhop->un_protocol;
nhm->nh_protocol = nhop_get_origin(nh);
nhm->nh_flags = 0;
nlattr_add_u32(nw, NHA_ID, unhop->un_idx);
if (uidx != 0)
nlattr_add_u32(nw, NHA_ID, uidx);
if (nh->nh_flags & NHF_BLACKHOLE) {
nlattr_add_flag(nw, NHA_BLACKHOLE);
goto done;
@ -475,6 +474,19 @@ dump_nhop(const struct user_nhop *unhop, struct nlmsghdr *hdr,
#endif
}
int off = nlattr_add_nested(nw, NHA_FREEBSD);
if (off != 0) {
nlattr_add_u32(nw, NHAF_AIF, nh->nh_aifp->if_index);
if (uidx == 0) {
nlattr_add_u32(nw, NHAF_KID, nhop_get_idx(nh));
nlattr_add_u32(nw, NHAF_FAMILY, nhop_get_upper_family(nh));
nlattr_add_u32(nw, NHAF_TABLE, nhop_get_fibnum(nh));
}
nlattr_set_len(nw, off);
}
done:
if (nlmsg_end(nw))
return (true);
@ -488,7 +500,7 @@ dump_unhop(const struct user_nhop *unhop, struct nlmsghdr *hdr,
struct nl_writer *nw)
{
if (unhop->un_nhop_src != NULL)
dump_nhop(unhop, hdr, nw);
dump_nhop(unhop->un_nhop_src, unhop->un_idx, hdr, nw);
else
dump_nhgrp(unhop, hdr, nw);
}
@ -670,15 +682,29 @@ struct nl_parsed_nhop {
uint32_t nha_id;
uint8_t nha_blackhole;
uint8_t nha_groups;
uint8_t nhaf_knhops;
uint8_t nhaf_family;
struct ifnet *nha_oif;
struct sockaddr *nha_gw;
struct nlattr *nha_group;
uint8_t nh_family;
uint8_t nh_protocol;
uint32_t nhaf_table;
uint32_t nhaf_kid;
uint32_t nhaf_aif;
};
#define _IN(_field) offsetof(struct nhmsg, _field)
#define _OUT(_field) offsetof(struct nl_parsed_nhop, _field)
static struct nlattr_parser nla_p_nh_fbsd[] = {
{ .type = NHAF_KNHOPS, .off = _OUT(nhaf_knhops), .cb = nlattr_get_flag },
{ .type = NHAF_TABLE, .off = _OUT(nhaf_table), .cb = nlattr_get_uint32 },
{ .type = NHAF_FAMILY, .off = _OUT(nhaf_family), .cb = nlattr_get_uint8 },
{ .type = NHAF_KID, .off = _OUT(nhaf_kid), .cb = nlattr_get_uint32 },
{ .type = NHAF_AIF, .off = _OUT(nhaf_aif), .cb = nlattr_get_uint32 },
};
NL_DECLARE_ATTR_PARSER(nh_fbsd_parser, nla_p_nh_fbsd);
static const struct nlfield_parser nlf_p_nh[] = {
{ .off_in = _IN(nh_family), .off_out = _OUT(nh_family), .cb = nlf_get_u8 },
{ .off_in = _IN(nh_protocol), .off_out = _OUT(nh_protocol), .cb = nlf_get_u8 },
@ -691,6 +717,7 @@ static const struct nlattr_parser nla_p_nh[] = {
{ .type = NHA_OIF, .off = _OUT(nha_oif), .cb = nlattr_get_ifp },
{ .type = NHA_GATEWAY, .off = _OUT(nha_gw), .cb = nlattr_get_ip },
{ .type = NHA_GROUPS, .off = _OUT(nha_groups), .cb = nlattr_get_flag },
{ .type = NHA_FREEBSD, .arg = &nh_fbsd_parser, .cb = nlattr_get_nested },
};
#undef _IN
#undef _OUT
@ -801,6 +828,7 @@ newnhop(struct nl_parsed_nhop *attrs, struct user_nhop *unhop, struct nl_pstate
return (ENOMEM);
}
nhop_set_uidx(nh, attrs->nha_id);
nhop_set_origin(nh, attrs->nh_protocol);
if (attrs->nha_blackhole)
nhop_set_blackhole(nh, NHF_BLACKHOLE);
@ -957,14 +985,10 @@ static int
rtnl_handle_getnhop(struct nlmsghdr *hdr, struct nlpcb *nlp,
struct nl_pstate *npt)
{
struct unhop_ctl *ctl = atomic_load_ptr(&V_un_ctl);
struct user_nhop *unhop;
UN_TRACKER;
int error;
if (__predict_false(ctl == NULL))
return (ESRCH);
struct nl_parsed_nhop attrs = {};
error = nl_parse_nlmsg(hdr, &nhmsg_parser, npt, &attrs);
if (error != 0)
@ -979,8 +1003,13 @@ rtnl_handle_getnhop(struct nlmsghdr *hdr, struct nlpcb *nlp,
};
if (attrs.nha_id != 0) {
struct unhop_ctl *ctl = atomic_load_ptr(&V_un_ctl);
struct user_nhop key = { .un_idx = attrs.nha_id };
if (__predict_false(ctl == NULL))
return (ESRCH);
NL_LOG(LOG_DEBUG2, "searching for uidx %u", attrs.nha_id);
struct user_nhop key= { .un_idx = attrs.nha_id };
UN_RLOCK(ctl);
CHT_SLIST_FIND_BYOBJ(&ctl->un_head, unhop, &key, unhop);
UN_RUNLOCK(ctl);
@ -989,15 +1018,53 @@ rtnl_handle_getnhop(struct nlmsghdr *hdr, struct nlpcb *nlp,
return (ESRCH);
dump_unhop(unhop, &wa.hdr, wa.nw);
return (0);
}
} else if (attrs.nhaf_kid != 0) {
struct nhop_iter iter = {
.fibnum = attrs.nhaf_table,
.family = attrs.nhaf_family,
};
int error = ESRCH;
UN_RLOCK(ctl);
wa.hdr.nlmsg_flags |= NLM_F_MULTI;
CHT_SLIST_FOREACH(&ctl->un_head, unhop, unhop) {
if (UNHOP_IS_MASTER(unhop) && match_unhop(&attrs, unhop))
dump_unhop(unhop, &wa.hdr, wa.nw);
} CHT_SLIST_FOREACH_END;
UN_RUNLOCK(ctl);
NL_LOG(LOG_DEBUG2, "START table %u family %d", attrs.nhaf_table, attrs.nhaf_family);
for (struct nhop_object *nh = nhops_iter_start(&iter); nh;
nh = nhops_iter_next(&iter)) {
NL_LOG(LOG_DEBUG3, "get %u", nhop_get_idx(nh));
if (nhop_get_idx(nh) == attrs.nhaf_kid) {
dump_nhop(nh, 0, &wa.hdr, wa.nw);
error = 0;
break;
}
}
nhops_iter_stop(&iter);
return (error);
} else if (attrs.nhaf_knhops) {
struct nhop_iter iter = {
.fibnum = attrs.nhaf_table,
.family = attrs.nhaf_family,
};
NL_LOG(LOG_DEBUG2, "DUMP table %u family %d", attrs.nhaf_table, attrs.nhaf_family);
wa.hdr.nlmsg_flags |= NLM_F_MULTI;
for (struct nhop_object *nh = nhops_iter_start(&iter); nh;
nh = nhops_iter_next(&iter)) {
dump_nhop(nh, 0, &wa.hdr, wa.nw);
}
nhops_iter_stop(&iter);
} else {
struct unhop_ctl *ctl = atomic_load_ptr(&V_un_ctl);
if (__predict_false(ctl == NULL))
return (ESRCH);
NL_LOG(LOG_DEBUG2, "DUMP unhops");
UN_RLOCK(ctl);
wa.hdr.nlmsg_flags |= NLM_F_MULTI;
CHT_SLIST_FOREACH(&ctl->un_head, unhop, unhop) {
if (UNHOP_IS_MASTER(unhop) && match_unhop(&attrs, unhop))
dump_unhop(unhop, &wa.hdr, wa.nw);
} CHT_SLIST_FOREACH_END;
UN_RUNLOCK(ctl);
}
if (wa.error == 0) {
if (!nlmsg_end_dump(wa.nw, wa.error, &wa.hdr))
@ -1026,7 +1093,7 @@ static const struct rtnl_cmd_handler cmd_handlers[] = {
}
};
static const struct nlhdr_parser *all_parsers[] = { &nhmsg_parser };
static const struct nlhdr_parser *all_parsers[] = { &nhmsg_parser, &nh_fbsd_parser };
void
rtnl_nexthops_init(void)

View File

@ -56,10 +56,21 @@ enum {
NHA_FDB, /* not supported */
NHA_RES_GROUP, /* not supported */
NHA_RES_BUCKET, /* not supported */
NHA_FREEBSD, /* nested: FreeBSD-specific attributes */
__NHA_MAX,
};
#define NHA_MAX (__NHA_MAX - 1)
enum {
NHAF_UNSPEC,
NHAF_KNHOPS, /* flag: dump kernel nexthops */
NHAF_KGOUPS, /* flag: dump kernel nexthop groups */
NHAF_TABLE, /* u32: rtable id */
NHAF_FAMILY, /* u32: upper family */
NHAF_KID, /* u32: kernel nexthop index */
NHAF_AIF, /* u32: source interface address */
};
/*
* Attributes that can be used as filters:
* NHA_ID (nexhop or group), NHA_OIF, NHA_GROUPS,