From 6c47349689eda2dfdae08b1ce34c8c15b9b6d5b7 Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Wed, 13 Jun 2012 14:29:13 -0700 Subject: [PATCH] Support 'red' queuing discipline - Also added 'ls' support for HFSC Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Tc.pm | 124 +++++++++++++--- Shorewall/manpages/shorewall-tcclasses.xml | 143 +++++++++++++++++-- Shorewall/manpages/shorewall-tcdevices.xml | 5 +- Shorewall6/manpages/shorewall6-tcclasses.xml | 140 ++++++++++++++++-- Shorewall6/manpages/shorewall6-tcdevices.xml | 5 +- docs/traffic_shaping.xml | 14 +- 6 files changed, 392 insertions(+), 39 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Tc.pm b/Shorewall/Perl/Shorewall/Tc.pm index bff40da84..b1d276fe4 100644 --- a/Shorewall/Perl/Shorewall/Tc.pm +++ b/Shorewall/Perl/Shorewall/Tc.pm @@ -1031,6 +1031,18 @@ sub dev_by_number( $ ) { ( $dev , $devref ); } +use constant { RED_INTEGER => 1, RED_FLOAT => 2, RED_NONE => 3 }; + +my %validredoptions = ( min => RED_INTEGER, + max => RED_INTEGER, + limit => RED_INTEGER, + burst => RED_INTEGER, + avpkt => RED_INTEGER, + bandwidth => RED_INTEGER, + probability => RED_FLOAT, + ecn => RED_NONE, + ); + sub validate_tc_class( ) { my ( $devclass, $mark, $rate, $ceil, $prio, $options ) = split_line 'tcclasses file', { interface => 0, mark => 1, rate => 2, ceil => 3, prio => 4, options => 5 }; @@ -1040,6 +1052,7 @@ sub validate_tc_class( ) { my $occurs = 1; my $parentclass = 1; my $parentref; + my $lsceil = 0; fatal_error 'INTERFACE must be specified' if $devclass eq '-'; fatal_error 'CEIL must be specified' if $ceil eq '-'; @@ -1116,7 +1129,9 @@ sub validate_tc_class( ) { my $parentnum = in_hexp $parentclass; fatal_error "Unknown Parent class ($parentnum)" unless $parentref && $parentref->{occurs} == 1; fatal_error "The class ($parentnum) specifies UMAX and/or DMAX; it cannot serve as a parent" if $parentref->{dmax}; - fatal_error "The class ($parentnum) specifies flow; it cannot serve as a parent" if $parentref->{flow}; + fatal_error "The class ($parentnum) specifies 'flow'; it cannot serve as a parent" if $parentref->{flow}; + fatal_error "The class ($parentnum) specifies 'red'; it cannot serve as a parent " if $parentref->{red}; + fatal_error "The class ($parentnum) has an 'ls' curve; it cannot serve as a parent " if $parentref->{lsceil}; fatal_error "The default class ($parentnum) may not have sub-classes" if ( $devref->{default} || 0 ) == $parentclass; $parentref->{leaf} = 0; $ratemax = $parentref->{rate}; @@ -1127,16 +1142,27 @@ sub validate_tc_class( ) { my ( $umax, $dmax ) = ( '', '' ); + if ( $ceil =~ /^(.+):(.+)/ ) { + fatal_error "An LS rate may only be specified for HFSC classes" unless $devref->{qdisc} eq 'hfsc'; + $lsceil = $1; + $ceil = $2; + } + if ( $devref->{qdisc} eq 'hfsc' ) { - ( my $trate , $dmax, $umax , my $rest ) = split ':', $rate , 4; + if ( $rate eq '-' ) { + fatal_error 'A RATE must be supplied' unless $lsceil; + $rate = 0; + } else { + ( my $trate , $dmax, $umax , my $rest ) = split ':', $rate , 4; - fatal_error "Invalid RATE ($rate)" if defined $rest; + fatal_error "Invalid RATE ($rate)" if defined $rest; - $rate = convert_rate ( $ratemax, $trate, 'RATE', $ratename ); - $dmax = convert_delay( $dmax ); - $umax = convert_size( $umax ); - fatal_error "DMAX must be specified when UMAX is specified" if $umax && ! $dmax; - $parentclass ||= 1; + $rate = convert_rate ( $ratemax, $trate, 'RATE', $ratename ); + $dmax = convert_delay( $dmax ); + $umax = convert_size( $umax ); + fatal_error "DMAX must be specified when UMAX is specified" if $umax && ! $dmax; + $parentclass ||= 1; + } } else { $rate = convert_rate ( $ratemax, $rate, 'RATE' , $ratename ); } @@ -1154,6 +1180,7 @@ sub validate_tc_class( ) { umax => $umax , dmax => $dmax , ceiling => convert_rate( $ceilmax, $ceil, 'CEIL' , $ceilname ) , + lsceil => $lsceil ? convert_rate( $ceilmax, $lsceil, 'CEIL', 'LSCEIL' ) : 0, priority => $prio eq '-' ? 1 : $prio , mark => $markval , flow => '' , @@ -1169,6 +1196,8 @@ sub validate_tc_class( ) { fatal_error "RATE ($tcref->{rate}) exceeds CEIL ($tcref->{ceiling})" if $tcref->{rate} > $tcref->{ceiling}; + my ( $red, %redopts ) = ( 0, ( avpkt => 1000 ) ); + unless ( $options eq '-' ) { for my $option ( split_list1 "\L$options", 'option' ) { my $optval = $tosoptions{$option}; @@ -1192,9 +1221,11 @@ sub validate_tc_class( ) { push @{$tcref->{tos}}, $option; } elsif ( $option =~ /^flow=(.*)$/ ) { fatal_error "The 'flow' option is not allowed with 'pfifo'" if $tcref->{pfifo}; + fatal_error "The 'flow' option is not allowed with 'red'" if $tcref->{red}; $tcref->{flow} = process_flow $1; } elsif ( $option eq 'pfifo' ) { - fatal_error "The 'pfifo'' option is not allowed with 'flow='" if $tcref->{flow}; + fatal_error "The 'pfifo' option is not allowed with 'flow='" if $tcref->{flow}; + fatal_error "The 'pfifo' option is not allowed with 'red='" if $tcref->{red}; $tcref->{pfifo} = 1; } elsif ( $option =~ /^occurs=(\d+)$/ ) { my $val = $1; @@ -1215,6 +1246,31 @@ sub validate_tc_class( ) { warning_message "limit ignored with pfifo queuing" if $tcref->{pfifo}; fatal_error "Invalid limit ($1)" if $1 < 3 || $1 > 128; $tcref->{limit} = $1; + } elsif ( $option =~ s/^red=// ) { + fatal_error "The 'red=' option is not allowed with 'flow='" if $tcref->{flow}; + fatal_error "The 'red=' option is not allowed with 'pfifo'" if $tcref->{pfifo}; + $tcref->{red} = 1; + my $opttype; + for my $redopt ( split_list( $option , q('red' option list) ) ) { + if ( $redopt =~ /^([a-z]+)(?:=((0?\.)?(\d{1,8})))?$/ ) { + fatal_error "Invalid 'red' option ($1)" unless $opttype = $validredoptions{$1}; + fatal_error "The $1 option requires a value" unless $opttype == RED_NONE || $2; + fatal_error "The $1 option requires a value 0 < value < 1" if $opttype == RED_FLOAT && ! $3; + fatal_error "The $1 option requires an integer value" if $opttype == RED_INTEGER && $3; + $redopts{$1} = $2; + } else { + fatal_error "Invalid 'red' option specification ($redopt)"; + } + } + + for ( qw/ limit min max avpkt burst probability / ) { + fatal_error "The $_ 'red' option is required" unless $redopts{$_}; + } + + fatal_error "The 'max' red option must be at least 2 * 'min'" unless $redopts{max} >= 2 * $redopts{min}; + fatal_error "The 'limit' red option must be at least 2 * 'max'" unless $redopts{limit} >= 2 * $redopts{min}; + $redopts{ecn} = 1 if exists $redopts{ecn}; + $tcref->{redopts} = \%redopts; } else { fatal_error "Unknown option ($option)"; } @@ -1246,6 +1302,8 @@ sub validate_tc_class( ) { occurs => 0, parent => $parentclass, limit => $tcref->{limit}, + red => $tcref->{red}, + redopts => $tcref->{redopts}, }; push @tcclasses, "$device:$classnumber"; }; @@ -1800,7 +1858,9 @@ sub process_traffic_shaping() { my $mark = $tcref->{mark}; my $devicenumber = in_hexp $devref->{number}; my $classid = join( ':', $devicenumber, $classnum); - my $rate = "$tcref->{rate}kbit"; + my $rawrate = $tcref->{rate}; + my $rate = "${rawrate}kbit"; + my $lsceil = $tcref->{lsceil}; my $quantum = calculate_quantum $rate, calculate_r2q( $devref->{out_bandwidth} ); $classids{$classid}=$device; @@ -1814,23 +1874,49 @@ sub process_traffic_shaping() { emit ( "run_tc class add dev $device parent $devicenumber:$parent classid $classid htb rate $rate ceil $tcref->{ceiling}kbit prio $tcref->{priority} \$${dev}_mtu1 quantum \$quantum" ); } else { my $dmax = $tcref->{dmax}; + my $rule = "run_tc class add dev $device parent $devicenumber:$parent classid $classid hfsc"; if ( $dmax ) { my $umax = $tcref->{umax} ? "$tcref->{umax}b" : "\${${dev}_mtu}b"; - emit ( "run_tc class add dev $device parent $devicenumber:$parent classid $classid hfsc sc umax $umax dmax ${dmax}ms rate $rate ul rate $tcref->{ceiling}kbit" ); + $rule .= " sc umax $umax dmax ${dmax}ms"; + $rule .= " rate $rate" if $rawrate; } else { - emit ( "run_tc class add dev $device parent $devicenumber:$parent classid $classid hfsc sc rate $rate ul rate $tcref->{ceiling}kbit" ); + $rule .= " sc rate $rate" if $rawrate; } + + $rule .= " ls rate ${lsceil}kbit" if $lsceil; + + emit ( "$rule ul rate $tcref->{ceiling}kbit" ); } - if ( $tcref->{leaf} && ! $tcref->{pfifo} ) { - 1 while $devnums[++$sfq]; + if ( $tcref->{leaf} ) { + if ( $tcref->{red} ) { + 1 while $devnums[++$sfq]; + $sfqinhex = in_hexp( $sfq); - $sfqinhex = in_hexp( $sfq); - if ( $devref->{qdisc} eq 'htb' ) { - emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: sfq quantum \$quantum limit $tcref->{limit} perturb 10" ); - } else { - emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: sfq limit $tcref->{limit} perturb 10" ); + my ( $options, $redopts ) = ( '', $tcref->{redopts} ); + + while ( my ( $option, $type ) = each %validredoptions ) { + if ( my $value = $redopts->{$option} ) { + if ( $type == RED_NONE ) { + $options = join( ' ', $options, $option ) if $value; + } else { + $options = join( ' ', $options, $option, $value ); + } + } + } + + emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: red${options}" ); + + } elsif ( $tcref->{leaf} && ! $tcref->{pfifo} ) { + 1 while $devnums[++$sfq]; + + $sfqinhex = in_hexp( $sfq); + if ( $devref->{qdisc} eq 'htb' ) { + emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: sfq quantum \$quantum limit $tcref->{limit} perturb 10" ); + } else { + emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: sfq limit $tcref->{limit} perturb 10" ); + } } } # diff --git a/Shorewall/manpages/shorewall-tcclasses.xml b/Shorewall/manpages/shorewall-tcclasses.xml index f6c3b49e9..14b5a19de 100644 --- a/Shorewall/manpages/shorewall-tcclasses.xml +++ b/Shorewall/manpages/shorewall-tcclasses.xml @@ -175,7 +175,7 @@ RATE - - rate[:dmax[:umax]] + {-|rate[:dmax[:umax]]} The minimum bandwidth this class should get, when the traffic @@ -185,11 +185,12 @@ class exceed the CEIL of the parent class, things don't work well. - When using the HFSC queuing discipline, leaf classes may - specify dmax, the maximum delay in - milliseconds that the first queued packet for this class should - experience. May be expressed as an integer, optionally followed by - 'ms' with no intervening white space (e.g., 10ms). + When using the HFSC queuing discipline, this column specify + the real-time (RT) service curve. leaf classes may specify + dmax, the maximum delay in milliseconds + that the first queued packet for this class should experience. May + be expressed as an integer, optionally followed by 'ms' with no + intervening white space (e.g., 10ms). HFSC leaf classes may also specify umax, the largest packet expected in this @@ -198,12 +199,18 @@ followed by 'b' with no intervening white space (e.g., 800b). umax may only be given if dmax is also given. + + Beginning with Shorewall 4.5.6, HFSC classes may omit this + column (e.g, '-' in the column), provided that an + lsrate is specified (see CEIL below). + These rates are used to arbitrate between classes of the same + priority. CEIL - - rate + [lsrate:]rate The maximum bandwidth this class is allowed to use when the @@ -214,6 +221,9 @@ here for setting the maximum bandwidth to the RATE of the parent class, or the OUT-BANDWIDTH of the device if there is no parent class. + + Beginning with Shorewall 4.5.6, you can also specify an + lsrate (link sharing rate). @@ -253,7 +263,7 @@ This is the default class for that interface where all traffic should go, that is not classified otherwise. - + You must define - + This option is only valid for ONE class per @@ -430,6 +440,119 @@ assumed. + + + red=(redoption=value, + ...) + + + Added in Shorewall 4.5.6. When specified on a leaf + class, causes the class to use the red queuing discipline + rather than SFQ. See tc-red (8) for additional + information. + + Allowable redoptions are: + + + + min + + + Average queue size at which marking becomes a + possibility. + + + + + max + + + At this average queue size, the marking + probability is maximal. Must be at least twice + min to prevent synchronous + retransmits, higher for low min. + + + + + probability + + + Maximum probability for marking, specified as a + floating point number from 0.0 to 1.0. Suggested values + are 0.01 or 0.02 (1 or 2%, respectively). + + + + + limit + + + Hard limit on the real (not average) queue size in + bytes. Further packets are dropped. Should be set higher + than + max+burst. + It is advised to set this a few times higher than + max. Shorewall requires that + max be at least twice + min. + + + + + burst + + + Used for determining how fast the average queue + size is influenced by the real queue size. Larger values + make the calculation more sluggish, allowing longer + bursts of traffic before marking starts. Real life + experiments support the following guide‐ line: + (min+min+max)/(3*avpkt). + + + + + + avpkt + + + Optional. Specified in bytes. Used with burst to + determine the time constant for average queue size + calculations. 1000 is a good value and is the Shorewall + default. + + + + + bandwidth + + + Optional. This rate is used for calculating the + average queue size after some idle time. Should be set + to the bandwidth of your interface. Does not mean that + RED will shape for you! + + + + + ecn + + + RED can either 'mark' or 'drop'. Explicit + Congestion Notification allows RED to notify remote + hosts that their rate exceeds the amount of bandwidth + available. Non-ECN capable hosts can only be notified by + dropping a packet. If this parameter is specified, + packets which indicate that their hosts honor ECN will + only be marked and not dropped, unless the queue size + hits limit bytes. Needs a tc binary with RED support + compiled in. Recommended. + + + + + @@ -503,6 +626,8 @@ http://shorewall.net/configuration_file_basics.htm#Pairs + tc-hfsc (7) + shorewall(8), shorewall-accounting(5), shorewall-actions(5), shorewall-blacklist(5), shorewall-hosts(5), shorewall_interfaces(5), shorewall-ipsets(5), shorewall-maclist(5), shorewall-masq(5), diff --git a/Shorewall/manpages/shorewall-tcdevices.xml b/Shorewall/manpages/shorewall-tcdevices.xml index 125ac7b2f..36b1f8583 100644 --- a/Shorewall/manpages/shorewall-tcdevices.xml +++ b/Shorewall/manpages/shorewall-tcdevices.xml @@ -200,7 +200,8 @@ - Shorewall normally uses the Hierarchical Token Bucket queuing discipline. When is specified, the Hierarchical - Fair Service Curves discipline is used instead. + Fair Service Curves discipline is used instead (see + tc-hfsc (7)). linklayer - Added in Shorewall 4.5.6. Type of link (ethernet, atm, adsl). When specified, @@ -276,6 +277,8 @@ See ALSO + tc-hfsc (7) + http://shorewall.net/traffic_shaping.htm diff --git a/Shorewall6/manpages/shorewall6-tcclasses.xml b/Shorewall6/manpages/shorewall6-tcclasses.xml index b63db67c1..6c15aa72e 100644 --- a/Shorewall6/manpages/shorewall6-tcclasses.xml +++ b/Shorewall6/manpages/shorewall6-tcclasses.xml @@ -171,7 +171,7 @@ RATE - - rate[:dmax[:umax]] + {-|rate[:dmax[:umax]]} The minimum bandwidth this class should get, when the traffic @@ -181,11 +181,12 @@ class exceed the CEIL of the parent class, things don't work well. - When using the HFSC queuing discipline, leaf classes may - specify dmax, the maximum delay in - milliseconds that the first queued packet for this class should - experience. May be expressed as an integer, optionally followed by - 'ms' with no intervening white space (e.g., 10ms). + When using the HFSC queuing discipline, this column specify + the real-time (RT) service curve. leaf classes may specify + dmax, the maximum delay in milliseconds + that the first queued packet for this class should experience. May + be expressed as an integer, optionally followed by 'ms' with no + intervening white space (e.g., 10ms). HFSC leaf classes may also specify umax, the largest packet expected in this @@ -194,12 +195,18 @@ followed by 'b' with no intervening white space (e.g., 800b). umax may only be given if dmax is also given. + + Beginning with Shorewall 4.5.6, HFSC classes may omit this + column (e.g, '-' in the column), provided that an + lsrate is specified (see CEIL below). + These rates are used to arbitrate between classes of the same + priority. CEIL - - rate + [lsrate:]rate The maximum bandwidth this class is allowed to use when the @@ -210,6 +217,9 @@ here for setting the maximum bandwidth to the RATE of the parent class, or the OUT-BANDWIDTH of the device if there is no parent class. + + Beginning with Shorewall 4.5.6, you can also specify an + lsrate (link sharing rate). @@ -304,7 +314,7 @@ limited to 64 bytes because we want only packets WITHOUT payload to match. - + This option is only valid for ONE class per @@ -381,6 +391,118 @@ assumed. + + + red=(redoption=value, + ...) + + + Added in Shorewall 4.5.6. When specified on a leaf + class, causes the class to use the red queuing discipline + rather than SFQ. See tc-red (8) for additional + information. + + Allowable redoptions are: + + + + min + + + Average queue size at which marking becomes a + possibility. + + + + + max + + + At this average queue size, the marking + probability is maximal. Must be at least twice + min to prevent synchronous + retransmits, higher for low min. + + + + + probability + + + Maximum probability for marking, specified as a + floating point number from 0.0 to 1.0. Suggested values + are 0.01 or 0.02 (1 or 2%, respectively). + + + + + limit + + + Hard limit on the real (not average) queue size in + bytes. Further packets are dropped. Should be set higher + than + max+burst. + It is advised to set this a few times higher than + max. Shorewall requires that + max be at least twice + min. + + + + + burst + + + Used for determining how fast the average queue + size is influenced by the real queue size. Larger values + make the calculation more sluggish, allowing longer + bursts of traffic before marking starts. Real life + experiments support the following guide‐ line: + (min+min+max)/(3*avpkt). + + + + + avpkt + + + Optional. Specified in bytes. Used with burst to + determine the time constant for average queue size + calculations. 1000 is a good value and is the Shorewall + default. + + + + + bandwidth + + + Optional. This rate is used for calculating the + average queue size after some idle time. Should be set + to the bandwidth of your interface. Does not mean that + RED will shape for you! + + + + + ecn + + + RED can either 'mark' or 'drop'. Explicit + Congestion Notification allows RED to notify remote + hosts that their rate exceeds the amount of bandwidth + available. Non-ECN capable hosts can only be notified by + dropping a packet. If this parameter is specified, + packets which indicate that their hosts honor ECN will + only be marked and not dropped, unless the queue size + hits limit bytes. Needs a tc binary with RED support + compiled in. Recommended. + + + + + @@ -448,6 +570,8 @@ See ALSO + tc-hfsc (7) + http://shorewall.net/traffic_shaping.htm diff --git a/Shorewall6/manpages/shorewall6-tcdevices.xml b/Shorewall6/manpages/shorewall6-tcdevices.xml index 8f0b0eb83..3dc2584a0 100644 --- a/Shorewall6/manpages/shorewall6-tcdevices.xml +++ b/Shorewall6/manpages/shorewall6-tcdevices.xml @@ -201,7 +201,8 @@ - Shorewall normally uses the Hierarchical Token Bucket queuing discipline. When is specified, the Hierarchical - Fair Service Curves discipline is used instead. + Fair Service Curves discipline is used instead(see + tc-hfsc (7)). linklayer - Added in Shorewall 4.5.6. Type of link (ethernet, atm, adsl). When specified, @@ -278,6 +279,8 @@ See ALSO + tc-hfsc (7) + http://shorewall.net/traffic_shaping.htm diff --git a/docs/traffic_shaping.xml b/docs/traffic_shaping.xml index 7b0800e9e..fb466bc24 100644 --- a/docs/traffic_shaping.xml +++ b/docs/traffic_shaping.xml @@ -431,7 +431,7 @@ linklayer - Added in Shorewall 4.5.6. Type of link (ethernet, atm, + Added in Shorewall 4.5.6. Type of link (ethernet, atm, adsl). When specified, causes scheduler packet size manipulation as described in tc-stab (8). When this option is given, the following options may also be given after @@ -792,6 +792,18 @@ ppp0 6000kbit 500kbit number must be > 2 and less than 128. If not specified, the value 127 is assumed + + + red=(redoption,...) - Added in + Shorewall 4.5.6. When specified on a leaf class, causes the + class to use the red queuing discipline rather than SFQ. See + tc-red (8) for additional information. + + See shorewall-tcdevices + (5) for a description of the allowable + redoptions. +