]>
git.ipfire.org Git - people/mfischer/ipfire-2.x.git/blob - config/qos/makeqosscripts.pl
2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2007-2013 IPFire Team <info@ipfire.org> #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
23 # enable only the following on debugging purpose
26 require '/var/ipfire/general-functions.pl' ;
27 require "${General::swroot}/lang.pl" ;
28 require "${General::swroot}/header.pl" ;
34 my $errormessage = "" ;
39 my $portruleentry = "" ;
40 my $tosruleentry = "" ;
50 my @portruleline = ();
53 my $classfile = "/var/ipfire/qos/classes" ;
54 my $level7file = "/var/ipfire/qos/level7config" ;
55 my $portfile = "/var/ipfire/qos/portconfig" ;
56 my $tosfile = "/var/ipfire/qos/tosconfig" ;
57 my $fqcodel_options = "limit 10240 quantum 1514" ;
59 # Define iptables MARKs
60 my $QOS_INC_MASK = 0x0000ff00 ;
61 my $QOS_INC_SHIFT = 8 ;
62 my $QOS_OUT_MASK = 0x000000ff ;
63 my $QOS_OUT_SHIFT = 0 ;
65 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%netsettings );
67 $qossettings { 'ENABLED' } = 'off' ;
68 $qossettings { 'EDIT' } = 'no' ;
69 $qossettings { 'OUT_SPD' } = '' ;
70 $qossettings { 'INC_SPD' } = '' ;
71 $qossettings { 'DEF_OUT_SPD' } = '' ;
72 $qossettings { 'DEF_INC_SPD' } = '' ;
73 $qossettings { 'DEFCLASS_INC' } = '' ;
74 $qossettings { 'DEFCLASS_OUT' } = '' ;
75 $qossettings { 'RED_DEV' } = `cat /var/ipfire/red/iface` ;
76 $qossettings { 'IMQ_DEV' } = 'imq0' ;
77 $qossettings { 'TOS' } = '' ;
78 $qossettings { 'VALID' } = 'yes' ;
80 & General
:: readhash
( "${General::swroot}/qos/settings" , \
%qossettings );
82 my $DEF_OUT_MARK = ( $qossettings { 'DEFCLASS_OUT' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK " ;
83 my $DEF_INC_MARK = ( $qossettings { 'DEFCLASS_INC' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK " ;
85 open ( FILE
, "< $classfile " ) or die "Unable to read $classfile " ;
88 open ( FILE
, "< $level7file " ) or die "Unable to read $level7file " ;
91 open ( FILE
, "< $portfile " ) or die "Unable to read $portfile " ;
94 open ( FILE
, "< $tosfile " ) or die "Unable to read $tosfile " ;
98 ############################################################################################################################
99 ############################################################################################################################
103 #################################################
104 # This is an autocreated QoS-Script for #
106 # Copyright by the IPFire Team (GPLv2) #
108 #################################################
111 # RED INTERFACE: $qossettings {'RED_DEV'}
112 # IMQ DEVICE: $qossettings {'IMQ_DEV'}
114 eval \$(/usr/local/bin/readhash /var/ipfire/main/settings)
115 if [ "\ $RRDLOG " == "" ]; then
125 tc -s qdisc show dev $qossettings {'RED_DEV'}
126 tc -s qdisc show dev $qossettings {'IMQ_DEV'}
131 tc -s class show dev $qossettings {'RED_DEV'}
132 tc -s class show dev $qossettings {'IMQ_DEV'}
137 tc -s filter show dev $qossettings {'RED_DEV'}
138 tc -s filter show dev $qossettings {'IMQ_DEV'}
143 iptables -t mangle -n -L QOS-OUT -v -x 2> /dev/null
144 iptables -t mangle -n -L QOS-INC -v -x 2> /dev/null
156 ### $qossettings {'RED_DEV'}
162 ### ADD HTB QDISC FOR $qossettings {'RED_DEV'}
163 tc qdisc del dev $qossettings {'RED_DEV'} root >/dev/null 2>&1
164 tc qdisc add dev $qossettings {'RED_DEV'} root handle 1: htb default $qossettings {'DEFCLASS_OUT'}
167 tc class add dev $qossettings {'RED_DEV'} parent 1: classid 1:1 htb rate $qossettings {'OUT_SPD'}kbit
169 ### CLASSES FOR $qossettings {'RED_DEV'}
172 foreach $classentry ( sort @classes )
174 @classline = split ( /\;/ , $classentry );
175 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
176 $qossettings { 'DEVICE' } = $classline [ 0 ];
177 $qossettings { 'CLASS' } = $classline [ 1 ];
178 $qossettings { 'PRIO' } = $classline [ 2 ];
179 $qossettings { 'RATE' } = $classline [ 3 ];
180 $qossettings { 'CEIL' } = $classline [ 4 ];
181 $qossettings { 'BURST' } = $classline [ 5 ];
182 $qossettings { 'CBURST' } = $classline [ 6 ];
183 print " \t tc class add dev $qossettings {'DEVICE'} parent 1:1 classid 1: $qossettings {'CLASS'} htb rate $qossettings {'RATE'}kbit ceil $qossettings {'CEIL'}kbit prio $qossettings {'PRIO'} " ;
184 if (( $qossettings { 'BURST' } ne '' ) && ( $qossettings { 'BURST' } ne 0 )) {
185 print "burst $qossettings {'BURST'}k " ;
187 if (( $qossettings { 'CBURST' } ne '' ) && ( $qossettings { 'CBURST' } ne 0 )) {
188 print "cburst $qossettings {'CBURST'}k" ;
194 print " \n\t ### ATTACH QDISC TO LEAF CLASSES \n " ;
195 foreach $classentry ( sort @classes )
197 @classline = split ( /\;/ , $classentry );
198 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
199 $qossettings { 'DEVICE' } = $classline [ 0 ];
200 $qossettings { 'CLASS' } = $classline [ 1 ];
201 print " \t tc qdisc add dev $qossettings {'DEVICE'} parent 1: $qossettings {'CLASS'} handle $qossettings {'CLASS'}: fq_codel $fqcodel_options \n " ;
204 print " \n\t ### FILTER TRAFFIC INTO CLASSES \n " ;
205 foreach $classentry ( sort @classes )
207 @classline = split ( /\;/ , $classentry );
208 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
209 $qossettings { 'DEVICE' } = $classline [ 0 ];
210 $qossettings { 'CLASS' } = $classline [ 1 ];
211 print " \t tc filter add dev $qossettings {'DEVICE'} parent 1:0 prio 0 protocol ip" ;
212 printf ( " u32 match mark 0x %x 0x %x flowid 1: %d \n " , ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ), $QOS_OUT_MASK , $qossettings { 'CLASS' });
218 ### ADD QOS-OUT CHAIN TO THE MANGLE TABLE IN IPTABLES
219 iptables -t mangle -N QOS-OUT
220 iptables -t mangle -I POSTROUTING -o $qossettings {'RED_DEV'} -j QOS-OUT
222 ### Don't change mark on traffic for the ipsec tunnel
223 iptables -t mangle -A QOS-OUT -m mark --mark 50 -j RETURN
228 foreach $tosruleentry ( sort @tosrules )
230 @tosruleline = split ( /\;/ , $tosruleentry );
231 $qossettings { 'CLASS' } = $tosruleline [ 0 ];
232 $qossettings { 'TOS' } = abs $tosruleline [ 2 ] * 2 ;
233 if ( $tosruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
235 print " \t iptables -t mangle -A QOS-OUT -m tos --tos $qossettings {'TOS'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK \n " ;
236 print " \t iptables -t mangle -A QOS-OUT -m tos --tos $qossettings {'TOS'} -j RETURN \n " ;
240 print " \n\t ### SET PORT-RULES \n " ;
241 foreach $portruleentry ( sort @portrules )
243 @portruleline = split ( /\;/ , $portruleentry );
244 if ( $portruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
246 $qossettings { 'CLASS' } = $portruleline [ 0 ];
247 $qossettings { 'DEVICE' } = $portruleline [ 1 ];
248 $qossettings { 'PPROT' } = $portruleline [ 2 ];
249 $qossettings { 'QIP' } = $portruleline [ 3 ];
250 $qossettings { 'QPORT' } = $portruleline [ 4 ];
251 $qossettings { 'DIP' } = $portruleline [ 5 ];
252 $qossettings { 'DPORT' } = $portruleline [ 6 ];
253 print " \t iptables -t mangle -A QOS-OUT " ;
254 if ( $qossettings { 'QIP' } ne '' ){
255 print "-s $qossettings {'QIP'} " ;
257 if ( $qossettings { 'DIP' } ne '' ){
258 print "-d $qossettings {'DIP'} " ;
260 print "-p $qossettings {'PPROT'} " ;
261 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
262 # print "-m multiport ";
264 if ( $qossettings { 'QPORT' } ne '' ){
265 print "--sport $qossettings {'QPORT'} " ;
267 if ( $qossettings { 'DPORT' } ne '' ){
268 print "--dport $qossettings {'DPORT'} " ;
270 print "-j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK \n " ;
271 print " \t iptables -t mangle -A QOS-OUT " ;
272 if ( $qossettings { 'QIP' } ne '' ){
273 print "-s $qossettings {'QIP'} " ;
275 if ( $qossettings { 'DIP' } ne '' ){
276 print "-d $qossettings {'DIP'} " ;
278 print "-p $qossettings {'PPROT'} " ;
279 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
280 # print "-m multiport ";
282 if ( $qossettings { 'QPORT' } ne '' ){
283 print "--sport $qossettings {'QPORT'} " ;
285 if ( $qossettings { 'DPORT' } ne '' ){
286 print "--dport $qossettings {'DPORT'} " ;
288 print "-j RETURN \n\n " ;
297 foreach $l7ruleentry ( sort @l7rules )
299 @l7ruleline = split ( /\;/ , $l7ruleentry );
300 if ( $l7ruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
302 $qossettings { 'CLASS' } = $l7ruleline [ 0 ];
303 $qossettings { 'DEVICE' } = $l7ruleline [ 1 ];
304 $qossettings { 'L7PROT' } = $l7ruleline [ 2 ];
305 $qossettings { 'QIP' } = $l7ruleline [ 3 ];
306 $qossettings { 'DIP' } = $l7ruleline [ 4 ];
307 print " \t iptables -t mangle -A QOS-OUT " ;
308 if ( $qossettings { 'QIP' } ne '' ){
309 print "-s $qossettings {'QIP'} " ;
311 if ( $qossettings { 'DIP' } ne '' ){
312 print "-d $qossettings {'DIP'} " ;
314 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j MARK --set-xmark " . $qossettings { 'CLASS' } << $QOS_OUT_SHIFT . "/ $QOS_OUT_MASK \n " ;
315 print " \t iptables -t mangle -A QOS-OUT " ;
316 if ( $qossettings { 'QIP' } ne '' ){
317 print "-s $qossettings {'QIP'} " ;
319 if ( $qossettings { 'DIP' } ne '' ){
320 print "-d $qossettings {'DIP'} " ;
322 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j RETURN \n " ;
328 ### REDUNDANT: SET ALL NONMARKED PACKETS TO DEFAULT CLASS
329 iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK -j MARK --set-xmark $DEF_OUT_MARK
332 ### $qossettings {'IMQ_DEV'}
335 tc qdisc del dev $qossettings {'RED_DEV'} ingress >/dev/null 2>&1
336 tc qdisc add dev $qossettings {'RED_DEV'} handle ffff: ingress
338 ### BRING UP $qossettings {'IMQ_DEV'}
339 if [ ! -d "/sys/class/net/ $qossettings {'IMQ_DEV'}" ]; then
340 ip link add name $qossettings {'IMQ_DEV'} type ifb
343 ip link set $qossettings {'IMQ_DEV'} up
345 tc filter add dev $qossettings {'RED_DEV'} parent ffff: protocol all u32 match u32 0 0 \\
346 action mirred egress redirect dev $qossettings {'IMQ_DEV'}
348 ### ADD HTB QDISC FOR $qossettings {'IMQ_DEV'}
349 tc qdisc del dev $qossettings {'IMQ_DEV'} root >/dev/null 2>&1
350 tc qdisc add dev $qossettings {'IMQ_DEV'} root handle 2: htb default $qossettings {'DEFCLASS_INC'}
353 tc class add dev $qossettings {'IMQ_DEV'} parent 2: classid 2:1 htb rate $qossettings {'INC_SPD'}kbit
355 ### CLASSES FOR $qossettings {'IMQ_DEV'}
358 foreach $classentry ( sort @classes )
360 @classline = split ( /\;/ , $classentry );
361 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
362 $qossettings { 'DEVICE' } = $classline [ 0 ];
363 $qossettings { 'CLASS' } = $classline [ 1 ];
364 $qossettings { 'PRIO' } = $classline [ 2 ];
365 $qossettings { 'RATE' } = $classline [ 3 ];
366 $qossettings { 'CEIL' } = $classline [ 4 ];
367 $qossettings { 'BURST' } = $classline [ 5 ];
368 $qossettings { 'CBURST' } = $classline [ 6 ];
369 print " \t tc class add dev $qossettings {'DEVICE'} parent 2:1 classid 2: $qossettings {'CLASS'} htb rate $qossettings {'RATE'}kbit ceil $qossettings {'CEIL'}kbit prio $qossettings {'PRIO'} " ;
370 if (( $qossettings { 'BURST' } ne '' ) && ( $qossettings { 'BURST' } ne 0 )) {
371 print "burst $qossettings {'BURST'}k " ;
373 if (( $qossettings { 'CBURST' } ne '' ) && ( $qossettings { 'CBURST' } ne 0 )) {
374 print "cburst $qossettings {'CBURST'}k" ;
380 print " \n\t ### ATTACH QDISC TO LEAF CLASSES \n " ;
381 foreach $classentry ( sort @classes )
383 @classline = split ( /\;/ , $classentry );
384 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
385 $qossettings { 'DEVICE' } = $classline [ 0 ];
386 $qossettings { 'CLASS' } = $classline [ 1 ];
387 print " \t tc qdisc add dev $qossettings {'DEVICE'} parent 2: $qossettings {'CLASS'} handle $qossettings {'CLASS'}: fq_codel $fqcodel_options \n " ;
390 print " \n\t ### FILTER TRAFFIC INTO CLASSES \n " ;
391 foreach $classentry ( sort @classes )
393 @classline = split ( /\;/ , $classentry );
394 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
395 $qossettings { 'DEVICE' } = $classline [ 0 ];
396 $qossettings { 'CLASS' } = $classline [ 1 ];
397 print " \t tc filter add dev $qossettings {'DEVICE'} parent 2:0 prio 0 protocol ip" ;
398 printf ( " u32 match mark 0x %x 0x %x flowid 2: %d \n " , ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ), $QOS_INC_MASK , $qossettings { 'CLASS' });
403 ### ADD QOS-INC CHAIN TO THE MANGLE TABLE IN IPTABLES
404 iptables -t mangle -N QOS-INC
405 iptables -t mangle -A PREROUTING -i $qossettings {'RED_DEV'} -j QOS-INC
407 # If the packet is already marked, then skip the processing
408 iptables -t mangle -A QOS-INC -m mark ! --mark 0/ $QOS_INC_MASK -j RETURN
413 foreach $tosruleentry ( sort @tosrules )
415 @tosruleline = split ( /\;/ , $tosruleentry );
416 $qossettings { 'CLASS' } = $tosruleline [ 0 ];
417 $qossettings { 'TOS' } = abs $tosruleline [ 2 ] * 2 ;
418 if ( $tosruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
420 print " \t iptables -t mangle -A QOS-INC -m tos --tos $qossettings {'TOS'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
425 print " \n\t ### SET PORT-RULES \n " ;
426 foreach $portruleentry ( sort @portrules )
428 @portruleline = split ( /\;/ , $portruleentry );
429 if ( $portruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
431 $qossettings { 'CLASS' } = $portruleline [ 0 ];
432 $qossettings { 'DEVICE' } = $portruleline [ 1 ];
433 $qossettings { 'PPROT' } = $portruleline [ 2 ];
434 $qossettings { 'QIP' } = $portruleline [ 3 ];
435 $qossettings { 'QPORT' } = $portruleline [ 4 ];
436 $qossettings { 'DIP' } = $portruleline [ 5 ];
437 $qossettings { 'DPORT' } = $portruleline [ 6 ];
438 print " \t iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK " ;
439 if ( $qossettings { 'QIP' } ne '' ){
440 print "-s $qossettings {'QIP'} " ;
442 if ( $qossettings { 'DIP' } ne '' ){
443 print "-d $qossettings {'DIP'} " ;
445 print "-p $qossettings {'PPROT'} " ;
446 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
447 # print "-m multiport ";
449 if ( $qossettings { 'QPORT' } ne '' ){
450 print "--sport $qossettings {'QPORT'} " ;
452 if ( $qossettings { 'DPORT' } ne '' ){
453 print "--dport $qossettings {'DPORT'} " ;
455 print "-j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
464 foreach $l7ruleentry ( sort @l7rules )
466 @l7ruleline = split ( /\;/ , $l7ruleentry );
467 if ( $l7ruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
469 $qossettings { 'CLASS' } = $l7ruleline [ 0 ];
470 $qossettings { 'DEVICE' } = $l7ruleline [ 1 ];
471 $qossettings { 'L7PROT' } = $l7ruleline [ 2 ];
472 $qossettings { 'QIP' } = $l7ruleline [ 3 ];
473 $qossettings { 'DIP' } = $l7ruleline [ 4 ];
474 print " \t iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK " ;
475 if ( $qossettings { 'QIP' } ne '' ){
476 print "-s $qossettings {'QIP'} " ;
478 if ( $qossettings { 'DIP' } ne '' ){
479 print "-d $qossettings {'DIP'} " ;
481 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
486 ### REDUNDANT: SET ALL NONMARKED PACKETS TO DEFAULT CLASS
487 iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK -m layer7 ! --l7proto unset -j MARK --set-xmark $DEF_INC_MARK
489 # Save mark in connection tracking
490 iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK -j CONNMARK --save-mark
492 ## STARTING COLLECTOR
493 /usr/local/bin/qosd $qossettings {'RED_DEV'} >/dev/null 2>&1
494 /usr/local/bin/qosd $qossettings {'IMQ_DEV'} >/dev/null 2>&1
496 for i in \$(ls \ $RRDLOG /class_*.rrd); do
497 rrdtool update \ $i \$(date + %s ): 2>/dev/null
500 echo "Quality of Service was successfully started!"
504 ### RESET EVERYTHING TO A KNOWN STATE
505 killall qosd >/dev/null 2>&1
508 tc qdisc del dev $qossettings {'RED_DEV'} root >/dev/null 2>&1
509 tc qdisc del dev $qossettings {'RED_DEV'} ingress >/dev/null 2>&1
510 tc qdisc add root dev $qossettings {'RED_DEV'} fq_codel >/dev/null 2>&1
511 tc qdisc del dev $qossettings {'IMQ_DEV'} root >/dev/null 2>&1
512 tc qdisc del dev $qossettings {'IMQ_DEV'} ingress >/dev/null 2>&1
513 tc qdisc add root dev $qossettings {'IMQ_DEV'} fq_codel >/dev/null 2>&1
515 ip link set $qossettings {'IMQ_DEV'} down >/dev/null 2>&1
516 ip link del $qossettings {'IMQ_DEV'} >/dev/null 2>&1
518 # REMOVE & FLUSH CHAINS
519 iptables -t mangle --delete POSTROUTING -o $qossettings {'RED_DEV'} -j QOS-OUT >/dev/null 2>&1
520 iptables -t mangle --delete PREROUTING -i $qossettings {'RED_DEV'} -j QOS-INC >/dev/null 2>&1
521 iptables -t mangle --flush QOS-OUT >/dev/null 2>&1
522 iptables -t mangle --delete-chain QOS-OUT >/dev/null 2>&1
523 iptables -t mangle --flush QOS-INC >/dev/null 2>&1
524 iptables -t mangle --delete-chain QOS-INC >/dev/null 2>&1
526 rmmod sch_htb >/dev/null 2>&1
528 for i in \$(ls \ $RRDLOG /class_*.rrd); do
529 rrdtool update \ $i \$(date + %s ):
532 echo "Quality of Service was successfully cleared!"
535 echo -n "Generating the QoS-Scripts..."
536 /usr/bin/perl /var/ipfire/qos/bin/makeqosscripts.pl > /var/ipfire/qos/bin/qos.sh
541 ### FIRST CLEAR EVERYTHING
552 ############################################################################################################################
553 ############################################################################################################################