arduino-esp32
arduino-esp32 copied to clipboard
Adding IPv6 support to arduino-esp32
This patch partially depends on: https://github.com/espressif/esp32-arduino-lib-builder/pull/67 Without this patch we will get only Link local IPv6 (still useful for MDNS and etc). With patch we will get also global IPv6 address by SLAAC. By default IPv6 disabled, until it is properly tested.
Tested on BasicHttpClient by adding: wifiMulti.IPv6(true); before: wifiMulti.addAP() call
Enabling Core Debug Level: verbose If IP6 obtained, in logs will be visible: [ 8028][V][WiFiGeneric.cpp:380] _arduino_event_cb(): IF[0] Got IPv6: IP Index: 0, Zone: 2, fe80:0000:0000:0000:xxxx:xxxx:xxxx:xxxx [ 8028][D][WiFiGeneric.cpp:852] _eventCallback(): Arduino Event: 8 - STA_GOT_IP6 [ 11028][V][WiFiGeneric.cpp:380] _arduino_event_cb(): IF[0] Got IPv6: IP Index: 1, Zone: 0, 2a0d:yyyy:0000:4000:yyyy:yyyy:yyyy:yyyy [ 11028][D][WiFiGeneric.cpp:852] _eventCallback(): Arduino Event: 8 - STA_GOT_IP6
This is linked to: https://github.com/espressif/arduino-esp32/issues/6242
Signed-off-by: Denys Fedoryshchenko [email protected]
Unit Test Results
0 files 0 suites 0s :stopwatch: 0 tests 0 :heavy_check_mark: 0 :zzz: 0 :x:
Results for commit 01dd9c45.
:recycle: This comment has been updated with latest results.
Additional note, as we use this optional flag, it is addressing many users fears, that they dont want to get IPv6 address on their device. So by default it wont take it, unless they do IPv6(true).
Any feedback? :)
Hi @nuclearcat sorry for the late reply. I have merged the PR in lib-builder and IDF support will come in 2.0.4. We will look into this after we release that, because this adds new functionality and modifies good portion of existing code. At least with 2.0.4, you (and we) will be able to test everything properly.
Thanks! Will keep an eye, maybe meanwhile i will bring some good use-cases for IPv6 for new code
I am going to use ESP32-S3 to run an IPV6 web server, and I can access index.html in ESP32-S3 FLASH on any networked device through IPV6 address. Can version 2.0.4 implement this function?
Hi @Meekdai , with patches in this PR - yes. I am not sure vanilla 2.0.4 can run ipv6 web server properly.
Hi @nuclearcat I don't know how to use this PR, I just installed the package containing esp32 2.0.4 on my windows PC.
I am afraid it will be a bit difficult then to test ipv6 properly, without manual building, until this PR is merged.
This PR is really important... how soon can it be merged? (I'm going to see if I can reference the branch in PlatformIO).
Trying to get IPv6 working, and have the basic network (i.e. enable and get address) working, except then HTTPClient fails on something like http.begin("http://v6.ipv6-test.com/api/myip.php"); because the internals assume IPv4 addresses.
If you need any help testing, let me know.
I might make docker image with this PR and arduino-cli to build and flash some test arduino programs, if that will be useful. But thats a bit linux stuff, it will produce bin files at best
@sgryphon we plan to merge this for next major release 2.1.0.
Is "libraries/WiFi/src/WiFiUdp.cpp" also need to be update ? When people want to use IPv6 for UDP protocol.
Throwing a spanner into the works, I think this should be re-worked before merging it: https://github.com/espressif/arduino-esp32/issues/7114
I know a separate IPv6Address.h class has already been added to the core, but I think it is a bad design, and complicates things. e.g. It has meant adding duplicate methods everywhere, so there are both remoteIP() and remoteIP6() addresses, and it would be complicated for client code to have to check both and determine what to do.
The approach taken in ESP8266 leads to a lot simpler code: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/IPAddress.h
This makes IPAddress a wrapper around the Espressif ip_addr_t union, so that it supports both IPv4 and IPv6.
This means you only need one remoteIP() method, that simply returns what is appropriate, and simplifies the whole implementation down to supporting the new feature, rather than modifying all the APIs.
The format of an IP address should be an implementation detail, hidden from the user.
Suggestion (and I'm happy to help with the coding changes);
- Implement IPAddress similar to ESP8266, so it supports both types.
- Remove all the unnecessary overloads with IPv6Address
- Retain the changes to implementation where relevant that actually use IPv6 addresses.
- Mark the existing IPv6Address as deprecated (for the future, as everything it does will be in the main IPAddress), as it is already used in some places (e.g. UDP).
I implemented it as new classes/functions for better backward compatibility, to avoid breaking existing code. But looks like esp8266-arduino project running quite a while without issue. I will research this a bit more, and if project maintainers doesn't mind can send another PR with mentioned approach.
new classes/functions for better backward compatibility
Provided you are only adding new features, then it should not break any existing code. e.g. if the old IPAddress had constructors for 4 bytes, that will continue to work, even if you add a second constructor with 16 bytes. The new class would be fully backwards compatible (i.e. can do everything the old class can do).
There could be some corner cases where client code is relying on the implementation, rather than the interface, e.g. if it relies on the storage size being 4 bytes, which could be important for a resource constrained device. The ESP8266 approach had a nice solution in that if compiled with IPv6 turned off, then it falls back to the smaller memory footprint.
Maybe when considering forward compatibility, i.e.the ability of old code to handle the new features, such as if old code gets handed a new address. Certainly not allowing it at all (by adding a new class) might help in some corner cases, but also mean they are locked out of the new features, with is probably a larger negative.
In general I don't think people want to care about the low level details of which IP address they are using.
If you recompile with components that support IPv6, and then deploy into an IPv6 only network, the same code will just continue to work (except with slightly larger memory requirements).
If it is useful, I have put a proposal pull release in to the ArduinoCore-API to add IPv6 support to the standard API: https://github.com/arduino/ArduinoCore-API/pull/169
The code is slightly different from ESP8266. The public interface changes are minimal:
- add a type() getter and corresponding IPType enum, with values IPv4 and IPv6
- add three new constructors: one for 16 octets, empty with type specifier, and byte pointer with type specifier
- add constant for IP6ADDR_ANY (similar function as IPADDR_NONE)
Instead of type(), the ESP8266 implementation has isV4() and isV6(); in ESP8266 there is also a constructor from ip_addr_t, which we would want in the ESP32 implementation (but is not relevant for ArduinoCore-API).
There are also a bunch of other constructs in ESP8266, which I have kept out of the minimal implementation, e.g. a raw6() method which would be the same as type() == IPv6 ? raw_address() : nullptr, or isLocal() which returns if the address is a link local address (in my opinion badly named as the local address means something different to me than a link local address). These might be useful, but are not directly part of IPv6 support.
IPv6 support is now in ArduinoCore-API. I've copied the changes into a branch in my fork, which could be integrated into this change.
https://github.com/sgryphon/arduino-esp32/tree/feature/ipaddress-v6-support
It means you can avoid things like WiFiClient::connect(ip_addr_t ip, uint16_t port, int32_t timeout), because int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) would have ip.type() support both IPv4 and IPv6.
(With IPv4 work exactly the same as it did before, just new support for IPv6 directly in IPAddress rather than using ip_addr_t).
Thanks! Since it became a standard approach, i think will work on it this weekend to update my changes
The build / github actions for this project are a bit more complicated than for ArduinoCore-API, so I'm not sure how to build/compile locally (or run tests). Is there some instructions?
I started to convert my patch to new IPAddress contributed by @sgryphon: https://github.com/nuclearcat/arduino-esp32/tree/ipv6-support-v2 Work still in progress, please comment if you have suggestions.
I'll see when I have a chance to look in more detail. In the meanwhile:
(1) For web browsers the approach for dual stack is the "happy eyeballs" algorithm, which queries DNS for the first IPv6 address and the first IPv4, and then attempts connections to both simultaneously, aborting the loser once one responds. Part of this was due to early days misconfiguration of IPv6 given addresses that didn't work -- that is no longer really a consideration, but performance wise often both are used.
This may not be applicable for Arduino devices as limited capacity, not a lot of multithreading, can't abort, etc. Plus constraints we may just have to configure as known IPv6 or IPv4.
(2) For outputting "localIP()", you may want something that can be used as a server address and/or matched to logs.
If you look at the code I have in another project: https://github.com/sgryphon/AdvancedGsmClient/blob/main/src/SIM7020/SIM7020GsmModem.cpp#L470
This sorts addresses based on largest scope (i.e. we want to show a global address), and then by the RFC 6724 precedence. (The sorting is done on strings, as IPAddress in ESP32 doesn't have IPv6 yet).
Closed in favor of https://github.com/espressif/arduino-esp32/pull/7520