diff options
6 files changed, 121 insertions, 25 deletions
diff --git a/scripts/VyattaQosTrafficShaper.pm b/scripts/VyattaQosTrafficShaper.pm index 1fe92aa..1c35ba2 100644 --- a/scripts/VyattaQosTrafficShaper.pm +++ b/scripts/VyattaQosTrafficShaper.pm @@ -17,6 +17,8 @@ _ceiling => undef, _burst => undef, _match => undef, + _limit => undef, + _qdisc => undef, ); sub new { @@ -24,8 +26,10 @@ my $class = ref($that) || $that; my $self = {%fields}; + $self->{id} = $id; + bless $self, $class; - $self->_define($config, $id); + $self->_define($config); return $self; } @@ -38,10 +42,12 @@ $self->{_rate} = $config->returnValue("bandwidth"); defined $self->{_rate} or die "Bandwidth not defined for class $id\n"; - $self->{id} = $id; $self->{_priority} = $config->returnValue("priority"); $self->{_ceiling} = $config->returnValue("ceiling"); $self->{_burst} = $config->returnValue("burst"); + $self->{_limit} = $config->returnValue("queue-limit"); + $self->{_qdisc} = $config->returnValue("queue-type"); + $self->{dsmark} = VyattaQosUtil::getDsfield($config->returnValue("set-dscp")); foreach my $match ($config->listNodes("match")) { @@ -79,7 +85,7 @@ my $ceil = _getPercentRate($self->{_ceiling}, $speed); if ($rate > $speed) { - die "Bandwidth for class $self->{id} ($rate) > overall limit ($speed)\n"; + die "Bandwidth for class $self->{id} ($rate) > total ($speed)\n"; } # create the class @@ -88,32 +94,105 @@ } } + sub prioQdisc { + my ($self, $out, $dev, $rate) = @_; + my $prio_id = 0x4000 + $self->{id}; + my $limit = $self->{_limit}; + + print {$out} "handle $prio_id: prio\n"; + + if ($limit) { + foreach my $i (qw/1 2 3/) { + printf {$out} "qdisc add dev %s parent %x:%d pfifo limit %d\n", + $dev, $prio_id, $i, $limit; + } + } + } + + sub sfqQdisc { + my ($self, $out, $dev, $rate ) = @_; + + print ${out} "sfq"; + print ${out} " limit $self->{_limit}" if ($self->{_limit}); + print ${out} "\n"; + } + + sub fifoQdisc { + my ($self, $out, $dev, $rate) = @_; + + print ${out} "pfifo"; + print ${out} " limit $self->{_limit}" if ($self->{_limit}); + print ${out} "\n"; + } + + # Red is has way to many configuration options + # make some assumptions to make this sane (based on LARTC) + # average size := 1000 bytes + # limit := queue-limit * average + # max := limit / 8 + # min := max / 3 + # burst := (2 * min + max) / (3 * average) + sub redQdisc { + my ($self, $out, $dev, $rate) = @_; + my $limit = $self->{_limit}; + my $avg = 1000; + my $qlimit; + + if (defined $limit) { + $qlimit = $limit * $avg; # red limit in bytes + } else { + # rate is in bits/sec so queue-limit = 8 * 500ms * rate + $qlimit = $rate / 2; + } + my $qmax = $qlimit / 8; + my $qmin = $qmax / 3; + + printf ${out} "red limit %d min %d max %d avpkt %d", + $qlimit, $qmin, $qmax, $avg; + printf ${out} " burst %d probability 0.02 bandwidth %d ecn\n", + (2 * $qmin + $qmax) / (3 * $avg), $rate / 1000; + } + + my %qdiscOptions = ( + 'priority' => \&prioQdisc, + 'fair-queue' => \&sfqQdisc, + 'random-detect' => \&redQdisc, + 'drop-tail' => \&fifoQdisc, + ); + sub htbClass { - my ( $self, $out, $parent, $dev, $speed ) = @_; + my ( $self, $out, $dev, $parent, $speed ) = @_; my $rate = _getPercentRate($self->{_rate}, $speed); my $ceil = _getPercentRate($self->{_ceiling}, $speed); - my $id = sprintf "%04x", $self->{id}; - print ${out} "class add dev $dev parent $parent:1 classid $parent:$id" - . " htb rate $rate"; + + printf ${out} "class add dev %s parent %x:1 classid %x:%x htb rate %s", + $dev, $parent, $parent, $self->{id}, $rate; print ${out} " burst $self->{_burst}" if ( defined $self->{_burst} ); print ${out} " prio $self->{_priority}" if ( defined $self->{_priority} ); print {$out} "\n"; # create leaf qdisc - print {$out} "qdisc add dev $dev parent $parent:$id sfq\n"; + my $q = $qdiscOptions{$self->{_qdisc}}; + if (defined $q) { + printf {$out} "qdisc add dev %s parent %x:%x ", + $dev, $parent, $self->{id}; + $q->($self, $out, $dev, $rate); + } else { + die "Unknown queue type $self->{_qdisc}\n"; + } my $matches = $self->{_match}; foreach my $match (@$matches) { - $match->filter( $out, $dev, $parent, $id ); + $match->filter( $out, $dev, $parent, $self->{id} ); } } sub dsmarkClass { my ( $self, $out, $parent, $dev ) = @_; - my $id = sprintf "%x", $self->{id}; - print ${out} "class change dev $dev classid $parent:$id dsmark"; + printf ${out} "class change dev %s classid %x:%x dsmark", + $dev, $parent, $self->{id}; if ($self->{dsmark}) { print ${out} " mask 0 value $self->{dsmark}\n"; } else { @@ -236,7 +315,7 @@ sub commands { } } - my $parent = "1"; + my $parent = 1; my $root = "root"; if ($usedsmark) { @@ -252,16 +331,17 @@ sub commands { foreach my $class (@$classes) { $class->dsmarkClass($out, "1", $dev); } - $parent = "4000"; + $parent = $indices + 1; $root = "parent 1:1" } - print {$out} "qdisc add dev $dev $root handle $parent: htb"; - printf {$out} " default %x\n", $default->{id}; - print {$out} "class add dev $dev parent $parent: classid $parent:1 htb rate $rate\n"; + printf {$out} "qdisc add dev %s %s handle %x: htb default %x\n", + $dev, $root, $parent, $default->{id}; + printf {$out} "class add dev %s parent %x: classid %x:1 htb rate %s\n", + $dev, $parent, $parent, $rate; foreach my $class (@$classes) { - $class->htbClass($out, $parent, $dev, $rate); + $class->htbClass($out, $dev, $parent, $rate); } } diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue-limit/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue-limit/node.def new file mode 100644 index 0000000..4275b7b --- /dev/null +++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue-limit/node.def @@ -0,0 +1,2 @@ +type: u32 +help: Maximum queue size (packets) diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue-type/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue-type/node.def new file mode 100644 index 0000000..295c04c --- /dev/null +++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue-type/node.def @@ -0,0 +1,10 @@ +type: txt +default: "fair-queue" +syntax:expression: $VAR(@) in "fair-queue", "priority", "drop-tail", "random-detect"; "Unknown queue-type" +help: Set the queue type for this class +comp_help:Possible completions + fair-queue\tStochastic Fair Queue (SFQ) + drop-tail\tFirst-In-First-Out (FIFO) + priority\tPriority queueing based on DSCP + random-detect\tRandom Early Detection (RED) + diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue/node.def deleted file mode 100644 index bfe4544..0000000 --- a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue/node.def +++ /dev/null @@ -1,8 +0,0 @@ -type: txt -default: "SFQ" -syntax:expression: $VAR(@) in "SFQ", "FIFO", "RED"; "Queue must be SFQ, FIFO, or RED" -help: Set the queue type for this class -comp_help:Possible completions: - FIFO Use FIFO queue - RED Random Exponential Drop - TCP friendly behaviour - SFQ Use Stochastic Fair Queue - fairness by flow (default) diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/queue-limit/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/queue-limit/node.def new file mode 100644 index 0000000..4275b7b --- /dev/null +++ b/templates/qos-policy/traffic-shaper/node.tag/default/queue-limit/node.def @@ -0,0 +1,2 @@ +type: u32 +help: Maximum queue size (packets) diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/queue-type/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/queue-type/node.def new file mode 100644 index 0000000..295c04c --- /dev/null +++ b/templates/qos-policy/traffic-shaper/node.tag/default/queue-type/node.def @@ -0,0 +1,10 @@ +type: txt +default: "fair-queue" +syntax:expression: $VAR(@) in "fair-queue", "priority", "drop-tail", "random-detect"; "Unknown queue-type" +help: Set the queue type for this class +comp_help:Possible completions + fair-queue\tStochastic Fair Queue (SFQ) + drop-tail\tFirst-In-First-Out (FIFO) + priority\tPriority queueing based on DSCP + random-detect\tRandom Early Detection (RED) + |