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:
commit
a07d3e0fc9
@ -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
|
||||
|
@ -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
2
dist/tools/Makefile
vendored
@ -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
16
dist/tools/zep_dispatch/Makefile
vendored
Normal 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
121
dist/tools/zep_dispatch/main.c
vendored
Normal 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
99
dist/tools/zep_dispatch/start_network.sh
vendored
Executable 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}" "$@"
|
@ -14,4 +14,5 @@ ifeq (,$(filter native,$(BOARD)))
|
||||
endif
|
||||
else
|
||||
USEMODULE += socket_zep
|
||||
USEMODULE += socket_zep_hello
|
||||
endif
|
||||
|
@ -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)))
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user