Skip to content

Commit f67fb4d

Browse files
committed
ip,ip6: add route with gateway and device
Thanks to this commit, the following type of route can be added: ip route add 10.0.0.2 via 172.1.1.2 dev p0 WIP -> just to get feedback Signed-off-by: Maxime Leroy <[email protected]>
1 parent d8f21a5 commit f67fb4d

File tree

6 files changed

+98
-14
lines changed

6 files changed

+98
-14
lines changed

modules/ip/api/gr_ip4.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct gr_ip4_ifaddr {
1919
struct gr_ip4_route {
2020
struct ip4_net dest;
2121
ip4_addr_t nh;
22+
uint16_t iface_id;
2223
uint16_t vrf_id;
2324
gr_rt_origin_t origin;
2425
};
@@ -65,6 +66,7 @@ struct gr_ip4_route_add_req {
6566
uint16_t vrf_id;
6667
struct ip4_net dest;
6768
ip4_addr_t nh;
69+
uint16_t iface_id;
6870
gr_rt_origin_t origin;
6971
uint8_t exist_ok;
7072
};

modules/ip/cli/route.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,30 @@
1616
#include <errno.h>
1717

1818
static cmd_status_t route4_add(const struct gr_api_client *c, const struct ec_pnode *p) {
19-
struct gr_ip4_route_add_req req = {.exist_ok = true, .origin = GR_RT_ORIGIN_USER};
19+
struct gr_ip4_route_add_req req = {
20+
.exist_ok = true, .origin = GR_RT_ORIGIN_USER, .iface_id = GR_IFACE_ID_UNDEF
21+
};
22+
int ret;
2023

2124
if (arg_ip4_net(p, "DEST", &req.dest, true) < 0)
2225
return CMD_ERROR;
23-
if (arg_ip4(p, "NH", &req.nh) < 0)
26+
27+
ret = arg_ip4(p, "NH", &req.nh);
28+
if (ret < 0 && errno != ENOENT)
2429
return CMD_ERROR;
30+
31+
if (arg_str(p, "IFACE")) {
32+
struct gr_iface iface;
33+
34+
ret = iface_from_name(c, arg_str(p, "IFACE"), &iface);
35+
if (ret < 0)
36+
return CMD_ERROR;
37+
req.iface_id = iface.id;
38+
}
39+
40+
if (!req.nh && req.iface_id == GR_IFACE_ID_UNDEF)
41+
return CMD_ERROR;
42+
2543
if (arg_u16(p, "VRF", &req.vrf_id) < 0 && errno != ENOENT)
2644
return CMD_ERROR;
2745

@@ -49,6 +67,7 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p
4967
struct gr_ip4_route_list_req req = {.vrf_id = UINT16_MAX};
5068
struct libscols_table *table = scols_new_table();
5169
const struct gr_ip4_route_list_resp *resp;
70+
struct gr_iface iface;
5271
void *resp_ptr = NULL;
5372

5473
if (table == NULL)
@@ -66,6 +85,7 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p
6685
scols_table_new_column(table, "VRF", 0, 0);
6786
scols_table_new_column(table, "DESTINATION", 0, 0);
6887
scols_table_new_column(table, "NEXT_HOP", 0, 0);
88+
scols_table_new_column(table, "IFACE", 0, 0);
6989
scols_table_new_column(table, "ORIGIN", 0, 0);
7090
scols_table_set_column_separator(table, " ");
7191

@@ -75,7 +95,13 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p
7595
scols_line_sprintf(line, 0, "%u", route->vrf_id);
7696
scols_line_sprintf(line, 1, IP4_F "/%hhu", &route->dest.ip, route->dest.prefixlen);
7797
scols_line_sprintf(line, 2, IP4_F, &route->nh);
78-
scols_line_sprintf(line, 3, "%s", gr_rt_origin_name(route->origin));
98+
if (route->iface_id == GR_IFACE_ID_UNDEF)
99+
scols_line_sprintf(line, 3, "any");
100+
else if (iface_from_id(c, route->iface_id, &iface) == 0)
101+
scols_line_sprintf(line, 3, "%s", iface.name);
102+
else
103+
scols_line_sprintf(line, 3, "%u", route->iface_id);
104+
scols_line_sprintf(line, 4, "%s", gr_rt_origin_name(route->origin));
79105
}
80106

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

120146
ret = CLI_COMMAND(
121147
IP_ADD_CTX(root),
122-
"route DEST via NH [vrf VRF]",
148+
"route DEST [(via NH),(dev IFACE)][vrf VRF]",
123149
route4_add,
124150
"Add a new route.",
125151
with_help("IPv4 destination prefix.", ec_node_re("DEST", IPV4_NET_RE)),
126152
with_help("IPv4 next hop address.", ec_node_re("NH", IPV4_RE)),
153+
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL)),
127154
with_help("L3 routing domain ID.", ec_node_uint("VRF", 0, UINT16_MAX - 1, 10))
128155
);
129156
if (ret < 0)

modules/ip/control/route.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ int rib4_insert(
162162
&(struct gr_ip4_route) {
163163
{ip, prefixlen},
164164
nh->ipv4,
165+
nh->iface_id,
165166
nh->vrf_id,
166167
origin,
167168
}
@@ -202,6 +203,7 @@ int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen) {
202203
&(struct gr_ip4_route) {
203204
{ip, prefixlen},
204205
nh->ipv4,
206+
nh->iface_id,
205207
nh->vrf_id,
206208
origin,
207209
}
@@ -215,19 +217,28 @@ int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen) {
215217
static struct api_out route4_add(const void *request, void ** /*response*/) {
216218
const struct gr_ip4_route_add_req *req = request;
217219
struct nexthop *nh;
220+
ip4_addr_t nh_ipv4;
221+
uint16_t iface_id;
218222
int ret;
219223

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

223227
// ensure route gateway is reachable
224-
if ((nh = rib4_lookup(req->vrf_id, req->nh)) == NULL)
228+
if (req->nh)
229+
nh = rib4_lookup(req->vrf_id, req->nh);
230+
else
231+
nh = addr4_get_preferred(req->iface_id, req->nh);
232+
if (nh == NULL)
225233
return api_out(EHOSTUNREACH, 0);
226234

235+
nh_ipv4 = req->nh ? req->nh : nh->ipv4;
236+
iface_id = req->iface_id != GR_IFACE_ID_UNDEF ? req->iface_id : nh->iface_id;
237+
227238
// if the route gateway is reachable via a prefix route,
228239
// create a new unresolved nexthop
229-
if (nh->ipv4 != req->nh) {
230-
if ((nh = nh4_new(req->vrf_id, nh->iface_id, req->nh)) == NULL)
240+
if (nh->ipv4 != nh_ipv4 || nh->iface_id != iface_id) {
241+
if ((nh = nh4_new(req->vrf_id, iface_id, nh_ipv4)) == NULL)
231242
return api_out(errno, 0);
232243
nh->flags |= GR_NH_F_GATEWAY;
233244
}
@@ -321,6 +332,7 @@ static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_
321332
rte_rib_get_depth(rn, &r->dest.prefixlen);
322333
r->dest.ip = htonl(ip);
323334
r->nh = nh_id_to_ptr(nh_id)->ipv4;
335+
r->iface_id = nh_id_to_ptr(nh_id)->iface_id;
324336
r->vrf_id = vrf_id;
325337
r->origin = *origin;
326338
}
@@ -334,6 +346,7 @@ static void route4_rib_to_api(struct gr_ip4_route_list_resp *resp, uint16_t vrf_
334346
r->dest.ip = 0;
335347
r->dest.prefixlen = 0;
336348
r->nh = nh_id_to_ptr(nh_id)->ipv4;
349+
r->iface_id = nh_id_to_ptr(nh_id)->iface_id;
337350
r->vrf_id = vrf_id;
338351
r->origin = *origin;
339352
}

modules/ip6/api/gr_ip6.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct gr_ip6_ifaddr {
1919
struct gr_ip6_route {
2020
struct ip6_net dest;
2121
struct rte_ipv6_addr nh;
22+
uint16_t iface_id;
2223
uint16_t vrf_id;
2324
gr_rt_origin_t origin;
2425
};
@@ -65,6 +66,7 @@ struct gr_ip6_route_add_req {
6566
uint16_t vrf_id;
6667
struct ip6_net dest;
6768
struct rte_ipv6_addr nh;
69+
uint16_t iface_id;
6870
gr_rt_origin_t origin;
6971
uint8_t exist_ok;
7072
};

modules/ip6/cli/route.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,30 @@
1616
#include <errno.h>
1717

1818
static cmd_status_t route6_add(const struct gr_api_client *c, const struct ec_pnode *p) {
19-
struct gr_ip6_route_add_req req = {.exist_ok = true, .origin = GR_RT_ORIGIN_USER};
19+
struct gr_ip6_route_add_req req = {
20+
.exist_ok = true, .origin = GR_RT_ORIGIN_USER, .iface_id = GR_IFACE_ID_UNDEF
21+
};
22+
int ret;
2023

2124
if (arg_ip6_net(p, "DEST", &req.dest, true) < 0)
2225
return CMD_ERROR;
23-
if (arg_ip6(p, "NH", &req.nh) < 0)
26+
27+
ret = arg_ip6(p, "NH", &req.nh);
28+
if (ret < 0 && errno != ENOENT)
2429
return CMD_ERROR;
30+
31+
if (arg_str(p, "IFACE")) {
32+
struct gr_iface iface;
33+
34+
ret = iface_from_name(c, arg_str(p, "IFACE"), &iface);
35+
if (ret < 0)
36+
return CMD_ERROR;
37+
req.iface_id = iface.id;
38+
}
39+
40+
if (memcmp(req.nh.a, (uint8_t[16]) {0}, 16) == 0 && req.iface_id == GR_IFACE_ID_UNDEF)
41+
return CMD_ERROR;
42+
2543
if (arg_u16(p, "VRF", &req.vrf_id) < 0 && errno != ENOENT)
2644
return CMD_ERROR;
2745

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

5473
if (table == NULL)
@@ -66,6 +85,7 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p
6685
scols_table_new_column(table, "VRF", 0, 0);
6786
scols_table_new_column(table, "DESTINATION", 0, 0);
6887
scols_table_new_column(table, "NEXT_HOP", 0, 0);
88+
scols_table_new_column(table, "IFACE", 0, 0);
6989
scols_table_new_column(table, "ORIGIN", 0, 0);
7090
scols_table_set_column_separator(table, " ");
7191

@@ -75,7 +95,13 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p
7595
scols_line_sprintf(line, 0, "%u", route->vrf_id);
7696
scols_line_sprintf(line, 1, IP6_F "/%hhu", &route->dest, route->dest.prefixlen);
7797
scols_line_sprintf(line, 2, IP6_F, &route->nh);
78-
scols_line_sprintf(line, 3, "%s", gr_rt_origin_name(route->origin));
98+
if (route->iface_id == GR_IFACE_ID_UNDEF)
99+
scols_line_sprintf(line, 3, "any");
100+
else if (iface_from_id(c, route->iface_id, &iface) == 0)
101+
scols_line_sprintf(line, 3, "%s", iface.name);
102+
else
103+
scols_line_sprintf(line, 3, "%u", route->iface_id);
104+
scols_line_sprintf(line, 4, "%s", gr_rt_origin_name(route->origin));
79105
}
80106

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

121147
ret = CLI_COMMAND(
122148
IP6_ADD_CTX(root),
123-
"route DEST via NH [vrf VRF]",
149+
"route DEST [(via NH),(dev IFACE)][vrf VRF]",
124150
route6_add,
125151
"Add a new route.",
126152
with_help("IPv6 destination prefix.", ec_node_re("DEST", IPV6_NET_RE)),
127153
with_help("IPv6 next hop address.", ec_node_re("NH", IPV6_RE)),
154+
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL)),
128155
with_help("L3 routing domain ID.", ec_node_uint("VRF", 0, UINT16_MAX - 1, 10))
129156
);
130157
if (ret < 0)

modules/ip6/control/route.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ int rib6_insert(
176176
&(struct gr_ip6_route) {
177177
{*ip, prefixlen},
178178
nh->ipv6,
179+
nh->iface_id,
179180
vrf_id,
180181
origin,
181182
}
@@ -223,6 +224,7 @@ int rib6_delete(
223224
&(struct gr_ip6_route) {
224225
{*ip, prefixlen},
225226
nh->ipv6,
227+
nh->iface_id,
226228
vrf_id,
227229
origin,
228230
}
@@ -235,20 +237,29 @@ int rib6_delete(
235237

236238
static struct api_out route6_add(const void *request, void ** /*response*/) {
237239
const struct gr_ip6_route_add_req *req = request;
240+
const struct rte_ipv6_addr *nh_ipv6;
238241
struct nexthop *nh;
242+
uint16_t iface_id;
239243
int ret;
240244

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

244248
// ensure route gateway is reachable
245-
if ((nh = rib6_lookup(req->vrf_id, GR_IFACE_ID_UNDEF, &req->nh)) == NULL)
249+
if (!rte_ipv6_addr_is_unspec(&req->nh))
250+
nh = rib6_lookup(req->vrf_id, GR_IFACE_ID_UNDEF, &req->nh);
251+
else
252+
nh = addr6_get_linklocal(req->iface_id); // XX: TO CHECK if correct
253+
if (nh == NULL)
246254
return api_out(EHOSTUNREACH, 0);
247255

256+
nh_ipv6 = !rte_ipv6_addr_is_unspec(&req->nh) ? &req->nh : &nh->ipv6;
257+
iface_id = req->iface_id != GR_IFACE_ID_UNDEF ? req->iface_id : nh->iface_id;
258+
248259
// if the route gateway is reachable via a prefix route,
249260
// create a new unresolved nexthop
250-
if (!rte_ipv6_addr_eq(&nh->ipv6, &req->nh)) {
251-
if ((nh = nh6_new(req->vrf_id, nh->iface_id, &req->nh)) == NULL)
261+
if (!rte_ipv6_addr_eq(&nh->ipv6, nh_ipv6) || nh->iface_id != iface_id) {
262+
if ((nh = nh6_new(req->vrf_id, iface_id, nh_ipv6)) == NULL)
252263
return api_out(errno, 0);
253264
nh->flags |= GR_NH_F_GATEWAY;
254265
}
@@ -352,6 +363,7 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_
352363
rte_rib6_get_ip(rn, &r->dest.ip);
353364
rte_rib6_get_depth(rn, &r->dest.prefixlen);
354365
r->nh = nh_id_to_ptr(nh_id)->ipv6;
366+
r->iface_id = nh_id_to_ptr(nh_id)->iface_id;
355367
r->vrf_id = vrf_id;
356368
r->dest.ip = *addr6_linklocal_unscope(&r->dest.ip, &tmp);
357369
r->origin = *origin;
@@ -365,6 +377,7 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_
365377
rte_rib6_get_nh(rn, &nh_id);
366378
memset(&r->dest, 0, sizeof(r->dest));
367379
r->nh = nh_id_to_ptr(nh_id)->ipv6;
380+
r->iface_id = nh_id_to_ptr(nh_id)->iface_id;
368381
r->vrf_id = vrf_id;
369382
r->origin = *origin;
370383
}

0 commit comments

Comments
 (0)