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,

Reply via email to