ovn-sbctl: Use environment var OVN_SB_DB to find the database by default.
[cascardo/ovs.git] / tests / ovn.at
index 24479ec..1eb6d0b 100644 (file)
@@ -1,4 +1,4 @@
-AT_BANNER([OVN])
+AT_BANNER([OVN components])
 
 AT_SETUP([ovn -- lexer])
 dnl For lines without =>, input and expected output are identical.
@@ -37,7 +37,6 @@ a/b => a error("`/' is only valid as part of `//' or `/*'.") b
 0xfedcba9876543210
 0XFEDCBA9876543210 => 0xfedcba9876543210
 0xfedcba9876543210fedcba9876543210
-0xfedcba9876543210fedcba98765432100 => error("Hexadecimal constant requires more than 128 bits.")
 0x0000fedcba9876543210fedcba9876543210 => 0xfedcba9876543210fedcba9876543210
 0x => error("Hex digits expected following 0x.")
 0X => error("Hex digits expected following 0X.")
@@ -82,7 +81,8 @@ ff:ff:ff:ff:ff:ff/fe:ff:ff:ff:ff:ff => error("Value contains unmasked 1-bits.")
 fe:x => error("Invalid numeric constant.")
 00:01:02:03:04:x => error("Invalid numeric constant.")
 
-(){}[[]]==!=<<=>>=!&&||..,;= => ( ) { } [[ ]] == != < <= > >= ! && || .. , ; =
+# Test that operators are tokenized as expected, even without white space.
+(){}[[]]==!=<<=>>=!&&||..,;=<-> => ( ) { } [[ ]] == != < <= > >= ! && || .. , ; = <->
 & => error("`&' is only valid as part of `&&'.")
 | => error("`|' is only valid as part of `||'.")
 
@@ -200,8 +200,8 @@ ip6.src == ::1 => ip6.src == 0x1
 inport == "eth0"
 !(inport != "eth0") => inport == "eth0"
 
-ip4.src == "eth0" => Can't compare integer field ip4.src to string constant.
-inport == 1 => Can't compare string field inport to integer constant.
+ip4.src == "eth0" => Integer field ip4.src is not compatible with string constant.
+inport == 1 => String field inport is not compatible with integer constant.
 
 ip4.src > {1, 2, 3} => Only == and != operators may be used with value sets.
 eth.type > 0x800 => Only == and != operators may be used with nominal field eth.type.
@@ -253,9 +253,11 @@ eth.dst == {} => Syntax error at `}' expecting constant.
 
 eth.src > 00:00:00:00:11:11/00:00:00:00:ff:ff => Only == and != operators may be used with masked constants.  Consider using subfields instead (e.g. eth.src[0..15] > 0x1111 in place of eth.src > 00:00:00:00:11:11/00:00:00:00:ff:ff).
 
-ip4.src == ::1 => Cannot compare 128-bit constant against 32-bit field ip4.src.
+ip4.src == ::1 => 128-bit constant is not compatible with 32-bit field ip4.src.
 
 1 == eth.type == 2 => Range expressions must have the form `x < field < y' or `x > field > y', with each `<' optionally replaced by `<=' or `>' by `>=').
+
+eth.dst[40] x => Extra tokens at end of input.
 ]])
 sed 's/ =>.*//' test-cases.txt > input.txt
 sed 's/.* => //' test-cases.txt > expout
@@ -299,51 +301,99 @@ sed 's/.* => //' test-cases.txt > expout
 AT_CHECK([ovstest test-ovn annotate-expr < input.txt], [0], [expout])
 AT_CLEANUP
 
-AT_SETUP([ovn -- expression conversion (1)])
+AT_SETUP([ovn -- 1-term expression conversion])
 AT_CHECK([ovstest test-ovn exhaustive --operation=convert 1], [0],
-  [Tested converting all 1-terminal expressions with 2 vars each of 3 bits in terms of operators == != < <= > >=.
+  [Tested converting all 1-terminal expressions with 2 numeric vars (each 3 bits) in terms of operators == != < <= > >= and 2 string vars.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- expression conversion (2)])
+AT_SETUP([ovn -- 2-term expression conversion])
 AT_CHECK([ovstest test-ovn exhaustive --operation=convert 2], [0],
-  [Tested converting 562 expressions of 2 terminals with 2 vars each of 3 bits in terms of operators == != < <= > >=.
+  [Tested converting 570 expressions of 2 terminals with 2 numeric vars (each 3 bits) in terms of operators == != < <= > >= and 2 string vars.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- expression conversion (3)])
+AT_SETUP([ovn -- 3-term expression conversion])
 AT_CHECK([ovstest test-ovn exhaustive --operation=convert --bits=2 3], [0],
-  [Tested converting 57618 expressions of 3 terminals with 2 vars each of 2 bits in terms of operators == != < <= > >=.
+  [Tested converting 62418 expressions of 3 terminals with 2 numeric vars (each 2 bits) in terms of operators == != < <= > >= and 2 string vars.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 3-term numeric expression simplification])
+AT_CHECK([ovstest test-ovn exhaustive --operation=simplify --nvars=2 --svars=0 3], [0],
+  [Tested simplifying 477138 expressions of 3 terminals with 2 numeric vars (each 3 bits) in terms of operators == != < <= > >=.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 4-term string expression simplification])
+AT_CHECK([ovstest test-ovn exhaustive --operation=simplify --nvars=0 --svars=4 4], [0],
+  [Tested simplifying 21978 expressions of 4 terminals with 4 string vars.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 3-term mixed expression simplification])
+AT_CHECK([ovstest test-ovn exhaustive --operation=simplify --nvars=1 --svars=1 3], [0],
+  [Tested simplifying 124410 expressions of 3 terminals with 1 numeric vars (each 3 bits) in terms of operators == != < <= > >= and 1 string vars.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 4-term numeric expression normalization])
+AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --nvars=3 --svars=0 --bits=1 4], [0],
+  [Tested normalizing 1207162 expressions of 4 terminals with 3 numeric vars (each 1 bits) in terms of operators == != < <= > >=.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 4-term string expression normalization])
+AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --nvars=0 --svars=3 --bits=1 4], [0],
+  [Tested normalizing 11242 expressions of 4 terminals with 3 string vars.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 4-term mixed expression normalization])
+AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --nvars=1 --bits=1 --svars=2 4], [0],
+  [Tested normalizing 128282 expressions of 4 terminals with 1 numeric vars (each 1 bits) in terms of operators == != < <= > >= and 2 string vars.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- expression simplification])
-AT_CHECK([ovstest test-ovn exhaustive --operation=simplify --vars=2 3], [0],
-  [Tested simplifying 477138 expressions of 3 terminals with 2 vars each of 3 bits in terms of operators == != < <= > >=.
+AT_SETUP([ovn -- 5-term numeric expression normalization])
+AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --nvars=3 --svars=0 --bits=1 --relops='==' 5], [0],
+  [Tested normalizing 368550 expressions of 5 terminals with 3 numeric vars (each 1 bits) in terms of operators ==.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- expression normalization (1)])
-AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --vars=3 --bits=1 4], [0],
-  [Tested normalizing 1207162 expressions of 4 terminals with 3 vars each of 1 bits in terms of operators == != < <= > >=.
+AT_SETUP([ovn -- 5-term string expression normalization])
+AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --nvars=0 --svars=3 --bits=1 --relops='==' 5], [0],
+  [Tested normalizing 368550 expressions of 5 terminals with 3 string vars.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- expression normalization (1)])
-AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --vars=3 --bits=1 --relops='==' 5], [0],
-  [Tested normalizing 368550 expressions of 5 terminals with 3 vars each of 1 bits in terms of operators ==.
+AT_SETUP([ovn -- 5-term mixed expression normalization])
+AT_CHECK([ovstest test-ovn exhaustive --operation=normalize --nvars=1 --svars=1 --bits=1 --relops='==' 5], [0],
+  [Tested normalizing 116550 expressions of 5 terminals with 1 numeric vars (each 1 bits) in terms of operators == and 1 string vars.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- converting expressions to flows (1)])
-AT_CHECK([ovstest test-ovn exhaustive --operation=flow --vars=2 --bits=2 --relops='==' 4], [0],
-  [Tested converting to flows 128282 expressions of 4 terminals with 2 vars each of 2 bits in terms of operators ==.
+AT_SETUP([ovn -- 4-term numeric expressions to flows])
+AT_CHECK([ovstest test-ovn exhaustive --operation=flow --nvars=2 --svars=0 --bits=2 --relops='==' 4], [0],
+  [Tested converting to flows 128282 expressions of 4 terminals with 2 numeric vars (each 2 bits) in terms of operators ==.
 ])
 AT_CLEANUP
 
-AT_SETUP([ovn -- converting expressions to flows (2)])
-AT_CHECK([ovstest test-ovn exhaustive --operation=flow --vars=3 --bits=3 --relops='==' 3], [0],
-  [Tested converting to flows 38394 expressions of 3 terminals with 3 vars each of 3 bits in terms of operators ==.
+AT_SETUP([ovn -- 4-term string expressions to flows])
+AT_CHECK([ovstest test-ovn exhaustive --operation=flow --nvars=0 --svars=4 4], [0],
+  [Tested converting to flows 21978 expressions of 4 terminals with 4 string vars.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 4-term mixed expressions to flows])
+AT_CHECK([ovstest test-ovn exhaustive --operation=flow --nvars=1 --bits=2 --svars=1 --relops='==' 4], [0],
+  [Tested converting to flows 37994 expressions of 4 terminals with 1 numeric vars (each 2 bits) in terms of operators == and 1 string vars.
+])
+AT_CLEANUP
+
+AT_SETUP([ovn -- 3-term numeric expressions to flows])
+AT_CHECK([ovstest test-ovn exhaustive --operation=flow --nvars=3 --svars=0 --bits=3 --relops='==' 3], [0],
+  [Tested converting to flows 38394 expressions of 3 terminals with 3 numeric vars (each 3 bits) in terms of operators ==.
 ])
 AT_CLEANUP
 
@@ -351,31 +401,268 @@ AT_SETUP([ovn -- converting expressions to flows -- string fields])
 expr_to_flow () {
     echo "$1" | ovstest test-ovn expr-to-flows | sort
 }
-AT_CHECK([expr_to_flow 'inport == "eth0"'], [0], [in_port=5
+AT_CHECK([expr_to_flow 'inport == "eth0"'], [0], [reg6=0x5
 ])
-AT_CHECK([expr_to_flow 'inport == "eth1"'], [0], [in_port=6
+AT_CHECK([expr_to_flow 'inport == "eth1"'], [0], [reg6=0x6
 ])
 AT_CHECK([expr_to_flow 'inport == "eth2"'], [0], [(no flows)
 ])
 AT_CHECK([expr_to_flow 'inport == "eth0" && ip'], [0], [dnl
-ip,in_port=5
-ipv6,in_port=5
+ip,reg6=0x5
+ipv6,reg6=0x5
 ])
 AT_CHECK([expr_to_flow 'inport == "eth1" && ip'], [0], [dnl
-ip,in_port=6
-ipv6,in_port=6
+ip,reg6=0x6
+ipv6,reg6=0x6
 ])
 AT_CHECK([expr_to_flow 'inport == "eth2" && ip'], [0], [(no flows)
 ])
 AT_CHECK([expr_to_flow 'inport == {"eth0", "eth1", "eth2", "LOCAL"}'], [0],
-[in_port=5
-in_port=6
-in_port=LOCAL
+[reg6=0x5
+reg6=0x6
+reg6=0xfffe
 ])
 AT_CHECK([expr_to_flow 'inport == {"eth0", "eth1", "eth2"} && ip'], [0], [dnl
-ip,in_port=5
-ip,in_port=6
-ipv6,in_port=5
-ipv6,in_port=6
+ip,reg6=0x5
+ip,reg6=0x6
+ipv6,reg6=0x5
+ipv6,reg6=0x6
+])
+AT_CHECK([expr_to_flow 'inport == "eth0" && inport == "eth1"'], [0], [dnl
+(no flows)
 ])
 AT_CLEANUP
+
+AT_SETUP([ovn -- action parsing])
+dnl Text before => is input, text after => is expected output.
+AT_DATA([test-cases.txt], [[
+# Positive tests.
+drop; => actions=drop, prereqs=1
+next; => actions=resubmit(,11), prereqs=1
+output; => actions=resubmit(,64), prereqs=1
+outport="eth0"; next; outport="LOCAL"; next; => actions=set_field:0x5->reg7,resubmit(,11),set_field:0xfffe->reg7,resubmit(,11), prereqs=1
+tcp.dst=80; => actions=set_field:80->tcp_dst, prereqs=ip.proto == 0x6 && (eth.type == 0x800 || eth.type == 0x86dd)
+eth.dst[40] = 1; => actions=set_field:01:00:00:00:00:00/01:00:00:00:00:00->eth_dst, prereqs=1
+vlan.pcp = 2; => actions=set_field:0x4000/0xe000->vlan_tci, prereqs=vlan.tci[12]
+vlan.tci[13..15] = 2; => actions=set_field:0x4000/0xe000->vlan_tci, prereqs=1
+reg0 = reg1; => actions=move:OXM_OF_PKT_REG0[0..31]->OXM_OF_PKT_REG0[32..63], prereqs=1
+vlan.pcp = reg0[0..2]; => actions=move:OXM_OF_PKT_REG0[32..34]->NXM_OF_VLAN_TCI[13..15], prereqs=vlan.tci[12]
+reg0[10] = vlan.pcp[1]; => actions=move:NXM_OF_VLAN_TCI[14]->OXM_OF_PKT_REG0[42], prereqs=vlan.tci[12]
+outport = inport; => actions=move:NXM_NX_REG6[]->NXM_NX_REG7[], prereqs=1
+reg0 <-> reg1; => actions=push:OXM_OF_PKT_REG0[0..31],push:OXM_OF_PKT_REG0[32..63],pop:OXM_OF_PKT_REG0[0..31],pop:OXM_OF_PKT_REG0[32..63], prereqs=1
+vlan.pcp <-> reg0[0..2]; => actions=push:OXM_OF_PKT_REG0[32..34],push:NXM_OF_VLAN_TCI[13..15],pop:OXM_OF_PKT_REG0[32..34],pop:NXM_OF_VLAN_TCI[13..15], prereqs=vlan.tci[12]
+reg0[10] <-> vlan.pcp[1]; => actions=push:NXM_OF_VLAN_TCI[14],push:OXM_OF_PKT_REG0[42],pop:NXM_OF_VLAN_TCI[14],pop:OXM_OF_PKT_REG0[42], prereqs=vlan.tci[12]
+outport <-> inport; => actions=push:NXM_NX_REG6[],push:NXM_NX_REG7[],pop:NXM_NX_REG6[],pop:NXM_NX_REG7[], prereqs=1
+# Contradictionary prerequisites (allowed but not useful):
+ip4.src = ip6.src[0..31]; => actions=move:NXM_NX_IPV6_SRC[0..31]->NXM_OF_IP_SRC[], prereqs=eth.type == 0x800 && eth.type == 0x86dd
+ip4.src <-> ip6.src[0..31]; => actions=push:NXM_NX_IPV6_SRC[0..31],push:NXM_OF_IP_SRC[],pop:NXM_NX_IPV6_SRC[0..31],pop:NXM_OF_IP_SRC[], prereqs=eth.type == 0x800 && eth.type == 0x86dd
+
+## Negative tests.
+
+; => Syntax error at `;'.
+xyzzy; => Syntax error at `xyzzy' expecting action.
+next; 123; => Syntax error at `123'.
+next; xyzzy; => Syntax error at `xyzzy' expecting action.
+
+# "drop;" must be on its own:
+drop; next; => Syntax error at `next' expecting end of input.
+next; drop; => Syntax error at `drop' expecting action.
+
+# Missing ";":
+next => Syntax error at end of input expecting ';'.
+
+inport[1] = 1; => Cannot select subfield of string field inport.
+ip.proto[1] = 1; => Cannot select subfield of nominal field ip.proto.
+eth.dst[40] == 1; => Syntax error at `==' expecting `='.
+ip = 1; => Predicate symbol ip cannot be used in assignment.
+ip.proto = 6; => Field ip.proto is not modifiable.
+inport = {"a", "b"}; => Assignments require a single value.
+inport = {}; => Syntax error at `}' expecting constant.
+bad_prereq = 123; => Error parsing expression `xyzzy' encountered as prerequisite or predicate of initial expression: Syntax error at `xyzzy' expecting field name.
+self_recurse = 123; => Error parsing expression `self_recurse != 0' encountered as prerequisite or predicate of initial expression: Error parsing expression `self_recurse != 0' encountered as prerequisite or predicate of initial expression: Recursive expansion of symbol `self_recurse'.
+vlan.present = 0; => Predicate symbol vlan.present cannot be used in assignment.
+reg0[0] = vlan.present; => Predicate symbol vlan.present cannot be used in assignment.
+reg0 = reg1[0..10]; => Can't assign 11-bit value to 32-bit destination.
+inport = reg0; => Can't assign integer field (reg0) to string field (inport).
+inport = big_string; => String fields inport and big_string are incompatible for assignment.
+ip.proto = reg0[0..7]; => Field ip.proto is not modifiable.
+reg0[0] <-> vlan.present; => Predicate symbol vlan.present cannot be used in exchange.
+reg0 <-> reg1[0..10]; => Can't exchange 32-bit field with 11-bit field.
+inport <-> reg0; => Can't exchange string field (inport) with integer field (reg0).
+inport <-> big_string; => String fields inport and big_string are incompatible for exchange.
+ip.proto <-> reg0[0..7]; => Field ip.proto is not modifiable.
+reg0[0..7] <-> ip.proto; => Field ip.proto is not modifiable.
+]])
+sed 's/ =>.*//' test-cases.txt > input.txt
+sed 's/.* => //' test-cases.txt > expout
+AT_CHECK([ovstest test-ovn parse-actions < input.txt], [0], [expout])
+AT_CLEANUP
+
+AT_BANNER([OVN end-to-end tests])
+
+AT_SETUP([ovn -- 3 HVs, 3 VIFs/HV, 1 logical switch])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# Create hypervisors hv[123].
+# Add vif1[123] to hv1, vif2[123] to hv2, vif3[123].
+# Add all of the vifs to a single logical switch lsw0.
+# Turn on port security on all the vifs except vif[123]1.
+# Make vif13, vif2[23], vif3[123] destinations for unknown MACs.
+# Add some ACLs for Ethertypes 1234, 1235, 1236.
+ovn-nbctl lswitch-add lsw0
+net_add n1
+for i in 1 2 3; do
+    sim_add hv$i
+    as hv$i
+    ovs-vsctl add-br br-phys
+    ovn_attach n1 br-phys 192.168.0.$i
+
+    for j in 1 2 3; do
+        ovs-vsctl add-port br-int vif$i$j -- set Interface vif$i$j external-ids:iface-id=lp$i$j options:tx_pcap=hv$i/vif$i$j-tx.pcap options:rxq_pcap=hv$i/vif$i$j-rx.pcap ofport-request=$i$j
+        ovn-nbctl lport-add lsw0 lp$i$j
+       if test $j = 1; then
+            ovn-nbctl lport-set-macs lp$i$j f0:00:00:00:00:$i$j unknown
+        else
+            ovn-nbctl lport-set-macs lp$i$j f0:00:00:00:00:$i$j
+            ovn-nbctl lport-set-port-security lp$i$j f0:00:00:00:00:$i$j
+        fi
+    done
+done
+ovn-nbctl acl-add lsw0 from-lport 1000 'eth.type == 0x1234' drop
+ovn-nbctl acl-add lsw0 from-lport 1000 'eth.type == 0x1235 && inport == "lp11"' drop
+ovn-nbctl acl-add lsw0 to-lport 1000 'eth.type == 0x1236 && outport == "lp33"' drop
+
+# Pre-populate the hypervisors' ARP tables so that we don't lose any
+# packets for ARP resolution (native tunneling doesn't queue packets
+# for ARP resolution).
+ovn_populate_arp
+
+# Allow some time for ovn-northd and ovn-controller to catch up.
+# XXX This should be more systematic.
+sleep 1
+ovn-sbctl dump-flows -- list multicast_group
+
+# test_packet INPORT DST SRC ETHTYPE OUTPORT...
+#
+# This shell function causes a packet to be received on INPORT.  The packet's
+# content has Ethernet destination DST and source SRC (each exactly 12 hex
+# digits) and Ethernet type ETHTYPE (4 hex digits).  The OUTPORTs (zero or
+# more) list the VIFs on which the packet should be received.  INPORT and the
+# OUTPORTs are specified as lport numbers, e.g. 11 for vif11.
+trim_zeros() {
+    sed 's/\(00\)\{1,\}$//'
+}
+for i in 1 2 3; do
+    for j in 1 2 3; do
+        : > $i$j.expected
+    done
+done
+test_packet() {
+    local inport=$1 packet=$2$3$4; shift; shift; shift; shift
+    hv=hv`echo $inport | sed 's/^\(.\).*/\1/'`
+    vif=vif$inport
+    as $hv ovs-appctl netdev-dummy/receive $vif $packet
+    for outport; do
+        echo $packet | trim_zeros >> $outport.expected
+    done
+}
+
+# Send packets between all pairs of source and destination ports:
+#
+# 1. Unicast packets are delivered to exactly one lport (except that packets
+#    destined to their input ports are dropped).
+#
+# 2. Broadcast and multicast are delivered to all lports except the input port.
+#
+# 3. When port security is turned on, the lswitch drops packets from the wrong
+#    MAC address.
+#
+# 4. The lswitch drops all packets with a VLAN tag.
+#
+# 5. The lswitch drops all packets with a multicast source address.  (This only
+#    affects behavior when port security is turned off, since otherwise port
+#    security would drop the packet anyway.)
+#
+# 6. The lswitch delivers packets with an unknown destination to lports with
+#    "unknown" among their MAC addresses (and port security disabled).
+#
+# 7. The lswitch drops unicast packets that violate an ACL.
+#
+# 8. The lswitch drops multicast and broadcast packets that violate an ACL.
+for is in 1 2 3; do
+    for js in 1 2 3; do
+        s=$is$js
+        bcast=
+       unknown=
+       bacl2=
+       bacl3=
+        for id in 1 2 3; do
+            for jd in 1 2 3; do
+                d=$id$jd
+
+                if test $d != $s; then unicast=$d; else unicast=; fi
+                test_packet $s f000000000$d f000000000$s $s$d $unicast     #1
+
+                if test $d != $s && test $js = 1; then
+                   impersonate=$d
+               else
+                   impersonate=
+               fi
+                test_packet $s f000000000$d f00000000055 55$d $impersonate #3
+
+               if test $d != $s && test $s != 11; then acl2=$d; else acl2=; fi
+               if test $d != $s && test $d != 33; then acl3=$d; else acl3=; fi
+                test_packet $s f000000000$d f000000000$s 1234        #7, acl1
+                test_packet $s f000000000$d f000000000$s 1235 $acl2  #7, acl2
+                test_packet $s f000000000$d f000000000$s 1236 $acl3  #7, acl3
+
+                test_packet $s f000000000$d f00000000055 810000091234      #4
+                test_packet $s f000000000$d 0100000000$s $s$d              #5
+
+               if test $d != $s && test $jd = 1; then
+                   unknown="$unknown $d"
+               fi
+                bcast="$bcast $unicast"
+                bacl2="$bacl2 $acl2"
+                bacl3="$bacl3 $acl3"
+            done
+        done
+
+       # Broadcast and multicast.
+        test_packet $s ffffffffffff f000000000$s ${s}ff $bcast             #2
+        test_packet $s 010000000000 f000000000$s ${s}ff $bcast             #2
+       if test $js = 1; then
+            bcast_impersonate=$bcast
+        else
+           bcast_impersonate=
+       fi
+        test_packet $s 010000000000 f00000000044 44ff $bcast_impersonate   #3
+
+        test_packet $s f0000000ffff f000000000$s ${s}66 $unknown           #6
+
+        test_packet $s ffffffffffff f000000000$s 1234                #8, acl1
+        test_packet $s ffffffffffff f000000000$s 1235 $bacl2         #8, acl2
+        test_packet $s ffffffffffff f000000000$s 1236 $bacl3         #8, acl3
+        test_packet $s 010000000000 f000000000$s 1234                #8, acl1
+        test_packet $s 010000000000 f000000000$s 1235 $bacl2         #8, acl2
+        test_packet $s 010000000000 f000000000$s 1236 $bacl3         #8, acl3
+    done
+done
+
+# Allow some time for packet forwarding.
+# XXX This can be improved.
+sleep 1
+
+# Now check the packets actually received against the ones expected.
+for i in 1 2 3; do
+    for j in 1 2 3; do
+        file=hv$i/vif$i$j-tx.pcap
+        echo $file
+        $PYTHON "$top_srcdir/utilities/ovs-pcap.in" $file | trim_zeros > $i$j.packets
+        cp $i$j.expected expout
+        AT_CHECK([cat $i$j.packets], [0], [expout])
+        echo
+    done
+done
+AT_CLEANUP