mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16536 from benpicco/gnrc_ipv6_nib_subnets
gnrc_ipv6_simple_subnets: auto-configuration for nested subnets on a simple tree topology
This commit is contained in:
commit
9ac9b41a57
35
doc/doxygen/src/gnrc_ipv6_auto_subnets_simple.puml
Normal file
35
doc/doxygen/src/gnrc_ipv6_auto_subnets_simple.puml
Normal file
@ -0,0 +1,35 @@
|
||||
' to generate SVG run plantuml -tsvg gnrc_ipv6_auto_subnets_simple.puml
|
||||
@startuml
|
||||
nwdiag {
|
||||
|
||||
network level1 {
|
||||
address = "2001:db8::/60";
|
||||
|
||||
router_a [address = "2001:db8::<color:#8a8a8a>c8f4:13ff:fece:3f43", description = "1st level router"];
|
||||
leaf_a [address = "2001:db8::<color:#8a8a8a>804b:fcff:feb6:43fb", description = "1st level leaf node"];
|
||||
}
|
||||
|
||||
network level2 {
|
||||
address = "2001:db8:0:8::/61";
|
||||
|
||||
router_a [address = "2001:db8:0:8:<color:#8a8a8a>3c27:6dff:fe25:e95d"];
|
||||
router_b [address = "2001:db8:0:8:<color:#8a8a8a>5075:35ff:fefa:30bc", description = "2nd level router"];
|
||||
}
|
||||
|
||||
network level3 {
|
||||
address = "2001:db8:0:c::/62";
|
||||
|
||||
router_b [address = "2001:db8:0:c:<color:#8a8a8a>2ca3:9eff:fea9:68f7"];
|
||||
router_c [address = "2001:db8:0:c:<color:#8a8a8a>fc33:13ff:fe93:5ae4", description = "3rd level router"];
|
||||
leaf_b1 [address = "2001:db8:0:c:<color:#8a8a8a>209e:deff:fea9:fd1b", description = "3rd level leaf node"];
|
||||
leaf_b2 [address = "2001:db8:0:c:<color:#8a8a8a>5491:a2ff:fe98:61a2", description = "3rd level leaf node"];
|
||||
}
|
||||
|
||||
network level4 {
|
||||
address = "2001:db8:0:e::/63";
|
||||
|
||||
router_c [address = "2001:db8:0:e:<color:#8a8a8a>a8d9:e1ff:feab:d544"];
|
||||
leaf_c [address = "2001:db8:0:e:<color:#8a8a8a>1cf5:33ff:fe7c:c70c", description = "4th level leaf node"];
|
||||
}
|
||||
}
|
||||
@enduml
|
1
doc/doxygen/src/gnrc_ipv6_auto_subnets_simple.svg
Normal file
1
doc/doxygen/src/gnrc_ipv6_auto_subnets_simple.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.9 KiB |
50
examples/gnrc_networking_subnets/Makefile
Normal file
50
examples/gnrc_networking_subnets/Makefile
Normal file
@ -0,0 +1,50 @@
|
||||
# name of your application
|
||||
APPLICATION = gnrc_networking-subnets
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
# Include packages that pull up and auto-init the link layer.
|
||||
USEMODULE += gnrc_netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
# Activate ICMPv6 error messages
|
||||
USEMODULE += gnrc_icmpv6_error
|
||||
# Specify the mandatory networking modules for IPv6 and UDP
|
||||
USEMODULE += gnrc_udp
|
||||
# This application dumps received packets to STDIO using the pktdump module
|
||||
USEMODULE += gnrc_pktdump
|
||||
# Additional networking modules that can be dropped if not needed
|
||||
USEMODULE += gnrc_icmpv6_echo
|
||||
# Add also the shell, some shell commands
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
USEMODULE += netstats_l2
|
||||
USEMODULE += netstats_ipv6
|
||||
|
||||
# leaf nodes only have a single interface
|
||||
ifeq (1, $(LEAF))
|
||||
APPLICATION := $(APPLICATION)_leaf
|
||||
USEMODULE += gnrc_ipv6_default
|
||||
else
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_ipv6_auto_subnets
|
||||
CFLAGS += -DNETDEV_TAP_MAX=2
|
||||
PORT ?= tap_a0 tap_b0
|
||||
endif
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
DEVELHELP ?= 1
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
# Set a custom channel if needed
|
||||
include $(RIOTMAKE)/default-radio-settings.inc.mk
|
38
examples/gnrc_networking_subnets/Makefile.ci
Normal file
38
examples/gnrc_networking_subnets/Makefile.ci
Normal file
@ -0,0 +1,38 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-mega2560 \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega1284p \
|
||||
atmega328p \
|
||||
atmega328p-xplained-mini \
|
||||
atxmega-a3bu-xplained \
|
||||
bluepill-stm32f030c8 \
|
||||
derfmega128 \
|
||||
i-nucleo-lrwan1 \
|
||||
ict_panhead \
|
||||
m1284p \
|
||||
mega-xplained \
|
||||
microduino-corerf \
|
||||
msb-430 \
|
||||
msb-430h \
|
||||
nucleo-f030r8 \
|
||||
nucleo-f031k6 \
|
||||
nucleo-f042k6 \
|
||||
nucleo-f303k8 \
|
||||
nucleo-f334r8 \
|
||||
nucleo-l011k4 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
samd10-xmini \
|
||||
slstk3400a \
|
||||
stk3200 \
|
||||
stm32f030f4-demo \
|
||||
stm32f0discovery \
|
||||
stm32l0538-disco \
|
||||
telosb \
|
||||
waspmote-pro \
|
||||
z1 \
|
||||
zigduino \
|
||||
#
|
78
examples/gnrc_networking_subnets/README.md
Normal file
78
examples/gnrc_networking_subnets/README.md
Normal file
@ -0,0 +1,78 @@
|
||||
# Auto-configuration for nested subnets on a (simple) tree topology
|
||||
|
||||
This example demonstrates IPv6 subnet auto-configuration for networks on a
|
||||
tree topology.
|
||||
|
||||
This allows to connect multiple links with individual subnets and route
|
||||
between them.
|
||||
Each link can have an arbitrary number of hosts, but there can be only
|
||||
a single router on each link.
|
||||
Routers can have multiple interfaces to connect different downlinks.
|
||||
|
||||
![](../../doc/doxygen/src/gnrc_ipv6_auto_subnets_simple.svg)
|
||||
|
||||
## Setup on native
|
||||
|
||||
To simulate such a network on `native` a `setup_taps.sh` script is provided that
|
||||
will create TAP interfaces and bridges.
|
||||
Each bridge will be it's own subnet and `native` instances will act as routers
|
||||
to route between them.
|
||||
The setup script will also start `radvd` to advertise a large prefix that allows
|
||||
for sub-division by RIOT.
|
||||
|
||||
The interfaces that should be created are specified in the `tapology.txt` file.
|
||||
|
||||
Each router will have (at least) two interfaces that should be on different
|
||||
bridges.
|
||||
|
||||
To start the first router, run
|
||||
|
||||
make term PORT="tap_a0 tap_b1"
|
||||
|
||||
This will route between the `tap_a0` interface on `br0` and the `tap_b1`
|
||||
interface on `br1`.
|
||||
Start more `native` instances to simulate a cascading tree network:
|
||||
|
||||
make term PORT="tap_b0 tap_c1"
|
||||
make term PORT="tap_c0 tap_d1"
|
||||
…
|
||||
|
||||
It is also possible to connect non-routing leaf nodes with a single interface:
|
||||
|
||||
make flash term LEAF=1 PORT=tap_b2
|
||||
|
||||
|
||||
## Setup on hardware
|
||||
|
||||
On physical hardware the setup will be the same.
|
||||
Routing nodes need at least two interfaces between which they can route.
|
||||
For a simple setup, you can use `ethos` or `slipdev` to turn any UART into
|
||||
a network interface. (If you need to use DHCPv6 IA_PD for obtaining a prefix,
|
||||
use `slipdev_l2addr` instead of plain `slipdev`)
|
||||
|
||||
### Obtaining the prefix
|
||||
|
||||
#### Via router advertisements
|
||||
|
||||
Usually routers are configured to advertise a /64 prefix that can not be divided
|
||||
further when using SLAAC.
|
||||
If you can configure your router to advertise a larger prefix instead, this
|
||||
will be the easiest solution.
|
||||
|
||||
#### Via DHCPv6
|
||||
|
||||
If you can't change the configuration of your router, but your router supports
|
||||
DHCPv6 IA_PD, you can use this to request a larger prefix.
|
||||
|
||||
This requires a gateway node that uses the `gnrc_dhcpv6_client_simple_pd`
|
||||
module *instead* of `gnrc_ipv6_auto_subnets`.
|
||||
|
||||
Make sure to set the `CONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM` option to the
|
||||
ID of the upstream interface on the gateway device, e.g.
|
||||
|
||||
CFLAGS += -DCONFIG_GNRC_DHCPV6_CLIENT_6LBR_UPSTREAM=6
|
||||
|
||||
As with GNRC the interface ID is based on the PID of the interface thread, this can
|
||||
change if you add modules / threads and is a common source of errors.
|
||||
If the configuration is set wrong, you will not get a prefix for the downstream
|
||||
interface(s).
|
1
examples/gnrc_networking_subnets/main.c
Symbolic link
1
examples/gnrc_networking_subnets/main.c
Symbolic link
@ -0,0 +1 @@
|
||||
../gnrc_networking/main.c
|
64
examples/gnrc_networking_subnets/setup_taps.sh
Executable file
64
examples/gnrc_networking_subnets/setup_taps.sh
Executable file
@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
PREFIX=2001:db8::/60
|
||||
|
||||
SCRIPTPATH=$(dirname $(realpath "$0"))
|
||||
|
||||
RIOTBASE=$SCRIPTPATH/../..
|
||||
RIOTTOOLS=$RIOTBASE/dist/tools
|
||||
TOPOLOGY=$SCRIPTPATH/tapology.txt
|
||||
|
||||
setup() {
|
||||
echo "creating tap interfaces"
|
||||
i=0
|
||||
sed '/^#/d' "$1" | while read -r level num; do
|
||||
# we actually want to execute the output here.
|
||||
# shellcheck disable=SC2091
|
||||
$(printf -- "sudo %s/tapsetup/tapsetup -b br%s -t tap_%s -c %s\n" "$RIOTTOOLS" "$i" "$level" "$num") > /dev/null;
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
# add address to br0 so this can be tested by pinging the host system
|
||||
sudo ip addr add ${PREFIX/::\//::1\/} dev br0
|
||||
|
||||
# start radvd with a large prefix
|
||||
sudo "$RIOTTOOLS"/radvd/radvd.sh -c br0 $PREFIX
|
||||
}
|
||||
|
||||
teardown() {
|
||||
echo "deleting tap interfaces"
|
||||
i=0
|
||||
sed '/^#/d' "$1" | while read -r level num; do
|
||||
$(printf -- "sudo %s/tapsetup/tapsetup -b br%s -t tap_%s -d\n" "$RIOTTOOLS" "$i" "$level") > /dev/null;
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
# stop radvd
|
||||
sudo "$RIOTTOOLS"/radvd/radvd.sh -d
|
||||
}
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
TOPOLOGY=$2
|
||||
fi
|
||||
|
||||
if [ ! -f "$TOPOLOGY" ]; then
|
||||
echo "no such file: $TOPOLOGY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
case $1 in
|
||||
-c)
|
||||
;;
|
||||
-d)
|
||||
teardown "$TOPOLOGY"
|
||||
exit
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 [-c <topology>] [-d topology]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
setup "$TOPOLOGY"
|
9
examples/gnrc_networking_subnets/tapology.txt
Normal file
9
examples/gnrc_networking_subnets/tapology.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# This file specifies the tap bridges and tap devices that
|
||||
# should be created.
|
||||
#
|
||||
# bridge nodes
|
||||
a 1
|
||||
b 3
|
||||
c 3
|
||||
d 3
|
||||
e 3
|
1
examples/gnrc_networking_subnets/udp.c
Symbolic link
1
examples/gnrc_networking_subnets/udp.c
Symbolic link
@ -0,0 +1 @@
|
||||
../gnrc_networking/udp.c
|
@ -48,6 +48,7 @@ PSEUDOMODULES += gnrc_ipv6_nib_6lr
|
||||
PSEUDOMODULES += gnrc_ipv6_nib_dns
|
||||
PSEUDOMODULES += gnrc_ipv6_nib_rio
|
||||
PSEUDOMODULES += gnrc_ipv6_nib_router
|
||||
PSEUDOMODULES += gnrc_ipv6_nib_rtr_adv_pio_cb
|
||||
PSEUDOMODULES += gnrc_netdev_default
|
||||
PSEUDOMODULES += gnrc_neterr
|
||||
PSEUDOMODULES += gnrc_netapi_callbacks
|
||||
|
@ -88,6 +88,9 @@ endif
|
||||
ifneq (,$(filter gnrc_rpl_p2p,$(USEMODULE)))
|
||||
DIRS += routing/rpl/p2p
|
||||
endif
|
||||
ifneq (,$(filter gnrc_ipv6_auto_subnets,$(USEMODULE)))
|
||||
DIRS += routing/ipv6_auto_subnets
|
||||
endif
|
||||
ifneq (,$(filter gnrc_sixlowpan,$(USEMODULE)))
|
||||
DIRS += network_layer/sixlowpan
|
||||
endif
|
||||
|
@ -113,6 +113,12 @@ ifneq (,$(filter gnrc_rpl,$(USEMODULE)))
|
||||
USEMODULE += evtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_ipv6_auto_subnets,$(USEMODULE)))
|
||||
USEMODULE += gnrc_ipv6_nib_rtr_adv_pio_cb
|
||||
CFLAGS += -DCONFIG_GNRC_IPV6_NIB_ADV_ROUTER=0
|
||||
CFLAGS += -DCONFIG_GNRC_IPV6_NIB_ADD_RIO_IN_LAST_RA=1
|
||||
endif
|
||||
|
||||
ifneq (,$(filter gnrc_netif,$(USEMODULE)))
|
||||
USEMODULE += netif
|
||||
USEMODULE += l2util
|
||||
|
@ -754,6 +754,13 @@ static void _handle_rtr_adv(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
|
||||
(ndp_opt_pi_t *)opt);
|
||||
#endif /* CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C */
|
||||
next_timeout = _min(next_timeout, min_pfx_timeout);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ABRO was already secured in the option check above */
|
||||
|
3
sys/net/gnrc/routing/ipv6_auto_subnets/Makefile
Normal file
3
sys/net/gnrc/routing/ipv6_auto_subnets/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_ipv6_auto_subnets
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
218
sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c
Normal file
218
sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2021 ML!PA Consulting GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_ipv6_auto_subnets Simple-Subnet auto-configuration
|
||||
* @ingroup net_gnrc
|
||||
* @brief Automatic configuration for cascading subnets
|
||||
*
|
||||
* About
|
||||
* =====
|
||||
*
|
||||
* This module provides an automatic configuration for networks with a simple
|
||||
* tree topology.
|
||||
*
|
||||
* If a sufficiently large IPv6 prefix (> /64) is provided via Router Advertisements,
|
||||
* a routing node with this module will automatically configure subnets from it
|
||||
* by dividing it into sub-prefixes for each downstream interface.
|
||||
*
|
||||
* There can only be a single routing node on each level of the network but an
|
||||
* arbitrary number of leaf nodes.
|
||||
*
|
||||
* ![Example Topology](gnrc_ipv6_auto_subnets_simple.svg)
|
||||
*
|
||||
* The downstream network(s) receive the sub-prefix via Router Advertisements
|
||||
* and the process repeats until the bits of the prefix are exhausted.
|
||||
* The smallest subnet must still have a /64 prefix.
|
||||
*
|
||||
* The new subnet must no longer be considered on-link by the hosts in the
|
||||
* parent network.
|
||||
* Therefore the downstream router will send a router advertisement with only
|
||||
* a Route Information Option included to the upstream network.
|
||||
* The Route Information Option contains the prefix of the downstream network
|
||||
* so that upstream routers will no longer consider hosts in this subnet on-link
|
||||
* but instead will use the downstream router to route to the new subnet.
|
||||
*
|
||||
* Usage
|
||||
* =====
|
||||
*
|
||||
* Simply add the `gnrc_ipv6_auto_subnets` module to the code of the nodes that
|
||||
* should act as routers in the cascading network.
|
||||
* The upstream network will be automatically chosen as the one that first
|
||||
* receives a router advertisement.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
*/
|
||||
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/gnrc/ndp.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
|
||||
static void _init_sub_prefix(ipv6_addr_t *out,
|
||||
const ipv6_addr_t *prefix, uint8_t bits,
|
||||
uint8_t idx, uint8_t idx_bits)
|
||||
{
|
||||
uint8_t bytes = bits / 8;
|
||||
uint8_t rem = bits % 8;
|
||||
int8_t shift = 8 - rem - idx_bits;
|
||||
|
||||
/* first copy old prefix */
|
||||
memset(out, 0, sizeof(*out));
|
||||
ipv6_addr_init_prefix(out, prefix, bits);
|
||||
|
||||
/* if new bits are between bytes, first copy over the most significant bits */
|
||||
if (shift < 0) {
|
||||
out->u8[bytes] |= idx >> -shift;
|
||||
out->u8[++bytes] = 0;
|
||||
shift += 8;
|
||||
}
|
||||
|
||||
/* shift remaining bits at the end of the prefix */
|
||||
out->u8[bytes] |= idx << shift;
|
||||
}
|
||||
|
||||
static bool _remove_old_prefix(gnrc_netif_t *netif,
|
||||
const ipv6_addr_t *pfx, uint8_t pfx_len,
|
||||
gnrc_pktsnip_t **ext_opts)
|
||||
{
|
||||
gnrc_ipv6_nib_pl_t entry;
|
||||
gnrc_pktsnip_t *tmp;
|
||||
void *state = NULL;
|
||||
ipv6_addr_t old_pfx;
|
||||
uint8_t old_pfx_len = 0;
|
||||
|
||||
/* iterate prefix list to see if the prefix already exists */
|
||||
while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &entry)) {
|
||||
uint8_t match_len = ipv6_addr_match_prefix(&entry.pfx, pfx);
|
||||
|
||||
/* The prefix did not change - nothing to do here */
|
||||
if (match_len >= pfx_len && pfx_len == entry.pfx_len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* find prefix that is closest to the new prefix */
|
||||
if (match_len > old_pfx_len) {
|
||||
old_pfx_len = entry.pfx_len;
|
||||
old_pfx = entry.pfx;
|
||||
}
|
||||
}
|
||||
|
||||
/* no prefix found */
|
||||
if (old_pfx_len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG("auto_subnets: remove old prefix %s/%u\n",
|
||||
ipv6_addr_to_str(addr_str, &old_pfx, sizeof(addr_str)), old_pfx_len);
|
||||
|
||||
/* invalidate old prefix in RIO */
|
||||
tmp = gnrc_ndp_opt_ri_build(&old_pfx, old_pfx_len, 0,
|
||||
NDP_OPT_RI_FLAGS_PRF_NONE, *ext_opts);
|
||||
if (tmp) {
|
||||
*ext_opts = tmp;
|
||||
}
|
||||
|
||||
/* remove the prefix */
|
||||
gnrc_ipv6_nib_pl_del(netif->pid, &old_pfx, old_pfx_len);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _configure_subnets(uint8_t subnets, gnrc_netif_t *upstream,
|
||||
const ndp_opt_pi_t *pio)
|
||||
{
|
||||
gnrc_netif_t *downstream = NULL;
|
||||
gnrc_pktsnip_t *ext_opts = NULL;
|
||||
const ipv6_addr_t *prefix = &pio->prefix;
|
||||
uint32_t valid_ltime = byteorder_ntohl(pio->valid_ltime);
|
||||
uint32_t pref_ltime = byteorder_ntohl(pio->pref_ltime);
|
||||
const uint8_t prefix_len = pio->prefix_len;
|
||||
uint8_t new_prefix_len, subnet_len;
|
||||
|
||||
DEBUG("auto_subnets: create %u subnets\n", subnets);
|
||||
|
||||
/* Calculate remaining prefix length.
|
||||
* For n subnets we consume floor(log_2 n) + 1 bits.
|
||||
* To calculate floor(log_2 n) quickly, find the position of the
|
||||
* most significant set bit by counting leading zeros.
|
||||
*/
|
||||
subnet_len = 32 - __builtin_clz(subnets);
|
||||
new_prefix_len = prefix_len + subnet_len;
|
||||
|
||||
if (new_prefix_len > 64) {
|
||||
DEBUG("auto_subnets: can't split /%u into %u subnets\n", prefix_len, subnets);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((downstream = gnrc_netif_iter(downstream))) {
|
||||
gnrc_pktsnip_t *tmp;
|
||||
ipv6_addr_t new_prefix;
|
||||
|
||||
if (downstream == upstream) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* create subnet from upstream prefix */
|
||||
_init_sub_prefix(&new_prefix, prefix, prefix_len, subnets--, subnet_len);
|
||||
|
||||
DEBUG("auto_subnets: configure prefix %s/%u on %u\n",
|
||||
ipv6_addr_to_str(addr_str, &new_prefix, sizeof(addr_str)),
|
||||
new_prefix_len, downstream->pid);
|
||||
|
||||
/* first remove old prefix if the prefix changed */
|
||||
_remove_old_prefix(downstream, &new_prefix, new_prefix_len, &ext_opts);
|
||||
|
||||
/* configure subnet on downstream interface */
|
||||
gnrc_netif_ipv6_add_prefix(downstream, &new_prefix, new_prefix_len,
|
||||
valid_ltime, pref_ltime);
|
||||
|
||||
/* start advertising subnet */
|
||||
gnrc_ipv6_nib_change_rtr_adv_iface(downstream, true);
|
||||
|
||||
/* add route information option with new subnet */
|
||||
tmp = gnrc_ndp_opt_ri_build(&new_prefix, new_prefix_len, valid_ltime,
|
||||
NDP_OPT_RI_FLAGS_PRF_NONE, ext_opts);
|
||||
if (tmp == NULL) {
|
||||
DEBUG("auto_subnets: No space left in packet buffer. Not adding RIO\n");
|
||||
} else {
|
||||
ext_opts = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* immediately send an RA with RIO */
|
||||
if (ext_opts) {
|
||||
gnrc_ndp_rtr_adv_send(upstream, NULL,
|
||||
&ipv6_addr_all_nodes_link_local, 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)
|
||||
{
|
||||
/* create a subnet for each downstream interface */
|
||||
unsigned subnets = gnrc_netif_numof() - 1;
|
||||
|
||||
if (subnets == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pio->valid_ltime.u32 == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_configure_subnets(subnets, upstream, pio);
|
||||
}
|
||||
/** @} */
|
Loading…
Reference in New Issue
Block a user