1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #14755 from benpicco/examples/gnrc_border_router-native

examples/gnrc_border_route: simplify ZEP setup on native
This commit is contained in:
Martine Lenders 2020-11-13 18:41:03 +01:00 committed by GitHub
commit a07d3e0fc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 331 additions and 9 deletions

View File

@ -13,6 +13,39 @@
*
* @see @ref net_zep for protocol definitions
*
* This ZEP implementation can send a dummy HELLO packet on startup.
* This is used to make dispatchers aware of the node.
* To enable this behavior, add
*
* ```
* USEMODULE += socket_zep_hello
* ```
*
* to your Makefile.
*
* A ZEP dispatcher can just drop those packets (ZEP type 0xFF) if it
* chooses to parse the ZEP header.
*
* The header of the HELLO packet will look like this:
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Preamble (EX) | Version (2) | Type (255) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |
* + +
* | |
* + Reserved (0) +
* | |
* + +
* | |
* + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | 'H' | 'E' | 'L' |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 'L' | 'O' | 0 | 0 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0 | 0 | 0 | 0 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* @{
*
* @file

View File

@ -40,6 +40,9 @@
* (https://pubs.opengroup.org/onlinepubs/9699919799.2016edition/basedefs/time.h.html) */
#define TV_USEC_PER_SEC (1000000L)
/* dummy packet to register with ZEP dispatcher */
#define SOCKET_ZEP_V2_TYPE_HELLO (255)
static size_t _zep_hdr_fill_v2_data(socket_zep_t *dev, zep_v2_data_hdr_t *hdr,
size_t payload_len)
{
@ -390,6 +393,21 @@ static int _connect_remote(socket_zep_t *dev, const socket_zep_params_t *params)
return res;
}
static void _send_zep_hello(socket_zep_t *dev)
{
if (IS_USED(MODULE_SOCKET_ZEP_HELLO)) {
/* dummy packet */
zep_v2_data_hdr_t hdr = {
.hdr.preamble = "EX",
.hdr.version = 2,
.type = SOCKET_ZEP_V2_TYPE_HELLO,
.resv = "HELLO",
};
real_write(dev->sock_fd, &hdr, sizeof(hdr));
}
}
void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params)
{
int res;
@ -408,7 +426,10 @@ void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params)
dev->sock_fd = res;
}
_connect_remote(dev, params);
if (_connect_remote(dev, params) == 0) {
/* send dummy data to connect to dispatcher */
_send_zep_hello(dev);
}
/* generate hardware address from local address */
uint8_t ss_array[sizeof(struct sockaddr_storage)] = { 0 };

2
dist/tools/Makefile vendored
View File

@ -1,4 +1,4 @@
HOST_TOOLS=ethos uhcpd sliptty
HOST_TOOLS=ethos uhcpd sliptty zep_dispatch
.PHONY: all $(HOST_TOOLS)

16
dist/tools/zep_dispatch/Makefile vendored Normal file
View File

@ -0,0 +1,16 @@
CFLAGS?=-g -O3 -Wall -Wextra
BINARY := bin/zep_dispatch
all: bin $(BINARY)
bin:
mkdir bin
RIOTBASE:=../../..
RIOT_INCLUDE=$(RIOTBASE)/core/include
SRCS:=$(wildcard *.c)
$(BINARY): $(SRCS)
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) -I$(RIOT_INCLUDE) $(SRCS) -o $@
clean:
rm -f $(BINARY)

121
dist/tools/zep_dispatch/main.c vendored Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2020 Benjamin Valentin
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/
#ifndef ZEP_DISPATCH_PDU
#define ZEP_DISPATCH_PDU 256
#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "list.h"
#include "kernel_defines.h"
typedef struct {
list_node_t node;
struct sockaddr_in6 addr;
} zep_client_t;
static void dispatch_loop(int sock)
{
list_node_t head = { .next = NULL };
puts("entering loop…");
while (1) {
char addr_str[INET6_ADDRSTRLEN];
uint8_t buffer[ZEP_DISPATCH_PDU];
struct sockaddr_in6 src_addr;
socklen_t addr_len = sizeof(src_addr);
/* receive incoming packet */
ssize_t bytes_in = recvfrom(sock, buffer, sizeof(buffer), 0,
(struct sockaddr*)&src_addr, &addr_len);
if (bytes_in <= 0 || addr_len != sizeof(src_addr)) {
continue;
}
/* send packet to all other clients */
bool known_node = false;
list_node_t *prev = &head;
for (list_node_t* n = head.next; n; n = n->next) {
struct sockaddr_in6 *addr = &container_of(n, zep_client_t, node)->addr;
/* don't echo packet back to sender */
if (memcmp(&src_addr, addr, addr_len) == 0) {
known_node = true;
/* remove client if sending fails */
} else if (sendto(sock, buffer, bytes_in, 0, (struct sockaddr*)addr, addr_len) < 0) {
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
printf("removing [%s]:%d\n", addr_str, ntohs(addr->sin6_port));
prev->next = n->next;
free(n);
continue;
}
prev = n;
}
/* if the client new, add it to the broadcast list */
if (!known_node) {
inet_ntop(AF_INET6, &src_addr.sin6_addr, addr_str, INET6_ADDRSTRLEN);
printf("adding [%s]:%d\n", addr_str, ntohs(src_addr.sin6_port));
zep_client_t *client = malloc(sizeof(zep_client_t));
memcpy(&client->addr, &src_addr, addr_len);
list_add(&head, &client->node);
}
}
}
int main(int argc, char **argv)
{
if (argc < 3) {
fprintf(stderr, "usage: %s <address> <port>\n",
argv[0]);
exit(1);
}
struct addrinfo hint = {
.ai_family = AF_INET6,
.ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP,
.ai_flags = AI_NUMERICHOST,
};
struct addrinfo *server_addr;
int res = getaddrinfo(argv[1], argv[2],
&hint, &server_addr);
if (res != 0) {
perror("getaddrinfo()");
exit(1);
}
int sock = socket(server_addr->ai_family, server_addr->ai_socktype,
server_addr->ai_protocol);
if (sock < 0) {
perror("socket() failed");
exit(1);
}
if (bind(sock, server_addr->ai_addr, server_addr->ai_addrlen) < 0) {
perror("bind() failed");
exit(1);
}
freeaddrinfo(server_addr);
dispatch_loop(sock);
close(sock);
return 0;
}

99
dist/tools/zep_dispatch/start_network.sh vendored Executable file
View File

@ -0,0 +1,99 @@
#!/usr/bin/env bash
ZEP_DISPATCH_DIR="$(cd "$(dirname "$0")" && pwd -P)"
UHCPD="$(cd "${ZEP_DISPATCH_DIR}/../uhcpd/bin" && pwd -P)/uhcpd"
DHCPD="$(cd "${ZEP_DISPATCH_DIR}/../dhcpv6-pd_ia/" && pwd -P)/dhcpv6-pd_ia.py"
ZEP_DISPATCH="${ZEP_DISPATCH_DIR}/bin/zep_dispatch"
TAP_GLB="fdea:dbee:f::1/64"
NOSUDO="sudo -u ${SUDO_USER}"
create_tap() {
ip tuntap add "${TAP}" mode tap user "${SUDO_USER}"
sysctl -w net.ipv6.conf."${TAP}".forwarding=1
sysctl -w net.ipv6.conf."${TAP}".accept_ra=0
ip link set "${TAP}" up
ip a a fe80::1/64 dev "${TAP}"
ip a a ${TAP_GLB} dev "${TAP}"
ip route add "${PREFIX}" via fe80::2 dev "${TAP}"
}
remove_tap() {
ip tuntap del "${TAP}" mode tap
}
cleanup() {
echo "Cleaning up..."
remove_tap
if [ -n "${UHCPD_PID}" ]; then
kill "${UHCPD_PID}"
fi
if [ -n "${ZEP_DISPATCH_PID}" ]; then
kill "${ZEP_DISPATCH_PID}"
fi
if [ -n "${DHCPD_PIDFILE}" ]; then
kill "$(cat "${DHCPD_PIDFILE}")"
rm "${DHCPD_PIDFILE}"
fi
trap "" INT QUIT TERM EXIT
}
start_uhcpd() {
${UHCPD} "${TAP}" "${PREFIX}" > /dev/null &
UHCPD_PID=$!
}
start_dhcpd() {
DHCPD_PIDFILE=$(mktemp)
${DHCPD} -d -p "${DHCPD_PIDFILE}" "${TAP}" "${PREFIX}" 2> /dev/null
}
start_zep_dispatch() {
${ZEP_DISPATCH} :: "${ZEP_PORT_BASE}" > /dev/null &
ZEP_DISPATCH_PID=$!
}
if [ "$1" = "-d" ] || [ "$1" = "--use-dhcpv6" ]; then
USE_DHCPV6=1
shift 1
else
USE_DHCPV6=0
fi
if [ "$1" = "-z" ] || [ "$1" = "--use-zep-dispatch" ]; then
USE_ZEP_DISPATCH=1
ZEP_PORT_BASE=$2
shift 2
else
USE_ZEP_DISPATCH=0
fi
ELFFILE=$1
PREFIX=$2
shift 2
# tap will be the last argument
for TAP in "$@"; do :; done
[[ -z "${ELFFILE}" || -z "${PREFIX}" || -z "${TAP}" ]] && {
echo "usage: $0 [-d|--use-dhcp] [-z|--use-zep <port>] " \
"<elffile> <prefix> [elf args]"
exit 1
}
trap "cleanup" INT QUIT TERM EXIT
create_tap
if [ ${USE_ZEP_DISPATCH} -eq 1 ]; then
start_zep_dispatch
fi
if [ ${USE_DHCPV6} -eq 1 ]; then
start_dhcpd
else
start_uhcpd
fi
${NOSUDO} "${ELFFILE}" "${TAP}" "$@"

View File

@ -14,4 +14,5 @@ ifeq (,$(filter native,$(BOARD)))
endif
else
USEMODULE += socket_zep
USEMODULE += socket_zep_hello
endif

View File

@ -9,11 +9,17 @@ CFLAGS += -DASYNC_READ_NUMOF=$(shell expr $(ZEP_DEVICES) + 1)
# Set CFLAGS if not being set via Kconfig
CFLAGS += $(if $(CONFIG_KCONFIG_MODULE_DHCPV6),,-DCONFIG_DHCPV6_CLIENT_PFX_LEASE_MAX=$(ZEP_DEVICES))
# -z [::1]:$PORT for each ZEP device
TERMFLAGS += $(patsubst %,-z [::1]:%, $(shell seq $(ZEP_PORT_BASE) $(ZEP_PORT_MAX)))
ifneq (1,$(USE_DHCPV6))
# We don't need to start ethos so just start the UHCPD daemon in the
# background
TERMDEPS += uhcpd-daemon
ifeq (1,$(USE_DHCPV6))
FLAGS_EXTRAS += --use-dhcpv6
endif
# enable the ZEP dispatcher
FLAGS_EXTRAS += -z $(ZEP_PORT_BASE)
# Configure terminal parameters
TERMDEPS += host-tools
TERMPROG_FLAGS = $(FLAGS_EXTRAS) $(ELFFILE) $(IPV6_PREFIX)
TERMPROG ?= sudo $(RIOTTOOLS)/zep_dispatch/start_network.sh $(TERMPROG_FLAGS)
# -z [::1]:$PORT for each ZEP device
TERMFLAGS ?= $(patsubst %,-z [::1]:%, $(shell seq $(ZEP_PORT_BASE) $(ZEP_PORT_MAX)))

View File

@ -24,6 +24,8 @@ This example comes with support for three uplink types pre-configured:
For `native` the host-facing [`netdev_tap`](https://doc.riot-os.org/netdev__tap_8h.html) device
is configured, providing connectivity via a TAP interface to the RIOT instance.
On the node-facing side [`socket_zep`](https://doc.riot-os.org/group__drivers__socket__zep.html)
is used to simulate a IEEE 802.15.4 network.
To select an uplink, set the UPLINK environment variable. For instance, use `UPLINK=slip`
for a SLIP uplink.
@ -143,6 +145,17 @@ On this example, such address can be pinged from 6lo motes:
Thus far, IPv6 communication with between your PC and your motes is enabled.
### Simulated network with native
On native a IEEE 802.15.4 network is simulated by encapsulating 802.15.4 frames
inside UDP packets. For this the `socket_zep` modules is used both on the border
router and on the virtual mote.
The UDP packets are sent to a dispatcher which forwards them to all other nodes.
By default a simple dispatcher is provided that will forward every packet to
every node (perfect broadcast), but it can be replaced by the user with alternative
dispatchers to simulate more advanced topologies.
# gnrc_border_router with manual config
You can use `ethos` as a standalone driver, if you want to setup the BR manually.

View File

@ -36,6 +36,17 @@ USEMODULE += netstats_rpl
# development process:
DEVELHELP ?= 1
# Instead of simulating an Ethernet connection, we can also simulate
# an IEEE 802.15.4 radio using ZEP
USE_ZEP ?= 0
# set the ZEP port for native
ZEP_PORT_BASE ?= 17754
ifeq (1,$(USE_ZEP))
TERMFLAGS += -z [::1]:$(ZEP_PORT_BASE)
USEMODULE += socket_zep
endif
# Uncomment the following 2 lines to specify static link lokal IPv6 address
# this might be useful for testing, in cases where you cannot or do not want to
# run a shell with ifconfig to get the real link lokal address.

View File

@ -118,6 +118,7 @@ PSEUDOMODULES += sock_dtls
PSEUDOMODULES += sock_ip
PSEUDOMODULES += sock_tcp
PSEUDOMODULES += sock_udp
PSEUDOMODULES += socket_zep_hello
PSEUDOMODULES += soft_uart_modecfg
PSEUDOMODULES += stdin
PSEUDOMODULES += stdio_cdc_acm