Revert "Added extrarules to iptables to get UDP request."
[tomato.git] / release / src / router / rc / qos.c
blob912fb536f37c04022de5da298fedbdf993a9dada
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 unsigned int overhead;
353 FILE *f;
354 int x;
355 int inuse;
356 char s[256];
357 int first;
358 char burst_root[32];
359 char burst_leaf[32];
361 qosDefaultClassId = (nvram_get_int("qos_default") + 1) * 10;
362 incomingBandwidthInKilobitsPerSecond = strtoul(nvram_safe_get("qos_ibw"), NULL, 10);
364 // move me?
365 x = nvram_get_int("ne_vegas");
366 #ifdef LINUX26
367 if (x) {
368 char alpha[10], beta[10], gamma[10];
369 sprintf(alpha, "alpha=%d", nvram_get_int("ne_valpha"));
370 sprintf(beta, "beta=%d", nvram_get_int("ne_vbeta"));
371 sprintf(gamma, "gamma=%d", nvram_get_int("ne_vgamma"));
372 modprobe("tcp_vegas", alpha, beta, gamma);
373 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "vegas", 0, 0);
375 else {
376 modprobe_r("tcp_vegas");
377 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "", FW_NEWLINE, 0);
379 #else
380 f_write_string("/proc/sys/net/ipv4/tcp_vegas_cong_avoid", x ? "1" : "0", 0, 0);
381 if (x) {
382 f_write_string("/proc/sys/net/ipv4/tcp_vegas_alpha", nvram_safe_get("ne_valpha"), 0, 0);
383 f_write_string("/proc/sys/net/ipv4/tcp_vegas_beta", nvram_safe_get("ne_vbeta"), 0, 0);
384 f_write_string("/proc/sys/net/ipv4/tcp_vegas_gamma", nvram_safe_get("ne_vgamma"), 0, 0);
386 #endif
388 if (!nvram_get_int("qos_enable")) return;
390 if ((f = fopen(qosfn, "w")) == NULL) return;
392 i = nvram_get_int("qos_burst0");
393 if (i > 0) sprintf(burst_root, "burst %dk", i);
394 else burst_root[0] = 0;
395 i = nvram_get_int("qos_burst1");
396 if (i > 0) sprintf(burst_leaf, "burst %dk", i);
397 else burst_leaf[0] = 0;
399 mtu = strtoul(nvram_safe_get("wan_mtu"), NULL, 10);
400 bw = strtoul(nvram_safe_get("qos_obw"), NULL, 10);
401 overhead = strtoul(nvram_safe_get("atm_overhead"), NULL, 10);
402 r2q = 10;
404 if ((bw * 1000) / (8 * r2q) < mtu) {
405 r2q = (bw * 1000) / (8 * mtu);
406 if (r2q < 1) r2q = 1;
407 } else if ((bw * 1000) / (8 * r2q) > 60000) {
408 r2q = (bw * 1000) / (8 * 60000) + 1;
411 if (overhead == 0) {
412 fprintf(f,
413 "#!/bin/sh\n"
414 "WAN_DEV=%s\n"
415 "IMQ_DEV=%s\n"
416 "TQA=\"tc qdisc add dev $WAN_DEV\"\n"
417 "TCA=\"tc class add dev $WAN_DEV\"\n"
418 "TFA=\"tc filter add dev $WAN_DEV\"\n"
419 "TQA_IMQ=\"tc qdisc add dev $IMQ_DEV\"\n"
420 "TCA_IMQ=\"tc class add dev $IMQ_DEV\"\n"
421 "TFA_IMQ=\"tc filter add dev $IMQ_DEV\"\n"
422 "Q=\"%s\"\n"
423 "\n"
424 "case \"$1\" in\n"
425 "start)\n"
426 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
427 "\t$TQA root handle 1: htb default %u r2q %u\n"
428 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
429 get_wanface(),
430 qosImqDeviceString,
431 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
432 qosDefaultClassId, r2q,
433 bw, bw, burst_root);
434 } else {
435 fprintf(f,
436 "#!/bin/sh\n"
437 "WAN_DEV=%s\n"
438 "IMQ_DEV=%s\n"
439 "TQA=\"tc qdisc add dev $WAN_DEV\"\n"
440 "TCA=\"tc class add dev $WAN_DEV\"\n"
441 "TFA=\"tc filter add dev $WAN_DEV\"\n"
442 "TQA_IMQ=\"tc qdisc add dev $IMQ_DEV\"\n"
443 "TCA_IMQ=\"tc class add dev $IMQ_DEV\"\n"
444 "TFA_IMQ=\"tc filter add dev $IMQ_DEV\"\n"
445 "Q=\"%s\"\n"
446 "\n"
447 "case \"$1\" in\n"
448 "start)\n"
449 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
450 "\t$TQA root handle 1: htb default %u r2q %u\n"
451 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s overhead %u atm\n",
452 get_wanface(),
453 qosImqDeviceString,
454 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
455 qosDefaultClassId, r2q,
456 bw, bw, burst_root, overhead);
459 inuse = nvram_get_int("qos_inuse");
461 g = buf = strdup(nvram_safe_get("qos_orates"));
462 for (i = 0; i < 10; ++i) {
463 if ((!g) || ((p = strsep(&g, ",")) == NULL)) break;
465 if ((inuse & (1 << i)) == 0) continue;
467 // check if we've got a percentage definition in the form of "rate-ceiling"
468 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1)) continue; // 0=off
470 if (ceil > 0) sprintf(s, "ceil %ukbit ", calc(bw, ceil));
471 else s[0] = 0;
472 x = (i + 1) * 10;
474 if (overhead == 0) {
475 fprintf(f,
476 "# egress %d: %u-%u%%\n"
477 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
478 "\t$TQA parent 1:%d handle %d: $Q\n"
479 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
480 i, rate, ceil,
481 x, calc(bw, rate), s, burst_leaf, i+1, mtu,
482 x, x,
483 x, i + 1, x);
484 } else {
485 fprintf(f,
486 "# egress %d: %u-%u%%\n"
487 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u overhead %u atm\n"
488 "\t$TQA parent 1:%d handle %d: $Q\n"
489 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
490 i, rate, ceil,
491 x, calc(bw, rate), s, burst_leaf, i+1, mtu, overhead,
492 x, x,
493 x, i + 1, x);
496 free(buf);
498 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
502 if (nvram_match("qos_ack", "1")) {
503 fprintf(f,
504 "\n"
505 "\t$TFA parent 1: prio 15 protocol ip u32 "
506 "match ip protocol 6 0xff " // TCP
507 "match u8 0x05 0x0f at 0 " // IP header length
508 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
509 "match u8 0x10 0xff at 33 " // ACK only
510 "flowid 1:10\n");
512 if (nvram_match("qos_icmp", "1")) {
513 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
518 if (nvram_get_int("qos_ack")) {
519 fprintf(f,
520 "\n"
521 "\t$TFA parent 1: prio 14 protocol ip u32 "
522 "match ip protocol 6 0xff " // TCP
523 "match u8 0x05 0x0f at 0 " // IP header length
524 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
525 "match u8 0x10 0xff at 33 " // ACK only
526 "flowid 1:10\n");
529 if (nvram_get_int("qos_syn")) {
530 // 10000 = ACK
531 // 00010 = SYN
533 fprintf(f,
534 "\n"
535 "\t$TFA parent 1: prio 15 protocol ip u32 "
536 "match ip protocol 6 0xff " // TCP
537 "match u8 0x05 0x0f at 0 " // IP header length
538 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
539 "match u8 0x02 0xff at 33 " // SYN only
540 "flowid 1:10\n"
541 "\n"
542 "\t$TFA parent 1: prio 16 protocol ip u32 "
543 "match ip protocol 6 0xff " // TCP
544 "match u8 0x05 0x0f at 0 " // IP header length
545 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
546 "match u8 0x12 0xff at 33 " // SYN,ACK
547 "flowid 1:10\n");
550 if (nvram_get_int("qos_fin")) {
551 // 10000 = ACK
552 // 00001 = FIN
554 fprintf(f,
555 "\n"
556 "\t$TFA parent 1: prio 17 protocol ip u32 "
557 "match ip protocol 6 0xff " // TCP
558 "match u8 0x05 0x0f at 0 " // IP header length
559 "match u8 0x11 0xff at 33 " // ACK,FIN
560 "flowid 1:10\n"
561 "\n"
562 "\t$TFA parent 1: prio 18 protocol ip u32 "
563 "match ip protocol 6 0xff " // TCP
564 "match u8 0x05 0x0f at 0 " // IP header length
565 "match u8 0x01 0xff at 33 " // FIN
566 "flowid 1:10\n");
569 if (nvram_get_int("qos_rst")) {
570 // 10000 = ACK
571 // 00100 = RST
572 fprintf(f,
573 "\n"
574 "\t$TFA parent 1: prio 19 protocol ip u32 "
575 "match ip protocol 6 0xff " // TCP
576 "match u8 0x05 0x0f at 0 " // IP header length
577 "match u8 0x14 0xff at 33 " // ACK,RST
578 "flowid 1:10\n"
579 "\n"
580 "\t$TFA parent 1: prio 20 protocol ip u32 "
581 "match ip protocol 6 0xff " // TCP
582 "match u8 0x05 0x0f at 0 " // IP header length
583 "match u8 0x04 0xff at 33 " // RST
584 "flowid 1:10\n");
588 if (nvram_get_int("qos_icmp")) {
589 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
594 10000 = ACK
595 00100 = RST
596 00010 = SYN
597 00001 = FIN
600 if (nvram_get_int("qos_ack")) {
601 fprintf(f,
602 "\n"
603 "\t$TFA parent 1: prio 14 protocol ip u32 "
604 "match ip protocol 6 0xff " // TCP
605 "match u8 0x05 0x0f at 0 " // IP header length
606 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
607 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
608 "match u8 0x10 0xff at 33 " // ACK only
609 "flowid 1:10\n");
612 if (nvram_get_int("qos_syn")) {
613 fprintf(f,
614 "\n"
615 "\t$TFA parent 1: prio 15 protocol ip u32 "
616 "match ip protocol 6 0xff " // TCP
617 "match u8 0x05 0x0f at 0 " // IP header length
618 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
619 "match u8 0x02 0x02 at 33 " // SYN,*
620 "flowid 1:10\n");
623 if (nvram_get_int("qos_fin")) {
624 fprintf(f,
625 "\n"
626 "\t$TFA parent 1: prio 17 protocol ip u32 "
627 "match ip protocol 6 0xff " // TCP
628 "match u8 0x05 0x0f at 0 " // IP header length
629 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
630 "match u8 0x01 0x01 at 33 " // FIN,*
631 "flowid 1:10\n");
634 if (nvram_get_int("qos_rst")) {
635 fprintf(f,
636 "\n"
637 "\t$TFA parent 1: prio 19 protocol ip u32 "
638 "match ip protocol 6 0xff " // TCP
639 "match u8 0x05 0x0f at 0 " // IP header length
640 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
641 "match u8 0x04 0x04 at 33 " // RST,*
642 "flowid 1:10\n");
645 if (nvram_get_int("qos_icmp")) {
646 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
650 ////
651 //// INCOMING TRAFFIC SHAPING
652 ////
654 first = 1;
655 overhead = strtoul(nvram_safe_get("atm_overhead"), NULL, 10);
657 g = buf = strdup(nvram_safe_get("qos_irates"));
659 for (i = 0; i < 10; ++i)
661 if ((!g) || ((p = strsep(&g, ",")) == NULL))
663 break;
666 if ((inuse & (1 << i)) == 0)
668 continue;
671 // check if we've got a percentage definition in the form of "rate-ceiling"
672 if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1))
674 continue; // 0=off
677 // class ID
678 unsigned int classid = ((unsigned int)i + 1) * 10;
680 // priority
681 unsigned int priority = (unsigned int)i + 1; //prios 1-10 - Toastman
683 // rate in kb/s
684 unsigned int rateInKilobitsPerSecond =
685 calc(incomingBandwidthInKilobitsPerSecond, rate);
687 // ceiling in kb/s
688 unsigned int ceilingInKilobitsPerSecond =
689 calc(incomingBandwidthInKilobitsPerSecond, ceil);
691 // burst rate (2% of the classes' rate) - don't know if we should use this
692 //Commented out KDB 20130531 - produces compiler warning about being unused!
693 // unsigned int burstRateInBitsPerSecond =
694 // (rateInKilobitsPerSecond * 1000) / 50;
696 r2q = 10;
697 if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) < mtu)
699 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * mtu);
700 if (r2q < 1) r2q = 1;
702 else if ((incomingBandwidthInKilobitsPerSecond * 1000) / (8 * r2q) > 60000)
704 r2q = (incomingBandwidthInKilobitsPerSecond * 1000) / (8 * 60000) + 1;
707 if (first)
709 first = 0;
710 if (overhead == 0) {
711 fprintf(f,
712 "\n"
713 "\tip link set $IMQ_DEV up\n"
714 "\ttc qdisc del dev $IMQ_DEV 2>/dev/null\n"
715 "\t$TQA_IMQ handle 1: root htb default %u r2q %u\n"
716 "\t$TCA_IMQ parent 1: classid 1:1 htb rate %ukbit ceil %ukbit\n",
717 qosDefaultClassId, r2q,
718 incomingBandwidthInKilobitsPerSecond,
719 incomingBandwidthInKilobitsPerSecond);
720 } else {
721 fprintf(f,
722 "\n"
723 "\tip link set $IMQ_DEV up\n"
724 "\ttc qdisc del dev $IMQ_DEV 2>/dev/null\n"
725 "\t$TQA_IMQ handle 1: root htb default %u r2q %u\n"
726 "\t$TCA_IMQ parent 1: classid 1:1 htb rate %ukbit ceil %ukbit overhead %u atm\n",
727 qosDefaultClassId, r2q,
728 incomingBandwidthInKilobitsPerSecond,
729 incomingBandwidthInKilobitsPerSecond, overhead);
733 fprintf(
735 "\n"
736 "\t# class id %u: rate %ukbit ceil %ukbit\n",
737 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond);
739 if (overhead == 0) {
740 fprintf(
742 "\t$TCA_IMQ parent 1:1 classid 1:%u htb rate %ukbit ceil %ukbit prio %u quantum %u\n",
743 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond, priority, mtu);
744 } else {
745 fprintf(
747 "\t$TCA_IMQ parent 1:1 classid 1:%u htb rate %ukbit ceil %ukbit prio %u quantum %u overhead %u atm\n",
748 classid, rateInKilobitsPerSecond, ceilingInKilobitsPerSecond, priority, mtu, overhead);
751 fprintf(
753 "\t$TQA_IMQ parent 1:%u handle %u: $Q\n",
754 classid, classid);
756 fprintf(
758 "\t$TFA_IMQ parent 1: prio %u protocol ip handle %u fw flowid 1:%u \n",
759 classid, priority, classid);
762 free(buf);
764 //// write commands which adds rule to forward traffic to IMQ device
765 fputs(
766 "\n"
767 "\t# set up the IMQ device (otherwise this won't work) to limit the incoming data\n"
768 "\tip link set $IMQ_DEV up\n",
771 fputs(
772 "\t;;\n"
773 "stop)\n"
774 "\tip link set $IMQ_DEV down\n"
775 "\ttc qdisc del dev $WAN_DEV root 2>/dev/null\n"
776 "\ttc qdisc del dev $IMQ_DEV root 2>/dev/null\n"
777 "\t;;\n"
778 "*)\n"
779 "\techo \"...\"\n"
780 "\techo \"... OUTGOING QDISCS AND CLASSES FOR $WAN_DEV\"\n"
781 "\techo \"...\"\n"
782 "\ttc -s -d qdisc ls dev $WAN_DEV\n"
783 "\techo\n"
784 "\ttc -s -d class ls dev $WAN_DEV\n"
785 "\techo\n"
786 "\techo \"...\"\n"
787 "\techo \"... INCOMING QDISCS AND CLASSES FOR $WAN_DEV (routed through $IMQ_DEV)\"\n"
788 "\techo \"...\"\n"
789 "\ttc -s -d qdisc ls dev $IMQ_DEV\n"
790 "\techo\n"
791 "\ttc -s -d class ls dev $IMQ_DEV\n"
792 "\techo\n"
793 "esac\n",
796 fclose(f);
797 chmod(qosfn, 0700);
798 eval((char *)qosfn, "start");
801 void stop_qos(void)
803 eval((char *)qosfn, "stop");
805 if (!nvram_match("debug_keepfiles", "1")) {
806 unlink(qosfn);
813 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
814 QD | ^
817 INPUT (f) OUTPUT (mnf)