Remove TCP Vegas support (ARM)
[tomato.git] / release / src-rt-6.x.4708 / router / rc / qos.c
blob0bdf723361ab3c504b8998c81434c6d1d36c4fd7
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
8 Notes:
10 Originally Tomato had 10 classes, but only used 6 priority levels for some unknown reason.
11 Therefore, the last 4 classes all had the same prio of 7. The ingress system had no priority system
12 and allowed only class limits. It looked as if this was a legacy of an earlier prototype using CBQ.
14 On 4th February 2012 a new IMQ based ingress system was added to Toastman builds which
15 allows use of priorities on all incoming classes. QOS now uses 10 prios in both egress and ingress.
17 An incoming bandwidth pie chart was added at the same time, making it easier to see the result of
18 QOS rules on incoming data.
20 -Toastman
24 #include "rc.h"
26 #include <sys/stat.h>
28 static const char *qosfn = "/etc/qos";
29 static const char *qosImqDeviceNumberString = "0";
30 static const char *qosImqDeviceString = "ifb0";
32 // in mangle table
33 void ipt_qos(void)
35 char *buf;
36 char *g;
37 char *p;
38 char *addr_type, *addr;
39 char *proto;
40 char *port_type, *port;
41 char *class_prio;
42 char *ipp2p, *layer7;
43 char *bcount;
44 char *dscp;
45 char *desc;
46 int class_num;
47 int proto_num;
48 int v4v6_ok;
49 int i;
50 char sport[192];
51 char saddr[256];
52 char end[256];
53 char s[32];
54 char app[128];
55 int inuse;
56 const char *chain;
57 unsigned long min;
58 unsigned long max;
59 unsigned long prev_max;
60 int gum;
61 const char *qface;
62 int sizegroup;
63 int class_flag;
64 int rule_num;
66 if (!nvram_get_int("qos_enable")) return;
68 inuse = 0;
69 gum = 0x100;
70 sizegroup = 0;
71 prev_max = 0;
72 rule_num = 0;
74 ip46t_write(
75 ":QOSO - [0:0]\n"
76 "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n"
77 "-A QOSO -m connmark ! --mark 0/0x0f00 -j RETURN\n");
79 g = buf = strdup(nvram_safe_get("qos_orules"));
80 while (g) {
84 addr_type<addr<proto<port_type<port<ipp2p<L7<bcount<dscp<class_prio<desc
86 addr_type:
87 0 = any
88 1 = dest ip
89 2 = src ip
90 3 = src mac
91 addr:
92 ip/mac if addr_type == 1-3
93 proto:
94 0-65535 = protocol
95 -1 = tcp or udp
96 -2 = any protocol
97 port_type:
98 if proto == -1,tcp,udp:
99 d = dest
100 s = src
101 x = both
102 a = any
103 port:
104 port # if proto == -1,tcp,udp
105 bcount:
106 min:max
107 blank = none
108 dscp:
109 empty - any
110 numeric (0:63) - dscp value
111 afXX, csX, be, ef - dscp class
112 class_prio:
113 0-10 // was 0-8 - Changed from 8 in pkt_sched.h - Toastman
114 -1 = disabled
118 if ((p = strsep(&g, ">")) == NULL) break;
119 i = vstrsep(p, "<", &addr_type, &addr, &proto, &port_type, &port, &ipp2p, &layer7, &bcount, &dscp, &class_prio, &desc);
120 rule_num++;
121 if (i == 10) {
122 // fixup < v1.28.XX55
123 desc = class_prio;
124 class_prio = dscp;
125 dscp = "";
127 else if (i == 9) {
128 // fixup < v0.08 // !!! temp
129 desc = class_prio;
130 class_prio = bcount;
131 bcount = "";
132 dscp = "";
134 else if (i != 11) continue;
136 class_num = atoi(class_prio);
137 if ((class_num < 0) || (class_num > 9)) continue;
139 i = 1 << class_num;
140 ++class_num;
142 if ((inuse & i) == 0) {
143 inuse |= i;
146 v4v6_ok = IPT_V4;
147 #ifdef TCONFIG_IPV6
148 if (ipv6_enabled())
149 v4v6_ok |= IPT_V6;
150 #endif
151 class_flag = gum;
153 saddr[0] = '\0';
154 end[0] = '\0';
155 // mac or ip address
156 if ((*addr_type == '1') || (*addr_type == '2')) { // match ip
157 v4v6_ok &= ipt_addr(saddr, sizeof(saddr), addr, (*addr_type == '1') ? "dst" : "src",
158 v4v6_ok, (v4v6_ok==IPT_V4), "QoS", desc);
159 if (!v4v6_ok) continue;
161 else if (*addr_type == '3') { // match mac
162 sprintf(saddr, "-m mac --mac-source %s", addr); // (-m mac modified, returns !match in OUTPUT)
165 // IPP2P/Layer7
166 if (ipt_ipp2p(ipp2p, app)) v4v6_ok &= ~IPT_V6;
167 else ipt_layer7(layer7, app);
168 if (app[0]) {
169 v4v6_ok &= ~IPT_V6; // temp: l7 not working either!
170 class_flag = 0x100;
171 // IPP2P and L7 rules may need more than one packet before matching
172 // so port-based rules that come after them in the list can't be sticky
173 // or else these rules might never match.
174 gum = 0;
175 strcat(saddr, app);
178 // dscp
179 if (ipt_dscp(dscp, s)) {
180 #ifndef LINUX26
181 v4v6_ok &= ~IPT_V6; // dscp ipv6 match is not present in K2.4
182 #endif
183 strcat(saddr, s);
186 // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes
187 if (*bcount) {
188 min = strtoul(bcount, &p, 10);
189 if (*p != 0) {
190 strcat(saddr, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes ");
191 ++p;
192 if (*p == 0) {
193 sprintf(saddr + strlen(saddr), "%lu:", min * 1024);
195 else {
196 max = strtoul(p, NULL, 10);
197 sprintf(saddr + strlen(saddr), "%lu:%lu", min * 1024, (max * 1024) - 1);
198 if (gum) {
199 if (!sizegroup) {
200 // Create table of connbytes sizes, pass appropriate connections there
201 // and only continue processing them if mark was wiped
202 ip46t_write(
203 ":QOSSIZE - [0:0]\n"
204 "-I QOSO 3 -m connmark ! --mark 0/0xff000 -j QOSSIZE\n"
205 "-I QOSO 4 -m connmark ! --mark 0/0xff000 -j RETURN\n");
207 if (max != prev_max && sizegroup<255) {
208 class_flag = ++sizegroup << 12;
209 prev_max = max;
210 ip46t_flagged_write(v4v6_ok,
211 "-A QOSSIZE -m connmark --mark 0x%x/0xff000"
212 " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j CONNMARK --set-return 0x00000/0xFF\n",
213 (sizegroup << 12), (max * 1024));
214 #ifdef BCMARM
215 ip46t_flagged_write(v4v6_ok,
216 "-A QOSSIZE -m connmark --mark 0x%x/0xff000"
217 " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j RETURN\n",
218 (sizegroup << 12), (max * 1024));
219 #endif
221 else {
222 class_flag = sizegroup << 12;
228 else {
229 bcount = "";
233 chain = "QOSO";
234 class_num |= class_flag;
235 class_num |= rule_num << 20;
236 sprintf(end + strlen(end), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num);
238 // protocol & ports
239 proto_num = atoi(proto);
240 if (proto_num > -2) {
241 if ((proto_num == 6) || (proto_num == 17) || (proto_num == -1)) {
242 if (*port_type != 'a') {
243 if ((*port_type == 'x') || (strchr(port, ','))) {
244 // dst-or-src port matches, and anything with multiple lists "," use multiport
245 sprintf(sport, "-m multiport --%sports %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port);
247 else {
248 // single or simple x:y range, use built-in tcp/udp match
249 sprintf(sport, "--%sport %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port);
252 else {
253 sport[0] = 0;
255 if (proto_num != 6) {
256 ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "udp", sport, saddr, end);
257 #ifdef BCMARM
258 ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s -j RETURN\n", chain, "udp", sport, saddr);
259 #endif
261 if (proto_num != 17) {
262 ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "tcp", sport, saddr, end);
263 #ifdef BCMARM
264 ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s -j RETURN\n", chain, "tcp", sport, saddr);
265 #endif
268 else {
269 ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s %s", chain, proto_num, saddr, end);
270 #ifdef BCMARM
271 ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s -j RETURN\n", chain, proto_num, saddr);
272 #endif
275 else { // any protocol
276 ip46t_flagged_write(v4v6_ok, "-A %s %s %s", chain, saddr, end);
277 #ifdef BCMARM
278 ip46t_flagged_write(v4v6_ok, "-A %s %s -j RETURN\n", chain, saddr);
279 #endif
283 free(buf);
285 qface = wanfaces.iface[0].name;
287 i = nvram_get_int("qos_default");
288 if ((i < 0) || (i > 9)) i = 3; // "low"
289 class_num = i + 1;
290 class_num |= 0xFF00000; // use rule_num=255 for default
291 ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num);
292 #ifdef BCMARM
293 ip46t_write("-A QOSO -j RETURN\n");
294 #endif
296 ipt_write(
297 "-A FORWARD -o %s -j QOSO\n"
298 "-A OUTPUT -o %s -j QOSO\n"
299 "-A FORWARD -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n"
300 "-A OUTPUT -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n",
301 qface, qface, qface, qface);
303 #ifdef TCONFIG_IPV6
304 if (*wan6face) {
305 ip6t_write(
306 "-A FORWARD -o %s -j QOSO\n"
307 "-A OUTPUT -o %s -p icmpv6 -j RETURN\n"
308 "-A OUTPUT -o %s -j QOSO\n"
309 "-A FORWARD -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n"
310 "-A OUTPUT -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n",
311 wan6face, wan6face, wan6face, wan6face, wan6face);
313 #endif
315 inuse |= (1 << i) | 1; // default and highest are always built
316 sprintf(s, "%d", inuse);
317 nvram_set("qos_inuse", s);
320 g = buf = strdup(nvram_safe_get("qos_irates"));
321 for (i = 0; i < 10; ++i)
323 if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue;
324 if ((inuse & (1 << i)) == 0) continue;
326 unsigned int rate;
327 unsigned int ceil;
329 // check if we've got a percentage definition in the form of "rate-ceiling"
330 // and that rate > 1
331 if ((sscanf(p, "%u-%u", &rate, &ceil) == 2) && (rate >= 1))
333 ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", qface);
334 #ifdef BCMARM
335 ipt_write("-A PREROUTING -i %s -j RETURN\n", qface);
336 #endif
337 #ifdef TCONFIG_IPV6
338 if (*wan6face) {
339 ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face);
340 #ifdef BCMARM
341 ip6t_write("-A PREROUTING -i %s -j RETURN\n", wan6face);
342 #endif
344 #endif
345 break;
348 free(buf);
351 static unsigned calc(unsigned bw, unsigned pct)
353 unsigned n = ((unsigned long)bw * pct) / 100;
354 return (n < 2) ? 2 : n;
357 void start_qos(void)
359 int i;
360 char *buf, *g, *p, *qos;
361 unsigned int rate;
362 unsigned int ceil;
363 unsigned int bw;
364 unsigned int incomingBandwidthInKilobitsPerSecond;
365 unsigned int mtu;
366 unsigned int r2q;
367 unsigned int qosDefaultClassId;
368 unsigned int overhead;
369 FILE *f;
370 int x;
371 int inuse;
372 char s[256];
373 int first;
374 char burst_root[32];
375 char burst_leaf[32];
377 qosDefaultClassId = (nvram_get_int("qos_default") + 1) * 10;
378 incomingBandwidthInKilobitsPerSecond = strtoul(nvram_safe_get("qos_ibw"), NULL, 10);
380 if (!nvram_get_int("qos_enable")) return;
382 if ((f = fopen(qosfn, "w")) == NULL) return;
384 i = nvram_get_int("qos_burst0");
385 if (i > 0) sprintf(burst_root, "burst %dk", i);
386 else burst_root[0] = 0;
387 i = nvram_get_int("qos_burst1");
388 if (i > 0) sprintf(burst_leaf, "burst %dk", i);
389 else burst_leaf[0] = 0;
391 mtu = strtoul(nvram_safe_get("wan_mtu"), NULL, 10);
392 bw = strtoul(nvram_safe_get("qos_obw"), NULL, 10);
393 overhead = strtoul(nvram_safe_get("atm_overhead"), NULL, 10);
394 r2q = 10;
396 if ((bw * 1000) / (8 * r2q) < mtu) {
397 r2q = (bw * 1000) / (8 * mtu);
398 if (r2q < 1) r2q = 1;
399 } else if ((bw * 1000) / (8 * r2q) > 60000) {
400 r2q = (bw * 1000) / (8 * 60000) + 1;
403 x = nvram_get_int("qos_pfifo");
404 if (x == 1) {
405 qos = "pfifo limit 256";
406 } else if (x == 2) {
407 qos = "codel";
408 } else if (x == 3) {
409 qos = "fq_codel";
410 } else {
411 qos = "sfq perturb 10";
413 if (overhead == 0) {
414 fprintf(f,
415 "#!/bin/sh\n"
416 "WAN_DEV=%s\n"
417 "IMQ_DEV=%s\n"
418 "TQA=\"tc qdisc add dev $WAN_DEV\"\n"
419 "TCA=\"tc class add dev $WAN_DEV\"\n"
420 "TFA=\"tc filter add dev $WAN_DEV\"\n"
421 "TQA_IMQ=\"tc qdisc add dev $IMQ_DEV\"\n"
422 "TCA_IMQ=\"tc class add dev $IMQ_DEV\"\n"
423 "TFA_IMQ=\"tc filter add dev $IMQ_DEV\"\n"
424 "Q=\"%s\"\n"
425 "\n"
426 "case \"$1\" in\n"
427 "start)\n"
428 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
429 "\t$TQA root handle 1: htb default %u r2q %u\n"
430 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
431 get_wanface(),
432 qosImqDeviceString,
433 qos,
434 qosDefaultClassId, r2q,
435 bw, bw, burst_root);
436 } else {
437 fprintf(f,
438 "#!/bin/sh\n"
439 "WAN_DEV=%s\n"
440 "IMQ_DEV=%s\n"
441 "TQA=\"tc qdisc add dev $WAN_DEV\"\n"
442 "TCA=\"tc class add dev $WAN_DEV\"\n"
443 "TFA=\"tc filter add dev $WAN_DEV\"\n"
444 "TQA_IMQ=\"tc qdisc add dev $IMQ_DEV\"\n"
445 "TCA_IMQ=\"tc class add dev $IMQ_DEV\"\n"
446 "TFA_IMQ=\"tc filter add dev $IMQ_DEV\"\n"
447 "Q=\"%s\"\n"
448 "\n"
449 "case \"$1\" in\n"
450 "start)\n"
451 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
452 "\t$TQA root handle 1: htb default %u r2q %u\n"
453 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s overhead %u linklayer atm\n",
454 get_wanface(),
455 qosImqDeviceString,
456 qos,
457 qosDefaultClassId, r2q,
458 bw, bw, burst_root, overhead);
461 inuse = nvram_get_int("qos_inuse");
463 g = buf = strdup(nvram_safe_get("qos_orates"));
464 for (i = 0; i < 10; ++i) {
465 if ((!g) || ((p = strsep(&g, ",")) == NULL)) break;
467 if ((inuse & (1 << i)) == 0) continue;
469 // check if we've got a percentage definition in the form of "rate-ceiling"
470 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1)) continue; // 0=off
472 if (ceil > 0) sprintf(s, "ceil %ukbit ", calc(bw, ceil));
473 else s[0] = 0;
474 x = (i + 1) * 10;
476 if (overhead == 0) {
477 fprintf(f,
478 "# egress %d: %u-%u%%\n"
479 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
480 "\t$TQA parent 1:%d handle %d: $Q\n"
481 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
482 i, rate, ceil,
483 x, calc(bw, rate), s, burst_leaf, i+1, mtu,
484 x, x,
485 x, i + 1, x);
486 #ifdef TCONFIG_IPV6
487 fprintf(f,
488 "\t$TFA parent 1: prio %d protocol ipv6 handle %d fw flowid 1:%d\n",
489 x + 100, i + 1, x);
490 #endif
491 } else {
492 fprintf(f,
493 "# egress %d: %u-%u%%\n"
494 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u overhead %u linklayer atm\n"
495 "\t$TQA parent 1:%d handle %d: $Q\n"
496 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
497 i, rate, ceil,
498 x, calc(bw, rate), s, burst_leaf, i+1, mtu, overhead,
499 x, x,
500 x, i + 1, x);
501 #ifdef TCONFIG_IPV6
502 fprintf(f,
503 "\t$TFA parent 1: prio %d protocol ipv6 handle %d fw flowid 1:%d\n",
504 x + 100, i + 1, x);
505 #endif
508 free(buf);
510 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
514 if (nvram_match("qos_ack", "1")) {
515 fprintf(f,
516 "\n"
517 "\t$TFA parent 1: prio 15 protocol ip u32 "
518 "match ip protocol 6 0xff " // TCP
519 "match u8 0x05 0x0f at 0 " // IP header length
520 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
521 "match u8 0x10 0xff at 33 " // ACK only
522 "flowid 1:10\n");
524 if (nvram_match("qos_icmp", "1")) {
525 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
530 if (nvram_get_int("qos_ack")) {
531 fprintf(f,
532 "\n"
533 "\t$TFA parent 1: prio 14 protocol ip u32 "
534 "match ip protocol 6 0xff " // TCP
535 "match u8 0x05 0x0f at 0 " // IP header length
536 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
537 "match u8 0x10 0xff at 33 " // ACK only
538 "flowid 1:10\n");
541 if (nvram_get_int("qos_syn")) {
542 // 10000 = ACK
543 // 00010 = SYN
545 fprintf(f,
546 "\n"
547 "\t$TFA parent 1: prio 15 protocol ip u32 "
548 "match ip protocol 6 0xff " // TCP
549 "match u8 0x05 0x0f at 0 " // IP header length
550 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
551 "match u8 0x02 0xff at 33 " // SYN only
552 "flowid 1:10\n"
553 "\n"
554 "\t$TFA parent 1: prio 16 protocol ip u32 "
555 "match ip protocol 6 0xff " // TCP
556 "match u8 0x05 0x0f at 0 " // IP header length
557 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
558 "match u8 0x12 0xff at 33 " // SYN,ACK
559 "flowid 1:10\n");
562 if (nvram_get_int("qos_fin")) {
563 // 10000 = ACK
564 // 00001 = FIN
566 fprintf(f,
567 "\n"
568 "\t$TFA parent 1: prio 17 protocol ip u32 "
569 "match ip protocol 6 0xff " // TCP
570 "match u8 0x05 0x0f at 0 " // IP header length
571 "match u8 0x11 0xff at 33 " // ACK,FIN
572 "flowid 1:10\n"
573 "\n"
574 "\t$TFA parent 1: prio 18 protocol ip u32 "
575 "match ip protocol 6 0xff " // TCP
576 "match u8 0x05 0x0f at 0 " // IP header length
577 "match u8 0x01 0xff at 33 " // FIN
578 "flowid 1:10\n");
581 if (nvram_get_int("qos_rst")) {
582 // 10000 = ACK
583 // 00100 = RST
584 fprintf(f,
585 "\n"
586 "\t$TFA parent 1: prio 19 protocol ip u32 "
587 "match ip protocol 6 0xff " // TCP
588 "match u8 0x05 0x0f at 0 " // IP header length
589 "match u8 0x14 0xff at 33 " // ACK,RST
590 "flowid 1:10\n"
591 "\n"
592 "\t$TFA parent 1: prio 20 protocol ip u32 "
593 "match ip protocol 6 0xff " // TCP
594 "match u8 0x05 0x0f at 0 " // IP header length
595 "match u8 0x04 0xff at 33 " // RST
596 "flowid 1:10\n");
600 if (nvram_get_int("qos_icmp")) {
601 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
606 10000 = ACK
607 00100 = RST
608 00010 = SYN
609 00001 = FIN
612 if (nvram_get_int("qos_ack")) {
613 fprintf(f,
614 "\n"
615 "\t$TFA parent 1: prio 14 protocol ip u32 "
616 "match ip protocol 6 0xff " // TCP
617 "match u8 0x05 0x0f at 0 " // IP header length
618 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
619 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
620 "match u8 0x10 0xff at 33 " // ACK only
621 "flowid 1:10\n");
624 if (nvram_get_int("qos_syn")) {
625 fprintf(f,
626 "\n"
627 "\t$TFA parent 1: prio 15 protocol ip u32 "
628 "match ip protocol 6 0xff " // TCP
629 "match u8 0x05 0x0f at 0 " // IP header length
630 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
631 "match u8 0x02 0x02 at 33 " // SYN,*
632 "flowid 1:10\n");
635 if (nvram_get_int("qos_fin")) {
636 fprintf(f,
637 "\n"
638 "\t$TFA parent 1: prio 17 protocol ip u32 "
639 "match ip protocol 6 0xff " // TCP
640 "match u8 0x05 0x0f at 0 " // IP header length
641 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
642 "match u8 0x01 0x01 at 33 " // FIN,*
643 "flowid 1:10\n");
646 if (nvram_get_int("qos_rst")) {
647 fprintf(f,
648 "\n"
649 "\t$TFA parent 1: prio 19 protocol ip u32 "
650 "match ip protocol 6 0xff " // TCP
651 "match u8 0x05 0x0f at 0 " // IP header length
652 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
653 "match u8 0x04 0x04 at 33 " // RST,*
654 "flowid 1:10\n");
657 if (nvram_get_int("qos_icmp")) {
658 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
662 ////
663 //// INCOMING TRAFFIC SHAPING
664 ////
666 first = 1;
667 overhead = strtoul(nvram_safe_get("atm_overhead"), NULL, 10);
669 g = buf = strdup(nvram_safe_get("qos_irates"));
671 for (i = 0; i < 10; ++i)
673 if ((!g) || ((p = strsep(&g, ",")) == NULL))
675 break;
678 if ((inuse & (1 << i)) == 0)
680 continue;
683 // check if we've got a percentage definition in the form of "rate-ceiling"
684 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1))
686 continue; // 0=off
689 // class ID
690 unsigned int classid = ((unsigned int)i + 1) * 10;
692 // priority
693 unsigned int priority = (unsigned int)i + 1; //prios 1-10 - Toastman
695 // rate in kb/s
696 unsigned int rateInKilobitsPerSecond =
697 calc(incomingBandwidthInKilobitsPerSecond, rate);
699 // ceiling in kb/s
700 unsigned int ceilingInKilobitsPerSecond =
701 calc(incomingBandwidthInKilobitsPerSecond, ceil);
703 // burst rate (2% of the classes' rate) - don't know if we should use this
704 //Commented out KDB 20130531 - produces compiler warning about being unused!
705 // unsigned int burstRateInBitsPerSecond =
706 // (rateInKilobitsPerSecond * 1000) / 50;
708 r2q = 10;
709 if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) < mtu)
711 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * mtu);
712 if (r2q < 1) r2q = 1;
714 else if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) > 60000)
716 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * 60000) + 1;
719 if (first)
721 first = 0;
722 fprintf(f,
723 "\n"
724 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
725 "\t$TQA handle ffff: ingress\n");
726 if (overhead == 0) {
727 fprintf(f,
728 "\n"
729 "\tip link set $IMQ_DEV up\n"
730 "\ttc qdisc del dev $IMQ_DEV 2>/dev/null\n"
731 "\t$TQA_IMQ handle 1: root htb default %u r2q %u\n"
732 "\t$TCA_IMQ parent 1: classid 1:1 htb rate %ukbit ceil %ukbit\n",
733 qosDefaultClassId, r2q,
734 incomingBandwidthInKilobitsPerSecond,
735 incomingBandwidthInKilobitsPerSecond);
736 } else {
737 fprintf(f,
738 "\n"
739 "\tip link set $IMQ_DEV up\n"
740 "\ttc qdisc del dev $IMQ_DEV 2>/dev/null\n"
741 "\t$TQA_IMQ handle 1: root htb default %u r2q %u\n"
742 "\t$TCA_IMQ parent 1: classid 1:1 htb rate %ukbit ceil %ukbit overhead %u linklayer atm\n",
743 qosDefaultClassId, r2q,
744 incomingBandwidthInKilobitsPerSecond,
745 incomingBandwidthInKilobitsPerSecond, overhead);
748 fprintf(f,
749 "\n"
750 "\t$TFA parent ffff: protocol ip prio 10 u32 match ip %s action mirred egress redirect dev $IMQ_DEV\n", (nvram_get_int("qos_udp") == 1) ? "protocol 6 0xff" : "dst 0.0.0.0/0");
753 fprintf(
755 "\n"
756 "\t# class id %u: rate %ukbit ceil %ukbit\n",
757 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond);
759 if (overhead == 0) {
760 fprintf(
762 "\t$TCA_IMQ parent 1:1 classid 1:%u htb rate %ukbit ceil %ukbit prio %u quantum %u\n",
763 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond, priority, mtu);
764 } else {
765 fprintf(
767 "\t$TCA_IMQ parent 1:1 classid 1:%u htb rate %ukbit ceil %ukbit prio %u quantum %u overhead %u linklayer atm\n",
768 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond, priority, mtu, overhead);
771 fprintf(
773 "\t$TQA_IMQ parent 1:%u handle %u: $Q\n",
774 classid, classid);
776 fprintf(
778 "\t$TFA_IMQ parent 1: prio %u protocol ip handle %u fw flowid 1:%u \n",
779 classid, priority, classid);
781 #ifdef TCONFIG_IPV6
782 fprintf(
784 "\t$TFA_IMQ parent 1: prio %u protocol ipv6 handle %u fw flowid 1:%u \n",
785 classid + 100, priority, classid);
786 #endif
789 free(buf);
791 //// write commands which adds rule to forward traffic to IMQ device
792 fputs(
793 "\n"
794 "\t# set up the IMQ device (otherwise this won't work) to limit the incoming data\n"
795 "\tip link set $IMQ_DEV up\n",
798 fprintf(f,
799 "\t;;\n"
800 "stop)\n"
801 "\tip link set $IMQ_DEV down\n"
802 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
803 "\ttc qdisc del dev $IMQ_DEV root 2>/dev/null\n"
804 "\ttc filter del dev $WAN_DEV parent ffff: protocol ip prio 10 u32 match ip %s action mirred egress redirect dev $IMQ_DEV 2>/dev/null\n"
805 "\t;;\n"
806 "*)\n"
807 "\techo \"...\"\n"
808 "\techo \"... OUTGOING QDISCS AND CLASSES FOR $WAN_DEV\"\n"
809 "\techo \"...\"\n"
810 "\ttc -s -d qdisc ls dev $WAN_DEV\n"
811 "\techo\n"
812 "\ttc -s -d class ls dev $WAN_DEV\n"
813 "\techo\n"
814 "\techo \"...\"\n"
815 "\techo \"... INCOMING QDISCS AND CLASSES FOR $WAN_DEV (routed through $IMQ_DEV)\"\n"
816 "\techo \"...\"\n"
817 "\ttc -s -d qdisc ls dev $IMQ_DEV\n"
818 "\techo\n"
819 "\ttc -s -d class ls dev $IMQ_DEV\n"
820 "\techo\n"
821 "esac\n",
822 (nvram_get_int("qos_udp") == 1) ? "protocol 6 0xff" : "dst 0.0.0.0/0");
824 fclose(f);
825 chmod(qosfn, 0700);
826 eval((char *)qosfn, "start");
829 void stop_qos(void)
831 eval((char *)qosfn, "stop");
833 if (!nvram_match("debug_keepfiles", "1")) {
834 unlink(qosfn);
841 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
842 QD | ^
845 INPUT (f) OUTPUT (mnf)