]>
git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - config/qos/makeqosscripts.pl
cc91124df1b35cbe074418bd508260c2fcf8e09a
2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2007-2021 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" ;
58 # RED is by default connected to the Internet
62 # Define iptables MARKs
63 my $QOS_INC_MASK = 0x0000ff00 ;
64 my $QOS_INC_SHIFT = 8 ;
65 my $QOS_OUT_MASK = 0x000000ff ;
66 my $QOS_OUT_SHIFT = 0 ;
67 my $QOS_INC_SKIP_MASK = $QOS_INC_MASK ;
68 my $QOS_OUT_SKIP_MASK = $QOS_OUT_MASK ;
70 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%netsettings );
72 $qossettings { 'ENABLED' } = 'off' ;
73 $qossettings { 'EDIT' } = 'no' ;
74 $qossettings { 'OUT_SPD' } = '' ;
75 $qossettings { 'INC_SPD' } = '' ;
76 $qossettings { 'DEF_OUT_SPD' } = '' ;
77 $qossettings { 'DEF_INC_SPD' } = '' ;
78 $qossettings { 'DEFCLASS_INC' } = '' ;
79 $qossettings { 'DEFCLASS_OUT' } = '' ;
80 $qossettings { 'RED_DEV' } = `cat /var/ipfire/red/iface` ;
81 $qossettings { 'IMQ_DEV' } = 'imq0' ;
82 $qossettings { 'TOS' } = '' ;
83 $qossettings { 'VALID' } = 'yes' ;
85 & General
:: readhash
( "${General::swroot}/qos/settings" , \
%qossettings );
87 # Default to "conservative
88 unless ( defined $qossettings { 'CAKE_PROFILE' }) {
89 $qossettings { 'CAKE_PROFILE' } = "conservative" ;
91 push ( @cake_options , $qossettings { 'CAKE_PROFILE' });
93 my $DEF_OUT_MARK = ( $qossettings { 'DEFCLASS_OUT' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK " ;
94 my $DEF_INC_MARK = ( $qossettings { 'DEFCLASS_INC' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK " ;
96 open ( FILE
, "< $classfile " ) or die "Unable to read $classfile " ;
99 open ( FILE
, "< $level7file " ) or die "Unable to read $level7file " ;
102 open ( FILE
, "< $portfile " ) or die "Unable to read $portfile " ;
105 open ( FILE
, "< $tosfile " ) or die "Unable to read $tosfile " ;
109 ############################################################################################################################
110 ############################################################################################################################
114 #################################################
115 # This is an autocreated QoS-Script for #
117 # Copyright by the IPFire Team (GPLv2) #
119 #################################################
122 # RED INTERFACE: $qossettings {'RED_DEV'}
123 # IMQ DEVICE: $qossettings {'IMQ_DEV'}
125 eval \$(/usr/local/bin/readhash /var/ipfire/main/settings)
126 if [ "\ $RRDLOG " == "" ]; then
136 tc -s qdisc show dev $qossettings {'RED_DEV'}
137 tc -s qdisc show dev $qossettings {'IMQ_DEV'}
142 tc -s class show dev $qossettings {'RED_DEV'}
143 tc -s class show dev $qossettings {'IMQ_DEV'}
148 tc -s filter show dev $qossettings {'RED_DEV'}
149 tc -s filter show dev $qossettings {'IMQ_DEV'}
154 iptables -t mangle -n -L QOS-OUT -v -x 2> /dev/null
155 iptables -t mangle -n -L QOS-INC -v -x 2> /dev/null
167 ### $qossettings {'RED_DEV'}
173 ### ADD HTB QDISC FOR $qossettings {'RED_DEV'}
174 tc qdisc del dev $qossettings {'RED_DEV'} root >/dev/null 2>&1
175 tc qdisc add dev $qossettings {'RED_DEV'} root handle 1: htb default $qossettings {'DEFCLASS_OUT'}
178 tc class add dev $qossettings {'RED_DEV'} parent 1: classid 1:1 htb rate $qossettings {'OUT_SPD'}kbit
180 ### CLASSES FOR $qossettings {'RED_DEV'}
183 foreach $classentry ( sort @classes )
185 @classline = split ( /\;/ , $classentry );
186 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
187 $qossettings { 'DEVICE' } = $classline [ 0 ];
188 $qossettings { 'CLASS' } = $classline [ 1 ];
189 $qossettings { 'PRIO' } = $classline [ 2 ];
190 $qossettings { 'RATE' } = $classline [ 3 ];
191 $qossettings { 'CEIL' } = $classline [ 4 ];
192 $qossettings { 'BURST' } = $classline [ 5 ];
193 $qossettings { 'CBURST' } = $classline [ 6 ];
194 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'} " ;
195 if (( $qossettings { 'BURST' } ne '' ) && ( $qossettings { 'BURST' } ne 0 )) {
196 print "burst $qossettings {'BURST'}k " ;
198 if (( $qossettings { 'CBURST' } ne '' ) && ( $qossettings { 'CBURST' } ne 0 )) {
199 print "cburst $qossettings {'CBURST'}k" ;
205 print " \n\t ### ATTACH QDISC TO LEAF CLASSES \n " ;
206 foreach $classentry ( sort @classes )
208 @classline = split ( /\;/ , $classentry );
209 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
210 $qossettings { 'DEVICE' } = $classline [ 0 ];
211 $qossettings { 'CLASS' } = $classline [ 1 ];
212 print " \t tc qdisc add dev $qossettings {'DEVICE'} parent 1: $qossettings {'CLASS'} handle $qossettings {'CLASS'}: cake @cake_options \n " ;
215 print " \n\t ### FILTER TRAFFIC INTO CLASSES \n " ;
216 foreach $classentry ( sort @classes )
218 @classline = split ( /\;/ , $classentry );
219 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
220 $qossettings { 'DEVICE' } = $classline [ 0 ];
221 $qossettings { 'CLASS' } = $classline [ 1 ];
222 print " \t tc filter add dev $qossettings {'DEVICE'} parent 1:0 prio 0 protocol ip" ;
223 printf ( " u32 match mark 0x %x 0x %x flowid 1: %d \n " , ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ), $QOS_OUT_MASK , $qossettings { 'CLASS' });
229 ### ADD QOS-OUT CHAIN TO THE MANGLE TABLE IN IPTABLES
230 iptables -t mangle -N QOS-OUT
231 iptables -t mangle -A POSTROUTING -o $qossettings {'RED_DEV'} -j QOS-OUT
233 # If the packet is already marked, then skip the processing
234 iptables -t mangle -A QOS-OUT -m mark ! --mark 0/ $QOS_OUT_SKIP_MASK -j RETURN
239 foreach $tosruleentry ( sort @tosrules )
241 @tosruleline = split ( /\;/ , $tosruleentry );
242 $qossettings { 'CLASS' } = $tosruleline [ 0 ];
243 $qossettings { 'TOS' } = abs $tosruleline [ 2 ] * 2 ;
244 if ( $tosruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
246 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 " ;
247 print " \t iptables -t mangle -A QOS-OUT -m tos --tos $qossettings {'TOS'} -j RETURN \n " ;
251 print " \n\t ### SET PORT-RULES \n " ;
252 foreach $portruleentry ( sort @portrules )
254 @portruleline = split ( /\;/ , $portruleentry );
255 if ( $portruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
257 $qossettings { 'CLASS' } = $portruleline [ 0 ];
258 $qossettings { 'DEVICE' } = $portruleline [ 1 ];
259 $qossettings { 'PPROT' } = $portruleline [ 2 ];
260 $qossettings { 'QIP' } = $portruleline [ 3 ];
261 $qossettings { 'QPORT' } = $portruleline [ 4 ];
262 $qossettings { 'DIP' } = $portruleline [ 5 ];
263 $qossettings { 'DPORT' } = $portruleline [ 6 ];
264 print " \t iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK " ;
265 if ( $qossettings { 'QIP' } ne '' ){
266 print "-s $qossettings {'QIP'} " ;
268 if ( $qossettings { 'DIP' } ne '' ){
269 print "-d $qossettings {'DIP'} " ;
271 print "-p $qossettings {'PPROT'} " ;
272 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
273 # print "-m multiport ";
275 if ( $qossettings { 'QPORT' } ne '' ){
276 print "--sport $qossettings {'QPORT'} " ;
278 if ( $qossettings { 'DPORT' } ne '' ){
279 print "--dport $qossettings {'DPORT'} " ;
281 print "-j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK \n " ;
290 foreach $l7ruleentry ( sort @l7rules )
292 @l7ruleline = split ( /\;/ , $l7ruleentry );
293 if ( $l7ruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
295 $qossettings { 'CLASS' } = $l7ruleline [ 0 ];
296 $qossettings { 'DEVICE' } = $l7ruleline [ 1 ];
297 $qossettings { 'L7PROT' } = $l7ruleline [ 2 ];
298 $qossettings { 'QIP' } = $l7ruleline [ 3 ];
299 $qossettings { 'DIP' } = $l7ruleline [ 4 ];
300 print " \t iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK " ;
301 if ( $qossettings { 'QIP' } ne '' ){
302 print "-s $qossettings {'QIP'} " ;
304 if ( $qossettings { 'DIP' } ne '' ){
305 print "-d $qossettings {'DIP'} " ;
307 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK \n " ;
313 ### REDUNDANT: SET ALL NONMARKED PACKETS TO DEFAULT CLASS
314 iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK -m layer7 ! --l7proto unset -j MARK --set-xmark $DEF_OUT_MARK
316 # Save mark in connection tracking
317 iptables -t mangle -A QOS-OUT -m mark ! --mark 0/ $QOS_OUT_MASK -j CONNMARK --save-mark --mask $QOS_OUT_MASK
320 ### $qossettings {'IMQ_DEV'}
323 tc qdisc del dev $qossettings {'RED_DEV'} ingress >/dev/null 2>&1
324 tc qdisc add dev $qossettings {'RED_DEV'} handle ffff: ingress
326 ### BRING UP $qossettings {'IMQ_DEV'}
327 if [ ! -d "/sys/class/net/ $qossettings {'IMQ_DEV'}" ]; then
328 ip link add name $qossettings {'IMQ_DEV'} type ifb
331 ip link set $qossettings {'IMQ_DEV'} up
333 ### Pass IPSec traffic without redirect
334 tc filter add dev $qossettings {'RED_DEV'} parent ffff: prio 1 protocol all basic \\
335 match "ipt(-m policy --pol ipsec --dir in)" \\
338 ### Restore connmark and send rest of the traffic to $qossettings {'IMQ_DEV'}
339 tc filter add dev $qossettings {'RED_DEV'} parent ffff: prio 2 protocol all u32 \\
342 action mirred egress redirect dev $qossettings {'IMQ_DEV'}
344 ### ADD HTB QDISC FOR $qossettings {'IMQ_DEV'}
345 tc qdisc del dev $qossettings {'IMQ_DEV'} root >/dev/null 2>&1
346 tc qdisc add dev $qossettings {'IMQ_DEV'} root handle 2: htb default $qossettings {'DEFCLASS_INC'}
349 tc class add dev $qossettings {'IMQ_DEV'} parent 2: classid 2:1 htb rate $qossettings {'INC_SPD'}kbit
351 ### CLASSES FOR $qossettings {'IMQ_DEV'}
354 foreach $classentry ( sort @classes )
356 @classline = split ( /\;/ , $classentry );
357 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
358 $qossettings { 'DEVICE' } = $classline [ 0 ];
359 $qossettings { 'CLASS' } = $classline [ 1 ];
360 $qossettings { 'PRIO' } = $classline [ 2 ];
361 $qossettings { 'RATE' } = $classline [ 3 ];
362 $qossettings { 'CEIL' } = $classline [ 4 ];
363 $qossettings { 'BURST' } = $classline [ 5 ];
364 $qossettings { 'CBURST' } = $classline [ 6 ];
365 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'} " ;
366 if (( $qossettings { 'BURST' } ne '' ) && ( $qossettings { 'BURST' } ne 0 )) {
367 print "burst $qossettings {'BURST'}k " ;
369 if (( $qossettings { 'CBURST' } ne '' ) && ( $qossettings { 'CBURST' } ne 0 )) {
370 print "cburst $qossettings {'CBURST'}k" ;
376 print " \n\t ### ATTACH QDISC TO LEAF CLASSES \n " ;
377 foreach $classentry ( sort @classes )
379 @classline = split ( /\;/ , $classentry );
380 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
381 $qossettings { 'DEVICE' } = $classline [ 0 ];
382 $qossettings { 'CLASS' } = $classline [ 1 ];
383 print " \t tc qdisc add dev $qossettings {'DEVICE'} parent 2: $qossettings {'CLASS'} handle $qossettings {'CLASS'}: cake @cake_options \n " ;
386 print " \n\t ### FILTER TRAFFIC INTO CLASSES \n " ;
387 foreach $classentry ( sort @classes )
389 @classline = split ( /\;/ , $classentry );
390 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
391 $qossettings { 'DEVICE' } = $classline [ 0 ];
392 $qossettings { 'CLASS' } = $classline [ 1 ];
393 print " \t tc filter add dev $qossettings {'DEVICE'} parent 2:0 prio 0 protocol ip" ;
394 printf ( " u32 match mark 0x %x 0x %x flowid 2: %d \n " , ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ), $QOS_INC_MASK , $qossettings { 'CLASS' });
399 ### ADD QOS-INC CHAIN TO THE MANGLE TABLE IN IPTABLES
400 iptables -t mangle -N QOS-INC
401 iptables -t mangle -A PREROUTING -i $qossettings {'RED_DEV'} -j QOS-INC
403 # If the packet is already marked, then skip the processing
404 iptables -t mangle -A QOS-INC -m mark ! --mark 0/ $QOS_INC_SKIP_MASK -j RETURN
409 foreach $tosruleentry ( sort @tosrules )
411 @tosruleline = split ( /\;/ , $tosruleentry );
412 $qossettings { 'CLASS' } = $tosruleline [ 0 ];
413 $qossettings { 'TOS' } = abs $tosruleline [ 2 ] * 2 ;
414 if ( $tosruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
416 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 " ;
421 print " \n\t ### SET PORT-RULES \n " ;
422 foreach $portruleentry ( sort @portrules )
424 @portruleline = split ( /\;/ , $portruleentry );
425 if ( $portruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
427 $qossettings { 'CLASS' } = $portruleline [ 0 ];
428 $qossettings { 'DEVICE' } = $portruleline [ 1 ];
429 $qossettings { 'PPROT' } = $portruleline [ 2 ];
430 $qossettings { 'QIP' } = $portruleline [ 3 ];
431 $qossettings { 'QPORT' } = $portruleline [ 4 ];
432 $qossettings { 'DIP' } = $portruleline [ 5 ];
433 $qossettings { 'DPORT' } = $portruleline [ 6 ];
434 print " \t iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK " ;
435 if ( $qossettings { 'QIP' } ne '' ){
436 print "-s $qossettings {'QIP'} " ;
438 if ( $qossettings { 'DIP' } ne '' ){
439 print "-d $qossettings {'DIP'} " ;
441 print "-p $qossettings {'PPROT'} " ;
442 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
443 # print "-m multiport ";
445 if ( $qossettings { 'QPORT' } ne '' ){
446 print "--sport $qossettings {'QPORT'} " ;
448 if ( $qossettings { 'DPORT' } ne '' ){
449 print "--dport $qossettings {'DPORT'} " ;
451 print "-j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
460 foreach $l7ruleentry ( sort @l7rules )
462 @l7ruleline = split ( /\;/ , $l7ruleentry );
463 if ( $l7ruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
465 $qossettings { 'CLASS' } = $l7ruleline [ 0 ];
466 $qossettings { 'DEVICE' } = $l7ruleline [ 1 ];
467 $qossettings { 'L7PROT' } = $l7ruleline [ 2 ];
468 $qossettings { 'QIP' } = $l7ruleline [ 3 ];
469 $qossettings { 'DIP' } = $l7ruleline [ 4 ];
470 print " \t iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK " ;
471 if ( $qossettings { 'QIP' } ne '' ){
472 print "-s $qossettings {'QIP'} " ;
474 if ( $qossettings { 'DIP' } ne '' ){
475 print "-d $qossettings {'DIP'} " ;
477 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
482 ### REDUNDANT: SET ALL NONMARKED PACKETS TO DEFAULT CLASS
483 iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK -m layer7 ! --l7proto unset -j MARK --set-xmark $DEF_INC_MARK
485 # Save mark in connection tracking
486 iptables -t mangle -A QOS-INC -m mark ! --mark 0/ $QOS_INC_MASK -j CONNMARK --save-mark --mask $QOS_INC_MASK
488 ## STARTING COLLECTOR
489 /usr/local/bin/qosd $qossettings {'RED_DEV'} >/dev/null 2>&1
490 /usr/local/bin/qosd $qossettings {'IMQ_DEV'} >/dev/null 2>&1
492 for i in \$(ls \ $RRDLOG /class_*.rrd); do
493 rrdtool update \ $i \$(date + %s ): 2>/dev/null
496 echo "Quality of Service was successfully started!"
500 ### RESET EVERYTHING TO A KNOWN STATE
501 killall qosd >/dev/null 2>&1
504 tc qdisc del dev $qossettings {'RED_DEV'} root >/dev/null 2>&1
505 tc qdisc del dev $qossettings {'RED_DEV'} ingress >/dev/null 2>&1
506 INTERFACE=" $qossettings {'RED_DEV'}" ACTION="add" /lib/udev/network-aqm &>/dev/null
508 ip link set $qossettings {'IMQ_DEV'} down >/dev/null 2>&1
509 ip link del $qossettings {'IMQ_DEV'} >/dev/null 2>&1
511 # REMOVE & FLUSH CHAINS
512 iptables -t mangle --delete POSTROUTING -o $qossettings {'RED_DEV'} -j QOS-OUT >/dev/null 2>&1
513 iptables -t mangle --delete PREROUTING -i $qossettings {'RED_DEV'} -j QOS-INC >/dev/null 2>&1
514 iptables -t mangle --flush QOS-OUT >/dev/null 2>&1
515 iptables -t mangle --delete-chain QOS-OUT >/dev/null 2>&1
516 iptables -t mangle --flush QOS-INC >/dev/null 2>&1
517 iptables -t mangle --delete-chain QOS-INC >/dev/null 2>&1
519 for i in \$(ls \ $RRDLOG /class_*.rrd); do
520 rrdtool update \ $i \$(date + %s ):
523 echo "Quality of Service was successfully cleared!"
526 echo -n "Generating the QoS-Scripts..."
527 /usr/bin/perl /var/ipfire/qos/bin/makeqosscripts.pl > /var/ipfire/qos/bin/qos.sh
532 ### FIRST CLEAR EVERYTHING
543 ############################################################################################################################
544 ############################################################################################################################