4 Copyright (C) 2006-2009 Jonathan Zarate
19 char *addr_type
, *addr
;
21 char *port_type
, *port
;
40 unsigned long prev_max
;
47 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
, &desc
);
103 // fixup < v1.28.XX55
109 // fixup < v0.08 // !!! temp
115 else if (i
!= 11) continue;
117 class_num
= atoi(class_prio
);
118 if ((class_num
< 0) || (class_num
> 9)) continue;
123 if ((inuse
& i
) == 0) {
135 if (ipt_ipp2p(ipp2p
, app
)) v4v6_ok
&= ~IPT_V6
;
136 else ipt_layer7(layer7
, app
);
138 v4v6_ok
&= ~IPT_V6
; // temp: l7 not working either!
140 // IPP2P and L7 rules may need more than one packet before matching
141 // so port-based rules that come after them in the list can't be sticky
142 // or else these rules might never match.
148 if (ipt_dscp(dscp
, s
)) {
150 v4v6_ok
&= ~IPT_V6
; // dscp ipv6 match is not present in K2.4
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)
169 // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes
171 min
= strtoul(bcount
, &p
, 10);
173 strcat(end
, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes ");
176 sprintf(end
+ strlen(end
), "%lu:", min
* 1024);
179 max
= strtoul(p
, NULL
, 10);
180 sprintf(end
+ strlen(end
), "%lu:%lu", min
* 1024, (max
* 1024) - 1);
183 // Create table of connbytes sizes, pass appropriate connections there
184 // and only continue processing them if mark was wiped
187 "-I QOSO 3 -m connmark ! --mark 0/0xff000 -j QOSSIZE\n"
188 "-I QOSO 4 -m connmark ! --mark 0/0xff000 -j RETURN\n");
190 if (max
!= prev_max
&& sizegroup
<255) {
191 class_flag
= ++sizegroup
<< 12;
193 ip46t_flagged_write(v4v6_ok
,
194 "-A QOSSIZE -m connmark --mark 0x%x/0xff000"
195 " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j CONNMARK --set-return 0x00000/0xFF\n",
196 (sizegroup
<< 12), (max
* 1024));
199 class_flag
= sizegroup
<< 12;
211 class_num
|= class_flag
;
212 class_num
|= rule_num
<< 20;
213 sprintf(end
+ strlen(end
), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num
);
216 proto_num
= atoi(proto
);
217 if (proto_num
> -2) {
218 if ((proto_num
== 6) || (proto_num
== 17) || (proto_num
== -1)) {
219 if (*port_type
!= 'a') {
220 if ((*port_type
== 'x') || (strchr(port
, ','))) {
221 // dst-or-src port matches, and anything with multiple lists "," use multiport
222 sprintf(sport
, "-m multiport --%sports %s", (*port_type
== 's') ? "s" : ((*port_type
== 'd') ? "d" : ""), port
);
225 // single or simple x:y range, use built-in tcp/udp match
226 sprintf(sport
, "--%sport %s", (*port_type
== 's') ? "s" : ((*port_type
== 'd') ? "d" : ""), port
);
232 if (proto_num
!= 6) ip46t_flagged_write(v4v6_ok
, "-A %s -p %s %s %s %s", chain
, "udp", sport
, saddr
, end
);
233 if (proto_num
!= 17) ip46t_flagged_write(v4v6_ok
, "-A %s -p %s %s %s %s", chain
, "tcp", sport
, saddr
, end
);
236 ip46t_flagged_write(v4v6_ok
, "-A %s -p %d %s %s", chain
, proto_num
, saddr
, end
);
239 else { // any protocol
240 ip46t_flagged_write(v4v6_ok
, "-A %s %s %s", chain
, saddr
, end
);
246 qface
= wanfaces
.iface
[0].name
;
248 i
= nvram_get_int("qos_default");
249 if ((i
< 0) || (i
> 9)) i
= 3; // "low"
251 class_num
|= 0xFF00000; // use rule_num=255 for default
252 ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num
);
255 "-A FORWARD -o %s -j QOSO\n"
256 "-A OUTPUT -o %s -j QOSO\n",
262 "-A FORWARD -o %s -j QOSO\n"
263 "-A OUTPUT -o %s -j QOSO\n",
268 inuse
|= (1 << i
) | 1; // default and highest are always built
269 sprintf(s
, "%d", inuse
);
270 nvram_set("qos_inuse", s
);
273 g
= buf
= strdup(nvram_safe_get("qos_irates"));
274 for (i
= 0; i
< 10; ++i
) {
275 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) continue;
276 if ((inuse
& (1 << i
)) == 0) continue;
278 ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", qface
);
281 ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face
);
291 static const char *qosfn
= "/etc/qos";
293 static unsigned calc(unsigned bw
, unsigned pct
)
295 unsigned n
= ((unsigned long)bw
* pct
) / 100;
296 return (n
< 2) ? 2 : n
;
318 x
= nvram_get_int("ne_vegas");
321 char alpha
[10], beta
[10], gamma
[10];
322 sprintf(alpha
, "alpha=%d", nvram_get_int("ne_valpha"));
323 sprintf(beta
, "beta=%d", nvram_get_int("ne_vbeta"));
324 sprintf(gamma
, "gamma=%d", nvram_get_int("ne_vgamma"));
325 modprobe("tcp_vegas", alpha
, beta
, gamma
);
326 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "vegas", 0, 0);
329 modprobe_r("tcp_vegas");
330 f_write_string("/proc/sys/net/ipv4/tcp_congestion_control", "", FW_NEWLINE
, 0);
333 f_write_string("/proc/sys/net/ipv4/tcp_vegas_cong_avoid", x
? "1" : "0", 0, 0);
335 f_write_string("/proc/sys/net/ipv4/tcp_vegas_alpha", nvram_safe_get("ne_valpha"), 0, 0);
336 f_write_string("/proc/sys/net/ipv4/tcp_vegas_beta", nvram_safe_get("ne_vbeta"), 0, 0);
337 f_write_string("/proc/sys/net/ipv4/tcp_vegas_gamma", nvram_safe_get("ne_vgamma"), 0, 0);
341 if (!nvram_get_int("qos_enable")) return;
343 if ((f
= fopen(qosfn
, "w")) == NULL
) return;
345 i
= nvram_get_int("qos_burst0");
346 if (i
> 0) sprintf(burst_root
, "burst %dk", i
);
347 else burst_root
[0] = 0;
348 i
= nvram_get_int("qos_burst1");
349 if (i
> 0) sprintf(burst_leaf
, "burst %dk", i
);
350 else burst_leaf
[0] = 0;
352 mtu
= strtoul(nvram_safe_get("wan_mtu"), NULL
, 10);
353 bw
= strtoul(nvram_safe_get("qos_obw"), NULL
, 10);
356 if ((bw
* 1000) / (8 * r2q
) < mtu
) {
357 r2q
= (bw
* 1000) / (8 * mtu
);
358 if (r2q
< 1) r2q
= 1;
359 } else if ((bw
* 1000) / (8 * r2q
) > 60000) {
360 r2q
= (bw
* 1000) / (8 * 60000) + 1;
366 "TQA=\"tc qdisc add dev $I\"\n"
367 "TCA=\"tc class add dev $I\"\n"
368 "TFA=\"tc filter add dev $I\"\n"
373 "\ttc qdisc del dev $I root 2>/dev/null\n"
374 "\t$TQA root handle 1: htb default %u r2q %u\n"
375 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
377 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
378 (nvram_get_int("qos_default") + 1) * 10, r2q
,
381 inuse
= nvram_get_int("qos_inuse");
383 g
= buf
= strdup(nvram_safe_get("qos_orates"));
384 for (i
= 0; i
< 10; ++i
) {
385 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) break;
387 if ((inuse
& (1 << i
)) == 0) continue;
389 if ((sscanf(p
, "%u-%u", &rate
, &ceil
) != 2) || (rate
< 1)) continue; // 0=off
391 if (ceil
> 0) sprintf(s
, "ceil %ukbit ", calc(bw
, ceil
));
395 "# egress %d: %u-%u%%\n"
396 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
397 "\t$TQA parent 1:%d handle %d: $Q\n"
398 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
400 x
, calc(bw
, rate
), s
, burst_leaf
, (i
>= 6) ? 7 : (i
+ 1), mtu
,
406 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
410 if (nvram_match("qos_ack", "1")) {
413 "\t$TFA parent 1: prio 15 protocol ip u32 "
414 "match ip protocol 6 0xff " // TCP
415 "match u8 0x05 0x0f at 0 " // IP header length
416 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
417 "match u8 0x10 0xff at 33 " // ACK only
420 if (nvram_match("qos_icmp", "1")) {
421 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
426 if (nvram_get_int("qos_ack")) {
429 "\t$TFA parent 1: prio 14 protocol ip u32 "
430 "match ip protocol 6 0xff " // TCP
431 "match u8 0x05 0x0f at 0 " // IP header length
432 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
433 "match u8 0x10 0xff at 33 " // ACK only
437 if (nvram_get_int("qos_syn")) {
443 "\t$TFA parent 1: prio 15 protocol ip u32 "
444 "match ip protocol 6 0xff " // TCP
445 "match u8 0x05 0x0f at 0 " // IP header length
446 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
447 "match u8 0x02 0xff at 33 " // SYN only
450 "\t$TFA parent 1: prio 16 protocol ip u32 "
451 "match ip protocol 6 0xff " // TCP
452 "match u8 0x05 0x0f at 0 " // IP header length
453 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
454 "match u8 0x12 0xff at 33 " // SYN,ACK
458 if (nvram_get_int("qos_fin")) {
464 "\t$TFA parent 1: prio 17 protocol ip u32 "
465 "match ip protocol 6 0xff " // TCP
466 "match u8 0x05 0x0f at 0 " // IP header length
467 "match u8 0x11 0xff at 33 " // ACK,FIN
470 "\t$TFA parent 1: prio 18 protocol ip u32 "
471 "match ip protocol 6 0xff " // TCP
472 "match u8 0x05 0x0f at 0 " // IP header length
473 "match u8 0x01 0xff at 33 " // FIN
477 if (nvram_get_int("qos_rst")) {
482 "\t$TFA parent 1: prio 19 protocol ip u32 "
483 "match ip protocol 6 0xff " // TCP
484 "match u8 0x05 0x0f at 0 " // IP header length
485 "match u8 0x14 0xff at 33 " // ACK,RST
488 "\t$TFA parent 1: prio 20 protocol ip u32 "
489 "match ip protocol 6 0xff " // TCP
490 "match u8 0x05 0x0f at 0 " // IP header length
491 "match u8 0x04 0xff at 33 " // RST
496 if (nvram_get_int("qos_icmp")) {
497 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
508 if (nvram_get_int("qos_ack")) {
511 "\t$TFA parent 1: prio 14 protocol ip u32 "
512 "match ip protocol 6 0xff " // TCP
513 "match u8 0x05 0x0f at 0 " // IP header length
514 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
515 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
516 "match u8 0x10 0xff at 33 " // ACK only
520 if (nvram_get_int("qos_syn")) {
523 "\t$TFA parent 1: prio 15 protocol ip u32 "
524 "match ip protocol 6 0xff " // TCP
525 "match u8 0x05 0x0f at 0 " // IP header length
526 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
527 "match u8 0x02 0x02 at 33 " // SYN,*
531 if (nvram_get_int("qos_fin")) {
534 "\t$TFA parent 1: prio 17 protocol ip u32 "
535 "match ip protocol 6 0xff " // TCP
536 "match u8 0x05 0x0f at 0 " // IP header length
537 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
538 "match u8 0x01 0x01 at 33 " // FIN,*
542 if (nvram_get_int("qos_rst")) {
545 "\t$TFA parent 1: prio 19 protocol ip u32 "
546 "match ip protocol 6 0xff " // TCP
547 "match u8 0x05 0x0f at 0 " // IP header length
548 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
549 "match u8 0x04 0x04 at 33 " // RST,*
554 if (nvram_get_int("qos_icmp")) {
555 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f
);
561 bw
= strtoul(nvram_safe_get("qos_ibw"), NULL
, 10);
562 g
= buf
= strdup(nvram_safe_get("qos_irates"));
563 for (i
= 0; i
< 10; ++i
) {
564 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) break;
566 if ((inuse
& (1 << i
)) == 0) continue;
568 if ((rate
= atoi(p
)) < 1) continue; // 0 = off
574 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
575 "\t$TQA handle ffff: ingress\n");
579 unsigned int u
= calc(bw
, rate
);
582 unsigned int v
= u
/ 25;
584 // const unsigned int v = 200;
588 "# ingress %d: %u%%\n"
589 "\t$TFA parent ffff: prio %d protocol ip handle %d fw police rate %ukbit burst %ukbit drop flowid ffff:%d\n",
598 "\ttc qdisc del dev $I root 2>/dev/null\n"
599 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
602 "\ttc -s -d qdisc ls dev $I\n"
604 "\ttc -s -d class ls dev $I\n"
610 eval((char *)qosfn
, "start");
615 eval((char *)qosfn
, "stop");
617 if (!nvram_match("debug_keepfiles", "1")) {
625 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
629 INPUT (f) OUTPUT (mnf)