summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-07-15 14:13:51 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2008-07-15 14:13:51 -0700
commit81b51bb9270e77289604493761a2f7cb047bd3ea (patch)
treebc8c6d8cb285ea99ba8b4296b9b2a26b6bb4efea
parent3dd93c5175de9a4d32cadb7bb0c4f832fb14312d (diff)
downloadvyatta-cfg-qos-81b51bb9270e77289604493761a2f7cb047bd3ea.tar.gz
vyatta-cfg-qos-81b51bb9270e77289604493761a2f7cb047bd3ea.zip
Look for changes in QoS after commit
Since configuration system doesn't correctly notify on addition/deletion, have to introduce this extra verbosity to have each traffic-shaper type check for changes. Bugfix for 3452
-rw-r--r--scripts/VyattaQosFairQueue.pm16
-rw-r--r--scripts/VyattaQosRateLimiter.pm13
-rw-r--r--scripts/VyattaQosTrafficShaper.pm50
-rwxr-xr-xscripts/vyatta-qos.pl135
-rw-r--r--templates/qos-policy/node.def1
-rw-r--r--templates/qos-policy/traffic-shaper/node.def3
6 files changed, 186 insertions, 32 deletions
diff --git a/scripts/VyattaQosFairQueue.pm b/scripts/VyattaQosFairQueue.pm
index 8a9dfdf..278bb77 100644
--- a/scripts/VyattaQosFairQueue.pm
+++ b/scripts/VyattaQosFairQueue.pm
@@ -37,8 +37,8 @@ sub new {
my $class = ref($that) || $that;
my $self = {%fields};
- $self->{_perturb} = $config->returnValue("hash-interval");
- $self->{_limit} = $config->returnValue("queue-limit");
+ $self->{_perturb} = $config->returnValue('hash-interval');
+ $self->{_limit} = $config->returnValue('queue-limit');
return bless $self, $class;
}
@@ -51,4 +51,16 @@ sub commands {
print "\n";
}
+sub isChanged {
+ my ( $self, $name ) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("qos-policy fair-queue $name");
+ foreach my $attr ('hash-interval', 'queue-limit') {
+ if ($config->isChanged($attr)) {
+ return $attr
+ }
+ }
+ return undef; # false
+}
1;
diff --git a/scripts/VyattaQosRateLimiter.pm b/scripts/VyattaQosRateLimiter.pm
index 548526b..f519683 100644
--- a/scripts/VyattaQosRateLimiter.pm
+++ b/scripts/VyattaQosRateLimiter.pm
@@ -55,4 +55,17 @@ sub commands {
$dev, $self->{_rate}, $self->{_latency}, $self->{_burst};
}
+sub isChanged {
+ my ($self, $name) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("qos-policy rate-limit $name");
+ foreach my $attr ('bandwidth', 'burst', 'latency') {
+ if ($config->isChanged($attr)) {
+ return $attr
+ }
+ }
+ return undef; # false
+}
+
1;
diff --git a/scripts/VyattaQosTrafficShaper.pm b/scripts/VyattaQosTrafficShaper.pm
index f321e9b..325c02e 100644
--- a/scripts/VyattaQosTrafficShaper.pm
+++ b/scripts/VyattaQosTrafficShaper.pm
@@ -404,4 +404,54 @@ sub commands {
}
}
+# 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 VyattaConfig;
+
+ $config->setLevel("qos-policy traffic-shaper $name");
+
+ if ($config->isChanged('bandwidth') ) {
+ return 'bandwidth';
+ }
+
+ foreach my $attr ('bandwidth', 'burst', 'ceiling', 'priority', 'queue-limit', 'queue-type') {
+ if ($config->isChanged("default $attr")) {
+ return "default $attr";
+ }
+ }
+
+ my %classNodes = $config->listNodeStatus('class');
+ while (my ($class, $status) = each %classNodes) {
+ if ($status ne 'static') {
+ return "class $class";
+ }
+
+ foreach my $attr ('bandwidth', 'burst', 'ceiling', 'priority', 'queue-limit', 'queue-type') {
+ if ($config->isChanged("class $class $attr")) {
+ return "class $class $attr";
+ }
+ }
+
+ my %matchNodes = $config->listNodeStatus("class $class match");
+ while (my ($match, $status) = each %matchNodes) {
+ my $level = "class $class match $match";
+ if ($status ne 'static') {
+ return $level;
+ }
+
+ foreach my $parm ('vif', 'interface', 'ip dscp', 'ip protocol',
+ 'ip source address', 'ip destination address',
+ 'ip source port', 'ip destination port') {
+ if ($config->isChanged("$level $parm")) {
+ return "$level $parm";
+ }
+ }
+ }
+ }
+
+ return undef; # false
+}
+
1;
diff --git a/scripts/vyatta-qos.pl b/scripts/vyatta-qos.pl
index ad97617..3d8e58b 100755
--- a/scripts/vyatta-qos.pl
+++ b/scripts/vyatta-qos.pl
@@ -21,24 +21,22 @@ use strict;
use Getopt::Long;
my $debug = $ENV{'QOS_DEBUG'};
-my $check = undef;
+my ($check, $update, $applyChanges);
my @updateInterface = ();
my @deleteInterface = ();
-my $listPolicy = undef;
-my $deletePolicy = undef;
+my ($listPolicy, $deletePolicy);
my @createPolicy = ();
-my @updatePolicy = ();
GetOptions(
"check" => \$check,
+ "apply-changes" => \$applyChanges,
"update-interface=s{3}" => \@updateInterface,
"delete-interface=s{2}" => \@deleteInterface,
"list-policy" => \$listPolicy,
"delete-policy=s" => \$deletePolicy,
"create-policy=s{2}" => \@createPolicy,
- "update-policy=s{2}" => \@updatePolicy,
);
# class factory for policies
@@ -135,19 +133,92 @@ sub update_interface {
die "Unknown qos-policy $name\n";
}
-sub delete_policy {
+sub using_policy {
+ my ($config, $name, $interface) = @_;
+ my @inuse = ();
+
+ foreach my $dir ( $config->listNodes("$interface qos-policy") ) {
+ my $policy = $config->returnValue("$interface qos-policy $dir");
+ if ($policy eq $name) {
+ push @inuse, "$interface $dir";
+ }
+ }
+ return @inuse;
+}
+
+sub interfaces_using {
my ($name) = @_;
my $config = new VyattaConfig;
+ my @affected = ();
+
+ $config->setLevel('interfaces');
+ foreach my $type ( $config->listNodes() ) {
+ foreach my $interface ( $config->listNodes($type) ) {
+ push @affected, using_policy($config, $name, "$type $interface");
+
+ if ($type eq 'ethernet') {
+ foreach my $vif ( $config->listNodes("$type $interface vif") ) {
+ push @affected, using_policy($config, $name, "$type $interface vif $vif");
+ }
+ }
- $config->setLevel("interfaces ethernet");
- foreach my $interface ( $config->listNodes() ) {
- foreach my $direction ( $config->listNodes("$interface qos-policy") ) {
- if ($config->returnValue("$interface qos-policy $direction") eq $name) {
- # can't delete active policy
- die "Qos policy $name still in use on ethernet $interface $direction\n";
+ if ($type eq 'adsl') {
+ foreach my $pvc ( $config->listNodes("adsl $interface pvc") ) {
+ foreach my $pvctype ( $config->listNodes("adsl $interface pvc $pvc") ) {
+ foreach my $vc ( $config->listNodes("adsl $interface pvc $pvc $pvctype") ) {
+ push @affected, using_policy($config, $name,
+ "adsl $interface pvc $pvc $pvctype $vc");
+ }
+ }
+ }
}
}
}
+
+ return @affected;
+}
+
+sub etherName {
+ my $eth = shift;
+
+ if ($_ =~ /vif/) {
+ shift;
+ $eth .= $_;
+ }
+ return $eth;
+}
+
+sub serialName {
+ my $wan = shift;
+ # XXX add vif
+ return $wan;
+}
+
+sub adslName {
+ # adsl-name pvc pvc-num ppp-type id
+ my (undef, undef, undef, $type, $id) = @_;
+
+ return $type . $id;
+}
+
+# Handle mapping of interface types to device names
+my %interfaceTypes = (
+ 'ethernet' => \&etherName,
+ 'serial' => \&serialName,
+ 'adsl' => \&adslName,
+ );
+
+sub delete_policy {
+ my ($name) = @_;
+ my @inuse = interfaces_using($name);
+
+ if ( @inuse ) {
+ foreach my $usage (@inuse) {
+ warn "QoS policy $name used by $usage\n";
+ }
+ # can't delete active policy
+ die "Must delete QoS policy from interfaces before deleting rules\n";
+ }
}
sub check_conflict {
@@ -172,18 +243,24 @@ sub create_policy {
make_policy($config, $shaper, $name);
}
-sub update_policy {
- my ($shaper, $name) = @_;
+sub apply_changes {
my $config = new VyattaConfig;
- # Syntax check
- make_policy($config, $shaper, $name);
-
- $config->setLevel("interfaces ethernet");
- foreach my $interface ( $config->listNodes() ) {
- foreach my $direction ( $config->listNodes("$interface qos-policy") ) {
- if ($config->returnValue("$interface qos-policy $direction") eq $name) {
- update_interface($interface, $direction, $name);
+ $config->setLevel('qos-policy');
+ foreach my $policy ($config->listNodes()) {
+ foreach my $name ($config->listNodes($policy)) {
+ my $shaper = make_policy($config, $policy, $name);
+
+ if ($shaper->isChanged($name)) {
+ foreach my $cfgpath (interfaces_using($name)) {
+ my @elements = split / /, $cfgpath;
+ my $direction = pop @elements; # out, in, ...
+ my $type = shift @elements; # ethernet, serial, ...
+ my $interface = $interfaceTypes{$type};
+ my $device = $interface->(@elements);
+
+ update_interface($device, $direction, $name);
+ }
}
}
}
@@ -214,22 +291,24 @@ if ( $#createPolicy == 1) {
exit 0;
}
-if ( $#updatePolicy == 1) {
- update_policy(@updatePolicy);
- exit 0;
-}
-
if ( $deletePolicy ) {
delete_policy($deletePolicy);
exit 0;
+}
+
+if ( $applyChanges ) {
+ apply_changes();
+ exit 0;
}
print <<EOF;
usage: vyatta-qos.pl --check
vyatta-qos.pl --list-policy
+
vyatta-qos.pl --create-policy policy-type policy-name
vyatta-qos.pl --delete-policy policy-name
- vyatta-qos.pl --update-policy policy-type policy-name
+ vyatta-qos.pl --apply-changes policy-type policy-name
+
vyatta-qos.pl --update-interface interface direction policy-name
vyatta-qos.pl --delete-interface interface direction
diff --git a/templates/qos-policy/node.def b/templates/qos-policy/node.def
index 2499fd5..991b5f5 100644
--- a/templates/qos-policy/node.def
+++ b/templates/qos-policy/node.def
@@ -1,2 +1,3 @@
help: Configure Quality of Service (QOS) policy type
begin: /opt/vyatta/sbin/vyatta-qos.pl --check
+end: /opt/vyatta/sbin/vyatta-qos.pl --apply
diff --git a/templates/qos-policy/traffic-shaper/node.def b/templates/qos-policy/traffic-shaper/node.def
index 31bdc93..b0b209d 100644
--- a/templates/qos-policy/traffic-shaper/node.def
+++ b/templates/qos-policy/traffic-shaper/node.def
@@ -3,6 +3,5 @@ type: txt
help: Set traffic shaping based policy
syntax:expression: pattern $VAR(@) "^[[:alnum:]][-_[:alnum:]]*$"
; "only alpha-numeric policy name allowed"
-create: /opt/vyatta/sbin/vyatta-qos.pl --create-policy "$VAR(.)" "$VAR(@)"
+update: /opt/vyatta/sbin/vyatta-qos.pl --create-policy "$VAR(.)" "$VAR(@)"
delete: /opt/vyatta/sbin/vyatta-qos.pl --delete-policy "$VAR(@)"
-update: /opt/vyatta/sbin/vyatta-qos.pl --update-policy "$VAR(.)" "$VAR(@)"