Now with all of the explanation out of the way it's time to implement upstream bandwidth management with Linux.
CBQ is poorly documented and can get very complicated, so I will attempt to keep things simple
and explain them as best I can. Once again, the reason that we are using CBQ is to limit the rate
that we send data out eth0. This will prevent the ADSL modem from queuing packets. Also, we will
attach the sch_fwprio queue as a leaf queuing discipline.
All of the statements should be added to your rc.local file or another appropriate startup script.
First we tell Linux that we want CBQ to be the root queuing discipline on eth0:
tc qdisc add dev eth0 root handle 128: cbq bandwidth 10Mbit avpkt 700 |
With this line we've told Linux to use CBQ on eth0 and that the handle for this class
is 128:0, and the average packet is 700 bytes. We've also specified the total bandwidth for
eth0 as 10Mbit/sec because this is the maximum speed at which our ethernet card can transmit
data. This is NOT your upstream data rate! We'll specify that in the next statement:
tc class add dev eth0 parent 128:0 classid 128:1 cbq bandwidth 10Mbit \
rate 90Kbit allot 1514 weight 9Kbit prio 5 maxburst 1 avpkt 700 \
bounded |
This statement creates the class which will throttle outbound bandwidth on eth0 (in this
case, to 90kbit/s). Since this document is not meant to explain the inner workings of CBQ, I'll
skip a detailed explanation. The only important numbers up there are numbers following rate and weight.
The number following rate should be slightly lower than your upstream data rate. I use 90kbit
which works well for my 128kbit/s upstream, giving me almost full use of my available
bandwidth. Whatever you set your rate to, the weight should be about 1/10 of that value. Also,
the number following allot sould be set to the mtu for eth0 (1514 works fine for ethernet).
Also important is the bounded keyword. If this keyword is not specified,
then the class will attempt to borrow extra bandwidth from the parent class.
Now if you've decided NOT to patch your kernel, and instead have compiled the sch_fwprio
module, you'll need to load it BEFORE you use the prio queue. Otherwise the stock sch_prio will
be loaded:
insmod /usr/local/src/fwprio/sch_fwprio.o |
Now you have to attach the queue as a leaf discipline to the CBQ:
tc qdisc add dev eth0 parent 128:1 prio bands 4 priomap 0 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3
tc filter add dev eth0 parent 128:0 protocol ip prio 5 u32 match ip src \
1.2.3.4/32 flowid 128:1 |
With these statements we've created a prio queue of 4 bands
(which is really using our new sch_fwprio code)
and then we've used a filter to mark all of the packets
to be handled by the 128:1 classid of our CBQ, which the
prio filter is attached to. The priomap keyword, although unused by sch_fwprio, is still
necessary to initialize the individual bands. You MUST specify each band number at least
once in the 16-field priomap (in the above example I've initialized 4 bands, 0..3). You
must start at zero and end with the number of bands minus one. You must specify 16 fields
so it's okay to repeat the last band like I've done above. All of this garbage is to
satisfy the requirements of the old sch_prio code.