diff --git a/frr/if_grout.c b/frr/if_grout.c index 69fe6bc75..0ecdae546 100644 --- a/frr/if_grout.c +++ b/frr/if_grout.c @@ -19,11 +19,6 @@ #include #include -// ugly hack to avoid collision with ifindex kernel -// Don't use 1<<32, because ietf-interfaces.yang defined int32, not uint32 -// else it triggers assert in -// `libyang: Unsatisfied raInge - value "-2147483647" is out of the allowed range` -#define GROUT_INDEX_OFFSET (1000000000U) // 1<<30U , round-up to lower decimal numbers #define GROUT_NS NS_DEFAULT static uint64_t gr_if_flags_to_netlink(struct gr_iface *gr_if, enum zebra_link_type link_type) { diff --git a/frr/if_grout.h b/frr/if_grout.h index 7609adc2c..30e7378db 100644 --- a/frr/if_grout.h +++ b/frr/if_grout.h @@ -10,6 +10,12 @@ #include #include +// ugly hack to avoid collision with ifindex kernel +// Don't use 1<<32, because ietf-interfaces.yang defined int32, not uint32 +// else it triggers assert in +// `libyang: Unsatisfied raInge - value "-2147483647" is out of the allowed range` +#define GROUT_INDEX_OFFSET (1000000000) // 1<<30 , round-up to lower decimal numbers + enum zebra_dplane_result grout_add_del_address(struct zebra_dplane_ctx *ctx); void grout_interface_addr_dplane(struct gr_nexthop *gr_nh, bool new); diff --git a/frr/rt_grout.c b/frr/rt_grout.c index 93d0f9de0..1f2e83ec2 100644 --- a/frr/rt_grout.c +++ b/frr/rt_grout.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright (c) 2025 Maxime Leroy, Free Mobile +#include "if_grout.h" #include "log_grout.h" #include "rt_grout.h" @@ -8,84 +9,84 @@ #include #include -static inline bool is_selfroute(gr_rt_origin_t origin) { +static inline bool is_selfroute(gr_nh_origin_t origin) { switch (origin) { - case GR_RT_ORIGIN_ZEBRA: - case GR_RT_ORIGIN_BABEL: - case GR_RT_ORIGIN_BGP: - case GR_RT_ORIGIN_ISIS: - case GR_RT_ORIGIN_OSPF: - case GR_RT_ORIGIN_RIP: - case GR_RT_ORIGIN_RIPNG: - case GR_RT_ORIGIN_NHRP: - case GR_RT_ORIGIN_EIGRP: - case GR_RT_ORIGIN_LDP: - case GR_RT_ORIGIN_SHARP: - case GR_RT_ORIGIN_PBR: - case GR_RT_ORIGIN_ZSTATIC: - case GR_RT_ORIGIN_OPENFABRIC: - case GR_RT_ORIGIN_SRTE: + case GR_NH_ORIGIN_ZEBRA: + case GR_NH_ORIGIN_BABEL: + case GR_NH_ORIGIN_BGP: + case GR_NH_ORIGIN_ISIS: + case GR_NH_ORIGIN_OSPF: + case GR_NH_ORIGIN_RIP: + case GR_NH_ORIGIN_RIPNG: + case GR_NH_ORIGIN_NHRP: + case GR_NH_ORIGIN_EIGRP: + case GR_NH_ORIGIN_LDP: + case GR_NH_ORIGIN_SHARP: + case GR_NH_ORIGIN_PBR: + case GR_NH_ORIGIN_ZSTATIC: + case GR_NH_ORIGIN_OPENFABRIC: + case GR_NH_ORIGIN_SRTE: return true; default: return false; } } -static inline gr_rt_origin_t zebra2origin(int proto) { - gr_rt_origin_t origin; +static inline gr_nh_origin_t zebra2origin(int proto) { + gr_nh_origin_t origin; switch (proto) { case ZEBRA_ROUTE_BABEL: - origin = GR_RT_ORIGIN_BABEL; + origin = GR_NH_ORIGIN_BABEL; break; case ZEBRA_ROUTE_BGP: - origin = GR_RT_ORIGIN_BGP; + origin = GR_NH_ORIGIN_BGP; break; case ZEBRA_ROUTE_OSPF: case ZEBRA_ROUTE_OSPF6: - origin = GR_RT_ORIGIN_OSPF; + origin = GR_NH_ORIGIN_OSPF; break; case ZEBRA_ROUTE_STATIC: - origin = GR_RT_ORIGIN_ZSTATIC; + origin = GR_NH_ORIGIN_ZSTATIC; break; case ZEBRA_ROUTE_ISIS: - origin = GR_RT_ORIGIN_ISIS; + origin = GR_NH_ORIGIN_ISIS; break; case ZEBRA_ROUTE_RIP: - origin = GR_RT_ORIGIN_RIP; + origin = GR_NH_ORIGIN_RIP; break; case ZEBRA_ROUTE_RIPNG: - origin = GR_RT_ORIGIN_RIPNG; + origin = GR_NH_ORIGIN_RIPNG; break; case ZEBRA_ROUTE_NHRP: - origin = GR_RT_ORIGIN_NHRP; + origin = GR_NH_ORIGIN_NHRP; break; case ZEBRA_ROUTE_EIGRP: - origin = GR_RT_ORIGIN_EIGRP; + origin = GR_NH_ORIGIN_EIGRP; break; case ZEBRA_ROUTE_LDP: - origin = GR_RT_ORIGIN_LDP; + origin = GR_NH_ORIGIN_LDP; break; case ZEBRA_ROUTE_SHARP: - origin = GR_RT_ORIGIN_SHARP; + origin = GR_NH_ORIGIN_SHARP; break; case ZEBRA_ROUTE_PBR: - origin = GR_RT_ORIGIN_PBR; + origin = GR_NH_ORIGIN_PBR; break; case ZEBRA_ROUTE_OPENFABRIC: - origin = GR_RT_ORIGIN_OPENFABRIC; + origin = GR_NH_ORIGIN_OPENFABRIC; break; case ZEBRA_ROUTE_SRTE: - origin = GR_RT_ORIGIN_SRTE; + origin = GR_NH_ORIGIN_SRTE; break; case ZEBRA_ROUTE_TABLE: case ZEBRA_ROUTE_NHG: - origin = GR_RT_ORIGIN_ZEBRA; + origin = GR_NH_ORIGIN_ZEBRA; break; case ZEBRA_ROUTE_CONNECT: case ZEBRA_ROUTE_LOCAL: case ZEBRA_ROUTE_KERNEL: - origin = GR_RT_ORIGIN_LINK; + origin = GR_NH_ORIGIN_LINK; break; default: // When a user adds a new protocol this will show up @@ -93,77 +94,77 @@ static inline gr_rt_origin_t zebra2origin(int proto) { // is intentionally a warn because we should see // this as part of development of a new protocol. gr_log_debug("Please add this protocol(%d) to grout", proto); - origin = GR_RT_ORIGIN_ZEBRA; + origin = GR_NH_ORIGIN_ZEBRA; break; } return origin; } -static inline int origin2zebra(gr_rt_origin_t origin, int family, bool is_nexthop) { +static inline int origin2zebra(gr_nh_origin_t origin, int family, bool is_nexthop) { int proto; switch (origin) { - case GR_RT_ORIGIN_BABEL: + case GR_NH_ORIGIN_BABEL: proto = ZEBRA_ROUTE_BABEL; break; - case GR_RT_ORIGIN_BGP: + case GR_NH_ORIGIN_BGP: proto = ZEBRA_ROUTE_BGP; break; - case GR_RT_ORIGIN_OSPF: + case GR_NH_ORIGIN_OSPF: proto = (family == AF_INET) ? ZEBRA_ROUTE_OSPF : ZEBRA_ROUTE_OSPF6; break; - case GR_RT_ORIGIN_ISIS: + case GR_NH_ORIGIN_ISIS: proto = ZEBRA_ROUTE_ISIS; break; - case GR_RT_ORIGIN_RIP: + case GR_NH_ORIGIN_RIP: proto = ZEBRA_ROUTE_RIP; break; - case GR_RT_ORIGIN_RIPNG: + case GR_NH_ORIGIN_RIPNG: proto = ZEBRA_ROUTE_RIPNG; break; - case GR_RT_ORIGIN_NHRP: + case GR_NH_ORIGIN_NHRP: proto = ZEBRA_ROUTE_NHRP; break; - case GR_RT_ORIGIN_EIGRP: + case GR_NH_ORIGIN_EIGRP: proto = ZEBRA_ROUTE_EIGRP; break; - case GR_RT_ORIGIN_LDP: + case GR_NH_ORIGIN_LDP: proto = ZEBRA_ROUTE_LDP; break; - case GR_RT_ORIGIN_ZSTATIC: + case GR_NH_ORIGIN_ZSTATIC: proto = ZEBRA_ROUTE_STATIC; break; - case GR_RT_ORIGIN_SHARP: + case GR_NH_ORIGIN_SHARP: proto = ZEBRA_ROUTE_SHARP; break; - case GR_RT_ORIGIN_PBR: + case GR_NH_ORIGIN_PBR: proto = ZEBRA_ROUTE_PBR; break; - case GR_RT_ORIGIN_OPENFABRIC: + case GR_NH_ORIGIN_OPENFABRIC: proto = ZEBRA_ROUTE_OPENFABRIC; break; - case GR_RT_ORIGIN_SRTE: + case GR_NH_ORIGIN_SRTE: proto = ZEBRA_ROUTE_SRTE; break; - case GR_RT_ORIGIN_USER: - case GR_RT_ORIGIN_UNSPEC: - case GR_RT_ORIGIN_REDIRECT: - case GR_RT_ORIGIN_LINK: - case GR_RT_ORIGIN_BOOT: - case GR_RT_ORIGIN_GATED: - case GR_RT_ORIGIN_RA: - case GR_RT_ORIGIN_MRT: - case GR_RT_ORIGIN_BIRD: - case GR_RT_ORIGIN_DNROUTED: - case GR_RT_ORIGIN_XORP: - case GR_RT_ORIGIN_NTK: - case GR_RT_ORIGIN_MROUTED: - case GR_RT_ORIGIN_KEEPALIVED: - case GR_RT_ORIGIN_OPENR: + case GR_NH_ORIGIN_USER: + case GR_NH_ORIGIN_UNSPEC: + case GR_NH_ORIGIN_REDIRECT: + case GR_NH_ORIGIN_LINK: + case GR_NH_ORIGIN_BOOT: + case GR_NH_ORIGIN_GATED: + case GR_NH_ORIGIN_RA: + case GR_NH_ORIGIN_MRT: + case GR_NH_ORIGIN_BIRD: + case GR_NH_ORIGIN_DNROUTED: + case GR_NH_ORIGIN_XORP: + case GR_NH_ORIGIN_NTK: + case GR_NH_ORIGIN_MROUTED: + case GR_NH_ORIGIN_KEEPALIVED: + case GR_NH_ORIGIN_OPENR: proto = ZEBRA_ROUTE_KERNEL; break; - case GR_RT_ORIGIN_ZEBRA: + case GR_NH_ORIGIN_ZEBRA: if (is_nexthop) { proto = ZEBRA_ROUTE_NHG; break; @@ -182,35 +183,79 @@ static inline int origin2zebra(gr_rt_origin_t origin, int family, bool is_nextho return proto; } +static int grout_gr_nexthop_to_frr_nexthop( + struct gr_nexthop *gr_nh, + struct nexthop *nh, + int *nh_family, + bool new +) { + size_t sz; + + if (gr_nh->vrf_id != VRF_DEFAULT) { + gr_log_debug("no vrf support for nexthop, nexthop not sync"); + return -1; + } + if (gr_nh->iface_id) + nh->ifindex = gr_nh->iface_id + GROUT_INDEX_OFFSET; + else + nh->ifindex = 0; + + nh->vrf_id = gr_nh->vrf_id; + nh->weight = 1; + + switch (gr_nh->af) { + case GR_AF_IP4: + if (nh->ifindex) + nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + nh->type = NEXTHOP_TYPE_IPV4; + + sz = 4; + *nh_family = AF_INET; + memcpy(&nh->gate.ipv4, &gr_nh->ipv4, sz); + break; + case GR_AF_IP6: + if (nh->ifindex) + nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + else + nh->type = NEXTHOP_TYPE_IPV6; + + sz = 16; + *nh_family = AF_INET6; + memcpy(&nh->gate.ipv6, &gr_nh->ipv6, sz); + break; + default: + gr_log_debug("inval nexthop family %u, nexthop not sync", gr_nh->af); + return -1; + } + // XXX: no NEXTHOP_TYPE_IFINDEX in grout, unlike kernel + return 0; +} + static void grout_route_change( bool new, - uint16_t vrf_id, - gr_rt_origin_t origin, + gr_nh_origin_t origin, uint16_t family, - void *nh_addr, void *dest_addr, - uint8_t dest_prefixlen + uint8_t dest_prefixlen, + struct gr_nexthop *gr_nh ) { int tableid = RT_TABLE_ID_MAIN; /* no table support for now */ int proto = ZEBRA_ROUTE_KERNEL; - struct nexthop nh = {}; + uint32_t nh_id = gr_nh->nh_id; + struct nexthop _nh, *nh = NULL; uint32_t flags = 0; struct prefix p; size_t sz; afi_t afi; - if (vrf_id != VRF_DEFAULT) { - gr_log_debug("no vrf support for route, route not sync"); - return; - } - if (family == AF_INET) gr_log_debug( "get notification '%s route %pI4/%u (origin %s)'", new ? "add" : "del", dest_addr, dest_prefixlen, - gr_rt_origin_name(origin) + gr_nh_origin_name(origin) ); else gr_log_debug( @@ -218,25 +263,44 @@ static void grout_route_change( new ? "add" : "del", dest_addr, dest_prefixlen, - gr_rt_origin_name(origin) + gr_nh_origin_name(origin) ); if (new && is_selfroute(origin)) { gr_log_debug( "'%s' route received that we think we have originated, ignoring", - gr_rt_origin_name(origin) + gr_nh_origin_name(origin) ); return; } - if (origin == GR_RT_ORIGIN_LINK) { - gr_log_debug("'%s' route intentionally ignoring", gr_rt_origin_name(origin)); + if (origin == GR_NH_ORIGIN_LINK) { + gr_log_debug("'%s' route intentionally ignoring", gr_nh_origin_name(origin)); return; } - // A method to ignore our own messages. selfroute ? */ - memset(&nh, 0, sizeof(nh)); - nh.vrf_id = VRF_DEFAULT; + // if no nh_id, parse nexthop + if (nh_id == 0) { + int nh_family; + + memset(&_nh, 0, sizeof(_nh)); + nh = &_nh; + + if (grout_gr_nexthop_to_frr_nexthop(gr_nh, nh, &nh_family, new) < 0) { + gr_log_debug("route received has invalid nexthop, ignoring"); + return; + } + + if (nh_family != family) { + gr_log_debug( + "nexthop family %u different that route family %u nexthop, " + "ignoring", + nh_family, + family + ); + return; + } + } if (family == AF_INET) { afi = AFI_IP; @@ -245,10 +309,6 @@ static void grout_route_change( memcpy(&p.u.prefix4, dest_addr, sz); p.prefixlen = dest_prefixlen; - - // FIX IFINDEX CASE */ - nh.type = NEXTHOP_TYPE_IPV4; - memcpy(&nh.gate.ipv4, nh_addr, sz); } else { afi = AFI_IP6; p.family = AF_INET6; @@ -256,32 +316,32 @@ static void grout_route_change( memcpy(&p.u.prefix6, dest_addr, sz); p.prefixlen = dest_prefixlen; - - // FIX IFINDEX CASE */ - nh.type = NEXTHOP_TYPE_IPV6; - memcpy(&nh.gate.ipv6, nh_addr, sz); } proto = origin2zebra(origin, family, false); - if (new) - rib_add(afi, - SAFI_UNICAST, - VRF_DEFAULT, - proto, - 0, - flags, - &p, - NULL, - &nh, - 0, - tableid, - 0, - 0, - 0, - 0, - false); - else + if (new) { + struct route_entry *re; + struct nexthop_group *ng = NULL; + struct nexthop *nexthop; + + re = zebra_rib_route_entry_new( + VRF_DEFAULT, proto, 0, flags, nh_id, tableid, 0, 0, 0, 0 + ); + if (nh) { + ng = nexthop_group_new(); + + nexthop = nexthop_new(); + *nexthop = *nh; + nexthop_group_add_sorted(ng, nexthop); + assert(nh_id == 0); + } + + rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, re, ng, false); + + if (ng) + nexthop_group_delete(&ng); + } else rib_delete( afi, SAFI_UNICAST, @@ -291,8 +351,8 @@ static void grout_route_change( flags, &p, NULL, - &nh, - 0, + nh, + nh_id, tableid, 0, 0, @@ -303,24 +363,22 @@ static void grout_route_change( void grout_route4_change(bool new, struct gr_ip4_route *gr_r4) { grout_route_change( new, - gr_r4->nh.vrf_id, gr_r4->origin, AF_INET, - &gr_r4->nh.ipv4, (void *)&gr_r4->dest.ip, - gr_r4->dest.prefixlen + gr_r4->dest.prefixlen, + &gr_r4->nh ); } void grout_route6_change(bool new, struct gr_ip6_route *gr_r6) { grout_route_change( new, - gr_r6->nh.vrf_id, gr_r6->origin, AF_INET6, - &gr_r6->nh.ipv6, (void *)&gr_r6->dest.ip, - gr_r6->dest.prefixlen + gr_r6->dest.prefixlen, + &gr_r6->nh ); } @@ -331,15 +389,14 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) { struct gr_ip6_route_add_req r6_add; struct gr_ip6_route_del_req r6_del; } req; - const struct nexthop_group *ng; - enum nexthop_types_t nt = 0; + uint32_t nh_id = dplane_ctx_get_nhe_id(ctx); const struct prefix *p; - gr_rt_origin_t origin; + gr_nh_origin_t origin; uint32_t req_type; size_t req_len; bool new; - if (dplane_ctx_get_vrf(ctx) != 0) { + if (dplane_ctx_get_vrf(ctx) != VRF_DEFAULT) { gr_log_err( "impossible to add/del route on vrf %u (vrf not supported)", dplane_ctx_get_vrf(ctx) @@ -356,49 +413,26 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) { gr_log_err("impossible to add/del route with src (not supported)"); return ZEBRA_DPLANE_REQUEST_FAILURE; } - ng = dplane_ctx_get_ng(ctx); - if (nexthop_group_nexthop_num(ng) > 1) { - gr_log_err("impossible to add/del route with several nexthop (not supported)"); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - if (nexthop_group_nexthop_num(ng) == 0) { - gr_log_err("impossible to add/del route with no nexthop (not supported)"); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - nt = ng->nexthop->type; - if (nt == NEXTHOP_TYPE_BLACKHOLE) { - gr_log_err( - "impossible to add/del route with nexthop type = %u (not supported)", nt - ); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } // TODO: other check for metric, distance, and so-on origin = zebra2origin(dplane_ctx_get_type(ctx)); new = dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE; + + if (new && nh_id == 0) { + gr_log_err("impossible to add route with no nexthop id"); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + if (p->family == AF_INET) { struct ip4_net *dest; - if (nt == NEXTHOP_TYPE_IPV6 || nt == NEXTHOP_TYPE_IPV6_IFINDEX) { - gr_log_err( - "impossible to add/del ipv4 route with nexthop type = %u (not " - "supported)", - nt - ); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - if (new) { req.r4_add = (struct gr_ip4_route_add_req) {.exist_ok = true, .vrf_id = 0}; req_type = GR_IP4_ROUTE_ADD; req_len = sizeof(struct gr_ip4_route_add_req); - if (nt == NEXTHOP_TYPE_IFINDEX || nt == NEXTHOP_TYPE_IPV4_IFINDEX) - // TOFIX with next API in grout - req.r4_add.nh = p->u.prefix4.s_addr; - if (nt == NEXTHOP_TYPE_IPV4 || nt == NEXTHOP_TYPE_IPV4_IFINDEX) - req.r4_add.nh = ng->nexthop->gate.ipv4.s_addr; + req.r4_add.nh_id = nh_id; req.r4_add.origin = origin; dest = &req.r4_add.dest; } else { @@ -416,40 +450,23 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) { dest->prefixlen = p->prefixlen; gr_log_debug( - "%s route %pI4/%u (origin %s)", + "%s route %pI4/%u (origin %s, nh_id %u)", new ? "add" : "del", &dest->ip, dest->prefixlen, - gr_rt_origin_name(origin) + gr_nh_origin_name(origin), + nh_id ); } else { struct ip6_net *dest; - if (nt == NEXTHOP_TYPE_IPV4 || nt == NEXTHOP_TYPE_IPV4_IFINDEX) { - gr_log_err( - "impossible to add/del ipv6 route with nexthop type = %u (not " - "supported)", - nt - ); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - if (new) { req.r6_add = (struct gr_ip6_route_add_req) {.exist_ok = true, .vrf_id = 0}; req_type = GR_IP6_ROUTE_ADD; req_len = sizeof(struct gr_ip6_route_add_req); - if (nt == NEXTHOP_TYPE_IFINDEX || nt == NEXTHOP_TYPE_IPV6_IFINDEX) - // TOFIX with next API in grout - memcpy( - req.r6_add.nh.a, p->u.prefix6.s6_addr, sizeof(req.r6_add.nh) - ); - req.r4_add.nh = p->u.prefix4.s_addr; - if (nt == NEXTHOP_TYPE_IPV6 || nt == NEXTHOP_TYPE_IPV6_IFINDEX) - memcpy(req.r6_add.nh.a, - ng->nexthop->gate.ipv6.s6_addr, - sizeof(req.r6_add.nh)); + req.r6_add.nh_id = nh_id; req.r6_add.origin = origin; dest = &req.r6_add.dest; } else { @@ -468,11 +485,12 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) { dest->prefixlen = p->prefixlen; gr_log_debug( - "%s route %pI6/%u (origin %s)", + "%s route %pI6/%u (origin %s, nh_id %u)", new ? "add" : "del", &dest->ip, dest->prefixlen, - gr_rt_origin_name(origin) + gr_nh_origin_name(origin), + nh_id ); } @@ -486,3 +504,141 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) { return ZEBRA_DPLANE_REQUEST_SUCCESS; } + +enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx) { + uint32_t nh_id = dplane_ctx_get_nhe_id(ctx); + union { + struct gr_nh_add_req nh_add; + struct gr_nh_del_req nh_del; + } req; + const struct nexthop *nh; + struct gr_nexthop *gr_nh; + uint32_t req_type; + size_t req_len; + afi_t afi; + bool new; + + if (!nh_id) { + // it's supported by grout, but not by the linux kernel + gr_log_err("impossible to add/del nexthop in grout that does not have an ID"); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + + if (dplane_ctx_get_nhe_nh_grp_count(ctx)) { + // next group are not supported in grout + gr_log_err("impossible to add/del nexthop grout %u (nhg not supported)", nh_id); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + + if (dplane_ctx_get_nhe_vrf_id(ctx) != VRF_DEFAULT) { + gr_log_err( + "impossible to add/del nexthop on vrf %u (vrf not supported)", + dplane_ctx_get_vrf(ctx) + ); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + nh = dplane_ctx_get_nhe_ng(ctx)->nexthop; + if (nh->type == NEXTHOP_TYPE_BLACKHOLE) { + gr_log_err("impossible to add/del blackhole nexthop (not supported)"); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + + new = dplane_ctx_get_op(ctx) != DPLANE_OP_NH_DELETE; + if (new) { + req.nh_add = (struct gr_nh_add_req) {.exist_ok = true}; + + req_type = GR_NH_ADD; + req_len = sizeof(struct gr_nh_add_req); + + gr_nh = &req.nh_add.nh; + } else { + req.nh_del = (struct gr_nh_del_req) {.missing_ok = true}; + + req_type = GR_NH_DEL; + req_len = sizeof(struct gr_nh_del_req); + + gr_nh = &req.nh_del.nh; + } + gr_nh->nh_id = nh_id; + + if (!new) { + gr_log_debug("del nexthop id %u", nh_id); + goto end; + } + + gr_nh->type = GR_NH_T_L3; + gr_nh->vrf_id = 0; + afi = dplane_ctx_get_nhe_afi(ctx); + if (afi == AFI_IP) + gr_nh->af = GR_AF_IP4; + else + gr_nh->af = GR_AF_IP6; + + if (!nh->ifindex) { + gr_log_err("impossible to add/del nexthop in grout that does not have an ifindex"); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + if (nh->ifindex < GROUT_INDEX_OFFSET) { + gr_log_err("impossible to add/del nexthop on interface not managed by grout"); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + gr_nh->iface_id = nh->ifindex - GROUT_INDEX_OFFSET; + + switch (nh->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + memcpy(&gr_nh->ipv4, &nh->gate.ipv4, sizeof(gr_nh->ipv4)); + gr_log_debug("add nexthop id %u gw %pI4", nh_id, &gr_nh->ipv4); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + memcpy(&gr_nh->ipv6, &nh->gate.ipv6, sizeof(gr_nh->ipv6)); + gr_log_debug("add nexthop id %u gw %pI6", nh_id, &gr_nh->ipv6); + break; + case NEXTHOP_TYPE_IFINDEX: + gr_log_debug("add nexthop id %u ifindex %u", nh_id, gr_nh->iface_id); + break; + default: + gr_log_err("impossible to add nexthop %u (type %u not supported)", nh_id, nh->type); + return ZEBRA_DPLANE_REQUEST_FAILURE; + } + + gr_nh->origin = zebra2origin(dplane_ctx_get_nhe_type(ctx)); + if (!is_selfroute(gr_nh->origin)) { + gr_log_debug("no frr nexthop, skip it"); + return ZEBRA_DPLANE_REQUEST_SUCCESS; + } + +end: + if (grout_client_send_recv(req_type, req_len, &req, NULL) < 0) + return ZEBRA_DPLANE_REQUEST_FAILURE; + + return ZEBRA_DPLANE_REQUEST_SUCCESS; +} + +void grout_nexthop_change(bool new, struct gr_nexthop *gr_nh) { + struct nexthop nh = {.weight = 1}; + afi_t afi = AFI_UNSPEC; + int family, type; + + // XXX: grout is optional to have an ID for nexthop + // but in FRR, it's mandatory + if (gr_nh->nh_id == 0) { + gr_log_err("impossible to sync nexthop from grout that does not have an ID"); + return; + } + + if (grout_gr_nexthop_to_frr_nexthop(gr_nh, &nh, &family, new) < 0) + return; + + if (!new) { + zebra_nhg_kernel_del(gr_nh->nh_id, gr_nh->vrf_id); + return; + } + + afi = family2afi(family); + type = origin2zebra(gr_nh->origin, family, false); + SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE); + + zebra_nhg_kernel_find(gr_nh->nh_id, &nh, NULL, 0, gr_nh->vrf_id, afi, type, false, NULL); +} diff --git a/frr/rt_grout.h b/frr/rt_grout.h index 43918713a..8823a76da 100644 --- a/frr/rt_grout.h +++ b/frr/rt_grout.h @@ -12,5 +12,7 @@ void grout_route4_change(bool new, struct gr_ip4_route *gr_r4); void grout_route6_change(bool new, struct gr_ip6_route *gr_r6); enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx); +enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx); +void grout_nexthop_change(bool new, struct gr_nexthop *gr_nh); #endif /* _RT_GROUT_H */ diff --git a/frr/zebra_dplane_grout.c b/frr/zebra_dplane_grout.c index 6cf25efa2..348d9e385 100644 --- a/frr/zebra_dplane_grout.c +++ b/frr/zebra_dplane_grout.c @@ -36,10 +36,15 @@ static const char *plugin_name = "zebra_dplane_grout"; static void dplane_read_notifications(struct event *event); static void zebra_read_notifications(struct event *event); +struct grout_evt { + uint32_t type; + bool suppress_self_events; +}; + static int grout_notif_subscribe( struct gr_api_client **pgr_client, - const uint32_t *ev_types, - unsigned int nb_ev_types + const struct grout_evt *gr_evts, + unsigned int nb_gr_evts ) { struct gr_event_subscribe_req req; unsigned int i; @@ -52,9 +57,9 @@ static int grout_notif_subscribe( return -1; } - for (i = 0; i < nb_ev_types; i++) { - req.suppress_self_events = false; - req.ev_type = ev_types[i]; + for (i = 0; i < nb_gr_evts; i++) { + req.suppress_self_events = gr_evts[i].suppress_self_events; + req.ev_type = gr_evts[i].type; if (gr_api_client_send_recv( *pgr_client, GR_MAIN_EVENT_SUBSCRIBE, sizeof(req), &req, NULL @@ -77,19 +82,19 @@ static int grout_notif_subscribe( static void dplane_grout_connect(struct event *t) { struct event_loop *dg_master = dplane_get_thread_master(); - const uint32_t ev_types[] = { - GR_EVENT_IFACE_POST_ADD, - GR_EVENT_IFACE_STATUS_UP, - GR_EVENT_IFACE_STATUS_DOWN, - GR_EVENT_IFACE_POST_RECONFIG, - GR_EVENT_IFACE_PRE_REMOVE, - GR_EVENT_IP_ADDR_ADD, - GR_EVENT_IP6_ADDR_ADD, - GR_EVENT_IP_ADDR_DEL, - GR_EVENT_IP6_ADDR_DEL + static const struct grout_evt gr_evts[] = { + {.type = GR_EVENT_IFACE_POST_ADD, .suppress_self_events = true}, + {.type = GR_EVENT_IFACE_STATUS_UP, .suppress_self_events = true}, + {.type = GR_EVENT_IFACE_STATUS_DOWN, .suppress_self_events = true}, + {.type = GR_EVENT_IFACE_POST_RECONFIG, .suppress_self_events = true}, + {.type = GR_EVENT_IFACE_PRE_REMOVE, .suppress_self_events = true}, + {.type = GR_EVENT_IP_ADDR_ADD, .suppress_self_events = false}, + {.type = GR_EVENT_IP6_ADDR_ADD, .suppress_self_events = false}, + {.type = GR_EVENT_IP_ADDR_DEL, .suppress_self_events = false}, + {.type = GR_EVENT_IP6_ADDR_DEL, .suppress_self_events = false}, }; - if (grout_notif_subscribe(&grout_ctx.dplane_notifs, ev_types, ARRAY_SIZE(ev_types)) < 0) + if (grout_notif_subscribe(&grout_ctx.dplane_notifs, gr_evts, ARRAY_SIZE(gr_evts)) < 0) goto reschedule_connect; event_add_read( @@ -108,12 +113,15 @@ static void dplane_grout_connect(struct event *t) { } static void zebra_grout_connect(struct event *t) { - const uint32_t ev_types[] = { - GR_EVENT_IP_ROUTE_ADD, - GR_EVENT_IP_ROUTE_DEL, + static const struct grout_evt gr_evts[] = { + {.type = GR_EVENT_IP_ROUTE_ADD, .suppress_self_events = true}, + {.type = GR_EVENT_IP_ROUTE_DEL, .suppress_self_events = true}, + {.type = GR_EVENT_NEXTHOP_NEW, .suppress_self_events = true}, + {.type = GR_EVENT_NEXTHOP_DELETE, .suppress_self_events = true}, + {.type = GR_EVENT_NEXTHOP_UPDATE, .suppress_self_events = true}, }; - if (grout_notif_subscribe(&grout_ctx.zebra_notifs, ev_types, ARRAY_SIZE(ev_types)) < 0) + if (grout_notif_subscribe(&grout_ctx.zebra_notifs, gr_evts, ARRAY_SIZE(gr_evts)) < 0) goto reschedule_connect; event_add_read( @@ -149,6 +157,11 @@ static const char *gr_req_type_to_str(uint32_t e) { return TOSTRING(GR_IP6_ROUTE_ADD); case GR_IP6_ROUTE_DEL: return TOSTRING(GR_IP6_ROUTE_DEL); + case GR_NH_ADD: + return TOSTRING(GR_NH_ADD); + case GR_NH_DEL: + return TOSTRING(GR_NH_DEL); + default: return "unknown"; } @@ -213,6 +226,20 @@ static const char *gr_evt_to_str(uint32_t e) { return TOSTRING(GR_EVENT_IP6_ADDR_ADD); case GR_EVENT_IP6_ADDR_DEL: return TOSTRING(GR_EVENT_IP6_ADDR_DEL); + case GR_EVENT_IP_ROUTE_ADD: + return TOSTRING(GR_EVENT_IP_ROUTE_ADD); + case GR_EVENT_IP_ROUTE_DEL: + return TOSTRING(GR_EVENT_IP_ROUTE_DEL); + case GR_EVENT_IP6_ROUTE_ADD: + return TOSTRING(GR_EVENT_IP6_ROUTE_ADD); + case GR_EVENT_IP6_ROUTE_DEL: + return TOSTRING(GR_EVENT_IP6_ROUTE_DEL); + case GR_EVENT_NEXTHOP_NEW: + return TOSTRING(GR_EVENT_NEXTHOP_NEW); + case GR_EVENT_NEXTHOP_UPDATE: + return TOSTRING(GR_EVENT_NEXTHOP_UPDATE); + case GR_EVENT_NEXTHOP_DELETE: + return TOSTRING(GR_EVENT_NEXTHOP_DELETE); default: return "unknown"; } @@ -241,6 +268,7 @@ static void dplane_read_notifications(struct event *event) { case GR_EVENT_IFACE_STATUS_DOWN: case GR_EVENT_IFACE_POST_RECONFIG: new = true; + // fallthrough case GR_EVENT_IFACE_PRE_REMOVE: gr_p = PAYLOAD(gr_e); @@ -256,6 +284,7 @@ static void dplane_read_notifications(struct event *event) { case GR_EVENT_IP_ADDR_ADD: case GR_EVENT_IP6_ADDR_ADD: new = true; + // fallthrough case GR_EVENT_IP_ADDR_DEL: case GR_EVENT_IP6_ADDR_DEL: gr_nh = PAYLOAD(gr_e); @@ -305,6 +334,7 @@ static void zebra_read_notifications(struct event *event) { struct gr_api_event *gr_e = NULL; struct gr_ip4_route *gr_r4; struct gr_ip6_route *gr_r6; + struct gr_nexthop *gr_nh; bool new = false; if (gr_api_client_event_recv(grout_ctx.zebra_notifs, &gr_e) < 0 || gr_e == NULL) { @@ -320,6 +350,7 @@ static void zebra_read_notifications(struct event *event) { switch (gr_e->ev_type) { case GR_EVENT_IP_ROUTE_ADD: new = true; + // fallthrough case GR_EVENT_IP_ROUTE_DEL: gr_r4 = PAYLOAD(gr_e); @@ -335,6 +366,7 @@ static void zebra_read_notifications(struct event *event) { break; case GR_EVENT_IP6_ROUTE_ADD: new = true; + // fallthrough case GR_EVENT_IP6_ROUTE_DEL: gr_r6 = PAYLOAD(gr_e); @@ -348,6 +380,22 @@ static void zebra_read_notifications(struct event *event) { grout_route6_change(new, gr_r6); break; + case GR_EVENT_NEXTHOP_NEW: + case GR_EVENT_NEXTHOP_UPDATE: + new = true; + // fallthrough + case GR_EVENT_NEXTHOP_DELETE: + gr_nh = PAYLOAD(gr_e); + + gr_log_debug( + "%s nexthop %u notification (%s)", + new ? "add" : "del", + gr_nh->nh_id, + gr_evt_to_str(gr_e->ev_type) + ); + + grout_nexthop_change(new, gr_nh); + break; default: gr_log_debug( "Unknown notification %s (0x%x) received", @@ -383,8 +431,7 @@ static enum zebra_dplane_result zd_grout_process_update(struct zebra_dplane_ctx case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: - // As netlink_put_nexthop_update_msg when kernel doesn't support nexthop objects. - return ZEBRA_DPLANE_REQUEST_SUCCESS; + return grout_add_del_nexthop(ctx); case DPLANE_OP_NONE: return ZEBRA_DPLANE_REQUEST_SUCCESS; diff --git a/modules/infra/api/gr_nexthop.h b/modules/infra/api/gr_nexthop.h index 1a7435d3f..e9b82bbc7 100644 --- a/modules/infra/api/gr_nexthop.h +++ b/modules/infra/api/gr_nexthop.h @@ -33,6 +33,44 @@ typedef enum : uint8_t { GR_NH_T_DNAT, } gr_nh_type_t; +// Route install origin values shared by IPv4 and IPv6. +// See NH_ORIGIN_* in sys/route/nhop.h (BSD) and RTPROT_* in zebra/rt_netlink.h (FRR). +typedef enum : uint8_t { + GR_NH_ORIGIN_UNSPEC = 0, //!< (NH_ORIGIN_UNSPEC). + GR_NH_ORIGIN_REDIRECT = 1, //!< Installed implicitly by ICMP redirect (NH_ORIGIN_REDIRECT). + GR_NH_ORIGIN_LINK = 2, //!< Installed implicitly for local addresses (NH_ORIGIN_KERNEL). + GR_NH_ORIGIN_BOOT = 3, //!< Installed at boot?? (NH_ORIGIN_BOOT). + GR_NH_ORIGIN_USER = 4, //!< Installed explicitly by user (NH_ORIGIN_STATIC). + // Values 5 to 254 are allowed and are used by routing daemons. + GR_NH_ORIGIN_GATED = 8, // (RTPROT_GATED) + GR_NH_ORIGIN_RA = 9, // (RTPROT_RA) + GR_NH_ORIGIN_MRT = 10, // (RTPROT_MRT) + GR_NH_ORIGIN_ZEBRA = 11, // (RTPROT_ZEBRA) + GR_NH_ORIGIN_BIRD = 12, // (RTPROT_BIRD) + GR_NH_ORIGIN_DNROUTED = 13, // (RTPROT_DNROUTED) + GR_NH_ORIGIN_XORP = 14, // (RTPROT_XORP) + GR_NH_ORIGIN_NTK = 15, // (RTPROT_NTK) + GR_NH_ORIGIN_DHCP = 16, // (RTPROT_DHCP) + GR_NH_ORIGIN_MROUTED = 17, // (RTPROT_MROUTED) + GR_NH_ORIGIN_KEEPALIVED = 18, // (RTPROT_KEEPALIVED) + GR_NH_ORIGIN_BABEL = 42, // (RTPROT_BABEL) + GR_NH_ORIGIN_OPENR = 99, // (RTPROT_OPENR) + GR_NH_ORIGIN_BGP = 186, // (RTPROT_BGP) + GR_NH_ORIGIN_ISIS = 187, // (RTPROT_ISIS) + GR_NH_ORIGIN_OSPF = 188, // (RTPROT_OSPF) + GR_NH_ORIGIN_RIP = 189, // (RTPROT_RIP) + GR_NH_ORIGIN_RIPNG = 190, // (RTPROT_RIPNG from zebra) + GR_NH_ORIGIN_NHRP = 191, // (RTPROT_NHRP from zebra) + GR_NH_ORIGIN_EIGRP = 192, // (RTPROT_EIGRP) + GR_NH_ORIGIN_LDP = 193, // (RTPROT_LDP from zebra) + GR_NH_ORIGIN_SHARP = 194, // (RTPROT_SHARP from zebra) + GR_NH_ORIGIN_PBR = 195, // (RTPROT_PBR from zebra) + GR_NH_ORIGIN_ZSTATIC = 196, // (RTPROT_ZSTATIC from zebra) + GR_NH_ORIGIN_OPENFABRIC = 197, // (RTPROT_OPENFABIC from zebra) + GR_NH_ORIGIN_SRTE = 198, // (RTPROT_SRTE from zebra) + GR_NH_ORIGIN_INTERNAL = 255, //!< Reserved for internal use by grout. +} gr_nh_origin_t; + #define GR_NH_ID_UNSET UINT32_C(0) //! Nexthop structure exposed to the API. @@ -45,13 +83,14 @@ struct gr_nexthop { uint16_t vrf_id; //!< L3 VRF domain uint16_t iface_id; //!< interface associated with this nexthop struct rte_ether_addr mac; //!< link-layer address + uint8_t prefixlen; //!< only has meaning with GR_NH_F_LOCAL + gr_nh_origin_t origin; union { struct { } addr; ip4_addr_t ipv4; struct rte_ipv6_addr ipv6; }; - uint8_t prefixlen; //!< only has meaning with GR_NH_F_LOCAL }; //! Nexthop events. @@ -115,109 +154,71 @@ static inline const char *gr_nh_type_name(const struct gr_nexthop *nh) { return "?"; } -// Route install origin values shared by IPv4 and IPv6. -// See NH_ORIGIN_* in sys/route/nhop.h (BSD) and RTPROT_* in zebra/rt_netlink.h (FRR). -typedef enum : uint8_t { - GR_RT_ORIGIN_UNSPEC = 0, //!< (NH_ORIGIN_UNSPEC). - GR_RT_ORIGIN_REDIRECT = 1, //!< Installed implicitly by ICMP redirect (NH_ORIGIN_REDIRECT). - GR_RT_ORIGIN_LINK = 2, //!< Installed implicitly for local addresses (NH_ORIGIN_KERNEL). - GR_RT_ORIGIN_BOOT = 3, //!< Installed at boot?? (NH_ORIGIN_BOOT). - GR_RT_ORIGIN_USER = 4, //!< Installed explicitly by user (NH_ORIGIN_STATIC). - // Values 5 to 254 are allowed and are used by routing daemons. - GR_RT_ORIGIN_GATED = 8, // (RTPROT_GATED) - GR_RT_ORIGIN_RA = 9, // (RTPROT_RA) - GR_RT_ORIGIN_MRT = 10, // (RTPROT_MRT) - GR_RT_ORIGIN_ZEBRA = 11, // (RTPROT_ZEBRA) - GR_RT_ORIGIN_BIRD = 12, // (RTPROT_BIRD) - GR_RT_ORIGIN_DNROUTED = 13, // (RTPROT_DNROUTED) - GR_RT_ORIGIN_XORP = 14, // (RTPROT_XORP) - GR_RT_ORIGIN_NTK = 15, // (RTPROT_NTK) - GR_RT_ORIGIN_DHCP = 16, // (RTPROT_DHCP) - GR_RT_ORIGIN_MROUTED = 17, // (RTPROT_MROUTED) - GR_RT_ORIGIN_KEEPALIVED = 18, // (RTPROT_KEEPALIVED) - GR_RT_ORIGIN_BABEL = 42, // (RTPROT_BABEL) - GR_RT_ORIGIN_OPENR = 99, // (RTPROT_OPENR) - GR_RT_ORIGIN_BGP = 186, // (RTPROT_BGP) - GR_RT_ORIGIN_ISIS = 187, // (RTPROT_ISIS) - GR_RT_ORIGIN_OSPF = 188, // (RTPROT_OSPF) - GR_RT_ORIGIN_RIP = 189, // (RTPROT_RIP) - GR_RT_ORIGIN_RIPNG = 190, // (RTPROT_RIPNG from zebra) - GR_RT_ORIGIN_NHRP = 191, // (RTPROT_NHRP from zebra) - GR_RT_ORIGIN_EIGRP = 192, // (RTPROT_EIGRP) - GR_RT_ORIGIN_LDP = 193, // (RTPROT_LDP from zebra) - GR_RT_ORIGIN_SHARP = 194, // (RTPROT_SHARP from zebra) - GR_RT_ORIGIN_PBR = 195, // (RTPROT_PBR from zebra) - GR_RT_ORIGIN_ZSTATIC = 196, // (RTPROT_ZSTATIC from zebra) - GR_RT_ORIGIN_OPENFABRIC = 197, // (RTPROT_OPENFABIC from zebra) - GR_RT_ORIGIN_SRTE = 198, // (RTPROT_SRTE from zebra) - GR_RT_ORIGIN_INTERNAL = 255, //!< Reserved for internal use by grout. -} gr_rt_origin_t; - -static inline const char *gr_rt_origin_name(gr_rt_origin_t origin) { +static inline const char *gr_nh_origin_name(gr_nh_origin_t origin) { switch (origin) { - case GR_RT_ORIGIN_UNSPEC: + case GR_NH_ORIGIN_UNSPEC: return ""; - case GR_RT_ORIGIN_REDIRECT: + case GR_NH_ORIGIN_REDIRECT: return "redirect"; - case GR_RT_ORIGIN_LINK: + case GR_NH_ORIGIN_LINK: return "link"; - case GR_RT_ORIGIN_BOOT: + case GR_NH_ORIGIN_BOOT: return "boot"; - case GR_RT_ORIGIN_USER: + case GR_NH_ORIGIN_USER: return "user"; - case GR_RT_ORIGIN_GATED: + case GR_NH_ORIGIN_GATED: return "gated"; - case GR_RT_ORIGIN_RA: + case GR_NH_ORIGIN_RA: return "ra"; - case GR_RT_ORIGIN_MRT: + case GR_NH_ORIGIN_MRT: return "mrt"; - case GR_RT_ORIGIN_ZEBRA: + case GR_NH_ORIGIN_ZEBRA: return "zebra"; - case GR_RT_ORIGIN_BIRD: + case GR_NH_ORIGIN_BIRD: return "bird"; - case GR_RT_ORIGIN_DNROUTED: + case GR_NH_ORIGIN_DNROUTED: return "dnrouted"; - case GR_RT_ORIGIN_XORP: + case GR_NH_ORIGIN_XORP: return "xorp"; - case GR_RT_ORIGIN_NTK: + case GR_NH_ORIGIN_NTK: return "ntk"; - case GR_RT_ORIGIN_DHCP: + case GR_NH_ORIGIN_DHCP: return "dhcp"; - case GR_RT_ORIGIN_MROUTED: + case GR_NH_ORIGIN_MROUTED: return "mrouted"; - case GR_RT_ORIGIN_KEEPALIVED: + case GR_NH_ORIGIN_KEEPALIVED: return "keepalived"; - case GR_RT_ORIGIN_BABEL: + case GR_NH_ORIGIN_BABEL: return "babel"; - case GR_RT_ORIGIN_OPENR: + case GR_NH_ORIGIN_OPENR: return "openr"; - case GR_RT_ORIGIN_BGP: + case GR_NH_ORIGIN_BGP: return "bgp"; - case GR_RT_ORIGIN_ISIS: + case GR_NH_ORIGIN_ISIS: return "isis"; - case GR_RT_ORIGIN_OSPF: + case GR_NH_ORIGIN_OSPF: return "ospf"; - case GR_RT_ORIGIN_RIP: + case GR_NH_ORIGIN_RIP: return "rip"; - case GR_RT_ORIGIN_RIPNG: + case GR_NH_ORIGIN_RIPNG: return "ripng"; - case GR_RT_ORIGIN_NHRP: + case GR_NH_ORIGIN_NHRP: return "nhrp"; - case GR_RT_ORIGIN_EIGRP: + case GR_NH_ORIGIN_EIGRP: return "eigrp"; - case GR_RT_ORIGIN_LDP: + case GR_NH_ORIGIN_LDP: return "ldp"; - case GR_RT_ORIGIN_SHARP: + case GR_NH_ORIGIN_SHARP: return "sharp"; - case GR_RT_ORIGIN_PBR: + case GR_NH_ORIGIN_PBR: return "pbr"; - case GR_RT_ORIGIN_ZSTATIC: + case GR_NH_ORIGIN_ZSTATIC: return "zebra_static"; - case GR_RT_ORIGIN_OPENFABRIC: + case GR_NH_ORIGIN_OPENFABRIC: return "openfabric"; - case GR_RT_ORIGIN_SRTE: + case GR_NH_ORIGIN_SRTE: return "srte"; - case GR_RT_ORIGIN_INTERNAL: + case GR_NH_ORIGIN_INTERNAL: return "INTERNAL"; } return "?"; @@ -280,6 +281,7 @@ struct gr_nh_del_req { struct gr_nh_list_req { uint16_t vrf_id; + bool all; }; struct gr_nh_list_resp { diff --git a/modules/infra/api/nexthop.c b/modules/infra/api/nexthop.c index 9fe7db7d9..3c1bcf9bb 100644 --- a/modules/infra/api/nexthop.c +++ b/modules/infra/api/nexthop.c @@ -177,23 +177,24 @@ static struct gr_api_handler nh_del_handler = { struct list_context { uint16_t vrf_id; + bool all; struct gr_nexthop *nh; }; static void nh_list_cb(struct nexthop *nh, void *priv) { struct list_context *ctx = priv; - if (nh->flags & GR_NH_F_MCAST) - return; if (nh->vrf_id != ctx->vrf_id && ctx->vrf_id != UINT16_MAX) return; + if (!ctx->all && nh->origin == GR_NH_ORIGIN_INTERNAL) + return; gr_vec_add(ctx->nh, nh->base); } static struct api_out nh_list(const void *request, void **response) { const struct gr_nh_list_req *req = request; - struct list_context ctx = {.vrf_id = req->vrf_id, .nh = NULL}; + struct list_context ctx = {.vrf_id = req->vrf_id, .all = req->all, .nh = NULL}; struct gr_nh_list_resp *resp = NULL; size_t len; diff --git a/modules/infra/cli/events.c b/modules/infra/cli/events.c index 4ead2c082..1d8c5ee0b 100644 --- a/modules/infra/cli/events.c +++ b/modules/infra/cli/events.c @@ -73,7 +73,7 @@ static cmd_status_t events_show(const struct gr_api_client *c, const struct ec_p &r4->dest.ip, r4->dest.prefixlen, &r4->nh.ipv4, - gr_rt_origin_name(r4->origin)); + gr_nh_origin_name(r4->origin)); break; case GR_EVENT_IP_ROUTE_DEL: assert(e->payload_len == sizeof(*r4)); @@ -82,7 +82,7 @@ static cmd_status_t events_show(const struct gr_api_client *c, const struct ec_p &r4->dest.ip, r4->dest.prefixlen, &r4->nh.ipv4, - gr_rt_origin_name(r4->origin)); + gr_nh_origin_name(r4->origin)); break; case GR_EVENT_IP6_ROUTE_ADD: assert(e->payload_len == sizeof(*r6)); @@ -91,7 +91,7 @@ static cmd_status_t events_show(const struct gr_api_client *c, const struct ec_p &r6->dest.ip, r6->dest.prefixlen, &r6->nh.ipv6, - gr_rt_origin_name(r6->origin)); + gr_nh_origin_name(r6->origin)); break; case GR_EVENT_IP6_ROUTE_DEL: assert(e->payload_len == sizeof(*r6)); @@ -100,37 +100,40 @@ static cmd_status_t events_show(const struct gr_api_client *c, const struct ec_p &r6->dest.ip, r6->dest.prefixlen, &r6->nh.ipv6, - gr_rt_origin_name(r6->origin)); + gr_nh_origin_name(r6->origin)); break; case GR_EVENT_NEXTHOP_NEW: assert(e->payload_len == sizeof(*nh)); nh = PAYLOAD(e); - printf("> nh new: iface %d vrf %d " ADDR_F " " ETH_F "\n", + printf("> nh new: iface %d vrf %d " ADDR_F " " ETH_F " origin %s\n", nh->iface_id, nh->vrf_id, ADDR_W(nh->af), &nh->addr, - &nh->mac); + &nh->mac, + gr_nh_origin_name(nh->origin)); break; case GR_EVENT_NEXTHOP_DELETE: assert(e->payload_len == sizeof(*nh)); nh = PAYLOAD(e); - printf("> nh del: iface %d vrf %d " ADDR_F " " ETH_F "\n", + printf("> nh del: iface %d vrf %d " ADDR_F " " ETH_F " origin %s\n", nh->iface_id, nh->vrf_id, ADDR_W(nh->af), &nh->addr, - &nh->mac); + &nh->mac, + gr_nh_origin_name(nh->origin)); break; case GR_EVENT_NEXTHOP_UPDATE: assert(e->payload_len == sizeof(*nh)); nh = PAYLOAD(e); - printf("> nh update: iface %d vrf %d " ADDR_F " " ETH_F "\n", + printf("> nh update: iface %d vrf %d " ADDR_F " " ETH_F " origin %s\n", nh->iface_id, nh->vrf_id, ADDR_W(nh->af), &nh->addr, - &nh->mac); + &nh->mac, + gr_nh_origin_name(nh->origin)); break; default: printf("> unknown event 0x%08x\n", e->ev_type); diff --git a/modules/infra/cli/nexthop.c b/modules/infra/cli/nexthop.c index 047de7066..4881c47e8 100644 --- a/modules/infra/cli/nexthop.c +++ b/modules/infra/cli/nexthop.c @@ -59,7 +59,7 @@ static cmd_status_t show_config(const struct gr_api_client *c, const struct ec_p } static cmd_status_t nh_add(const struct gr_api_client *c, const struct ec_pnode *p) { - struct gr_nh_add_req req = {.exist_ok = true}; + struct gr_nh_add_req req = {.exist_ok = true, .nh.origin = GR_NH_ORIGIN_USER}; struct gr_iface iface; switch (arg_ip4(p, "IP", &req.nh.ipv4)) { @@ -131,6 +131,9 @@ static cmd_status_t nh_list(const struct gr_api_client *c, const struct ec_pnode scols_unref_table(table); return CMD_ERROR; } + + req.all = arg_str(p, "all") != NULL; + if (gr_api_client_send_recv(c, GR_NH_LIST, sizeof(req), &req, &resp_ptr) < 0) { scols_unref_table(table); return CMD_ERROR; @@ -147,6 +150,7 @@ static cmd_status_t nh_list(const struct gr_api_client *c, const struct ec_pnode scols_table_new_column(table, "IFACE", 0, 0); scols_table_new_column(table, "STATE", 0, 0); scols_table_new_column(table, "FLAGS", 0, 0); + scols_table_new_column(table, "ORIGIN", 0, 0); scols_table_set_column_separator(table, " "); for (size_t i = 0; i < resp->n_nhs; i++) { @@ -182,6 +186,7 @@ static cmd_status_t nh_list(const struct gr_api_client *c, const struct ec_pnode buf[n - 1] = '\0'; scols_line_sprintf(line, 8, "%s", buf); + scols_line_sprintf(line, 9, "%s", gr_nh_origin_name(nh->origin)); } scols_print_table(table); @@ -269,10 +274,11 @@ static int ctx_init(struct ec_node *root) { return ret; ret = CLI_COMMAND( CLI_CONTEXT(root, CTX_SHOW), - "nexthop [vrf VRF]", + "nexthop [vrf VRF] [all]", nh_list, "List all next hops.", - with_help("L3 routing domain ID.", ec_node_uint("VRF", 0, UINT16_MAX - 1, 10)) + with_help("L3 routing domain ID.", ec_node_uint("VRF", 0, UINT16_MAX - 1, 10)), + with_help("All next hops including internal ones.", ec_node_str("all", "all")) ); if (ret < 0) return ret; diff --git a/modules/infra/control/nexthop.c b/modules/infra/control/nexthop.c index 11db1d80d..ddf97ead5 100644 --- a/modules/infra/control/nexthop.c +++ b/modules/infra/control/nexthop.c @@ -161,7 +161,7 @@ struct nexthop *nexthop_new(const struct gr_nexthop *base) { nh = data; nh->base = *base; - if (!(nh->flags & GR_NH_F_MCAST)) + if (nh->origin != GR_NH_ORIGIN_INTERNAL) gr_event_push(GR_EVENT_NEXTHOP_NEW, nh); return nh; @@ -283,7 +283,7 @@ void nexthop_decref(struct nexthop *nh) { rte_pktmbuf_free(m); m = next; } - if (!(nh->flags & GR_NH_F_MCAST)) + if (nh->origin != GR_NH_ORIGIN_INTERNAL) gr_event_push(GR_EVENT_NEXTHOP_DELETE, nh); const struct nexthop_type_ops *ops = type_ops[nh->type]; if (ops != NULL && ops->free != NULL) diff --git a/modules/ip/api/dnat44.c b/modules/ip/api/dnat44.c index c7d6d28ee..66b800d4b 100644 --- a/modules/ip/api/dnat44.c +++ b/modules/ip/api/dnat44.c @@ -36,13 +36,14 @@ static struct api_out dnat44_add(const void *request, void ** /*response*/) { .vrf_id = iface->vrf_id, .iface_id = iface->id, .ipv4 = req->rule.match, + .origin = GR_NH_ORIGIN_INTERNAL, }); if (nh == NULL) return api_out(ENOMEM, 0); data = dnat44_nh_data(nh); data->replace = req->rule.replace; - ret = rib4_insert(iface->vrf_id, req->rule.match, 32, GR_RT_ORIGIN_INTERNAL, nh); + ret = rib4_insert(iface->vrf_id, req->rule.match, 32, GR_NH_ORIGIN_INTERNAL, nh); if (ret < 0) return api_out(-ret, 0); diff --git a/modules/ip/api/gr_ip4.h b/modules/ip/api/gr_ip4.h index a85be756d..acd60cd31 100644 --- a/modules/ip/api/gr_ip4.h +++ b/modules/ip/api/gr_ip4.h @@ -19,7 +19,7 @@ struct gr_ip4_ifaddr { struct gr_ip4_route { struct ip4_net dest; struct gr_nexthop nh; - gr_rt_origin_t origin; + gr_nh_origin_t origin; }; #define GR_IP4_MODULE 0xf00d @@ -33,7 +33,7 @@ struct gr_ip4_route_add_req { struct ip4_net dest; ip4_addr_t nh; uint32_t nh_id; - gr_rt_origin_t origin; + gr_nh_origin_t origin; uint8_t exist_ok; }; diff --git a/modules/ip/cli/route.c b/modules/ip/cli/route.c index 388e9a04b..cce68424d 100644 --- a/modules/ip/cli/route.c +++ b/modules/ip/cli/route.c @@ -16,7 +16,7 @@ #include static cmd_status_t route4_add(const struct gr_api_client *c, const struct ec_pnode *p) { - struct gr_ip4_route_add_req req = {.exist_ok = true, .origin = GR_RT_ORIGIN_USER}; + struct gr_ip4_route_add_req req = {.exist_ok = true, .origin = GR_NH_ORIGIN_USER}; if (arg_ip4_net(p, "DEST", &req.dest, true) < 0) return CMD_ERROR; @@ -78,7 +78,7 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p scols_line_sprintf(line, 0, "%u", route->nh.vrf_id); scols_line_sprintf(line, 1, IP4_F "/%hhu", &route->dest.ip, route->dest.prefixlen); scols_line_sprintf(line, 2, IP4_F, &route->nh.ipv4); - scols_line_sprintf(line, 3, "%s", gr_rt_origin_name(route->origin)); + scols_line_sprintf(line, 3, "%s", gr_nh_origin_name(route->origin)); if (route->nh.nh_id != GR_NH_ID_UNSET) scols_line_sprintf(line, 4, "%u", route->nh.nh_id); else diff --git a/modules/ip/control/address.c b/modules/ip/control/address.c index a0946e5c9..efbfecb07 100644 --- a/modules/ip/control/address.c +++ b/modules/ip/control/address.c @@ -89,6 +89,7 @@ static struct api_out addr_add(const void *request, void ** /*response*/) { .iface_id = iface->id, .ipv4 = req->addr.addr.ip, .prefixlen = req->addr.addr.prefixlen, + .origin = GR_NH_ORIGIN_LINK, }; if (iface_get_eth_addr(iface->id, &base.mac) < 0 && errno != EOPNOTSUPP) return api_out(errno, 0); @@ -96,7 +97,7 @@ static struct api_out addr_add(const void *request, void ** /*response*/) { if ((nh = nexthop_new(&base)) == NULL) return api_out(errno, 0); - if ((ret = rib4_insert(iface->vrf_id, nh->ipv4, nh->prefixlen, GR_RT_ORIGIN_LINK, nh)) < 0) + if ((ret = rib4_insert(iface->vrf_id, nh->ipv4, nh->prefixlen, GR_NH_ORIGIN_LINK, nh)) < 0) return api_out(-ret, 0); gr_vec_add(ifaddrs->nh, nh); diff --git a/modules/ip/control/gr_ip4_control.h b/modules/ip/control/gr_ip4_control.h index c3f0247de..5ce5fc42e 100644 --- a/modules/ip/control/gr_ip4_control.h +++ b/modules/ip/control/gr_ip4_control.h @@ -33,7 +33,7 @@ int rib4_insert( uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen, - gr_rt_origin_t origin, + gr_nh_origin_t origin, struct nexthop *nh ); int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen); diff --git a/modules/ip/control/nexthop.c b/modules/ip/control/nexthop.c index 84a396001..28fe91b2f 100644 --- a/modules/ip/control/nexthop.c +++ b/modules/ip/control/nexthop.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +50,7 @@ void nh4_unreachable_cb(struct rte_mbuf *m) { .vrf_id = nh->vrf_id, .iface_id = nh->iface_id, .ipv4 = dst, + .origin = GR_NH_ORIGIN_INTERNAL, }); } @@ -63,7 +63,7 @@ void nh4_unreachable_cb(struct rte_mbuf *m) { // Create an associated /32 route so that next packets take it // in priority with a single route lookup. - if (rib4_insert(nh->vrf_id, dst, 32, GR_RT_ORIGIN_INTERNAL, remote) < 0) { + if (rib4_insert(nh->vrf_id, dst, 32, GR_NH_ORIGIN_INTERNAL, remote) < 0) { LOG(ERR, "failed to insert route: %s", strerror(errno)); goto free; } @@ -128,13 +128,14 @@ void arp_probe_input_cb(struct rte_mbuf *m) { .vrf_id = iface->vrf_id, .iface_id = iface->id, .ipv4 = sip, + .origin = GR_NH_ORIGIN_INTERNAL, }); if (nh == NULL) { LOG(ERR, "ip4_nexthop_new: %s", strerror(errno)); goto free; } // Add an internal /32 route to reference the newly created nexthop. - if (rib4_insert(iface->vrf_id, sip, 32, GR_RT_ORIGIN_INTERNAL, nh) < 0) { + if (rib4_insert(iface->vrf_id, sip, 32, GR_NH_ORIGIN_INTERNAL, nh) < 0) { LOG(ERR, "ip4_nexthop_insert: %s", strerror(errno)); goto free; } @@ -149,7 +150,6 @@ void arp_probe_input_cb(struct rte_mbuf *m) { nh->ucast_probes = 0; nh->bcast_probes = 0; nh->mac = arp->arp_data.arp_sha; - gr_event_push(GR_EVENT_NEXTHOP_UPDATE, nh); } if (arp->arp_opcode == RTE_BE16(RTE_ARP_OP_REQUEST)) { @@ -188,7 +188,7 @@ void arp_probe_input_cb(struct rte_mbuf *m) { } static int nh4_add(struct nexthop *nh) { - return rib4_insert(nh->vrf_id, nh->ipv4, 32, GR_RT_ORIGIN_INTERNAL, nh); + return rib4_insert(nh->vrf_id, nh->ipv4, 32, GR_NH_ORIGIN_INTERNAL, nh); } static void nh4_del(struct nexthop *nh) { diff --git a/modules/ip/control/route.c b/modules/ip/control/route.c index 9fe7ffc29..51a165f18 100644 --- a/modules/ip/control/route.c +++ b/modules/ip/control/route.c @@ -29,7 +29,7 @@ static struct rte_rib **vrf_ribs; static struct rte_rib_conf rib_conf = { - .ext_sz = sizeof(gr_rt_origin_t), + .ext_sz = sizeof(gr_nh_origin_t), .max_nodes = IP4_MAX_ROUTES, }; @@ -126,13 +126,13 @@ int rib4_insert( uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen, - gr_rt_origin_t origin, + gr_nh_origin_t origin, struct nexthop *nh ) { struct rte_rib *rib = get_or_create_rib(vrf_id); struct nexthop *existing; struct rte_rib_node *rn; - gr_rt_origin_t *o; + gr_nh_origin_t *o; int ret; nexthop_incref(nh); @@ -156,7 +156,7 @@ int rib4_insert( o = rte_rib_get_ext(rn); *o = origin; fib4_insert(vrf_id, ip, prefixlen, nh); - if (origin != GR_RT_ORIGIN_INTERNAL) { + if (origin != GR_NH_ORIGIN_INTERNAL) { gr_event_push( GR_EVENT_IP_ROUTE_ADD, &(struct gr_ip4_route) { @@ -175,7 +175,7 @@ int rib4_insert( int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen) { struct rte_rib *rib = get_rib(vrf_id); - gr_rt_origin_t *o, origin; + gr_nh_origin_t *o, origin; struct rte_rib_node *rn; struct nexthop *nh; uintptr_t nh_id; @@ -195,7 +195,7 @@ int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen) { rte_rib_remove(rib, rte_be_to_cpu_32(ip), prefixlen); fib4_remove(vrf_id, ip, prefixlen); - if (origin != GR_RT_ORIGIN_INTERNAL) { + if (origin != GR_NH_ORIGIN_INTERNAL) { gr_event_push( GR_EVENT_IP_ROUTE_DEL, &(struct gr_ip4_route) { @@ -215,7 +215,7 @@ static struct api_out route4_add(const void *request, void ** /*response*/) { struct nexthop *nh; int ret; - if (req->origin == GR_RT_ORIGIN_INTERNAL) + if (req->origin == GR_NH_ORIGIN_INTERNAL) return api_out(EINVAL, 0); if (req->nh_id != GR_NH_ID_UNSET) { @@ -237,6 +237,7 @@ static struct api_out route4_add(const void *request, void ** /*response*/) { .vrf_id = req->vrf_id, .iface_id = nh->iface_id, .ipv4 = req->nh, + .origin = req->origin, }); if (nh == NULL) return api_out(errno, 0); @@ -287,7 +288,7 @@ static struct api_out route4_get(const void *request, void **response) { static int route4_count(uint16_t vrf_id) { struct rte_rib_node *rn = NULL; - gr_rt_origin_t *origin; + gr_nh_origin_t *origin; struct rte_rib *rib; int num; @@ -298,13 +299,13 @@ static int route4_count(uint16_t vrf_id) { num = 0; while ((rn = rte_rib_get_nxt(rib, 0, 0, rn, RTE_RIB_GET_NXT_ALL)) != NULL) { origin = rte_rib_get_ext(rn); - if (*origin != GR_RT_ORIGIN_INTERNAL) + if (*origin != GR_NH_ORIGIN_INTERNAL) num++; } // FIXME: remove this when rte_rib_get_nxt returns a default route, if any is configured if ((rn = rte_rib_lookup_exact(rib, 0, 0)) != NULL) { origin = rte_rib_get_ext(rn); - if (*origin != GR_RT_ORIGIN_INTERNAL) + if (*origin != GR_NH_ORIGIN_INTERNAL) num++; } @@ -314,7 +315,7 @@ static int route4_count(uint16_t vrf_id) { static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_id) { struct rte_rib_node *rn = NULL; struct gr_ip4_route *r; - gr_rt_origin_t *origin; + gr_nh_origin_t *origin; struct rte_rib *rib; uintptr_t nh_id; uint32_t ip; @@ -324,7 +325,7 @@ static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_ while ((rn = rte_rib_get_nxt(rib, 0, 0, rn, RTE_RIB_GET_NXT_ALL)) != NULL) { origin = rte_rib_get_ext(rn); - if (*origin == GR_RT_ORIGIN_INTERNAL) + if (*origin == GR_NH_ORIGIN_INTERNAL) continue; r = &resp->routes[resp->n_routes++]; rte_rib_get_nh(rn, &nh_id); @@ -337,7 +338,7 @@ static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_ // FIXME: remove this when rte_rib_get_nxt returns a default route, if any is configured if ((rn = rte_rib_lookup_exact(rib, 0, 0)) != NULL) { origin = rte_rib_get_ext(rn); - if (*origin == GR_RT_ORIGIN_INTERNAL) + if (*origin == GR_NH_ORIGIN_INTERNAL) return; r = &resp->routes[resp->n_routes++]; rte_rib_get_nh(rn, &nh_id); diff --git a/modules/ip6/api/gr_ip6.h b/modules/ip6/api/gr_ip6.h index 32db7f355..63cce41ca 100644 --- a/modules/ip6/api/gr_ip6.h +++ b/modules/ip6/api/gr_ip6.h @@ -19,7 +19,7 @@ struct gr_ip6_ifaddr { struct gr_ip6_route { struct ip6_net dest; struct gr_nexthop nh; - gr_rt_origin_t origin; + gr_nh_origin_t origin; }; #define GR_IP6_MODULE 0xfeed @@ -33,7 +33,7 @@ struct gr_ip6_route_add_req { struct ip6_net dest; struct rte_ipv6_addr nh; uint32_t nh_id; - gr_rt_origin_t origin; + gr_nh_origin_t origin; uint8_t exist_ok; }; diff --git a/modules/ip6/cli/route.c b/modules/ip6/cli/route.c index 4a1777bf0..b6d7e9845 100644 --- a/modules/ip6/cli/route.c +++ b/modules/ip6/cli/route.c @@ -16,7 +16,7 @@ #include static cmd_status_t route6_add(const struct gr_api_client *c, const struct ec_pnode *p) { - struct gr_ip6_route_add_req req = {.exist_ok = true, .origin = GR_RT_ORIGIN_USER}; + struct gr_ip6_route_add_req req = {.exist_ok = true, .origin = GR_NH_ORIGIN_USER}; if (arg_ip6_net(p, "DEST", &req.dest, true) < 0) return CMD_ERROR; @@ -78,7 +78,7 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p scols_line_sprintf(line, 0, "%u", route->nh.vrf_id); scols_line_sprintf(line, 1, IP6_F "/%hhu", &route->dest, route->dest.prefixlen); scols_line_sprintf(line, 2, IP6_F, &route->nh.ipv6); - scols_line_sprintf(line, 3, "%s", gr_rt_origin_name(route->origin)); + scols_line_sprintf(line, 3, "%s", gr_nh_origin_name(route->origin)); if (route->nh.nh_id != GR_NH_ID_UNSET) scols_line_sprintf(line, 4, "%u", route->nh.nh_id); else diff --git a/modules/ip6/control/address.c b/modules/ip6/control/address.c index b1c584722..0cd729fc4 100644 --- a/modules/ip6/control/address.c +++ b/modules/ip6/control/address.c @@ -112,6 +112,7 @@ static int mcast6_addr_add(const struct iface *iface, const struct rte_ipv6_addr .vrf_id = iface->vrf_id, .iface_id = iface->id, .ipv6 = *ip, + .origin = GR_NH_ORIGIN_INTERNAL, }; rte_ether_mcast_from_ipv6(&base.mac, ip); @@ -181,6 +182,7 @@ iface6_addr_add(const struct iface *iface, const struct rte_ipv6_addr *ip, uint8 .iface_id = iface->id, .ipv6 = *ip, .prefixlen = prefixlen, + .origin = GR_NH_ORIGIN_LINK, }; if ((ret = iface_get_eth_addr(iface->id, &base.mac)) < 0 && errno != EOPNOTSUPP) return errno_set(-ret); @@ -188,7 +190,7 @@ iface6_addr_add(const struct iface *iface, const struct rte_ipv6_addr *ip, uint8 if ((nh = nexthop_new(&base)) == NULL) return errno_set(-errno); - ret = rib6_insert(iface->vrf_id, iface->id, ip, nh->prefixlen, GR_RT_ORIGIN_LINK, nh); + ret = rib6_insert(iface->vrf_id, iface->id, ip, nh->prefixlen, GR_NH_ORIGIN_LINK, nh); if (ret < 0) return errno_set(-ret); diff --git a/modules/ip6/control/gr_ip6_control.h b/modules/ip6/control/gr_ip6_control.h index fb47b87a3..579553973 100644 --- a/modules/ip6/control/gr_ip6_control.h +++ b/modules/ip6/control/gr_ip6_control.h @@ -30,7 +30,7 @@ int rib6_insert( uint16_t iface_id, const struct rte_ipv6_addr *, uint8_t prefixlen, - gr_rt_origin_t origin, + gr_nh_origin_t origin, struct nexthop *nh ); int rib6_delete( diff --git a/modules/ip6/control/nexthop.c b/modules/ip6/control/nexthop.c index caeca897f..c307712ff 100644 --- a/modules/ip6/control/nexthop.c +++ b/modules/ip6/control/nexthop.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -52,6 +51,7 @@ void nh6_unreachable_cb(struct rte_mbuf *m) { .vrf_id = nh->vrf_id, .iface_id = nh->iface_id, .ipv6 = *dst, + .origin = GR_NH_ORIGIN_INTERNAL, }); } @@ -69,7 +69,7 @@ void nh6_unreachable_cb(struct rte_mbuf *m) { nh->iface_id, dst, RTE_IPV6_MAX_DEPTH, - GR_RT_ORIGIN_INTERNAL, + GR_NH_ORIGIN_INTERNAL, remote ); if (ret < 0) { @@ -164,6 +164,7 @@ void ndp_probe_input_cb(struct rte_mbuf *m) { .vrf_id = iface->vrf_id, .iface_id = iface->id, .ipv6 = *remote, + .origin = GR_NH_ORIGIN_INTERNAL, }); if (nh == NULL) { LOG(ERR, "ip6_nexthop_new: %s", strerror(errno)); @@ -176,7 +177,7 @@ void ndp_probe_input_cb(struct rte_mbuf *m) { iface->id, remote, RTE_IPV6_MAX_DEPTH, - GR_RT_ORIGIN_INTERNAL, + GR_NH_ORIGIN_INTERNAL, nh ); if (ret < 0) { @@ -194,7 +195,6 @@ void ndp_probe_input_cb(struct rte_mbuf *m) { nh->ucast_probes = 0; nh->bcast_probes = 0; nh->mac = mac; - gr_event_push(GR_EVENT_NEXTHOP_UPDATE, nh); } if (icmp6->type == ICMP6_TYPE_NEIGH_SOLICIT && local != NULL) { @@ -232,7 +232,7 @@ void ndp_probe_input_cb(struct rte_mbuf *m) { } static int nh6_add(struct nexthop *nh) { - return rib6_insert(nh->vrf_id, nh->iface_id, &nh->ipv6, 128, GR_RT_ORIGIN_INTERNAL, nh); + return rib6_insert(nh->vrf_id, nh->iface_id, &nh->ipv6, 128, GR_NH_ORIGIN_INTERNAL, nh); } static void nh6_del(struct nexthop *nh) { diff --git a/modules/ip6/control/route.c b/modules/ip6/control/route.c index 09c361e26..8e1e3b1bf 100644 --- a/modules/ip6/control/route.c +++ b/modules/ip6/control/route.c @@ -28,7 +28,7 @@ static struct rte_rib6 **vrf_ribs; static struct rte_rib6_conf rib6_conf = { - .ext_sz = sizeof(gr_rt_origin_t), + .ext_sz = sizeof(gr_nh_origin_t), .max_nodes = IP6_MAX_ROUTES, }; @@ -137,7 +137,7 @@ int rib6_insert( uint16_t iface_id, const struct rte_ipv6_addr *ip, uint8_t prefixlen, - gr_rt_origin_t origin, + gr_nh_origin_t origin, struct nexthop *nh ) { struct rte_rib6 *rib = get_or_create_rib6(vrf_id); @@ -145,7 +145,7 @@ int rib6_insert( struct rte_ipv6_addr tmp; struct rte_rib6_node *rn; struct nexthop *existing; - gr_rt_origin_t *o; + gr_nh_origin_t *o; int ret; nexthop_incref(nh); @@ -170,7 +170,7 @@ int rib6_insert( o = rte_rib6_get_ext(rn); *o = origin; fib6_insert(vrf_id, iface_id, scoped_ip, prefixlen, nh); - if (origin != GR_RT_ORIGIN_INTERNAL) { + if (origin != GR_NH_ORIGIN_INTERNAL) { gr_event_push( GR_EVENT_IP6_ROUTE_ADD, &(struct gr_ip6_route) { @@ -195,7 +195,7 @@ int rib6_delete( ) { struct rte_rib6 *rib = get_rib6(vrf_id); const struct rte_ipv6_addr *scoped_ip; - gr_rt_origin_t *o, origin; + gr_nh_origin_t *o, origin; struct rte_ipv6_addr tmp; struct rte_rib6_node *rn; struct nexthop *nh; @@ -216,7 +216,7 @@ int rib6_delete( rte_rib6_remove(rib, scoped_ip, prefixlen); - if (origin != GR_RT_ORIGIN_INTERNAL) { + if (origin != GR_NH_ORIGIN_INTERNAL) { gr_event_push( GR_EVENT_IP6_ROUTE_DEL, &(struct gr_ip6_route) { @@ -236,7 +236,7 @@ static struct api_out route6_add(const void *request, void ** /*response*/) { struct nexthop *nh; int ret; - if (req->origin == GR_RT_ORIGIN_INTERNAL) + if (req->origin == GR_NH_ORIGIN_INTERNAL) return api_out(EINVAL, 0); if (req->nh_id != GR_NH_ID_UNSET) { @@ -258,6 +258,7 @@ static struct api_out route6_add(const void *request, void ** /*response*/) { .vrf_id = nh->vrf_id, .iface_id = nh->iface_id, .ipv6 = req->nh, + .origin = req->origin, }); if (nh == NULL) return api_out(errno, 0); @@ -318,7 +319,7 @@ static struct api_out route6_get(const void *request, void **response) { static int route6_count(uint16_t vrf_id) { struct rte_ipv6_addr zero = RTE_IPV6_ADDR_UNSPEC; struct rte_rib6_node *rn = NULL; - gr_rt_origin_t *origin; + gr_nh_origin_t *origin; struct rte_rib6 *rib; int num; @@ -329,13 +330,13 @@ static int route6_count(uint16_t vrf_id) { num = 0; while ((rn = rte_rib6_get_nxt(rib, &zero, 0, rn, RTE_RIB6_GET_NXT_ALL)) != NULL) { origin = rte_rib6_get_ext(rn); - if (*origin != GR_RT_ORIGIN_INTERNAL) + if (*origin != GR_NH_ORIGIN_INTERNAL) num++; } // check if there is a default route configured if ((rn = rte_rib6_lookup_exact(rib, &zero, 0)) != NULL) { origin = rte_rib6_get_ext(rn); - if (*origin != GR_RT_ORIGIN_INTERNAL) + if (*origin != GR_NH_ORIGIN_INTERNAL) num++; } @@ -347,7 +348,7 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_ struct rte_rib6_node *rn = NULL; struct rte_ipv6_addr tmp; struct gr_ip6_route *r; - gr_rt_origin_t *origin; + gr_nh_origin_t *origin; struct rte_rib6 *rib; uintptr_t nh_id; @@ -356,7 +357,7 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_ while ((rn = rte_rib6_get_nxt(rib, &zero, 0, rn, RTE_RIB6_GET_NXT_ALL)) != NULL) { origin = rte_rib6_get_ext(rn); - if (*origin == GR_RT_ORIGIN_INTERNAL) + if (*origin == GR_NH_ORIGIN_INTERNAL) continue; r = &resp->routes[resp->n_routes++]; rte_rib6_get_nh(rn, &nh_id); @@ -369,7 +370,7 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_ // check if there is a default route configured if ((rn = rte_rib6_lookup_exact(rib, &zero, 0)) != NULL) { origin = rte_rib6_get_ext(rn); - if (*origin == GR_RT_ORIGIN_INTERNAL) + if (*origin == GR_NH_ORIGIN_INTERNAL) return; r = &resp->routes[resp->n_routes++]; rte_rib6_get_nh(rn, &nh_id); diff --git a/modules/srv6/control/localsid.c b/modules/srv6/control/localsid.c index 24d27cdad..75f5847c8 100644 --- a/modules/srv6/control/localsid.c +++ b/modules/srv6/control/localsid.c @@ -22,6 +22,7 @@ static struct api_out srv6_localsid_add(const void *request, void ** /*response* .vrf_id = req->l.vrf_id, .iface_id = GR_IFACE_ID_UNDEF, .ipv6 = req->l.lsid, + .origin = GR_NH_ORIGIN_LINK, }; struct nexthop *nh; int r; @@ -34,7 +35,7 @@ static struct api_out srv6_localsid_add(const void *request, void ** /*response* data->behavior = req->l.behavior; data->out_vrf_id = req->l.out_vrf_id; data->flags = req->l.flags; - r = rib6_insert(req->l.vrf_id, GR_IFACE_ID_UNDEF, &req->l.lsid, 128, GR_RT_ORIGIN_LINK, nh); + r = rib6_insert(req->l.vrf_id, GR_IFACE_ID_UNDEF, &req->l.lsid, 128, GR_NH_ORIGIN_LINK, nh); if (r < 0) return api_out(-r, 0); diff --git a/modules/srv6/control/route.c b/modules/srv6/control/route.c index 8e6a989d5..5b3d4362e 100644 --- a/modules/srv6/control/route.c +++ b/modules/srv6/control/route.c @@ -56,6 +56,7 @@ static struct api_out srv6_route_add(const void *request, void ** /*response*/) .flags = GR_NH_F_GATEWAY | GR_NH_F_STATIC, .vrf_id = req->r.key.vrf_id, .iface_id = GR_IFACE_ID_UNDEF, + .origin = GR_NH_ORIGIN_LINK, }; struct nexthop *nh; int ret; @@ -101,7 +102,7 @@ static struct api_out srv6_route_add(const void *request, void ** /*response*/) GR_IFACE_ID_UNDEF, &req->r.key.dest6.ip, req->r.key.dest6.prefixlen, - GR_RT_ORIGIN_LINK, + GR_NH_ORIGIN_LINK, nh ); else @@ -109,7 +110,7 @@ static struct api_out srv6_route_add(const void *request, void ** /*response*/) req->r.key.vrf_id, req->r.key.dest4.ip, req->r.key.dest4.prefixlen, - GR_RT_ORIGIN_LINK, + GR_NH_ORIGIN_LINK, nh ); diff --git a/smoke/nexthop_ageing_test.sh b/smoke/nexthop_ageing_test.sh index be60dceed..c99704013 100755 --- a/smoke/nexthop_ageing_test.sh +++ b/smoke/nexthop_ageing_test.sh @@ -9,7 +9,7 @@ check_nexthop() { local expect_reacheable="$2" local timeout=5 for i in $(seq 1 $timeout); do - grcli show nexthop | grep -qE "$ip.+reachable"; + grcli show nexthop all | grep -qE "$ip.+reachable"; local result=$? if [ "$expect_reacheable" = "true" ] && [ "$result" -eq 0 ]; then diff --git a/subprojects/packagefiles/frr/meson-add-dependency-definition.patch b/subprojects/packagefiles/frr/meson-add-dependency-definition.patch index d688960e6..b13a75be7 100644 --- a/subprojects/packagefiles/frr/meson-add-dependency-definition.patch +++ b/subprojects/packagefiles/frr/meson-add-dependency-definition.patch @@ -1,13 +1,13 @@ -From 567fc4fe322a8a88e6a520d06d024f2dfbab96f6 Mon Sep 17 00:00:00 2001 +From 5745031d387c18ed2da7d3cbcce5e2525f9d73b7 Mon Sep 17 00:00:00 2001 From: Maxime Leroy Date: Fri, 23 May 2025 17:44:02 +0200 Subject: [PATCH] meson add dependency definition Signed-off-by: Maxime Leroy --- - frr_install.sh | 35 ++++++++++++++++++++++ - meson.build | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 115 insertions(+) + frr_install.sh | 35 +++++++++++++++++++++ + meson.build | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 120 insertions(+) create mode 100644 frr_install.sh create mode 100644 meson.build @@ -54,10 +54,10 @@ index 0000000..1e40167 +}" "$conf_file" diff --git a/meson.build b/meson.build new file mode 100644 -index 0000000..5518634 +index 0000000..3153050 --- /dev/null +++ b/meson.build -@@ -0,0 +1,80 @@ +@@ -0,0 +1,85 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2025 Maxime Leroy, Free Mobile + @@ -88,6 +88,12 @@ index 0000000..5518634 +group_name = run_command('id', '-gn', check: true).stdout().strip() +extra_configure_option = '--enable-user=' + user_name + ' ' + '--enable-group=' + group_name + ++buildtype = get_option('buildtype') ++debug = buildtype.startswith('debug') ++if debug ++ extra_configure_option += ' --enable-dev-build' ++endif ++ +configure = custom_target( + 'configure', + output: configure_stamp, @@ -97,7 +103,7 @@ index 0000000..5518634 + '"' + srcdir + '/configure" ' + + '--prefix="' + prefix + '" ' + + '--with-moduledir="' + moduledir + '" ' + -+ '--disable-doc ' + ++ '--disable-doc --enable-multipath=1 ' + + '--disable-ripd --disable-ripngd --disable-ospfd --disable-ospf6d ' + + '--disable-ldpd --disable-nhrpd --disable-eigrpd --disable-babeld ' + + '--disable-isisd --disable-pimd --disable-pim6d --disable-pbrd --disable-fabricd ' + @@ -129,7 +135,6 @@ index 0000000..5518634 + '-D_GNU_SOURCE', + '-fms-extensions', + '-Wno-missing-field-initializers', -+ '-Wno-implicit-fallthrough', + '-Wno-unused-parameter', + ], + sources: [build],