]>
git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - config/qos/makeqosscripts.pl
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" ;
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 ;
64 my $IPSEC_MASK = 0x00800000 ;
65 my $QOS_INC_SKIP_MASK = $QOS_INC_MASK | $IPSEC_MASK ;
66 my $QOS_OUT_SKIP_MASK = $QOS_OUT_MASK | $IPSEC_MASK ;
68 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%netsettings );
70 $qossettings { 'ENABLED' } = 'off' ;
71 $qossettings { 'EDIT' } = 'no' ;
72 $qossettings { 'OUT_SPD' } = '' ;
73 $qossettings { 'INC_SPD' } = '' ;
74 $qossettings { 'DEF_OUT_SPD' } = '' ;
75 $qossettings { 'DEF_INC_SPD' } = '' ;
76 $qossettings { 'DEFCLASS_INC' } = '' ;
77 $qossettings { 'DEFCLASS_OUT' } = '' ;
78 $qossettings { 'RED_DEV' } = `cat /var/ipfire/red/iface` ;
79 $qossettings { 'IMQ_DEV' } = 'imq0' ;
80 $qossettings { 'TOS' } = '' ;
81 $qossettings { 'VALID' } = 'yes' ;
83 & General
:: readhash
( "${General::swroot}/qos/settings" , \
%qossettings );
85 my $DEF_OUT_MARK = ( $qossettings { 'DEFCLASS_OUT' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK " ;
86 my $DEF_INC_MARK = ( $qossettings { 'DEFCLASS_INC' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK " ;
88 open ( FILE
, "< $classfile " ) or die "Unable to read $classfile " ;
91 open ( FILE
, "< $level7file " ) or die "Unable to read $level7file " ;
94 open ( FILE
, "< $portfile " ) or die "Unable to read $portfile " ;
97 open ( FILE
, "< $tosfile " ) or die "Unable to read $tosfile " ;
101 ############################################################################################################################
102 ############################################################################################################################
106 #################################################
107 # This is an autocreated QoS-Script for #
109 # Copyright by the IPFire Team (GPLv2) #
111 #################################################
114 # RED INTERFACE: $qossettings {'RED_DEV'}
115 # IMQ DEVICE: $qossettings {'IMQ_DEV'}
117 eval \$(/usr/local/bin/readhash /var/ipfire/main/settings)
118 if [ "\ $RRDLOG " == "" ]; then
128 tc -s qdisc show dev $qossettings {'RED_DEV'}
129 tc -s qdisc show dev $qossettings {'IMQ_DEV'}
134 tc -s class show dev $qossettings {'RED_DEV'}
135 tc -s class show dev $qossettings {'IMQ_DEV'}
140 tc -s filter show dev $qossettings {'RED_DEV'}
141 tc -s filter show dev $qossettings {'IMQ_DEV'}
146 iptables -t mangle -n -L QOS-OUT -v -x 2> /dev/null
147 iptables -t mangle -n -L QOS-INC -v -x 2> /dev/null
159 ### $qossettings {'RED_DEV'}
165 ### ADD HTB QDISC FOR $qossettings {'RED_DEV'}
166 tc qdisc del dev $qossettings {'RED_DEV'} root >/dev/null 2>&1
167 tc qdisc add dev $qossettings {'RED_DEV'} root handle 1: htb default $qossettings {'DEFCLASS_OUT'}
170 tc class add dev $qossettings {'RED_DEV'} parent 1: classid 1:1 htb rate $qossettings {'OUT_SPD'}kbit
172 ### CLASSES FOR $qossettings {'RED_DEV'}
175 foreach $classentry ( sort @classes )
177 @classline = split ( /\;/ , $classentry );
178 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
179 $qossettings { 'DEVICE' } = $classline [ 0 ];
180 $qossettings { 'CLASS' } = $classline [ 1 ];
181 $qossettings { 'PRIO' } = $classline [ 2 ];
182 $qossettings { 'RATE' } = $classline [ 3 ];
183 $qossettings { 'CEIL' } = $classline [ 4 ];
184 $qossettings { 'BURST' } = $classline [ 5 ];
185 $qossettings { 'CBURST' } = $classline [ 6 ];
186 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'} " ;
187 if (( $qossettings { 'BURST' } ne '' ) && ( $qossettings { 'BURST' } ne 0 )) {
188 print "burst $qossettings {'BURST'}k " ;
190 if (( $qossettings { 'CBURST' } ne '' ) && ( $qossettings { 'CBURST' } ne 0 )) {
191 print "cburst $qossettings {'CBURST'}k" ;
197 print " \n\t ### ATTACH QDISC TO LEAF CLASSES \n " ;
198 foreach $classentry ( sort @classes )
200 @classline = split ( /\;/ , $classentry );
201 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
202 $qossettings { 'DEVICE' } = $classline [ 0 ];
203 $qossettings { 'CLASS' } = $classline [ 1 ];
204 print " \t tc qdisc add dev $qossettings {'DEVICE'} parent 1: $qossettings {'CLASS'} handle $qossettings {'CLASS'}: fq_codel $fqcodel_options \n " ;
207 print " \n\t ### FILTER TRAFFIC INTO CLASSES \n " ;
208 foreach $classentry ( sort @classes )
210 @classline = split ( /\;/ , $classentry );
211 if ( $qossettings { 'RED_DEV' } eq $classline [ 0 ]) {
212 $qossettings { 'DEVICE' } = $classline [ 0 ];
213 $qossettings { 'CLASS' } = $classline [ 1 ];
214 print " \t tc filter add dev $qossettings {'DEVICE'} parent 1:0 prio 0 protocol ip" ;
215 printf ( " u32 match mark 0x %x 0x %x flowid 1: %d \n " , ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ), $QOS_OUT_MASK , $qossettings { 'CLASS' });
221 ### ADD QOS-OUT CHAIN TO THE MANGLE TABLE IN IPTABLES
222 iptables -t mangle -N QOS-OUT
223 iptables -t mangle -A POSTROUTING -o $qossettings {'RED_DEV'} -j QOS-OUT
225 # If the packet is already marked, then skip the processing
226 iptables -t mangle -A QOS-OUT -m mark ! --mark 0/ $QOS_OUT_SKIP_MASK -j RETURN
231 foreach $tosruleentry ( sort @tosrules )
233 @tosruleline = split ( /\;/ , $tosruleentry );
234 $qossettings { 'CLASS' } = $tosruleline [ 0 ];
235 $qossettings { 'TOS' } = abs $tosruleline [ 2 ] * 2 ;
236 if ( $tosruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
238 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 " ;
239 print " \t iptables -t mangle -A QOS-OUT -m tos --tos $qossettings {'TOS'} -j RETURN \n " ;
243 print " \n\t ### SET PORT-RULES \n " ;
244 foreach $portruleentry ( sort @portrules )
246 @portruleline = split ( /\;/ , $portruleentry );
247 if ( $portruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
249 $qossettings { 'CLASS' } = $portruleline [ 0 ];
250 $qossettings { 'DEVICE' } = $portruleline [ 1 ];
251 $qossettings { 'PPROT' } = $portruleline [ 2 ];
252 $qossettings { 'QIP' } = $portruleline [ 3 ];
253 $qossettings { 'QPORT' } = $portruleline [ 4 ];
254 $qossettings { 'DIP' } = $portruleline [ 5 ];
255 $qossettings { 'DPORT' } = $portruleline [ 6 ];
256 print " \t iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK " ;
257 if ( $qossettings { 'QIP' } ne '' ){
258 print "-s $qossettings {'QIP'} " ;
260 if ( $qossettings { 'DIP' } ne '' ){
261 print "-d $qossettings {'DIP'} " ;
263 print "-p $qossettings {'PPROT'} " ;
264 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
265 # print "-m multiport ";
267 if ( $qossettings { 'QPORT' } ne '' ){
268 print "--sport $qossettings {'QPORT'} " ;
270 if ( $qossettings { 'DPORT' } ne '' ){
271 print "--dport $qossettings {'DPORT'} " ;
273 print "-j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK \n " ;
282 foreach $l7ruleentry ( sort @l7rules )
284 @l7ruleline = split ( /\;/ , $l7ruleentry );
285 if ( $l7ruleline [ 1 ] eq $qossettings { 'RED_DEV' } )
287 $qossettings { 'CLASS' } = $l7ruleline [ 0 ];
288 $qossettings { 'DEVICE' } = $l7ruleline [ 1 ];
289 $qossettings { 'L7PROT' } = $l7ruleline [ 2 ];
290 $qossettings { 'QIP' } = $l7ruleline [ 3 ];
291 $qossettings { 'DIP' } = $l7ruleline [ 4 ];
292 print " \t iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK " ;
293 if ( $qossettings { 'QIP' } ne '' ){
294 print "-s $qossettings {'QIP'} " ;
296 if ( $qossettings { 'DIP' } ne '' ){
297 print "-d $qossettings {'DIP'} " ;
299 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_OUT_SHIFT ) . "/ $QOS_OUT_MASK \n " ;
305 ### REDUNDANT: SET ALL NONMARKED PACKETS TO DEFAULT CLASS
306 iptables -t mangle -A QOS-OUT -m mark --mark 0/ $QOS_OUT_MASK -m layer7 ! --l7proto unset -j MARK --set-xmark $DEF_OUT_MARK
308 # Save mark in connection tracking
309 iptables -t mangle -A QOS-OUT -m mark ! --mark 0/ $QOS_OUT_MASK -j CONNMARK --save-mark --mask $QOS_OUT_MASK
312 ### $qossettings {'IMQ_DEV'}
315 tc qdisc del dev $qossettings {'RED_DEV'} ingress >/dev/null 2>&1
316 tc qdisc add dev $qossettings {'RED_DEV'} handle ffff: ingress
318 ### BRING UP $qossettings {'IMQ_DEV'}
319 if [ ! -d "/sys/class/net/ $qossettings {'IMQ_DEV'}" ]; then
320 ip link add name $qossettings {'IMQ_DEV'} type ifb
323 ip link set $qossettings {'IMQ_DEV'} up
325 ### Restore conmark and continue with next filter
326 tc filter add dev $qossettings {'RED_DEV'} parent ffff: prio 1 protocol all u32 \\
328 action connmark continue
329 ### Send all traffic except IPSec to $qossettings {'IMQ_DEV'}
330 tc filter add dev $qossettings {'RED_DEV'} parent ffff: prio 2 protocol all u32 \\
331 match mark 0 $IPSEC_MASK \\
332 action mirred egress redirect dev $qossettings {'IMQ_DEV'}
334 ### ADD HTB QDISC FOR $qossettings {'IMQ_DEV'}
335 tc qdisc del dev $qossettings {'IMQ_DEV'} root >/dev/null 2>&1
336 tc qdisc add dev $qossettings {'IMQ_DEV'} root handle 2: htb default $qossettings {'DEFCLASS_INC'}
339 tc class add dev $qossettings {'IMQ_DEV'} parent 2: classid 2:1 htb rate $qossettings {'INC_SPD'}kbit
341 ### CLASSES FOR $qossettings {'IMQ_DEV'}
344 foreach $classentry ( sort @classes )
346 @classline = split ( /\;/ , $classentry );
347 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
348 $qossettings { 'DEVICE' } = $classline [ 0 ];
349 $qossettings { 'CLASS' } = $classline [ 1 ];
350 $qossettings { 'PRIO' } = $classline [ 2 ];
351 $qossettings { 'RATE' } = $classline [ 3 ];
352 $qossettings { 'CEIL' } = $classline [ 4 ];
353 $qossettings { 'BURST' } = $classline [ 5 ];
354 $qossettings { 'CBURST' } = $classline [ 6 ];
355 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'} " ;
356 if (( $qossettings { 'BURST' } ne '' ) && ( $qossettings { 'BURST' } ne 0 )) {
357 print "burst $qossettings {'BURST'}k " ;
359 if (( $qossettings { 'CBURST' } ne '' ) && ( $qossettings { 'CBURST' } ne 0 )) {
360 print "cburst $qossettings {'CBURST'}k" ;
366 print " \n\t ### ATTACH QDISC TO LEAF CLASSES \n " ;
367 foreach $classentry ( sort @classes )
369 @classline = split ( /\;/ , $classentry );
370 if ( $qossettings { 'IMQ_DEV' } eq $classline [ 0 ]) {
371 $qossettings { 'DEVICE' } = $classline [ 0 ];
372 $qossettings { 'CLASS' } = $classline [ 1 ];
373 print " \t tc qdisc add dev $qossettings {'DEVICE'} parent 2: $qossettings {'CLASS'} handle $qossettings {'CLASS'}: fq_codel $fqcodel_options \n " ;
376 print " \n\t ### FILTER TRAFFIC INTO 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 filter add dev $qossettings {'DEVICE'} parent 2:0 prio 0 protocol ip" ;
384 printf ( " u32 match mark 0x %x 0x %x flowid 2: %d \n " , ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ), $QOS_INC_MASK , $qossettings { 'CLASS' });
389 ### ADD QOS-INC CHAIN TO THE MANGLE TABLE IN IPTABLES
390 iptables -t mangle -N QOS-INC
391 iptables -t mangle -A PREROUTING -i $qossettings {'RED_DEV'} -j QOS-INC
393 # If the packet is already marked, then skip the processing
394 iptables -t mangle -A QOS-INC -m mark ! --mark 0/ $QOS_INC_SKIP_MASK -j RETURN
399 foreach $tosruleentry ( sort @tosrules )
401 @tosruleline = split ( /\;/ , $tosruleentry );
402 $qossettings { 'CLASS' } = $tosruleline [ 0 ];
403 $qossettings { 'TOS' } = abs $tosruleline [ 2 ] * 2 ;
404 if ( $tosruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
406 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 " ;
411 print " \n\t ### SET PORT-RULES \n " ;
412 foreach $portruleentry ( sort @portrules )
414 @portruleline = split ( /\;/ , $portruleentry );
415 if ( $portruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
417 $qossettings { 'CLASS' } = $portruleline [ 0 ];
418 $qossettings { 'DEVICE' } = $portruleline [ 1 ];
419 $qossettings { 'PPROT' } = $portruleline [ 2 ];
420 $qossettings { 'QIP' } = $portruleline [ 3 ];
421 $qossettings { 'QPORT' } = $portruleline [ 4 ];
422 $qossettings { 'DIP' } = $portruleline [ 5 ];
423 $qossettings { 'DPORT' } = $portruleline [ 6 ];
424 print " \t iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK " ;
425 if ( $qossettings { 'QIP' } ne '' ){
426 print "-s $qossettings {'QIP'} " ;
428 if ( $qossettings { 'DIP' } ne '' ){
429 print "-d $qossettings {'DIP'} " ;
431 print "-p $qossettings {'PPROT'} " ;
432 # if (($qossettings{'QPORT'} ne '') || ($qossettings{'DPORT'} ne '')){
433 # print "-m multiport ";
435 if ( $qossettings { 'QPORT' } ne '' ){
436 print "--sport $qossettings {'QPORT'} " ;
438 if ( $qossettings { 'DPORT' } ne '' ){
439 print "--dport $qossettings {'DPORT'} " ;
441 print "-j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
450 foreach $l7ruleentry ( sort @l7rules )
452 @l7ruleline = split ( /\;/ , $l7ruleentry );
453 if ( $l7ruleline [ 1 ] eq $qossettings { 'IMQ_DEV' } )
455 $qossettings { 'CLASS' } = $l7ruleline [ 0 ];
456 $qossettings { 'DEVICE' } = $l7ruleline [ 1 ];
457 $qossettings { 'L7PROT' } = $l7ruleline [ 2 ];
458 $qossettings { 'QIP' } = $l7ruleline [ 3 ];
459 $qossettings { 'DIP' } = $l7ruleline [ 4 ];
460 print " \t iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK " ;
461 if ( $qossettings { 'QIP' } ne '' ){
462 print "-s $qossettings {'QIP'} " ;
464 if ( $qossettings { 'DIP' } ne '' ){
465 print "-d $qossettings {'DIP'} " ;
467 print "-m layer7 --l7dir /etc/l7-protocols/protocols --l7proto $qossettings {'L7PROT'} -j MARK --set-xmark " . ( $qossettings { 'CLASS' } << $QOS_INC_SHIFT ) . "/ $QOS_INC_MASK \n " ;
472 ### REDUNDANT: SET ALL NONMARKED PACKETS TO DEFAULT CLASS
473 iptables -t mangle -A QOS-INC -m mark --mark 0/ $QOS_INC_MASK -m layer7 ! --l7proto unset -j MARK --set-xmark $DEF_INC_MARK
475 # Save mark in connection tracking
476 iptables -t mangle -A QOS-INC -m mark ! --mark 0/ $QOS_INC_MASK -j CONNMARK --save-mark --mask $QOS_INC_MASK
478 ## STARTING COLLECTOR
479 /usr/local/bin/qosd $qossettings {'RED_DEV'} >/dev/null 2>&1
480 /usr/local/bin/qosd $qossettings {'IMQ_DEV'} >/dev/null 2>&1
482 for i in \$(ls \ $RRDLOG /class_*.rrd); do
483 rrdtool update \ $i \$(date + %s ): 2>/dev/null
486 echo "Quality of Service was successfully started!"
490 ### RESET EVERYTHING TO A KNOWN STATE
491 killall qosd >/dev/null 2>&1
494 tc qdisc del dev $qossettings {'RED_DEV'} root >/dev/null 2>&1
495 tc qdisc del dev $qossettings {'RED_DEV'} ingress >/dev/null 2>&1
496 tc qdisc add root dev $qossettings {'RED_DEV'} fq_codel >/dev/null 2>&1
497 tc qdisc del dev $qossettings {'IMQ_DEV'} root >/dev/null 2>&1
498 tc qdisc del dev $qossettings {'IMQ_DEV'} ingress >/dev/null 2>&1
499 tc qdisc add root dev $qossettings {'IMQ_DEV'} fq_codel >/dev/null 2>&1
501 ip link set $qossettings {'IMQ_DEV'} down >/dev/null 2>&1
502 ip link del $qossettings {'IMQ_DEV'} >/dev/null 2>&1
504 # REMOVE & FLUSH CHAINS
505 iptables -t mangle --delete POSTROUTING -o $qossettings {'RED_DEV'} -j QOS-OUT >/dev/null 2>&1
506 iptables -t mangle --delete PREROUTING -i $qossettings {'RED_DEV'} -j QOS-INC >/dev/null 2>&1
507 iptables -t mangle --flush QOS-OUT >/dev/null 2>&1
508 iptables -t mangle --delete-chain QOS-OUT >/dev/null 2>&1
509 iptables -t mangle --flush QOS-INC >/dev/null 2>&1
510 iptables -t mangle --delete-chain QOS-INC >/dev/null 2>&1
512 rmmod sch_htb >/dev/null 2>&1
514 for i in \$(ls \ $RRDLOG /class_*.rrd); do
515 rrdtool update \ $i \$(date + %s ):
518 echo "Quality of Service was successfully cleared!"
521 echo -n "Generating the QoS-Scripts..."
522 /usr/bin/perl /var/ipfire/qos/bin/makeqosscripts.pl > /var/ipfire/qos/bin/qos.sh
527 ### FIRST CLEAR EVERYTHING
538 ############################################################################################################################
539 ############################################################################################################################