fix QOS prios
[tomato.git] / release / src / router / rc / qos.c
blobdfd55558dcc33b6b209481424b526f0f7a3b7bcf
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 = "imq0";
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[192];
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;
154 if (ipt_ipp2p(ipp2p, app)) v4v6_ok &= ~IPT_V6;
155 else ipt_layer7(layer7, app);
156 if (app[0]) {
157 v4v6_ok &= ~IPT_V6; // temp: l7 not working either!
158 class_flag = 0x100;
159 // IPP2P and L7 rules may need more than one packet before matching
160 // so port-based rules that come after them in the list can't be sticky
161 // or else these rules might never match.
162 gum = 0;
164 strcpy(end, app);
166 // dscp
167 if (ipt_dscp(dscp, s)) {
168 #ifndef LINUX26
169 v4v6_ok &= ~IPT_V6; // dscp ipv6 match is not present in K2.4
170 #endif
171 strcat(end, s);
174 // mac or ip address
175 if ((*addr_type == '1') || (*addr_type == '2')) { // match ip
176 v4v6_ok &= ipt_addr(saddr, sizeof(saddr), addr, (*addr_type == '1') ? "dst" : "src",
177 v4v6_ok, (v4v6_ok==IPT_V4), "QoS", desc);
178 if (!v4v6_ok) continue;
180 else if (*addr_type == '3') { // match mac
181 sprintf(saddr, "-m mac --mac-source %s", addr); // (-m mac modified, returns !match in OUTPUT)
183 else {
184 saddr[0] = 0;
188 // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes
189 if (*bcount) {
190 min = strtoul(bcount, &p, 10);
191 if (*p != 0) {
192 strcat(end, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes ");
193 ++p;
194 if (*p == 0) {
195 sprintf(end + strlen(end), "%lu:", min * 1024);
197 else {
198 max = strtoul(p, NULL, 10);
199 sprintf(end + strlen(end), "%lu:%lu", min * 1024, (max * 1024) - 1);
200 if (gum) {
201 if (!sizegroup) {
202 // Create table of connbytes sizes, pass appropriate connections there
203 // and only continue processing them if mark was wiped
204 ip46t_write(
205 ":QOSSIZE - [0:0]\n"
206 "-I QOSO 3 -m connmark ! --mark 0/0xff000 -j QOSSIZE\n"
207 "-I QOSO 4 -m connmark ! --mark 0/0xff000 -j RETURN\n");
209 if (max != prev_max && sizegroup<255) {
210 class_flag = ++sizegroup << 12;
211 prev_max = max;
212 ip46t_flagged_write(v4v6_ok,
213 "-A QOSSIZE -m connmark --mark 0x%x/0xff000"
214 " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j CONNMARK --set-return 0x00000/0xFF\n",
215 (sizegroup << 12), (max * 1024));
217 else {
218 class_flag = sizegroup << 12;
224 else {
225 bcount = "";
229 chain = "QOSO";
230 class_num |= class_flag;
231 class_num |= rule_num << 20;
232 sprintf(end + strlen(end), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num);
234 // protocol & ports
235 proto_num = atoi(proto);
236 if (proto_num > -2) {
237 if ((proto_num == 6) || (proto_num == 17) || (proto_num == -1)) {
238 if (*port_type != 'a') {
239 if ((*port_type == 'x') || (strchr(port, ','))) {
240 // dst-or-src port matches, and anything with multiple lists "," use multiport
241 sprintf(sport, "-m multiport --%sports %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port);
243 else {
244 // single or simple x:y range, use built-in tcp/udp match
245 sprintf(sport, "--%sport %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port);
248 else {
249 sport[0] = 0;
251 if (proto_num != 6) ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "udp", sport, saddr, end);
252 if (proto_num != 17) ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "tcp", sport, saddr, end);
254 else {
255 ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s %s", chain, proto_num, saddr, end);
258 else { // any protocol
259 ip46t_flagged_write(v4v6_ok, "-A %s %s %s", chain, saddr, end);
263 free(buf);
265 qface = wanfaces.iface[0].name;
267 i = nvram_get_int("qos_default");
268 if ((i < 0) || (i > 9)) i = 3; // "low"
269 class_num = i + 1;
270 class_num |= 0xFF00000; // use rule_num=255 for default
271 ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num);
273 ipt_write(
274 "-A FORWARD -o %s -j QOSO\n"
275 "-A OUTPUT -o %s -j QOSO\n",
276 qface, qface);
278 #ifdef TCONFIG_IPV6
279 if (*wan6face) {
280 ip6t_write(
281 "-A FORWARD -o %s -j QOSO\n"
282 "-A OUTPUT -o %s -j QOSO\n",
283 wan6face, wan6face);
285 #endif
287 inuse |= (1 << i) | 1; // default and highest are always built
288 sprintf(s, "%d", inuse);
289 nvram_set("qos_inuse", s);
292 g = buf = strdup(nvram_safe_get("qos_irates"));
294 for (i = 0; i < 10; ++i)
296 if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue;
297 if ((inuse & (1 << i)) == 0) continue;
299 unsigned int rate;
300 unsigned int ceil;
302 // check if we've got a percentage definition in the form of "rate-ceiling"
303 // and that rate > 1
304 if ((sscanf(p, "%u-%u", &rate, &ceil) == 2) && (rate >= 1))
306 ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", qface);
309 if (nvram_get_int("qos_udp")) {
310 ipt_write("-A PREROUTING -i %s -p tcp -j IMQ --todev %s\n", qface, qosImqDeviceNumberString); // pass only tcp
312 else {
313 ipt_write("-A PREROUTING -i %s -j IMQ --todev %s\n", qface, qosImqDeviceNumberString); // pass everything thru ingress
316 #ifdef TCONFIG_IPV6
317 if (*wan6face)
319 ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face);
321 if (nvram_get_int("qos_udp")) {
322 ip6t_write("-A PREROUTING -i %s -p tcp -j IMQ --todev %s\n", wan6face, qosImqDeviceNumberString); // pass only tcp
324 else {
325 ip6t_write("-A PREROUTING -i %s -j IMQ --todev %s\n", wan6face, qosImqDeviceNumberString); // pass everything thru ingress
328 #endif
329 break;
332 free(buf);
335 static unsigned calc(unsigned bw, unsigned pct)
337 unsigned n = ((unsigned long)bw * pct) / 100;
338 return (n < 2) ? 2 : n;
341 void start_qos(void)
343 int i;
344 char *buf, *g, *p;
345 unsigned int rate;
346 unsigned int ceil;
347 unsigned int bw;
348 unsigned int incomingBandwidthInKilobitsPerSecond;
349 unsigned int mtu;
350 unsigned int r2q;
351 unsigned int qosDefaultClassId;
352 FILE *f;
353 int x;
354 int inuse;
355 char s[256];
356 int first;
357 char burst_root[32];
358 char burst_leaf[32];
360 qosDefaultClassId = (nvram_get_int("qos_default") + 1) * 10;
361 incomingBandwidthInKilobitsPerSecond = strtoul(nvram_safe_get("qos_ibw"), NULL, 10);
363 // move me?
364 x = nvram_get_int("ne_vegas");
365 #ifdef LINUX26
366 if (x) {
367 char alpha[10], beta[10], gamma[10];
368 sprintf(alpha, "alpha=%d", nvram_get_int("ne_valpha"));
369 sprintf(beta, "beta=%d", nvram_get_int("ne_vbeta"));
370 sprintf(gamma, "gamma=%d", nvram_get_int("ne_vgamma"));
371 modprobe("tcp_vegas", alpha, beta, gamma);
372 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "vegas", 0, 0);
374 else {
375 modprobe_r("tcp_vegas");
376 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "", FW_NEWLINE, 0);
378 #else
379 f_write_string("/proc/sys/net/ipv4/tcp_vegas_cong_avoid", x ? "1" : "0", 0, 0);
380 if (x) {
381 f_write_string("/proc/sys/net/ipv4/tcp_vegas_alpha", nvram_safe_get("ne_valpha"), 0, 0);
382 f_write_string("/proc/sys/net/ipv4/tcp_vegas_beta", nvram_safe_get("ne_vbeta"), 0, 0);
383 f_write_string("/proc/sys/net/ipv4/tcp_vegas_gamma", nvram_safe_get("ne_vgamma"), 0, 0);
385 #endif
387 if (!nvram_get_int("qos_enable")) return;
389 if ((f = fopen(qosfn, "w")) == NULL) return;
391 i = nvram_get_int("qos_burst0");
392 if (i > 0) sprintf(burst_root, "burst %dk", i);
393 else burst_root[0] = 0;
394 i = nvram_get_int("qos_burst1");
395 if (i > 0) sprintf(burst_leaf, "burst %dk", i);
396 else burst_leaf[0] = 0;
398 mtu = strtoul(nvram_safe_get("wan_mtu"), NULL, 10);
399 bw = strtoul(nvram_safe_get("qos_obw"), NULL, 10);
401 r2q = 10;
402 if ((bw * 1000) / (8 * r2q) < mtu) {
403 r2q = (bw * 1000) / (8 * mtu);
404 if (r2q < 1) r2q = 1;
405 } else if ((bw * 1000) / (8 * r2q) > 60000) {
406 r2q = (bw * 1000) / (8 * 60000) + 1;
409 fprintf(f,
410 "#!/bin/sh\n"
411 "WAN_DEV=%s\n"
412 "IMQ_DEV=%s\n"
413 "TQA=\"tc qdisc add dev $WAN_DEV\"\n"
414 "TCA=\"tc class add dev $WAN_DEV\"\n"
415 "TFA=\"tc filter add dev $WAN_DEV\"\n"
416 "TQA_IMQ=\"tc qdisc add dev $IMQ_DEV\"\n"
417 "TCA_IMQ=\"tc class add dev $IMQ_DEV\"\n"
418 "TFA_IMQ=\"tc filter add dev $IMQ_DEV\"\n"
419 "Q=\"%s\"\n"
420 "\n"
421 "case \"$1\" in\n"
422 "start)\n"
423 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
424 "\t$TQA root handle 1: htb default %u r2q %u\n"
425 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
426 get_wanface(),
427 qosImqDeviceString,
428 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
429 qosDefaultClassId, r2q,
430 bw, bw, burst_root);
432 inuse = nvram_get_int("qos_inuse");
434 g = buf = strdup(nvram_safe_get("qos_orates"));
435 for (i = 0; i < 10; ++i) {
436 if ((!g) || ((p = strsep(&g, ",")) == NULL)) break;
438 if ((inuse & (1 << i)) == 0) continue;
440 // check if we've got a percentage definition in the form of "rate-ceiling"
441 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1)) continue; // 0=off
443 if (ceil > 0) sprintf(s, "ceil %ukbit ", calc(bw, ceil));
444 else s[0] = 0;
445 x = (i + 1) * 10;
446 fprintf(f,
447 "# egress %d: %u-%u%%\n"
448 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
449 "\t$TQA parent 1:%d handle %d: $Q\n"
450 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
451 i, rate, ceil,
452 x, calc(bw, rate), s, burst_leaf, i+1, mtu, //prios 1-10 - Toastman
453 x, x,
454 x, i + 1, x);
456 free(buf);
458 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
462 if (nvram_match("qos_ack", "1")) {
463 fprintf(f,
464 "\n"
465 "\t$TFA parent 1: prio 15 protocol ip u32 "
466 "match ip protocol 6 0xff " // TCP
467 "match u8 0x05 0x0f at 0 " // IP header length
468 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
469 "match u8 0x10 0xff at 33 " // ACK only
470 "flowid 1:10\n");
472 if (nvram_match("qos_icmp", "1")) {
473 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
478 if (nvram_get_int("qos_ack")) {
479 fprintf(f,
480 "\n"
481 "\t$TFA parent 1: prio 14 protocol ip u32 "
482 "match ip protocol 6 0xff " // TCP
483 "match u8 0x05 0x0f at 0 " // IP header length
484 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
485 "match u8 0x10 0xff at 33 " // ACK only
486 "flowid 1:10\n");
489 if (nvram_get_int("qos_syn")) {
490 // 10000 = ACK
491 // 00010 = SYN
493 fprintf(f,
494 "\n"
495 "\t$TFA parent 1: prio 15 protocol ip u32 "
496 "match ip protocol 6 0xff " // TCP
497 "match u8 0x05 0x0f at 0 " // IP header length
498 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
499 "match u8 0x02 0xff at 33 " // SYN only
500 "flowid 1:10\n"
501 "\n"
502 "\t$TFA parent 1: prio 16 protocol ip u32 "
503 "match ip protocol 6 0xff " // TCP
504 "match u8 0x05 0x0f at 0 " // IP header length
505 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
506 "match u8 0x12 0xff at 33 " // SYN,ACK
507 "flowid 1:10\n");
510 if (nvram_get_int("qos_fin")) {
511 // 10000 = ACK
512 // 00001 = FIN
514 fprintf(f,
515 "\n"
516 "\t$TFA parent 1: prio 17 protocol ip u32 "
517 "match ip protocol 6 0xff " // TCP
518 "match u8 0x05 0x0f at 0 " // IP header length
519 "match u8 0x11 0xff at 33 " // ACK,FIN
520 "flowid 1:10\n"
521 "\n"
522 "\t$TFA parent 1: prio 18 protocol ip u32 "
523 "match ip protocol 6 0xff " // TCP
524 "match u8 0x05 0x0f at 0 " // IP header length
525 "match u8 0x01 0xff at 33 " // FIN
526 "flowid 1:10\n");
529 if (nvram_get_int("qos_rst")) {
530 // 10000 = ACK
531 // 00100 = RST
532 fprintf(f,
533 "\n"
534 "\t$TFA parent 1: prio 19 protocol ip u32 "
535 "match ip protocol 6 0xff " // TCP
536 "match u8 0x05 0x0f at 0 " // IP header length
537 "match u8 0x14 0xff at 33 " // ACK,RST
538 "flowid 1:10\n"
539 "\n"
540 "\t$TFA parent 1: prio 20 protocol ip u32 "
541 "match ip protocol 6 0xff " // TCP
542 "match u8 0x05 0x0f at 0 " // IP header length
543 "match u8 0x04 0xff at 33 " // RST
544 "flowid 1:10\n");
548 if (nvram_get_int("qos_icmp")) {
549 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
554 10000 = ACK
555 00100 = RST
556 00010 = SYN
557 00001 = FIN
560 if (nvram_get_int("qos_ack")) {
561 fprintf(f,
562 "\n"
563 "\t$TFA parent 1: prio 14 protocol ip u32 "
564 "match ip protocol 6 0xff " // TCP
565 "match u8 0x05 0x0f at 0 " // IP header length
566 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
567 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
568 "match u8 0x10 0xff at 33 " // ACK only
569 "flowid 1:10\n");
572 if (nvram_get_int("qos_syn")) {
573 fprintf(f,
574 "\n"
575 "\t$TFA parent 1: prio 15 protocol ip u32 "
576 "match ip protocol 6 0xff " // TCP
577 "match u8 0x05 0x0f at 0 " // IP header length
578 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
579 "match u8 0x02 0x02 at 33 " // SYN,*
580 "flowid 1:10\n");
583 if (nvram_get_int("qos_fin")) {
584 fprintf(f,
585 "\n"
586 "\t$TFA parent 1: prio 17 protocol ip u32 "
587 "match ip protocol 6 0xff " // TCP
588 "match u8 0x05 0x0f at 0 " // IP header length
589 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
590 "match u8 0x01 0x01 at 33 " // FIN,*
591 "flowid 1:10\n");
594 if (nvram_get_int("qos_rst")) {
595 fprintf(f,
596 "\n"
597 "\t$TFA parent 1: prio 19 protocol ip u32 "
598 "match ip protocol 6 0xff " // TCP
599 "match u8 0x05 0x0f at 0 " // IP header length
600 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
601 "match u8 0x04 0x04 at 33 " // RST,*
602 "flowid 1:10\n");
605 if (nvram_get_int("qos_icmp")) {
606 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
610 ////
611 //// INCOMING TRAFFIC SHAPING
612 ////
614 first = 1;
616 g = buf = strdup(nvram_safe_get("qos_irates"));
618 for (i = 0; i < 10; ++i)
620 if ((!g) || ((p = strsep(&g, ",")) == NULL))
622 break;
625 if ((inuse & (1 << i)) == 0)
627 continue;
630 // check if we've got a percentage definition in the form of "rate-ceiling"
631 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1))
633 continue; // 0=off
636 // class ID
637 unsigned int classid = ((unsigned int)i + 1) * 10;
639 // priority
640 unsigned int priority = (unsigned int)i + 1; //prios 1-10 - Toastman
642 // rate in kb/s
643 unsigned int rateInKilobitsPerSecond =
644 calc(incomingBandwidthInKilobitsPerSecond, rate);
646 // ceiling in kb/s
647 unsigned int ceilingInKilobitsPerSecond =
648 calc(incomingBandwidthInKilobitsPerSecond, ceil);
650 // burst rate (2% of the classes' rate) - don't know if we should use this
651 unsigned int burstRateInBitsPerSecond =
652 (rateInKilobitsPerSecond * 1000) / 50;
654 r2q = 10;
655 if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) < mtu)
657 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * mtu);
658 if (r2q < 1) r2q = 1;
660 else if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) > 60000)
662 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * 60000) + 1;
665 if (first)
667 first = 0;
668 fprintf(f,
669 "\n"
670 "\tip link set $IMQ_DEV up\n"
671 "\ttc qdisc del dev $IMQ_DEV 2>/dev/null\n"
672 "\t$TQA_IMQ handle 1: root htb default %u r2q %u\n"
673 "\t$TCA_IMQ parent 1: classid 1:1 htb rate %ukbit ceil %ukbit\n",
674 qosDefaultClassId, r2q,
675 incomingBandwidthInKilobitsPerSecond,
676 incomingBandwidthInKilobitsPerSecond);
679 fprintf(
681 "\n"
682 "\t# class id %u: rate %ukbit ceil %ukbit\n",
683 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond);
685 fprintf(
687 "\t$TCA_IMQ parent 1:1 classid 1:%u htb rate %ukbit ceil %ukbit prio %u quantum %u\n",
688 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond, priority, mtu);
690 fprintf(
692 "\t$TQA_IMQ parent 1:%u handle %u: $Q\n",
693 classid, classid);
695 fprintf(
697 "\t$TFA_IMQ parent 1: prio %u protocol ip handle %u fw flowid 1:%u \n",
698 classid, priority, classid);
701 free(buf);
703 //// write commands which adds rule to forward traffic to IMQ device
704 fputs(
705 "\n"
706 "\t# set up the IMQ device (otherwise this won't work) to limit the incoming data\n"
707 "\tip link set $IMQ_DEV up\n",
710 fputs(
711 "\t;;\n"
712 "stop)\n"
713 "\tip link set $IMQ_DEV down\n"
714 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
715 "\ttc qdisc del dev $IMQ_DEV root 2>/dev/null\n"
716 "\t;;\n"
717 "*)\n"
718 "\techo \"...\"\n"
719 "\techo \"... OUTGOING QDISCS AND CLASSES FOR $WAN_DEV\"\n"
720 "\techo \"...\"\n"
721 "\ttc -s -d qdisc ls dev $WAN_DEV\n"
722 "\techo\n"
723 "\ttc -s -d class ls dev $WAN_DEV\n"
724 "\techo\n"
725 "\techo \"...\"\n"
726 "\techo \"... INCOMING QDISCS AND CLASSES FOR $WAN_DEV (routed through $IMQ_DEV)\"\n"
727 "\techo \"...\"\n"
728 "\ttc -s -d qdisc ls dev $IMQ_DEV\n"
729 "\techo\n"
730 "\ttc -s -d class ls dev $IMQ_DEV\n"
731 "\techo\n"
732 "esac\n",
735 fclose(f);
736 chmod(qosfn, 0700);
737 eval((char *)qosfn, "start");
740 void stop_qos(void)
742 eval((char *)qosfn, "stop");
744 if (!nvram_match("debug_keepfiles", "1")) {
745 unlink(qosfn);
752 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
753 QD | ^
756 INPUT (f) OUTPUT (mnf)