From faae6d56be98475ae80d29f4a80e4723d32516c7 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 27 Jun 2021 18:38:00 +0200 Subject: [PATCH] examples: add example for cascading subnets --- examples/gnrc_networking_subnets/Makefile | 50 ++++++++++++ examples/gnrc_networking_subnets/Makefile.ci | 38 +++++++++ examples/gnrc_networking_subnets/README.md | 78 +++++++++++++++++++ examples/gnrc_networking_subnets/main.c | 1 + .../gnrc_networking_subnets/setup_taps.sh | 64 +++++++++++++++ examples/gnrc_networking_subnets/tapology.txt | 9 +++ examples/gnrc_networking_subnets/udp.c | 1 + 7 files changed, 241 insertions(+) create mode 100644 examples/gnrc_networking_subnets/Makefile create mode 100644 examples/gnrc_networking_subnets/Makefile.ci create mode 100644 examples/gnrc_networking_subnets/README.md create mode 120000 examples/gnrc_networking_subnets/main.c create mode 100755 examples/gnrc_networking_subnets/setup_taps.sh create mode 100644 examples/gnrc_networking_subnets/tapology.txt create mode 120000 examples/gnrc_networking_subnets/udp.c diff --git a/examples/gnrc_networking_subnets/Makefile b/examples/gnrc_networking_subnets/Makefile new file mode 100644 index 0000000000..025cd6e13b --- /dev/null +++ b/examples/gnrc_networking_subnets/Makefile @@ -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 diff --git a/examples/gnrc_networking_subnets/Makefile.ci b/examples/gnrc_networking_subnets/Makefile.ci new file mode 100644 index 0000000000..04703170cd --- /dev/null +++ b/examples/gnrc_networking_subnets/Makefile.ci @@ -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 \ + # diff --git a/examples/gnrc_networking_subnets/README.md b/examples/gnrc_networking_subnets/README.md new file mode 100644 index 0000000000..2707ee3fbb --- /dev/null +++ b/examples/gnrc_networking_subnets/README.md @@ -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). diff --git a/examples/gnrc_networking_subnets/main.c b/examples/gnrc_networking_subnets/main.c new file mode 120000 index 0000000000..f6a0e7f508 --- /dev/null +++ b/examples/gnrc_networking_subnets/main.c @@ -0,0 +1 @@ +../gnrc_networking/main.c \ No newline at end of file diff --git a/examples/gnrc_networking_subnets/setup_taps.sh b/examples/gnrc_networking_subnets/setup_taps.sh new file mode 100755 index 0000000000..15c36626f8 --- /dev/null +++ b/examples/gnrc_networking_subnets/setup_taps.sh @@ -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 ] [-d topology]" + exit 1 + ;; + esac +fi + +setup "$TOPOLOGY" diff --git a/examples/gnrc_networking_subnets/tapology.txt b/examples/gnrc_networking_subnets/tapology.txt new file mode 100644 index 0000000000..04e21b7865 --- /dev/null +++ b/examples/gnrc_networking_subnets/tapology.txt @@ -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 diff --git a/examples/gnrc_networking_subnets/udp.c b/examples/gnrc_networking_subnets/udp.c new file mode 120000 index 0000000000..c03f41c7ed --- /dev/null +++ b/examples/gnrc_networking_subnets/udp.c @@ -0,0 +1 @@ +../gnrc_networking/udp.c \ No newline at end of file