How I doubled my bandwidth by playing with routing tables
A while back, I availed of Sun's postpaid HSDPA service, primarily as a stopgap until I could finagle a proper hardline connection. I kept it, so I could work, even in the middle of a farm, as I stated in a previous post.
Except I haven't been to that farm in a while. Hell, I haven't gone anywhere in a while. I'm either working, sleeping or studying. For the past 2 or 3 months, the Huawei dongle that Sun provided went unused (except the one time my mom borrowed it to use during a trip to Baguio). Aside from that, it used to see daylight only when I take it out of the drawer when I clean my office. Or, you know, when I took it out to take a picture for use with an entry.
I'm still paying monthly fees for the thing; I'm locked to it by a 2-year contract. So I figured I should find a way to actually make use of it.
Back when I was still using Windows, I remembered a little trick you could do with dial-up connections. You could trunk them, resulting in a single virtual connection with bandwidth that's effectively the sum of its individual connections. I figured if Windows could do it, GNU/Linux should also be able to, no sweat.
As most of you know, I'm a code monkey by temperament and vocation; what system and network administrations skills I have, I learned by virtue of being the most qualified one in the family to take it up. So it took me a while to figure out, but, by ghod, was it worth it when I finally managed to do it.
In the interest of saving other people much hair-pulling, incomprehensible mumbling and outright violent tantrums, I'm writing the instructions down.
The situation¶
The DSL connection I'm using can do bursts of up to and around 120 to 140 kB/second, or about 1 mbps. Nothing to write home about, but it works out okay. For the past couple of days or so, I've noticed problems with my main connection's bandwidth shrinking to pretty much nothing, before going back up to its normal state.
This happens without rhyme nor reason (that I can figure out), although it's probably my lousy v7 Linksys router signaling its impending (and none-too-soon) death. Although it could also be the telco's fault; the ineptitude of PLDT's "technical" staff is legion.
As you can probably imagine, I got a little bit of a push from being annoyed by this.
Sun's HSDPA connection, meanwhile, averages about the same. True, Sun says I ought to get up to twice as much bandwidth, but I'm literally 4 feet away from a dead spot in every direction--I'm taking whatever I can get.
The payback¶
When I finally got this setup working, I managed to hit a little under 200 kB/sec before (it seems) a bunch of seeders called it a night. Sadly, I was too stunned and giddy after I got it working that I didn't manage to grab a screenshot as it was going down, so you're going to have to trust me on this one.
The screenshot I did manage to grab is shows an ongoing torrent while the YouTube video clip in the background is still able to buffer quite a sizable percentage. Normally, even when only about 50 kBps of my downstream goes to torrents, I'm unable to build up that much of a buffer in YouTube.
The build-up¶
While guides abound, none of the ones I dug up explained clearly the difference between bridging, bonding/link aggregation, and a bunch of other networking terms that seem to require a CCNA to understand. Also, all of the guides I've come across assume that you're trying work with two or more ethernet adapters.
After multiple cursing rounds that would make any tanned and salted sailor blush, I finally hit the right sequence of incantations required to get it working. And, no, you don't need to actually need to be a CCNA (or have one by your side) to get this working; you don't even have to read the links in the previous paragraph.
The setup¶
If you're using a GPRS "modem", as I am, I'm assuming you've already
managed to figure out how to connect to your provider. Personally, I
use the stock ppp package, with a custom
chat script, to which I've also
added custom ip-up
and ip-down
scripts.
Having facilities for post-connection and post-disconnection scripts isn't required, of course, but helps in making things run smoother.
In any case, here're the commands you need to run, presented without comment (those come afterward):
ip route add $PPP_NET dev $PPP_DEV src $PPP_IP table gprs
ip route add default dev $PPP_DEV table gprs
ip route add $HOME_NET dev $HOME_DEV src $HOME_IP table home
ip route add default via $HOME_GATEWAY table home
ip rule add from $PPP_IP table gprs
ip rule add from $HOME_IP table home
ip route del default via $HOME_GATEWAY dev wlan0
ip route add default scope global \
nexthop via $HOME_GATEWAY dev $HOME_DEV weight 5 \
nexthop via $PPP_NET dev $PPP_DEV weight 1
After pulling the plug on your HSDPA connection, you need these commands to ensure that traffic flows normally through your remaining connection properly:
ip route add default via $HOME_GATEWAY dev $HOME_DEV
Here're what the variables above should be:
- $PPP_NET is the network segment your HSDPA connection tells you
you're a member of. For my Sun connection, it's
10.64.64.64
. - $PPP_DEV is the PPP device your connection is attached to. Most
likely
ppp0
, unless you have another PPP connection. - $PPP_IP is the IP address your provider has assigned to your connection.
- $HOME_NET is the network segment your wireless connection is
associated with. Mine's
192.168.1.0/24
. - $HOME_DEV is the device associated with your wireless connection.
Probably
wlan0
. - $HOME_IP is your wireless connection's IP address.
- $HOME_GATEWAY is your gateway's address. If you only have one router, this'll be your router's IP address.
The identifier after table
in the above commands is an arbitrary
string. You probably have to edit the iputils
configuration first;
on my Arch Linux install, the file I
needed to edit was /etc/iproute2/rt_tables
.
Of course, this isn't limited to pairings of an HSDPA and wireless
connections; this would work just as well with wired connections.
Just replace $HOME_DEV
with the appropriate ethernet device name
(e.g., eth0
). The weight
values can be tweaked, as well; think of
it as an affinity indicator for packets. The higher the weight, the
more likely it is that a given packet will go through that particular
route.
(This is probably incorrect, or, at best, inaccurate.) Near as I can tell, what we're doing is we're setting up the routes for each connection. Setting each individual connection up, as it is, to be able to perform by itself. Then we tell GNU/Linux about the two separate routes we've set up, and let the system figure out how it's going to use it. We also tell the system that no matter what happens, particular IP addresses have to be reached by a particular route. This lets me still reach (and be reached by) the other computers in my network without a hitch.
The letdown¶
It's not all sweetness and light, mind you. There are some caveats to this setup.
As an example, take this publicly-private tracker I've recently become a member of. It tracks ratios using a member's IP address; since I'm reachable by, and (worse yet) can reach them using, two addresses, my ratios have become a little off.
(I've since added a rule that connections to that tracker have to go through my home network; though as to why I never thought about doing it earlier, I can only plead being tired. And lazy. And, also, being a n00b.)
So, if you frequent a site that tracks you by IP (as opposed to cookies), you should add a rule that restricts traffic to that site's IP address to a specified route. Switching between two or more routes might lead to hair-pulling, and people only have so much hair.
(There are likely incomplete thoughts, errors and whatnot in this post; if so, excuse please, and let me know. I'll get to them eventually--right now, I just want to catch up on my sleep debt.)
[Update: Here's another screengrab, this time of bwm-ng, done while I was pulling Evolution from the repos:
Yep. 340+ kilobytes per second. A little under 3 megabits/sec. It's like my connections, together, are the little pipes that could. :D]