The branch main has been updated by melifaro:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a2728a9a5b8da974e238e6413a980134dbd6297f

commit a2728a9a5b8da974e238e6413a980134dbd6297f
Author:     Alexander V. Chernikov <[email protected]>
AuthorDate: 2023-04-25 11:08:47 +0000
Commit:     Alexander V. Chernikov <[email protected]>
CommitDate: 2023-04-25 11:08:47 +0000

    netlink: allow creation of temporary lle entries.
    
    MFC after:      2 weeks
---
 sys/netlink/route/neigh.c | 58 +++++++++++++++++++++++++++++++++++------------
 sys/netlink/route/neigh.h |  8 ++++++-
 2 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/sys/netlink/route/neigh.c b/sys/netlink/route/neigh.c
index 5a6309321524..97f438630503 100644
--- a/sys/netlink/route/neigh.c
+++ b/sys/netlink/route/neigh.c
@@ -122,6 +122,14 @@ lle_flags_to_nl_flags(const struct llentry *lle)
        return (nl_flags);
 }
 
+static uint32_t
+get_lle_next_ts(const struct llentry *lle)
+{
+       if (lle->la_expire == 0)
+               return (0);
+       return (lle->la_expire + lle->lle_remtime / hz + time_second - 
time_uptime);
+}
+
 static int
 dump_lle_locked(struct llentry *lle, void *arg)
 {
@@ -182,6 +190,13 @@ dump_lle_locked(struct llentry *lle, void *arg)
        /* TODO: provide confirmed/updated */
        cache->ndm_refcnt = lle->lle_refcnt;
 
+       int off = nlattr_add_nested(nw, NDA_FREEBSD);
+       if (off != 0) {
+               nlattr_add_u32(nw, NDAF_NEXT_STATE_TS, get_lle_next_ts(lle));
+
+               nlattr_set_len(nw, off);
+       }
+
         if (nlmsg_end(nw))
                return (0);
 enomem:
@@ -285,6 +300,7 @@ struct nl_parsed_neigh {
        struct sockaddr *nda_dst;
        struct ifnet    *nda_ifp;
        struct nlattr   *nda_lladdr;
+       uint32_t        ndaf_next_ts;
        uint32_t        ndm_flags;
        uint16_t        ndm_state;
        uint8_t         ndm_family;
@@ -292,18 +308,24 @@ struct nl_parsed_neigh {
 
 #define        _IN(_field)     offsetof(struct ndmsg, _field)
 #define        _OUT(_field)    offsetof(struct nl_parsed_neigh, _field)
-static struct nlfield_parser nlf_p_neigh[] = {
+static const struct nlattr_parser nla_p_neigh_fbsd[] = {
+       { .type = NDAF_NEXT_STATE_TS, .off = _OUT(ndaf_next_ts), .cb = 
nlattr_get_uint32 },
+};
+NL_DECLARE_ATTR_PARSER(neigh_fbsd_parser, nla_p_neigh_fbsd);
+
+static const struct nlfield_parser nlf_p_neigh[] = {
        { .off_in = _IN(ndm_family), .off_out = _OUT(ndm_family), .cb = 
nlf_get_u8 },
        { .off_in = _IN(ndm_flags), .off_out = _OUT(ndm_flags), .cb = 
nlf_get_u8_u32 },
        { .off_in = _IN(ndm_state), .off_out = _OUT(ndm_state), .cb = 
nlf_get_u16 },
        { .off_in = _IN(ndm_ifindex), .off_out = _OUT(nda_ifp), .cb = 
nlf_get_ifpz },
 };
 
-static struct nlattr_parser nla_p_neigh[] = {
+static const struct nlattr_parser nla_p_neigh[] = {
        { .type = NDA_DST, .off = _OUT(nda_dst), .cb = nlattr_get_ip },
        { .type = NDA_LLADDR, .off = _OUT(nda_lladdr), .cb = nlattr_get_nla },
        { .type = NDA_IFINDEX, .off = _OUT(nda_ifp), .cb = nlattr_get_ifp },
        { .type = NDA_FLAGS_EXT, .off = _OUT(ndm_flags), .cb = 
nlattr_get_uint32 },
+       { .type = NDA_FREEBSD, .arg = &neigh_fbsd_parser, .cb = 
nlattr_get_nested },
 };
 #undef _IN
 #undef _OUT
@@ -353,11 +375,6 @@ rtnl_handle_newneigh(struct nlmsghdr *hdr, struct nlpcb 
*nlp, struct nl_pstate *
                return (EINVAL);
        }
 
-       if (attrs.ndm_state != NUD_PERMANENT) {
-               NLMSG_REPORT_ERR_MSG(npt, "ndm_state %d not supported", 
attrs.ndm_state);
-               return (ENOTSUP);
-       }
-
        const uint16_t supported_flags = NTF_PROXY | NTF_STICKY;
        if ((attrs.ndm_flags & supported_flags) != attrs.ndm_flags) {
                NLMSG_REPORT_ERR_MSG(npt, "ndm_flags %X not supported",
@@ -383,26 +400,36 @@ rtnl_handle_newneigh(struct nlmsghdr *hdr, struct nlpcb 
*nlp, struct nl_pstate *
                return (EINVAL);
        }
 
-       int lle_flags = LLE_STATIC | ((attrs.ndm_flags & NTF_PROXY) ? LLE_PUB : 
0);
+       int lle_flags = (attrs.ndm_flags & NTF_PROXY) ? LLE_PUB : 0;
+       if (attrs.ndm_flags & NTF_STICKY)
+               lle_flags |= LLE_STATIC;
        struct llentry *lle = lltable_alloc_entry(llt, lle_flags, 
attrs.nda_dst);
        if (lle == NULL)
                return (ENOMEM);
        lltable_set_entry_addr(attrs.nda_ifp, lle, linkhdr, linkhdrsize, 
lladdr_off);
 
-       /* llentry created, try to insert or update :*/
+       if (attrs.ndm_flags & NTF_STICKY)
+               lle->la_expire = 0;
+       else
+               lle->la_expire = attrs.ndaf_next_ts - time_second + time_uptime;
+
+       /* llentry created, try to insert or update */
        IF_AFDATA_WLOCK(attrs.nda_ifp);
        LLE_WLOCK(lle);
        struct llentry *lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, attrs.nda_dst);
        if (lle_tmp != NULL) {
+               error = EEXIST;
                if (hdr->nlmsg_flags & NLM_F_EXCL) {
                        LLE_WUNLOCK(lle_tmp);
                        lle_tmp = NULL;
-                       error = EEXIST;
                } else if (hdr->nlmsg_flags & NLM_F_REPLACE) {
-                       lltable_unlink_entry(llt, lle_tmp);
-                       lltable_link_entry(llt, lle);
-               } else
-                       error = EEXIST;
+                       if ((lle_tmp->la_flags & LLE_IFADDR) == 0) {
+                               lltable_unlink_entry(llt, lle_tmp);
+                               lltable_link_entry(llt, lle);
+                               error = 0;
+                       } else
+                               error = EPERM;
+               }
        } else {
                if (hdr->nlmsg_flags & NLM_F_CREATE)
                        lltable_link_entry(llt, lle);
@@ -458,6 +485,7 @@ rtnl_handle_delneigh(struct nlmsghdr *hdr, struct nlpcb 
*nlp, struct nl_pstate *
                        LLE_WUNLOCK(lle);
                        lle = NULL;
                        error = EPERM;
+                       NLMSG_REPORT_ERR_MSG(npt, "unable to delete ifaddr 
record");
                } else
                        lltable_unlink_entry(llt, lle);
        } else
@@ -557,7 +585,7 @@ rtnl_lle_event(void *arg __unused, struct llentry *lle, int 
evt)
        nlmsg_flush(&nw);
 }
 
-static const struct nlhdr_parser *all_parsers[] = { &ndmsg_parser };
+static const struct nlhdr_parser *all_parsers[] = { &ndmsg_parser, 
&neigh_fbsd_parser };
 
 void
 rtnl_neighs_init(void)
diff --git a/sys/netlink/route/neigh.h b/sys/netlink/route/neigh.h
index 1ec1b95fdcde..970fe7312df7 100644
--- a/sys/netlink/route/neigh.h
+++ b/sys/netlink/route/neigh.h
@@ -49,7 +49,7 @@ enum {
        NDA_DST,                /* binary: neigh l3 address */
        NDA_LLADDR,             /* binary: neigh link-level address */
        NDA_CACHEINFO,          /* binary, struct nda_cacheinfo */
-       NDA_PROBES,             /* XXX */
+       NDA_PROBES,             /* u32: number of probes sent */
        NDA_VLAN,               /* upper 802.1Q tag */
        NDA_PORT,               /* not supported */
        NDA_VNI,                /* not supported */
@@ -63,11 +63,17 @@ enum {
        NDA_FLAGS_EXT,          /* u32: ndm_flags */
        NDA_NDM_STATE_MASK,     /* XXX */
        NDA_NDM_FLAGS_MASK,     /* XXX */
+       NDA_FREEBSD,            /* nested: FreeBSD-specific */
        __NDA_MAX
 };
 
 #define        NDA_MAX (__NDA_MAX - 1)
 
+enum {
+       NDAF_UNSPEC,
+       NDAF_NEXT_STATE_TS,     /* (u32) seconds from time_uptime when moving 
to the next state */
+};
+
 
 /* ndm_flags / NDA_FLAGS_EXT */
 #define        NTF_USE                 0x0001  /* XXX */

Reply via email to