From b4d994115e86059fd943304e567e2844a313d0c3 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 20 Feb 2024 13:50:48 +0100 Subject: [PATCH] route: expose nexthop id attribute Routes may reference a nexthop (group) via the new nexthop API by its ID, so add accessors for setting and getting it. Referencing a nexthop is mutually exclusive to specifiying nexthops in the route, so make sure we do not do that when creating netlink messages (which may exist both, since netlink messages from the kernel contain both unless 'nexthop_compat_mode' is disabled). $ ip -6 r 2001:db8:3::/64 nhid 20 metric 1024 pref medium nexthop via 2001:db8:1::2 dev v0 weight 1 nexthop via 2001:db8:2::2 dev v1 weight 1 Before: $ nl-route-list inet6 2001:db8:3::/64 table main type unicast via 2001:db8:1::2 dev v0 via 2001:db8:2::2 dev v1 After: $ nl-route-list inet6 2001:db8:3::/64 table main type unicast nhid 20 via 2001:db8:1::2 dev v0 via 2001:db8:2::2 dev v1 Signed-off-by: Jonas Gorski --- include/netlink/route/route.h | 2 ++ lib/route/route_obj.c | 35 ++++++++++++++++++++++++++++++++++- libnl-route-3.sym | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h index 38247628e..4377062fc 100644 --- a/include/netlink/route/route.h +++ b/include/netlink/route/route.h @@ -94,6 +94,8 @@ extern int rtnl_route_get_src_len(struct rtnl_route *); extern void rtnl_route_set_ttl_propagate(struct rtnl_route *route, uint8_t ttl_prop); extern int rtnl_route_get_ttl_propagate(struct rtnl_route *route); +extern void rtnl_route_set_nhid(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_nhid(struct rtnl_route *); extern void rtnl_route_add_nexthop(struct rtnl_route *, struct rtnl_nexthop *); diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c index 0a0c06d6b..71b6a53ec 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.c @@ -65,6 +65,7 @@ struct rtnl_route { uint32_t rt_metrics[RTAX_MAX]; uint32_t rt_metrics_mask; uint32_t rt_nr_nh; + uint32_t rt_nhid; struct nl_addr *rt_pref_src; struct nl_list_head rt_nexthops; struct rtnl_rtcacheinfo rt_cacheinfo; @@ -90,6 +91,7 @@ struct rtnl_route { #define ROUTE_ATTR_REALMS 0x010000 #define ROUTE_ATTR_CACHEINFO 0x020000 #define ROUTE_ATTR_TTL_PROPAGATE 0x040000 +#define ROUTE_ATTR_NHID 0x080000 /** @endcond */ static void route_constructor(struct nl_object *c) @@ -194,6 +196,9 @@ static void route_dump_line(struct nl_object *a, struct nl_dump_params *p) if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0) nl_dump(p, "tos %#x ", r->rt_tos); + if (r->ce_mask & ROUTE_ATTR_NHID) + nl_dump(p, "nhid %u ", r->rt_nhid); + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { struct rtnl_nexthop *nh; @@ -284,6 +289,9 @@ static void route_dump_details(struct nl_object *a, struct nl_dump_params *p) r->rt_ttl_propagate ? "enabled" : "disabled"); } + if (r->ce_mask & ROUTE_ATTR_NHID) + nl_dump(p, "nhid %u ", r->rt_nhid); + nl_dump(p, "\n"); if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { @@ -414,6 +422,7 @@ static uint64_t route_compare(struct nl_object *_a, struct nl_object *_b, nl_addr_cmp(a->rt_pref_src, b->rt_pref_src)); diff |= _DIFF(ROUTE_ATTR_TTL_PROPAGATE, a->rt_ttl_propagate != b->rt_ttl_propagate); + diff |= _DIFF(ROUTE_ATTR_NHID, a->rt_nhid != b->rt_nhid); if (flags & LOOSE_COMPARISON) { nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { @@ -619,6 +628,7 @@ static const struct trans_tbl route_attrs[] = { __ADD(ROUTE_ATTR_REALMS, realms), __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo), __ADD(ROUTE_ATTR_TTL_PROPAGATE, ttl_propagate), + __ADD(ROUTE_ATTR_NHID, nhid), }; static char *route_attrs2str(int attrs, char *buf, size_t len) @@ -966,6 +976,21 @@ int rtnl_route_get_ttl_propagate(struct rtnl_route *route) return route->rt_ttl_propagate; } +void rtnl_route_set_nhid(struct rtnl_route *route, uint32_t nhid) +{ + route->rt_nhid = nhid; + + if (nhid > 0) + route->ce_mask |= ROUTE_ATTR_NHID; + else + route->ce_mask &= ~ROUTE_ATTR_NHID; +} + +uint32_t rtnl_route_get_nhid(struct rtnl_route *route) +{ + return route->rt_nhid; +} + /** @} */ /** @@ -1048,6 +1073,7 @@ static struct nla_policy route_policy[RTA_MAX+1] = { [RTA_TTL_PROPAGATE] = { .type = NLA_U8 }, [RTA_ENCAP] = { .type = NLA_NESTED }, [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, + [RTA_NH_ID] = { .type = NLA_U32 }, }; static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) @@ -1339,6 +1365,10 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) return err; } + if (tb[RTA_NH_ID]) { + rtnl_route_set_nhid(route, nla_get_u32(tb[RTA_NH_ID])); + } + if (old_nh) { rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff); if (route->rt_nr_nh == 0) { @@ -1441,7 +1471,10 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) nla_nest_end(msg, metrics); } - if (rtnl_route_get_nnexthops(route) == 1) { + /* Nexthop specification and nexthop id are mutually exclusive */ + if (route->ce_mask & ROUTE_ATTR_NHID) { + NLA_PUT_U32(msg, RTA_NH_ID, route->rt_nhid); + } else if (rtnl_route_get_nnexthops(route) == 1) { struct rtnl_nexthop *nh; nh = rtnl_route_nexthop_n(route, 0); diff --git a/libnl-route-3.sym b/libnl-route-3.sym index aca02e9b6..9cb21f74e 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1328,5 +1328,7 @@ global: rtnl_link_bridge_set_port_vlan_map_range; rtnl_link_bridge_set_port_vlan_pvid; rtnl_link_bridge_unset_port_vlan_map_range; + rtnl_route_get_nhid; rtnl_route_nh_identical; + rtnl_route_set_nhid; } libnl_3_9;