fix outgoing QOS prios
[tomato.git] / release / src / router / rc / qos.c
blob25601a067868e9b3568cf3ee1cd7fce005eb90bd
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "rc.h"
10 #include <sys/stat.h>
12 static const char *qosfn = "/etc/qos";
13 static const char *qosImqDeviceNumberString = "0";
14 static const char *qosImqDeviceString = "imq0";
16 // in mangle table
17 void ipt_qos(void)
19 char *buf;
20 char *g;
21 char *p;
22 char *addr_type, *addr;
23 char *proto;
24 char *port_type, *port;
25 char *class_prio;
26 char *ipp2p, *layer7;
27 char *bcount;
28 char *dscp;
29 char *desc;
30 int class_num;
31 int proto_num;
32 int v4v6_ok;
33 int i;
34 char sport[192];
35 char saddr[192];
36 char end[256];
37 char s[32];
38 char app[128];
39 int inuse;
40 const char *chain;
41 unsigned long min;
42 unsigned long max;
43 unsigned long prev_max;
44 int gum;
45 const char *qface;
46 int sizegroup;
47 int class_flag;
48 int rule_num;
50 if (!nvram_get_int("qos_enable")) return;
52 inuse = 0;
53 gum = 0x100;
54 sizegroup = 0;
55 prev_max = 0;
56 rule_num = 0;
58 ip46t_write(
59 ":QOSO - [0:0]\n"
60 "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n"
61 "-A QOSO -m connmark ! --mark 0/0x0f00 -j RETURN\n");
63 g = buf = strdup(nvram_safe_get("qos_orules"));
64 while (g) {
68 addr_type<addr<proto<port_type<port<ipp2p<L7<bcount<dscp<class_prio<desc
70 addr_type:
71 0 = any
72 1 = dest ip
73 2 = src ip
74 3 = src mac
75 addr:
76 ip/mac if addr_type == 1-3
77 proto:
78 0-65535 = protocol
79 -1 = tcp or udp
80 -2 = any protocol
81 port_type:
82 if proto == -1,tcp,udp:
83 d = dest
84 s = src
85 x = both
86 a = any
87 port:
88 port # if proto == -1,tcp,udp
89 bcount:
90 min:max
91 blank = none
92 dscp:
93 empty - any
94 numeric (0:63) - dscp value
95 afXX, csX, be, ef - dscp class
96 class_prio:
97 0-10 // Changed from 8 in pkt_sched.h - Toastman
98 -1 = disabled
102 if ((p = strsep(&g, ">")) == NULL) break;
103 i = vstrsep(p, "<", &addr_type, &addr, &proto, &port_type, &port, &ipp2p, &layer7, &bcount, &dscp, &class_prio, &desc);
104 rule_num++;
105 if (i == 10) {
106 // fixup < v1.28.XX55
107 desc = class_prio;
108 class_prio = dscp;
109 dscp = "";
111 else if (i == 9) {
112 // fixup < v0.08 // !!! temp
113 desc = class_prio;
114 class_prio = bcount;
115 bcount = "";
116 dscp = "";
118 else if (i != 11) continue;
120 class_num = atoi(class_prio);
121 if ((class_num < 0) || (class_num > 9)) continue;
123 i = 1 << class_num;
124 ++class_num;
126 if ((inuse & i) == 0) {
127 inuse |= i;
130 v4v6_ok = IPT_V4;
131 #ifdef TCONFIG_IPV6
132 if (ipv6_enabled())
133 v4v6_ok |= IPT_V6;
134 #endif
135 class_flag = gum;
138 if (ipt_ipp2p(ipp2p, app)) v4v6_ok &= ~IPT_V6;
139 else ipt_layer7(layer7, app);
140 if (app[0]) {
141 v4v6_ok &= ~IPT_V6; // temp: l7 not working either!
142 class_flag = 0x100;
143 // IPP2P and L7 rules may need more than one packet before matching
144 // so port-based rules that come after them in the list can't be sticky
145 // or else these rules might never match.
146 gum = 0;
148 strcpy(end, app);
150 // dscp
151 if (ipt_dscp(dscp, s)) {
152 #ifndef LINUX26
153 v4v6_ok &= ~IPT_V6; // dscp ipv6 match is not present in K2.4
154 #endif
155 strcat(end, s);
158 // mac or ip address
159 if ((*addr_type == '1') || (*addr_type == '2')) { // match ip
160 v4v6_ok &= ipt_addr(saddr, sizeof(saddr), addr, (*addr_type == '1') ? "dst" : "src",
161 v4v6_ok, (v4v6_ok==IPT_V4), "QoS", desc);
162 if (!v4v6_ok) continue;
164 else if (*addr_type == '3') { // match mac
165 sprintf(saddr, "-m mac --mac-source %s", addr); // (-m mac modified, returns !match in OUTPUT)
167 else {
168 saddr[0] = 0;
172 // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes
173 if (*bcount) {
174 min = strtoul(bcount, &p, 10);
175 if (*p != 0) {
176 strcat(end, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes ");
177 ++p;
178 if (*p == 0) {
179 sprintf(end + strlen(end), "%lu:", min * 1024);
181 else {
182 max = strtoul(p, NULL, 10);
183 sprintf(end + strlen(end), "%lu:%lu", min * 1024, (max * 1024) - 1);
184 if (gum) {
185 if (!sizegroup) {
186 // Create table of connbytes sizes, pass appropriate connections there
187 // and only continue processing them if mark was wiped
188 ip46t_write(
189 ":QOSSIZE - [0:0]\n"
190 "-I QOSO 3 -m connmark ! --mark 0/0xff000 -j QOSSIZE\n"
191 "-I QOSO 4 -m connmark ! --mark 0/0xff000 -j RETURN\n");
193 if (max != prev_max && sizegroup<255) {
194 class_flag = ++sizegroup << 12;
195 prev_max = max;
196 ip46t_flagged_write(v4v6_ok,
197 "-A QOSSIZE -m connmark --mark 0x%x/0xff000"
198 " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j CONNMARK --set-return 0x00000/0xFF\n",
199 (sizegroup << 12), (max * 1024));
201 else {
202 class_flag = sizegroup << 12;
208 else {
209 bcount = "";
213 chain = "QOSO";
214 class_num |= class_flag;
215 class_num |= rule_num << 20;
216 sprintf(end + strlen(end), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num);
218 // protocol & ports
219 proto_num = atoi(proto);
220 if (proto_num > -2) {
221 if ((proto_num == 6) || (proto_num == 17) || (proto_num == -1)) {
222 if (*port_type != 'a') {
223 if ((*port_type == 'x') || (strchr(port, ','))) {
224 // dst-or-src port matches, and anything with multiple lists "," use multiport
225 sprintf(sport, "-m multiport --%sports %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port);
227 else {
228 // single or simple x:y range, use built-in tcp/udp match
229 sprintf(sport, "--%sport %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port);
232 else {
233 sport[0] = 0;
235 if (proto_num != 6) ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "udp", sport, saddr, end);
236 if (proto_num != 17) ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "tcp", sport, saddr, end);
238 else {
239 ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s %s", chain, proto_num, saddr, end);
242 else { // any protocol
243 ip46t_flagged_write(v4v6_ok, "-A %s %s %s", chain, saddr, end);
247 free(buf);
249 qface = wanfaces.iface[0].name;
251 i = nvram_get_int("qos_default");
252 if ((i < 0) || (i > 9)) i = 3; // "low"
253 class_num = i + 1;
254 class_num |= 0xFF00000; // use rule_num=255 for default
255 ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num);
257 ipt_write(
258 "-A FORWARD -o %s -j QOSO\n"
259 "-A OUTPUT -o %s -j QOSO\n",
260 qface, qface);
262 #ifdef TCONFIG_IPV6
263 if (*wan6face) {
264 ip6t_write(
265 "-A FORWARD -o %s -j QOSO\n"
266 "-A OUTPUT -o %s -j QOSO\n",
267 wan6face, wan6face);
269 #endif
271 inuse |= (1 << i) | 1; // default and highest are always built
272 sprintf(s, "%d", inuse);
273 nvram_set("qos_inuse", s);
276 g = buf = strdup(nvram_safe_get("qos_irates"));
278 for (i = 0; i < 10; ++i)
280 if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue;
281 if ((inuse & (1 << i)) == 0) continue;
283 unsigned int rate;
284 unsigned int ceil;
286 // check if we've got a percentage definition in the form of "rate-ceiling"
287 // and that rate > 1
288 if ((sscanf(p, "%u-%u", &rate, &ceil) == 2) && (rate >= 1))
290 ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", qface);
293 if (nvram_get_int("qos_udp")) {
294 ipt_write("-A PREROUTING -i %s -p tcp -j IMQ --todev %s\n", qface, qosImqDeviceNumberString); // pass only tcp
296 else {
297 ipt_write("-A PREROUTING -i %s -j IMQ --todev %s\n", qface, qosImqDeviceNumberString); // pass everything thru ingress
300 #ifdef TCONFIG_IPV6
301 if (*wan6face)
303 ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face);
305 if (nvram_get_int("qos_udp")) {
306 ip6t_write("-A PREROUTING -i %s -p tcp -j IMQ --todev %s\n", wan6face, qosImqDeviceNumberString); // pass only tcp
308 else {
309 ip6t_write("-A PREROUTING -i %s -j IMQ --todev %s\n", wan6face, qosImqDeviceNumberString); // pass everything thru ingress
312 #endif
313 break;
316 free(buf);
319 static unsigned calc(unsigned bw, unsigned pct)
321 unsigned n = ((unsigned long)bw * pct) / 100;
322 return (n < 2) ? 2 : n;
325 void start_qos(void)
327 int i;
328 char *buf, *g, *p;
329 unsigned int rate;
330 unsigned int ceil;
331 unsigned int bw;
332 unsigned int incomingBandwidthInKilobitsPerSecond;
333 unsigned int mtu;
334 unsigned int r2q;
335 unsigned int qosDefaultClassId;
336 FILE *f;
337 int x;
338 int inuse;
339 char s[256];
340 int first;
341 char burst_root[32];
342 char burst_leaf[32];
344 qosDefaultClassId = (nvram_get_int("qos_default") + 1) * 10;
345 incomingBandwidthInKilobitsPerSecond = strtoul(nvram_safe_get("qos_ibw"), NULL, 10);
347 // move me?
348 x = nvram_get_int("ne_vegas");
349 #ifdef LINUX26
350 if (x) {
351 char alpha[10], beta[10], gamma[10];
352 sprintf(alpha, "alpha=%d", nvram_get_int("ne_valpha"));
353 sprintf(beta, "beta=%d", nvram_get_int("ne_vbeta"));
354 sprintf(gamma, "gamma=%d", nvram_get_int("ne_vgamma"));
355 modprobe("tcp_vegas", alpha, beta, gamma);
356 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "vegas", 0, 0);
358 else {
359 modprobe_r("tcp_vegas");
360 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "", FW_NEWLINE, 0);
362 #else
363 f_write_string("/proc/sys/net/ipv4/tcp_vegas_cong_avoid", x ? "1" : "0", 0, 0);
364 if (x) {
365 f_write_string("/proc/sys/net/ipv4/tcp_vegas_alpha", nvram_safe_get("ne_valpha"), 0, 0);
366 f_write_string("/proc/sys/net/ipv4/tcp_vegas_beta", nvram_safe_get("ne_vbeta"), 0, 0);
367 f_write_string("/proc/sys/net/ipv4/tcp_vegas_gamma", nvram_safe_get("ne_vgamma"), 0, 0);
369 #endif
371 if (!nvram_get_int("qos_enable")) return;
373 if ((f = fopen(qosfn, "w")) == NULL) return;
375 i = nvram_get_int("qos_burst0");
376 if (i > 0) sprintf(burst_root, "burst %dk", i);
377 else burst_root[0] = 0;
378 i = nvram_get_int("qos_burst1");
379 if (i > 0) sprintf(burst_leaf, "burst %dk", i);
380 else burst_leaf[0] = 0;
382 mtu = strtoul(nvram_safe_get("wan_mtu"), NULL, 10);
383 bw = strtoul(nvram_safe_get("qos_obw"), NULL, 10);
385 r2q = 10;
386 if ((bw * 1000) / (8 * r2q) < mtu) {
387 r2q = (bw * 1000) / (8 * mtu);
388 if (r2q < 1) r2q = 1;
389 } else if ((bw * 1000) / (8 * r2q) > 60000) {
390 r2q = (bw * 1000) / (8 * 60000) + 1;
393 fprintf(f,
394 "#!/bin/sh\n"
395 "WAN_DEV=%s\n"
396 "IMQ_DEV=%s\n"
397 "TQA=\"tc qdisc add dev $WAN_DEV\"\n"
398 "TCA=\"tc class add dev $WAN_DEV\"\n"
399 "TFA=\"tc filter add dev $WAN_DEV\"\n"
400 "TQA_IMQ=\"tc qdisc add dev $IMQ_DEV\"\n"
401 "TCA_IMQ=\"tc class add dev $IMQ_DEV\"\n"
402 "TFA_IMQ=\"tc filter add dev $IMQ_DEV\"\n"
403 "Q=\"%s\"\n"
404 "\n"
405 "case \"$1\" in\n"
406 "start)\n"
407 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
408 "\t$TQA root handle 1: htb default %u r2q %u\n"
409 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
410 get_wanface(),
411 qosImqDeviceString,
412 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
413 qosDefaultClassId, r2q,
414 bw, bw, burst_root);
416 inuse = nvram_get_int("qos_inuse");
418 g = buf = strdup(nvram_safe_get("qos_orates"));
419 for (i = 0; i < 10; ++i) {
420 if ((!g) || ((p = strsep(&g, ",")) == NULL)) break;
422 if ((inuse & (1 << i)) == 0) continue;
424 // check if we've got a percentage definition in the form of "rate-ceiling"
425 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1)) continue; // 0=off
427 if (ceil > 0) sprintf(s, "ceil %ukbit ", calc(bw, ceil));
428 else s[0] = 0;
429 x = (i + 1) * 10;
430 fprintf(f,
431 "# egress %d: %u-%u%%\n"
432 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
433 "\t$TQA parent 1:%d handle %d: $Q\n"
434 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
435 i, rate, ceil,
436 // x, calc(bw, rate), s, burst_leaf, (i >= 6) ? 7 : (i + 1), mtu,
437 x, calc(bw, rate), s, burst_leaf, i, mtu, //Toastman
438 x, x,
439 x, i + 1, x);
441 free(buf);
443 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
447 if (nvram_match("qos_ack", "1")) {
448 fprintf(f,
449 "\n"
450 "\t$TFA parent 1: prio 15 protocol ip u32 "
451 "match ip protocol 6 0xff " // TCP
452 "match u8 0x05 0x0f at 0 " // IP header length
453 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
454 "match u8 0x10 0xff at 33 " // ACK only
455 "flowid 1:10\n");
457 if (nvram_match("qos_icmp", "1")) {
458 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
463 if (nvram_get_int("qos_ack")) {
464 fprintf(f,
465 "\n"
466 "\t$TFA parent 1: prio 14 protocol ip u32 "
467 "match ip protocol 6 0xff " // TCP
468 "match u8 0x05 0x0f at 0 " // IP header length
469 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
470 "match u8 0x10 0xff at 33 " // ACK only
471 "flowid 1:10\n");
474 if (nvram_get_int("qos_syn")) {
475 // 10000 = ACK
476 // 00010 = SYN
478 fprintf(f,
479 "\n"
480 "\t$TFA parent 1: prio 15 protocol ip u32 "
481 "match ip protocol 6 0xff " // TCP
482 "match u8 0x05 0x0f at 0 " // IP header length
483 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
484 "match u8 0x02 0xff at 33 " // SYN only
485 "flowid 1:10\n"
486 "\n"
487 "\t$TFA parent 1: prio 16 protocol ip u32 "
488 "match ip protocol 6 0xff " // TCP
489 "match u8 0x05 0x0f at 0 " // IP header length
490 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
491 "match u8 0x12 0xff at 33 " // SYN,ACK
492 "flowid 1:10\n");
495 if (nvram_get_int("qos_fin")) {
496 // 10000 = ACK
497 // 00001 = FIN
499 fprintf(f,
500 "\n"
501 "\t$TFA parent 1: prio 17 protocol ip u32 "
502 "match ip protocol 6 0xff " // TCP
503 "match u8 0x05 0x0f at 0 " // IP header length
504 "match u8 0x11 0xff at 33 " // ACK,FIN
505 "flowid 1:10\n"
506 "\n"
507 "\t$TFA parent 1: prio 18 protocol ip u32 "
508 "match ip protocol 6 0xff " // TCP
509 "match u8 0x05 0x0f at 0 " // IP header length
510 "match u8 0x01 0xff at 33 " // FIN
511 "flowid 1:10\n");
514 if (nvram_get_int("qos_rst")) {
515 // 10000 = ACK
516 // 00100 = RST
517 fprintf(f,
518 "\n"
519 "\t$TFA parent 1: prio 19 protocol ip u32 "
520 "match ip protocol 6 0xff " // TCP
521 "match u8 0x05 0x0f at 0 " // IP header length
522 "match u8 0x14 0xff at 33 " // ACK,RST
523 "flowid 1:10\n"
524 "\n"
525 "\t$TFA parent 1: prio 20 protocol ip u32 "
526 "match ip protocol 6 0xff " // TCP
527 "match u8 0x05 0x0f at 0 " // IP header length
528 "match u8 0x04 0xff at 33 " // RST
529 "flowid 1:10\n");
533 if (nvram_get_int("qos_icmp")) {
534 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
539 10000 = ACK
540 00100 = RST
541 00010 = SYN
542 00001 = FIN
545 if (nvram_get_int("qos_ack")) {
546 fprintf(f,
547 "\n"
548 "\t$TFA parent 1: prio 14 protocol ip u32 "
549 "match ip protocol 6 0xff " // TCP
550 "match u8 0x05 0x0f at 0 " // IP header length
551 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
552 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
553 "match u8 0x10 0xff at 33 " // ACK only
554 "flowid 1:10\n");
557 if (nvram_get_int("qos_syn")) {
558 fprintf(f,
559 "\n"
560 "\t$TFA parent 1: prio 15 protocol ip u32 "
561 "match ip protocol 6 0xff " // TCP
562 "match u8 0x05 0x0f at 0 " // IP header length
563 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
564 "match u8 0x02 0x02 at 33 " // SYN,*
565 "flowid 1:10\n");
568 if (nvram_get_int("qos_fin")) {
569 fprintf(f,
570 "\n"
571 "\t$TFA parent 1: prio 17 protocol ip u32 "
572 "match ip protocol 6 0xff " // TCP
573 "match u8 0x05 0x0f at 0 " // IP header length
574 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
575 "match u8 0x01 0x01 at 33 " // FIN,*
576 "flowid 1:10\n");
579 if (nvram_get_int("qos_rst")) {
580 fprintf(f,
581 "\n"
582 "\t$TFA parent 1: prio 19 protocol ip u32 "
583 "match ip protocol 6 0xff " // TCP
584 "match u8 0x05 0x0f at 0 " // IP header length
585 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
586 "match u8 0x04 0x04 at 33 " // RST,*
587 "flowid 1:10\n");
590 if (nvram_get_int("qos_icmp")) {
591 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
595 ////
596 //// INCOMING TRAFFIC SHAPING
597 ////
599 first = 1;
601 g = buf = strdup(nvram_safe_get("qos_irates"));
603 for (i = 0; i < 10; ++i)
605 if ((!g) || ((p = strsep(&g, ",")) == NULL))
607 break;
610 if ((inuse & (1 << i)) == 0)
612 continue;
615 // check if we've got a percentage definition in the form of "rate-ceiling"
616 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1))
618 continue; // 0=off
621 // class ID
622 unsigned int classid = ((unsigned int)i + 1) * 10;
624 // priority
625 unsigned int priority = (unsigned int)i + 1;
627 // rate in kb/s
628 unsigned int rateInKilobitsPerSecond =
629 calc(incomingBandwidthInKilobitsPerSecond, rate);
631 // ceiling in kb/s
632 unsigned int ceilingInKilobitsPerSecond =
633 calc(incomingBandwidthInKilobitsPerSecond, ceil);
635 // burst rate (2% of the classes' rate) - don't know if we should use this
636 unsigned int burstRateInBitsPerSecond =
637 (rateInKilobitsPerSecond * 1000) / 50;
639 r2q = 10;
640 if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) < mtu)
642 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * mtu);
643 if (r2q < 1) r2q = 1;
645 else if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) > 60000)
647 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * 60000) + 1;
650 if (first)
652 first = 0;
653 fprintf(f,
654 "\n"
655 "\tip link set $IMQ_DEV up\n"
656 "\ttc qdisc del dev $IMQ_DEV 2>/dev/null\n"
657 "\t$TQA_IMQ handle 1: root htb default %u r2q %u\n"
658 "\t$TCA_IMQ parent 1: classid 1:1 htb rate %ukbit ceil %ukbit\n",
659 qosDefaultClassId, r2q,
660 incomingBandwidthInKilobitsPerSecond,
661 incomingBandwidthInKilobitsPerSecond);
664 fprintf(
666 "\n"
667 "\t# class id %u: rate %ukbit ceil %ukbit\n",
668 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond);
670 fprintf(
672 "\t$TCA_IMQ parent 1:1 classid 1:%u htb rate %ukbit ceil %ukbit prio %u quantum %u\n",
673 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond, priority, mtu);
675 fprintf(
677 "\t$TQA_IMQ parent 1:%u handle %u: $Q\n",
678 classid, classid);
680 fprintf(
682 "\t$TFA_IMQ parent 1: prio %u protocol ip handle %u fw flowid 1:%u \n",
683 classid, priority, classid);
686 free(buf);
688 //// write commands which adds rule to forward traffic to IMQ device
689 fputs(
690 "\n"
691 "\t# set up the IMQ device (otherwise this won't work) to limit the incoming data\n"
692 "\tip link set $IMQ_DEV up\n",
695 fputs(
696 "\t;;\n"
697 "stop)\n"
698 "\tip link set $IMQ_DEV down\n"
699 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
700 "\ttc qdisc del dev $IMQ_DEV root 2>/dev/null\n"
701 "\t;;\n"
702 "*)\n"
703 "\techo \"...\"\n"
704 "\techo \"... OUTGOING QDISCS AND CLASSES FOR $WAN_DEV\"\n"
705 "\techo \"...\"\n"
706 "\ttc -s -d qdisc ls dev $WAN_DEV\n"
707 "\techo\n"
708 "\ttc -s -d class ls dev $WAN_DEV\n"
709 "\techo\n"
710 "\techo \"...\"\n"
711 "\techo \"... INCOMING QDISCS AND CLASSES FOR $WAN_DEV (routed through $IMQ_DEV)\"\n"
712 "\techo \"...\"\n"
713 "\ttc -s -d qdisc ls dev $IMQ_DEV\n"
714 "\techo\n"
715 "\ttc -s -d class ls dev $IMQ_DEV\n"
716 "\techo\n"
717 "esac\n",
720 fclose(f);
721 chmod(qosfn, 0700);
722 eval((char *)qosfn, "start");
725 void stop_qos(void)
727 eval((char *)qosfn, "stop");
729 if (!nvram_match("debug_keepfiles", "1")) {
730 unlink(qosfn);
737 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
738 QD | ^
741 INPUT (f) OUTPUT (mnf)