1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
m4_divert_push([PREPARE_TESTS])
[
# Strips out uninteresting parts of ovs-ofctl output, as well as parts
# that vary from one run to another.
ofctl_strip () {
sed '
s/ (xid=0x[0-9a-fA-F]*)//
s/ duration=[0-9.]*s,//
s/ cookie=0x0,//
s/ table=0,//
s/ n_packets=0,//
s/ n_bytes=0,//
s/ idle_age=[0-9]*,//
s/ hard_age=[0-9]*,//
'
}
# Filter (multiline) vconn debug messages from ovs-vswitchd.log.
# Use with vconn_windows_sub() and ofctl_strip()
print_vconn_debug () { awk -F\| < ovs-vswitchd.log '
BEGIN { prt=0 }
/\|vconn\|DBG\|/ { sub(/[ \t]*$/, ""); print $3 "|" $4 "|" $5; prt=1; next }
$4 != "" { prt=0; next }
prt==1 { sub(/[ \t]*$/, ""); print $0 }
'
}
vconn_windows_sub() {
sed '
s/tcp:127.0.0.1:[0-9][0-9]*:/unix:/
s/No error/Success/
'
}
# parse_listening_port [SERVER]
#
# Parses the TCP or SSL port on which a server is listening from the
# log, given that the server was told to listen on a kernel-chosen
# port, file provided on stdin, and prints the port number on stdout.
# You should specify the listening remote as ptcp:0:127.0.0.1 or
# pssl:0:127.0.0.1, or the equivalent with [::1] instead of 127.0.0.1.
#
# Here's an example of how to use this with ovsdb-server:
#
# ovsdb-server --log-file --remote=ptcp:0:127.0.0.1 ...
# TCP_PORT=`parse_listening_port < ovsdb-server.log`
parse_listening_port () {
sed -n 's/.*0:.*: listening on port \([0-9]*\)$/\1/p'
}]
start_daemon () {
"$@" -vconsole:off --detach --no-chdir --pidfile --log-file
pid=`cat "$OVS_RUNDIR"/$1.pid`
on_exit "kill $pid"
}
# sim_add SANDBOX
#
# Starts a new simulated Open vSwitch instance named SANDBOX. Files related to
# the instance, such as logs, databases, sockets, and pidfiles, are created in
# a subdirectory of the main test directory also named SANDBOX. Afterward, the
# "as" command (see below) can be used to run Open vSwitch utilities in the
# context of the new sandbox.
#
# The new sandbox starts out without any bridges. Use ovs-vsctl in the context
# of the new sandbox to create a bridge, e.g.:
#
# sim_add hv0 # Create sandbox hv0.
# as hv0 # Set hv0 as default sandbox.
# ovs-vsctl add-br br0 # Add bridge br0 inside hv0.
#
# or:
#
# sim_add hv0
# as hv0 ovs-vsctl add-br br0
sims=
sim_add () {
echo "adding simulator '$1'"
sims="$sims $1"
# Create sandbox.
local d="$ovs_base"/$1
mkdir "$d" || return 1
ovs_setenv $1
# Create database and start ovsdb-server.
: > "$d"/.conf.db.~lock~
as $1 ovsdb-tool create "$d"/conf.db "$abs_top_srcdir"/vswitchd/vswitch.ovsschema || return 1
as $1 start_daemon ovsdb-server --remote=punix:"$d"/db.sock || return 1
# Initialize database.
as $1 ovs-vsctl --no-wait -- init || return 1
# Start ovs-vswitchd
as $1 start_daemon ovs-vswitchd --enable-dummy=system -vvconn -vofproto_dpif
}
# "as $1" sets the OVS_*DIR environment variables to point to $ovs_base/$1.
#
# "as $1 COMMAND..." sets those variables in a subshell and invokes COMMAND
# there.
as() {
if test "X$1" != X; then
(ovs_setenv $1; shift; $@)
else
ovs_setenv $1
fi
}
# ovn_init_db DATABASE
#
# Creates and initializes the given DATABASE (one of "ovn-sb" or "ovn-nb"),
# starts its ovsdb-server instance, and sets the appropriate environment
# variable (OVN_SB_DB or OVN_NB_DB) so that ovn-sbctl or ovn-nbctl uses the
# database by default.
#
# Usually invoked from ovn_start.
ovn_init_db () {
echo "creating $1 database"
local d=$ovs_base/$1
mkdir "$d" || return 1
: > "$d"/.$1.db.~lock~
as $1 ovsdb-tool create "$d"/$1.db "$abs_top_srcdir"/ovn/$1.ovsschema
as $1 start_daemon ovsdb-server --remote=punix:"$d"/$1.sock "$d"/$1.db
local var=`echo $1_db | tr a-z- A-Z_`
AS_VAR_SET([$var], [unix:$ovs_base/$1/$1.sock]); export $var
}
# ovn_start
#
# Creates and initializes ovn-sb and ovn-nb databases and starts their
# ovsdb-server instance, sets appropriate environment variables so that
# ovn-sbctl and ovn-nbctl use them by default, and starts ovn-northd running
# against them.
ovn_start () {
ovn_init_db ovn-sb
ovn_init_db ovn-nb
echo "starting ovn-northd"
mkdir "$ovs_base"/northd
as northd start_daemon ovn-northd \
--ovnnb-db=unix:"$ovs_base"/ovn-nb/ovn-nb.sock \
--ovnsb-db=unix:"$ovs_base"/ovn-sb/ovn-sb.sock
}
# Interconnection networks.
#
# When multiple sandboxed Open vSwitch instances exist, one will inevitably
# want to connect them together. These commands allow for that. Conceptually,
# an interconnection network is a switch for which these functions make it easy
# to plug into other switches in other sandboxed Open vSwitch instances.
# Interconnection networks are implemented as bridges in a switch named "main",
# so to use interconnection networks please avoid working with that switch
# directly.
# net_add NETWORK
#
# Creates a new interconnection network named NETWORK.
net_add () {
test -d "$ovs_base"/main || sim_add main || return 1
as main ovs-vsctl add-br "$1"
}
# net_attach NETWORK BRIDGE
#
# Adds a new port to BRIDGE in the default sandbox (as set with as()) and plugs
# it into the NETWORK interconnection network. NETWORK must already have been
# created by a previous invocation of net_add. The default sandbox must not be
# "main".
net_attach () {
local net=$1 bridge=$2
local port=${sandbox}_$bridge
as main ovs-vsctl \
-- add-port $net $port \
-- set Interface $port options:pstream="punix:$ovs_base/main/$port.sock" options:rxq_pcap="$ovs_base/main/$port-rx.pcap" options:tx_pcap="$ovs_base/main/$port-tx.pcap" \
|| return 1
ovs-vsctl \
-- set Interface $bridge options:tx_pcap="$ovs_base/$sandbox/$bridge-tx.pcap" options:rxq_pcap="$ovs_base/$sandbox/$bridge-rx.pcap" \
-- add-port $bridge ${bridge}_$net \
-- set Interface ${bridge}_$net options:stream="unix:$ovs_base/main/$port.sock" options:rxq_pcap="$ovs_base/$sandbox/${bridge}_$net-rx.pcap" options:tx_pcap="$ovs_base/$sandbox/${bridge}_$net-tx.pcap" \
|| return 1
}
# ovn_attach NETWORK BRIDGE IP [MASKLEN]
#
# First, this command attaches BRIDGE to interconnection network NETWORK, just
# like "net_attach NETWORK BRIDGE". Second, it configures (simulated) IP
# address IP (with network mask length MASKLEN, which defaults to 24) on
# BRIDGE. Finally, it configures the Open vSwitch database to work with OVN
# and starts ovn-controller.
ovn_attach() {
local net=$1 bridge=$2 ip=$3 masklen=${4-24}
net_attach $net $bridge || return 1
mac=`ovs-vsctl get Interface $bridge mac_in_use | sed s/\"//g`
arp_table="$arp_table $sandbox,$bridge,$ip,$mac"
ovs-appctl netdev-dummy/ip4addr $bridge $ip/$masklen >/dev/null || return 1
ovs-appctl ovs/route/add $ip/$masklen $bridge >/dev/null || return 1
ovs-vsctl \
-- set Open_vSwitch . external-ids:system-id=$sandbox \
-- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-- set Open_vSwitch . external-ids:ovn-encap-ip=$ip \
-- add-br br-int \
-- set bridge br-int fail-mode=secure other-config:disable-in-band=true \
|| return 1
start_daemon ovn-controller || return 1
}
# ovn_populate_arp
#
# This pre-populates the ARP tables of all of the OVN instances that have been
# started with ovn_attach(). That means that packets sent from one hypervisor
# to another never get dropped or delayed by ARP resolution, which makes
# testing easier.
ovn_populate_arp() {
for e1 in $arp_table; do
set `echo $e1 | sed 's/,/ /g'`; sb1=$1 br1=$2 ip=$3 mac=$4
for e2 in $arp_table; do
set `echo $e2 | sed 's/,/ /g'`; sb2=$1 br2=$2
if test $sb1,$br1 != $sb2,$br2; then
as $sb2 ovs-appctl tnl/arp/set $br2 $ip $mac
fi
done
done
}
m4_divert_pop([PREPARE_TESTS])
m4_define([STRIP_XIDS], [[sed 's/ (xid=0x[0-9a-fA-F]*)//']])
m4_define([STRIP_DURATION], [[sed 's/\bduration=[0-9.]*s/duration=?s/']])
m4_define([STRIP_USED], [[sed 's/used:[0-9]\.[0-9]*/used:0.0/']])
m4_define([STRIP_UFID], [[sed 's/ufid:[-0-9a-f]* //']])
m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
# _OVS_VSWITCHD_START([vswitchd-aux-args])
#
# Creates an empty database and starts ovsdb-server.
# Starts ovs-vswitchd, with additional arguments 'vswitchd-aux-args'.
#
m4_define([_OVS_VSWITCHD_START],
[dnl Create database.
touch .conf.db.~lock~
AT_CHECK([ovsdb-tool create conf.db $abs_top_srcdir/vswitchd/vswitch.ovsschema])
dnl Start ovsdb-server.
AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:$OVS_RUNDIR/db.sock], [0], [], [stderr])
on_exit "kill `cat ovsdb-server.pid`"
AT_CHECK([[sed < stderr '
/vlog|INFO|opened log file/d
/ovsdb_server|INFO|ovsdb-server (Open vSwitch)/d']])
AT_CAPTURE_FILE([ovsdb-server.log])
dnl Initialize database.
AT_CHECK([ovs-vsctl --no-wait init])
dnl Start ovs-vswitchd.
AT_CHECK([ovs-vswitchd $1 --detach --no-chdir --pidfile --log-file -vvconn -vofproto_dpif], [0], [], [stderr])
AT_CAPTURE_FILE([ovs-vswitchd.log])
on_exit "kill `cat ovs-vswitchd.pid`"
AT_CHECK([[sed < stderr '
/ovs_numa|INFO|Discovered /d
/vlog|INFO|opened log file/d
/vswitchd|INFO|ovs-vswitchd (Open vSwitch)/d
/reconnect|INFO|/d
/ofproto|INFO|using datapath ID/d
/ofproto|INFO|datapath ID changed to fedcba9876543210/d']])
])
# OVS_VSWITCHD_START([vsctl-args], [vsctl-output], [=override])
#
# Creates a database and starts ovsdb-server, starts ovs-vswitchd
# connected to that database, calls ovs-vsctl to create a bridge named
# br0 with predictable settings, passing 'vsctl-args' as additional
# commands to ovs-vsctl. If 'vsctl-args' causes ovs-vsctl to provide
# output (e.g. because it includes "create" commands) then 'vsctl-output'
# specifies the expected output after filtering through uuidfilt.pl.
#
# If a test needs to use "system" devices (as dummies), then specify
# =override (literally) as the third argument. Otherwise, system devices
# won't work at all (which makes sense because tests should not access a
# system's real Ethernet devices).
m4_define([OVS_VSWITCHD_START],
[_OVS_VSWITCHD_START([--enable-dummy$3 --disable-system])
dnl Add bridges, ports, etc.
AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 protocols=[[OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13,OpenFlow14,OpenFlow15]] fail-mode=secure -- $1 m4_if([$2], [], [], [| ${PERL} $srcdir/uuidfilt.pl])], [0], [$2])
])
# check_logs scans through all *.log files (except '*.log' and testsuite.log)
# and reports all WARN, ERR, EMER log entries. User can add custom sed filters
# in $1.
m4_divert_push([PREPARE_TESTS])
check_logs () {
local logs
for log in *.log; do
case ${log} in # (
'*.log'|testsuite.log) ;; # (
*) logs="${logs} ${log}" ;;
esac
done
sed -n "$1
/timeval.*Unreasonably long [[0-9]]*ms poll interval/d
/timeval.*faults: [[0-9]]* minor, [[0-9]]* major/d
/timeval.*disk: [[0-9]]* reads, [[0-9]]* writes/d
/timeval.*context switches: [[0-9]]* voluntary, [[0-9]]* involuntary/d
/ovs_rcu.*blocked [[0-9]]* ms waiting for .* to quiesce/d
/|WARN|/p
/|ERR|/p
/|EMER|/p" ${logs}
}
m4_divert_pop([PREPARE_TESTS])
# OVS_VSWITCHD_STOP([WHITELIST])
#
# Gracefully stops ovs-vswitchd and ovsdb-server, checking their log files
# for messages with severity WARN or higher and signaling an error if any
# is present. The optional WHITELIST may contain shell-quoted "sed"
# commands to delete any warnings that are actually expected, e.g.:
#
# OVS_VSWITCHD_STOP(["/expected error/d"])
m4_define([OVS_VSWITCHD_STOP],
[AT_CHECK([check_logs $1])
AT_CHECK([ovs-appctl -t ovs-vswitchd exit])
AT_CHECK([ovs-appctl -t ovsdb-server exit])])
m4_define([OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP],
[AT_CHECK([ovs-appctl ofproto/tnl-push-pop off], [0], [dnl
Tunnel push-pop off
])])
# ADD_OF_PORTS(BRIDGE, OF_PORT[, OF_PORT...])
#
# Creates a dummy interface with an OpenFlow port number of OF_PORT and
# name of p{OF_PORT}. The dummy implementation will treat the OF_PORT
# as the datapath port number, which as the effect of making the
# OpenFlow and datapath numbers the same.
m4_define([ADD_OF_PORTS],
[ovs-vsctl m4_foreach([of_port], m4_cdr($@),
[ \
-- add-port $1 p[]of_port -- set Interface p[]of_port type=dummy ofport_request=of_port])])
# WAIT_FOR_DUMMY_PORTS(NETDEV_DUMMY_PORT[, NETDEV_DUMMY_PORT...])
#
# Wait until the netdev dummy ports are connected to each other
m4_define([WAIT_FOR_DUMMY_PORTS], \
[m4_foreach([dummy_port], [$@],
[ \
OVS_WAIT_WHILE([ovs-appctl netdev-dummy/conn-state dummy_port \
| grep 'unknown\|disconnected'])])])
|