@@ -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+
1123dnl IPSEC_ADD_NODE([namespace], [device], [address], [peer address]))
1224dnl
1325dnl 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],
110115dnl IPSEC_STATUS_LOADED([])
111116dnl
112117dnl 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
117123dnl IPSEC_STATUS_ACTIVE([])
118124dnl
119125dnl 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
124131dnl CHECK_ESP_TRAFFIC()
125132dnl
@@ -401,3 +408,108 @@ CHECK_ESP_TRAFFIC
401408
402409OVS_TRAFFIC_VSWITCHD_STOP()
403410AT_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