espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.44k stars 7.25k forks source link

Example of making a bridge between Ethernet and PPPos (IDFGH-10874) #12076

Closed MJavadJafari closed 11 months ago

MJavadJafari commented 1 year ago

Is your feature request related to a problem?

I am trying to connect some Ethernet device to my esp32 so thay can use internet connection provided by the modem. The modem I am trying to use is sim800c for now which supports PPPos. Is it possible to include this functionality in network/bridge examples?

Describe the solution you'd like.

I need some information on how to do this. If it can be included in bridge section with examples it would be nice.

Describe alternatives you've considered.

No response

Additional context.

No response

david-cermak commented 1 year ago

Hi @MJavadJafari

Bridging PPPoS interface to anything is tricky, since bridging works on L2 and PPP doesn't have L2. Would L3 forwarding (with NAT) be an option? If so, you can check this example:

https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples/ap_to_pppos

and just, replace wifi initialization with Ethernet (you might also want to setup DHCP server on Ethernet)

As for the lwip bridge example: for adding PPPoS interface, you would have to somehow "pretend" that this netif supports ETHARP and implement related input and output functions, supplying the Ethernet header. It's also possible to implement a 1:1 L2 forwarder, where you can use lwip's PPP implementation and "inject" IP layer input/output functions passing the packets to Ethernet interface. Similar has been done in https://github.com/espressif/esp-protocols/blob/master/components/esp_modem/port/linux/esp_netif_linux/tun_io.c

But the NAT/L3 forwarding is by far the easiest option, plus the performance overhead in address translation is minimal, compared to the usual speeds of PPPoS interface.

david-cermak commented 11 months ago

Closing as won't do.

Rationale

As mentioned above, bridging an L3 interface on L2 level doesn't make much sense, since we would have to somehow mimic the L2 functionality for the PPPoS. It is doable, but might be complex and error prone with very few benefits. Throughput bottleneck would always be the serial speed, so we won't gain anything here.

Alternative

Please use NAT/L3 forwarding. The packets would have go come and go via lwip for routing, but the performance impact would be minimal and we'd benefit from the flexibility of setting IP ranges on the Ethernet side.

gidlstar commented 5 months ago

Hi @MJavadJafari

Bridging PPPoS interface to anything is tricky, since bridging works on L2 and PPP doesn't have L2. Would L3 forwarding (with NAT) be an option? If so, you can check this example:

https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples/ap_to_pppos

and just, replace wifi initialization with Ethernet (you might also want to setup DHCP server on Ethernet)

As for the lwip bridge example: for adding PPPoS interface, you would have to somehow "pretend" that this netif supports ETHARP and implement related input and output functions, supplying the Ethernet header. It's also possible to implement a 1:1 L2 forwarder, where you can use lwip's PPP implementation and "inject" IP layer input/output functions passing the packets to Ethernet interface. Similar has been done in https://github.com/espressif/esp-protocols/blob/master/components/esp_modem/port/linux/esp_netif_linux/tun_io.c

But the NAT/L3 forwarding is by far the easiest option, plus the performance overhead in address translation is minimal, compared to the usual speeds of PPPoS interface.

@david-cermak

Hi, I have a follow up question to your suggestion, not sure this is the right way to ask but here it is: I would like to do exactly what you suggested and I got everything working (GSM PPPoS with internet connection, DHCP Server on SPI W5500 Ethernet Module with the correct DNS information), only thing not working seems to be the NAPT command, the client connected to the ethernet port won't get internet connection. I am able to ping the W5500 interface but no internet (tried with and without dns). Do you have any adivice? (Off course I can send you the code) Thank you!

david-cermak commented 5 months ago

Hi @gidlstar

There's an official example: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples/ap_to_pppos

so you just replace the WiFi AP interface with your Ethernet interface. You just need to make sure, that you enable NAPT after the interface went up. And then configuring DNS (or setting the DHCP option) after you got the DNS info from your PPP connection.

gidlstar commented 5 months ago

Hi @david-cermak,

thank you very very much for your reply, I was really hoping you would.

I did use the official ap_to_pppos example and I also wait for the interface to go up, here the part of the code where I try to swap out the interface. The receiving client (notebook) get's an IP address from the esp and the correct dns server ip. The client can ping the esp IP address but internet won't work. the PPP connection is successfully up and the internet on the esp works correctly over via the ppp interface.

Could you please have a look at my code? (I can also send you the full code if you want) Thank you!!

`

uint8_t eth_port_cnt = 0;
esp_eth_handle_t *eth_handles;
ESP_ERROR_CHECK(ethernet_init_all(&eth_handles, &eth_port_cnt));

const esp_netif_ip_info_t my_ap_ip = {
    .ip = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) },
    .gw = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) },
    .netmask = { .addr = ESP_IP4TOADDR( 255, 255, 255, 0) },
};

const esp_netif_inherent_config_t eth_behav_cfg = {
        .get_ip_event = IP_EVENT_ETH_GOT_IP,
        .lost_ip_event = 0,
        .flags = ESP_NETIF_DHCP_SERVER | ESP_NETIF_FLAG_AUTOUP,
        .ip_info = (esp_netif_ip_info_t*)& my_ap_ip,
        .if_key = "ETHDHCPS",
        .if_desc = "eth",
        .route_prio = 50
};

esp_netif_config_t my_eth_cfg = { .base = &eth_behav_cfg, .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH };
esp_netif_t *eth_netif = esp_netif_new(& my_eth_cfg);
assert(eth_netif);

esp_netif_dns_info_t dns;
ESP_ERROR_CHECK(esp_netif_get_dns_info(ppp_netif, ESP_NETIF_DNS_MAIN, &dns));

set_dhcps_dns(eth_netif, dns.ip.u_addr.ip4.addr);

ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0])));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));

// Start Ethernet driver state machine
for (int i = 0; i < eth_port_cnt; i++) {
    ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
}

if(esp_netif_is_netif_up(eth_netif) == ESP_OK){       //only chekcing if interface is up for troubleshooting purposes
     ESP_LOGW(TAG, "eth_netif is up");
}else{
    ESP_LOGW(TAG, "eth_netif is down");
}

if(esp_netif_is_netif_up(ppp_netif) == ESP_OK){
     ESP_LOGW(TAG, "ppp_netif is up");
}else{
    ESP_LOGW(TAG, "ppp_netif is down");
}

ESP_LOGW(TAG, "bevore napt");
vTaskDelay (5000/portTICK_PERIOD_MS);      // only safty waiting to make sure interface is up
ESP_LOGW(TAG, "afeter break");

ip_napt_enable(my_ap_ip.ip.addr, 1);

`

david-cermak commented 5 months ago

The code looks okay to me, I don't see anything wrong at the first glance, I would say that it should work. Which IDF version are you using? I think there were some issues with Ethernet and NAT on older versions. It should be safe with v5.1.

gidlstar commented 5 months ago

Thanks for looking at my code and your feedback. I thought as well this should work but unfortunatly it's not working. I am using "ESP-IDF v5.2-dirty" and "ESP_MODEM v1.1.0". Is there an alternative way to get such a functionality with my current hardware?

david-cermak commented 5 months ago

You can also try this example -- probably very similar to your usecase, so maybe you can check if you get it running with the iot-bridge component: https://github.com/espressif/esp-iot-bridge/tree/master/examples/4g_nic

gidlstar commented 5 months ago

@david-cermak ok thank you I'll give that a try

dvosully commented 1 month ago

@gidlstar I had the same issue trying to run the same configuration. I could ping the gateway over ethernet, and access a webserver running on the ESP32 over ethernet, but could not get wider internet access despite having set DHCP, DNS, NAPT etc. The problem was the root priority causing the wrong netif to be set as the default interface - see doc below. https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/network/esp_netif.html#_CPPv4N25esp_netif_inherent_config10route_prioE

The default initialisation of the PPP interface has a route priority of 20 https://github.com/espressif/esp-idf/blob/dbce23f8a449eb436b0b574726fe6ce9a6df67cc/components/esp_netif/include/esp_netif_defaults.h#L108 while the Ethernet interface has a default route priority of 50 https://github.com/espressif/esp-idf/blob/dbce23f8a449eb436b0b574726fe6ce9a6df67cc/components/esp_netif/include/esp_netif_defaults.h#L94

My chosen solution was to call esp_netif_set_default_netif() (https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/network/esp_netif.html#_CPPv427esp_netif_set_default_netifP11esp_netif_t) on the PPP interface. Alternatively I could have set the priority of either the PPP interface to be above the Ethernet interface, or the Ethernet below the PPP. After this everything started working perfectly.