Skip to content

Commit 94aeab7

Browse files
committed
tests: ipsec: Add NxN + reconciliation test.
Add a test to check establishment of IPsec connections among multiple nodes and check the reconciliation logic along the way. The test: - Creates 20 network namespaces. - Starts Libreswan, OVS and ovs-monitor-ipsec in each of them. - Adds a geneve tunnel from each namespace to every other namespace. - Checks that each namespace has all the IPsec connections loaded. - Removes a few connections manually. - Checks that these connections are added back. Unfortunately, many widely used versions of Libreswan have issues of pluto crashing frequently. For that reason the test is trying to bring pluto back online once it finds a dead one. Also, since retransmit-timeout is 60 seconds and our command timeout is 120, we can't actually use the OVS_WAIT_UNTIL macro most of the time, so the checks are done in the custom loop that waits up to 300 seconds. Acked-by: Eelco Chaudron <[email protected]> Signed-off-by: Ilya Maximets <[email protected]>
1 parent 992e09e commit 94aeab7

File tree

1 file changed

+125
-13
lines changed

1 file changed

+125
-13
lines changed

tests/system-ipsec.at

Lines changed: 125 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ m4_define([IPSEC_SETUP_UNDERLAY],
88
dnl Set up the underlay switch
99
AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])])
1010

11+
m4_define([START_PLUTO], [
12+
rm -f $ovs_base/$1/pluto.pid
13+
mkdir -p $ovs_base/$1/ipsec.d
14+
touch $ovs_base/$1/ipsec.conf
15+
touch $ovs_base/$1/secrets
16+
ipsec initnss --nssdir $ovs_base/$1/ipsec.d
17+
NS_CHECK_EXEC([$1], [ipsec pluto --config $ovs_base/$1/ipsec.conf \
18+
--ipsecdir $ovs_base/$1 --nssdir $ovs_base/$1/ipsec.d \
19+
--logfile $ovs_base/$1/pluto.log --secretsfile $ovs_base/$1/secrets \
20+
--rundir $ovs_base/$1], [0], [], [stderr])
21+
])
22+
1123
dnl IPSEC_ADD_NODE([namespace], [device], [address], [peer address]))
1224
dnl
1325
dnl Creates a dummy host that acts as an IPsec endpoint. Creates host in
@@ -45,15 +57,8 @@ m4_define([IPSEC_ADD_NODE],
4557
on_exit "kill_ovs_vswitchd `cat $ovs_base/$1/vswitchd.pid`"
4658

4759
dnl Start pluto
48-
mkdir -p $ovs_base/$1/ipsec.d
49-
touch $ovs_base/$1/ipsec.conf
50-
touch $ovs_base/$1/secrets
51-
ipsec initnss --nssdir $ovs_base/$1/ipsec.d
52-
NS_CHECK_EXEC([$1], [ipsec pluto --config $ovs_base/$1/ipsec.conf \
53-
--ipsecdir $ovs_base/$1 --nssdir $ovs_base/$1/ipsec.d \
54-
--logfile $ovs_base/$1/pluto.log --secretsfile $ovs_base/$1/secrets \
55-
--rundir $ovs_base/$1], [0], [], [stderr])
56-
on_exit "kill `cat $ovs_base/$1/pluto.pid`"
60+
START_PLUTO([$1])
61+
on_exit 'kill $(cat $ovs_base/$1/pluto.pid)'
5762

5863
dnl Start ovs-monitor-ipsec
5964
NS_CHECK_EXEC([$1], [ovs-monitor-ipsec unix:${OVS_RUNDIR}/$1/db.sock\
@@ -110,16 +115,18 @@ m4_define([CHECK_LIBRESWAN],
110115
dnl IPSEC_STATUS_LOADED([])
111116
dnl
112117
dnl Get number of loaded connections from ipsec status
113-
m4_define([IPSEC_STATUS_LOADED], [ipsec --rundir $ovs_base/$1 status | \
118+
m4_define([IPSEC_STATUS_LOADED], [
119+
ipsec --rundir $ovs_base/$1 status | \
114120
grep "Total IPsec connections" | \
115-
sed 's/[[0-9]]* *Total IPsec connections: loaded \([[0-2]]\), active \([[0-2]]\).*/\1/m'])
121+
sed 's/[[0-9]]* *Total IPsec connections: loaded \([[0-9]]*\), active \([[0-9]]*\).*/\1/m'])
116122

117123
dnl IPSEC_STATUS_ACTIVE([])
118124
dnl
119125
dnl Get number of active connections from ipsec status
120-
m4_define([IPSEC_STATUS_ACTIVE], [ipsec --rundir $ovs_base/$1 status | \
126+
m4_define([IPSEC_STATUS_ACTIVE], [
127+
ipsec --rundir $ovs_base/$1 status | \
121128
grep "Total IPsec connections" | \
122-
sed 's/[[0-9]]* *Total IPsec connections: loaded \([[0-2]]\), active \([[0-2]]\).*/\2/m'])
129+
sed 's/[[0-9]]* *Total IPsec connections: loaded \([[0-9]]*\), active \([[0-9]]*\).*/\2/m'])
123130

124131
dnl CHECK_ESP_TRAFFIC()
125132
dnl
@@ -401,3 +408,108 @@ CHECK_ESP_TRAFFIC
401408

402409
OVS_TRAFFIC_VSWITCHD_STOP()
403410
AT_CLEANUP
411+
412+
AT_SETUP([IPsec -- Libreswan NxN geneve tunnels + reconciliation])
413+
AT_KEYWORDS([ipsec libreswan scale reconciliation])
414+
dnl Note: Geneve test may not work on older kernels due to CVE-2020-25645
415+
dnl https://bugzilla.redhat.com/show_bug.cgi?id=1883988
416+
417+
CHECK_LIBRESWAN()
418+
OVS_TRAFFIC_VSWITCHD_START()
419+
IPSEC_SETUP_UNDERLAY()
420+
421+
m4_define([NODES], [20])
422+
423+
dnl Set up fake hosts.
424+
m4_for([id], [1], NODES, [1], [
425+
IPSEC_ADD_NODE([node-id], [p-id], 10.1.1.id, 10.1.1.254)
426+
AT_CHECK([ovs-pki -b -d ${ovs_base} -l ${ovs_base}/ovs-pki.log \
427+
req -u node-id], [0], [stdout])
428+
AT_CHECK([ovs-pki -b -d ${ovs_base} -l ${ovs_base}/ovs-pki.log \
429+
self-sign node-id], [0], [stdout])
430+
AT_CHECK(OVS_VSCTL([node-id], set Open_vSwitch . \
431+
other_config:certificate=${ovs_base}/node-id-cert.pem \
432+
other_config:private_key=${ovs_base}/node-id-privkey.pem),
433+
[0], [ignore], [ignore])
434+
on_exit "ipsec --rundir $ovs_base/node-id status > $ovs_base/node-id/status"
435+
])
436+
437+
dnl Create a full mesh of tunnels.
438+
m4_for([LEFT], [1], NODES, [1], [
439+
m4_for([RIGHT], [1], NODES, [1], [
440+
if test LEFT -ne RIGHT; then
441+
AT_CHECK(OVS_VSCTL(node-LEFT, add-port br-ipsec tun-RIGHT \
442+
-- set Interface tun-RIGHT type=geneve options:remote_ip=10.1.1.RIGHT \
443+
options:remote_cert=${ovs_base}/node-RIGHT-cert.pem),
444+
[0], [ignore], [ignore])
445+
fi
446+
])])
447+
448+
m4_define([WAIT_FOR_LOADED_CONNS], [
449+
m4_for([id], [1], NODES, [1], [
450+
echo "================== node-id ========================="
451+
iterations=0
452+
loaded=0
453+
dnl Using a custom loop instead of OVS_WAIT_UNTIL, because it may take
454+
dnl much longer than a default timeout. The default retransmit timeout
455+
dnl for pluto is 60 seconds. Also, we need to make sure pluto didn't
456+
dnl crash in the process and revive it if it did, unfortunately.
457+
while true; do
458+
date
459+
AT_CHECK([ipsec --rundir $ovs_base/node-id status 2>&1 \
460+
| grep -E "whack|Total"], [ignore], [stdout])
461+
if grep -E 'is Pluto running?|refused' stdout; then
462+
echo "node-id: Pluto died, restarting..."
463+
START_PLUTO([node-id])
464+
else
465+
loaded=$(IPSEC_STATUS_LOADED(node-id))
466+
fi
467+
if test "$loaded" -ne $(( (NODES - 1) * 2 )); then
468+
sleep 3
469+
else
470+
break
471+
fi
472+
let iterations=$iterations+1
473+
AT_CHECK([test $iterations -lt 100])
474+
done
475+
])
476+
])
477+
478+
dnl Wait for all the connections to be loaded to pluto. Not waiting for
479+
dnl them to become active, because if pluto is down on one of the nodes,
480+
dnl some connections may not become active until we revive it. Some
481+
dnl connections may also never become active due to bugs in libreswan 4.x.
482+
WAIT_FOR_LOADED_CONNS()
483+
484+
AT_CHECK([ipsec auto --help], [ignore], [ignore], [stderr])
485+
auto=auto
486+
if test -s stderr; then
487+
auto=
488+
fi
489+
490+
dnl Remove connections for two tunnels. One fully and one partially.
491+
AT_CHECK([ipsec $auto --ctlsocket $ovs_base/node-1/pluto.ctl \
492+
--config $ovs_base/node-1/ipsec.conf \
493+
--delete tun-5-out-1], [0], [stdout])
494+
AT_CHECK([ipsec $auto --ctlsocket $ovs_base/node-1/pluto.ctl \
495+
--config $ovs_base/node-1/ipsec.conf \
496+
--delete tun-2-in-1], [0], [stdout])
497+
AT_CHECK([ipsec $auto --ctlsocket $ovs_base/node-1/pluto.ctl \
498+
--config $ovs_base/node-1/ipsec.conf \
499+
--delete tun-2-out-1], [0], [stdout])
500+
501+
dnl Wait for the monitor to notice the missing connections.
502+
OVS_WAIT_UNTIL([grep -q 'tun-2.*need to reconcile' \
503+
$ovs_base/node-1/ovs-monitor-ipsec.log])
504+
505+
dnl Wait for all the connections to be loaded back.
506+
WAIT_FOR_LOADED_CONNS()
507+
508+
dnl These are not necessary, but nice to have in the test log in
509+
dnl order to spot pluto failures during the test.
510+
grep -E 'Timed out|outdated|half-loaded|defunct' \
511+
$ovs_base/node-*/ovs-monitor-ipsec.log
512+
grep -E 'ABORT|ERROR' $ovs_base/node-*/pluto.log
513+
514+
OVS_TRAFFIC_VSWITCHD_STOP()
515+
AT_CLEANUP

0 commit comments

Comments
 (0)