summaryrefslogtreecommitdiff
path: root/lib/Vyatta/Qos/RandomDetect.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Vyatta/Qos/RandomDetect.pm')
-rw-r--r--lib/Vyatta/Qos/RandomDetect.pm143
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;