samples: net: echo-server: Add tunneling interface support

Add support for IP tunneling with overlay-tunnel.conf file.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2021-03-02 18:37:51 +02:00 committed by Anas Nashif
commit 64b7a11ccc
7 changed files with 210 additions and 0 deletions

View file

@ -21,6 +21,7 @@ target_sources( app PRIVATE src/echo-server.c)
target_sources_ifdef(CONFIG_NET_UDP app PRIVATE src/udp.c)
target_sources_ifdef(CONFIG_NET_TCP app PRIVATE src/tcp.c)
target_sources_ifdef(CONFIG_NET_VLAN app PRIVATE src/vlan.c)
target_sources_ifdef(CONFIG_NET_L2_IPIP app PRIVATE src/tunnel.c)
include(${ZEPHYR_BASE}/samples/net/common/common.cmake)

View file

@ -60,6 +60,18 @@ config NET_SAMPLE_IFACE3_VLAN_TAG
Set VLAN (virtual LAN) tag (id) that is used in the sample
application.
config NET_SAMPLE_TUNNEL_PEER_ADDR
string "Remote IP address of the tunnel interface"
depends on NET_L2_IPIP
help
Use overlay-tunnel.conf to setup the tunnel support.
config NET_SAMPLE_TUNNEL_MY_ADDR
string "My address for tunnel interface"
depends on NET_L2_IPIP
help
The value depends on your network setup.
config NET_SAMPLE_PSK_HEADER_FILE
string "Header file containing PSK"
default "dummy_psk.h"

View file

@ -54,6 +54,9 @@ echo-server directory:
- :file:`overlay-tls.conf`
This overlay config enables support for TLS.
- :file:`overlay-tunnel.conf`
This overlay config enables support for IP tunneling.
Build echo-server sample application like this:
.. zephyr-app-commands::

View file

@ -0,0 +1,16 @@
CONFIG_NET_L2_VIRTUAL=y
CONFIG_NET_L2_VIRTUAL_MGMT=y
CONFIG_NET_L2_IPIP=y
CONFIG_NET_IF_MAX_IPV6_COUNT=4
CONFIG_NET_IF_MAX_IPV4_COUNT=4
# First tunneling interface will have these settings
CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR="192.0.2.2"
#CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR="2001:db8::2"
# Use this for IPv6 over IPv4
CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR="2001:db8:200::1"
# Use this for IPv4 over IPv4
#CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR="198.51.100.1"

View file

@ -81,3 +81,19 @@ static inline int init_vlan(void)
return 0;
}
#endif /* CONFIG_NET_VLAN */
#if defined(CONFIG_NET_L2_IPIP)
int init_tunnel(void);
bool is_tunnel(struct net_if *iface);
#else
static inline int init_tunnel(void)
{
return 0;
}
static inline bool is_tunnel(struct net_if *iface)
{
ARG_UNUSED(iface);
return false;
}
#endif /* CONFIG_NET_L2_IPIP */

View file

@ -93,6 +93,11 @@ static void event_handler(struct net_mgmt_event_callback *cb,
want_to_quit = false;
}
if (is_tunnel(iface)) {
/* Tunneling is handled separately, so ignore it here */
return;
}
if (mgmt_event == NET_EVENT_L4_CONNECTED) {
LOG_INF("Network connected");
@ -192,6 +197,7 @@ static void init_app(void)
}
init_vlan();
init_tunnel();
}
static int cmd_sample_quit(const struct shell *shell,

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_DECLARE(net_echo_server_sample, LOG_LEVEL_DBG);
#include <zephyr.h>
#include <net/ethernet.h>
#include <net/virtual_mgmt.h>
/* User data for the interface callback */
struct ud {
struct net_if *tunnel;
struct net_if *peer;
};
bool is_tunnel(struct net_if *iface)
{
if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) {
return true;
}
return false;
}
static void iface_cb(struct net_if *iface, void *user_data)
{
struct ud *ud = user_data;
if (!ud->tunnel && is_tunnel(iface)) {
ud->tunnel = iface;
return;
}
}
static int setup_iface(struct net_if *iface, const char *ipaddr)
{
struct net_if_addr *ifaddr;
struct sockaddr addr;
if (!net_ipaddr_parse(ipaddr, strlen(ipaddr), &addr)) {
LOG_ERR("Tunnel peer address \"%s\" invalid.", ipaddr);
return -EINVAL;
}
if (IS_ENABLED(CONFIG_NET_IPV6) && addr.sa_family == AF_INET6) {
ifaddr = net_if_ipv6_addr_add(iface,
&net_sin6(&addr)->sin6_addr,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
LOG_ERR("Cannot add %s to interface %d",
ipaddr, net_if_get_by_iface(iface));
return -EINVAL;
}
}
if (IS_ENABLED(CONFIG_NET_IPV4) && addr.sa_family == AF_INET) {
ifaddr = net_if_ipv4_addr_add(iface,
&net_sin(&addr)->sin_addr,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
LOG_ERR("Cannot add %s to interface %d",
ipaddr, net_if_get_by_iface(iface));
return -EINVAL;
}
}
return 0;
}
int init_tunnel(void)
{
struct virtual_interface_req_params params = { 0 };
struct sockaddr peer = { 0 };
struct ud ud;
int ret;
int mtu;
memset(&ud, 0, sizeof(ud));
if (!net_ipaddr_parse(CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR,
strlen(CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR),
&peer)) {
LOG_ERR("Tunnel peer address \"%s\" invalid.",
CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR);
return -EINVAL;
}
if (IS_ENABLED(CONFIG_NET_IPV6) && peer.sa_family == AF_INET6) {
struct net_if *iface;
iface = net_if_ipv6_select_src_iface(
&net_sin6(&peer)->sin6_addr);
ud.peer = iface;
params.family = AF_INET6;
net_ipaddr_copy(&params.peer6addr,
&net_sin6(&peer)->sin6_addr);
mtu = NET_ETH_MTU - sizeof(struct net_ipv6_hdr);
} else if (IS_ENABLED(CONFIG_NET_IPV4) && peer.sa_family == AF_INET) {
struct net_if *iface;
iface = net_if_ipv4_select_src_iface(
&net_sin(&peer)->sin_addr);
ud.peer = iface;
params.family = AF_INET;
net_ipaddr_copy(&params.peer4addr,
&net_sin(&peer)->sin_addr);
mtu = NET_ETH_MTU - sizeof(struct net_ipv4_hdr);
} else {
LOG_ERR("Invalid address family %d", peer.sa_family);
return -EINVAL;
}
if (ud.peer == NULL) {
LOG_ERR("Peer address %s unreachable",
CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR);
return -ENETUNREACH;
}
net_if_foreach(iface_cb, &ud);
ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PEER_ADDRESS,
ud.tunnel, &params, sizeof(params));
if (ret < 0 && ret != -ENOTSUP) {
LOG_ERR("Cannot set peer address %s to "
"interface %d (%d)",
CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR,
net_if_get_by_iface(ud.tunnel),
ret);
}
params.mtu = mtu;
ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_MTU,
ud.tunnel, &params, sizeof(params));
if (ret < 0 && ret != -ENOTSUP) {
LOG_ERR("Cannot set interface %d MTU to %d (%d)",
net_if_get_by_iface(ud.tunnel), params.mtu, ret);
}
ret = setup_iface(ud.tunnel,
CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR);
if (ret < 0) {
LOG_ERR("Cannot set IP address %s to tunnel interface",
CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR);
return -EINVAL;
}
return 0;
}