From 6d9cca1cffbe56c8b4645e39dc55b30bb93a9ba2 Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Sat, 29 Dec 2012 10:58:11 -0800 Subject: [PATCH] fq_codel Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Tc.pm | 124 ++++++++++++++++--- Shorewall/manpages/shorewall-tcclasses.xml | 91 +++++++++++++- Shorewall6/manpages/shorewall6-tcclasses.xml | 88 +++++++++++++ 3 files changed, 284 insertions(+), 19 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Tc.pm b/Shorewall/Perl/Shorewall/Tc.pm index 6e08b7d4f..33e445094 100644 --- a/Shorewall/Perl/Shorewall/Tc.pm +++ b/Shorewall/Perl/Shorewall/Tc.pm @@ -1129,6 +1129,17 @@ my %validredoptions = ( min => RED_INTEGER, ecn => RED_NONE, ); +use constant { CODEL_INTEGER => 1, CODEL_INTERVAL => 2, CODEL_NONE => 3 }; + +my %validcodeloptions = ( flows => CODEL_INTEGER, + target => CODEL_INTERVAL, + interval => CODEL_INTERVAL, + limit => CODEL_INTEGER, + ecn => CODEL_NONE, + noecn => CODEL_NONE, + quantum => CODEL_INTEGER + ); + sub validate_filter_priority( $$ ) { my ( $priority, $kind ) = @_; @@ -1303,6 +1314,7 @@ sub validate_tc_class( ) { fatal_error "RATE ($rate) exceeds CEIL ($ceil)" if $rate && $ceil && $rate > $ceil; my ( $red, %redopts ) = ( 0, ( avpkt => 1000 ) ); + my ( $codel, %codelopts ) = ( 0, ( ) ); unless ( $options eq '-' ) { for my $option ( split_list1 "\L$options", 'option' ) { @@ -1352,8 +1364,9 @@ sub validate_tc_class( ) { 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 'red='" if $tcref->{red}; + 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}; + fatal_error "The 'pfifo' option is not allowed with 'fq_codel='" if $tcref->{fq_codel}; $tcref->{pfifo} = 1; } elsif ( $option =~ /^occurs=(\d+)$/ ) { my $val = $1; @@ -1375,8 +1388,9 @@ sub validate_tc_class( ) { 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}; + 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}; + fatal_error "The 'pfifo' option is not allowed with 'fq_codel='" if $tcref->{fq_codel}; $tcref->{red} = 1; my $opttype; @@ -1425,6 +1439,61 @@ sub validate_tc_class( ) { 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; + } elsif ( $option =~ /^fq_codel(?:=.+)?$/ ) { + fatal_error "The 'fq_codel' option is not allowed with 'red='" if $tcref->{red}; + fatal_error "The 'fq_codel' option is not allowed with 'pfifo'" if $tcref->{pfifo}; + $tcref->{fq_codel} = 1; + my $opttype; + + $option =~ s/fq_codel=?//; + + for my $codelopt ( split_list( $option , q('fq_codel' option list) ) ) { + # + # $2 -------------------- + # $1 ------ | $3 ----------- | + # | | | | | | + if ( $codelopt =~ /^([a-z]+) (?:= ((?:\d+)(ms)?))?$/x ) + { + fatal_error "Invalid CODEL option ($1)" unless $opttype = $validcodeloptions{$1}; + if ( $2 ) { + # + # '=' supplied + # + fatal_error "The $1 option does not take a value" if $opttype == CODEL_NONE; + if ( $3 ) { + # + # Rate + # + fatal_error "The $1 option requires an integer value" if $opttype == CODEL_INTEGER; + } else { + # + # Interval value + # + fatal_error "The $1 option requires an interval value" if $opttype == CODEL_INTERVAL; + } + } else { + # + # No value supplied + # + fatal_error "The $1 option requires a value" unless $opttype == CODEL_NONE; + } + + $codelopts{$1} = $2; + } else { + fatal_error "Invalid fq_codel option specification ($codelopt)"; + } + } + + if ( exists $codelopts{ecn} ) { + fatal_error "The 'ecn' and 'noecn' fq_codel options are mutually exclusive" if exists $codelopts{noecn}; + $codelopts{ecn} = 1; + } elsif ( exists $codelopts{noecn} ) { + $codelopts{noecn} = 1; + } else { + $codelopts{ecn} = 1; + } + + $tcref->{codelopts} = \%codelopts; } else { fatal_error "Unknown option ($option)"; } @@ -1443,19 +1512,21 @@ sub validate_tc_class( ) { while ( --$occurs ) { fatal_error "Duplicate class number ($classnumber)" if $tcclasses{$device}{++$classnumber}; - $tcclasses{$device}{$classnumber} = { tos => [] , - rate => $tcref->{rate} , - ceiling => $tcref->{ceiling} , - priority => $tcref->{priority} , - mark => 0 , - markprio => $markprio , - flow => $tcref->{flow} , - pfifo => $tcref->{pfifo}, - occurs => 0, - parent => $parentclass, - limit => $tcref->{limit}, - red => $tcref->{red}, - redopts => $tcref->{redopts}, + $tcclasses{$device}{$classnumber} = { tos => [] , + rate => $tcref->{rate} , + ceiling => $tcref->{ceiling} , + priority => $tcref->{priority} , + mark => 0 , + markprio => $markprio , + flow => $tcref->{flow} , + pfifo => $tcref->{pfifo}, + occurs => 0, + parent => $parentclass, + limit => $tcref->{limit}, + red => $tcref->{red}, + redopts => $tcref->{redopts}, + fq_codel => $tcref->{fq_codel}, + codelopts => $tcref->{codelopts}, }; push @tcclasses, "$device:$classnumber"; }; @@ -2063,8 +2134,25 @@ sub process_traffic_shaping() { } emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: red${options}" ); + } elsif ( $tcref->{fq_codel} ) { + 1 while $devnums[++$sfq]; + $sfqinhex = in_hexp( $sfq); - } elsif ( $tcref->{leaf} && ! $tcref->{pfifo} ) { + my ( $options, $codelopts ) = ( '', $tcref->{codelopts} ); + + while ( my ( $option, $type ) = each %validcodeloptions ) { + if ( my $value = $codelopts->{$option} ) { + if ( $type == CODEL_NONE ) { + $options = join( ' ', $options, $option ); + } else { + $options = join( ' ', $options, $option, $value ); + } + } + } + + emit( "run_tc qdisc add dev $device parent $classid handle $sfqinhex: fq_codel${options}" ); + + } elsif ( ! $tcref->{pfifo} ) { 1 while $devnums[++$sfq]; $sfqinhex = in_hexp( $sfq); diff --git a/Shorewall/manpages/shorewall-tcclasses.xml b/Shorewall/manpages/shorewall-tcclasses.xml index ca5c455d8..b1566bb80 100644 --- a/Shorewall/manpages/shorewall-tcclasses.xml +++ b/Shorewall/manpages/shorewall-tcclasses.xml @@ -501,7 +501,8 @@ Detection) queuing discipline rather than SFQ. See tc-red (8) for additional information. - Allowable redoptions are: + Allowable redoptions + are: @@ -605,6 +606,94 @@ + + + fq_codel[=(codeloption=value, + ...)] + + + Added in Shorewall 4.5.12. When specified for a leaf + class, causes the class to use the FQ_CODEL (Fair-queuing + Controlled Delay) queuing discipline rather than SFQ. See + tc-fq_codel (8) for additional information. + + Allowable codeloptions + are: + + + + limit + + + hard limit on the real queue size. When this limit + is reached, incoming packets are dropped. If the value + is lowered, packets are dropped so that the new limit is + met. Default is 1000 packets. + + + + + flows + + + is the number of flows into which the incoming + packets are classified. Due to the stochastic nature of + hashing, multiple flows may end up being hashed into the + same slot. Newer flows have priority over older ones. + This parameter can be set only at load time since memory + has to be allocated for the hash table. Default value is + 1024. + + + + + target + + + is the acceptable minimum standing/persistent + queue delay. This minimum delay is identified by + tracking the local minimum queue delay that packets + experience. Default and recommended value is 5ms. + + + + + interval + + + is used to ensure that the measured minimum delay + does not become too stale. The minimum delay must be + experienced in the last epoch of length interval. It + should be set on the order of the worst-case RTT through + the bottleneck to give endpoints sufficient time to + react. Default value is 100ms. + + + + + quantum + + + is the number of bytes used as 'deficit' in the + fair queuing algorithm. Default is set to 1514 bytes + which corresponds to the Ethernet MTU plus the hardware + header length of 14 bytes. + + + + + ecn | noecn + + + can be used to mark packets instead of dropping + them. If ecn has been enabled, noecn can be used to turn + it off and vice-a-versa. By default, ecn is + enabled. + + + + + diff --git a/Shorewall6/manpages/shorewall6-tcclasses.xml b/Shorewall6/manpages/shorewall6-tcclasses.xml index 591b4b362..b9aa9eb6b 100644 --- a/Shorewall6/manpages/shorewall6-tcclasses.xml +++ b/Shorewall6/manpages/shorewall6-tcclasses.xml @@ -557,6 +557,94 @@ + + + fq_codel[=(codeloption=value, + ...)] + + + Added in Shorewall 4.5.12. When specified for a leaf + class, causes the class to use the FQ_CODEL (Fair-queuing + Controlled Delay) queuing discipline rather than SFQ. See + tc-fq_codel (8) for additional information. + + Allowable codeloptions + are: + + + + limit + + + hard limit on the real queue size. When this limit + is reached, incoming packets are dropped. If the value + is lowered, packets are dropped so that the new limit is + met. Default is 1000 packets. + + + + + flows + + + is the number of flows into which the incoming + packets are classified. Due to the stochastic nature of + hashing, multiple flows may end up being hashed into the + same slot. Newer flows have priority over older ones. + This parameter can be set only at load time since memory + has to be allocated for the hash table. Default value is + 1024. + + + + + target + + + is the acceptable minimum standing/persistent + queue delay. This minimum delay is identified by + tracking the local minimum queue delay that packets + experience. Default and recommended value is 5ms. + + + + + interval + + + is used to ensure that the measured minimum delay + does not become too stale. The minimum delay must be + experienced in the last epoch of length interval. It + should be set on the order of the worst-case RTT through + the bottleneck to give endpoints sufficient time to + react. Default value is 100ms. + + + + + quantum + + + is the number of bytes used as 'deficit' in the + fair queuing algorithm. Default is set to 1514 bytes + which corresponds to the Ethernet MTU plus the hardware + header length of 14 bytes. + + + + + ecn | noecn + + + can be used to mark packets instead of dropping + them. If ecn has been enabled, noecn can be used to turn + it off and vice-a-versa. By default, ecn is + enabled. + + + + +