Repository navigation
IPv6 Support in micropython for ESP32 (or anything for that matter) #3683
Description
Activity
I found some documentation which stated that IPv6 support was "port" dependent, but I have yet to find any port of micropython with IPv6 support enabled.
The unix port supports IPv6: you can create sockets with family AF_INET6 (=10) and then connect them to a remote IPv6 address. This is how it would work on any port that supports IPv6.
it looks like there are no IPv6 capabilities in the network or WLAN class implementations which means that the interface can't get an IPv6 address, etc.
Most of the network module functions should be IP agnostic and allow you to connect to an IPv6 network. The ifconfig() method will need some enhancement to support IPv6.
The first step to get IPv6 working on the ESP32 would be to work out how to control the ESP IDF to get on a IPv6 network, then it can be seen how to incorporate this into the network module.
Most of the network module functions should be IP agnostic and allow you to connect to an IPv6 network. The ifconfig() method will need some enhancement to support IPv6.
The first step to get IPv6 working on the ESP32 would be to work out how to control the ESP IDF to get on a IPv6 network, then it can be seen how to incorporate this into the network module.
My understanding from looking at the ESP-IDF (admittedly, by far no expert) is that all of the existing LWIP libs include all the necessary IPv6 support and we just need to make the appropriate calls.
Unfortunately, from looking at the source for the ifconfig() PERL call in the ports/esp32 source code, I wasn't able to figure out how it crawled down into the LWIP code in the ESP-IDF to do its thing.
Further, I wasn't able to figure out enough about the generic WLAN startup code to figure out how to add IPv6 initialization so that it could "just work" with SLAAC (which is built into the LWIP code if we just turn on IPv6 AIUI).
Does the UNIX port have the ability to configure interfaces or does it depend on that being done outside of the MicroPython environment since it's running as an application inside an operating system instead of running as an operating system?
Does the UNIX port have the ability to configure interfaces or does it depend on that being done outside of the MicroPython environment
It doesn't have the
networkmodule so relies on network interfaces to be set up via the host OS.It doesn't have the network module so relies on network interfaces to be set up via the host OS.
Which then renders it a less than useful port for the purpose of identifying or finding example code for porting IPv6 to any form of MCU such as the ESP32.
Not trying to be obnoxious, but hoping to find some code examples or something I can use to help contribute IPv6 work towards the ESP32. I think that the ESP32 version of the sockets/usockets module(s) has IPv6 capabilities as well, but that doesn't do any good if I can't get an IPv6 address on the underlying interface in the network module.
Are there any Micropython ports where MP controls the hardware that have the ability to put IPv6 on an interface through the network module?
Are there any Micropython ports where MP controls the hardware that have the ability to put IPv6 on an interface through the network module?
No, not that I know of.
It's great that you want to help get IPv6 support working. The first place to start is understanding what calls to make to the ESP IDF to get the device connected on an IPv6 network and have it assigned an address. Wit that knowledge we can see how to incorporate it into the network module. Then move on to making socket work.
OK... I can definitely look into that. From what I understand, it should be pretty straight forward set of calls to LWIP, at least for SLAAC. I'm not sure if DHCPv6 is implemented in LWIP yet. I've seen conflicting reports, mostly negative.
The following page appears to have a workable code example for FreeRTOS: https://github.com/espressif/esp-idf/blob/master/examples/protocols/udp_multicast/main/udp_multicast_example_main.c
I think the relevant code snippets are:
#include "esp_system.h" #include "esp_wifi.h" #include "lwip/err.h" #include "lwip/sockets.h" #include "lwip/sys.h" #include <lwip/netdb.h> // Note the following examples are defined using "make menuconfig" in the ESP-IDF. // Alternatively, just specify applicable values for your environment in the code directly #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD #define UDP_PORT CONFIG_EXAMPLE_PORT #define MULTICAST_LOOPBACK CONFIG_EXAMPLE_LOOPBACK #define MULTICAST_TTL CONFIG_EXAMPLE_MULTICAST_TTL #define MULTICAST_IPV4_ADDR CONFIG_EXAMPLE_MULTICAST_IPV4_ADDR #define MULTICAST_IPV6_ADDR CONFIG_EXAMPLE_MULTICAST_IPV6_ADDR #define LISTEN_DEFAULT_IF CONFIG_EXAMPLE_LISTEN_DEFAULT_IF // Extracted from the event handler, normally triggered by different events denoting steps in the // process of bringing up the interface: esp_wifi_connect(); // Upon station start tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); // Upon AP Association (STA_CONNECTED) // Extracted from initialize_wifi function tcpip_adapter_init(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_WIFI_SSID, .password = EXAMPLE_WIFI_PASS, }, }; ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid); ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); ESP_ERROR_CHECK( esp_wifi_start() ); // The following statements come from a function called create_multicast_ipv6_socket() struct sockaddr_in6 saddr = { 0 }; struct in6_addr if_inaddr = { 0 }; struct ip6_addr if_ipaddr = { 0 }; struct ip6_mreq v6imreq = { 0 }; int sock = -1; int err = 0; sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IPV6); // Standard error check applies if socket() fails. saddr.sin6_family = AF_INET6; saddr.sin6_port = htons(UDP_PORT); bzero(&saddr.sin6_addr.un, sizeof(saddr.sin6_addr.un)); err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)); // Standard error check applies if bind() fails bzero(&if_inaddr.un, sizeof(if_inaddr.un)); err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_inaddr, sizeof(struct in6_addr)); uint8_t ttl = MULTICAST_TTL; setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(uint8_t)); // Standard error check(s) apply to above setsockopt() calls v6imreq.imr_interface.s_addr = IPADDR_ANY; err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &v6imreq, sizeof(struct ip6_mreq)); // Standard error checks apply to above setsockopt() call int only = 1; /* IPV6-only socket */ err = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &only, sizeof(int)); // Standard error checks apply to above setsockopt() call return sock; // The next function is called "mcast_example_task and takes a void pointer (*pvParameters) // It calls the above socket creation function. //Then it uses select() to wait for traffic.Upon receiving traffic, it hits this: // First checks for an error returned from select() else if (s > 0) { if (FD_ISSET(sock, &rfds)) { // Incoming datagram received char recvbuf[48]; char raddr_name[32] = { 0 }; struct sockaddr_in6 raddr; // Large enough for both IPv4 or IPv6 socklen_t socklen = sizeof(raddr); int len = recvfrom(sock, recvbuf, sizeof(recvbuf)-1, 0, (struct sockaddr *)&raddr, &socklen); //Usual error check on recvfrom() if (raddr.sin6_family == PF_INET6) { inet6_ntoa_r(raddr.sin6_addr, raddr_name, sizeof(raddr_name)-1); } ESP_LOGI(TAG, "received %d bytes from %s:", len, raddr_name); recvbuf[len] = 0; // Null-terminate whatever we received and treat like a string... ESP_LOGI(TAG, "%s", recvbuf); //If timeout without receiving anything, something is sent using the following code: static int send_count; const char sendfmt[] = "Multicast #%d sent by ESP32\n"; char sendbuf[48]; char addrbuf[32] = { 0 }; int len = snprintf(sendbuf, sizeof(sendbuf), sendfmt, send_count++); // Standard check for buffer overflow struct addrinfo hints = { .ai_flags = AI_PASSIVE, .ai_socktype = SOCK_DGRAM, }; struct addrinfo *res; hints.ai_family = AF_INET6; hints.ai_protocol = 0; err = getaddrinfo(CONFIG_EXAMPLE_MULTICAST_IPV6_ADDR, NULL, &hints, &res); // Standard check for errors from getaddrinfo() struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *)res->ai_addr; s6addr->sin6_port = htons(UDP_PORT); inet6_ntoa_r(s6addr->sin6_addr, addrbuf, sizeof(addrbuf)-1); ESP_LOGI(TAG, "Sending to IPV6 multicast address %s...", addrbuf); err = sendto(sock, sendbuf, len, 0, res->ai_addr, res->ai_addrlen); // Standard error check on sendto()The app_main() function just calls the functions described above to initialize wifi and set up the multicast task.
Hopefully that's helpful. I apologize for my limited understanding here. I'm early in the process of learning some of this stuff. My previous experience is mostly on the application side, using these tools. This is my first real venture into contributing to them and I feel like I've fallen in the deep end.
Hi,
since some time has passed, I wanted to ask if there is any update on this. I would be very interested in having IPv6 support on Micropython because I see it as crucial.Reacted by Volodymyr Shymanskyy, Jimmy Hedman, rmoriz, Wynton, Michael Gries, Sébastien RAMAGE, James Hannah, Sebastian, Steven A. Silva, Alexandre Cardim and 4 moreIs there any branch or fork working on IPv6?
Reacted by Sébastien RAMAGE, Antonis Gotsis, James Hannah, Lennart Pelz, Leonel, Alexandre Cardim, David Young and Wilfried Klaebejust submitted a very small PR aimed at supporting ipv6 in
uasyncio. would really appreciate input/feedback!Reacted by Alexandre CardimAny progress on this?
I just want to (not very helpfully) chime in that I'd like this too. IPv6 is the only way I can have random monitoring devices report back to my central reporting server reasonably
@fireduck64 check #11111
Any progress now?
A new API for IPv6 on bare-metal lwIP ports has been implemented in 1c6012b
The next thing to do would be to implement that API for esp32.
I'm interested too, especially together with mDNS. I want to have a microdot HTTP server reachable via a .local name via IPv6.
Reacted by T-X and Rob SeastromHas anyone started an implementation yet? I recently did some work with IPv6 on ESPHome and could probably help.
Looking forward to the day when I could host my blog on ESP32 with IPv6!
Reacted by gxxk-dev, tiantianpei and Max BroomfieldCan't comment on ESP32, but I have a RP2350 here (Pimironi Interstate 75W):
>>> wlan.ipconfig("addr6") [('FE80::2ACD:C1FF:FE15:9305', 48, 0, 0), ('2001:44B8:21AC:7053:2ACD:C1FF:FE15:9305', 48, 2680, 5380)]At the very least, SLAAC is working, but I am getting stuck with joining a multicast group because
socket.IPPROTO_IPV6isn't defined.
It looks like LWIP in the ESP-IDF being used for micropython has IPv6 support.
Is there an effort to take advantage of the yet? I found some documentation which stated that IPv6 support was "port" dependent, but I have yet to find any port of micropython with IPv6 support enabled.
It looks like the current build has IPv6 capabilities in the usocket module, but it looks like there are no IPv6 capabilities in the network or WLAN class implementations which means that the interface can't get an IPv6 address, etc.
I'm willing to put some effort into trying to do the needful, but the existing API seems to be so thoroughly incapable of understanding that there could possibly be any protocol other than IPv4 that I'm unsure how to go about providing a mergeable codebase that wouldn't break people's existing code.
Further, I'd like to know if there are any standard APIs for IPv6 interface configuration that I should be following as the existing interface configuration capabilities in the ESP32 port are quite thoroughly incapable of such.
Any pointers (or ideally a solution already developed) greatly appreciated.