summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore18
-rw-r--r--AUTHORS1
-rw-r--r--COPYING27
-rw-r--r--Makefile.am24
-rw-r--r--NEWS1
-rw-r--r--README1
-rw-r--r--configure.ac30
-rw-r--r--debian/README5
-rwxr-xr-xdebian/autogen.sh37
-rw-r--r--debian/changelog5
-rw-r--r--debian/compat1
-rw-r--r--debian/control20
-rw-r--r--debian/copyright34
-rw-r--r--debian/docs2
-rw-r--r--debian/linda1
-rw-r--r--debian/lintian2
-rwxr-xr-xdebian/rules101
-rw-r--r--debian/vyatta-cfg-qos.postinst.in9
-rw-r--r--scripts/VyattaQosFairQueue.pm41
-rw-r--r--scripts/VyattaQosMatch.pm82
-rw-r--r--scripts/VyattaQosPolicy.pm34
-rw-r--r--scripts/VyattaQosTrafficShaper.pm182
-rw-r--r--scripts/VyattaQosUtil.pm173
-rwxr-xr-xscripts/vyatta-qos-util.pl44
-rwxr-xr-xscripts/vyatta-qos.pl106
-rw-r--r--templates/interfaces/ethernet/node.tag/qos-policy/node.def1
-rw-r--r--templates/interfaces/ethernet/node.tag/qos-policy/out/node.def4
-rw-r--r--templates/qos-policy/fair-queue/node.def4
-rw-r--r--templates/qos-policy/fair-queue/node.tag/description/node.def2
-rw-r--r--templates/qos-policy/fair-queue/node.tag/hash-interval/node.def3
-rw-r--r--templates/qos-policy/fair-queue/node.tag/queue-limit/node.def2
-rw-r--r--templates/qos-policy/node.def1
-rw-r--r--templates/qos-policy/traffic-shaper/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/burst/node.def3
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/ceiling/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/description/node.def2
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/description/node.def2
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/interface/node.def11
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/address/node.def2
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/port/node.def3
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/dsfield/node.def3
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/protocol/node.def3
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/address/node.def2
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/port/node.def3
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/vif/node.def6
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/priority/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue/node.def8
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/class/node.tag/rate/node.def11
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/default/burst/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/default/ceiling/node.def6
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/default/node.def1
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/default/priority/node.def4
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/default/queue/node.def8
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/default/rate/node.def11
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/description/node.def2
-rw-r--r--templates/qos-policy/traffic-shaper/node.tag/rate/node.def10
58 files changed, 1123 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3f43d67
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+*~
+.*.swp
+/aclocal.m4
+/autom4te.cache
+/build-stamp
+/ChangeLog
+/config
+/config.log
+/config.guess
+/config.status
+/config.sub
+/configure
+/debian/files
+/INSTALL
+/Makefile.in
+/Makefile
+/scripts/install-system
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..ee635b2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+eng@vyatta.com
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..8adada1
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,27 @@
+/*
+ * Package: vyatt-cfg-qos
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) "YEAR" Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: eng@vyatta.com
+ * Date: 2007
+ * Description: Vyatta system-level configuration templates/scripts
+ *
+ * **** End License ****
+ *
+ */
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..aaa1718
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,24 @@
+cfgdir = $(datadir)/vyatta-cfg/templates
+share_perl5dir = /opt/vyatta/share/perl5
+
+bin_SCRIPTS =
+sbin_SCRIPTS =
+sysconf_DATA =
+share_perl5_DATA =
+
+sbin_SCRIPTS += scripts/vyatta-qos.pl
+sbin_SCRIPTS += scripts/vyatta-qos-util.pl
+
+share_perl5_DATA += scripts/VyattaQosUtil.pm
+share_perl5_DATA += scripts/VyattaQosPolicy.pm
+share_perl5_DATA += scripts/VyattaQosFairQueue.pm
+share_perl5_DATA += scripts/VyattaQosTrafficShaper.pm
+share_perl5_DATA += scripts/VyattaQosMatch.pm
+
+cpiop = find . ! -regex '\(.*~\|.*\.bak\|.*\.swp\|.*\#.*\#\)' -print0 | \
+ cpio -0pd
+
+install-exec-hook:
+ mkdir -p $(DESTDIR)$(cfgdir)
+ cd templates; $(cpiop) $(DESTDIR)$(cfgdir)
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..78fdaa6
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+see http://www.vyatta.com/news/
diff --git a/README b/README
new file mode 100644
index 0000000..973af9d
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+This package has the Vyatta QoS configuration templates and scripts.
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..3f916a3
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,30 @@
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.59)
+
+m4_define([VERSION_ID], [m4_esyscmd([
+ if test -f .version ; then
+ head -n 1 .version | tr -d \\n
+ else
+ echo -n 2.4
+ fi])])
+AC_INIT([vyatta-cfg-qos], VERSION_ID, [vyatta-support@vyatta.com])
+
+test -n "$VYATTA_VERSION" || VYATTA_VERSION=$PACKAGE_VERSION
+
+AC_CONFIG_AUX_DIR([config])
+AM_INIT_AUTOMAKE([gnu no-dist-gzip dist-bzip2 subdir-objects])
+AC_PREFIX_DEFAULT([/opt/vyatta])
+
+AC_ARG_ENABLE([nostrip],
+ AC_HELP_STRING([--enable-nostrip],
+ [include -nostrip option during packaging]),
+ [NOSTRIP=-nostrip], [NOSTRIP=])
+
+AC_CONFIG_FILES(
+ [Makefile]
+ [debian/vyatta-cfg-qos.postinst])
+
+AC_SUBST(NOSTRIP)
+
+AC_OUTPUT
+
diff --git a/debian/README b/debian/README
new file mode 100644
index 0000000..aeae320
--- /dev/null
+++ b/debian/README
@@ -0,0 +1,5 @@
+The Debian Package vyatta-cfg-qos
+----------------------------
+
+This package has the Vyatta Qos configuration templates and scripts.
+
diff --git a/debian/autogen.sh b/debian/autogen.sh
new file mode 100755
index 0000000..ff125d1
--- /dev/null
+++ b/debian/autogen.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+
+if [ -d .git ] ; then
+# generate GNU/Debian format ChangeLog from git log
+
+ rm -f ChangeLog
+
+ if which git2cl >/dev/null ; then
+ git-log --pretty --numstat --summary | git2cl >> ChangeLog
+ else
+ git-log --pretty=short >> ChangeLog
+ fi
+
+# append repository reference
+
+ url=` git repo-config --get remote.origin.url`
+ test "x$url" = "x" && url=`pwd`
+
+ branch=`git-branch --no-color | sed '/^\* /!d; s/^\* //'`
+ test "x$branch" = "x" && branch=master
+
+ sha=`git log --pretty=oneline --no-color -n 1 | cut -c-8`
+ test "x$sha" = "x" && sha=00000000
+
+ echo "$url#$branch-$sha" >> ChangeLog
+
+fi
+
+rm -rf config
+rm -f aclocal.m4 config.guess config.statusconfig.sub configure INSTALL
+
+autoreconf --force --install
+
+rm -f config.sub config.guess
+ln -s /usr/share/misc/config.sub .
+ln -s /usr/share/misc/config.guess .
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..82ef481
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+vyatta-cfg-qos (0.1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- Stephen Hemminger <stephen.hemminger@vyatta.com> Wed, 30 Jan 2008 11:23:18 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..73fac62
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,20 @@
+Source: vyatta-cfg-qos
+Section: contrib/net
+Priority: extra
+Maintainer: Stephen Hemminger <stephen.hemminger@vyatta.com>
+Build-Depends: debhelper (>= 5), autotools-dev
+Standards-Version: 3.7.2
+
+Package: vyatta-cfg-qos
+Architecture: all
+Depends: bash (>= 3.1),
+ sed (>= 4.1.5),
+ perl (>= 5.8.8),
+ procps (>= 1:3.2.7-3),
+ coreutils (>= 5.97-5.3),
+ vyatta-cfg, sudo,
+ vyatta-bash, bridge-utils, vyatta-iproute, ethtool
+Suggests: util-linux (>= 2.13-5),
+ net-tools,
+Description: Vyatta Qos configuration templates/scripts
+ Vyatta Qos configuration templates and scripts.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..a7d84e1
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,34 @@
+This package was created by Stephen Hemminger <stephen.hemminger@vyatta.com>
+on Wed, Wed Jan 30 11:23:52 PST 2008
+
+It's original content from the GIT repository <http://vyatt.com/git/vyatta-cfg-qos>
+
+Upstream Author:
+
+ <eng@vyatta.com>
+
+Copyright:
+
+ Copyright (C) 2008 Vyatta, Inc.
+ All Rights Reserved.
+
+License:
+
+ The contents of this package are subject to the Vyatta Public License
+ Version 1.0 ("License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.vyatta.com/vpl
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ This code was originally developed by Vyatta, Inc.
+ Portions created by Vyatta are Copyright (C) 2008 Vyatta, Inc.
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+
+The Debian packaging is (C) 2008, Stephen Hemminger
+<stephen.hemminger@vyatta.com> and is licensed under the GPL, see above.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..50bd824
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,2 @@
+NEWS
+README
diff --git a/debian/linda b/debian/linda
new file mode 100644
index 0000000..0381d9d
--- /dev/null
+++ b/debian/linda
@@ -0,0 +1 @@
+Tag: file-in-opt
diff --git a/debian/lintian b/debian/lintian
new file mode 100644
index 0000000..f1dafbd
--- /dev/null
+++ b/debian/lintian
@@ -0,0 +1,2 @@
+vyatta-cfg-qos: file-in-unusual-dir
+vyatta-cfg-qos: dir-or-file-in-opt
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..b02c352
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,101 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+PACKAGE=vyatta-cfg-qos
+PKGDIR=$(CURDIR)/debian/$(PACKAGE)
+
+CFLAGS = -Wall -g
+
+configure = ./configure
+configure += --host=$(DEB_HOST_GNU_TYPE)
+configure += --build=$(DEB_BUILD_GNU_TYPE)
+configure += --prefix=/opt/vyatta
+configure += --mandir=\$${prefix}/share/man
+configure += --infodir=\$${prefix}/share/info
+configure += CFLAGS="$(CFLAGS)"
+configure += LDFLAGS="-Wl,-z,defs"
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+
+configure: configure.ac Makefile.am
+ chmod +x debian/autogen.sh
+ debian/autogen.sh
+
+config.status: configure
+ dh_testdir
+ rm -f config.cache
+ $(configure)
+
+build: build-stamp
+
+build-stamp: config.status
+ dh_testdir
+ $(MAKE)
+ touch $@
+
+clean: clean-patched
+
+# Clean everything up, including everything auto-generated
+# at build time that needs not to be kept around in the Debian diff
+clean-patched:
+ dh_testdir
+ dh_testroot
+ if test -f Makefile ; then $(MAKE) clean distclean ; fi
+ rm -f build-stamp
+ rm -f config.status config.sub config.guess config.log
+ rm -f aclocal.m4 configure Makefile.in Makefile INSTALL
+ rm -rf config
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ $(MAKE) DESTDIR=$(PKGDIR) install
+
+ install -D --mode=0644 debian/lintian $(PKGDIR)/usr/share/lintian/overrides/$(PACKAGE)
+ install -D --mode=0644 debian/linda $(PKGDIR)/usr/share/linda/overrides/$(PACKAGE)
+
+# Build architecture-independent files here.
+binary-indep: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs ChangeLog
+ dh_installdocs
+ dh_install
+ dh_installdebconf
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# This is an architecture independent package
+# so; we have nothing to do by default.
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/vyatta-cfg-qos.postinst.in b/debian/vyatta-cfg-qos.postinst.in
new file mode 100644
index 0000000..3751d0b
--- /dev/null
+++ b/debian/vyatta-cfg-qos.postinst.in
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+sysconfdir=@sysconfdir@
+bindir=@bindir@
+sbindir=@sbindir@
+
+# Don't do anything for now.
diff --git a/scripts/VyattaQosFairQueue.pm b/scripts/VyattaQosFairQueue.pm
new file mode 100644
index 0000000..d943db2
--- /dev/null
+++ b/scripts/VyattaQosFairQueue.pm
@@ -0,0 +1,41 @@
+package VyattaQosFairQueue;
+@ISA = qw/VyattaQosPolicy/;
+
+#
+# This is a wrapper around Stochastic Fair Queue(SFQ) queue discipline
+# Since SFQ is a hard to explain, use the name fair-queue since SFQ
+# is most similar to Weighted Fair Queue (WFQ) on Cisco IOS.
+#
+
+use strict;
+
+require VyattaConfig;
+
+# Fair Queue
+# Uses SFQ which is similar to (but not same as) WFQ
+
+my %fields = (
+ _perturb => undef,
+ _limit => undef,
+);
+
+sub new {
+ my ( $that, $config ) = @_;
+ my $class = ref($that) || $that;
+ my $self = {%fields};
+
+ $self->{_perturb} = $config->returnValue("rekey-interval");
+ $self->{_limit} = $config->returnValue("queue-limit");
+ return bless $self, $class;
+}
+
+sub commands {
+ my ( $self, $out, $dev ) = @_;
+
+ print {$out} "qdisc add dev $dev root sfq";
+ print {$out} " perturb $self->{_perturb}" if ( defined $self->{_perturb} );
+ print {$out} " limit $self->{_limit}" if ( defined $self->{_limit} );
+ print "\n";
+}
+
+1;
diff --git a/scripts/VyattaQosMatch.pm b/scripts/VyattaQosMatch.pm
new file mode 100644
index 0000000..72f7a36
--- /dev/null
+++ b/scripts/VyattaQosMatch.pm
@@ -0,0 +1,82 @@
+package VyattaQosMatch;
+require VyattaConfig;
+use VyattaQosUtil;
+use strict;
+
+my %fields = (
+ _dev => undef,
+ _vlan => undef,
+ _ip => {
+ _src => undef,
+ _dst => undef,
+ _dsfield => undef,
+ _protocol => undef,
+ _sport => undef,
+ _dport => undef,
+ }
+);
+
+sub new {
+ my ( $that, $config ) = @_;
+ my $self = {%fields};
+ my $class = ref($that) || $that;
+
+ bless $self, $class;
+ $self->_define($config);
+
+ return $self;
+}
+
+sub _tos {
+ my $tos = shift;
+ my $ret = undef;
+
+ if ( defined $tos ) {
+ $ret = VyattaQosUtil::getDsfield($tos);
+ if ( !defined $ret ) {
+ $tos = hex($tos);
+ }
+ }
+ return $ret;
+}
+
+sub _define {
+ my ( $self, $config ) = @_;
+
+ my $level=$config->setLevel();
+
+ $self->{_vlan} = $config->returnValue("vif");
+ $self->{_dev} = $config->returnValue("interface");
+
+ $self->{_ip}->{_tos} = _tos( $config->returnValue("ip tos") );
+ $self->{_ip}->{_protocol} = $config->returnValue("ip protocol");
+ $self->{_ip}->{_src} = $config->returnValue("ip source address");
+ $self->{_ip}->{_dst} = $config->returnValue("ip destination address");
+ $self->{_ip}->{_sport} = $config->returnValue("ip source port");
+ $self->{_ip}->{_dport} = $config->returnValue("ip source dport");
+}
+
+sub filter {
+ my ( $self, $out, $dev, $id ) = @_;
+
+ print {$out} "filter add dev $dev parent 1:0 prio 10";
+
+ # TODO match on vlan, device, ...
+ if (defined $self->{_ip}) {
+ print {$out} " u32";
+ print {$out} " match ip tos $self->{_ip}->{_tos} 0xff"
+ if defined $self->{_ip}->{_tos};
+ print {$out} " match ip protocol $self->{_ip}->{_protcol} 0xff"
+ if defined $self->{_ip}->{_protocol};
+ print {$out} " match ip src $self->{_ip}->{_src}"
+ if defined $self->{_ip}->{_src};
+ print {$out} " match ip sport $self->{_ip}->{_sport}"
+ if defined $self->{_ip}->{_sport};
+ print {$out} " match ip dst $self->{_ip}->{_dst}"
+ if defined $self->{_ip}->{_dst};
+ print {$out} " match ip dport $self->{_ip}->{_dport}"
+ if defined $self->{_ip}->{_dport};
+ }
+
+ print {$out} " classid $id\n";
+}
diff --git a/scripts/VyattaQosPolicy.pm b/scripts/VyattaQosPolicy.pm
new file mode 100644
index 0000000..76f86eb
--- /dev/null
+++ b/scripts/VyattaQosPolicy.pm
@@ -0,0 +1,34 @@
+package VyattaQosPolicy;
+
+use strict;
+
+require VyattaConfig;
+use VyattaQosTrafficShaper;
+use VyattaQosFairQueue;
+
+# Main class for all QoS policys
+# It is a base class, and actual policies are subclass instances.
+
+# Build a new traffic shaper of the proper type based
+# on the configuration information.
+sub config {
+ my ( $class, $config, $type ) = @_;
+ my $object = undef;
+
+ SWITCH: {
+ ( $type eq 'fair-queue' ) && do {
+ $object = new VyattaQosFairQueue($config);
+ last SWITCH;
+ };
+
+ ( $type eq 'traffic-shaper' ) && do {
+ $object = new VyattaQosTrafficShaper($config);
+ last SWITCH;
+ };
+
+ die "Unknown policy type \"$type\"\n";
+ }
+ return $object;
+}
+
+1;
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;
diff --git a/scripts/VyattaQosUtil.pm b/scripts/VyattaQosUtil.pm
new file mode 100644
index 0000000..121970e
--- /dev/null
+++ b/scripts/VyattaQosUtil.pm
@@ -0,0 +1,173 @@
+package VyattaQosUtil;
+use POSIX;
+require Exporter;
+@EXPORT = qw/getRate getSize getProtocol getDsfield interfaceRate/;
+
+sub get_num {
+ my ($str) = @_;
+
+ # clear errno
+ $! = 0;
+ ($num, $unparsed) = POSIX::strtod($str);
+ if (($str eq '') || $!) {
+ die "Non-numeric input \"$str\"" . ($! ? ": $!\n" : "\n");
+ }
+
+ if ($unparsed > 0) { return $num, substr($str, -$unparsed); }
+ else { return $num; }
+}
+
+## get_rate("10mbit")
+# convert rate specification to number
+# from tc/tc_util.c
+sub getRate {
+ my ($num, $suffix) = get_num(@_);
+
+ if (defined $suffix) {
+ SWITCH: {
+ ($suffix eq 'bit') && do { last SWITCH; };
+ ($suffix eq 'kibit') && do { $num *= 1024.; last SWITCH };
+ ($suffix eq 'kbit') && do { $num *= 1000.,; last SWITCH; };
+ ($suffix eq 'mibit') && do { $num *= 1048576.,; last SWITCH; };
+ ($suffix eq 'mbit') && do { $num *= 1000000.,; last SWITCH; };
+ ($suffix eq 'gibit') && do { $num *= 1073741824.,; last SWITCH; };
+ ($suffix eq 'gbit') && do { $num *= 1000000000.,; last SWITCH; };
+ ($suffix eq 'tibit') && do { $num *= 1099511627776.,; last SWITCH; };
+ ($suffix eq 'tbit') && do { $num *= 1000000000000.,; last SWITCH; };
+ ($suffix eq 'bps') && do { $num *= 8.,; last SWITCH; };
+ ($suffix eq 'kibps') && do { $num *= 8192.,; last SWITCH; };
+ ($suffix eq 'kbps') && do { $num *= 8000.,; last SWITCH; };
+ ($suffix eq 'mibps') && do { $num *= 8388608.,; last SWITCH; };
+ ($suffix eq 'mbps') && do { $num *= 8000000.,; last SWITCH; };
+ ($suffix eq 'gibps') && do { $num *= 8589934592.,; last SWITCH; };
+ ($suffix eq 'gbps') && do { $num *= 8000000000.,; last SWITCH; };
+ ($suffix eq 'tibps') && do { $num *= 8796093022208.,; last SWITCH; };
+ ($suffix eq 'tbps') && do { $num *= 8000000000000.,; last SWITCH; };
+
+ die "Rate must be a number followed by a optional suffix (kbit, mbps, ...)\n";
+ }
+ }
+
+ die "Negative rate not allowed\n" if ($num < 0);
+ return $num;
+}
+
+sub getSize {
+ my ($num, $suffix) = get_num(@_);
+
+ if (defined $suffix) {
+ SWITCH: {
+ ($suffix eq 'b') && do { $num *= 1.,; last SWITCH; };
+ ($suffix eq 'k') && do { $num *= 1024.,; last SWITCH; };
+ ($suffix eq 'kb') && do { $num *= 1024.,; last SWITCH; };
+ ($suffix eq 'kbit') && do { $num *= 128.,; last SWITCH; };
+ ($suffix eq 'm') && do { $num *= 1048576.,; last SWITCH; };
+ ($suffix eq 'mb') && do { $num *= 1048576.,; last SWITCH; };
+ ($suffix eq 'mbit') && do { $num *= 131072.,; last SWITCH; };
+ ($suffix eq 'g') && do { $num *= 1073741824.,; last SWITCH; };
+ ($suffix eq 'gb') && do { $num *= 1073741824.,; last SWITCH; };
+ ($suffix eq 'gbit') && do { $num *= 134217728.,; last SWITCH; };
+
+ die "Unknown suffix \"$suffix\"\n";
+ }
+ }
+
+ die "Negative size not allowed\n" if ($num < 0);
+ return $num;
+}
+
+sub getProtocol {
+ my ($p) = @_;
+
+ if ($p =~ /^([0-9]+)|(0x[0-9a-fA-F]+)$/) {
+ if ($p < 0 || $p > 255) {
+ die "$p is not a valid protocol number\n";
+ }
+ return $p;
+ }
+
+ ($name, $aliases, $proto) = getprotobyname($p);
+ (defined $proto) or die "\"$p\" unknown protocol\n";
+ return $proto;
+}
+
+# Parse /etc/iproute/rt_dsfield
+# return a hex string "0x10" or undefined
+sub getDsfield {
+ my ($str) = @_;
+ my $match = undef;
+ my $dsFileName = '/etc/iproute2/rt_dsfield';
+
+ if ($str =~ /^([0-9]+)|(0x[0-9a-fA-F]+)$/) {
+ if ($str < 0 || $str > 255) {
+ die "$str is not a valid dsfield value\n";
+ }
+ return $str;
+ }
+
+ open(DSFIELD,"<$dsFileName") || die "Can't open $dsFileName, $!\n";
+ while (<DSFIELD>) {
+ next if /^#/;
+ chomp;
+ @fields = split;
+ if ($str eq $fields[1]) {
+ $match = $fields[0];
+ last;
+ }
+ }
+ close(DSFIELD);
+
+ return $match;
+}
+
+# Utility routines
+
+## interfaceRate("eth0")
+# return result in bits per second
+sub interfaceRate {
+ my ($interface) = @_;
+ my $rate = undef;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("interfaces ethernet");
+ if ($config->exists("$interface")) {
+ my $speed = $config->returnValue("$interface speed");
+ if (defined($speed) && $speed != "auto") {
+ return $speed * 1000000;
+ }
+ }
+
+ $rate = ethtoolRate($interface);
+
+ if (! defined $rate) {
+ die "Interace speed for $interface unknown\n";
+ }
+
+ return $rate * 1000000;
+}
+
+## ethtoolRate("eth0")
+# Fetch actual rate using ethtool and format to valid tc rate
+sub ethtoolRate {
+ my ($dev) = @_;
+ my $rate = undef;
+
+ open(ETHTOOL, "sudo ethtool $dev |") or return $rate;
+
+ # ethtool produces:
+ #
+ # Settings for eth1:
+ # Supported ports: [ TP ]
+ # ...
+ # Speed: 1000Mb/s
+ while (<ETHTOOL>) {
+ my @line = split;
+ if ($line[0] =~ /^Speed/) {
+ $rate = $line[1];
+ $rate =~ s/Mb\/s/000000/;
+ last;
+ }
+ }
+ close(ETHTOOL);
+ return $rate;
+}
diff --git a/scripts/vyatta-qos-util.pl b/scripts/vyatta-qos-util.pl
new file mode 100755
index 0000000..5dd869f
--- /dev/null
+++ b/scripts/vyatta-qos-util.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+#
+# Utility routines for validating input
+# These functions don't change existing QoS parameters
+#
+
+use lib "/opt/vyatta/share/perl5/";
+use VyattaQosUtil;
+use Getopt::Long;
+
+GetOptions(
+ "rate=s" => \$rate,
+ "burst=s" => \$burst,
+ "protocol=s" => \$protocol,
+ "dsfield=s" => \$dsfield,
+);
+
+if ( defined $rate ) {
+ my $r = VyattaQosUtil::getRate($rate);
+ exit 0;
+}
+
+if ( defined $burst ) {
+ my $b = VyattaQosUtil::getSize($burst);
+ exit 0;
+}
+
+if ( defined $protocol ) {
+ my $p = VyattaQosUtil::getProtocol($protocol);
+ exit 0;
+}
+
+if ( defined $dsfield ) {
+ my $d = VyattaQosUtil::getDsfield($dsfield);
+ exit 0;
+}
+
+print <<EOF;
+usage: vyatta-qos-util.pl --rate rate
+ vyatta-qos-util.pl --burst size
+ vyatta-qos-util.pl --protocol protocol
+ vyatta-qos-util.pl --dsfield tos|dsfield
+EOF
+exit 1;
diff --git a/scripts/vyatta-qos.pl b/scripts/vyatta-qos.pl
new file mode 100755
index 0000000..86a0c62
--- /dev/null
+++ b/scripts/vyatta-qos.pl
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+
+use lib "/opt/vyatta/share/perl5/";
+use VyattaConfig;
+use VyattaQosPolicy;
+
+use Getopt::Long;
+
+my $qosNode = 'qos-policy';
+
+my @update = ();
+my @delete = ();
+my $debug = $ENV{"DEBUG"};
+my $list = undef;
+
+GetOptions(
+ "debug" => \$debug,
+ "list" => \$list,
+ "update=s{3}" => \@update,
+ "delete=s{2}" => \@delete,
+);
+
+## list available qos policy names
+sub list_available {
+ my $config = new VyattaConfig;
+ my @nodes = ();
+
+ foreach my $policy ( $config->listNodes($qosNode) ) {
+ foreach my $name ( $config->listNodes("$qosNode $policy") ) {
+ push @nodes, $name;
+ }
+ }
+
+ print join( ' ', @nodes ), "\n";
+}
+
+## delete_interface('eth0', 'out')
+# remove all filters and qdisc's
+sub delete_interface {
+ my ( $interface, $direction ) = @_;
+
+ if ( $direction =~ /^out/ ) {
+
+ # delete old qdisc - will give error if no policy in place
+ system("tc qdisc del dev $interface root 2>/dev/null");
+ system("tc filter del dev $interface 2>/dev/null");
+ }
+ else {
+ return -1;
+ }
+}
+
+## update_interface('eth0', 'out', 'my-shaper')
+# update policy to interface
+sub update_interface {
+ my ( $interface, $direction, $name ) = @_;
+ my $config = new VyattaConfig;
+
+ # TODO: add support for ingress
+ ( $direction =~ /^out/ ) or die "Only out direction supported";
+
+ foreach my $policy ( $config->listNodes($qosNode) ) {
+ if ( $config->exists("$qosNode $policy $name") ) {
+ $config->setLevel("$qosNode $policy $name");
+
+ my $policy = VyattaQosPolicy->config( $config, $policy );
+ defined $policy or die "undefined policy";
+
+ # When doing debugging just echo the commands
+ if (defined $debug) {
+ open (my $out, ">&STDOUT");
+ } else {
+ open( my $out, "|sudo tc -batch -" )
+ or die "Tc setup failed: $!\n";
+ }
+
+ $policy->commands($out, $interface);
+ close $out or die "Tc command failed: $!\n";
+ exit 0;
+ }
+ }
+
+ die "Unknown $qosNode $name\n";
+}
+
+if ( defined $list ) {
+ list_available();
+ exit 0;
+}
+
+if ( $#delete == 1 ) {
+ delete_interface(@delete);
+ exit 0;
+}
+
+if ( $#update == 2 ) {
+ update_interface(@update);
+ exit 0;
+}
+
+print <<EOF;
+usage: vyatta-qos.pl --list
+ vyatta-qos.pl --update interface direction policy
+ vyatta-qos.pl --delete interface direction
+EOF
+exit 1;
diff --git a/templates/interfaces/ethernet/node.tag/qos-policy/node.def b/templates/interfaces/ethernet/node.tag/qos-policy/node.def
new file mode 100644
index 0000000..b4ab8d8
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/qos-policy/node.def
@@ -0,0 +1 @@
+help: "Configure qos-policy"
diff --git a/templates/interfaces/ethernet/node.tag/qos-policy/out/node.def b/templates/interfaces/ethernet/node.tag/qos-policy/out/node.def
new file mode 100644
index 0000000..bb9ea38
--- /dev/null
+++ b/templates/interfaces/ethernet/node.tag/qos-policy/out/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: "Set outbound QOS policy"
+update: "sudo /opt/vyatta/sbin/vyatta-qos.pl --update $(../../@) out $(@)"
+delete: "sudo /opt/vyatta/sbin/vyatta-qos.pl --delete $(../../@) out"
diff --git a/templates/qos-policy/fair-queue/node.def b/templates/qos-policy/fair-queue/node.def
new file mode 100644
index 0000000..36f3a35
--- /dev/null
+++ b/templates/qos-policy/fair-queue/node.def
@@ -0,0 +1,4 @@
+tag:
+type: txt
+syntax: pattern $(@) "^[^-]" ; "Qos queue name cannot start with \"-\""
+help: "Configure fair queueing based policy"
diff --git a/templates/qos-policy/fair-queue/node.tag/description/node.def b/templates/qos-policy/fair-queue/node.tag/description/node.def
new file mode 100644
index 0000000..335eb7e
--- /dev/null
+++ b/templates/qos-policy/fair-queue/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: "Description for this queuing policy"
diff --git a/templates/qos-policy/fair-queue/node.tag/hash-interval/node.def b/templates/qos-policy/fair-queue/node.tag/hash-interval/node.def
new file mode 100644
index 0000000..de3d6a0
--- /dev/null
+++ b/templates/qos-policy/fair-queue/node.tag/hash-interval/node.def
@@ -0,0 +1,3 @@
+type: u32
+default: 0
+help: "Rehash interval (seconds)"
diff --git a/templates/qos-policy/fair-queue/node.tag/queue-limit/node.def b/templates/qos-policy/fair-queue/node.tag/queue-limit/node.def
new file mode 100644
index 0000000..e6456f8
--- /dev/null
+++ b/templates/qos-policy/fair-queue/node.tag/queue-limit/node.def
@@ -0,0 +1,2 @@
+type: u32
+help: "Maximum queue size (packets)"
diff --git a/templates/qos-policy/node.def b/templates/qos-policy/node.def
new file mode 100644
index 0000000..9e04559
--- /dev/null
+++ b/templates/qos-policy/node.def
@@ -0,0 +1 @@
+help: "Qos policy type"
diff --git a/templates/qos-policy/traffic-shaper/node.def b/templates/qos-policy/traffic-shaper/node.def
new file mode 100644
index 0000000..3d623b7
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.def
@@ -0,0 +1,4 @@
+tag:
+type: txt
+syntax: pattern $(@) "^[^-]" ; "Qos queue name cannot start with \"-\""
+help: "Configure traffic shaping based policy"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.def
new file mode 100644
index 0000000..a9944bd
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.def
@@ -0,0 +1,4 @@
+tag:
+type: u32
+help: "Configure class handle"
+syntax: ($(@) > 1 && $(@) < 65536) ; "$(@) handle must be between 2 and 65535"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/burst/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/burst/node.def
new file mode 100644
index 0000000..d32af54
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/burst/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Set the burst size for this class"
+syntax: exec "/opt/vyatta/sbin/vyatta-qos-util.pl --burst \"$(@)\""
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/ceiling/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/ceiling/node.def
new file mode 100644
index 0000000..ad78fa2
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/ceiling/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: "Set the limit for this class"
+syntax: exec "[[ \"$(@)\" =~ \"[0-9]+(\.[0-9]*)?%\" ]] || \
+ /opt/vyatta/sbin/vyatta-qos-util.pl --rate \"$(@)\""
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/description/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/description/node.def
new file mode 100644
index 0000000..f632aa0
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: "Description for this traffic class"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.def
new file mode 100644
index 0000000..6b77136
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.def
@@ -0,0 +1,4 @@
+tag:
+type: txt
+syntax: pattern $(@) "^[^-]" ; "Match queue name cannot start with \"-\""
+help: "Configure class matching rule name"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/description/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/description/node.def
new file mode 100644
index 0000000..e62ed79
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: "Description for this match"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/interface/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/interface/node.def
new file mode 100644
index 0000000..fa8f1cb
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/interface/node.def
@@ -0,0 +1,11 @@
+tag:
+type: txt
+help: "Ethernet interface name"
+syntax: exec " \
+ if [ -z \"`ip link | egrep -v 'eth[0-9]+[.]' | grep $(@)`\" ]; then \
+ echo Invalid ethernet interface [$(@)]; \
+ exit 1 ; \
+ fi ; "
+#allowed: local -a array ;
+# array=( /sys/class/net/{eth,vmnet}[0-9]+[^.] ) ;
+# echo -n ${array[@]##*/}
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/address/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/address/node.def
new file mode 100644
index 0000000..95087be
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/address/node.def
@@ -0,0 +1,2 @@
+type: ipv4net
+help: "Match IP destination address"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/port/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/port/node.def
new file mode 100644
index 0000000..a082a37
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/destination/port/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Match IP destination port"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/dsfield/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/dsfield/node.def
new file mode 100644
index 0000000..4a9e22e
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/dsfield/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Match dsfield/TOS: either hexadecimal number (0x10) or identifier"
+syntax: exec "/opt/vyatta/sbin/vyatta-qos-util.pl --dsfield \"$(@)\""
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/protocol/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/protocol/node.def
new file mode 100644
index 0000000..5681770
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/protocol/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Match IP protocol name or number"
+syntax: exec "/opt/vyatta/sbin/vyatta-qos-util.pl --protocol \"$(@)\""
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/address/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/address/node.def
new file mode 100644
index 0000000..e20679d
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/address/node.def
@@ -0,0 +1,2 @@
+type: ipv4net
+help: "Match IP source address"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/port/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/port/node.def
new file mode 100644
index 0000000..c0af33f
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/ip/source/port/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Match IP source port"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/vif/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/vif/node.def
new file mode 100644
index 0000000..3de7d2f
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/match/node.tag/vif/node.def
@@ -0,0 +1,6 @@
+tag:
+type: u32
+help: "VLAN ID"
+syntax: $(@) >= 0 && $(@) <= 4095; "VLAN ID must be between 0 and 4095"
+#comp_help: possible completions:
+# <0-4095> Set VLAN ID
diff --git a/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/priority/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/priority/node.def
new file mode 100644
index 0000000..72b36e2
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/priority/node.def
@@ -0,0 +1,4 @@
+type: u32
+default: 1
+help: "Priority for usage of extra bandwidth"
+syntax: ($(@) > 0 && $(@) < 10) ; "priority must be between 1 and 10"
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
new file mode 100644
index 0000000..a18ecc1
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/queue/node.def
@@ -0,0 +1,8 @@
+type: txt
+default: "SFQ"
+syntax: $(@) 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/class/node.tag/rate/node.def b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/rate/node.def
new file mode 100644
index 0000000..9f9721a
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/class/node.tag/rate/node.def
@@ -0,0 +1,11 @@
+type: txt
+default: "100%"
+help: "Set the base rate for this class"
+syntax: exec "[[ \"$(@)\" =~ \"[0-9]+(\.[0-9]*)?%\" ]] || \
+ /opt/vyatta/sbin/vyatta-qos-util.pl --rate \"$(@)\""
+#comp_help: Allowed values:
+# <number>% Percentage of overall rate (default 100%)
+# <number><suffix> Bitrate with scaling suffix
+# bits per sec (kbit, mbit, gbit)
+# bytes per sec (kbps, mbps, gbps)
+
diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/burst/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/burst/node.def
new file mode 100644
index 0000000..8360670
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/default/burst/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: "Set the burst size for default traffic"
+default: "15k"
+syntax: exec "/opt/vyatta/sbin/vyatta-qos-util.pl --burst \"$(@)\""
diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/ceiling/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/ceiling/node.def
new file mode 100644
index 0000000..7c501b3
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/default/ceiling/node.def
@@ -0,0 +1,6 @@
+type: txt
+help: "Set the limit for default traffic"
+default: "100%"
+syntax: exec "[[ \"$(@)\" =~ \"[0-9]+(\.[0-9]*)?%\" ]] || \
+ /opt/vyatta/sbin/vyatta-qos-util.pl --rate \"$(@)\""
+
diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/node.def
new file mode 100644
index 0000000..f5adce3
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/default/node.def
@@ -0,0 +1 @@
+help: "Configure default policy"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/priority/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/priority/node.def
new file mode 100644
index 0000000..ad6b9aa
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/default/priority/node.def
@@ -0,0 +1,4 @@
+type: u32
+default: 8
+help: "Priority for usage of extra bandwidth"
+syntax: ($(@) > 0 && $(@) < 10) ; "priority must be between 1 and 10"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/default/queue/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/queue/node.def
new file mode 100644
index 0000000..a18ecc1
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/default/queue/node.def
@@ -0,0 +1,8 @@
+type: txt
+default: "SFQ"
+syntax: $(@) 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/rate/node.def b/templates/qos-policy/traffic-shaper/node.tag/default/rate/node.def
new file mode 100644
index 0000000..b12c6b6
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/default/rate/node.def
@@ -0,0 +1,11 @@
+type: txt
+default: "50%"
+help: "Set the rate for default traffic"
+syntax: exec "[[ \"$(@)\" =~ \"[0-9]+(\.[0-9]*)?%\" ]] || \
+ /opt/vyatta/sbin/vyatta-qos-util.pl --rate \"$(@)\""
+#comp_help: Allowed values:
+# <number>% Percentage of overall rate (default 50%)
+# <number><suffix> Bitrate with scaling suffix
+# bits per sec (kbit, mbit, gbit)
+# bytes per sec (kbps, mbps, gbps)
+
diff --git a/templates/qos-policy/traffic-shaper/node.tag/description/node.def b/templates/qos-policy/traffic-shaper/node.tag/description/node.def
new file mode 100644
index 0000000..335eb7e
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: "Description for this queuing policy"
diff --git a/templates/qos-policy/traffic-shaper/node.tag/rate/node.def b/templates/qos-policy/traffic-shaper/node.tag/rate/node.def
new file mode 100644
index 0000000..22d54b5
--- /dev/null
+++ b/templates/qos-policy/traffic-shaper/node.tag/rate/node.def
@@ -0,0 +1,10 @@
+type: txt
+help: "Set the base rate for this policy"
+default: "auto"
+syntax: exec "[[ \"$(@)\" == \"auto\" ]] || \
+ /opt/vyatta/sbin/vyatta-qos-util.pl --rate \"$(@)\""
+#comp_help: Allowed values:
+# auto Set rate based on interface speed (default)
+# <number><suffix> Bitrate with scaling suffix
+# bits per sec (kbit, mbit, gbit)
+# bytes per sec (kbps, mbps, gbps)