9
9
# value to something sane for your network.
10
10
#
11
11
# The hierarchy with 8 host buckets looks like:
12
- # http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos_8hosts.png;hb=HEAD
13
12
#
14
- # Or if you prefer ASCII:
13
+ # ASCII:
15
14
#
16
15
# Interface
17
16
# |
18
17
# HTB 1:1
19
18
# / \
20
19
# Host Bucket 1 .. NUM_HOST_BUCKETS [Classes 1:10-1:(10+NUM_HOST_BUCKETS)]
20
+ # |
21
+ # DRR
21
22
# / | \
22
- # High Normal Low [Priority classes are named 1:(HOST_BUCKET * 16 + 1) ]
23
+ # High Normal Low [DRR: With three classes ]
23
24
# |
24
- # Flow Bucket 1 .. NUM_FLOW_BUCKETS [Flow QDiscs are named (HOST_BUCKET * 16 + 1 + 1):0 ]
25
+ # Leaf QDisc [Choose the type of the leaf QDisc below ]
25
26
#
26
- # The 0->NUM_FLOW_BUCKETS exist under every high, normal and low class. SFQ, SFB and FQ_CODEL
27
- # have embedded classes per flow and do not use NUM_FLOW_BUCKETS.
27
+ # The tree is created and the QDiscs are named in depth first order.
28
28
#
29
- # Yes, the class and QDisc naming is confusing and there are probably bugs
30
- # if you set the NUM_HOST_BUCKETS or NUM_FLOW_BUCKETS too high.
31
- #
32
- # ###
29
+ # #####################
33
30
# Config
34
- # ###
31
+ # #####################
35
32
36
33
# TC="/usr/local/sbin/tc"
37
34
TC=` which tc`
@@ -46,15 +43,6 @@ DEVICE="ppp0"
46
43
# in your network.
47
44
NUM_HOST_BUCKETS=16
48
45
49
- if [ ${NUM_HOST_BUCKETS} -gt 150 ] ; then
50
- # Safety valve. Script won't work after ~160 today. This is because
51
- # the parent class for each of the per host classes is encoded in the
52
- # class minor number. This makes debugging easier but wastes the minor
53
- # number space.
54
- echo " Sorry, can't do more than 150 hosts right now."
55
- exit
56
- fi
57
-
58
46
# The number of flow buckets within each high, normal and low class.
59
47
# If SFQ, SFB or FQ_CODEL are used this value is not used as these QDiscs
60
48
# have many embedded queues.
@@ -65,12 +53,7 @@ NUM_FLOW_BUCKETS=32
65
53
# ###
66
54
# All rates are kbit/sec.
67
55
# RATE should be set to just under your link rate.
68
- RATE=" 6400"
69
- # Below three rates should add up to RATE.
70
- # Priority of these classes is 1 (Higest) -> 3 (Lowest)
71
- RATE_1=" 2000"
72
- RATE_2=" 2400"
73
- RATE_3=" 2000"
56
+ RATE=" 6200"
74
57
75
58
# ###
76
59
# Queue size
@@ -136,7 +119,7 @@ HOST_KEYS="nfct-src"
136
119
137
120
# ###
138
121
# Choose the type of queue for each of the three per host priority classes
139
- # Options :
122
+ # Support options :
140
123
# drr
141
124
# sfq
142
125
# fq_codel
@@ -179,7 +162,7 @@ if [ "${QUANTUM}" != "" ]; then
179
162
fi
180
163
181
164
# #####################
182
- # Util functions
165
+ # Utility functions
183
166
# #####################
184
167
185
168
function DEBUG()
@@ -240,6 +223,16 @@ function tc_h {
240
223
${OUTPUT}
241
224
}
242
225
226
+ function get_next_free_major {
227
+ if [ " ${FREE_MAJOR} " == " " ]; then
228
+ FREE_MAJOR=2 # Assumes 1 is used.
229
+
230
+ return
231
+ fi
232
+
233
+ FREE_MAJOR=$( expr ${FREE_MAJOR} + 1)
234
+ }
235
+
243
236
# #####################
244
237
# Functions to create QDiscs at the leaves.
245
238
# #####################
@@ -343,19 +336,13 @@ function priority_class_qdisc {
343
336
# The real work starts here.
344
337
# #####################
345
338
346
- # Calculate the divided rate values for use later.
339
+ # Calculate the divided rate value for use later.
347
340
DIV_RATE=` expr ${RATE} / ${NUM_HOST_BUCKETS} `
348
- DIV_RATE_1=` expr ${RATE_1} / ${NUM_HOST_BUCKETS} `
349
- DIV_RATE_2=` expr ${RATE_2} / ${NUM_HOST_BUCKETS} `
350
- DIV_RATE_3=` expr ${RATE_3} / ${NUM_HOST_BUCKETS} `
351
341
352
342
echo " Number of host buckets: ${NUM_HOST_BUCKETS} "
353
343
echo " Rate per host (DIV_RATE):" ${DIV_RATE}
354
- echo " High priority rate per host (DIV_RATE_1):" ${DIV_RATE_1}
355
- echo " Normal priority rate per host (DIV_RATE_2):" ${DIV_RATE_2}
356
- echo " Low priority rate per host (DIV_RATE_3):" ${DIV_RATE_3}
357
344
358
- # Delete any existing qdiscs if they exist.
345
+ # Delete any existing QDiscs if they exist.
359
346
tc_h qdisc del dev ${DEVICE} root
360
347
361
348
# HTB QDisc at the root. Default all traffic into the prio qdisc.
@@ -366,7 +353,8 @@ tc_h class add dev ${DEVICE} parent 1: classid 1:1 htb rate ${RATE}kbit ${QUANTU
366
353
367
354
# #####
368
355
# Create NUM_HOST_BUCKETS classes within the top-level class.
369
- # Within each of these create three priority classes.
356
+ # Within each of these create a DRR with three classes which implement the three priorities.
357
+ # Within each priority class create the configured leaf QDisc.
370
358
# #####
371
359
for HOST_NUM in ` seq ${NUM_HOST_BUCKETS} ` ; do
372
360
DEBUG printf " Create host class: %i\n" $HOST_NUM
@@ -375,48 +363,55 @@ for HOST_NUM in `seq ${NUM_HOST_BUCKETS}`; do
375
363
DEBUG printf " \tQID: %i\n" ${QID}
376
364
tc_h class add dev ${DEVICE} parent 1:1 classid 1:${QID} htb rate ${DIV_RATE} kbit ceil ${RATE} kbit ${QUANTUM} prio 0 ${LINKLAYER} ${OVERHEAD}
377
365
366
+
378
367
# #####
379
- # Within each host bucket add three sub-classes, high, normal and low priority.
380
- # Priority classes are named 1:[HOST_BUCKET * 16 + 1]
381
- # Why 16? Because tc shows major:minor in hex so this makes it easy to match
382
- # the three sub class to the parent host bucket.
383
- #
384
- # Within each priority class uncomment one of the QDisc types.
368
+ # Within each host class create a DRR QDisc within which we'll create the
369
+ # high, normal and low priority classes.
385
370
# #####
371
+ get_next_free_major
372
+ SUB_MAJOR=${FREE_MAJOR}
373
+ tc_h qdisc add dev ${DEVICE} parent 1:${QID} handle ${SUB_MAJOR} : drr
374
+
375
+ # Filter from the host class to the DRR within it.
376
+ tc_h filter add dev ${DEVICE} prio 2 protocol ip parent 1:${QID} u32 match ip dst 0.0.0.0/0 flowid ${SUB_MAJOR} :0
377
+
386
378
387
379
# ##
388
380
# High priority class
389
381
# ##
390
- QID_1=` expr $QID ' *' 16 + 0`
391
382
DEBUG printf " \t\tHigh: %i\n" ${QID_1}
392
- tc_h class add dev ${DEVICE} parent 1: ${QID} classid 1: ${QID_1} htb rate ${DIV_RATE_1} kbit ceil ${RATE} kbit ${ QUANTUM} prio 0 ${LINKLAYER} ${OVERHEAD }
383
+ tc_h class add dev ${DEVICE} parent ${SUB_MAJOR} : classid ${SUB_MAJOR} :1 drr ${ QUANTUM}
393
384
394
385
# Create the leaf QDisc for this priority class.
395
- priority_class_qdisc ${HIGH_PRIORITY_QDISC_TYPE} 1:${QID_1} ${QID_1}
386
+ get_next_free_major
387
+ SUB_PRIO_MAJOR=${FREE_MAJOR}
388
+ priority_class_qdisc ${HIGH_PRIORITY_QDISC_TYPE} ${SUB_MAJOR} :1 ${SUB_PRIO_MAJOR}
396
389
397
390
# ##
398
391
# Normal priority class
399
392
# ##
400
- QID_2=` expr $QID ' *' 16 + 1`
401
393
DEBUG printf " \t\tNormal: %i\n" ${QID_2}
402
- tc_h class add dev ${DEVICE} parent 1: ${QID} classid 1: ${QID_2} htb rate ${DIV_RATE_2} kbit ceil ${RATE} kbit ${ QUANTUM} prio 1 ${LINKLAYER} ${OVERHEAD }
394
+ tc_h class add dev ${DEVICE} parent ${SUB_MAJOR} : classid ${SUB_MAJOR} :2 drr ${ QUANTUM}
403
395
404
396
# Create the leaf QDisc for this priority class.
405
- priority_class_qdisc ${NORMAL_PRIORITY_QDISC_TYPE} 1:${QID_2} ${QID_2}
397
+ get_next_free_major
398
+ SUB_PRIO_MAJOR=${FREE_MAJOR}
399
+ priority_class_qdisc ${NORMAL_PRIORITY_QDISC_TYPE} ${SUB_MAJOR} :2 ${SUB_PRIO_MAJOR}
406
400
407
401
# ##
408
402
# Low priority class
409
403
# ##
410
- QID_3=` expr $QID ' *' 16 + 2`
411
404
DEBUG printf " \t\tLow: %i\n" ${QID_3}
412
- tc_h class add dev ${DEVICE} parent 1: ${QID} classid 1: ${QID_3} htb rate ${DIV_RATE_3} kbit ceil ${RATE} kbit ${ QUANTUM} prio 2 ${LINKLAYER} ${OVERHEAD }
405
+ tc_h class add dev ${DEVICE} parent ${SUB_MAJOR} : classid ${SUB_MAJOR} :3 drr ${ QUANTUM}
413
406
414
407
# Create the leaf QDisc for this priority class.
415
- priority_class_qdisc ${LOW_PRIORITY_QDISC_TYPE} 1:${QID_3} ${QID_3}
408
+ get_next_free_major
409
+ SUB_PRIO_MAJOR=${FREE_MAJOR}
410
+ priority_class_qdisc ${LOW_PRIORITY_QDISC_TYPE} ${SUB_MAJOR} :3 ${SUB_PRIO_MAJOR}
416
411
417
412
418
413
# #####
419
- # Add filters to classify based on the TOS bits.
414
+ # Add filters to classify based on the TOS bits into the high, normal and low priority classes .
420
415
# Only mask against the three (used) TOS bits. The final two bits are used for ECN.
421
416
# TOS field is XXXDTRXX.
422
417
# X= Not part of the TOS field.
@@ -427,7 +422,7 @@ for HOST_NUM in `seq ${NUM_HOST_BUCKETS}`; do
427
422
# OpenSSH terminal sets D.
428
423
# OpenSSH SCP/SFTP sets T.
429
424
# It's easy to configure the Transmission Bittorrent client to set T (settings.json).
430
- # For home VoIP devices use an Iptables rule to set all of their traffic to have D.
425
+ # For home VoIP devices I use an iptables rule to set all of their traffic to have D.
431
426
#
432
427
# The thinking behind the below rules is to use D as an indication of delay sensitive
433
428
# and T as an indication of background (big transfer). All other combinations are put into
@@ -436,22 +431,22 @@ for HOST_NUM in `seq ${NUM_HOST_BUCKETS}`; do
436
431
DEBUG printf " \t\tCreating filters\n"
437
432
438
433
# D bit set.
439
- tc_h filter add dev ${DEVICE} parent 1: ${QID} protocol ip prio 10 u32 match ip tos 0x10 0x1c flowid 1: ${QID_1}
434
+ tc_h filter add dev ${DEVICE} parent ${SUB_MAJOR} : protocol ip prio 10 u32 match ip tos 0x10 0x1c flowid ${SUB_MAJOR} :1
440
435
441
436
# Diffserv expedited forwarding. Put this in the high priority class.
442
437
# Some VoIP clients set this (ie Ekiga).
443
438
# DSCP=b8
444
- tc_h filter add dev ${DEVICE} parent 1: ${QID} protocol ip prio 10 u32 match ip tos 0xb8 0xfc flowid 1: ${QID_1}
439
+ tc_h filter add dev ${DEVICE} parent ${SUB_MAJOR} : protocol ip prio 10 u32 match ip tos 0xb8 0xfc flowid ${SUB_MAJOR} :1
445
440
446
441
# T bit set.
447
- tc_h filter add dev ${DEVICE} parent 1: ${QID} protocol ip prio 10 u32 match ip tos 0x08 0x1c flowid 1: ${QID_3}
442
+ tc_h filter add dev ${DEVICE} parent ${SUB_MAJOR} : protocol ip prio 10 u32 match ip tos 0x08 0x1c flowid ${SUB_MAJOR} :3
448
443
449
444
# Everything else into default.
450
- tc_h filter add dev ${DEVICE} parent 1: ${QID} protocol ip prio 10 u32 match ip tos 0x00 0x00 flowid 1: ${QID_2}
445
+ tc_h filter add dev ${DEVICE} parent ${SUB_MAJOR} : protocol ip prio 10 u32 match ip tos 0x00 0x00 flowid ${SUB_MAJOR} :2
451
446
done
452
447
453
448
# Send everything that hits the top level QDisc to the top class.
454
- tc_h filter add dev ${DEVICE} prio 1 protocol ip parent 1:0 u32 match u32 0 0 flowid 1:1
449
+ tc_h filter add dev ${DEVICE} prio 1 protocol ip parent 1:0 u32 match ip dst 0.0.0.0/ 0 flowid 1:1
455
450
456
451
# From the top level class hash into the host classes.
457
452
tc_h filter add dev ${DEVICE} prio 1 protocol ip parent 1:1 handle 1 flow hash keys ${HOST_KEYS} divisor ${NUM_HOST_BUCKETS} ${PERTURB} baseclass 1:10
0 commit comments