From fa80f9ebb7284cfde5736a37cf3fd59434555d30 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Wed, 30 Oct 2024 11:46:13 +0100 Subject: [PATCH] ip: show routes from all vrfs by default Be consistent with `show ip nexthop`, display routes from all VRFs by default, unless a VRF id is specified. Change the default vrf_id parameter in the request to UINT16_MAX (meaning "all vrfs"). Add a vrf_id attribute to struct gr_ip4_route and display it in the CLI. Split route4_list to make counting and listing routes in mutliple VRFs possible without too much code duplication. Signed-off-by: Robin Jarry --- modules/ip/api/gr_ip4.h | 1 + modules/ip/cli/route.c | 8 +++-- modules/ip/control/route.c | 70 +++++++++++++++++++++++++++++++------- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/modules/ip/api/gr_ip4.h b/modules/ip/api/gr_ip4.h index be220a3b..782c9e01 100644 --- a/modules/ip/api/gr_ip4.h +++ b/modules/ip/api/gr_ip4.h @@ -64,6 +64,7 @@ struct gr_ip4_nh { struct gr_ip4_route { struct ip4_net dest; ip4_addr_t nh; + uint16_t vrf_id; }; #define GR_IP4_MODULE 0xf00d diff --git a/modules/ip/cli/route.c b/modules/ip/cli/route.c index d57eabad..136e77c5 100644 --- a/modules/ip/cli/route.c +++ b/modules/ip/cli/route.c @@ -48,9 +48,9 @@ static cmd_status_t route4_del(const struct gr_api_client *c, const struct ec_pn } static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_pnode *p) { + struct gr_ip4_route_list_req req = {.vrf_id = UINT16_MAX}; struct libscols_table *table = scols_new_table(); const struct gr_ip4_route_list_resp *resp; - struct gr_ip4_route_list_req req = {0}; char dest[BUFSIZ], nh[BUFSIZ]; void *resp_ptr = NULL; @@ -66,6 +66,7 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p } resp = resp_ptr; + scols_table_new_column(table, "VRF", 0, 0); scols_table_new_column(table, "DESTINATION", 0, 0); scols_table_new_column(table, "NEXT_HOP", 0, 0); scols_table_set_column_separator(table, " "); @@ -75,8 +76,9 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p const struct gr_ip4_route *route = &resp->routes[i]; ip4_net_format(&route->dest, dest, sizeof(dest)); inet_ntop(AF_INET, &route->nh, nh, sizeof(nh)); - scols_line_set_data(line, 0, dest); - scols_line_set_data(line, 1, nh); + scols_line_sprintf(line, 0, "%u", route->vrf_id); + scols_line_set_data(line, 1, dest); + scols_line_set_data(line, 2, nh); } scols_print_table(table); diff --git a/modules/ip/control/route.c b/modules/ip/control/route.c index db10a064..380356ed 100644 --- a/modules/ip/control/route.c +++ b/modules/ip/control/route.c @@ -252,19 +252,15 @@ static struct api_out route4_get(const void *request, void **response) { return api_out(0, sizeof(*resp)); } -static struct api_out route4_list(const void *request, void **response) { - const struct gr_ip4_route_list_req *req = request; - struct gr_ip4_route_list_resp *resp = NULL; - struct rte_fib *fib = get_fib(req->vrf_id); +static int route4_count(uint16_t vrf_id) { struct rte_rib_node *rn = NULL; - struct gr_ip4_route *r; + struct rte_fib *fib; struct rte_rib *rib; - size_t num, len; - uintptr_t nh_id; - uint32_t ip; + int num; + fib = get_fib(vrf_id); if (fib == NULL) - return api_out(errno, 0); + return -errno; rib = rte_fib_get_rib(fib); @@ -275,9 +271,20 @@ static struct api_out route4_list(const void *request, void **response) { if (rte_rib_lookup_exact(rib, 0, 0) != NULL) num++; - len = sizeof(*resp) + num * sizeof(struct gr_ip4_route); - if ((resp = calloc(1, len)) == NULL) - return api_out(ENOMEM, 0); + return num; +} + +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; + struct rte_fib *fib; + struct rte_rib *rib; + uintptr_t nh_id; + uint32_t ip; + + fib = get_fib(vrf_id); + assert(fib != NULL); + rib = rte_fib_get_rib(fib); while ((rn = rte_rib_get_nxt(rib, 0, 0, rn, RTE_RIB_GET_NXT_ALL)) != NULL) { r = &resp->routes[resp->n_routes++]; @@ -286,6 +293,7 @@ static struct api_out route4_list(const void *request, void **response) { rte_rib_get_depth(rn, &r->dest.prefixlen); r->dest.ip = htonl(ip); r->nh = nh_id_to_ptr(nh_id)->ip; + r->vrf_id = vrf_id; } // 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) { @@ -294,7 +302,45 @@ static struct api_out route4_list(const void *request, void **response) { r->dest.ip = 0; r->dest.prefixlen = 0; r->nh = nh_id_to_ptr(nh_id)->ip; + r->vrf_id = vrf_id; + } +} + +static struct api_out route4_list(const void *request, void **response) { + const struct gr_ip4_route_list_req *req = request; + struct gr_ip4_route_list_resp *resp = NULL; + size_t num, len; + int n; + + if (req->vrf_id == UINT16_MAX) { + num = 0; + for (uint16_t v = 0; v < IP4_MAX_VRFS; v++) { + if (vrf_fibs[v] == NULL) + continue; + if ((n = route4_count(v)) < 0) + return api_out(errno, 0); + num += n; + } + } else { + if ((n = route4_count(req->vrf_id)) < 0) + return api_out(errno, 0); + num = n; + } + + len = sizeof(*resp) + num * sizeof(struct gr_ip4_route); + if ((resp = calloc(1, len)) == NULL) + return api_out(ENOMEM, 0); + + if (req->vrf_id == UINT16_MAX) { + for (uint16_t v = 0; v < IP4_MAX_VRFS; v++) { + if (vrf_fibs[v] == NULL) + continue; + route4_rib_to_api(resp, v); + } + } else { + route4_rib_to_api(resp, req->vrf_id); } + *response = resp; return api_out(0, len);