Skip to content

Commit 8ed8b9d

Browse files
christophefontainerjarry
authored andcommitted
ip6: router advertisement configuration
Add configuration knobs for RA messages. Instead of a hardcoded periodic message, allow a per-interface configuration. Signed-off-by: Christophe Fontaine <[email protected]>
1 parent 2e45b6c commit 8ed8b9d

File tree

5 files changed

+286
-35
lines changed

5 files changed

+286
-35
lines changed

modules/ip6/api/gr_ip6.h

+23
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,15 @@ struct gr_ip6_addr_list_resp {
132132
struct gr_ip6_ifaddr addrs[/* n_addrs */];
133133
};
134134

135+
// router advertisement ////////////////////////////////////////////////////////
135136
#define GR_IP6_IFACE_RA_SET REQUEST_TYPE(GR_IP6_MODULE, 0x0030)
136137
struct gr_ip6_ra_set_req {
137138
uint16_t iface_id;
139+
uint16_t set_interval : 1;
140+
uint16_t set_lifetime : 1;
141+
142+
uint16_t interval;
143+
uint16_t lifetime;
138144
};
139145
// struct gr_ip6_ra_set_resp { };
140146

@@ -143,4 +149,21 @@ struct gr_ip6_ra_clear_req {
143149
uint16_t iface_id;
144150
};
145151
// struct gr_ip6_ra_clear_resp { };
152+
153+
#define GR_IP6_IFACE_RA_SHOW REQUEST_TYPE(GR_IP6_MODULE, 0x0032)
154+
struct gr_ip6_ra_show_req {
155+
uint16_t iface_id;
156+
};
157+
158+
struct gr_ip6_ra_conf {
159+
bool enabled;
160+
uint16_t iface_id;
161+
uint16_t interval;
162+
uint16_t lifetime;
163+
};
164+
165+
struct gr_ip6_ra_show_resp {
166+
uint16_t n_ras;
167+
struct gr_ip6_ra_conf ras[];
168+
};
146169
#endif

modules/ip6/cli/ip.h

+3
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@
99
#define IP6_ADD_CTX(root) CLI_CONTEXT(root, CTX_ADD, CTX_ARG("ip6", "Create IPv6 stack elements."))
1010
#define IP6_DEL_CTX(root) CLI_CONTEXT(root, CTX_DEL, CTX_ARG("ip6", "Delete IPv6 stack elements."))
1111
#define IP6_SHOW_CTX(root) CLI_CONTEXT(root, CTX_SHOW, CTX_ARG("ip6", "Show IPv6 stack details."))
12+
#define IP6_SET_CTX(root) CLI_CONTEXT(root, CTX_SET, CTX_ARG("ip6", "Set IPv6 stack elements."))
13+
#define IP6_CLEAR_CTX(root) \
14+
CLI_CONTEXT(root, CTX_CLEAR, CTX_ARG("ip6", "Clear IPv6 stack elements."))
1215

1316
#endif

modules/ip6/cli/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ cli_src += files(
55
'address.c',
66
'nexthop.c',
77
'route.c',
8+
'router_advert.c',
89
)

modules/ip6/cli/router_advert.c

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (c) 2025 Christophe Fontaine
3+
4+
#include "ip.h"
5+
6+
#include <gr_api.h>
7+
#include <gr_cli.h>
8+
#include <gr_cli_iface.h>
9+
#include <gr_ip6.h>
10+
#include <gr_net_types.h>
11+
#include <gr_table.h>
12+
13+
#include <ecoli.h>
14+
#include <libsmartcols.h>
15+
16+
#include <errno.h>
17+
18+
static cmd_status_t ra_show(const struct gr_api_client *c, const struct ec_pnode *p) {
19+
struct libscols_table *table = scols_new_table();
20+
struct gr_ip6_ra_show_resp *resp;
21+
struct gr_ip6_ra_show_req req;
22+
struct gr_iface iface;
23+
void *resp_ptr = NULL;
24+
25+
if (!iface_from_name(c, arg_str(p, "IFACE"), &iface))
26+
req.iface_id = iface.id;
27+
else
28+
req.iface_id = 0;
29+
30+
if (gr_api_client_send_recv(c, GR_IP6_IFACE_RA_SHOW, sizeof(req), &req, &resp_ptr) < 0)
31+
return CMD_ERROR;
32+
resp = resp_ptr;
33+
34+
scols_table_new_column(table, "IFACE", 0, 0);
35+
scols_table_new_column(table, "RA", 0, 0);
36+
scols_table_new_column(table, "interval", 0, 0);
37+
scols_table_new_column(table, "lifetime", 0, 0);
38+
scols_table_set_column_separator(table, " ");
39+
40+
for (uint16_t i = 0; i < resp->n_ras; i++) {
41+
struct libscols_line *line = scols_table_new_line(table, NULL);
42+
if (iface_from_id(c, resp->ras[i].iface_id, &iface) == 0)
43+
scols_line_sprintf(line, 0, "%s", iface.name);
44+
else
45+
scols_line_sprintf(line, 0, "%u", resp->ras[i].iface_id);
46+
scols_line_sprintf(line, 1, "%u", resp->ras[i].enabled);
47+
scols_line_sprintf(line, 2, "%u", resp->ras[i].interval);
48+
scols_line_sprintf(line, 3, "%u", resp->ras[i].lifetime);
49+
}
50+
51+
scols_print_table(table);
52+
scols_unref_table(table);
53+
free(resp_ptr);
54+
return CMD_SUCCESS;
55+
}
56+
57+
static cmd_status_t ra_set(const struct gr_api_client *c, const struct ec_pnode *p) {
58+
struct gr_ip6_ra_set_req req = {0};
59+
struct gr_iface iface;
60+
61+
if (iface_from_name(c, arg_str(p, "IFACE"), &iface) < 0)
62+
return CMD_ERROR;
63+
64+
req.iface_id = iface.id;
65+
if (!arg_u16(p, "IT", &req.interval))
66+
req.set_interval = 1;
67+
68+
if (!arg_u16(p, "LT", &req.lifetime))
69+
req.set_lifetime = 1;
70+
71+
if (gr_api_client_send_recv(c, GR_IP6_IFACE_RA_SET, sizeof(req), &req, NULL) < 0)
72+
return CMD_ERROR;
73+
return CMD_SUCCESS;
74+
}
75+
76+
static cmd_status_t ra_clear(const struct gr_api_client *c, const struct ec_pnode *p) {
77+
struct gr_ip6_ra_clear_req req;
78+
struct gr_iface iface;
79+
80+
if (iface_from_name(c, arg_str(p, "IFACE"), &iface) < 0)
81+
return CMD_ERROR;
82+
83+
req.iface_id = iface.id;
84+
if (gr_api_client_send_recv(c, GR_IP6_IFACE_RA_CLEAR, sizeof(req), &req, NULL) < 0)
85+
return CMD_ERROR;
86+
return CMD_SUCCESS;
87+
}
88+
89+
static int ctx_init(struct ec_node *root) {
90+
int ret;
91+
92+
ret = CLI_COMMAND(
93+
IP6_SHOW_CTX(root),
94+
"router-advert [IFACE]",
95+
ra_show,
96+
"Show router advertisement configuration",
97+
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL))
98+
);
99+
if (ret < 0)
100+
return ret;
101+
102+
ret = CLI_COMMAND(
103+
IP6_SET_CTX(root),
104+
"router-advert IFACE [interval IT] [lifetime LT]",
105+
ra_set,
106+
"Set router advertisement parameters",
107+
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL)),
108+
with_help("Interval", ec_node_uint("IT", 0, UINT16_MAX - 1, 10)),
109+
with_help("Life time", ec_node_uint("LT", 0, UINT16_MAX - 1, 10))
110+
);
111+
if (ret < 0)
112+
return ret;
113+
114+
ret = CLI_COMMAND(
115+
IP6_CLEAR_CTX(root),
116+
"router-advert IFACE",
117+
ra_clear,
118+
"Disable router advertisement and reset parameters",
119+
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL))
120+
);
121+
if (ret < 0)
122+
return ret;
123+
124+
return 0;
125+
}
126+
127+
static struct gr_cli_context ctx = {
128+
.name = "ipv6 router-advert",
129+
.init = ctx_init,
130+
};
131+
132+
static void __attribute__((constructor, used)) init(void) {
133+
register_context(&ctx);
134+
}

0 commit comments

Comments
 (0)