Skip to content
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

gnrc/ipv6_auto_subnets: add option to derive subnet prefix from EUI #21080

Merged
merged 2 commits into from
Jan 16, 2025
Merged
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
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ PSEUDOMODULES += gnrc_dhcpv6_client_simple_pd
## @}
## @}
PSEUDOMODULES += gnrc_ipv6_auto_subnets_auto_init
PSEUDOMODULES += gnrc_ipv6_auto_subnets_eui
PSEUDOMODULES += gnrc_ipv6_auto_subnets_simple
PSEUDOMODULES += gnrc_ipv6_classic
PSEUDOMODULES += gnrc_ipv6_default
Expand Down
4 changes: 4 additions & 0 deletions sys/net/gnrc/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ ifneq (,$(filter gnrc_rpl,$(USEMODULE)))
USEMODULE += evtimer
endif

ifneq (,$(filter gnrc_ipv6_auto_subnets_eui,$(USEMODULE)))
USEMODULE += gnrc_ipv6_auto_subnets_simple
endif

ifneq (,$(filter gnrc_ipv6_auto_subnets_simple,$(USEMODULE)))
USEMODULE += gnrc_ipv6_auto_subnets
endif
Expand Down
5 changes: 3 additions & 2 deletions sys/net/gnrc/network_layer/ipv6/nib/nib.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@
icmpv6_len -= (opt->len << 3), \
opt = (ndp_opt_t *)(((uint8_t *)opt) + (opt->len << 3)))

#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ROUTER)

Check warning on line 565 in sys/net/gnrc/network_layer/ipv6/nib/nib.c

View workflow job for this annotation

GitHub Actions / static-tests

full block {} expected in the control structure
static void _handle_rtr_sol(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
const ndp_rtr_sol_t *rtr_sol, size_t icmpv6_len)
{
Expand Down Expand Up @@ -849,8 +849,9 @@
/* notify optional PIO consumer */
if (IS_USED(MODULE_GNRC_IPV6_NIB_RTR_ADV_PIO_CB)) {
extern void gnrc_ipv6_nib_rtr_adv_pio_cb(gnrc_netif_t *netif,
const ndp_opt_pi_t *pio);
gnrc_ipv6_nib_rtr_adv_pio_cb(netif, (ndp_opt_pi_t *)opt);
const ndp_opt_pi_t *pio,
const ipv6_addr_t *src);
gnrc_ipv6_nib_rtr_adv_pio_cb(netif, (ndp_opt_pi_t *)opt, &ipv6->src);
}
break;
}
Expand Down
74 changes: 68 additions & 6 deletions sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,24 @@
* The upstream network will be automatically chosen as the one that first
* receives a router advertisement.
*
* If only a single level of downstream routers exists and a sufficiently small
* upstream prefix is provided, we can skip the synchronisation and instead derive
* the *prefix* from the EUI of the downstream interface.
*
* e.g. given a prefix `fd12::/16` a router with a downstream interface with the
* layer 2 address `12:84:0C:87:1F:B7` would create the prefix `fd12:1284:c87:1fb7::/64`
* for the downstream network.
*
* To enable this behavior, chose the `gnrc_ipv6_auto_subnets_eui` module.
*
* @{
*
* @file
* @author Benjamin Valentin <[email protected]>
*/

#include "compiler_hints.h"
#include "macros/utils.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netif/hdr.h"
Expand Down Expand Up @@ -305,6 +316,39 @@
out->u8[bytes] |= idx << shift;
}

static uint8_t _init_sub_prefix_eui(ipv6_addr_t *out,
const ipv6_addr_t *prefix, uint8_t bits,
const uint8_t *eui, uint8_t eui_len)
{
assert(eui_len <= sizeof(uint64_t));

/* If the EUI is too large, discard most significant bits as
those are typically manufacturer ID */
uint64_t mask = UINT64_MAX >> bits;

union {
uint64_t u64;
uint8_t u8[8];
} eui64 = {};
uint64_t pfx = byteorder_ntohll(prefix->u64[0]);

/* If EUI is small, we want to preserve leftover unused bits at the end */
uint8_t bits_total = bits + 8 * eui_len;
uint8_t shift = bits_total < 64
? 64 - bits_total
: 0;

/* treat EUI as a EUI-64 with unused bytes set to 0 */
memcpy(&eui64.u8[sizeof(uint64_t) - eui_len], eui, eui_len);
eui64.u64 = ntohll(eui64.u64) & mask;

/* create downstream prefix from upstream prefix + masked EUI64 */
out->u64[0] = byteorder_htonll(pfx | (eui64.u64 << shift));

/* we don't create prefixes that longer than 64 bits */
return MIN(64, bits_total);
}

/* returns true if a new prefix was added, false if nothing changed */
static bool _remove_old_prefix(gnrc_netif_t *netif,
const ipv6_addr_t *pfx, uint8_t pfx_len,
Expand Down Expand Up @@ -354,7 +398,7 @@
}

static void _configure_subnets(uint8_t subnets, uint8_t start_idx, gnrc_netif_t *upstream,
const ndp_opt_pi_t *pio)
const ndp_opt_pi_t *pio, const ipv6_addr_t *src)
{
gnrc_netif_t *downstream = NULL;
gnrc_pktsnip_t *ext_opts = NULL;
Expand Down Expand Up @@ -393,7 +437,19 @@
}

/* create subnet from upstream prefix */
_init_sub_prefix(&new_prefix, prefix, prefix_len, ++start_idx, subnet_len);
if (IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_EUI)) {
uint8_t hwaddr[GNRC_NETIF_L2ADDR_MAXLEN];
int hwaddr_len = netif_get_opt(&downstream->netif, NETOPT_ADDRESS, 0,
hwaddr, sizeof(hwaddr));
if (hwaddr_len <= 0) {
DEBUG("auto_subnets: can't get l2 address from netif %u\n", downstream->pid);
continue;
}
new_prefix_len = _init_sub_prefix_eui(&new_prefix, prefix, prefix_len, hwaddr, hwaddr_len);

Check warning on line 448 in sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
new_prefix_len = MAX(new_prefix_len, CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_MIN_LEN);
} else {
_init_sub_prefix(&new_prefix, prefix, prefix_len, ++start_idx, subnet_len);
}

DEBUG("auto_subnets: configure prefix %s/%u on %u\n",
ipv6_addr_to_str(addr_str, &new_prefix, sizeof(addr_str)),
Expand Down Expand Up @@ -429,13 +485,14 @@

/* immediately send an RA with RIO */
if (ext_opts) {
gnrc_ndp_rtr_adv_send(upstream, NULL, NULL, true, ext_opts);
gnrc_ndp_rtr_adv_send(upstream, NULL, src, true, ext_opts);
} else {
DEBUG("auto_subnets: Options empty, not sending RA\n");
}
}

void gnrc_ipv6_nib_rtr_adv_pio_cb(gnrc_netif_t *upstream, const ndp_opt_pi_t *pio)
void gnrc_ipv6_nib_rtr_adv_pio_cb(gnrc_netif_t *upstream, const ndp_opt_pi_t *pio,
const ipv6_addr_t *src)
mguetschow marked this conversation as resolved.
Show resolved Hide resolved
{
/* create a subnet for each downstream interface */
unsigned subnets = gnrc_netif_numof() - 1;
Expand All @@ -454,13 +511,18 @@
}

#if IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE)
/* 'don't broadcast RA if we are a 6lo node - unicast allows l2 retransmissions */
if (!gnrc_netif_is_6ln(upstream)) {
src = NULL;
}
/* if we are the only router on this bus, we can directly choose a prefix */
_configure_subnets(subnets, 0, upstream, pio);
_configure_subnets(subnets, 0, upstream, pio, src);
#else
(void)src;

/* store PIO information for later use */
if (!_store_pio(pio)) {
DEBUG("auto_subnets: no space left in PIO cache, increase CONFIG_GNRC_IPV6_AUTO_SUBNETS_NUMOF\n");

Check warning on line 525 in sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
return;
}
_upstream = upstream;
Expand Down Expand Up @@ -628,7 +690,7 @@
}

/* use PIO for prefix configuration */
_configure_subnets(subnets, idx_start, upstream, &_pio_cache[i]);
_configure_subnets(subnets, idx_start, upstream, &_pio_cache[i], NULL);

/* invalidate entry */
_pio_cache[i].len = 0;
Expand Down
Loading