Hi all.
Here's a success story, mixed with my theory of why what I did works.
My underlying philosophy to computers is that if the hardware makes it physically possible and reasonably feasible, it should be easy to do. If two machines are networked, I want to plug my joystick into one and use it on the other (damn laptops don't come with joystick ports these days). And I want to use the keyboard and mouse too (synergy does 33% of what I want, which is what I do 95% of the time).
This story is not about peripherals though, but one of networking itself. My laptop, as most laptops, has an ethernet card and a wireless interface. What I want is that whenever the cable is in, my laptop uses that (since it's faster). Whenever I unplug, it seamlessly switches to using the wireless.
Seamlessly here means that nothing except my laptop and my AP/switch sees any difference; in particular, I'm still reachable at the same IP address(es) and no TCP connections are closed. In terms of applications, any files I'm wget'ing will keep on coming down, my ssh and sshfs connection won't close and I can continue watching that youtube video of cute cats eating cheezburgr.
How might we go about that? The quick-and-dirty idea is to configure the two interfaces to have the same IP address. That's fairly easy; you edit /etc/network/interfaces (I'm on ubuntu) to make eth0 manually configured, grab an IP address for eth1 with your favorite dhcp client (network manager does this for you). Then you ifconfig eth0 {the-address-of-eth1}. That'll kinda' sorta' work. You probably need to write a shell script that detects the plugging and unplugging of cables, and invoke `ip route' just the right way when it happens to switch from using one interface to the other.
But there's this cute thing called arp that routers use to know the connection between mac addresses and ip addresses, such that it knows on which port it should send its traffic to reach the right box. If I start announcing "69.555.123.45 is at 00:13:37:d0:0d:00" and "69.555.123.45 is at 00:ca:fe:ba:be:00", the poor router will get mightily confused. Okay, so could one work around this with macchanger? Yeah, maybe, but you still need the homegrown script, and there's an easier solution to that. Also, not all NICs can change their mac address.
Besides, I'm no hardcore networking expert. I've read the IP, TCP and UDP RFCs (somewhat cursorily) and kinda' grok the ascii packet diagrams, but I've never implemented any networking code more complicated than {create socket, listen, put the client socket on a list, do a select call every now and then, do something to the data}. I'd trust the people who write networking stacks to know more about the lower levels of networking stacks than I do (and I really like networking).
Which leads to... the "bonding" kernel module. We can do away with the homegrown ip-route-invoking script and not worry about changing mac addresses, because all the smart people have already thought about that for us
What the module does is create an interface, bond0, that you can enslave other interfaces to, meaning that data routed to bond0 will be sent via one of the those devices. The bond0 device has an IP address, not the slave devices. How does it choose which slave interface to use? There are six different policies you can choose from, depending on whether you want high availability (AKA instant failover) or more bandwidth, based on an assumption of satisfactorily high availability as is.
For today's scenario, we want high availability. Sure, we might want to do something really fancy and use both interfaces at the same time, but by the figures I did the math on, you can at most increase your bandwidth by 5% by also using the wireless NIC when the cable is plugged in. So we choose to just have the box automatically switch to using eth1 when eth0 becomes down.
And here's how you do it: add to /etc/modules a line saying "
bonding mode=active-backup miimon=100 primary=eth0"
If you use WPA to encrypt, you need to run wpa_supplicant to authenticate with the access point (network manager does this for you). But the nasty trick is this: when you do that, you need to use the mac address of the interface you want to authenticate with. That means you either have to unplug eth0 when you do it, or write a little script. But you need to reauthenticate every so often, and I know me: I couldn't remember to unplug and replug eth0 every n minutes, and I don't want to do that. So script it is.
It's actually not so bad, as wpa_supplicant has a command-line interface that lets you talk to it. Here it is, in its full glory; for future reference, I've chosen to store it in /root/wpa_bonding_supplicant.
Code:
#!/bin/sh
cd /
bond=/sys/class/net/bond0/bonding/
while sleep 1s; do
pgrep wpa_supplicant > /dev/null || exit
wpa_cli status | grep -q 'COMPLETED'
primary=eth$?
echo $primary | diff - $bond/active_slave > /dev/null || \
echo $primary > $bond/primary
done
It checks whether we have completed the authentication with the AP. If so, it says to the bonding module "please use eth0 if possible"; otherwise, "please use eth1 if possible". That way, you only use eth1 when you authenticate or when eth0 is unplugged.
What's left is putting all this into motion. Here's the bond0 stanza from my /etc/network/interfaces:
Code:
noauto bond0
iface bond0 inet dhcp
pre-up ifconfig bond0 up
pre-up ifenslave bond0 eth0 eth1
pre-up wpa_supplicant -i eth1 -b bond0 -c /root/wpa.conf &
pre-up /root/wpa_bonding_supplicant &
down wpa_cli terminate
down pkill wpa_bonding
post-down ifconfig bond0 up
post-down ifenslave -d bond0 eth0 eth1
post-down ifconfig bond0 down
I've forgotten exactly what "
-b bond0" makes wpa_supplicant do differently, but I seem to recall that it makes wpa_supplicant talk to the AP over bond0 instead of eth1, meaning you use the IP and mac address of bond0 (which is kind of important).
I've put this as "noauto" beacuse I don't trust my own code (a sign that I was born to be a sysadmin

). You can put it as auto if you like, but be sure to have stanzas for eth0 and eth1 that say "manual" instead of "dhcp"; only this, and nothing more.
And there you go. Boot up. Become root. Run "ifup bond0". Start a long-lasting connection (download a big file, or ssh into one of your other machines). Plug and unplug the cable. Observe how the physically possible actually happens. And that, boy and girls, concludes today's lesson
Happy hacking.
[should this not work for you, please create a new thread instead of replying to this one; it probably belongs in Linux - Networking. Feel free to post a link to it here, though, and we can all look at it]