4 Copyright (C) 2006-2009 Jonathan Zarate
19 char *addr_type
, *addr
;
21 char *port_type
, *port
;
40 if (!nvram_get_int("qos_enable")) return;
49 "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n"
50 "-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n");
52 g
= buf
= strdup(nvram_safe_get("qos_orules"));
57 addr_type<addr<proto<port_type<port<ipp2p<L7<bcount<desc
65 ip/mac if addr_type == 1-3
71 if proto == -1,tcp,udp:
77 port # if proto == -1,tcp,udp
87 if ((p
= strsep(&g
, ">")) == NULL
) break;
88 i
= vstrsep(p
, "<", &addr_type
, &addr
, &proto
, &port_type
, &port
, &ipp2p
, &layer7
, &bcount
, &class_prio
, &p
);
90 // fixup < v0.08 // !!! temp
94 else if (i
!= 10) continue;
96 class_num
= atoi(class_prio
);
97 if ((class_num
< 0) || (class_num
> 9)) continue;
102 if ((inuse
& i
) == 0) {
107 if ((*addr_type
== '1') || (*addr_type
== '2')) { // match ip
108 if (strchr(addr
, '-') != NULL
) {
109 sprintf(saddr
, "-m iprange --%s-range %s", (*addr_type
== '1') ? "dst" : "src", addr
);
112 sprintf(saddr
, "-%c %s", (*addr_type
== '1') ? 'd' : 's', addr
);
115 else if (*addr_type
== '3') { // match mac
116 sprintf(saddr
, "-m mac --mac-source %s", addr
); // (-m mac modified, returns !match in OUTPUT)
123 if (!ipt_ipp2p(ipp2p
, app
)) ipt_layer7(layer7
, app
);
130 // -m bcount --range x-y
132 min
= strtoul(bcount
, &p
, 10);
134 strcat(end
, " -m bcount --range ");
137 sprintf(end
+ strlen(end
), "0x%lx", min
* 1024);
140 sprintf(end
+ strlen(end
), "0x%lx-0x%lx", min
* 1024, (strtoul(p
, NULL
, 10) * 1024) - 1);
154 sprintf(end
+ strlen(end
), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num
);
157 proto_num
= atoi(proto
);
158 if (proto_num
> -2) {
159 if ((proto_num
== 6) || (proto_num
== 17) || (proto_num
== -1)) {
160 if (*port_type
!= 'a') {
161 if ((*port_type
== 'x') || (strchr(port
, ','))) {
162 // dst-or-src port matches, and anything with multiple lists "," use mport
163 sprintf(sport
, "-m mport --%sports %s", (*port_type
== 's') ? "s" : ((*port_type
== 'd') ? "d" : ""), port
);
166 // single or simple x:y range, use built-in tcp/udp match
167 sprintf(sport
, "--%sport %s", (*port_type
== 's') ? "s" : ((*port_type
== 'd') ? "d" : ""), port
);
173 if (proto_num
!= 6) ipt_write("-A %s -p %s %s %s %s", chain
, "udp", sport
, saddr
, end
);
174 if (proto_num
!= 17) ipt_write("-A %s -p %s %s %s %s", chain
, "tcp", sport
, saddr
, end
);
177 ipt_write("-A %s -p %d %s %s", chain
, proto_num
, saddr
, end
);
180 else { // any protocol
181 ipt_write("-A %s %s %s", chain
, saddr
, end
);
189 ipt_write("-I QOSO -j BCOUNT\n");
192 i
= nvram_get_int("qos_default");
193 if ((i
< 0) || (i
> 9)) i
= 3; // "low"
196 "-A QOSO -j CONNMARK --set-return 0x%x\n"
197 "-A FORWARD -o %s -j QOSO\n"
198 "-A OUTPUT -o %s -j QOSO\n",
199 class_num
, wanface
, wanface
);
201 inuse
|= (1 << i
) | 1; // default and highest are always built
202 sprintf(s
, "%d", inuse
);
203 nvram_set("qos_inuse", s
);
206 g
= buf
= strdup(nvram_safe_get("qos_irates"));
207 for (i
= 0; i
< 10; ++i
) {
208 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) continue;
209 if ((inuse
& (1 << i
)) == 0) continue;
211 ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wanface
);
220 static const char *qosfn
= "/etc/qos";
222 static unsigned calc(unsigned bw
, unsigned pct
)
224 unsigned n
= ((unsigned long)bw
* pct
) / 100;
225 return (n
< 2) ? 2 : n
;
246 x
= nvram_get_int("ne_vegas");
247 f_write_string("/proc/sys/net/ipv4/tcp_vegas_cong_avoid", x
? "1" : "0", 0, 0);
249 f_write_string("/proc/sys/net/ipv4/tcp_vegas_alpha", nvram_safe_get("ne_valpha"), 0, 0);
250 f_write_string("/proc/sys/net/ipv4/tcp_vegas_beta", nvram_safe_get("ne_vbeta"), 0, 0);
251 f_write_string("/proc/sys/net/ipv4/tcp_vegas_gamma", nvram_safe_get("ne_vgamma"), 0, 0);
255 if (!nvram_get_int("qos_enable")) return;
257 if ((f
= fopen(qosfn
, "w")) == NULL
) return;
259 i
= nvram_get_int("qos_burst0");
260 if (i
> 0) sprintf(burst_root
, "burst %dk", i
);
261 else burst_root
[0] = 0;
262 i
= nvram_get_int("qos_burst1");
263 if (i
> 0) sprintf(burst_leaf
, "burst %dk", i
);
264 else burst_leaf
[0] = 0;
266 mtu
= strtoul(nvram_safe_get("wan_mtu"), NULL
, 10);
267 bw
= strtoul(nvram_safe_get("qos_obw"), NULL
, 10);
272 "TQA=\"tc qdisc add dev $I\"\n"
273 "TCA=\"tc class add dev $I\"\n"
274 "TFA=\"tc filter add dev $I\"\n"
279 "\ttc qdisc del dev $I root 2>/dev/null\n"
280 "\t$TQA root handle 1: htb default %u\n"
281 "\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n",
282 nvram_safe_get("wan_iface"),
283 nvram_get_int("qos_pfifo") ? "pfifo limit 256" : "sfq perturb 10",
284 (nvram_get_int("qos_default") + 1) * 10,
287 inuse
= nvram_get_int("qos_inuse");
289 g
= buf
= strdup(nvram_safe_get("qos_orates"));
290 for (i
= 0; i
< 10; ++i
) {
291 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) break;
293 if ((inuse
& (1 << i
)) == 0) continue;
295 if ((sscanf(p
, "%u-%u", &rate
, &ceil
) != 2) || (rate
< 1)) continue; // 0=off
297 if (ceil
> 0) sprintf(s
, "ceil %ukbit ", calc(bw
, ceil
));
301 "# egress %d: %u-%u%%\n"
302 "\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
303 "\t$TQA parent 1:%d handle %d: $Q\n"
304 "\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
306 x
, calc(bw
, rate
), s
, burst_leaf
, (i
>= 6) ? 7 : (i
+ 1), mtu
,
312 // "\t$TFA parent 1: prio 10 protocol ip u32 match ip tos 0x10 0xff flowid :10\n" // TOS EF -> Highest
316 if (nvram_match("qos_ack", "1")) {
319 "\t$TFA parent 1: prio 15 protocol ip u32 "
320 "match ip protocol 6 0xff " // TCP
321 "match u8 0x05 0x0f at 0 " // IP header length
322 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
323 "match u8 0x10 0xff at 33 " // ACK only
326 if (nvram_match("qos_icmp", "1")) {
327 fputs("\n\t$TFA parent 1: prio 14 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
332 if (nvram_get_int("qos_ack")) {
335 "\t$TFA parent 1: prio 14 protocol ip u32 "
336 "match ip protocol 6 0xff " // TCP
337 "match u8 0x05 0x0f at 0 " // IP header length
338 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
339 "match u8 0x10 0xff at 33 " // ACK only
343 if (nvram_get_int("qos_syn")) {
349 "\t$TFA parent 1: prio 15 protocol ip u32 "
350 "match ip protocol 6 0xff " // TCP
351 "match u8 0x05 0x0f at 0 " // IP header length
352 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
353 "match u8 0x02 0xff at 33 " // SYN only
356 "\t$TFA parent 1: prio 16 protocol ip u32 "
357 "match ip protocol 6 0xff " // TCP
358 "match u8 0x05 0x0f at 0 " // IP header length
359 "match u16 0x0000 0xff80 at 2 " // total length (0-127)
360 "match u8 0x12 0xff at 33 " // SYN,ACK
364 if (nvram_get_int("qos_fin")) {
370 "\t$TFA parent 1: prio 17 protocol ip u32 "
371 "match ip protocol 6 0xff " // TCP
372 "match u8 0x05 0x0f at 0 " // IP header length
373 "match u8 0x11 0xff at 33 " // ACK,FIN
376 "\t$TFA parent 1: prio 18 protocol ip u32 "
377 "match ip protocol 6 0xff " // TCP
378 "match u8 0x05 0x0f at 0 " // IP header length
379 "match u8 0x01 0xff at 33 " // FIN
383 if (nvram_get_int("qos_rst")) {
388 "\t$TFA parent 1: prio 19 protocol ip u32 "
389 "match ip protocol 6 0xff " // TCP
390 "match u8 0x05 0x0f at 0 " // IP header length
391 "match u8 0x14 0xff at 33 " // ACK,RST
394 "\t$TFA parent 1: prio 20 protocol ip u32 "
395 "match ip protocol 6 0xff " // TCP
396 "match u8 0x05 0x0f at 0 " // IP header length
397 "match u8 0x04 0xff at 33 " // RST
402 if (nvram_get_int("qos_icmp")) {
403 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
414 if (nvram_get_int("qos_ack")) {
417 "\t$TFA parent 1: prio 14 protocol ip u32 "
418 "match ip protocol 6 0xff " // TCP
419 "match u8 0x05 0x0f at 0 " // IP header length
420 // "match u16 0x0000 0xff80 at 2 " // total length (0-127)
421 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
422 "match u8 0x10 0xff at 33 " // ACK only
426 if (nvram_get_int("qos_syn")) {
429 "\t$TFA parent 1: prio 15 protocol ip u32 "
430 "match ip protocol 6 0xff " // TCP
431 "match u8 0x05 0x0f at 0 " // IP header length
432 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
433 "match u8 0x02 0x02 at 33 " // SYN,*
437 if (nvram_get_int("qos_fin")) {
440 "\t$TFA parent 1: prio 17 protocol ip u32 "
441 "match ip protocol 6 0xff " // TCP
442 "match u8 0x05 0x0f at 0 " // IP header length
443 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
444 "match u8 0x01 0x01 at 33 " // FIN,*
448 if (nvram_get_int("qos_rst")) {
451 "\t$TFA parent 1: prio 19 protocol ip u32 "
452 "match ip protocol 6 0xff " // TCP
453 "match u8 0x05 0x0f at 0 " // IP header length
454 "match u16 0x0000 0xffc0 at 2 " // total length (0-63)
455 "match u8 0x04 0x04 at 33 " // RST,*
460 if (nvram_get_int("qos_icmp")) {
461 fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f
);
467 bw
= strtoul(nvram_safe_get("qos_ibw"), NULL
, 10);
468 g
= buf
= strdup(nvram_safe_get("qos_irates"));
469 for (i
= 0; i
< 10; ++i
) {
470 if ((!g
) || ((p
= strsep(&g
, ",")) == NULL
)) break;
472 if ((inuse
& (1 << i
)) == 0) continue;
474 if ((rate
= atoi(p
)) < 1) continue; // 0 = off
480 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
481 "\t$TQA handle ffff: ingress\n");
485 unsigned int u
= calc(bw
, rate
);
488 unsigned int v
= u
/ 25;
490 // const unsigned int v = 200;
494 "# ingress %d: %u%%\n"
495 "\t$TFA parent ffff: prio %d protocol ip handle %d fw police rate %ukbit burst %ukbit drop flowid ffff:%d\n",
504 "\ttc qdisc del dev $I root 2>/dev/null\n"
505 "\ttc qdisc del dev $I ingress 2>/dev/null\n"
508 "\ttc -s -d qdisc ls dev $I\n"
510 "\ttc -s -d class ls dev $I\n"
516 eval((char *)qosfn
, "start");
521 eval((char *)qosfn
, "stop");
523 if (!nvram_match("debug_keepfiles", "1")) {
531 PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n)
535 INPUT (f) OUTPUT (mnf)