4 Copyright (C) 2006-2009 Jonathan Zarate
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.
28 static const char *qosfn
= "/etc/qos";
29 static const char *qosImqDeviceNumberString
= "0";
30 static const char *qosImqDeviceString
= "ifb0";
38 char *addr_type
, *addr
;
40 char *port_type
, *port
;
59 unsigned long prev_max
;
66 if (!nvram_get_int("qos_enable")) return;
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"));
84 addr_type<addr<proto<port_type<port<ipp2p<L7<bcount<dscp<class_prio<desc
92 ip/mac if addr_type == 1-3
98 if proto == -1,tcp,udp:
104 port # if proto == -1,tcp,udp
110 numeric (0:63) - dscp value
111 afXX, csX, be, ef - dscp class
113 0-10 // was 0-8 - Changed from 8 in pkt_sched.h - Toastman
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
);
122 // fixup < v1.28.XX55
128 // fixup < v0.08 // !!! temp
134 else if (i
!= 11) continue;
136 class_num
= atoi(class_prio
);
137 if ((class_num
< 0) || (class_num
> 9)) continue;
142 if ((inuse
& i
) == 0) {
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)
166 if (ipt_ipp2p(ipp2p
, app
)) v4v6_ok
&= ~IPT_V6
;
167 else ipt_layer7(layer7
, app
);
169 v4v6_ok
&= ~IPT_V6
; // temp: l7 not working either!
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.
179 if (ipt_dscp(dscp
, s
)) {
181 v4v6_ok
&= ~IPT_V6
; // dscp ipv6 match is not present in K2.4
186 // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes
188 min
= strtoul(bcount
, &p
, 10);
190 strcat(saddr
, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes ");
193 sprintf(saddr
+ strlen(saddr
), "%lu:", min
* 1024);
196 max
= strtoul(p
, NULL
, 10);
197 sprintf(saddr
+ strlen(saddr
), "%lu:%lu", min
* 1024, (max
* 1024) - 1);
200 // Create table of connbytes sizes, pass appropriate connections there
201 // and only continue processing them if mark was wiped
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;
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));
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));
222 class_flag
= sizegroup
<< 12;
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
);
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
);
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
);
255 if (proto_num
!= 6) {
256 ip46t_flagged_write(v4v6_ok
, "-A %s -p %s %s %s %s", chain
, "udp", sport
, saddr
, end
);
258 ip46t_flagged_write(v4v6_ok
, "-A %s -p %s %s %s -j RETURN\n", chain
, "udp", sport
, saddr
);
261 if (proto_num
!= 17) {
262 ip46t_flagged_write(v4v6_ok
, "-A %s -p %s %s %s %s", chain
, "tcp", sport
, saddr
, end
);
264 ip46t_flagged_write(v4v6_ok
, "-A %s -p %s %s %s -j RETURN\n", chain
, "tcp", sport
, saddr
);
269 ip46t_flagged_write(v4v6_ok
, "-A %s -p %d %s %s", chain
, proto_num
, saddr
, end
);
271 ip46t_flagged_write(v4v6_ok
, "-A %s -p %d %s -j RETURN\n", chain
, proto_num
, saddr
);
275 else { // any protocol
276 ip46t_flagged_write(v4v6_ok
, "-A %s %s %s", chain
, saddr
, end
);
278 ip46t_flagged_write(v4v6_ok
, "-A %s %s -j RETURN\n", chain
, saddr
);
285 qface
= wanfaces
.iface
[0].name
;
287 i
= nvram_get_int("qos_default");
288 if ((i
< 0) || (i
> 9)) i
= 3; // "low"
290 class_num
|= 0xFF00000; // use rule_num=255 for default
291 ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num
);
293 ip46t_write("-A QOSO -j RETURN\n");
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
);
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
);
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;
329 // check if we've got a percentage definition in the form of "rate-ceiling"
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
);
335 ipt_write("-A PREROUTING -i %s -j RETURN\n", qface
);
339 ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face
);
341 ip6t_write("-A PREROUTING -i %s -j RETURN\n", wan6face
);
351 static unsigned calc(unsigned bw
, unsigned pct
)
353 unsigned n
= ((unsigned long)bw
* pct
) / 100;
354 return (n
< 2) ? 2 : n
;
360 char *buf
, *g
, *p
, *qos
;
364 unsigned int incomingBandwidthInKilobitsPerSecond
;
367 unsigned int qosDefaultClassId
;
368 unsigned int overhead
;
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);
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");
405 qos
= "pfifo limit 256";
411 qos
= "sfq perturb 10";
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"
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",
434 qosDefaultClassId
, r2q
,
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"
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",
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
));
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",
483 x
, calc(bw
, rate
), s
, burst_leaf
, i
+1, mtu
,
488 "\t$TFA parent 1: prio %d protocol ipv6 handle %d fw flowid 1:%d\n",
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",
498 x
, calc(bw
, rate
), s
, burst_leaf
, i
+1, mtu
, overhead
,
503 "\t$TFA parent 1: prio %d protocol ipv6 handle %d fw flowid 1:%d\n",
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")) {
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
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")) {
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
541 if (nvram_get_int("qos_syn")) {
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
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
562 if (nvram_get_int("qos_fin")) {
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
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
581 if (nvram_get_int("qos_rst")) {
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
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
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);
612 if (nvram_get_int("qos_ack")) {
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
624 if (nvram_get_int("qos_syn")) {
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,*
635 if (nvram_get_int("qos_fin")) {
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,*
646 if (nvram_get_int("qos_rst")) {
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,*
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
);
663 //// INCOMING TRAFFIC SHAPING
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
))
678 if ((inuse
& (1 << i
)) == 0)
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))
690 unsigned int classid
= ((unsigned int)i
+ 1) * 10;
693 unsigned int priority
= (unsigned int)i
+ 1; //prios 1-10 - Toastman
696 unsigned int rateInKilobitsPerSecond
=
697 calc(incomingBandwidthInKilobitsPerSecond
, rate
);
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;
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;
724 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
725 "\t$TQA handle ffff: ingress\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
);
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
);
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");
756 "\t# class id %u: rate %ukbit ceil %ukbit\n",
757 classid
, rateInKilobitsPerSecond
, ceilingInKilobitsPerSecond
);
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
);
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
);
773 "\t$TQA_IMQ parent 1:%u handle %u: $Q\n",
778 "\t$TFA_IMQ parent 1: prio %u protocol ip handle %u fw flowid 1:%u \n",
779 classid
, priority
, classid
);
784 "\t$TFA_IMQ parent 1: prio %u protocol ipv6 handle %u fw flowid 1:%u \n",
785 classid
+ 100, priority
, classid
);
791 //// write commands which adds rule to forward traffic to IMQ device
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",
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"
808 "\techo \"... OUTGOING QDISCS AND CLASSES FOR $WAN_DEV\"\n"
810 "\ttc -s -d qdisc ls dev $WAN_DEV\n"
812 "\ttc -s -d class ls dev $WAN_DEV\n"
815 "\techo \"... INCOMING QDISCS AND CLASSES FOR $WAN_DEV (routed through $IMQ_DEV)\"\n"
817 "\ttc -s -d qdisc ls dev $IMQ_DEV\n"
819 "\ttc -s -d class ls dev $IMQ_DEV\n"
822 (nvram_get_int("qos_udp") == 1) ? "protocol 6 0xff" : "dst 0.0.0.0/0");
826 eval((char *)qosfn
, "start");
831 eval((char *)qosfn
, "stop");
833 if (!nvram_match("debug_keepfiles", "1")) {
841 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
845 INPUT (f) OUTPUT (mnf)