The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=b32cf15d861794fc91d0f2666a71865ccd0fcb3e
commit b32cf15d861794fc91d0f2666a71865ccd0fcb3e Author: Alexander V. Chernikov <melif...@freebsd.org> AuthorDate: 2023-04-25 11:12:18 +0000 Commit: Alexander V. Chernikov <melif...@freebsd.org> CommitDate: 2023-04-25 11:12:18 +0000 netlink: add support for dumping kernel nexthops. MFC after: 2 weeks --- sys/netlink/route/nexthop.c | 107 +++++++++++++++++++++++++++++++++++--------- sys/netlink/route/nexthop.h | 11 +++++ 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/sys/netlink/route/nexthop.c b/sys/netlink/route/nexthop.c index 1b468ca18e73..94cc6caf7d82 100644 --- a/sys/netlink/route/nexthop.c +++ b/sys/netlink/route/nexthop.c @@ -436,11 +436,9 @@ enomem: } 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; + + 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); - 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 (__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) diff --git a/sys/netlink/route/nexthop.h b/sys/netlink/route/nexthop.h index 310c3e08fc4b..4128e014a2d0 100644 --- a/sys/netlink/route/nexthop.h +++ b/sys/netlink/route/nexthop.h @@ -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,