aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2023-04-02 13:47:10 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2023-04-02 13:47:10 +0000
commitc35a43b261f807fd85b8cc30306112eee9dd62ce (patch)
treec5e2d3496f1549b560eed0e30642cd6a10e3bea8
parent4aeb939ecf8b2b6913ae51d828416743bad812ab (diff)
downloadsrc-c35a43b261f807fd85b8cc30306112eee9dd62ce.tar.gz
src-c35a43b261f807fd85b8cc30306112eee9dd62ce.zip
netlink: allow exact-match route lookups via RTM_GETROUTE.
Use already-existing RTM_F_PREFIX rtm_flag to indicate that the request assumes exact-prefix lookup instead of the longest-prefix-match. MFC after: 2 weeks
-rw-r--r--sys/net/route/route_ctl.c14
-rw-r--r--sys/net/route/route_ctl.h6
-rw-r--r--sys/netlink/route/rt.c13
3 files changed, 26 insertions, 7 deletions
diff --git a/sys/net/route/route_ctl.c b/sys/net/route/route_ctl.c
index 755765869e84..db3728c3cd88 100644
--- a/sys/net/route/route_ctl.c
+++ b/sys/net/route/route_ctl.c
@@ -96,6 +96,8 @@ static int delete_route(struct rib_head *rnh, struct rtentry *rt,
static int rt_delete_conditional(struct rib_head *rnh, struct rtentry *rt,
int prio, rib_filter_f_t *cb, void *cbdata, struct rib_cmd_info *rc);
+static bool fill_pxmask_family(int family, int plen, struct sockaddr *_dst,
+ struct sockaddr **pmask);
static int get_prio_from_info(const struct rt_addrinfo *info);
static int nhop_get_prio(const struct nhop_object *nh);
@@ -391,6 +393,18 @@ lookup_prefix(struct rib_head *rnh, const struct rt_addrinfo *info,
return (rt);
}
+const struct rtentry *
+rib_lookup_prefix_plen(struct rib_head *rnh, struct sockaddr *dst, int plen,
+ struct route_nhop_data *rnd)
+{
+ union sockaddr_union mask_storage;
+ struct sockaddr *netmask = &mask_storage.sa;
+
+ if (fill_pxmask_family(dst->sa_family, plen, dst, &netmask))
+ return (lookup_prefix_bysa(rnh, dst, netmask, rnd));
+ return (NULL);
+}
+
static bool
fill_pxmask_family(int family, int plen, struct sockaddr *_dst,
struct sockaddr **pmask)
diff --git a/sys/net/route/route_ctl.h b/sys/net/route/route_ctl.h
index b65b64fcdaa0..7a4ed804feb7 100644
--- a/sys/net/route/route_ctl.h
+++ b/sys/net/route/route_ctl.h
@@ -123,11 +123,9 @@ struct nhop_object;
struct nhgrp_object;
struct ucred;
-const struct rtentry *rib_lookup_prefix(uint32_t fibnum, int family,
- const struct sockaddr *dst, const struct sockaddr *netmask,
+const struct rtentry *
+rib_lookup_prefix_plen(struct rib_head *rnh, struct sockaddr *dst, int plen,
struct route_nhop_data *rnd);
-const struct rtentry *rib_lookup_lpm(uint32_t fibnum, int family,
- const struct sockaddr *dst, struct route_nhop_data *rnd);
/* rtentry accessors */
bool rt_is_host(const struct rtentry *rt);
diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c
index 6d76390016dd..288ff111a038 100644
--- a/sys/netlink/route/rt.c
+++ b/sys/netlink/route/rt.c
@@ -461,6 +461,7 @@ struct nl_parsed_route {
uint8_t rtm_dst_len;
uint8_t rtm_protocol;
uint8_t rtm_type;
+ uint32_t rtm_flags;
};
#define _IN(_field) offsetof(struct rtmsg, _field)
@@ -488,6 +489,7 @@ static const struct nlfield_parser nlf_p_rtmsg[] = {
{ .off_in = _IN(rtm_dst_len), .off_out = _OUT(rtm_dst_len), .cb = nlf_get_u8 },
{ .off_in = _IN(rtm_protocol), .off_out = _OUT(rtm_protocol), .cb = nlf_get_u8 },
{ .off_in = _IN(rtm_type), .off_out = _OUT(rtm_type), .cb = nlf_get_u8 },
+ { .off_in = _IN(rtm_flags), .off_out = _OUT(rtm_flags), .cb = nlf_get_u32 },
};
#undef _IN
#undef _OUT
@@ -581,7 +583,8 @@ handle_rtm_getroute(struct nlpcb *nlp, struct nl_parsed_route *attrs,
{
RIB_RLOCK_TRACKER;
struct rib_head *rnh;
- struct rtentry *rt;
+ const struct rtentry *rt;
+ struct route_nhop_data rnd;
uint32_t fibnum = attrs->rta_table;
sa_family_t family = attrs->rtm_family;
@@ -596,13 +599,17 @@ handle_rtm_getroute(struct nlpcb *nlp, struct nl_parsed_route *attrs,
RIB_RLOCK(rnh);
- rt = (struct rtentry *)rnh->rnh_matchaddr(attrs->rta_dst, &rnh->head);
+ struct sockaddr *dst = attrs->rta_dst;
+
+ if (attrs->rtm_flags & RTM_F_PREFIX)
+ rt = rib_lookup_prefix_plen(rnh, dst, attrs->rtm_dst_len, &rnd);
+ else
+ rt = (const struct rtentry *)rnh->rnh_matchaddr(dst, &rnh->head);
if (rt == NULL) {
RIB_RUNLOCK(rnh);
return (ESRCH);
}
- struct route_nhop_data rnd;
rt_get_rnd(rt, &rnd);
rnd.rnd_nhop = nhop_select_func(rnd.rnd_nhop, 0);