summaryrefslogtreecommitdiff
path: root/scripts/VyattaQosTrafficShaper.pm
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-01-30 12:19:39 -0800
committerStephen Hemminger <stephen.hemminger@vyatta.com>2008-01-30 12:19:39 -0800
commit86fc4e7801919a1da123f34500218a69a30c2059 (patch)
treeb74d8bc3df7acc298420667710f4d60447504dff /scripts/VyattaQosTrafficShaper.pm
downloadvyatta-cfg-qos-86fc4e7801919a1da123f34500218a69a30c2059.tar.gz
vyatta-cfg-qos-86fc4e7801919a1da123f34500218a69a30c2059.zip
Initial version of vyatta-cfg-qosdebian/0.1
This the initial checkin prior to integration
Diffstat (limited to 'scripts/VyattaQosTrafficShaper.pm')
-rw-r--r--scripts/VyattaQosTrafficShaper.pm182
1 files changed, 182 insertions, 0 deletions
diff --git a/scripts/VyattaQosTrafficShaper.pm b/scripts/VyattaQosTrafficShaper.pm
new file mode 100644
index 0000000..903aeeb
--- /dev/null
+++ b/scripts/VyattaQosTrafficShaper.pm
@@ -0,0 +1,182 @@
+# Traffic shaper
+# This is a extended form of Hierarchal Token Bucket with
+# more admin friendly features. Similar in spirt to other shaper scripts
+# such as wondershaper.
+
+{
+ package ShaperClass;
+ use strict;
+ require VyattaConfig;
+ use VyattaQosMatch;
+
+ my %fields = (
+ id => undef,
+ _priority => undef,
+ _rate => undef,
+ _ceiling => undef,
+ _burst => undef,
+ _match => undef,
+ );
+
+ sub new {
+ my ( $that, $config, $id ) = @_;
+ my $class = ref($that) || $that;
+ my $self = {%fields};
+
+ bless $self, $class;
+ $self->_define($config, $id);
+
+ return $self;
+ }
+
+ sub _define {
+ my ( $self, $config, $id ) = @_;
+ my $level = $config->setLevel();
+ my @matches = ();
+
+
+ $self->{_id} = sprintf "%04x", $id;
+ $self->{_priority} = $config->returnValue("priority");
+ $self->{_rate} = $config->returnValue("rate");
+ $self->{_ceiling} = $config->returnValue("ceiling");
+ $self->{_burst} = $config->returnValue("burst");
+
+ foreach my $match ($config->listNodes("match")) {
+ $config->setLevel("$level match $match");
+ push @matches, new VyattaQosMatch($config);
+ }
+ $self->{_match} = \@matches;
+ }
+
+ sub _getPercentRate {
+ my ($rate, $speed) = @_;
+
+ if ( ! defined $rate ) {
+ return; # leave rate undef
+ }
+
+ # Rate might be a percentage of speed
+ if ( $rate =~ /%$/ ) {
+ my $percent = substr( $rate, 0, length($rate) - 1 );
+ if ( $percent < 0 || $percent > 100 ) {
+ die "Invalid percentage bandwidth\n";
+ }
+
+ $rate = ( $percent * $speed ) / 100.;
+ } else {
+ $rate = VyattaQosUtil::getRate($rate);
+ }
+
+ return $rate;
+ }
+
+ sub commands {
+ my ( $self, $out, $dev, $speed ) = @_;
+ my $rate = _getPercentRate($self->{_rate}, $speed);
+ my $ceil = _getPercentRate($self->{_ceiling}, $speed);
+ my $id = $self->{_id};
+ my $matches = $self->{_match};
+
+ die "Rate is not defined\n" if (! defined $rate );
+ die "Class $id rate $rate > shaper rate $speed\n" if ($rate > $speed);
+
+ # create the class
+ my $cmd ="class add dev $dev parent 1:1 classid 1:$id htb rate $rate";
+ if ( defined $ceil) {
+ if ($ceil < $rate ) {
+ die "Rate limit (ceiling) $ceil < base rate $rate\n";
+ }
+ $cmd .= " ceil $ceil";
+ }
+
+ $cmd .= " burst $self->{_burst}" if ( defined $self->{_burst} );
+ $cmd .= " prio $self->{_priority}" if ( defined $self->{_priority} );
+
+ print {$out} $cmd . "\n";
+
+ # create leaf qdisc
+ print {$out} "qdisc add dev $dev parent 1:$id sfq\n";
+
+ foreach my $match (@$matches) {
+ $match->filter( $out, $dev, $id );
+ }
+ }
+}
+
+package VyattaQosTrafficShaper;
+@ISA = qw/VyattaQosPolicy/;
+use strict;
+require VyattaConfig;
+use VyattaQosUtil;
+
+my $defaultId = 0x4000;
+
+my %fields = (
+ _rate => undef,
+ _classes => undef,
+);
+
+# new VyattaQosTrafficShaper($config)
+# Create a new instance based on config information
+sub new {
+ my ( $that, $config ) = @_;
+ my $self = {%fields};
+ my $class = ref($that) || $that;
+
+ bless $self, $class;
+ $self->_define($config);
+
+ return $self;
+}
+
+# Rate can be something like "auto" or "10.2mbit"
+sub _getAutoRate {
+ my ($rate, $dev) = @_;
+
+ if ( $rate eq "auto" ) {
+ my $rate = VyattaQosUtil::interfaceRate($dev);
+ if ( ! defined $rate ) {
+ die "Auto speed setting but can't get rate from $dev\n";
+ }
+ } else {
+ $rate = VyattaQosUtil::getRate($rate);
+ }
+
+ return $rate;
+}
+
+# Setup new instance.
+# Assumes caller has done $config->setLevel to "traffic-shaper $name"
+sub _define {
+ my ( $self, $config ) = @_;
+ my $level = $config->setLevel();
+ my @classes = ( );
+
+ $self->{_rate} = $config->returnValue("rate");
+
+ $config->setLevel("$level default");
+ push @classes, new ShaperClass( $config, $defaultId);
+ $config->setLevel($level);
+
+ foreach my $id ( $config->listNodes("class") ) {
+ $config->setLevel("$level class $id");
+ push @classes, new ShaperClass( $config, $id );
+ }
+ $self->{_classes} = \@classes;
+}
+
+sub commands {
+ my ( $self, $out, $dev ) = @_;
+ my $rate = _getAutoRate($self->{_rate}, $dev);
+ my $classes = $self->{_classes};
+ my @tc = ( );
+
+ print {$out} "qdisc add dev $dev root handle 1: htb default $defaultId\n";
+ print {$out} "class add dev $dev parent 1: classid 1:1 htb rate $rate\n";
+
+ foreach my $class (@$classes) {
+ $class->commands( $out, $dev, $rate );
+ }
+}
+
+1;