summaryrefslogtreecommitdiffstats
path: root/package/qos-scripts/files/usr/lib/qos/tcrules.awk
blob: ebda50640bb9c4cbd9d6acf4bbb4d7d4941eec64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
BEGIN {
	dmax=100
	if (!(linespeed > 0)) linespeed = 128
	FS=":"
	n = 0
}

($1 != "") {
	n++
	class[n] = $1
	prio[n] = $2
	avgrate[n] = ($3 * linespeed / 100)
	pktsize[n] = $4
	delay[n] = $5
	maxrate[n] = ($6 * linespeed / 100)
	qdisc_esfq[n] = $7
}

END {
	allocated = 0
	maxdelay = 0

	for (i = 1; i <= n; i++) {
		# set defaults
		if (!(pktsize[i] > 0)) pktsize[i] = 1500
		if (!(prio[i] > 0)) prio[i] = 1

		allocated += avgrate[i]
		sum_prio += prio[i]
		if ((avgrate[i] > 0) && !(delay[i] > 0)) {
			sum_rtprio += prio[i]
		}
	}
	
	# allocation of m1 in rt classes:
	# sum(d * m1) must not exceed dmax * (linespeed - allocated)
	dmax = 0
	for (i = 1; i <= n; i++) {
		if (avgrate[i] > 0) {
			rtm2[i] = avgrate[i]
			if (delay[i] > 0) {
				d[i] = delay[i]
			} else {
				d[i] = 2 * pktsize[i] * 1000 / (linespeed * 1024)
				if (d[i] > dmax) dmax = d[i]
			}
		}
	}	

	ds_avail = dmax * (linespeed - allocated)
	for (i = 1; i <= n; i++) {
		lsm1[i] = 0
		rtm1[i] = 0
		lsm2[i] = linespeed * prio[i] / sum_prio
		if ((avgrate[i] > 0) && (d[i] > 0)) {
			if (!(delay[i] > 0)) {
				ds = ds_avail * prio[i] / sum_rtprio
				ds_avail -= ds
				rtm1[i] = rtm2[i] + ds/d[i]
			}
			lsm1[i] = rtm1[i]
		}
		else {
			d[i] = 0
		}
	}

	# main qdisc
	for (i = 1; i <= n; i++) {
		printf "tc class add dev "device" parent 1:1 classid 1:"class[i]"0 hfsc"
		if (qdisc_esfq[i] != "") {
			# user requested esfq
			print "esfq " qdisc_esfq[i] " limit " ql
		} else if (rtm1[i] > 0) {
			# rt class - use sfq
			printf " rt m1 " int(rtm1[i]) "kbit d " int(d[i] * 1000) "us m2 " int(rtm2[i])"kbit"
		}
		printf " ls m1 " int(lsm1[i]) "kbit d " int(d[i] * 1000) "us m2 " int(lsm2[i]) "kbit"
		print " ul rate " int(maxrate[i]) "kbit"
	}

	# leaf qdisc
	avpkt = 1200
	for (i = 1; i <= n; i++) {
		printf "tc qdisc add dev "device" parent 1:"class[i]"0 handle "class[i]"00: "

		# RED parameters - also used to determine the queue length for sfq
		# calculate min value. for links <= 256 kbit, we use 1500 bytes
		# use 50 ms queue length as min threshold for faster links
		# max threshold is fixed to 3*min
		base_pkt=3000
		base_rate=256
		min_lat=50
		if (maxrate[i] <= base_rate) min = base_pkt
		else min = int(maxrate[i] * 1024 / 8 * 0.05)
		max = 3 * min
		limit = (min + max) * 3

		if (rtm1[i] > 0) {
			# rt class - use sfq
			print "sfq perturb 2 limit "  limit
		} else {
			# non-rt class - use RED

			avpkt = pktsize[i]
			# don't use avpkt values less than 500 bytes
			if (avpkt < 500) avpkt = 500
			# if avpkt is too close to min, scale down avpkt to allow proper bursting
			if (avpkt > min * 0.70) avpkt *= 0.70


			# according to http://www.cs.unc.edu/~jeffay/papers/IEEE-ToN-01.pdf a drop
			# probability somewhere between 0.1 and 0.2 should be a good tradeoff
			# between link utilization and response time (0.1: response; 0.2: utilization)
			prob="0.12"
		
			rburst=int((2*min + max) / (3 * avpkt))
			if (rburst < 2) rburst = 2
			print "red min " min " max " max " burst " rburst " avpkt " avpkt " limit " limit " probability " prob " ecn"
		}
	}
	
	# filter rule
	for (i = 1; i <= n; i++) {
		print "tc filter add dev "device" parent 1: prio "class[i]" protocol ip handle "class[i]" fw flowid 1:"class[i] "0" 
	}
}