Skip to content

Commit 698d414

Browse files
committed
gnrc/ipv6_auto_subnets: add gnrc_ipv6_auto_subnets_eui
1 parent 64c10f3 commit 698d414

3 files changed

Lines changed: 63 additions & 1 deletion

File tree

makefiles/pseudomodules.inc.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ PSEUDOMODULES += gnrc_dhcpv6_client_simple_pd
107107
## @}
108108
## @}
109109
PSEUDOMODULES += gnrc_ipv6_auto_subnets_auto_init
110+
PSEUDOMODULES += gnrc_ipv6_auto_subnets_eui
110111
PSEUDOMODULES += gnrc_ipv6_auto_subnets_simple
111112
PSEUDOMODULES += gnrc_ipv6_classic
112113
PSEUDOMODULES += gnrc_ipv6_default

sys/net/gnrc/Makefile.dep

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ ifneq (,$(filter gnrc_rpl,$(USEMODULE)))
126126
USEMODULE += evtimer
127127
endif
128128

129+
ifneq (,$(filter gnrc_ipv6_auto_subnets_eui,$(USEMODULE)))
130+
USEMODULE += gnrc_ipv6_auto_subnets_simple
131+
endif
132+
129133
ifneq (,$(filter gnrc_ipv6_auto_subnets_simple,$(USEMODULE)))
130134
USEMODULE += gnrc_ipv6_auto_subnets
131135
endif

sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,24 @@
8383
* The upstream network will be automatically chosen as the one that first
8484
* receives a router advertisement.
8585
*
86+
* If only a single level of downstream routers exists and a sufficiently small
87+
* upstream prefix is provided, we can skip the synchronisation and instead derive
88+
* the *prefix* from the EUI of the downstream interface.
89+
*
90+
* e.g. given a prefix `fd12::/16` a router with a downstream interface with the
91+
* layer 2 address `12:84:0C:87:1F:B7` would create the prefix `fd12:1284:c87:1fb7::/64`
92+
* for the downstream network.
93+
*
94+
* To enable this behavior, chose the `gnrc_ipv6_auto_subnets_eui` module.
95+
*
8696
* @{
8797
*
8898
* @file
8999
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
90100
*/
91101

92102
#include "compiler_hints.h"
103+
#include "macros/utils.h"
93104
#include "net/gnrc/ipv6.h"
94105
#include "net/gnrc/netif.h"
95106
#include "net/gnrc/netif/hdr.h"
@@ -305,6 +316,39 @@ static void _init_sub_prefix(ipv6_addr_t *out,
305316
out->u8[bytes] |= idx << shift;
306317
}
307318

319+
static uint8_t _init_sub_prefix_eui(ipv6_addr_t *out,
320+
const ipv6_addr_t *prefix, uint8_t bits,
321+
const uint8_t *eui, uint8_t eui_len)
322+
{
323+
assert(eui_len <= sizeof(uint64_t));
324+
325+
/* If the EUI is too large, discard most significant bits as
326+
those are typically manufacturer ID */
327+
uint64_t mask = UINT64_MAX >> bits;
328+
329+
union {
330+
uint64_t u64;
331+
uint8_t u8[8];
332+
} eui64 = {};
333+
uint64_t pfx = byteorder_ntohll(prefix->u64[0]);
334+
335+
/* If EUI is small, we want to preserve leftover unused bits at the end */
336+
uint8_t bits_total = bits + 8 * eui_len;
337+
uint8_t shift = bits_total < 64
338+
? 64 - bits_total
339+
: 0;
340+
341+
/* treat EUI as a EUI-64 with unused bytes set to 0 */
342+
memcpy(&eui64.u8[sizeof(uint64_t) - eui_len], eui, eui_len);
343+
eui64.u64 = ntohll(eui64.u64) & mask;
344+
345+
/* create downstream prefix from upstream prefix + masked EUI64 */
346+
out->u64[0] = byteorder_htonll(pfx | (eui64.u64 << shift));
347+
348+
/* we don't create prefixes that longer than 64 bits */
349+
return MIN(64, bits_total);
350+
}
351+
308352
/* returns true if a new prefix was added, false if nothing changed */
309353
static bool _remove_old_prefix(gnrc_netif_t *netif,
310354
const ipv6_addr_t *pfx, uint8_t pfx_len,
@@ -393,7 +437,19 @@ static void _configure_subnets(uint8_t subnets, uint8_t start_idx, gnrc_netif_t
393437
}
394438

395439
/* create subnet from upstream prefix */
396-
_init_sub_prefix(&new_prefix, prefix, prefix_len, ++start_idx, subnet_len);
440+
if (IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_EUI)) {
441+
uint8_t hwaddr[GNRC_NETIF_L2ADDR_MAXLEN];
442+
int hwaddr_len = netif_get_opt(&downstream->netif, NETOPT_ADDRESS, 0,
443+
hwaddr, sizeof(hwaddr));
444+
if (hwaddr_len <= 0) {
445+
DEBUG("auto_subnets: can't get l2 address from netif %u\n", downstream->pid);
446+
continue;
447+
}
448+
new_prefix_len = _init_sub_prefix_eui(&new_prefix, prefix, prefix_len, hwaddr, hwaddr_len);
449+
new_prefix_len = MAX(new_prefix_len, CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_MIN_LEN);
450+
} else {
451+
_init_sub_prefix(&new_prefix, prefix, prefix_len, ++start_idx, subnet_len);
452+
}
397453

398454
DEBUG("auto_subnets: configure prefix %s/%u on %u\n",
399455
ipv6_addr_to_str(addr_str, &new_prefix, sizeof(addr_str)),
@@ -462,6 +518,7 @@ void gnrc_ipv6_nib_rtr_adv_pio_cb(gnrc_netif_t *upstream, const ndp_opt_pi_t *pi
462518
/* if we are the only router on this bus, we can directly choose a prefix */
463519
_configure_subnets(subnets, 0, upstream, pio, src);
464520
#else
521+
(void)src;
465522

466523
/* store PIO information for later use */
467524
if (!_store_pio(pio)) {

0 commit comments

Comments
 (0)