aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2023-04-25 11:08:47 +0000
committerKristof Provost <kp@FreeBSD.org>2023-10-31 08:08:44 +0000
commitec4ae38566569bfac4e18e1fb2ce61fec1e2361b (patch)
treee46301135df5292f934bfc2481764a2418632935
parentb174bec464ba8a072502e647adc9c03bb2881f17 (diff)
downloadsrc-ec4ae38566569bfac4e18e1fb2ce61fec1e2361b.tar.gz
src-ec4ae38566569bfac4e18e1fb2ce61fec1e2361b.zip
netlink: allow creation of temporary lle entries.
MFC after: 2 weeks (cherry picked from commit a2728a9a5b8da974e238e6413a980134dbd6297f)
-rw-r--r--sys/netlink/route/neigh.c58
-rw-r--r--sys/netlink/route/neigh.h8
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 */