summaryrefslogtreecommitdiff
path: root/scripts/vyatta-vti-config.pl
diff options
context:
space:
mode:
authorSaurabh Mohan <saurabh.mohan@vyatta.com>2012-07-25 14:53:42 -0700
committerSaurabh Mohan <saurabh.mohan@vyatta.com>2012-07-25 14:53:42 -0700
commitf1f5731f32e744ba11aef2ecdf0e6bc0e0c03307 (patch)
tree29e09b9b3c86930ef3949d144f61e11d7fd7137d /scripts/vyatta-vti-config.pl
parent2afcd1518814ae1ff900196e57b9fcbd4b61b56f (diff)
downloadvyatta-cfg-vpn-f1f5731f32e744ba11aef2ecdf0e6bc0e0c03307.tar.gz
vyatta-cfg-vpn-f1f5731f32e744ba11aef2ecdf0e6bc0e0c03307.zip
Bugfix 8222: deletion and adding bind parameter under vti deletes vti interface in show interfaces output though vti configuration exists
The bind, mark parameters can be changed individually but the vti script runs at the vpn node level. By that time the old value is not known. With this change now I find out the exisiting vti tunnels from the kernel and discover the old vti-name, and mark setting from there. After that it is possible to figure out if a. No change was done to a VTI: In that case do not do any config. b. If a tunnel was changed: Delete and create the tunnel again. c. If a tunnel was deleted: Remove the tunnel config from the kernel. d. If the tunnel was added: Configure it. Also, configure the vti interface prior to the strongswan configuration. This way if the ipsec tunnel comes up then we can bring the interface up/down (see Bug 8219). Remove the disable configuration param (see Bug 8221).
Diffstat (limited to 'scripts/vyatta-vti-config.pl')
-rwxr-xr-xscripts/vyatta-vti-config.pl208
1 files changed, 193 insertions, 15 deletions
diff --git a/scripts/vyatta-vti-config.pl b/scripts/vyatta-vti-config.pl
index cbbde32..86c9f95 100755
--- a/scripts/vyatta-vti-config.pl
+++ b/scripts/vyatta-vti-config.pl
@@ -82,6 +82,26 @@ if ($checkref ne '' ) {
exit $rval;
}
+###
+# Following code is to configure the vti.
+#
+
+# Collect set of existing Vti's.
+my %existingVtiName = ();
+my %existingVtiMark = ();
+
+my @currentVtis = `/sbin/ip tunnel | grep "^vti"`;
+if (@currentVtis != 0) {
+ my ($remote, $local, $name, $mark);
+ my $key;
+ foreach my $curVti (@currentVtis) {
+ ($remote, $local, $name, $mark) = parseVtiTun($curVti);
+ $key = "remote $remote local $local";
+ $existingVtiName{$key} = $name;
+ $existingVtiMark{$key} = $mark;
+ }
+}
+
#
# Prepare Vyatta::Config object
#
@@ -92,16 +112,19 @@ $vcVPN->setLevel('vpn');
$vcIntf->setLevel('interfaces');
if (!$vcVPN->exists('ipsec') ) {
+ cleanupVtiNotConfigured();
+ $result = execGenCmds();
exit $result;
}
if (!$vcVPN->exists('ipsec site-to-site') ) {
+ cleanupVtiNotConfigured();
+ $result = execGenCmds();
exit $result;
}
-my @peers = $vcVPN->listNodes('ipsec site-to-site peer');
-if (@peers == 0) {
- exit $result;
-}
+ my %marks = ();
+ my %binds = ();
+ my @peers = $vcVPN->listNodes('ipsec site-to-site peer');
foreach my $peer (@peers) {
if (! $vcVPN->exists("ipsec site-to-site peer $peer vti")) {
next;
@@ -112,6 +135,7 @@ if (@peers == 0) {
my $lip = $vcVPN->returnValue("ipsec site-to-site peer $peer local-address");
my $mark = $vcVPN->returnValue("ipsec site-to-site peer $peer vti mark");
my $tunName = $vcVPN->returnValue("ipsec site-to-site peer $peer vti bind");
+ my $change = 0;
# Check local address is valid.
if (!defined($lip)) {
@@ -128,6 +152,13 @@ if (@peers == 0) {
print STDERR "$vti_cfg_err Invalid tunnel name vti \"$tunName\".\n";
exit -1;
}
+ if (exists $binds{ $tunName }) {
+ vti_die(["vpn","ipsec","site-to-site","peer",$peer,"vti","bind"],
+ "vti bind $tunName already used.\n");
+ } else {
+ $binds{ $tunName } = 1;
+ }
+
# Check mark is valid.
if (!defined($mark)) {
print STDERR "$vti_cfg_err mark not defined.\n";
@@ -137,6 +168,14 @@ if (@peers == 0) {
print STDERR "$vti_cfg_err Invalid mark \"$mark\".\n";
exit -1;
}
+ if (exists $marks{ $mark }) {
+ vti_die(["vpn","ipsec","site-to-site","peer",$peer,"vti","mark"],
+ "vti mark $mark already used.\n");
+ } else {
+ $marks{ $mark } = 1;
+ }
+
+ $gencmds .= "# For peer $peer local $lip.\n";
#
# Get the tunnel parameters.
#
@@ -152,6 +191,34 @@ if (@peers == 0) {
# description.
my $description = $vcIntf->returnValue("vti $tunName description");
+ # Check if the tunnel exists already.
+ my $vtiPresent = isVtinamepresent($peer, $lip);
+ if (defined($vtiPresent) && !($vtiPresent eq "")) {
+ if ($vtiPresent ne $tunName) {
+ # Binding changed.
+ $gencmds .= "sudo /sbin/ip link delete $vtiPresent &> /dev/null\n";
+ $change = 1;
+ }
+ }
+
+ my $existingMark = isVtimarkpresent($peer, $lip);
+ if (defined($existingMark) && !($existingMark eq "")) {
+ if ($existingMark ne $mark) {
+ # Mark changed.
+ $gencmds .= iptableDelMark($peer, $lip, $existingMark);
+ $change = 1;
+ }
+ } else {
+ $change = 1;
+ }
+
+ if ($change eq 0) {
+ # now remove it from the exisiting tunnel list as
+ # we've already configured it.
+ deleteVtinamepresent($peer, $lip);
+ next;
+ }
+
#
# Set the configuration into the output string.
#
@@ -166,19 +233,14 @@ if (@peers == 0) {
if (defined($description)) {
$gencmds .= "if [ -d /sys/class/net/$tunName ] ; then\n\tsudo echo \"$description\" > /sys/class/net/$tunName/ifalias\nfi\n";
}
+
+ # setup the new mark.
+ $gencmds .= iptableAddMark($peer, $lip, $mark);
}
-if ($gencmds ne "") {
- open my $output_config, '>', '/tmp/vti_config' or die "Can't open /tmp/vti_config $!";
- print ${output_config} "#!/bin/sh\n";
- print ${output_config} $gencmds;
- close $output_config;
- `chmod 755 /tmp/vti_config`;
- system("/tmp/vti_config");
- $result = $? >> 8;
- #@SM TODO: remove /tmp/vti_config;
-}
-exit $result;
+ cleanupVtiNotConfigured();
+ $result = execGenCmds();
+ exit $result;
#
@@ -214,3 +276,119 @@ sub vti_check_reference {
}
return 0;
}
+
+#
+# Api takes as input the o/p of 'ip tunnel show' and
+# returns a list with {remote,local,name,mark}
+# Example input:
+# vti2: ip/ip remote 12.0.0.2 local 12.0.0.1 ttl inherit nopmtudisc key 15
+#
+sub parseVtiTun {
+ my ($tunop) = @_;
+ my ($tunName, $remote, $local, $mark);
+ if ($tunop =~ m/(^vti.*): .*/) {
+ $tunName = $1;
+ }
+ if ($tunop =~ m/remote ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) {
+ $remote = $1;
+ }
+ if ($tunop =~ m/local ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) {
+ $local = $1;
+ }
+ if ($tunop =~ m/key ([0-9\.]+)/) {
+ $mark = $1;
+ }
+ return($remote, $local, $tunName, $mark);
+}
+
+sub extractRemoteLocal {
+ my ($key) = @_;
+ my ($remote, $local);
+ if ($key =~ m/remote ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) {
+ $remote = $1;
+ }
+ if ($key =~ m/local ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) {
+ $local = $1;
+ }
+ return($remote, $local);
+}
+
+sub isVtinamepresent {
+ my ($remote, $local) = @_;
+ my $key = "remote $remote local $local";
+
+ if (exists $existingVtiName{$key} ) {
+ return $existingVtiName{$key};
+ }
+ return "";
+}
+
+sub deleteVtinamepresent {
+ my ($remote, $local) = @_;
+ my $key = "remote $remote local $local";
+
+ if (exists $existingVtiName{$key} ) {
+ delete $existingVtiName{$key};
+ }
+}
+
+sub isVtimarkpresent {
+ my ($remote, $local) = @_;
+ my $key = "remote $remote local $local";
+
+ if (exists $existingVtiMark{$key} ) {
+ return $existingVtiMark{$key};
+ }
+ return "";
+}
+
+sub iptableDelMark {
+ my ($remote, $local, $mark) = @_;
+ my $opcmd="";
+
+ $opcmd .= "sudo iptables -t mangle -D PREROUTING -s $remote -d $local -p esp -j MARK --set-mark $mark\n";
+ $opcmd .= "sudo iptables -t mangle -D PREROUTING -s $remote -d $local -p udp --dport 4500 -j MARK --set-mark $mark\n";
+ return $opcmd;
+}
+
+sub iptableAddMark {
+ my ($remote, $local, $mark) = @_;
+ my $opcmd="";
+
+ $opcmd .= "sudo iptables -t mangle -A PREROUTING -s $remote -d $local -p esp -j MARK --set-mark $mark\n";
+ $opcmd .= "sudo iptables -t mangle -A PREROUTING -s $remote -d $local -p udp --dport 4500 -j MARK --set-mark $mark\n";
+ return $opcmd;
+}
+
+sub cleanupVtiNotConfigured {
+ # for all remaining entries in the Vtinamepresent hash
+ # remove them from the system.
+ while (my ($tunKey, $presentVtiName) = each(%existingVtiName) ) {
+ my ($remote, $local) = extractRemoteLocal($tunKey);
+ my $existingMark = isVtimarkpresent($remote, $local);
+ $gencmds .= "# For peer $remote local $local.\n";
+ $gencmds .= "sudo /sbin/ip link delete $presentVtiName &> /dev/null\n";
+ $gencmds .= iptableDelMark($remote, $local, $existingMark);
+ }
+}
+
+sub execGenCmds {
+ if ($gencmds ne "") {
+ open my $output_config, '>', '/tmp/vti_config' or die "Can't open /tmp/vti_config $!";
+ print ${output_config} "#!/bin/sh\n";
+ print ${output_config} $gencmds;
+ close $output_config;
+ `chmod 755 /tmp/vti_config`;
+ system("/tmp/vti_config");
+ $result = $? >> 8;
+ #TODO: remove /tmp/vti_config;
+ return $result;
+ }
+ return 0;
+}
+
+sub vti_die {
+ my (@path,$msg) = @_;
+ Vyatta::Config::outputError(@path, $msg);
+ exit 1;
+}