-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
examples: Add common linux component tapif_io
That can be used with linux target on lwip to pass packets from lwip to linux host networking stack, e.g. routing the trafic to internet.
- Loading branch information
1 parent
332e490
commit 854e16f
Showing
12 changed files
with
593 additions
and
0 deletions.
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
examples/common_components/protocol_examples_common/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
examples/common_components/protocol_examples_tapif_io/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
idf_build_get_property(target IDF_TARGET) | ||
|
||
if(${target} STREQUAL "linux") | ||
idf_component_register(INCLUDE_DIRS include | ||
SRCS linux/tapio.c linux_connect.c lwip/tapif.c | ||
PRIV_REQUIRES esp_netif lwip) | ||
else() | ||
message(FATAL_ERROR "This component is currently only supported for linux target") | ||
endif() |
44 changes: 44 additions & 0 deletions
44
examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
menu "Example Connection Configuration" | ||
|
||
config EXAMPLE_CONNECT_LWIP_TAPIF | ||
bool "connect using lwip to linux tap interface" | ||
depends on IDF_TARGET_LINUX && ESP_NETIF_TCPIP_LWIP | ||
default n | ||
|
||
if EXAMPLE_CONNECT_LWIP_TAPIF | ||
config EXAMPLE_CONNECT_TAPIF_IP_ADDR | ||
string "Static IP address" | ||
default "192.168.5.100" | ||
help | ||
Set static IP address. | ||
|
||
config EXAMPLE_CONNECT_TAPIF_NETMASK | ||
string "Static netmask address" | ||
default "255.255.255.0" | ||
help | ||
Set static netmask address. | ||
|
||
config EXAMPLE_CONNECT_TAPIF_GW | ||
string "Static gateway address" | ||
default "192.168.5.1" | ||
help | ||
Set static gateway address. | ||
|
||
config EXAMPLE_CONNECT_TAPIF_OUT_LOSS | ||
int "Percentage of packets to be dropped on transmission" | ||
default 0 | ||
range 0 100 | ||
help | ||
Set non-zero number simulate packet loss when sending data. | ||
Number represents probability between 0 and 100% | ||
|
||
config EXAMPLE_CONNECT_TAPIF_IN_LOSS | ||
int "Percentage of packets to be dropped on reception" | ||
default 0 | ||
range 0 100 | ||
help | ||
Set non-zero number simulate packet loss when receiving data. | ||
Number represents probability between 0 and 100% | ||
endif | ||
|
||
endmenu |
154 changes: 154 additions & 0 deletions
154
examples/common_components/protocol_examples_tapif_io/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# tapif-io Component | ||
|
||
This component implements a tap networking interface that provides connectivity to host network using `tuntap` interface in Linux. | ||
It could be used to route lwip traffic to host side network, typically when working with the **Linux target**. | ||
|
||
## How to use this component | ||
|
||
### Usage of the API | ||
|
||
1) Add the path to this component to the `EXTRA_COMPONENT_DIRS` in your project makefile | ||
```cmake | ||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/common_components/tapif_io") | ||
``` | ||
2) Include lwip and linux side of the configuration | ||
```cpp | ||
#include "esp_netif.h" // esp-netif | ||
#include "tapio.h" // esp-netif's driver side | ||
#include "lwip/tapif.h" // esp-netif's network stack side | ||
``` | ||
3) Configure the esp-netif | ||
a) setup the linux tap I/O config | ||
```cpp | ||
esp_netif_driver_ifconfig_t driver_cfg = { | ||
.handle = tapio_create(), | ||
.transmit = tapio_output, | ||
}; | ||
``` | ||
b) configure the lwip netif for the tap interface | ||
```cpp | ||
struct esp_netif_netstack_config stack_cfg = { | ||
.lwip = { | ||
.init_fn = lwip_tapif_init, | ||
.input_fn = lwip_tapif_input, | ||
} | ||
}; | ||
``` | ||
|
||
c) configure the esp-netif basic parameters | ||
```cpp | ||
esp_netif_inherent_config_t base_cfg = { | ||
.if_key = "TAP", // unique name of the interface | ||
.flags = ESP_NETIF_FLAG_AUTOUP, // no dhcp client, starts when it's set up | ||
.ip_info = &ip_info, // add static IP info | ||
.route_prio = 100 // priority for setting default gateway | ||
}; | ||
``` | ||
4) Initialize and attach the esp_netif to the I/O handle | ||
```cpp | ||
esp_netif_t *tap_netif = esp_netif_new(&cfg); | ||
esp_netif_attach(tap_netif, driver_cfg.handle); | ||
``` | ||
|
||
### Host side networking | ||
|
||
1) Create a new tun/tap interface type named `tap0` | ||
a) You can run the script `./make_tap_netif` | ||
b) Update the IP address of the interface to correspond to the configured static IP in previous step | ||
|
||
2) Start the application and send/receive the packets via `tap0` interface | ||
* it is possible to create server or client test application listening or connecting to this interface. | ||
* it is also possible to route these packets to external network (using routing rules or simply by ip forwarding if using the same subnet) | ||
|
||
#### Common networking/routing examples | ||
|
||
##### Isolated internal connection | ||
|
||
Is useful to experiment with one interface with no intention to connect to internet or external facilities. | ||
Typically, when we want to create a server listening on the `tap0` interface and run a client in lwip, e.g. the default `tcp_client` socket example in IDF. | ||
* Create the tap interface using `./make_tap_netif` and set the IP address **not to overlap** with any other IPv4 network range (e.g. `ip addr add 192.168.5.1/24 dev tap0`) | ||
* Configure the `tapif_io` component to use static address from that range (e.g. `192.168.5.x`) | ||
* Configure the `tcp_client` example to connect to the tap interface IP address (e.g. `192.168.5.1`) | ||
* Execute a tcp server listening on the tap interface and the configured port (e.g. `nc -l 3333`) | ||
* Build and run the `tcp_client` example to send and receive data between the server created in the previous step. | ||
|
||
##### Connecting to the external network using IP forwarding | ||
|
||
This allows using full-featured network facilities of your host network, but a care must be taken to the selected IP addresses to avoid potential conflicts. | ||
* Set the IP address of the `tap0` interface from the range used by your host system's default gateway (e.g. `ip addr add 192.168.0.123/24 dev tap0`, assuming the default netif is `eth0` with IP range of `192.168.0.x` and this address doesn't overlap with any other IP address in this network) | ||
* Configure the `tapif_io` with another address from the same range, e.g. | ||
```text | ||
CONFIG_EXAMPLE_CONNECT_TAPIF_IP_ADDR="192.168.0.100" | ||
CONFIG_EXAMPLE_CONNECT_TAPIF_NETMASK="255.255.255.0" | ||
CONFIG_EXAMPLE_CONNECT_TAPIF_GW="192.168.0.1" | ||
``` | ||
assuming that the default gateway of your host network is configured to `192.168.0.1` | ||
* Build and run the lwip example to interact with the host network, e.g, to send an HTTP request to a publicly available http server (if the server is reachable from your host network) | ||
|
||
(Note, that the IP forwarding must be enabled in the host system: | ||
```bash | ||
echo 1 > /proc/sys/net/ipv4/ip_forward | ||
``` | ||
) | ||
|
||
##### Routing the internal interface to the host network with IP tables | ||
|
||
Uses an isolated interface with routing and NAT-ing between interfaces | ||
* Configure the `tap0` interface address **not to overlap** with any other IPv4 network range. | ||
* Setup `MASQUERADE` target to route network traffic between `tap0` and your default network interface (`eth0` in the below example). | ||
```bash | ||
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE | ||
sudo iptables -A FORWARD -i eth0 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT | ||
sudo iptables -A FORWARD -i tap0 -o eth0 -j ACCEPT | ||
``` | ||
|
||
##### Using DHCP | ||
|
||
It's also possible to configure the lwip interface to use DHCP client (common setup for most default network interfaces, such as Ethernet or WiFi station) | ||
and set up a DHCP server on the host machine to assign the IP address dynamically. | ||
|
||
1) **Configure and set the `esp-netif` up** | ||
|
||
* Same as in [API usage](#Usage-of-the-API), but update the base esp-netif config `3c)` to enable DHCP client | ||
```cpp | ||
esp_netif_inherent_config_t base_cfg = { | ||
.if_key = "TAP", | ||
.flags = (esp_netif_flags_t)(ESP_NETIF_DHCP_CLIENT | ESP_NETIF_FLAG_EVENT_IP_MODIFIED | ESP_NETIF_FLAG_AUTOUP), | ||
.route_prio = 100 | ||
}; | ||
``` | ||
* After starting the netif, tell the lwIP that we're connected | ||
```cpp | ||
esp_netif_action_connected(tap_netif, 0, 0, 0); | ||
``` | ||
* Wait for the IP address to be assigned. | ||
This could be implemented as a wait loop below, as the esp-event currently doesn't support IP events on Linux target. | ||
```cpp | ||
esp_netif_ip_info_t ip_info = {}; | ||
while (ip_info.ip.addr == 0) { | ||
ESP_LOGI("tap-init", "No IP assigned, waiting..."); | ||
usleep(1000000); | ||
esp_netif_get_ip_info(tap_netif, &ip_info); | ||
} | ||
ESP_LOGI("tap-init", "Assigned IP address:"IPSTR ",", IP2STR(&ip_info.ip)); | ||
``` | ||
2) **Configure forwarding/routing** if needed based on the previous sections. | ||
3) **Configure the DHCP server on the host machine** | ||
Example for `isc-dhcp-server` | ||
```bash | ||
INTERFACES="tap0"; | ||
authoritative; | ||
subnet 192.168.5.0 netmask 255.255.255.0 { | ||
range 192.168.5.2 192.168.5.200; | ||
option routers 192.168.5.1; | ||
option domain-name-servers 8.8.8.8; | ||
} | ||
``` |
32 changes: 32 additions & 0 deletions
32
examples/common_components/protocol_examples_tapif_io/include/protocol_examples_common.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Unlicense OR CC0-1.0 | ||
*/ | ||
/* Common functions for protocol examples, to establish tap interface connection | ||
* For linux target | ||
This example code is in the Public Domain (or CC0 licensed, at your option.) | ||
Unless required by applicable law or agreed to in writing, this | ||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | ||
CONDITIONS OF ANY KIND, either express or implied. | ||
*/ | ||
#pragma once | ||
#include "esp_err.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Configure and connect, wait for IP | ||
* | ||
* @return ESP_OK on successful connection | ||
*/ | ||
esp_err_t example_connect(void); | ||
|
||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
27 changes: 27 additions & 0 deletions
27
examples/common_components/protocol_examples_tapif_io/include/tapio.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
#pragma once | ||
#include "esp_err.h" | ||
#include "esp_netif.h" | ||
|
||
/** | ||
* @brief Creates tapio layer as a driver interface to esp-netif | ||
* | ||
* @warning Implemented as singleton, can use only one tapio in the system! | ||
* | ||
* @return pointer to the tapio driver handle | ||
*/ | ||
void *tapio_create(void); | ||
|
||
/** | ||
* @brief esp-netif driver I/O output path | ||
* | ||
* @param h Driver's handle | ||
* @param buffer Data to output | ||
* @param len Data size | ||
* @return ESP_OK on success | ||
*/ | ||
esp_err_t tapio_output(void *h, void *buffer, size_t len); |
Oops, something went wrong.