Skip to content

Commit

Permalink
Merge pull request #21080 from benpicco/gnrc_ipv6_auto_subnets_eui
Browse files Browse the repository at this point in the history
gnrc/ipv6_auto_subnets: add option to derive subnet prefix from EUI
  • Loading branch information
benpicco authored Jan 16, 2025
2 parents f4fcac2 + 698d414 commit cefa182
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 8 deletions.
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 @@ -849,8 +849,9 @@ static void _handle_rtr_adv(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
/* 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 @@ static void _init_sub_prefix(ipv6_addr_t *out,
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 bool _remove_old_prefix(gnrc_netif_t *netif,
}

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 @@ static void _configure_subnets(uint8_t subnets, uint8_t start_idx, gnrc_netif_t
}

/* 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 @@ static void _configure_subnets(uint8_t subnets, uint8_t start_idx, gnrc_netif_t

/* 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)
{
/* create a subnet for each downstream interface */
unsigned subnets = gnrc_netif_numof() - 1;
Expand All @@ -454,9 +511,14 @@ void gnrc_ipv6_nib_rtr_adv_pio_cb(gnrc_netif_t *upstream, const ndp_opt_pi_t *pi
}

#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)) {
Expand Down Expand Up @@ -628,7 +690,7 @@ static void _process_pio_cache(uint8_t subnets, uint8_t idx_start, gnrc_netif_t
}

/* 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

0 comments on commit cefa182

Please sign in to comment.