-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32/network: Add support for SO_BINDTODEVICE. #12062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
esp32/network: Add support for SO_BINDTODEVICE. #12062
Conversation
b32ec4a
to
edefc22
Compare
Thanks for the patch, it looks pretty good to me. It looks CPython compatible. I'm guessing you can't use normal
This is the main point to consider, how/if this feature could be added to other ports if/when they need it. And also consider |
d15fe21
to
67fba03
Compare
I've force-pushed a new version of the patch which uses
It is, if the platform you're running on supports SO_BINDTODEVICE. It does on CPython on Linux:
Main difference is that in CPython it requires the parameter to be
Correct. I could perhaps have polled the IP every time I wanted to make a connection, but this seemed like a better solution since this actually binds to a device, not an IP, and I wasn't sure whether lwIP uses a strong or weak model, thus whether binding to an IP was sufficient to guarantee it would use that device or it would still depend on the routing table.
I haven't looked into the network stack on other ports as I don't currently use networking on any of them; but given (some) seem to use lwIP as well I assume it will be similar as for the ESP32; since we don't really use much ESP-IDF specific functionality here, the only IDF function we use is simply a wrapper for |
This implements support for SO_BINDTODEVICE, which allows telling a socket to use a specific interface instead of lwIP automatically selecting one. This allows devices that have multiple connections (for example cellular over PPP in addition to WLAN) to explicitly choose which data is send over which connection, which may have different reliability and or (mobile data) costs associated with using them. The used lwIP network stack already has support for this, so all that was needed was to expose this functionality in MicroPython. This commit exposes a new constant SO_BINDTODEVICE which can be set as an socket option. As a value it expects the name of the interface to bind to. These names can be retrieved using `.config('ifname')` implemented on each interface type (including adding in this commit a `.config()` method to PPP, which it didn't have before), which returns a string with the interface name: >>> import machine >>> import network >>> network.WLAN(network.AP_IF).config('ifname') 'lo0' >>> wlan = network.WLAN(network.AP_IF) >>> wlan.active(True) and wlan.config('ifname') 'ap1' >>> wlan = network.WLAN(network.STA_IF) >>> wlan.active(True) and wlan.config('ifname') 'st1' >>> ppp = network.PPP(machine.UART(0)) >>> ppp.active(True) and ppp.config('ifname') 'pp1' >>> ppp = network.PPP(machine.UART(0)) >>> ppp.active(True) and ppp.config('ifname') 'pp2' >>> ppp = network.PPP(machine.UART(0)) >>> ppp.active(True) and ppp.config('ifname') 'pp3' Note that lo0 seems to be returned by lwIP if the interface is not yet active. The method can also return None in the case of PPP where the entire lwIP interface doesn't yet exist before being activated. Currently no effort is made to unify those cases; it is expected that whatever we receive from lwIP is valid. When the socket option is set, this forces using a specific device: import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, 'st1') setsockopt will throw (OSError: [Errno 19] ENODEV) if the specified interface does not exist. Tested with LAN, WLAN, and PPP; can specify which interface should be used and when testing with, for example, HTTP requests to ifconfig.co the returned IP address confirms a specific interface was used. Signed-off-by: Daniël van de Giessen <daniel@dvdgiessen.nl>
67fba03
to
ba8aad3
Compare
Thanks for updating to use |
Greetings, can it be done on rp2? RPI PICO W ? |
This implements support for
SO_BINDTODEVICE
, which allows telling a socket to use a specific interface instead of lwIP automatically selecting one. This allows devices that have multiple connections (for example cellular over PPP in addition to WLAN) to explicitly choose which data is send over which connection, which may have different reliability and or (mobile data) costs associated with using them.The used lwIP network stack already has support for this, so all that was needed was to expose this functionality in MicroPython. This commit exposes a new constant
SO_BINDTODEVICE
which can be set as an socket option. As a value it expects the name of the interface to bind to. These names can be retrieved using.config('ifname')
implemented on each interface type (including adding a.config()
method to PPP, which didn't have it before), which returns a string with the interface name:Note that
lo0
seems to be returned by lwIP if the interface is not yet active. The method can also return None in the case of PPP where the entire lwIP interface doesn't yet exist before being activated. Currently no effort is made to unify those cases; it is expected that whatever we receive from lwIP is valid.When the socket option is set, this forces using a specific device:
setsockopt
will throw (OSError: [Errno 19] ENODEV
) if the specified interface does not exist.I've tested it works correctly with LAN, WLAN, and PPP; I can specify which interface should be used and when testing with for example HTTP requests to ifconfig.co the returned IP address confirms a specific interface was used.
Like other SO_* constants this currently lacks further documentation. And, presumably we can also implement this in other ports that use lwIP; at that point we could also document the
ifname
config parameter in the general network docs.Tagging #8173.