From 00825afd79a45977698e25f31db65fc60d96628f Mon Sep 17 00:00:00 2001 From: zsdc Date: Mon, 4 May 2020 16:24:57 +0300 Subject: VTI: T1291: Fix for invlid VTI interface down state In case when between hosts exists two IPSec tunnels for VTI (for example, when both sides act as connection initiators), the older unused/replaced tunnel may switch VTI interface to the "down" state even if a newer IPSec connection is still in-use. Depending on other IPSec settings, this leads to a situation when VTI interfaces continuously flapping or stuck in a "down" state. This fix is an adaptation of PR from @m-asama for the current code base. It adding new dependency from actual SA state of IPSec connection, and do not allow to switch down a VTI interface if at least one of child connections is active or try to change the state of a VTI interface to the same, as already active. --- scripts/vti-up-down | 7 +++---- scripts/vyatta-vti-config.pl | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/scripts/vti-up-down b/scripts/vti-up-down index 08e31c0..4672076 100755 --- a/scripts/vti-up-down +++ b/scripts/vti-up-down @@ -5,15 +5,14 @@ source /etc/default/vyatta source /etc/default/locale case "$PLUTO_VERB" in -route-client | up-client | up-host) +up-client | up-host) /bin/ip route delete default table 220 -/opt/vyatta/sbin/vyatta-vti-config.pl --updown --intf=$1 --action=up +/opt/vyatta/sbin/vyatta-vti-config.pl --updown --intf=$1 --conn=$PLUTO_CONNECTION --action=up > /dev/null 2>&1 & ;; down-client | down-host) -/opt/vyatta/sbin/vyatta-vti-config.pl --updown --intf=$1 --action=down +/opt/vyatta/sbin/vyatta-vti-config.pl --updown --intf=$1 --conn=$PLUTO_CONNECTION --action=down > /dev/null 2>&1 & ;; *) ;; esac exit 0 - diff --git a/scripts/vyatta-vti-config.pl b/scripts/vyatta-vti-config.pl index 0886202..0318b22 100755 --- a/scripts/vyatta-vti-config.pl +++ b/scripts/vyatta-vti-config.pl @@ -45,29 +45,35 @@ my $gencmds = ""; my $result = 0; my $updown=""; my $intfName=""; +my $conn_name=""; my $action=""; my $checkref=""; GetOptions( "updown" => \$updown, "intf=s" => \$intfName, + "conn=s" => \$conn_name, "action=s" => \$action, "checkref" => \$checkref, ); # -# --updown intfName --action=[up|down] +# --updown --intf=vtiX --conn=peer-X.X.X.X-tunnel-vti --action=[up|down] # if ($updown ne '') { if (!(defined $intfName) || $intfName eq '') { # invalid exit -1; } + if (!(defined $conn_name) || $conn_name eq '' || $conn_name !~ m/^peer-[a-zA-Z0-9_.:-]+-tunnel-vti$/) { + # invalid + exit -1; + } if (!(defined $action) || $action eq '') { # invalid exit -1; } - vti_handle_updown($intfName, $action); + vti_handle_updown($intfName, $conn_name, $action); exit 0; } @@ -230,7 +236,7 @@ exit $result; # Handle VTI tunnel state based on input from strongswan and configuration. # sub vti_handle_updown { - my ($intfName, $action) = @_; + my ($intfName, $conn_name, $action) = @_; my $vcIntf = new Vyatta::Config(); $vcIntf->setLevel('interfaces'); my $disabled = $vcIntf->existsOrig("vti $intfName disabled"); @@ -254,7 +260,15 @@ sub vti_handle_updown { } } } - system("sudo /sbin/ip link set $intfName $action\n"); + # check if child SA is in ISTALLED state (connection already fully established) + # we are inverting exit code to convert 0 value to True in Perl + my $child_sa_installed = !system("sudo swanctl -l -r -i $conn_name | grep -s -q state=INSTALLED"); + # change interface state only if one of these is true: + # - VTI interface is in UP state, no active child SA was found, and event is down-client or down-host + # - VTI interface is in DOWN state, active child SA was found, and event is up-client or up-host + if (($state && !$child_sa_installed && ($action eq "down")) || (!$state && $child_sa_installed && ($action eq "up"))) { + system("sudo /sbin/ip link set $intfName $action\n"); + } } } } -- cgit v1.2.3