summaryrefslogtreecommitdiff
path: root/tests/ofproto-macros.at
blob: 8aa69ee9583467168e1764896aa59a45fb3148d0 (plain)
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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
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]*,//
s/dp_hash=0x[0-9a-f]*\//dp_hash=0x0\//
s/recirc_id=0x[0-9a-f]*,/recirc_id=0x0,/
s/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z|//
s/dir\/[0-9]*\/br0.mgmt/dir\/XXXX\/br0.mgmt/
'
}

# Filter (multiline) vconn debug messages from ovs-vswitchd.log.
# Use with vconn_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_sub() {
    sed '
s/tcp:127.0.0.1:[0-9][0-9]*:/unix:/
s/unix#[0-9]*:/unix:/
'
}
]

# PARSE_LISTENING_PORT LOGFILE VARIABLE
#
# Parses the TCP or SSL port on which a server is listening from
# LOGFILE, given that the server was told to listen on a kernel-chosen
# port, and assigns the port number to shell VARIABLE.  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 ...
#    PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
#    # Now $TCP_PORT holds the listening port.
m4_define([PARSE_LISTENING_PORT],
    [OVS_WAIT_UNTIL([$2=`sed -n 's/.*0:.*: listening on port \([[0-9]]*\)$/\1/p' "$1"` && test X != X"[$]$2"])])

start_daemon () {
    "$@" -vconsole:off --detach --no-chdir --pidfile --log-file
    pidfile="$OVS_RUNDIR"/$1.pid
    on_exit "test -e \"$pidfile\" && kill \`cat \"$pidfile\"\`"
}

# 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 -vunixctl
}

# "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$2" != X; then
        (ovs_setenv $1; shift; "$@")
    else
        ovs_setenv $1
    fi
}

# OVN_CLEANUP_VSWITCH(sim)
#
# Gracefully terminate vswitch daemons in the
# specified sandbox.
m4_define([OVN_CLEANUP_VSWITCH],[
    as $1
    OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
    OVS_APP_EXIT_AND_WAIT([ovsdb-server])
])

# OVN_CLEANUP_SBOX(sbox)
#
# Gracefully terminate OVN daemons in the specified
# sandbox instance. The sandbox name "vtep" is treated
# as a special case, and is assumed to have ovn-controller-vtep
# and ovs-vtep daemons running instead of ovn-controller.
m4_define([OVN_CLEANUP_SBOX],[
    as $1
    if test "$1" = "vtep"; then
        OVS_APP_EXIT_AND_WAIT([ovn-controller-vtep])
        OVS_APP_EXIT_AND_WAIT([ovs-vtep])
    else
        OVS_APP_EXIT_AND_WAIT([ovn-controller])
    fi
    OVN_CLEANUP_VSWITCH([$1])
])

# OVN_CLEANUP(sim [, sim ...])
#
# Gracefully terminate all OVN daemons, including those in the
# specified sandbox instances.
m4_define([OVN_CLEANUP],[
    m4_foreach([sbox], [$@], [
        OVN_CLEANUP_SBOX([sbox])
    ])
    as ovn-sb
    OVS_APP_EXIT_AND_WAIT([ovsdb-server])

    as ovn-nb
    OVS_APP_EXIT_AND_WAIT([ovsdb-server])

    as northd
    OVS_APP_EXIT_AND_WAIT([ovn-northd])

    as northd-backup
    OVS_APP_EXIT_AND_WAIT([ovn-northd])

    OVN_CLEANUP_VSWITCH([main])
])

# 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-sbctl init
    ovn_init_db ovn-nb; ovn-nbctl init

    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

    echo "starting backup ovn-northd"
    mkdir "$ovs_base"/northd-backup
    as northd-backup 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,vxlan \
        -- 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/neigh/set $br2 $ip $mac || return 1
            fi
        done
    done
}
m4_define([OVN_POPULATE_ARP], [AT_CHECK(ovn_populate_arp__, [0], [ignore])])

# Strips 'xid=0x1234' from ovs-ofctl output.
strip_xids () {
    sed 's/ (xid=0x[[0-9a-fA-F]]*)//'
}

# Changes all 'used:...' to say 'used:0.0', to make output easier to compare.
strip_used () {
    sed 's/used:[[0-9]]\.[[0-9]]*/used:0.0/'
}

# Removes all 'duration=...' to make output easier to compare.
strip_duration () {
    sed 's/duration=[[0-9]]*\.[[0-9]]*s,//'
}

# Strips 'ufid:...' from output, to make it easier to compare.
# (ufids are random.)
strip_ufid () {
    sed 's/ufid:[[-0-9a-f]]* //'
}
m4_divert_pop([PREPARE_TESTS])

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 $2])

   dnl Start ovs-vswitchd.
   AT_CHECK([ovs-vswitchd $1 --detach --no-chdir --pidfile --log-file -vvconn -vofproto_dpif -vunixctl], [0], [], [stderr])
   AT_CAPTURE_FILE([ovs-vswitchd.log])
   on_exit "kill_ovs_vswitchd `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
/dpif_netlink|INFO|Generic Netlink family .ovs_datapath. does not exist/d
/ofproto|INFO|using datapath ID/d
/netdev_linux|INFO|.*device has unknown hardware address family/d
/ofproto|INFO|datapath ID changed to fedcba9876543210/d
/dpdk|INFO|DPDK Disabled - Use other_config:dpdk-init to enable/d
/netlink_socket|INFO|netlink: could not enable listening to all nsid/d
/netdev: Flow API/d
/probe tc:/d
/tc: Using policy/d']])
])

# OVS_VSWITCHD_START([vsctl-args], [vsctl-output], [=override],
#                    [vswitchd-aux-args])
#
# 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.
#
# 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).
#
# 'vswitchd-aux-args' provides a way to pass extra command line arguments
# to ovs-vswitchd
m4_define([OVS_VSWITCHD_START],
  [_OVS_VSWITCHD_START([--enable-dummy$3 --disable-system $4])
   AT_CHECK([add_of_br 0 $1 m4_if([$2], [], [], [| uuidfilt])], [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

    # We most notably ignore 'Broken pipe' warnings.  These often and
    # intermittently appear in ovsdb-server.log, because *ctl commands
    # (e.g. ovs-vsctl, ovn-nbctl) exit right after committing a change to the
    # database.  However, in reaction, some daemon may immediately update the
    # database, and this later update may cause database sending update back to
    # *ctl command if *ctl has not exited yet.  If *ctl command exits before
    # the database calls send, the send fails with 'Broken pipe'.  Also removes
    # all "connection reset" warning logs for similar reasons (either EPIPE or
    # ECONNRESET can be returned on a send depending on whether the peer had
    # unconsumed data when it closed the socket).
    sed -n "$1
/reset by peer/d
/Broken pipe/d
/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}
}

# add_of_br BRNUM [ARG...]
add_of_br () {
    local brnum=$1; shift
    local br=br$brnum
    local dpid=fedcba987654321$brnum
    local mac=aa:55:aa:55:00:0$brnum
    ovs-vsctl --timeout=20 \
        -- add-br $br \
	-- set bridge $br datapath-type=dummy \
			  fail-mode=secure \
			  other-config:datapath-id=$dpid \
			  other-config:hwaddr=$mac \
			  protocols="[[OpenFlow10,OpenFlow11,OpenFlow12,\
                                       OpenFlow13,OpenFlow14,OpenFlow15,\
                                       OpenFlow16]]" \
        -- "$@"
}

# add_of_ports__ PORT_TYPE [--pcap] BRIDGE PNUM...
#
# Creates PORT_TYPE interfaces in BRIDGE named pPNUM, OpenFlow port number
# PNUM, and datapath port number PNUM (the latter is a consequence of
# the dummy implementation, which tries to assign datapath port
# numbers based on port names).
#
# If --pcap is supplied then packets received from the interface will
# be written to $port-rx.pcap and those sent to it to $port-tx.pcap.
add_of_ports__ () {
    local args
    local pcap=false
    local ptype=$1
    shift
    if test "$1" = --pcap; then
        pcap=:
    shift
    fi
    local br=$1; shift
    for pnum; do
        AS_VAR_APPEND([args], [" -- add-port $br p$pnum -- set Interface p$pnum type=$ptype ofport_request=$pnum"])
    if $pcap; then
        AS_VAR_APPEND([args], [" -- set Interface p$pnum options:rxq_pcap=p$pnum-rx.pcap options:tx_pcap=p$pnum-tx.pcap"])
    fi
    done
    echo ovs-vsctl $args
    ovs-vsctl $args
}

# add_of_ports [--pcap] BRIDGE PNUM...
#
add_of_ports () {
    add_of_ports__ dummy $@
}

# add_pmd_of_ports [--pcap] BRIDGE PNUM...
#
add_pmd_of_ports () {
    add_of_ports__ dummy-pmd $@
}

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])
   OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
   OVS_APP_EXIT_AND_WAIT([ovsdb-server])])

m4_define([OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP],
  [AT_CHECK([ovs-appctl dpif/set-dp-features br0 tnl_push_pop false], [0])
])

# 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'])])])