mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
155 lines
6.4 KiB
Markdown
155 lines
6.4 KiB
Markdown
|
# 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;
|
||
|
}
|
||
|
```
|