git: ec4ae3856656 - stable/13 - netlink: allow creation of temporary lle entries.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 01 Nov 2023 09:06:05 UTC
The branch stable/13 has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=ec4ae38566569bfac4e18e1fb2ce61fec1e2361b commit ec4ae38566569bfac4e18e1fb2ce61fec1e2361b Author: Alexander V. Chernikov <melifaro@FreeBSD.org> AuthorDate: 2023-04-25 11:08:47 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2023-10-31 08:08:44 +0000 netlink: allow creation of temporary lle entries. MFC after: 2 weeks (cherry picked from commit a2728a9a5b8da974e238e6413a980134dbd6297f) --- 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 097b75298745..140194b4ad32 100644 --- a/sys/netlink/route/neigh.c +++ b/sys/netlink/route/neigh.c @@ -119,6 +119,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) { @@ -179,6 +187,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: @@ -282,6 +297,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; @@ -289,18 +305,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 @@ -350,11 +372,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", @@ -380,26 +397,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); @@ -455,6 +482,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 @@ -554,7 +582,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 d6835505ea74..eacacc09711a 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 */