Quality of Surfing: An Intermediate Level HowTo

by Glenn Stone

How many of us poor blighters on 56K (or even DSL) have been dinking away on an SSH session when all of a sudden the connection seems to lag? The data lights on the modem indicate furious activity. And then we notice it--the spousal unit or the child process is busy sucking down some huge web page, hogging our connections. You'd feel bad telling them to lay off for a bit; besides, having their own machines sharing your Internet feeds keeps them out of your hair, right? Well, not exactly. If they've got the bandwidth that means you don't. And, there's always the question of glomming the latest ISO off the Pink Tie mirror or the new trailer for Hollywood's latest attempt at converting a comic book into several million dollars worth of popcorn revenues. One would love to see it real soon now, without waiting until the dinner hour when no one is on to dedicate the bit-pipe. Or, even better, perhaps you're one of the lucky ones who actually can run a server from home these days, and you just made Slashdot. Uh-oh. Now you'll never get anything done.

Not to worry, you're running Linux. There are ways of fixing this situation, but you'll need to clog the bit-pipe one last time. You're going to need the kernel source and any dependencies, as well as the iproute package. You also need to know how to recompile the kernel. Much about this topic has been written elsewhere; go Google for the Linux Kernel HOWTO if you need more information.

Unpack your kernel source, copy an old .config into place if you want and do make menuconfig (make xconfig if you like point and click). Go down to Networking options, turn on Network packet filtering, IP: advanced router and IP: use TOS as routing key. You may want to key on some of the other options here if you want to play around with, say, user-based priorities, but let's keep it simple for now. I'll provide a link to more than you ever wanted to know about this topic when we get done. Go down almost to the bottom of Networking options, select QoS and/or fair queueing and turn everything in there on. (Save maybe IPv6, if you're not playing with that; if you're thinking "huh?" you're not.) Crank up your kernel compile, and finish reading this article while you wait.

What we're going to do is make our Linux box into what's called an advanced router. If you're already using Linux to do NAT or at least network connection sharing, you know Linux can be used as a router, passing packets from one network to another. You probably also know something about firewalling, the ability to reject packets coming into or going out of your network on the basis of content. What you probably didn't know was that Linux not only can say "yea" or "nay" to a packet, but also "slow down" or "hold up a sec, let him go first". This is called Quality of Service support and interfaces to userland in the form of a little program called tc, for traffic control. We'll use a fairly simple kernel filter called u32 to ferret out interactive traffic (looking at the ToS or Type of Service field in the packet), bump it to the head of the line outbound and set the bulk traffic filter ("queueing discipline") to use only a percentage of the outbound bandwidth. The other thing we'll do is implement stochastic (random) queueing on each of the data streams (interactive and bulk) going outbound, so no one connection of either type can hog all the bandwidth all the time.

That takes care of outbound, but what about inbound? Because inbound traffic has already hit the modem by the time Linux sees it, we can't do any fancy priority tricks with it. But, we can take advantage of the fact that TCP/IP, by design, rate-limits the data stream based on how many of its packets are getting ACKed. If we start dropping packets, the big bad upstream router takes the hint and throttles back until it's getting a steady stream of ACKs. The stochastic queueing upstream makes sure each connection gets its fair share and only its fair share of those ACKs. What we do is tell Linux to hold the inbound packet rate to just under our datalink rate and then allow bursting of the bandwidth; this lets interactive packets sneak through. Filtering the inbound data stream is called "policing", and while it isn't as versatile as using a queueing discipline, it's still effective.

Okay, here's where the rubber meets the road. Instead of reproducing the whole queueing script here, I'm going to give you a link to one designed for DSL that is located elsewhere. Then, I'll tell you what I did to make it work with my little ol' 56K modem, and why I did it. The script is here. I'm using the CBQ script in 15.8.2. Cut and paste, then follow along as I tinker with it.

The first thing to do is set the uplink and downlink speeds to something resembling reality; I set DOWNLINK=45 and UPLINK=30. 6K modems really uplink at only 33.6. Your mileage may vary; feel free to frob this until it works right. Then I tinkered with the traffic percentage on the bulk queue (look for the line just below and a lower priority), and change $[9*$UPLINK/10]kbit. I set the multiplier (9) to 7. You can up this for higher datalink rates or lower it to get meaningful bandwidth for interactive links on slow modems. The final bit of tinkering comes at the end; I replaced the ${DOWNLINK} in the last line with $[9*DOWNLINK/10]. This set the default inbound bandwidth to 90% of the link speed and changed the burst size from 10K to 2K. These numbers are something you'll want to tinker with as well; bigger pipes can handle bigger bursts without impairing your interactive performance.

When your kernel compile finishes, go ahead and install it and the iproute package, if you haven't installed it already. (It's iproute2 under Mandrake, if you use that distribution.) Now, reboot, bring up your netlink if it doesn't come up automatically and run the script as root, of course. Then fire up an SSH outbound session, change windows and start a big--for your link--download. Go back to SSH and try typing. Isn't that cool? If it's still a little laggy, or if it's really fast and you want to try tweaking it, edit your script, drop the link, re-up it and rerun the script. It doesn't work simply to rerun the script; I tried. I'm not sure I understand why, but that's what I got.

Life at 56K finally is bearable. I was able to type away at a remote shell with a 20MB download pounding along in another window. Something I ordinarily would have saved for an overnight run. And I could surf, too, thanks to the stochastic queueing. The single download isn't allowed to overwhelm its own queue, much less the modem link. No, you're not controlling downstream directly, but think of the stream of ACKs going back up as the reins on a fiery thoroughbred. Tug enough, and he'll slow down. Sure, it's no 1.5Mb firehose, but it sure is nice to be able to keep reading mail when my wife decides to download the morning comics.

Have fun!


The author would like to acknowledge Burt Hubert and company for the Linux Advanced Routing & Traffic Control HOWTO, which, while being more than you ever wanted to know about rocket-science-class Linux routing, is actually quite readable. It enabled me to grok the scripty goodness well enough to explain it to you hopefully without blowing you away.

Glenn Stone is a Red Hat Certified Engineer, sysadmin, technical writer, cover model and general Linux flunkie. He has been hand-building computers for fun and profit since 1999, and he is a happy denizen of the Pacific Northwest.

email: liawol.org!gs

Load Disqus comments