diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | interface-templates/input-policy/mirror/node.def | 3 | ||||
-rw-r--r-- | interface-templates/input-policy/node.def | 3 | ||||
-rw-r--r-- | interface-templates/input-policy/redirect/node.def | 3 | ||||
-rw-r--r-- | lib/Vyatta/Qos/IngressMirror.pm | 56 | ||||
-rw-r--r-- | lib/Vyatta/Qos/IngressRedirect.pm | 57 | ||||
-rwxr-xr-x | scripts/vyatta-qos.pl | 120 |
7 files changed, 197 insertions, 48 deletions
diff --git a/Makefile.am b/Makefile.am index d70d917..818a38d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,11 +13,12 @@ share_perl5_DATA += lib/Vyatta/Qos/ShaperClass.pm share_perl5_DATA += lib/Vyatta/Qos/Match.pm share_perl5_DATA += lib/Vyatta/Qos/RateLimiter.pm share_perl5_DATA += lib/Vyatta/Qos/DropTail.pm -share_perl5_DATA += lib/Vyatta/Qos/TrafficLimiter.pm share_perl5_DATA += lib/Vyatta/Qos/LimiterClass.pm share_perl5_DATA += lib/Vyatta/Qos/RoundRobin.pm share_perl5_DATA += lib/Vyatta/Qos/NetworkEmulator.pm share_perl5_DATA += lib/Vyatta/Qos/RandomDetect.pm +share_perl5_DATA += lib/Vyatta/Qos/IngressRedirect.pm +share_perl5_DATA += lib/Vyatta/Qos/IngressMirror.pm etcdir = /etc etc_SCRIPTS = diff --git a/interface-templates/input-policy/mirror/node.def b/interface-templates/input-policy/mirror/node.def new file mode 100644 index 0000000..49fb3df --- /dev/null +++ b/interface-templates/input-policy/mirror/node.def @@ -0,0 +1,3 @@ +type: txt +help: Set incoming packet mirroring destination +allowed: ${vyatta_sbindir}/vyatta-interfaces.pl --show=all diff --git a/interface-templates/input-policy/node.def b/interface-templates/input-policy/node.def new file mode 100644 index 0000000..094375e --- /dev/null +++ b/interface-templates/input-policy/node.def @@ -0,0 +1,3 @@ +help: Set incoming packet policy +update: /opt/vyatta/sbin/vyatta-qos.pl --update-ingress $IFNAME +delete: sudo tc qdisc del dev $IFNAME ingress 2>/dev/null diff --git a/interface-templates/input-policy/redirect/node.def b/interface-templates/input-policy/redirect/node.def new file mode 100644 index 0000000..5582d07 --- /dev/null +++ b/interface-templates/input-policy/redirect/node.def @@ -0,0 +1,3 @@ +type: txt +help: Set incoming packet redirection destination +allowed: ${vyatta_sbindir}/vyatta-interfaces.pl --show=all diff --git a/lib/Vyatta/Qos/IngressMirror.pm b/lib/Vyatta/Qos/IngressMirror.pm new file mode 100644 index 0000000..d3e52c0 --- /dev/null +++ b/lib/Vyatta/Qos/IngressMirror.pm @@ -0,0 +1,56 @@ +# Ingress Mirror +# Duplicate all packets to another interface +# This is useful for some forms of IDS or capture +# +# **** 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) 2010 Vyatta, Inc. +# All Rights Reserved. +# **** End License **** + +package Vyatta::Qos::IngressMirror; +use strict; +use warnings; + +require Vyatta::Config; + +sub new { + my ( $that, $config, $name ) = @_; + my $self = {}; + my $class = ref($that) || $that; + + bless $self, $class; + $self->_define($config); + + return $self; +} + +# Setup new instance. +sub _define { + my ( $self, $config ) = @_; + # config is at level: interfaces ethernet $dev input-policy redirect + $self->{_target} = $config->returnValue(); +} + +sub commands { + my ( $self, $dev, $parent ) = @_; + my $target = $self->{_target}; + + # Apply filter to ingress qdisc + # NB: action is egress because we are in ingress (upside down) + printf "filter add dev %s parent %x: ", $dev, $parent; + print " protocol all prio 10 u32"; + print " match u32 0 0 flowid 1:1"; + print " action mirred egress mirror dev $target\n"; +} + +1; diff --git a/lib/Vyatta/Qos/IngressRedirect.pm b/lib/Vyatta/Qos/IngressRedirect.pm new file mode 100644 index 0000000..a04018f --- /dev/null +++ b/lib/Vyatta/Qos/IngressRedirect.pm @@ -0,0 +1,57 @@ +# Ingress Redirect +# Forward all packets to another interface +# +# **** 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) 2010 Vyatta, Inc. +# All Rights Reserved. +# **** End License **** + +package Vyatta::Qos::IngressRedirect; +use strict; +use warnings; + +require Vyatta::Config; + +sub new { + my ( $that, $config, $name ) = @_; + my $self = {}; + my $class = ref($that) || $that; + + bless $self, $class; + $self->_define($config); + + return $self; +} + +# Setup new instance. +sub _define { + my ( $self, $config, $dev ) = @_; + # config is at level: interfaces ethernet $dev input-policy redirect + $self->{_target} = $config->returnValue(); +} + +sub commands { + my ( $self, $dev, $parent ) = @_; + my $target = $self->{_target}; + + # Apply filter to ingress qdisc + # NB: action is egress because we are in ingress (upside down) + printf "filter add dev %s parent %x: ", $dev, $parent; + print " protocol all prio 10 u32"; + print " match u32 0 0 flowid 1:1"; + print " action mirred egress redirect dev $target\n"; +} + +1; + + diff --git a/scripts/vyatta-qos.pl b/scripts/vyatta-qos.pl index 7abfacc..b26b3c1 100755 --- a/scripts/vyatta-qos.pl +++ b/scripts/vyatta-qos.pl @@ -34,7 +34,6 @@ my %policies = ( 'round-robin' => 'RoundRobin', 'priority-queue' => 'Priority', 'random-detect' => 'RandomDetect', - 'traffic-limiter' => 'TrafficLimiter', ); # find policy for name - also check for duplicates @@ -107,13 +106,6 @@ sub delete_interface { # ignore errors (may have no qdisc) system($cmd); - - # remove IFB device if any - my $ifb = "ifb.$interface"; - if ( -d "/sys/class/net/$ifb") { - $cmd = "sudo ip link delete dev $ifb"; - system ($cmd); - } } ## start_interface('ppp0') @@ -164,40 +156,6 @@ sub update_interface { } my $parent = 1; - # Special case for traffic-limiter (not a real qdisc) - if ($policy eq 'traffic-limiter') { - if ($direction eq 'in') { - $parent = 0xffff; - print "qdisc add dev $device ingress\n"; - } else { - print "qdisc add dev $device root handle 1: prio\n"; - } - } - - # For non-ingress Qos use ifb device - elsif ($direction eq 'in') { - # load module but don't make any ifb's - system("sudo modprobe ifb numifbs=0") unless ( -d '/sys/module/ifb' ); - - # create new ifb device - my $ifb = "ifb.$device"; - system("sudo ip link add dev $ifb type ifb") == 0 - or die "Can't create $ifb: $!"; - system("sudo ip link set dev $ifb up") == 0 - or die "Can't bring $ifb up: $!"; - - # create ingress queue discipline - print "qdisc add dev $device ingress\n"; - - # redirect incoming packets to ifb - print "filter add dev $device parent ffff: protocol all prio 10"; - print " u32 match u32 0 0 flowid 1:1"; - print " action mirred egress redirect dev $ifb\n"; - - # tell shaper to use ifb device - $device = $ifb; - } - $shaper->commands( $device, $parent ); return if ($debug); @@ -274,6 +232,68 @@ sub apply_policy { } } +# ingress policy factory +sub ingress_policy { + my ($ifname) = @_; + my $intf = new Vyatta::Interface($ifname); + die "Unknown interface name $ifname\n" unless $intf; + + my $path = $intf->path(); + die "Can't find $ifname in configuration\n" unless $path; + + my $config = new Vyatta::Config; + $config->setLevel( "$path input-policy" ); + + my @names = $config->listNodes( ); + return if $#names < 0; + die "Only one incoming policy is allowed\n" if ($#names > 0); + + $config->setLevel( "$path input-policy " . $names[0] ); + my $type = ucfirst($names[0]); + my $location = "Vyatta/Qos/Ingress$type.pm"; + require $location; + + my $class = "Vyatta::Qos::Ingress$type"; + return $class->new( $config, $ifname ); +} + +# sets up input filtering +sub update_ingress { + my $device = shift; + + die "$device not present\n" unless (-d "/sys/class/net/$device"); + + my $ingress = ingress_policy( $device ); + return unless $ingress; + + # Drop existing ingress filters + system("sudo tc filter dev $device root 2>/dev/null"); + + # When doing debugging just echo the commands + my $out; + unless ($debug) { + open $out, "|-" + or exec qw:sudo /sbin/tc -batch -: + or die "Tc setup failed: $!\n"; + + select $out; + } + + my $parent = 0xffff; + $ingress->commands( $device, $parent ); + return if ($debug); + + select STDOUT; + unless (close $out) { + # cleanup any partial commands + system("sudo tc del dev $device ingress 2>/dev/null"); + + # replay commands to stdout + $ingress->commands($device, $parent ); + die "TC command failed."; + } +} + sub usage { print <<EOF; usage: vyatta-qos.pl --list-policy direction @@ -284,6 +304,7 @@ usage: vyatta-qos.pl --list-policy direction vyatta-qos.pl --update-interface interface direction policy-name vyatta-qos.pl --delete-interface interface direction + vyatta-qos.pl --update-ingress interface EOF exit 1; } @@ -296,22 +317,27 @@ my @applyPolicy = (); my @deletePolicy = (); my @startList = (); +my $updateIngress; + GetOptions( "start-interface=s" => \@startList, "update-interface=s{3}" => \@updateInterface, "delete-interface=s{2}" => \@deleteInterface, - - "list-policy=s" => \@listPolicy, - "delete-policy=s" => \@deletePolicy, - "create-policy=s{2}" => \@createPolicy, - "apply-policy=s" => \@applyPolicy, + "list-policy=s" => \@listPolicy, + "delete-policy=s" => \@deletePolicy, + "create-policy=s{2}" => \@createPolicy, + "apply-policy=s" => \@applyPolicy, + "update-ingress=s" => \$updateIngress ) or usage(); delete_interface(@deleteInterface) if ( $#deleteInterface == 1 ); update_interface(@updateInterface) if ( $#updateInterface == 2 ); start_interface(@startList) if (@startList); + list_policy(@listPolicy) if (@listPolicy); create_policy(@createPolicy) if ( $#createPolicy == 1 ); delete_policy(@deletePolicy) if (@deletePolicy); apply_policy(@applyPolicy) if (@applyPolicy); +update_ingress($updateIngress) if ($updateIngress); + |