4 Copyright (C) 2006-2009 Jonathan Zarate
19 char *addr_type
, *addr
;
21 char *port_type
, *port
;
39 unsigned long prev_max
;
46 if (!nvram_get_int("qos_enable")) return;
57 "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n"
58 "-A QOSO -m connmark ! --mark 0/0x0f00 -j RETURN\n");
60 g
= buf
= strdup(nvram_safe_get("qos_orules"));
65 addr_type<addr<proto<port_type<port<ipp2p<L7<bcount<dscp<class_prio<desc
73 ip/mac if addr_type == 1-3
79 if proto == -1,tcp,udp:
85 port # if proto == -1,tcp,udp
91 numeric (0:63) - dscp value
92 afXX, csX, be, ef - dscp class
99 if ((p
= strsep(&g
, ">")) == NULL
) break;
100 i
= vstrsep(p
, "<", &addr_type
, &addr
, &proto
, &port_type
, &port
, &ipp2p
, &layer7
, &bcount
, &dscp
, &class_prio
, &p
);
103 // fixup < v1.28.XX55
108 // fixup < v0.08 // !!! temp
113 else if (i
!= 11) continue;
115 class_num
= atoi(class_prio
);
116 if ((class_num
< 0) || (class_num
> 9)) continue;
121 if ((inuse
& i
) == 0) {
129 if ((*addr_type
== '1') || (*addr_type
== '2')) { // match ip
130 ipt_addr(saddr
, sizeof(saddr
), addr
, (*addr_type
== '1') ? "dst" : "src");
132 // if it appears to be ipv4 dotted decimal or IPv4 range,
133 // don't apply it to ip6tables; otherwise assume it's ok for both.
134 if (sscanf(addr
, "%[0-9.]-%[0-9.]", s
, s
) == 2 || sscanf(addr
, "%[0-9.]", s
) == 1)
138 else if (*addr_type
== '3') { // match mac
139 sprintf(saddr
, "-m mac --mac-source %s", addr
); // (-m mac modified, returns !match in OUTPUT)
146 if (ipt_ipp2p(ipp2p
, app
)) ipv6_ok
= 0;
147 else ipt_layer7(layer7
, app
);
149 ipv6_ok
= 0; // temp: l7 not working either!
151 // IPP2P and L7 rules may need more than one packet before matching
152 // so port-based rules that come after them in the list can't be sticky
153 // or else these rules might never match.
159 if (ipt_dscp(dscp
, s
)) {
161 ipv6_ok
= 0; // dscp ipv6 match is not present in K2.4
166 // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes
168 min
= strtoul(bcount
, &p
, 10);
170 strcat(end
, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes ");
173 sprintf(end
+ strlen(end
), "%lu:", min
* 1024);
176 max
= strtoul(p
, NULL
, 10);
177 sprintf(end
+ strlen(end
), "%lu:%lu", min
* 1024, (max
* 1024) - 1);
180 // Create table of connbytes sizes, pass appropriate connections there
181 // and only continue processing them if mark was wiped
182 // FIX: if the current rule isn't ipv6_ok ?
185 "-I QOSO 3 -m connmark ! --mark 0/0xff000 -j QOSSIZE\n"
186 "-I QOSO 4 -m connmark ! --mark 0/0xff000 -j RETURN\n");
188 if (max
!= prev_max
&& sizegroup
<255) {
189 class_flag
= ++sizegroup
<< 12;
191 ip46t_flagged_write( ipv6_ok
,
192 "-A QOSSIZE -m connmark --mark 0x%x/0xff000"
193 " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j CONNMARK --set-return 0x00000/0xFF\n",
194 (sizegroup
<< 12), (max
* 1024));
197 class_flag
= sizegroup
<< 12;
209 class_num
|= class_flag
;
210 class_num
|= rule_num
<< 20;
211 sprintf(end
+ strlen(end
), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num
);
214 proto_num
= atoi(proto
);
215 if (proto_num
> -2) {
216 if ((proto_num
== 6) || (proto_num
== 17) || (proto_num
== -1)) {
217 if (*port_type
!= 'a') {
218 if ((*port_type
== 'x') || (strchr(port
, ','))) {
219 // dst-or-src port matches, and anything with multiple lists "," use multiport
220 sprintf(sport
, "-m multiport --%sports %s", (*port_type
== 's') ? "s" : ((*port_type
== 'd') ? "d" : ""), port
);
223 // single or simple x:y range, use built-in tcp/udp match
224 sprintf(sport
, "--%sport %s", (*port_type
== 's') ? "s" : ((*port_type
== 'd') ? "d" : ""), port
);
230 if (proto_num
!= 6) ip46t_flagged_write(ipv6_ok
, "-A %s -p %s %s %s %s", chain
, "udp", sport
, saddr
, end
);
231 if (proto_num
!= 17) ip46t_flagged_write(ipv6_ok
, "-A %s -p %s %s %s %s", chain
, "tcp", sport
, saddr
, end
);
234 ip46t_flagged_write(ipv6_ok
, "-A %s -p %d %s %s", chain
, proto_num
, saddr
, end
);
237 else { // any protocol
238 ip46t_flagged_write(ipv6_ok
, "-A %s %s %s", chain
, saddr
, end
);
244 qface
= wanfaces
.iface
[0].name
;
246 i
= nvram_get_int("qos_default");
247 if ((i
< 0) || (i
> 9)) i
= 3; // "low"
249 class_num
|= 0xFF00000; // use rule_num=255 for default
250 ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num
);
253 "-A FORWARD -o %s -j QOSO\n"
254 "-A OUTPUT -o %s -j QOSO\n",
259 "-A FORWARD -o %s -j QOSO\n"
260 "-A OUTPUT -o %s -j QOSO\n",
264 inuse
|= (1 << i
) | 1; // default and highest are always built
265 sprintf(s
, "%d", inuse
);
266 nvram_set("qos_inuse", s
);
269 g
= buf
= strdup(nvram_safe_get("qos_irates"));
270 for (i
= 0; i
< 10; ++i
) {
271 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) continue;
272 if ((inuse
& (1 << i
)) == 0) continue;
274 ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", qface
);
276 ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face
);
286 static const char *qosfn
= "/etc/qos";
288 static unsigned calc(unsigned bw
, unsigned pct
)
290 unsigned n
= ((unsigned long)bw
* pct
) / 100;
291 return (n
< 2) ? 2 : n
;
313 x
= nvram_get_int("ne_vegas");
316 char alpha
[10], beta
[10], gamma
[10];
317 sprintf(alpha
, "alpha=%d", nvram_get_int("ne_valpha"));
318 sprintf(beta
, "beta=%d", nvram_get_int("ne_vbeta"));
319 sprintf(gamma
, "gamma=%d", nvram_get_int("ne_vgamma"));
320 modprobe("tcp_vegas", alpha
, beta
, gamma
);
321 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "vegas", 0, 0);
324 modprobe_r("tcp_vegas");
325 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "", FW_NEWLINE
, 0);
328 f_write_string("/proc/sys/net/ipv4/tcp_vegas_cong_avoid", x
? "1" : "0", 0, 0);
330 f_write_string("/proc/sys/net/ipv4/tcp_vegas_alpha", nvram_safe_get("ne_valpha"), 0, 0);
331 f_write_string("/proc/sys/net/ipv4/tcp_vegas_beta", nvram_safe_get("ne_vbeta"), 0, 0);
332 f_write_string("/proc/sys/net/ipv4/tcp_vegas_gamma", nvram_safe_get("ne_vgamma"), 0, 0);
336 if (!nvram_get_int("qos_enable")) return;
338 if ((f
= fopen(qosfn
, "w")) == NULL
) return;
340 i
= nvram_get_int("qos_burst0");
341 if (i
> 0) sprintf(burst_root
, "burst %dk", i
);
342 else burst_root
[0] = 0;
343 i
= nvram_get_int("qos_burst1");
344 if (i
> 0) sprintf(burst_leaf
, "burst %dk", i
);
345 else burst_leaf
[0] = 0;
347 mtu
= strtoul(nvram_safe_get("wan_mtu"), NULL
, 10);
348 bw
= strtoul(nvram_safe_get("qos_obw"), NULL
, 10);
351 if ((bw
* 1000) / (8 * r2q
) < mtu
) {
352 r2q
= (bw
* 1000) / (8 * mtu
);
353 if (r2q
< 1) r2q
= 1;
354 } else if ((bw
* 1000) / (8 * r2q
) > 60000) {
355 r2q
= (bw
* 1000) / (8 * 60000) + 1;
361 "TQA=\"tc qdisc add dev $I\"\n"
362 "TCA=\"tc class add dev $I\"\n"
363 "TFA=\"tc filter add dev $I\"\n"
368 "\ttc qdisc del dev $I root 2>/dev/null\n"
369 "\t$TQA root handle 1: htb default %u r2q %u\n"
370 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
372 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
373 (nvram_get_int("qos_default") + 1) * 10, r2q
,
376 inuse
= nvram_get_int("qos_inuse");
378 g
= buf
= strdup(nvram_safe_get("qos_orates"));
379 for (i
= 0; i
< 10; ++i
) {
380 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) break;
382 if ((inuse
& (1 << i
)) == 0) continue;
384 if ((sscanf(p
, "%u-%u", &rate
, &ceil
) != 2) || (rate
< 1)) continue; // 0=off
386 if (ceil
> 0) sprintf(s
, "ceil %ukbit ", calc(bw
, ceil
));
390 "# egress %d: %u-%u%%\n"
391 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
392 "\t$TQA parent 1:%d handle %d: $Q\n"
393 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
395 x
, calc(bw
, rate
), s
, burst_leaf
, (i
>= 6) ? 7 : (i
+ 1), mtu
,
401 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
405 if (nvram_match("qos_ack", "1")) {
408 "\t$TFA parent 1: prio 15 protocol ip u32 "
409 "match ip protocol 6 0xff " // TCP
410 "match u8 0x05 0x0f at 0 " // IP header length
411 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
412 "match u8 0x10 0xff at 33 " // ACK only
415 if (nvram_match("qos_icmp", "1")) {
416 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
421 if (nvram_get_int("qos_ack")) {
424 "\t$TFA parent 1: prio 14 protocol ip u32 "
425 "match ip protocol 6 0xff " // TCP
426 "match u8 0x05 0x0f at 0 " // IP header length
427 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
428 "match u8 0x10 0xff at 33 " // ACK only
432 if (nvram_get_int("qos_syn")) {
438 "\t$TFA parent 1: prio 15 protocol ip u32 "
439 "match ip protocol 6 0xff " // TCP
440 "match u8 0x05 0x0f at 0 " // IP header length
441 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
442 "match u8 0x02 0xff at 33 " // SYN only
445 "\t$TFA parent 1: prio 16 protocol ip u32 "
446 "match ip protocol 6 0xff " // TCP
447 "match u8 0x05 0x0f at 0 " // IP header length
448 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
449 "match u8 0x12 0xff at 33 " // SYN,ACK
453 if (nvram_get_int("qos_fin")) {
459 "\t$TFA parent 1: prio 17 protocol ip u32 "
460 "match ip protocol 6 0xff " // TCP
461 "match u8 0x05 0x0f at 0 " // IP header length
462 "match u8 0x11 0xff at 33 " // ACK,FIN
465 "\t$TFA parent 1: prio 18 protocol ip u32 "
466 "match ip protocol 6 0xff " // TCP
467 "match u8 0x05 0x0f at 0 " // IP header length
468 "match u8 0x01 0xff at 33 " // FIN
472 if (nvram_get_int("qos_rst")) {
477 "\t$TFA parent 1: prio 19 protocol ip u32 "
478 "match ip protocol 6 0xff " // TCP
479 "match u8 0x05 0x0f at 0 " // IP header length
480 "match u8 0x14 0xff at 33 " // ACK,RST
483 "\t$TFA parent 1: prio 20 protocol ip u32 "
484 "match ip protocol 6 0xff " // TCP
485 "match u8 0x05 0x0f at 0 " // IP header length
486 "match u8 0x04 0xff at 33 " // RST
491 if (nvram_get_int("qos_icmp")) {
492 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
503 if (nvram_get_int("qos_ack")) {
506 "\t$TFA parent 1: prio 14 protocol ip u32 "
507 "match ip protocol 6 0xff " // TCP
508 "match u8 0x05 0x0f at 0 " // IP header length
509 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
510 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
511 "match u8 0x10 0xff at 33 " // ACK only
515 if (nvram_get_int("qos_syn")) {
518 "\t$TFA parent 1: prio 15 protocol ip u32 "
519 "match ip protocol 6 0xff " // TCP
520 "match u8 0x05 0x0f at 0 " // IP header length
521 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
522 "match u8 0x02 0x02 at 33 " // SYN,*
526 if (nvram_get_int("qos_fin")) {
529 "\t$TFA parent 1: prio 17 protocol ip u32 "
530 "match ip protocol 6 0xff " // TCP
531 "match u8 0x05 0x0f at 0 " // IP header length
532 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
533 "match u8 0x01 0x01 at 33 " // FIN,*
537 if (nvram_get_int("qos_rst")) {
540 "\t$TFA parent 1: prio 19 protocol ip u32 "
541 "match ip protocol 6 0xff " // TCP
542 "match u8 0x05 0x0f at 0 " // IP header length
543 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
544 "match u8 0x04 0x04 at 33 " // RST,*
549 if (nvram_get_int("qos_icmp")) {
550 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f
);
556 bw
= strtoul(nvram_safe_get("qos_ibw"), NULL
, 10);
557 g
= buf
= strdup(nvram_safe_get("qos_irates"));
558 for (i
= 0; i
< 10; ++i
) {
559 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) break;
561 if ((inuse
& (1 << i
)) == 0) continue;
563 if ((rate
= atoi(p
)) < 1) continue; // 0 = off
569 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
570 "\t$TQA handle ffff: ingress\n");
574 unsigned int u
= calc(bw
, rate
);
577 unsigned int v
= u
/ 25;
579 // const unsigned int v = 200;
583 "# ingress %d: %u%%\n"
584 "\t$TFA parent ffff: prio %d protocol ip handle %d fw police rate %ukbit burst %ukbit drop flowid ffff:%d\n",
593 "\ttc qdisc del dev $I root 2>/dev/null\n"
594 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
597 "\ttc -s -d qdisc ls dev $I\n"
599 "\ttc -s -d class ls dev $I\n"
605 eval((char *)qosfn
, "start");
610 eval((char *)qosfn
, "stop");
612 if (!nvram_match("debug_keepfiles", "1")) {
620 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
624 INPUT (f) OUTPUT (mnf)