Skip to content

Ifindex rt #209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions modules/infra/control/gr_nh_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ struct hoplist {
struct nexthop *
nexthop_lookup(gr_nh_type_t type, uint16_t vrf_id, uint16_t iface_id, const void *addr);

// Compare two nexthops, return True if the same, else False
bool nexthop_equal(struct nexthop *nh1, struct nexthop *nh2);

// Allocate a new nexthop from the global pool with the provided initial values.
struct nexthop *
nexthop_new(gr_nh_type_t type, uint16_t vrf_id, uint16_t iface_id, const void *addr);
Expand Down
18 changes: 18 additions & 0 deletions modules/infra/control/nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,24 @@ nexthop_new(gr_nh_type_t type, uint16_t vrf_id, uint16_t iface_id, const void *a
return nh;
}

bool nexthop_equal(struct nexthop *nh1, struct nexthop *nh2) {
if (nh1->vrf_id != nh2->vrf_id || nh1->iface_id != nh2->iface_id || nh1->type != nh2->type)
return false;

switch (nh1->type) {
case GR_NH_IPV4:
case GR_NH_SR6_IPV4:
return (memcmp(&nh1->ipv4, &nh2->ipv4, sizeof(nh1->ipv4)) == 0);
case GR_NH_IPV6:
case GR_NH_SR6_IPV6:
return (memcmp(&nh1->ipv6, &nh2->ipv6, sizeof(nh1->ipv6)) == 0);
default:
ABORT("invalid nexthop type %hhu", nh1->type);
}

return false;
}

struct pool_iterator {
nh_iter_cb_t user_cb;
void *priv;
Expand Down
2 changes: 2 additions & 0 deletions modules/ip/api/gr_ip4.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct gr_ip4_ifaddr {
struct gr_ip4_route {
struct ip4_net dest;
ip4_addr_t nh;
uint16_t iface_id;
uint16_t vrf_id;
gr_rt_origin_t origin;
};
Expand Down Expand Up @@ -65,6 +66,7 @@ struct gr_ip4_route_add_req {
uint16_t vrf_id;
struct ip4_net dest;
ip4_addr_t nh;
uint16_t iface_id;
gr_rt_origin_t origin;
uint8_t exist_ok;
};
Expand Down
35 changes: 31 additions & 4 deletions modules/ip/cli/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,30 @@
#include <errno.h>

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_RT_ORIGIN_USER, .iface_id = GR_IFACE_ID_UNDEF
};
int ret;

if (arg_ip4_net(p, "DEST", &req.dest, true) < 0)
return CMD_ERROR;
if (arg_ip4(p, "NH", &req.nh) < 0)

ret = arg_ip4(p, "NH", &req.nh);
if (ret < 0 && errno != ENOENT)
return CMD_ERROR;

if (arg_str(p, "IFACE")) {
struct gr_iface iface;

ret = iface_from_name(c, arg_str(p, "IFACE"), &iface);
if (ret < 0)
return CMD_ERROR;
req.iface_id = iface.id;
}

if (!req.nh && req.iface_id == GR_IFACE_ID_UNDEF)
return CMD_ERROR;

if (arg_u16(p, "VRF", &req.vrf_id) < 0 && errno != ENOENT)
return CMD_ERROR;

Expand Down Expand Up @@ -49,6 +67,7 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_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_iface iface;
void *resp_ptr = NULL;

if (table == NULL)
Expand All @@ -66,6 +85,7 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p
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_new_column(table, "IFACE", 0, 0);
scols_table_new_column(table, "ORIGIN", 0, 0);
scols_table_set_column_separator(table, " ");

Expand All @@ -75,7 +95,13 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p
scols_line_sprintf(line, 0, "%u", route->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);
scols_line_sprintf(line, 3, "%s", gr_rt_origin_name(route->origin));
if (route->iface_id == GR_IFACE_ID_UNDEF)
scols_line_sprintf(line, 3, "any");
else if (iface_from_id(c, route->iface_id, &iface) == 0)
scols_line_sprintf(line, 3, "%s", iface.name);
else
scols_line_sprintf(line, 3, "%u", route->iface_id);
scols_line_sprintf(line, 4, "%s", gr_rt_origin_name(route->origin));
}

scols_print_table(table);
Expand Down Expand Up @@ -119,11 +145,12 @@ static int ctx_init(struct ec_node *root) {

ret = CLI_COMMAND(
IP_ADD_CTX(root),
"route DEST via NH [vrf VRF]",
"route DEST [(via NH),(dev IFACE)][vrf VRF]",
route4_add,
"Add a new route.",
with_help("IPv4 destination prefix.", ec_node_re("DEST", IPV4_NET_RE)),
with_help("IPv4 next hop address.", ec_node_re("NH", IPV4_RE)),
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL)),
with_help("L3 routing domain ID.", ec_node_uint("VRF", 0, UINT16_MAX - 1, 10))
);
if (ret < 0)
Expand Down
28 changes: 20 additions & 8 deletions modules/ip/control/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ int rib4_insert(
) {
struct rte_rib *rib = get_or_create_rib(vrf_id);
struct rte_rib_node *rn;
struct nexthop *_nh;
gr_rt_origin_t *o;
int ret;

Expand All @@ -140,8 +141,9 @@ int rib4_insert(
ret = -errno;
goto fail;
}
if (rib4_lookup_exact(vrf_id, ip, prefixlen) != NULL) {
ret = -EEXIST;
_nh = rib4_lookup_exact(vrf_id, ip, prefixlen);
if (_nh != NULL) {
ret = nexthop_equal(nh, _nh) ? -EEXIST : -EBUSY;
goto fail;
}

Expand All @@ -160,6 +162,7 @@ int rib4_insert(
&(struct gr_ip4_route) {
{ip, prefixlen},
nh->ipv4,
nh->iface_id,
nh->vrf_id,
origin,
}
Expand Down Expand Up @@ -200,6 +203,7 @@ int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen) {
&(struct gr_ip4_route) {
{ip, prefixlen},
nh->ipv4,
nh->iface_id,
nh->vrf_id,
origin,
}
Expand All @@ -213,19 +217,28 @@ int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen) {
static struct api_out route4_add(const void *request, void ** /*response*/) {
const struct gr_ip4_route_add_req *req = request;
struct nexthop *nh;
ip4_addr_t nh_ipv4;
uint16_t iface_id;
int ret;

if (req->origin == GR_RT_ORIGIN_INTERNAL)
return api_out(EINVAL, 0);

// ensure route gateway is reachable
if ((nh = rib4_lookup(req->vrf_id, req->nh)) == NULL)
if (req->nh)
nh = rib4_lookup(req->vrf_id, req->nh);
else
nh = addr4_get_preferred(req->iface_id, req->nh);
if (nh == NULL)
return api_out(EHOSTUNREACH, 0);

nh_ipv4 = req->nh ? req->nh : nh->ipv4;
iface_id = req->iface_id != GR_IFACE_ID_UNDEF ? req->iface_id : nh->iface_id;

// if the route gateway is reachable via a prefix route,
// create a new unresolved nexthop
if (nh->ipv4 != req->nh) {
if ((nh = nh4_new(req->vrf_id, nh->iface_id, req->nh)) == NULL)
if (nh->ipv4 != nh_ipv4 || nh->iface_id != iface_id) {
if ((nh = nh4_new(req->vrf_id, iface_id, nh_ipv4)) == NULL)
return api_out(errno, 0);
nh->flags |= GR_NH_F_GATEWAY;
}
Expand All @@ -248,9 +261,6 @@ static struct api_out route4_del(const void *request, void ** /*response*/) {
return api_out(ENOENT, 0);
}

if (!(nh->flags & GR_NH_F_GATEWAY))
return api_out(EBUSY, 0);

if (rib4_delete(req->vrf_id, req->dest.ip, req->dest.prefixlen) < 0)
return api_out(errno, 0);

Expand Down Expand Up @@ -322,6 +332,7 @@ static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_
rte_rib_get_depth(rn, &r->dest.prefixlen);
r->dest.ip = htonl(ip);
r->nh = nh_id_to_ptr(nh_id)->ipv4;
r->iface_id = nh_id_to_ptr(nh_id)->iface_id;
r->vrf_id = vrf_id;
r->origin = *origin;
}
Expand All @@ -335,6 +346,7 @@ static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_
r->dest.ip = 0;
r->dest.prefixlen = 0;
r->nh = nh_id_to_ptr(nh_id)->ipv4;
r->iface_id = nh_id_to_ptr(nh_id)->iface_id;
r->vrf_id = vrf_id;
r->origin = *origin;
}
Expand Down
2 changes: 2 additions & 0 deletions modules/ip6/api/gr_ip6.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct gr_ip6_ifaddr {
struct gr_ip6_route {
struct ip6_net dest;
struct rte_ipv6_addr nh;
uint16_t iface_id;
uint16_t vrf_id;
gr_rt_origin_t origin;
};
Expand Down Expand Up @@ -65,6 +66,7 @@ struct gr_ip6_route_add_req {
uint16_t vrf_id;
struct ip6_net dest;
struct rte_ipv6_addr nh;
uint16_t iface_id;
gr_rt_origin_t origin;
uint8_t exist_ok;
};
Expand Down
35 changes: 31 additions & 4 deletions modules/ip6/cli/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,30 @@
#include <errno.h>

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_RT_ORIGIN_USER, .iface_id = GR_IFACE_ID_UNDEF
};
int ret;

if (arg_ip6_net(p, "DEST", &req.dest, true) < 0)
return CMD_ERROR;
if (arg_ip6(p, "NH", &req.nh) < 0)

ret = arg_ip6(p, "NH", &req.nh);
if (ret < 0 && errno != ENOENT)
return CMD_ERROR;

if (arg_str(p, "IFACE")) {
struct gr_iface iface;

ret = iface_from_name(c, arg_str(p, "IFACE"), &iface);
if (ret < 0)
return CMD_ERROR;
req.iface_id = iface.id;
}

if (memcmp(req.nh.a, (uint8_t[16]) {0}, 16) == 0 && req.iface_id == GR_IFACE_ID_UNDEF)
return CMD_ERROR;

if (arg_u16(p, "VRF", &req.vrf_id) < 0 && errno != ENOENT)
return CMD_ERROR;

Expand Down Expand Up @@ -49,6 +67,7 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p
struct gr_ip6_route_list_req req = {.vrf_id = UINT16_MAX};
struct libscols_table *table = scols_new_table();
const struct gr_ip6_route_list_resp *resp;
struct gr_iface iface;
void *resp_ptr = NULL;

if (table == NULL)
Expand All @@ -66,6 +85,7 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p
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_new_column(table, "IFACE", 0, 0);
scols_table_new_column(table, "ORIGIN", 0, 0);
scols_table_set_column_separator(table, " ");

Expand All @@ -75,7 +95,13 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p
scols_line_sprintf(line, 0, "%u", route->vrf_id);
scols_line_sprintf(line, 1, IP6_F "/%hhu", &route->dest, route->dest.prefixlen);
scols_line_sprintf(line, 2, IP6_F, &route->nh);
scols_line_sprintf(line, 3, "%s", gr_rt_origin_name(route->origin));
if (route->iface_id == GR_IFACE_ID_UNDEF)
scols_line_sprintf(line, 3, "any");
else if (iface_from_id(c, route->iface_id, &iface) == 0)
scols_line_sprintf(line, 3, "%s", iface.name);
else
scols_line_sprintf(line, 3, "%u", route->iface_id);
scols_line_sprintf(line, 4, "%s", gr_rt_origin_name(route->origin));
}

scols_print_table(table);
Expand Down Expand Up @@ -120,11 +146,12 @@ static int ctx_init(struct ec_node *root) {

ret = CLI_COMMAND(
IP6_ADD_CTX(root),
"route DEST via NH [vrf VRF]",
"route DEST [(via NH),(dev IFACE)][vrf VRF]",
route6_add,
"Add a new route.",
with_help("IPv6 destination prefix.", ec_node_re("DEST", IPV6_NET_RE)),
with_help("IPv6 next hop address.", ec_node_re("NH", IPV6_RE)),
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL)),
with_help("L3 routing domain ID.", ec_node_uint("VRF", 0, UINT16_MAX - 1, 10))
);
if (ret < 0)
Expand Down
Loading