ansible-collection-tp-link-easy-smart-switch
ansible-collection-tp-link-easy-smart-switch copied to clipboard
Bind receiving socket to specific interface
This makes sure the receiving socket only gets one answer from the switch, even if multiple interfaces are connected to the same network.
My laptop has two network interfaces, both are connected to the same switch. This might be unusual, but I use it to play with different vlans without loosing internet connectivity when I screw up things on one port. I'm now trying to manage this switch (and later others as well) without the web interface.
When I first tried your Ansible collection (and also the original smrt code it is based on) I figured that neither worked at all. The switch answered as expected but the software somehow didn't get the correct answers. After hours of debugging I found that the the debug logs showed the exact same response beeing parsed twice, but for different requests. I also found that wireshark captured two answer packets per request, when listening on the 'any' interface. This seems plausible as the switch answers to the broadcast address, which should obviously go to all ports. Having one machine connected to multiple ports at the same time triggers the issue.
My first quick fix was to call rs.recvfrom() twice, discarding the first result. As this would break with just one or more than two connections to the switch, I tried to find a way to get around this issue.
Another possibility could be to just read all remaining data from the socket before sending a new request or keep track of expected and received/processed answers to detect duplicates, but this seemed to be a simple and elegant solution.
I now understand! And I like the solution :-)
Can you also bind the sending socket to that interface? I think that would make it more consistent with the intent of "use the same interface to send/receive data despite the host network configuration".
I think the sending interface is already bound to the correct interface, as bind
is called with the corresponding IP.
I'm not sure if I already understood the overall picture, but maybe it would make even more sense to specify the interface in the inventory.yml and defer the IP from there, as the specified IP is just used to bind
to the correct interface? That would make sure the correct interface is used, as someone could also assign the same IP to different interfaces.
Ah indeed it is. Scrap what I've said :-)
Since I assign multiple IPs to the same interface, I'd rather not use the interface to infer its IP address.
How about if we binded the receiving socket to the IP instead of the broadcast address? I'm not really sure whether that socket would receive broadcast packets from other interfaces thou... but, if that works, the code would be even simpler.
I tried binding to the IP, but could not make it work.
Multiple IPs on the interface should'nt be a problem. The IP just shows up as the sender address but as far as I know, the switch does not care. So, just picking the first IPv4 should be fine, as long as the interface is correct. Others are doing so as well.
I'd be more worried about breaking existing configurations. Thats why I didn't look into that yet. Also, because I just started with Ansible today and I still have no clue how things work :see_no_evil:
What does seem to work:
bind
ing the sending socket to 255.255.255.255
:28809
and to the interface. Then, a single socket can be used to send/receive stuff. No IP needed at all.
New proposal: I tried to change the configuration to use the interface instead of MAC and IP. My tests where successful so far. I didn't touch the take_ownership files yet as I can't test them right now (will need to find some switch downtime).
Its looking good :-)
What switch model are you testing this on?
I own two TL-SG108.
I also changed switch_take_ownership_client.py to the changed constructor of Network. I think this should work now, but I still didn't test yet.
I'll now change the PR to ready for review, as I think all necessary changes are in now.