diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2009-05-23 08:57:19 -0700 |
---|---|---|
committer | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2009-05-23 15:19:54 -0700 |
commit | 87794a3d5ddb55af9cc298ec97b2892918e657d4 (patch) | |
tree | da72c22470325ba2b891350e7c435a0bad2a2960 /lib/Vyatta/Qos/RandomDetect.pm | |
parent | a7ec99d913b0169b987a4ebdf2d26a36670b20bb (diff) | |
download | vyatta-cfg-qos-87794a3d5ddb55af9cc298ec97b2892918e657d4.tar.gz vyatta-cfg-qos-87794a3d5ddb55af9cc298ec97b2892918e657d4.zip |
Reimplementation of WRED
Make a simpler version of WRED that acts more like Cisco.
Use Diffserv on Linux paper for example of how to use DSMARK and GRED
to achieve similar result.
Diffstat (limited to 'lib/Vyatta/Qos/RandomDetect.pm')
-rw-r--r-- | lib/Vyatta/Qos/RandomDetect.pm | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/lib/Vyatta/Qos/RandomDetect.pm b/lib/Vyatta/Qos/RandomDetect.pm new file mode 100644 index 0000000..155b669 --- /dev/null +++ b/lib/Vyatta/Qos/RandomDetect.pm @@ -0,0 +1,143 @@ +# Random Detect +# +# This Qos module uses DSMARK and GRED to provide a policy +# similar to Cisco Weighted Random Detect. +# +# See Almesberger, Werner; Hadi Salim, Jamal; Kuznetsov, Alexey +# "Differentiated Services on Linux" +# http://www.almesberger.net/cv/papers/18270721.pdf +# +# **** License **** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2008 Vyatta, Inc. +# All Rights Reserved. +# **** End License **** + +package Vyatta::Qos::RandomDetect; +use strict; +use warnings; + +require Vyatta::Config; +use Vyatta::Qos::Util qw/getRate getAutoRate getTime/; + +# default values for different precedence levels +my @default_fields = ( + { 'min-threshold' => 9, 'max-threshold' => 18, 'mark-probability' => 1/2 }, + { 'min-threshold' => 10, 'max-threshold' => 18, 'mark-probability' => 5/9 }, + { 'min-threshold' => 11, 'max-threshold' => 18, 'mark-probability' => .1 }, + { 'min-threshold' => 12, 'max-threshold' => 18, 'mark-probability' => 2/3 }, + { 'min-threshold' => 13, 'max-threshold' => 18, 'mark-probability' => .1 }, + { 'min-threshold' => 14, 'max-threshold' => 18, 'mark-probability' => 7/9 }, + { 'min-threshold' => 15, 'max-threshold' => 18, 'mark-probability' => 5/6 }, + { 'min-threshold' => 16, 'max-threshold' => 18, 'mark-probability' => 8/9 }, +); + +# Create a new instance based on config information +sub new { + my ( $that, $config, $name ) = @_; + my $level = $config->setLevel(); + + my $rate = $config->returnValue("bandwidth"); + die "$level bandwidth configuration missing" unless $rate; + my @precedence = getPrecedence( $level ); + + my $self = {}; + my $class = ref($that) || $that; + bless $self, $class; + + $self->{_rate} = $rate; + $self->{_precedence} = \@precedence; + + return $self; +} + +sub getPrecedence { + my ( $level ) = @_; + my $config = new Vyatta::Config; + my @precedence; + + for ( my $i = 0 ; $i <= 7 ; $i++ ) { + my $defaults = $default_fields[$i]; + my %param; + + $config->setLevel("$level precedence $i"); + foreach my $field (keys %$defaults) { + my $val = $config->returnValue($field); + + if ( !defined $val ) { + $param{$field} = $defaults->{$field}; + } elsif ( $field eq 'mark-probability' ) { + $param{$field} = 1 / $val; + } else { + $param{$field} = $val; + } + } + $precedence[$i] = \%param; + } + + return @precedence; +} + +sub commands { + my ( $self, $dev ) = @_; + my $root = 1; + my $precedence = $self->{_precedence}; + my $rate = getAutoRate( $self->{_rate}, $dev ); + + # 1. setup DSMARK to convert DSCP to tc_index + print "qdisc add dev eth0 root handle $root: dsmark indices 1 set_tc_index\n"; + + # 2. use tcindex filter to convert tc_index to precedence + print + "filter add dev $dev parent $root: protocol ip prio 1 tcindex mask 0xe0 shift 5\n"; + + print "qdisc add dev $dev parent $root: gred setup DPs 8 default 7\n"; + + # set VQ parameters + for ( my $i = 0 ; $i <= 7 ; $i++ ) { + my $param = $precedence->[$i]; + my $qmin = $param->{'min-threshold'}; + my $qmax = $param->{'max-threshold'}; + my $prob = $param->{'mark-probability'}; + + print "qdisc change dev $dev parent $root:$i gred"; + printf " limit %dK min %dK max %dK avpkt 1K", 4 * $qmax, $qmin, $qmax; + printf " burst %d bandwidth %d DP %d probability %f\n", + ( 2 * $qmin + $qmax ) / 3, $rate, $i, $prob; + } +} + +# Walk configuration tree and look for changed nodes +# The configuration system should do this but doesn't do it right +sub isChanged { + my ( $self, $name ) = @_; + my $config = new Vyatta::Config; + + $config->setLevel("qos-policy random-detect $name"); + + return 'bandwidth' if ( $config->isChanged('bandwidth') ); + + my %precedenceNodes = $config->listNodeStatus('precedence'); + while ( my ( $pred, $status ) = each %precedenceNodes ) { + return "precedence $pred" if ( $status ne 'static' ); + + my $defaults = $default_fields[0]; + foreach my $attr (keys %$defaults) { + return "precedence $pred $attr" + if ( $config->isChanged("precedence $pred $attr") ); + } + } + + return; # false +} + +1; |