Skip to content

Commit

Permalink
ip6: router advertisement configuration
Browse files Browse the repository at this point in the history
Add configuration knobs for RA messages.
Instead of a hardcoded perdiodic message, allow a per-interface
configuration.

Signed-off-by: Christophe Fontaine <[email protected]>
  • Loading branch information
christophefontaine committed Jan 15, 2025
1 parent 52c6b25 commit 39dd3a3
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 34 deletions.
26 changes: 26 additions & 0 deletions modules/ip6/api/gr_ip6.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,17 @@ struct gr_ip6_addr_list_resp {
struct gr_ip6_ifaddr addrs[/* n_addrs */];
};

// router advertisement ////////////////////////////////////////////////////////
#define GR_IP6_IFACE_RA_SET REQUEST_TYPE(GR_IP6_MODULE, 0x0030)
struct gr_ip6_ra_set_req {
uint16_t iface_id;
uint16_t set_interval : 1;
uint16_t set_lifetime : 1;
uint16_t set_preference : 1;

uint16_t interval;
uint16_t lifetime;
uint16_t preference;
};
// struct gr_ip6_ra_set_resp { };

Expand All @@ -143,4 +151,22 @@ struct gr_ip6_ra_clear_req {
uint16_t iface_id;
};
// struct gr_ip6_ra_clear_resp { };

#define GR_IP6_IFACE_RA_SHOW REQUEST_TYPE(GR_IP6_MODULE, 0x0032)
struct gr_ip6_ra_show_req {
uint16_t iface_id;
};

struct gr_ip6_ra_conf {
bool enabled;
uint16_t iface_id;
uint16_t interval;
uint16_t lifetime;
uint16_t preference;
};

struct gr_ip6_ra_show_resp {
uint16_t n_ras;
struct gr_ip6_ra_conf ras[];
};
#endif
3 changes: 3 additions & 0 deletions modules/ip6/cli/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
#define IP6_ADD_CTX(root) CLI_CONTEXT(root, CTX_ADD, CTX_ARG("ip6", "Create IPv6 stack elements."))
#define IP6_DEL_CTX(root) CLI_CONTEXT(root, CTX_DEL, CTX_ARG("ip6", "Delete IPv6 stack elements."))
#define IP6_SHOW_CTX(root) CLI_CONTEXT(root, CTX_SHOW, CTX_ARG("ip6", "Show IPv6 stack details."))
#define IP6_SET_CTX(root) CLI_CONTEXT(root, CTX_SET, CTX_ARG("ip6", "Set IPv6 stack elements."))
#define IP6_CLEAR_CTX(root) \
CLI_CONTEXT(root, CTX_CLEAR, CTX_ARG("ip6", "Clear IPv6 stack elements."))

#endif
1 change: 1 addition & 0 deletions modules/ip6/cli/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ cli_src += files(
'address.c',
'nexthop.c',
'route.c',
'router_advertisement.c',
)
140 changes: 140 additions & 0 deletions modules/ip6/cli/router_advertisement.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2024 Christophe Fontaine

#include "ip.h"

#include <gr_api.h>
#include <gr_cli.h>
#include <gr_cli_iface.h>
#include <gr_ip6.h>
#include <gr_net_types.h>
#include <gr_table.h>

#include <ecoli.h>
#include <libsmartcols.h>

#include <errno.h>

static cmd_status_t ra_show(const struct gr_api_client *c, const struct ec_pnode *p) {
struct libscols_table *table = scols_new_table();
struct gr_ip6_ra_show_resp *resp;
struct gr_ip6_ra_show_req req;
struct gr_iface iface;
void *resp_ptr = NULL;

if (!iface_from_name(c, arg_str(p, "IFACE"), &iface))
req.iface_id = iface.id;
else
req.iface_id = 0;

if (gr_api_client_send_recv(c, GR_IP6_IFACE_RA_SHOW, sizeof(req), &req, &resp_ptr) < 0)
return CMD_ERROR;
resp = resp_ptr;

scols_table_new_column(table, "IFACE", 0, 0);
scols_table_new_column(table, "RA", 0, 0);
scols_table_new_column(table, "interval", 0, 0);
scols_table_new_column(table, "lifetime", 0, 0);
scols_table_new_column(table, "preference", 0, 0);
scols_table_set_column_separator(table, " ");

for (uint16_t i = 0; i < resp->n_ras; i++) {
struct libscols_line *line = scols_table_new_line(table, NULL);
if (iface_from_id(c, resp->ras[i].iface_id, &iface) == 0)
scols_line_sprintf(line, 0, "%s", iface.name);
else
scols_line_sprintf(line, 0, "%u", resp->ras[i].iface_id);
scols_line_sprintf(line, 1, "%u", resp->ras[i].enabled);
scols_line_sprintf(line, 2, "%u", resp->ras[i].interval);
scols_line_sprintf(line, 3, "%u", resp->ras[i].lifetime);
scols_line_sprintf(line, 4, "%u", resp->ras[i].preference);
}

scols_print_table(table);
scols_unref_table(table);
free(resp_ptr);
return CMD_SUCCESS;
}

static cmd_status_t ra_set(const struct gr_api_client *c, const struct ec_pnode *p) {
struct gr_ip6_ra_set_req req = {0};
struct gr_iface iface;

if (iface_from_name(c, arg_str(p, "IFACE"), &iface) < 0)
return CMD_ERROR;

req.iface_id = iface.id;
if (!arg_u16(p, "IT", &req.interval))
req.set_interval = 1;

if (!arg_u16(p, "LT", &req.lifetime))
req.set_lifetime = 1;

if (!arg_u16(p, "PREF", &req.preference))
req.set_preference = 1;

if (gr_api_client_send_recv(c, GR_IP6_IFACE_RA_SET, sizeof(req), &req, NULL) < 0)
return CMD_ERROR;
return CMD_SUCCESS;
}

static cmd_status_t ra_clear(const struct gr_api_client *c, const struct ec_pnode *p) {
struct gr_ip6_ra_clear_req req;
struct gr_iface iface;

if (iface_from_name(c, arg_str(p, "IFACE"), &iface) < 0)
return CMD_ERROR;

req.iface_id = iface.id;
if (gr_api_client_send_recv(c, GR_IP6_IFACE_RA_CLEAR, sizeof(req), &req, NULL) < 0)
return CMD_ERROR;
return CMD_SUCCESS;
}

static int ctx_init(struct ec_node *root) {
int ret;

ret = CLI_COMMAND(
IP6_SHOW_CTX(root),
"router-advertisment [IFACE]",
ra_show,
"Show router advertisement configuration",
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL))
);
if (ret < 0)
return ret;

ret = CLI_COMMAND(
IP6_SET_CTX(root),
"router-advertisment IFACE [interval IT] [lifetime LT] [preference PREF]",
ra_set,
"Set router advertisement parameters",
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL)),
with_help("Interval", ec_node_uint("IT", 0, UINT16_MAX - 1, 10)),
with_help("Life time", ec_node_uint("LT", 0, UINT16_MAX - 1, 10)),
with_help("preference", ec_node_uint("PREF", 0, UINT16_MAX - 1, 10))
);
if (ret < 0)
return ret;

ret = CLI_COMMAND(
IP6_CLEAR_CTX(root),
"router-advertisement IFACE",
ra_clear,
"Disable router advertisement and reset parameters",
with_help("Interface name.", ec_node_dyn("IFACE", complete_iface_names, NULL))
);
if (ret < 0)
return ret;

return 0;
}

static struct gr_cli_context ctx = {
.name = "ipv6 router-advertisement",
.init = ctx_init,
};

static void __attribute__((constructor, used)) init(void) {
register_context(&ctx);
}
Loading

0 comments on commit 39dd3a3

Please sign in to comment.