AT_BANNER([datapath-sanity])

AT_SETUP([datapath - ping between two ports])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - http between two ports])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping between two ports on vlan])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

ADD_VLAN(p0, at_ns0, 100, "10.2.2.1/24")
ADD_VLAN(p1, at_ns1, 100, "10.2.2.2/24")

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping between two ports on cvlan])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_8021AD()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

ADD_SVLAN(p0, at_ns0, 4094, "10.255.2.1/24")
ADD_SVLAN(p1, at_ns1, 4094, "10.255.2.2/24")

ADD_CVLAN(p0.4094, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p1.4094, at_ns1, 100, "10.2.2.2/24")

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping6 between two ports])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping6 between two ports on vlan])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

ADD_VLAN(p0, at_ns0, 100, "fc00:1::1/96")
ADD_VLAN(p1, at_ns1, 100, "fc00:1::2/96")

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00:1::2])

NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:1::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00:1::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00:1::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping6 between two ports on cvlan])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_8021AD()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

ADD_SVLAN(p0, at_ns0, 4094, "fc00:ffff::1/96")
ADD_SVLAN(p1, at_ns1, 4094, "fc00:ffff::2/96")

ADD_CVLAN(p0.4094, at_ns0, 100, "fc00:1::1/96")
ADD_CVLAN(p1.4094, at_ns1, 100, "fc00:1::2/96")

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00:1::2])

NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:1::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00:1::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00:1::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping6 between two ports IPv6 later fragments])
OVS_TRAFFIC_VSWITCHD_START()
CHECK_LATER_IPV6_FRAGMENTS()

AT_CHECK([ovs-ofctl add-flow br0 "priority=1,actions=normal"])
AT_CHECK([ovs-ofctl add-flow br0 "priority=2,tcp6,actions=drop"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ovs-appctl dpctl/dump-flows -m --names > stdout.txt])
NS_CHECK_EXEC([at_ns0], [grep ipv6 stdout.txt | grep frag=later | grep -q proto=44], [0], [])
NS_CHECK_EXEC([at_ns0], [grep ipv6 stdout.txt | grep frag=later | grep -v -q proto=44], [1], [])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping6 between two ports with header modify])
OVS_TRAFFIC_VSWITCHD_START()
CHECK_LATER_IPV6_FRAGMENTS()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96", e4:11:22:33:44:55)
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", e4:11:22:33:44:54)
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::3 lladdr e4:11:22:33:44:54 dev p0])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
OVS_WAIT_UNTIL([ip netns exec at_ns1 ping6 -c 1 fc00::1])

AT_DATA([flows.txt], [dnl
priority=100,in_port=ovs-p0,ipv6,ipv6_src=fc00::1,ipv6_dst=fc00::3,actions=set_field:fc00::2->ipv6_dst,ovs-p1
priority=100,in_port=ovs-p1,ipv6,ipv6_src=fc00::2,ipv6_dst=fc00::1,actions=set_field:fc00::3->ipv6_src,ovs-p0
priority=0,actions=NORMAL
])

AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl We need to wait until the new flows are actually in the datapath to avoid
dnl intermittent loss of first ping packet.
AT_CHECK([ovs-appctl revalidator/wait])

NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::3 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00::3 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00::3 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over bond])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH_BOND(p1 p2, at_ns1, br0, bond0, lacp=active bond_mode=balance-tcp, "10.1.1.2/24")

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over vxlan tunnel])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_CHECK_VXLAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [id 0 dstport 4789])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start ncat listeners.
OVS_DAEMONIZE([nc -l 10.1.1.100 1234 > tcp_data], [nc.pid])
NETNS_DAEMONIZE([at_ns0], [nc -l -u 10.1.1.1 4321 > udp_data], [nc2.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([netstat -ln | grep :1234])
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :4321])])

dnl Check large bidirectional TCP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.100 1234 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin tcp_data])

dnl Check UDP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=600 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT -u 10.1.1.1 4321 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin udp_data])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - tcp over vxlan tunnel with software fallback])
AT_SKIP_IF([test $HAVE_NC = no])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_CHECK_VXLAN()

dnl This test is only valid with tso. If the kernel segments the packets, the
dnl packet lengths in the final test will be different.
m4_ifndef([CHECK_SYSTEM_TSO], [AT_SKIP_IF(:)])

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Test the case where one side has all checksum and TSO offload disabled.
AT_CHECK([ethtool -K ovs-p0 tso off], [0], [ignore], [ignore])
AT_CHECK([ethtool -K ovs-p0 sg off], [0], [ignore], [ignore])

dnl Reinitialize.
AT_CHECK([ovs-vsctl del-port ovs-p0])
AT_CHECK([ovs-vsctl add-port br-underlay ovs-p0])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100],
                  [10.1.1.1/24], [id 0 dstport 4789])

dnl Set MTU for tunnel to generate 1500 byte packets.
AT_CHECK([ip link set dev br0 mtu 1400])

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING],
              [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Check that the tunnel is up.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING],
              [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start tcpdump to capture the encapsulated packets.
OVS_DAEMONIZE([tcpdump -i ovs-p0 -w p0.pcap], [tcpdump.pid])

dnl Wait until the pcap is written, which happens after the interface
dnl is opened by tcpdump.
OVS_WAIT_UNTIL([test -e p0.pcap])

dnl Initialize the listener before it is needed.
NETNS_DAEMONIZE([at_ns0], [nc -l 10.1.1.1 1234 > data2], [nc.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :1234])])

dnl Large TCP transfer aimed towards ovs-p0, which has TSO disabled.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT 10.1.1.1 1234 < payload.bin])

dnl Wait until transfer completes before checking.
OVS_WAIT_WHILE([kill -0 $(cat nc.pid)])
AT_CHECK([diff -q payload.bin data2], [0])
OVS_WAIT_WHILE([test $(stat -c %s p0.pcap) -le 68000 ])

dnl Stop OVS and tcpdump and verify the results.
AT_CHECK([kill -15 $(cat tcpdump.pid)])
OVS_WAIT_WHILE([kill -0 $(cat tcpdump.pid)])

dnl The exact number of packets sent will vary, but we check that the largest
dnl segments have the correct lengths and certain other fields.
AT_CHECK([test $(ovs-pcap p0.pcap | grep -Ec dnl
"^.{24}0800"dnl Ethernet
"450005aa....4000..11....ac1f0164ac1f0101"dnl IP(len=1450, DF, UDP, 172.31.1.100->172.31.1.1)
"....12b505960000"dnl UDP(len=1430, dport=4789)
"0800000000000000"dnl VXLAN(gpid=0, vni=0)
".{24}0800"dnl Ethernet
"45000578....4000..06....0a0101640a010101"dnl IP(len=1400, DF, TCP, 10.1.1.100->10.1.1.1)
"....04d2............................0000"dnl TCP(dport=1234
) -ge 20])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping vlan over vxlan tunnel])
OVS_CHECK_TUNNEL_TSO()
OVS_CHECK_VXLAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.2.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.2.1.1/24],
                  [id 0 dstport 4789])

AT_CHECK([ovs-vsctl set port br0 tag=100])
AT_CHECK([ovs-vsctl set port br-underlay tag=42])

ADD_VLAN(at_vxlan1, at_ns0, 100, "10.1.1.1/24")
ADD_VLAN(p0, at_ns0, 42, "172.31.1.1/24")

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over vxlan6 tunnel])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_CHECK_VXLAN_UDP6ZEROCSUM()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00::1/64", [], [], "nodad")
AT_CHECK([ip addr add dev br-underlay "fc00::100/64" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([vxlan], [br0], [at_vxlan0], [fc00::1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL6([vxlan], [at_vxlan1], [at_ns0], [fc00::100], [10.1.1.1/24],
                   [id 0 dstport 4789 udp6zerocsumtx udp6zerocsumrx])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::100])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start ncat listeners.
OVS_DAEMONIZE([nc -l 10.1.1.100 1234 > tcp_data], [nc.pid])
NETNS_DAEMONIZE([at_ns0], [nc -l -u 10.1.1.1 4321 > udp_data], [nc2.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([netstat -ln | grep :1234])
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :4321])])

dnl Check large bidirectional TCP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.100 1234 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin tcp_data])

dnl Check UDP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=600 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT -u 10.1.1.1 4321 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin udp_data])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over gre tunnel])
OVS_CHECK_GRE()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([gre], [br0], [at_gre0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([gretap], [ns_gre0], [at_ns0], [172.31.1.100], [10.1.1.1/24])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start ncat listeners.
OVS_DAEMONIZE([nc -l 10.1.1.100 1234 > tcp_data], [nc.pid])
NETNS_DAEMONIZE([at_ns0], [nc -l -u 10.1.1.1 4321 > udp_data], [nc2.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([netstat -ln | grep :1234])
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :4321])])

dnl Check large bidirectional TCP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.100 1234 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin tcp_data])

dnl Check UDP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=600 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT -u 10.1.1.1 4321 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin udp_data])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - tcp over gre tunnel with software fallback])
AT_SKIP_IF([test $HAVE_NC = no])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_CHECK_GRE()

dnl This test is only valid with tso. If the kernel segments the packets, the
dnl packet lengths in the final test will be different.
m4_ifndef([CHECK_SYSTEM_TSO], [AT_SKIP_IF(:)])

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Test the case where one side has all checksum and TSO offload disabled.
AT_CHECK([ethtool -K ovs-p0 tso off], [0], [ignore], [ignore])
AT_CHECK([ethtool -K ovs-p0 sg off], [0], [ignore], [ignore])

dnl Reinitialize.
AT_CHECK([ovs-vsctl del-port ovs-p0])
AT_CHECK([ovs-vsctl add-port br-underlay ovs-p0])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([gre], [br0], [at_gre0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([gretap], [at_gre1], [at_ns0], [172.31.1.100], [10.1.1.1/24])

dnl Set MTU for tunnel to generate 1500 byte packets.
AT_CHECK([ip link set dev br0 mtu 1400])

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING],
              [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Check that the tunnel is up.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING],
              [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start tcpdump to capture the encapsulated packets.
OVS_DAEMONIZE([tcpdump -i ovs-p0 -w p0.pcap], [tcpdump.pid])

dnl Wait until the pcap is written, which happens after the interface
dnl is opened by tcpdump.
OVS_WAIT_UNTIL([test -e p0.pcap])

dnl Initialize the listener before it is needed.
NETNS_DAEMONIZE([at_ns0], [nc -l 10.1.1.1 1234 > data2], [nc.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :1234])])

dnl Large TCP transfer aimed towards ovs-p0, which has TSO disabled.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT 10.1.1.1 1234 < payload.bin])

dnl Wait until transfer completes before checking.
OVS_WAIT_WHILE([kill -0 $(cat nc.pid)])
AT_CHECK([diff -q payload.bin data2], [0])
OVS_WAIT_WHILE([test $(stat -c %s p0.pcap) -le 68000 ])

dnl Stop OVS and tcpdump and verify the results.
AT_CHECK([kill -15 $(cat tcpdump.pid)])
OVS_WAIT_WHILE([kill -0 $(cat tcpdump.pid)])

dnl The exact number of packets sent will vary, but we check that the largest
dnl segments have the correct lengths and certain other fields.
AT_CHECK([test $(ovs-pcap p0.pcap | grep -Ec dnl
"^.{24}0800"dnl Ethernet
"4500059e....4000..2f....ac1f0164ac1f0101"dnl IP(len=1450, DF, GRE, 172.31.1.100->172.31.1.1)
"00006558"dnl GRE(flags=0, proto=0x6558)
".{24}0800"dnl Ethernet
"45000578....4000..06....0a0101640a010101"dnl IP(len=1400, DF, TCP, 10.1.1.100->10.1.1.1)
"....04d2............................0000"dnl TCP(dport=1234
) -ge 20])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over ip6gre L2 tunnel])
OVS_CHECK_GRE()
OVS_CHECK_ERSPAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00:100::1/96", [], [], nodad)
AT_CHECK([ip addr add dev br-underlay "fc00:100::100/96" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([ip6gre], [br0], [at_gre0], [fc00:100::1], [10.1.1.100/24],
                [options:packet_type=legacy_l2])
ADD_NATIVE_TUNNEL6([ip6gretap], [ns_gretap0], [at_ns0], [fc00:100::100],
                   [10.1.1.1/24], [local fc00:100::1])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 2 fc00:100::100])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:100::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start ncat listeners.
OVS_DAEMONIZE([nc -l 10.1.1.100 1234 > tcp_data], [nc.pid])
NETNS_DAEMONIZE([at_ns0], [nc -l -u 10.1.1.1 4321 > udp_data], [nc2.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([netstat -ln | grep :1234])
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :4321])])

dnl Check large bidirectional TCP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.100 1234 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin tcp_data])

dnl Check UDP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=600 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT -u 10.1.1.1 4321 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin udp_data])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([datapath - ping over erspan v1 tunnel])
OVS_CHECK_KERNEL_EXCL(3, 10, 4, 15)
OVS_CHECK_GRE()
OVS_CHECK_ERSPAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([erspan], [br0], [at_erspan0], [172.31.1.1], [10.1.1.100/24], [options:key=1 options:erspan_ver=1 options:erspan_idx=7])
ADD_NATIVE_TUNNEL([erspan], [ns_erspan0], [at_ns0], [172.31.1.100], [10.1.1.1/24], [seq key 1 erspan_ver 1 erspan 7])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
dnl NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
NS_CHECK_EXEC([at_ns0], [ping -s 1200 -i 0.3 -c 3 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over erspan v2 tunnel])
OVS_CHECK_KERNEL_EXCL(3, 10, 4, 15)
OVS_CHECK_GRE()
OVS_CHECK_ERSPAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([erspan], [br0], [at_erspan0], [172.31.1.1], [10.1.1.100/24], [options:key=1 options:erspan_ver=2 options:erspan_dir=1 options:erspan_hwid=0x7])
ADD_NATIVE_TUNNEL([erspan], [ns_erspan0], [at_ns0], [172.31.1.100], [10.1.1.1/24], [seq key 1 erspan_ver 2 erspan_dir egress erspan_hwid 7])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
dnl NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
NS_CHECK_EXEC([at_ns0], [ping -s 1200 -i 0.3 -c 3 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over ip6erspan v1 tunnel])
OVS_CHECK_KERNEL_EXCL(3, 10, 4, 15)
OVS_CHECK_GRE()
OVS_CHECK_ERSPAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00:100::1/96", [], [], nodad)
AT_CHECK([ip addr add dev br-underlay "fc00:100::100/96" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([ip6erspan], [br0], [at_erspan0], [fc00:100::1], [10.1.1.100/24],
                [options:key=123 options:erspan_ver=1 options:erspan_idx=0x7])
ADD_NATIVE_TUNNEL6([ip6erspan], [ns_erspan0], [at_ns0], [fc00:100::100],
                   [10.1.1.1/24], [local fc00:100::1 seq key 123 erspan_ver 1 erspan 7])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 2 fc00:100::100])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:100::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over ip6erspan v2 tunnel])
OVS_CHECK_KERNEL_EXCL(3, 10, 4, 15)
OVS_CHECK_GRE()
OVS_CHECK_ERSPAN()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00:100::1/96", [], [], nodad)
AT_CHECK([ip addr add dev br-underlay "fc00:100::100/96" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([ip6erspan], [br0], [at_erspan0], [fc00:100::1], [10.1.1.100/24],
                [options:key=121 options:erspan_ver=2 options:erspan_dir=0 options:erspan_hwid=0x7])
ADD_NATIVE_TUNNEL6([ip6erspan], [ns_erspan0], [at_ns0], [fc00:100::100],
                   [10.1.1.1/24],
                   [local fc00:100::1 seq key 121 erspan_ver 2 erspan_dir ingress erspan_hwid 0x7])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 2 fc00:100::100])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:100::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over geneve tunnel])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_CHECK_GENEVE()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [vni 0])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start ncat listeners.
OVS_DAEMONIZE([nc -l 10.1.1.100 1234 > tcp_data], [nc.pid])
NETNS_DAEMONIZE([at_ns0], [nc -l -u 10.1.1.1 4321 > udp_data], [nc2.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([netstat -ln | grep :1234])
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :4321])])

dnl Check large bidirectional TCP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.100 1234 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin tcp_data])

dnl Check UDP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=600 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT -u 10.1.1.1 4321 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin udp_data])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over geneve tunnel, delete flow regression])
OVS_CHECK_GENEVE()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_DATA([flows.txt], [dnl
priority=100,icmp actions=resubmit(,10)
priority=0 actions=NORMAL
table=10, priority=100, ip, actions=ct(table=20,zone=65520)
table=20, priority=200, ip, ct_state=-new+trk, actions=resubmit(,30)
table=20, priority=100, ip, ct_state=+new, actions=resubmit(,30)
table=20, priority=50, ip, actions=DROP
table=30, priority=100, ip, actions=ct(commit,table=40,zone=65520)
table=40, actions=normal
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [vni 0])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl ping over tunnel should work
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-ofctl del-flows br0 "ct_state=+new"])

dnl ping should not go through after removal of the flow
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.100 | FORMAT_PING], [0], [dnl
7 packets transmitted, 0 received, 100% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP(["/|ERR|/d
/|WARN|/d"])
AT_CLEANUP

AT_SETUP([datapath - flow resume with geneve tun_metadata])
OVS_CHECK_GENEVE()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl monitor br0 resume --detach --no-chdir --pidfile 2> /dev/null])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [vni 0])

dnl Set up flows
AT_DATA([flows.txt], [dnl
table=0, arp action=NORMAL
table=0, in_port=LOCAL icmp action=output:at_gnv0
table=0, in_port=at_gnv0 icmp action=set_field:0xa->tun_metadata0,resubmit(,1)
table=1, icmp action=controller(pause), resubmit(,2)
table=2, tun_metadata0=0xa, icmp action=output:LOCAL
])
AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Test OVS handles TLV map modifictions properly when restores frozen state.
NETNS_DAEMONIZE([at_ns0], [ping 10.1.1.100 > /dev/null], [ping0.pid])

AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0x88,len=4}->tun_metadata1"])
sleep 1
AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0x99,len=4}->tun_metadata2"])
sleep 1
AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0xaa,len=4}->tun_metadata3"])
sleep 1

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over geneve6 tunnel])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_CHECK_GENEVE_UDP6ZEROCSUM()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00::1/64", [], [], "nodad")
AT_CHECK([ip addr add dev br-underlay "fc00::100/64" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([geneve], [br0], [at_gnv0], [fc00::1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL6([geneve], [ns_gnv0], [at_ns0], [fc00::100], [10.1.1.1/24],
                   [vni 0 udp6zerocsumtx udp6zerocsumrx])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::100])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start ncat listeners.
OVS_DAEMONIZE([nc -l 10.1.1.100 1234 > tcp_data], [nc.pid])
NETNS_DAEMONIZE([at_ns0], [nc -l -u 10.1.1.1 4321 > udp_data], [nc2.pid])

dnl Verify that ncat is ready.
OVS_WAIT_UNTIL([netstat -ln | grep :1234])
OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :4321])])

dnl Check large bidirectional TCP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.100 1234 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin tcp_data])

dnl Check UDP.
AT_CHECK([dd if=/dev/urandom of=payload.bin bs=600 count=1 2> /dev/null])
AT_CHECK([nc $NC_EOF_OPT -u 10.1.1.1 4321 < payload.bin])
OVS_WAIT_UNTIL([diff -q payload.bin udp_data])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - slow_action on geneve6 tunnel])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_CHECK_GENEVE_UDP6ZEROCSUM()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00::1/64", [], [], "nodad")
AT_CHECK([ip addr add dev br-underlay "fc00::100/64" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([geneve], [br0], [at_gnv0], [fc00::1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL6([geneve], [ns_gnv0], [at_ns0], [fc00::100], [10.1.1.1/24],
                   [vni 0 udp6zerocsumtx udp6zerocsumrx])
AT_CHECK([ovs-ofctl add-flow br0 "table=37,actions=at_gnv0"])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::100])

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Start tcpdump to capture the encapsulated packets.
NETNS_DAEMONIZE([at_ns0], [tcpdump -n -U -i p0 -w p0.pcap], [tcpdump.pid])
sleep 1

dnl Generate a single packet trough the controler that needs an ARP modification
AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller packet=fffffffffffffa163e949d8008060001080006040001fa163e949d80c0a820300000000000000a0000fe actions=set_field:0xa0000f4->reg1,move:NXM_NX_XXREG0[[64..95]]->NXM_OF_ARP_SPA[[]],resubmit(,37)"])
sleep 1

dnl Stop OVS and tcpdump and verify the results.
OVS_TRAFFIC_VSWITCHD_STOP

ovs-pcap p0.pcap

AT_CHECK([ovs-pcap p0.pcap | grep -Eq "^[[[:xdigit:]]]{24}86dd60000000003a1140fc000000000000000000000000000100fc000000000000000000000000000001[[[:xdigit:]]]{4}17c1003a[[[:xdigit:]]]{4}0000655800000000fffffffffffffa163e949d8008060001080006040001[[[:xdigit:]]]{12}0a0000f40000000000000a0000fe$"])
AT_CLEANUP

AT_SETUP([datapath - bridging two geneve tunnels])
OVS_CHECK_TUNNEL_TSO()
OVS_CHECK_GENEVE()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay-0])
ADD_BR([br-underlay-1])

ADD_NAMESPACES(at_ns0)
ADD_NAMESPACES(at_ns1)

dnl Set up underlay link from host into the namespaces using veth pairs.
ADD_VETH(p0, at_ns0, br-underlay-0, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay-0 "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay-0 up])

ADD_VETH(p1, at_ns1, br-underlay-1, "172.31.2.1/24")
AT_CHECK([ip addr add dev br-underlay-1 "172.31.2.100/24"])
AT_CHECK([ip link set dev br-underlay-1 up])

dnl Set up two OVS tunnel endpoints in a root namespace and two native
dnl linux devices inside the test namespaces.
dnl
dnl  ns_gnv0                          |               ns_gnv1
dnl  ip:        10.1.1.1/24           |               ip:        10.1.1.2/24
dnl  remote_ip: 172.31.1.100          |               remote_ip: 172.31.2.100
dnl          |                        |                  |
dnl          |                        |                  |
dnl  p0                               |               p1
dnl  ip: 172.31.1.1/24                |               ip: 172.31.2.1/24
dnl          |                  NS0   |   NS1            |
dnl ---------|------------------------+------------------|--------------------
dnl          |                                           |
dnl       br-underlay-0:                           br-underlay-1:
dnl       ip: 172.31.1.100/24                      ip: 172.31.2.100/24
dnl         ovs-p0                                   ovs-p1
dnl          |                                           |
dnl          |            br0                            |
dnl       encap/decap --- ip: 10.1.1.100/24 --------- encap/decap
dnl                         at_gnv0
dnl                           remote_ip: 172.31.1.1
dnl                         at_gnv1
dnl                           remote_ip: 172.31.2.1
dnl
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [vni 0])
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv1], [172.31.2.1], [10.1.1.101/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv1], [at_ns1], [172.31.2.100], [10.1.1.2/24],
                  [vni 0])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay-0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay-1 "actions=normal"])

dnl First, check both underlays.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -W 2 172.31.2.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Now, check the overlay with different packet sizes.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - handling of geneve corrupted metadata])
OVS_CHECK_GENEVE()

OVS_TRAFFIC_VSWITCHD_START(
    [_ADD_BR([br-underlay]) -- \
     set bridge br0 other-config:hwaddr=f2:ff:00:00:00:01 -- \
     set bridge br-underlay other-config:hwaddr=f2:ff:00:00:00:02])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24", f2:ff:00:00:00:03)
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [vni 0], [address f2:ff:00:00:00:04])

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 03 08 00 45 00 00 52 00 01 00 00 40 11 1f f7 ac 1f 01 01 ac 1f 01 64 de c1 17 c1 00 3e 59 e9 01 00 65 58 00 00 00 00 00 03 00 02 f2 ff 00 00 00 01 f2 ff 00 00 00 04 08 00 45 00 00 1c 00 01 00 00 40 01 64 7a 0a 01 01 01 0a 01 01 64 08 00 f7 ff 00 00 00 00  > /dev/null])

OVS_WAIT_UNTIL([grep -q 'Invalid Geneve tunnel metadata' ovs-vswitchd.log])

OVS_TRAFFIC_VSWITCHD_STOP(["/Invalid Geneve tunnel metadata on bridge br0 while processing icmp,in_port=1,vlan_tci=0x0000,dl_src=f2:ff:00:00:00:04,dl_dst=f2:ff:00:00:00:01,nw_src=10.1.1.1,nw_dst=10.1.1.100,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,icmp_type=8,icmp_code=0/d
/Unable to parse geneve options/d"])
AT_CLEANUP

AT_SETUP([datapath - ping over gre tunnel by simulated packets])
OVS_CHECK_XT()

OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-vsctl -- set bridge br0 other-config:hwaddr=\"f2:ff:00:00:00:01\"])
ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"f2:ff:00:00:00:02\"])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24", f2:ff:00:00:00:03)
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace.
ADD_OVS_TUNNEL([gre], [br0], [at_gre0], [172.31.1.1], [10.1.1.100/24])

XT_ACCEPT([br-underlay])

NETNS_DAEMONIZE([at_ns0], [tcpdump -n -i p0 dst host 172.31.1.1 -l > p0.pcap 2>/dev/null], [tcpdump.pid])
sleep 1

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl We don't actually add gretap port as below, instead, we will
dnl emulate one that sends packets. Suppose its mac address is f2:ff:00:00:00:04.
dnl ADD_NATIVE_TUNNEL([gretap], [ns_gre0], [at_ns0], [172.31.1.100], [10.1.1.1/24])

dnl Now, check the overlay by sending out raw arp and icmp packets.
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff00000003080045000042ec2c4000402ff3bcac1f0101ac1f016400006558fffffffffffff2ff0000000408060001080006040001f2ff000000040a0101010000000000000a010164 actions=NORMAL"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "IP 172.31.1.100 > 172.31.1.1: GREv0, length 46: ARP, Reply 10.1.1.100 is-at f2:ff:00:00:00:01.* length 28" 2>&1 1>/dev/null])

ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000308004500007aec8e4000402ff322ac1f0101ac1f016400006558f2ff00000001f2ff00000004080045000054548f40004001cfb30a0101010a0101640800e6e829270003e1a3435b00000000ff1a050000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 actions=NORMAL"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "IP 172.31.1.100 > 172.31.1.1: GREv0, length 102: IP 10.1.1.100 > 10.1.1.1: ICMP echo reply,.* length 64$" 2>&1 1>/dev/null])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over erspan v1 tunnel by simulated packets])
OVS_CHECK_XT()
OVS_CHECK_MIN_KERNEL(3, 10)

OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-vsctl -- set bridge br0 other-config:hwaddr=\"f2:ff:00:00:00:01\"])
ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"f2:ff:00:00:00:02\"])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24", f2:ff:00:00:00:03)
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and emulate a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([erspan], [br0], [at_erspan0], [172.31.1.1], [10.1.1.100/24], [options:key=1 options:erspan_ver=1 options:erspan_idx=7])

XT_ACCEPT([br-underlay])

NETNS_DAEMONIZE([at_ns0], [tcpdump -n -x -i p0 dst host 172.31.1.1 -l > p0.pcap 2>/dev/null], [tcpdump.pid])
sleep 1

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now send out an arp request from 10.1.1.1 for 10.1.1.100 in erspan.
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000308004500004e151d4000402fcac0ac1f0101ac1f0164100088be000000061000000100000007fffffffffffff2ff0000000408060001080006040001f2ff000000040a0101010000000000000a010164 actions=normal"

dnl 0002 is arp reply, followed by mac address of 10.1.1.100.
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0030:  0806 0001 0800 0604 0002 f2ff 0000 0001" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0040:  0a01 0164 f2ff 0000 0004 0a01 0101" 2>&1 1>/dev/null])

dnl Okay, now check the overlay with raw icmp packets.
AT_FAIL_IF([cat p0.pcap | grep -E "IP 172.31.1.100 > 172.31.1.1: GREv0,.* length 122" 2>&1 1>/dev/null])

ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000308004500008e70cb4000402f6ed2ac1f0101ac1f0164100088be000000051000000100000007f2ff00000001f2ff0000000408004500005c4a3340004001da070a0101010a010164080084f238fb0001f36a6b5b0000000021870e0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f actions=normal"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "IP 172.31.1.100 > 172.31.1.1: GREv0,.* length 122" 2>&1 1>/dev/null])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over erspan v2 tunnel by simulated packets])
OVS_CHECK_XT()
OVS_CHECK_MIN_KERNEL(3, 10)

OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-vsctl -- set bridge br0 other-config:hwaddr=\"f2:ff:00:00:00:01\"])
ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"f2:ff:00:00:00:02\"])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24", f2:ff:00:00:00:03)
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and simulate a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([erspan], [br0], [at_erspan0], [172.31.1.1], [10.1.1.100/24], [options:key=1 options:erspan_ver=2 options:erspan_dir=1 options:erspan_hwid=0x7])

XT_ACCEPT([br-underlay])

NETNS_DAEMONIZE([at_ns0], [tcpdump -n -x -i p0 dst host 172.31.1.1 -l > p0.pcap 2>/dev/null], [tcpdump.pid])
sleep 1

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, send raw arp request and icmp echo request.
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff00000003080045000052373d4000402fa89cac1f0101ac1f0164100088be00000006200000016f54b41700008078fffffffffffff2ff0000000408060001080006040001f2ff000000040a0101010000000000000a010164 actions=normal"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0030:  0000 0001 0806 0001 0800 0604 0002 f2ff" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0040:  0000 0001 0a01 0164 f2ff 0000 0004 0a01" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0050:  0101" 2>&1 1>/dev/null])

dnl Because tcpdump might not be able to parse erspan headers, we check icmp echo reply
dnl by packet length.
AT_FAIL_IF([cat p0.pcap | grep -E "IP 172.31.1.100 > 172.31.1.1: GREv0,.* length 126" 2>&1 1>/dev/null])

ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000308004500009287e14000402f57b8ac1f0101ac1f0164100088be0000000520000001144cd5a400008078f2ff00000001f2ff0000000408004500005c38d640004001eb640a0101010a01016408005e57585f0001df6c6b5b0000000045bc050000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f actions=normal"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "IP 172.31.1.100 > 172.31.1.1: GREv0,.* length 126" 2>&1 1>/dev/null])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over ip6erspan v1 tunnel by simulated packets])
OVS_CHECK_XT()
OVS_CHECK_MIN_KERNEL(3, 10)

OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-vsctl -- set bridge br0 other-config:hwaddr=\"f2:ff:00:00:00:01\"])
ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"f2:ff:00:00:00:02\"])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00:100::1/96", f2:ff:00:00:00:03, [], nodad)
AT_CHECK([ip addr add dev br-underlay "fc00:100::100/96" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and simulate a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([ip6erspan], [br0], [at_erspan0], [fc00:100::1], [10.1.1.100/24],
                [options:key=123 options:erspan_ver=1 options:erspan_idx=0x7])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 2 fc00:100::100])

XT6_ACCEPT([br-underlay])

NETNS_DAEMONIZE([at_ns0], [tcpdump -n -x -i p0 dst host fc00:100::1 -l > p0.pcap 2>/dev/null], [tcpdump.pid])
sleep 1

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:100::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now send raw arp request and icmp echo request.
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000386dd60008531003a2f40fc000100000000000000000000000001fc000100000000000000000000000100100088be000000051000007b00000007fffffffffffff2ff0000000408060001080006040001f2ff000000040a0101010000000000000a010164 actions=normal"

dnl Check arp reply.
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0040:  0000 0001 0806 0001 0800 0604 0002 f2ff" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0050:  0000 0001 0a01 0164 f2ff 0000 0004 0a01" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0060:  0101" 2>&1 1>/dev/null])

AT_FAIL_IF([cat p0.pcap | grep -E "IP6 fc00:100::100 > fc00:100::1: GREv0,.* length 114" 2>&1 1>/dev/null])

ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000386dd60008531007a3c40fc000100000000000000000000000001fc0001000000000000000000000001002f00040104010100100088be000000061000407b00000007f2ff00000001f2ff0000000408004500005429b640004001fa8c0a0101010a01016408005c2c7526000118d3685b00000000e4aa020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 actions=normal"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "IP6 fc00:100::100 > fc00:100::1: GREv0,.* length 114" 2>&1 1>/dev/null])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over ip6erspan v2 tunnel by simulated packets])
OVS_CHECK_XT()
OVS_CHECK_MIN_KERNEL(3, 10)

OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-vsctl -- set bridge br0 other-config:hwaddr=\"f2:ff:00:00:00:01\"])
ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"f2:ff:00:00:00:02\"])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "fc00:100::1/96", f2:ff:00:00:00:03, [], nodad)
AT_CHECK([ip addr add dev br-underlay "fc00:100::100/96" nodad])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and simulate a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL6([ip6erspan], [br0], [at_erspan0], [fc00:100::1], [10.1.1.100/24],
                [options:key=121 options:erspan_ver=2 options:erspan_dir=0 options:erspan_hwid=0x7])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 2 fc00:100::100])

XT6_ACCEPT([br-underlay])

NETNS_DAEMONIZE([at_ns0], [tcpdump -n -x -i p0 dst host fc00:100::1 -l > p0.pcap 2>/dev/null], [tcpdump.pid])
sleep 1

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00:100::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now send raw arp request and icmp echo request.
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000386dd60008531003e2f40fc000100000000000000000000000001fc000100000000000000000000000100100088be0000000620000079af514f9900008070fffffffffffff2ff0000000408060001080006040001f2ff000000040a0101010000000000000a010164 actions=normal"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0040:  0004 f2ff 0000 0001 0806 0001 0800 0604" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0050:  0002 f2ff 0000 0001 0a01 0164 f2ff 0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p0.pcap | grep -E "0x0060:  0004 0a01 0101" 2>&1 1>/dev/null])

AT_FAIL_IF([cat p0.pcap | grep -E "IP6 fc00:100::100 > fc00:100::1: GREv0, .* length 118" 2>&1 1>/dev/null])

ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=f2ff00000002f2ff0000000386dd60008531007e3c40fc000100000000000000000000000001fc0001000000000000000000000001002f00040104010100100088be0000000720004079af514f9b00008070f2ff00000001f2ff00000004080045000054ffcb4000400124770a0101010a0101640800419e23ac000112d7685b000000004caf0c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 actions=normal"

OVS_WAIT_UNTIL([cat p0.pcap | grep -E "IP6 fc00:100::100 > fc00:100::1: GREv0, .* length 118" 2>&1 1>/dev/null])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping over srv6 tunnel])
OVS_CHECK_SRV6()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0)
ADD_NAMESPACES(at_ns1)
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.default.seg6_enabled=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv4.conf.default.forwarding=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.default.forwarding=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.seg6_enabled=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv4.conf.all.forwarding=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.forwarding=1])

dnl Set up underlay link from host into the namespace 'at_ns0'
dnl using veth pair. Kernel side tunnel endpoint (SID) is
dnl 'fc00:a::1/128', so add it to the route.
dnl Only IPPROTO_IPIP(4) and IPPROTO_ICMPV6(58) are needed in underlay link.
ADD_BR([br-underlay])
ADD_VETH(p0, at_ns0, br-underlay, "fc00::1/64", [], [], "nodad")
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=1,actions=drop"])
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=100,ipv6,nw_proto=4,actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=100,ipv6,nw_proto=58,actions=normal"])
AT_CHECK([ip addr add dev br-underlay "fc00::100/64" nodad])
AT_CHECK([ip link set dev br-underlay up])
AT_CHECK([ip route add fc00:a::1/128 dev br-underlay via fc00::1])

dnl Set up tunnel endpoints on OVS outside the namespace.
ADD_OVS_TUNNEL6([srv6], [br0], [at_srv6], [fc00:a::1], [10.100.100.100/24])
AT_CHECK([ovs-vsctl set bridge br0 other_config:hwaddr=aa:55:aa:55:00:00])
AT_CHECK([ip route add 10.1.1.0/24 dev br0 via 10.100.100.1])
AT_CHECK([arp -s 10.100.100.1 aa:55:aa:55:00:01])
AT_CHECK([ovs-ofctl add-flow br0 in_port=LOCAL,actions=output:at_srv6])
AT_CHECK([ovs-ofctl add-flow br0 in_port=at_srv6,actions=mod_dl_dst:aa:55:aa:55:00:00,output:LOCAL])

dnl Set up tunnel endpoints on the namespace 'at_ns0',
dnl and overlay port on the namespace 'at_ns1'
ADD_VETH_NS([at_ns0], [ovs-veth0], [10.1.1.2/24], [at_ns1], [ovs-veth1], [10.1.1.1/24])
NS_CHECK_EXEC([at_ns0], [ip sr tunsrc set fc00:a::1])
NS_CHECK_EXEC([at_ns0], [ip route add 10.100.100.0/24 encap seg6 mode encap segs fc00::100 dev p0])
NS_CHECK_EXEC([at_ns0], [ip -6 route add fc00:a::1 encap seg6local action End.DX4 nh4 0.0.0.0 dev ovs-veth0])
NS_CHECK_EXEC([at_ns1], [ip route add 10.100.100.0/24 via 10.1.1.2 dev ovs-veth1])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::100])

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay.
NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -W 2 10.100.100.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - ping6 over srv6 tunnel])
OVS_CHECK_SRV6()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0)
ADD_NAMESPACES(at_ns1)
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.default.seg6_enabled=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.default.forwarding=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.seg6_enabled=1])
NS_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.forwarding=1])

dnl Set up underlay link from host into the namespace 'at_ns0'
dnl using veth pair. Kernel side tunnel endpoint (SID) is
dnl 'fc00:a::1/128', so add it to the route.
dnl Only IPPROTO_IPV6(41) and IPPROTO_ICMPV6(58) are needed in underlay link.
ADD_BR([br-underlay])
ADD_VETH(p0, at_ns0, br-underlay, "fc00::1/64", [], [], "nodad")
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=1,actions=drop"])
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=100,ipv6,nw_proto=41,actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=100,ipv6,nw_proto=58,actions=normal"])
AT_CHECK([ip addr add dev br-underlay "fc00::100/64" nodad])
AT_CHECK([ip link set dev br-underlay up])
AT_CHECK([ip -6 route add fc00:a::1/128 dev br-underlay via fc00::1])

dnl Set up tunnel endpoints on OVS outside the namespace.
ADD_OVS_TUNNEL6([srv6], [br0], [at_srv6], [fc00:a::1], [fc00:100::100/64])
AT_CHECK([ovs-vsctl set bridge br0 other_config:hwaddr=aa:55:aa:55:00:00])
AT_CHECK([ip addr add dev br0 fc00:100::100/64])
AT_CHECK([ip -6 route add fc00:1::1/128 dev br0 via fc00:100::1])
AT_CHECK([ip -6 neigh add fc00:100::1 lladdr aa:55:aa:55:00:01 dev br0])
AT_CHECK([ovs-ofctl add-flow br0 in_port=LOCAL,actions=output:at_srv6])
AT_CHECK([ovs-ofctl add-flow br0 in_port=at_srv6,actions=mod_dl_dst:aa:55:aa:55:00:00,output:LOCAL])

dnl Set up tunnel endpoints on the namespace 'at_ns0',
dnl and overlay port on the namespace 'at_ns1'
ADD_VETH_NS([at_ns0], [ovs-veth0], [fc00:1::2/64], [at_ns1], [ovs-veth1], [fc00:1::1/64])
NS_CHECK_EXEC([at_ns0], [ip sr tunsrc set fc00:a::1])
NS_CHECK_EXEC([at_ns0], [ip -6 route add fc00:100::0/64 encap seg6 mode encap segs fc00::100 dev p0])
NS_CHECK_EXEC([at_ns0], [ip -6 route add fc00:a::1 encap seg6local action End.DX6 nh6 :: dev ovs-veth0])
NS_CHECK_EXEC([at_ns1], [ip -6 route add fc00:100::/64 via fc00:1::2 dev ovs-veth1])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::100])
OVS_WAIT_UNTIL([ip netns exec at_ns1 ping6 -c 1 fc00:100::100])

dnl First, check the underlay.
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay.
NS_CHECK_EXEC([at_ns1], [ping6 -q -c 3 -i 0.3 -W 2 fc00:100::100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - clone action])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_CHECK([ovs-vsctl -- set interface ovs-p0 ofport_request=1 \
                    -- set interface ovs-p1 ofport_request=2])

AT_DATA([flows.txt], [dnl
priority=1 actions=NORMAL
priority=10 in_port=1,ip,actions=clone(mod_dl_dst(50:54:00:00:00:0a),set_field:192.168.3.3->ip_dst), output:2
priority=10 in_port=2,ip,actions=clone(mod_dl_src(ae:c6:7e:54:8d:4d),mod_dl_dst(50:54:00:00:00:0b),set_field:192.168.4.4->ip_dst, controller), output:1
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([cat ofctl_monitor.log | STRIP_MONITOR_CSUM], [0], [dnl
icmp,vlan_tci=0x0000,dl_src=ae:c6:7e:54:8d:4d,dl_dst=50:54:00:00:00:0b,nw_src=10.1.1.2,nw_dst=192.168.4.4,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,icmp_type=0,icmp_code=0 icmp_csum: <skip>
icmp,vlan_tci=0x0000,dl_src=ae:c6:7e:54:8d:4d,dl_dst=50:54:00:00:00:0b,nw_src=10.1.1.2,nw_dst=192.168.4.4,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,icmp_type=0,icmp_code=0 icmp_csum: <skip>
icmp,vlan_tci=0x0000,dl_src=ae:c6:7e:54:8d:4d,dl_dst=50:54:00:00:00:0b,nw_src=10.1.1.2,nw_dst=192.168.4.4,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,icmp_type=0,icmp_code=0 icmp_csum: <skip>
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - mpls actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0])
AT_CHECK([ovs-vsctl add-port br1 patch1])

AT_DATA([flows.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_mpls_label:4,resubmit(,1)
table=0,priority=100,dl_type=0x8847,mpls_label=4 actions=pop_mpls:0x0800,resubmit(,1)
table=0,priority=10 actions=resubmit(,1)
table=1,priority=10 actions=normal
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl add-flows br1 flows.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -W 2 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - multiple mpls label pop])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0])
AT_CHECK([ovs-vsctl add-port br1 patch1])

AT_DATA([flows.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_mpls_label:4,push_mpls:0x8847,set_mpls_label:2,push_mpls:0x8847,set_mpls_label:1,resubmit(,3)
table=0,priority=100,dl_type=0x8847,mpls_label=1 actions=pop_mpls:0x8847,resubmit(,1)
table=1,priority=100,dl_type=0x8847,mpls_label=2 actions=pop_mpls:0x8847,resubmit(,2)
table=2,priority=100,dl_type=0x8847,mpls_label=4 actions=pop_mpls:0x0800,resubmit(,3)
table=0,priority=10 actions=resubmit(,3)
table=3,priority=10 actions=normal
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl add-flows br1 flows.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -W 2 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - encap decap mpls actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])
AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])

AT_DATA([flows.txt], [dnl
table=0,priority=100,in_port=ovs-p0 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p0
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,in_port=ovs-p1 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1
])

AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3  10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3  10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - encap decap mpls_mc actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])
AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])

AT_DATA([flows.txt], [dnl
table=0,priority=100,in_port=ovs-p0 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8848,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p0
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,in_port=ovs-p1 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8848,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1
])

AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3  10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3  10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - multiple encap decap mpls actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])
AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])

AT_DATA([flows.txt], [dnl
table=0,priority=100,in_port=ovs-p0 actions=encap(mpls),set_mpls_label:3, encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=1,type=0x8847)),decap(packet_type(ns=0,type=0)),ovs-p0
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,in_port=ovs-p1 actions=encap(mpls),set_mpls_label:3, encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=1,type=0x8847)),decap(packet_type(ns=0,type=0)),ovs-p1
])

AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - multiple encap decap mpls_mc actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])
AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])

AT_DATA([flows.txt], [dnl
table=0,priority=100,in_port=ovs-p0 actions=encap(mpls_mc),set_mpls_label:3, encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8848,mpls_label=2 actions=decap(),decap(packet_type(ns=1,type=0x8848)),decap(packet_type(ns=0,type=0)),ovs-p0
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,in_port=ovs-p1 actions=encap(mpls_mc),set_mpls_label:3, encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100
table=0,priority=100,in_port=100,dl_type=0x8848,mpls_label=2 actions=decap(),decap(packet_type(ns=1,type=0x8848)),decap(packet_type(ns=0,type=0)),ovs-p1
])

AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - encap mpls pop mpls actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24", 36:b1:ee:7c:01:02)

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])
AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])

AT_DATA([flows.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=decap,encap(mpls),set_mpls_label:2,encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:02,mod_dl_src:36:b1:ee:7c:01:03,output:100
table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=pop_mpls:0x0800,resubmit(,3)
table=0,priority=10 actions=resubmit(,3)
table=3,priority=10 actions=normal
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=decap,encap(mpls),set_mpls_label:2,encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:03,mod_dl_src:36:b1:ee:7c:01:02,output:100
table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=pop_mpls:0x0800,resubmit(,3)
table=0,priority=10 actions=resubmit(,3)
table=3,priority=10 actions=normal
])

AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - push mpls decap mpls actions])
OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24", 36:b1:ee:7c:01:02)

AT_CHECK([ip link add patch0 type veth peer name patch1])
on_exit 'ip link del patch0'

AT_CHECK([ip link set dev patch0 up])
AT_CHECK([ip link set dev patch1 up])
AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])
AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])

AT_DATA([flows.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_field:2->mpls_label,output:100
table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap,decap(packet_type(ns=1,type=0x0800)),encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:03,mod_dl_src:36:b1:ee:7c:01:02,resubmit(,3)
table=0,priority=10 actions=resubmit(,3)
table=3,priority=10 actions=normal
])

AT_DATA([flows1.txt], [dnl
table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_field:2->mpls_label,output:100
table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap,decap(packet_type(ns=1,type=0x0800)),encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:02,mod_dl_src:36:b1:ee:7c:01:03,resubmit(,3)
table=0,priority=10 actions=resubmit(,3)
table=3,priority=10 actions=normal
])

AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - basic truncate action])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-ofctl del-flows br0])

dnl Create p0 and ovs-p0(1)
ADD_NAMESPACES(at_ns0)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])

dnl Create p1(3) and ovs-p1(2), packets received from ovs-p1 will appear in p1
AT_CHECK([ip link add p1 type veth peer name ovs-p1])
on_exit 'ip link del ovs-p1'
AT_CHECK([ip link set dev ovs-p1 up])
AT_CHECK([ip link set dev p1 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p1 -- set interface ovs-p1 ofport_request=2])
dnl Use p1 to check the truncated packet
AT_CHECK([ovs-vsctl add-port br0 p1 -- set interface p1 ofport_request=3])

dnl Create p2(5) and ovs-p2(4)
AT_CHECK([ip link add p2 type veth peer name ovs-p2])
on_exit 'ip link del ovs-p2'
AT_CHECK([ip link set dev ovs-p2 up])
AT_CHECK([ip link set dev p2 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p2 -- set interface ovs-p2 ofport_request=4])
dnl Use p2 to check the truncated packet
AT_CHECK([ovs-vsctl add-port br0 p2 -- set interface p2 ofport_request=5])

dnl basic test
AT_CHECK([ovs-ofctl del-flows br0])
AT_DATA([flows.txt], [dnl
in_port=3 dl_dst=e6:66:c1:22:22:22 actions=drop
in_port=5 dl_dst=e6:66:c1:22:22:22 actions=drop
in_port=1 dl_dst=e6:66:c1:22:22:22 actions=output(port=2,max_len=100),output:4
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl use this file as payload file for ncat
AT_CHECK([dd if=/dev/urandom of=payload200.bin bs=200 count=1 2> /dev/null])
on_exit 'rm -f payload200.bin'
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT -u 10.1.1.2 1234 < payload200.bin])

dnl packet with truncated size
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 table=0 | grep "in_port=3" |  sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=100
])
dnl packet with original size
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 table=0 | grep "in_port=5" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=242
])

dnl more complicated output actions
AT_CHECK([ovs-ofctl del-flows br0])
AT_DATA([flows.txt], [dnl
in_port=3 dl_dst=e6:66:c1:22:22:22 actions=drop
in_port=5 dl_dst=e6:66:c1:22:22:22 actions=drop
in_port=1 dl_dst=e6:66:c1:22:22:22 actions=output(port=2,max_len=100),output:4,output(port=2,max_len=100),output(port=4,max_len=100),output:2,output(port=4,max_len=200),output(port=2,max_len=65535)
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT -u 10.1.1.2 1234 < payload200.bin])

dnl 100 + 100 + 242 + min(65535,242) = 684
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 table=0 | grep "in_port=3" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=684
])
dnl 242 + 100 + min(242,200) = 542
AT_CHECK([ovs-ofctl dump-flows br0 table=0 | grep "in_port=5" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=542
])

dnl SLOW_ACTION: disable kernel datapath truncate support
dnl Repeat the test above, but exercise the SLOW_ACTION code path
AT_CHECK([ovs-appctl dpif/set-dp-features br0 trunc false], [0])

dnl SLOW_ACTION test1: check datapatch actions
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_type=0x800,dl_src=e6:66:c1:11:11:11,dl_dst=e6:66:c1:22:22:22,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,tp_src=8,tp_dst=9"], [0], [stdout])
AT_CHECK([tail -3 stdout], [0],
[Datapath actions: trunc(100),3,5,trunc(100),3,trunc(100),5,3,trunc(200),5,trunc(65535),3
This flow is handled by the userspace slow path because it:
  - Uses action(s) not supported by datapath.
])

dnl SLOW_ACTION test2: check actual packet truncate
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT -u 10.1.1.2 1234 < payload200.bin])

dnl 100 + 100 + 242 + min(65535,242) = 684
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 table=0 | grep "in_port=3" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=684
])

dnl 242 + 100 + min(242,200) = 542
AT_CHECK([ovs-ofctl dump-flows br0 table=0 | grep "in_port=5" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=542
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

dnl Create 2 bridges and 2 namespaces to test truncate over
dnl GRE tunnel:
dnl   br0: overlay bridge
dnl   ns1: connect to br0, with IP:10.1.1.2
dnl   br-underlay: with IP: 172.31.1.100
dnl   ns0: connect to br-underlay, with IP: 10.1.1.1
AT_SETUP([datapath - truncate and output to gre tunnel by simulated packets])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_NO_TC_OFFLOAD()
OVS_TRAFFIC_VSWITCHD_START()

ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"02:90:8c:a8:a1:49\"])
ADD_NAMESPACES(at_ns0)
ADD_NAMESPACES(at_ns1)
AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24", fa:ad:fa:25:05:60)
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([gre], [br0], [at_gre0], [172.31.1.1], [10.1.1.100/24])

dnl The below native tunnel isn't actually added. We simulate it to send
dnl and receive packets.
dnl ADD_NATIVE_TUNNEL([gretap], [ns_gre0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
dnl                   [], [address e6:66:c1:11:11:11])
dnl AT_CHECK([ovs-vsctl -- set interface at_gre0 ofport_request=1])
dnl NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])

dnl Set up (p1 and ovs-p1) at br0
ADD_VETH(p1, at_ns1, br0, '10.1.1.2/24')
AT_CHECK([ovs-vsctl -- set interface ovs-p1 ofport_request=2])
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])

dnl Set up (p2 and ovs-p2) as loopback for verifying packet size
AT_CHECK([ip link add p2 type veth peer name ovs-p2])
on_exit 'ip link del ovs-p2'
AT_CHECK([ip link set dev ovs-p2 up])
AT_CHECK([ip link set dev p2 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p2 -- set interface ovs-p2 ofport_request=3])
AT_CHECK([ovs-vsctl add-port br0 p2 -- set interface p2 ofport_request=4])

dnl use this file as payload file for ncat
AT_CHECK([dd if=/dev/urandom of=payload200.bin bs=200 count=1 2> /dev/null])
on_exit 'rm -f payload200.bin'

AT_CHECK([ovs-ofctl del-flows br0])
AT_DATA([flows.txt], [dnl
priority=99,in_port=1,actions=output(port=2,max_len=100),output(port=3,max_len=100)
priority=99,in_port=2,udp,actions=output(port=1,max_len=100)
priority=1,in_port=4,ip,actions=drop
priority=1,actions=drop
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl del-flows br-underlay])
AT_DATA([flows-underlay.txt], [dnl
priority=99,dl_type=0x0800,nw_proto=47,in_port=1,actions=LOCAL
priority=99,dl_type=0x0800,nw_proto=47,in_port=LOCAL,ip_dst=172.31.1.1/24,actions=1
priority=1,actions=drop
])

AT_CHECK([ovs-ofctl add-flows br-underlay flows-underlay.txt])

dnl check tunnel push path, from at_ns1 to at_ns0
NS_CHECK_EXEC([at_ns1], [nc $NC_EOF_OPT -u 10.1.1.1 1234 < payload200.bin])
AT_CHECK([ovs-appctl revalidator/purge], [0])

dnl Before truncation = ETH(14) + IP(20) + UDP(8) + 200 = 242B
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=2" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=242
])
dnl After truncation = outer ETH(14) + outer IP(20) + GRE(4) + 100 = 138B
OVS_WAIT_UNTIL_EQUAL([ovs-ofctl dump-flows br-underlay | grep "in_port=LOCAL" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [dnl
n_bytes=138])

dnl check tunnel pop path, from at_ns0 to at_ns1
dnl This 200-byte packet is simulated on behalf of ns_gre0
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=02908ca8a149faadfa25056008004500010a9e9d4000402f4084ac1f0101ac1f016400006558e666c1222222e666c11111110800450000e46f8e40004011b4760a0101010a010102e026162e00d016e6a366ebf904c74132c6fed42a9e9e46240b4d9fd13c9b47d9704a388e70a5e77db16934a6188dc01d86aa20007ace2cf9cdb111f208474b88ffc851c871f0e3fb4fff138c1d288d437efff487e2b86a9c99fbf4229a6485e133bcf3e16f6e345207fda0932d9eeb602740456fd077b4847d25481337bd716155cc245be129ccc11bf82b834767b3760b52fe913c0e24f31c0e1b27f88acf7bba6b985fb64ee2cd6fc6bba1a9c1f021e253e1728b046fd4d023307e3296361a37ea2617ebcb2537e0284a81050dd0ee actions=LOCAL"

dnl After truncation = 100 byte at loopback device p2(4)
AT_CHECK([ovs-appctl revalidator/purge], [0])
OVS_WAIT_UNTIL_EQUAL([ovs-ofctl dump-flows br0 | grep "in_port=4" | ofctl_strip], [dnl
 n_packets=1, n_bytes=100, priority=1,ip,in_port=4 actions=drop])


dnl SLOW_ACTION: disable datapath truncate support
dnl Repeat the test above, but exercise the SLOW_ACTION code path
AT_CHECK([ovs-appctl dpif/set-dp-features br0 trunc false], [0])

dnl SLOW_ACTION test1: check datapatch actions
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl SLOW_ACTION test2: check actual packet truncate
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl del-flows br-underlay])
AT_CHECK([ovs-ofctl add-flows br-underlay flows-underlay.txt])

dnl check tunnel push path, from at_ns1 to at_ns0
NS_CHECK_EXEC([at_ns1], [nc $NC_EOF_OPT -u 10.1.1.1 1234 < payload200.bin])
AT_CHECK([ovs-appctl revalidator/purge], [0])

dnl Before truncation = ETH(14) + IP(20) + UDP(8) + 200 = 242B
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=2" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=242
])
dnl After truncation = outer ETH(14) + outer IP(20) + GRE(4) + 100 = 138B
OVS_WAIT_UNTIL_EQUAL([ovs-ofctl dump-flows br-underlay | grep "in_port=LOCAL" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [dnl
n_bytes=138])

dnl check tunnel pop path, from at_ns0 to at_ns1
dnl This 200-byte packet is simulated on behalf of ns_gre0
ovs-ofctl -O OpenFlow13 packet-out br-underlay "in_port=1 packet=02908ca8a149faadfa25056008004500010a9e9d4000402f4084ac1f0101ac1f016400006558e666c1222222e666c11111110800450000e46f8e40004011b4760a0101010a010102e026162e00d016e6a366ebf904c74132c6fed42a9e9e46240b4d9fd13c9b47d9704a388e70a5e77db16934a6188dc01d86aa20007ace2cf9cdb111f208474b88ffc851c871f0e3fb4fff138c1d288d437efff487e2b86a9c99fbf4229a6485e133bcf3e16f6e345207fda0932d9eeb602740456fd077b4847d25481337bd716155cc245be129ccc11bf82b834767b3760b52fe913c0e24f31c0e1b27f88acf7bba6b985fb64ee2cd6fc6bba1a9c1f021e253e1728b046fd4d023307e3296361a37ea2617ebcb2537e0284a81050dd0ee actions=LOCAL"

dnl After truncation = 100 byte at loopback device p2(4)
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=4" | ofctl_strip], [0], [dnl
 n_packets=1, n_bytes=100, priority=1,ip,in_port=4 actions=drop
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

dnl Create 2 bridges and 2 namespaces to test truncate over
dnl GRE tunnel:
dnl   br0: overlay bridge
dnl   ns1: connect to br0, with IP:10.1.1.2
dnl   br-underlay: with IP: 172.31.1.100
dnl   ns0: connect to br-underlay, with IP: 10.1.1.1
AT_SETUP([datapath - truncate and output to gre tunnel])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_CHECK_GRE()
CHECK_NO_TC_OFFLOAD()
OVS_TRAFFIC_VSWITCHD_START()

ADD_BR([br-underlay])
ADD_NAMESPACES(at_ns0)
ADD_NAMESPACES(at_ns1)
AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([gre], [br0], [at_gre0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([gretap], [ns_gre0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [], [address e6:66:c1:11:11:11])
AT_CHECK([ovs-vsctl -- set interface at_gre0 ofport_request=1])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])

dnl Set up (p1 and ovs-p1) at br0
ADD_VETH(p1, at_ns1, br0, '10.1.1.2/24')
AT_CHECK([ovs-vsctl -- set interface ovs-p1 ofport_request=2])
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])

dnl Set up (p2 and ovs-p2) as loopback for verifying packet size
AT_CHECK([ip link add p2 type veth peer name ovs-p2])
on_exit 'ip link del ovs-p2'
AT_CHECK([ip link set dev ovs-p2 up])
AT_CHECK([ip link set dev p2 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p2 -- set interface ovs-p2 ofport_request=3])
AT_CHECK([ovs-vsctl add-port br0 p2 -- set interface p2 ofport_request=4])

dnl use this file as payload file for ncat
AT_CHECK([dd if=/dev/urandom of=payload200.bin bs=200 count=1 2> /dev/null])
on_exit 'rm -f payload200.bin'

AT_CHECK([ovs-ofctl del-flows br0])
AT_DATA([flows.txt], [dnl
priority=99,in_port=1,actions=output(port=2,max_len=100),output(port=3,max_len=100)
priority=99,in_port=2,udp,actions=output(port=1,max_len=100)
priority=1,in_port=4,ip,actions=drop
priority=1,actions=drop
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl del-flows br-underlay])
AT_DATA([flows-underlay.txt], [dnl
priority=99,dl_type=0x0800,nw_proto=47,in_port=1,actions=LOCAL
priority=99,dl_type=0x0800,nw_proto=47,in_port=LOCAL,ip_dst=172.31.1.1/24,actions=1
priority=1,actions=drop
])

AT_CHECK([ovs-ofctl add-flows br-underlay flows-underlay.txt])

dnl check tunnel push path, from at_ns1 to at_ns0
NS_CHECK_EXEC([at_ns1], [nc $NC_EOF_OPT -u 10.1.1.1 1234 < payload200.bin])
AT_CHECK([ovs-appctl revalidator/purge], [0])

dnl Before truncation = ETH(14) + IP(20) + UDP(8) + 200 = 242B
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=2" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=242
])
dnl After truncation = outer ETH(14) + outer IP(20) + GRE(4) + 100 = 138B
AT_CHECK([ovs-ofctl dump-flows br-underlay | grep "in_port=LOCAL" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=138
])

dnl check tunnel pop path, from at_ns0 to at_ns1
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT -u 10.1.1.2 5678 < payload200.bin])
dnl After truncation = 100 byte at loopback device p2(4)
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=4" | ofctl_strip], [0], [dnl
 n_packets=1, n_bytes=100, priority=1,ip,in_port=4 actions=drop
])

dnl SLOW_ACTION: disable datapath truncate support
dnl Repeat the test above, but exercise the SLOW_ACTION code path
AT_CHECK([ovs-appctl dpif/set-dp-features br0 trunc false], [0])

dnl SLOW_ACTION test1: check datapatch actions
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl SLOW_ACTION test2: check actual packet truncate
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl del-flows br-underlay])
AT_CHECK([ovs-ofctl add-flows br-underlay flows-underlay.txt])

dnl check tunnel push path, from at_ns1 to at_ns0
NS_CHECK_EXEC([at_ns1], [nc $NC_EOF_OPT -u 10.1.1.1 1234 < payload200.bin])
AT_CHECK([ovs-appctl revalidator/purge], [0])

dnl Before truncation = ETH(14) + IP(20) + UDP(8) + 200 = 242B
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=2" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=242
])
dnl After truncation = outer ETH(14) + outer IP(20) + GRE(4) + 100 = 138B
AT_CHECK([ovs-ofctl dump-flows br-underlay | grep "in_port=LOCAL" | sed -n 's/.*\(n\_bytes=[[0-9]]*\).*/\1/p'], [0], [dnl
n_bytes=138
])

dnl check tunnel pop path, from at_ns0 to at_ns1
NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT -u 10.1.1.2 5678 < payload200.bin])
dnl After truncation = 100 byte at loopback device p2(4)
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 | grep "in_port=4" | ofctl_strip], [0], [dnl
 n_packets=1, n_bytes=100, priority=1,ip,in_port=4 actions=drop
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - configure cache size])

OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_KERNEL_EXCL(3, 10, 5, 8)

AT_CHECK([ovs-dpctl cache-get-size one-bad-dp], [1], [], [dnl
ovs-dpctl: Opening datapath one-bad-dp failed (No such device)
])
AT_CHECK([ovs-dpctl cache-get-size | grep masks-cache | tr -d [[:blank:]]], [0], [dnl
masks-cache:size:256
])
AT_CHECK([ovs-dpctl cache-set-size one-bad-dp masks-cache 0], [1], [], [dnl
ovs-dpctl: Opening datapath one-bad-dp failed (No such device)
])
AT_CHECK([ovs-dpctl cache-set-size system@ovs-system dummy-cache 0], [1], [], [dnl
ovs-dpctl: Cache name "dummy-cache" not found on dpif (Invalid argument)
])
AT_CHECK([ovs-dpctl cache-set-size system@ovs-system masks-cache 80000], [1], [], [dnl
ovs-dpctl: Setting cache size failed (Numerical result out of range)
])
AT_CHECK([ovs-dpctl cache-set-size system@ovs-system masks-cache 0], [0], [dnl
Setting cache size successful, new size 0
])
AT_CHECK([ovs-dpctl cache-get-size | grep masks-cache | tr -d [[:blank:]]], [0], [dnl
masks-cache:size:0
])
AT_CHECK([ovs-dpctl cache-set-size system@ovs-system masks-cache 256], [0], [dnl
Setting cache size successful, new size 256
])
AT_CHECK([ovs-dpctl cache-get-size | grep masks-cache | tr -d [[:blank:]]], [0], [dnl
masks-cache:size:256
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - drop action])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_DROP_ACTION()
AT_KEYWORDS(drop_action)

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Exceed the max number of resubmits.
(echo "dl_type=0x806, actions=normal"
for i in $(seq 1 64); do
     j=$(expr $i + 1)
     echo "in_port=$i, actions=resubmit:$j, resubmit:$j, local"
 done
 echo "in_port=65, actions=local"
) > flows.txt
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl Generate some traffic.
NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2], [1], [ignore])

OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/dump-flows | grep "eth_type(0x0800)" | dnl
                      strip_ptype | strip_eth | strip_recirc | strip_stats | dnl
                      strip_used | sort], [dnl
recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:drop])

OVS_TRAFFIC_VSWITCHD_STOP(["/WARN/d"])
AT_CLEANUP

AT_SETUP([datapath - simulated flow action update])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
add in_port=ovs-p0,actions=ovs-p1,br0
add in_port=ovs-p1,actions=ovs-p0,br0
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
10 packets transmitted, 10 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-flows | grep "eth_type(0x0800)" | sort | dnl
          strip_recirc | strip_used | dnl
          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:756/bytes:882/'],
          [0], [dnl
recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:882, used:0.0s, actions:3,1
recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:882, used:0.0s, actions:2,1
])

AT_DATA([flows2.txt], [dnl
modify in_port=ovs-p0,actions=ovs-p1
modify in_port=ovs-p1,actions=ovs-p0
])
AT_CHECK([ovs-ofctl add-flows br0 flows2.txt])
AT_CHECK([ovs-appctl revalidator/wait], [0])

NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
10 packets transmitted, 10 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-flows | grep "eth_type(0x0800)" | sort | dnl
          strip_recirc | strip_used | dnl
          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:1596/bytes:1862/'],
          [0], [dnl
recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:19, bytes:1862, used:0.0s, actions:3
recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:19, bytes:1862, used:0.0s, actions:2
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-appctl revalidator/wait], [0])

NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
10 packets transmitted, 10 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-flows | grep "eth_type(0x0800)" | sort | dnl
          strip_recirc | strip_used | dnl
          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:2436/bytes:2842/'],
          [0], [dnl
recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:29, bytes:2842, used:0.0s, actions:3,1
recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:29, bytes:2842, used:0.0s, actions:2,1
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - netdev offload software fallback])
AT_SKIP_IF([test $HAVE_NC = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Test the case where only one side has all checksum and tso offload disabled.
AT_CHECK([ethtool -K ovs-p1 tso off], [0], [ignore], [ignore])
AT_CHECK([ethtool -K ovs-p1 sg off], [0], [ignore], [ignore])

dnl Reinitialize.
AT_CHECK([ovs-vsctl del-port ovs-p1])
AT_CHECK([ovs-vsctl add-port br0 ovs-p1])

NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns1], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NETNS_DAEMONIZE([at_ns0], [nc -l 1234 > data_0], [nc1.pid])
NETNS_DAEMONIZE([at_ns1], [nc -l 1234 > data_1], [nc2.pid])

AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
on_exit 'rm -f payload.bin'

NS_CHECK_EXEC([at_ns0], [nc $NC_EOF_OPT 10.1.1.2 1234 < payload.bin])
NS_CHECK_EXEC([at_ns1], [nc $NC_EOF_OPT 10.1.1.1 1234 < payload.bin])

dnl Wait until transfer completes.
OVS_WAIT_WHILE([kill -0 $(cat nc1.pid) $(cat nc2.pid)])

AT_CHECK([diff -q payload.bin data_0], [0])
AT_CHECK([diff -q payload.bin data_1], [0])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - Neighbor Discovery with loose match])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "2001::1:0:392/64", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "2001::1:0:9/64", 36:b1:ee:7c:01:02)

dnl Set up flows for moving icmp ND Solicit around.  This should be the
dnl same for the other ND types.
AT_DATA([flows.txt], [dnl
table=0 priority=95 icmp6,icmp_type=136,nd_target=2001::1:0:9 actions=resubmit(,10)
table=0 priority=95 icmp6,icmp_type=136,nd_target=2001::1:0:392 actions=resubmit(,10)
table=0 priority=65 actions=resubmit(,20)
table=10 actions=NORMAL
table=20 actions=drop
])
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

m4_define([ND_NS_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x86dd],
  [ipv6_src=fe80::f816:3eff:fe04:6604,ipv6_dst=fe80::f816:3eff:fea7:dd0e],
  [nw_proto=58,nw_ttl=255,nw_frag=no],
  [icmpv6_type=136,icmpv6_code=0],
  [nd_options_type=2,nd_tll=36:b1:ee:7c:01:03])])

dnl Send a mismatching neighbor discovery.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=3000::1')],
  [0], [ignore])

dnl Send a matching neighbor discovery.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=2001::1:0:392')],
  [0], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-flows | strip_stats | strip_used | dnl
          strip_key32 | strip_ptype | strip_eth | strip_recirc | dnl
          grep ",nd" | sort], [0], [dnl
recirc_id(<recirc>),in_port(2),eth(src=36:b1:ee:7c:01:03,dst=36:b1:ee:7c:01:02),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=136),nd(target=2001::1:0:392), packets:0, bytes:0, used:never, actions:1,3
recirc_id(<recirc>),in_port(2),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=136),nd(target=3000::1), packets:0, bytes:0, used:never, actions:drop
])

OVS_WAIT_UNTIL([ovs-appctl dpctl/dump-flows | grep ",nd" | wc -l | grep -E ^0])

dnl Send a matching neighbor discovery.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=2001::1:0:392')],
  [0], [ignore])

dnl Send a mismatching neighbor discovery.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ND_NS_PKT,nd_target=3000::1')],
  [0], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-flows | strip_stats | strip_used | dnl
          strip_key32 | strip_ptype | strip_eth | strip_recirc | dnl
          grep ",nd" | sort], [0], [dnl
recirc_id(<recirc>),in_port(2),eth(src=36:b1:ee:7c:01:03,dst=36:b1:ee:7c:01:02),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=136),nd(target=2001::1:0:392), packets:0, bytes:0, used:never, actions:1,3
recirc_id(<recirc>),in_port(2),eth_type(0x86dd),ipv6(proto=58,frag=no),icmpv6(type=136),nd(target=3000::1), packets:0, bytes:0, used:never, actions:drop
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - Dump OF rules corresponding to UFID])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p1, at_ns0, br0, "10.0.0.1/24")
ADD_VETH(p2, at_ns1, br0, "10.0.0.2/24")

AT_CHECK([ovs-vsctl -- set interface ovs-p1 ofport_request=1 \
                    -- set interface ovs-p2 ofport_request=2])

dnl Add some OpenFlow rules and groups.
AT_DATA([groups.txt], [dnl
group_id=1,type=select,selection_method=dp_hash,bucket=bucket_id:0,weight:100,actions=ct(commit,table=2)
])
AT_DATA([flows.txt], [dnl
table=0,arp,actions=NORMAL
table=0,priority=100,cookie=0x12345678,in_port=ovs-p1,ip,nw_dst=10.0.0.2,actions=resubmit(,1)
table=0,priority=100,cookie=0xabcedf,in_port=ovs-p2,ip,nw_dst=10.0.0.1,actions=ct(table=3)
table=1,priority=200,ip,actions=group:1
table=2,ip,actions=ovs-p2
table=3,ip,actions=ovs-p1
])
AT_CHECK([ovs-ofctl add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.1 -W 2 10.0.0.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl revalidator/wait])
# Add an unrelated OF change to populate the xcache during the next reval run.
AT_CHECK([ovs-ofctl add-flow br0 table=4,ip,action=drop])
AT_CHECK([ovs-appctl revalidator/wait])

AT_CHECK([ovs-appctl revalidator/pause])

AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [stdout])

core=$(head -1 stdout | grep "flow-dump from pmd" | grep -o "[[-]]\?[[0-9]]\+$")
if test -z $core; then
    pmd_id=""
else
    pmd_id="pmd=$core"
fi

AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep "ipv4" | strip_used | strip_stats | \
          strip_duration | strip_dp_hash | strip_recirc | sed 's/:never/:0.0s/' | \
          strip_ptype | strip_eth | sort], [0], [dnl
recirc_id(<recirc>),in_port(ovs-p1),eth_type(0x0800),ipv4(dst=10.0.0.2,frag=no), packets:0, bytes:0, used:0.0s, actions:hash(l4(0)),recirc(<recirc>)
recirc_id(<recirc>),in_port(ovs-p1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(commit),recirc(<recirc>)
recirc_id(<recirc>),in_port(ovs-p1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ovs-p2
recirc_id(<recirc>),in_port(ovs-p2),eth_type(0x0800),ipv4(dst=10.0.0.1,frag=no), packets:0, bytes:0, used:0.0s, actions:ct,recirc(<recirc>)
recirc_id(<recirc>),in_port(ovs-p2),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ovs-p1
])

ufid=$(ovs-appctl dpctl/dump-flows -m filter='recirc_id(0),in_port(ovs-p1),ipv4' | parse_ufid)
AT_CHECK([ovs-appctl ofproto/detrace $ufid $pmd_id | ofctl_strip | \
          sed -E 's/n_bytes=2(66|80),/n_bytes=294,/'], [0], [dnl
cookie=0x12345678, n_packets=3, n_bytes=294, priority=100,ip,in_port=1,nw_dst=10.0.0.2,actions=resubmit(,1)
table_id=1, n_packets=3, n_bytes=294, priority=200,ip,actions=group:1
])

ufid=$(ovs-appctl dpctl/dump-flows -m filter='in_port(ovs-p1),ipv4' | grep "ct(commit)" | parse_ufid)
AT_CHECK([ovs-appctl ofproto/detrace $ufid $pmd_id | ofctl_strip | \
          sed -E 's/n_bytes=2(66|80),/n_bytes=294,/'], [0], [dnl
group_id=1,type=select,selection_method=dp_hash,bucket=bucket_id:0,weight:100,actions=ct(commit,table=2)
])

ufid=$(ovs-appctl dpctl/dump-flows -m filter='in_port(ovs-p1),ipv4' | grep "actions:ovs-p2" | parse_ufid)
AT_CHECK([ovs-appctl ofproto/detrace $ufid $pmd_id | ofctl_strip | \
          sed -E 's/n_bytes=2(66|80),/n_bytes=294,/'], [0], [dnl
table_id=2, n_packets=3, n_bytes=294, ip,actions=output:2
])

ufid=$(ovs-appctl dpctl/dump-flows -m filter='recirc_id(0),in_port(ovs-p2),ipv4' | grep "ct," | parse_ufid)
AT_CHECK([ovs-appctl ofproto/detrace $ufid $pmd_id | ofctl_strip | \
          sed -E 's/n_bytes=2(66|80),/n_bytes=294,/'], [0], [dnl
cookie=0xabcedf, n_packets=3, n_bytes=294, priority=100,ip,in_port=2,nw_dst=10.0.0.1,actions=ct(table=3)
])

ufid=$(ovs-appctl dpctl/dump-flows -m filter='in_port(ovs-p2),ipv4' | grep "actions:ovs-p1" | parse_ufid)
AT_CHECK([ovs-appctl ofproto/detrace $ufid $pmd_id | ofctl_strip | \
          sed -E 's/n_bytes=2(66|80),/n_bytes=294,/'], [0], [dnl
table_id=3, n_packets=3, n_bytes=294, ip,actions=output:1
])

AT_CHECK([ovs-appctl revalidator/resume])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([datapath - mod_nw_src/set_field on IP fragments])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

AT_DATA([flows.txt], [dnl
  in_port=ovs-p0,ip,nw_src=10.1.1.1 actions=mod_nw_src=11.1.1.1,ovs-p1
  in_port=ovs-p0,ipv6,ipv6_src=fc00::1 actions=set_field:fc00::100->ipv6_src,ovs-p1
])

AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl -Oopenflow13 add-flows br0 flows.txt])

NETNS_DAEMONIZE([at_ns1],
                [tcpdump -l -nn -xx -U -i p1 -w p1.pcap 2> tcpdump.err],
                [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump.err])

dnl IPv4 Packet content:
dnl   Ethernet II, Src: 36:b1:ee:7c:01:03, Dst: 36:b1:ee:7c:01:02
dnl       Type: IPv4 (0x0800)
dnl   Internet Protocol Version 4, Src: 10.1.1.1, Dst: 10.1.1.2
dnl       0100 .... = Version: 4
dnl       .... 0101 = Header Length: 20 bytes (5)
dnl       Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
dnl       Total Length: 38
dnl       Identification: 0x0001 (1)
dnl       001. .... = Flags: 0x1, More fragments
dnl           0... .... = Reserved bit: Not set
dnl           .0.. .... = Don't fragment: Not set
dnl           ..1. .... = More fragments: Set
dnl       ...0 0000 0000 0000 = Fragment Offset: 0
dnl       Time to Live: 64
dnl       Protocol: UDP (17)
dnl       Header Checksum: 0x44c2
dnl   Data (18 bytes)
eth="36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00"
ip="45 00 00 26 00 01 20 00 40 11 44 c2 0a 01 01 01 0a 01 01 02"
data="0b c4 08 84 00 26 e9 64 01 02 03 04 05 06 07 08 09 0a"
packet="${eth} ${ip} ${data}"

dnl We send each packet multiple times, one for learning, which will go to
dnl ovs-vswitchd, and the others will go through the actual datapath.
for i in 1 2 3 4 5; do
  NS_CHECK_EXEC([at_ns0],
                [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])
done

dnl Update source address and checksums in original packet for comparison.
packet=$(echo "$packet" | sed -e 's/ //g' \
         -e 's/0a010101/0b010101/g' -e 's/44c2/43c2/g' -e 's/e964/e864/g')
OVS_WAIT_UNTIL([test $(ovs-pcap p1.pcap | grep -c "${packet}") -eq 5])

dnl Repeat similar test with IPv6.
dnl Packet content:
dnl   Ethernet II, Src: 36:b1:ee:7c:01:03, Dst: 36:b1:ee:7c:01:02
dnl       Type: IPv6 (0x86dd)
dnl   Internet Protocol Version 6, Src: fc00::1, Dst: fc00::2
dnl       Payload Length: 24
dnl       Next Header: Fragment Header for IPv6 (44)
dnl       Hop Limit: 64
dnl       Fragment Header for IPv6
dnl           Next header: UDP (17)
dnl           Reserved octet: 0x00
dnl           0000 0000 0000 0... = Offset: 0 (0 bytes)
dnl           .... .... .... .00. = Reserved bits: 0
dnl           .... .... .... ...1 = More Fragments: Yes
dnl           Identification: 0x2316ab36
dnl   Data (16 bytes)
eth="36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 86 dd"
ip="60 00 00 00 00 18 2c 40 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 \
    fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 11 00 00 01 23 16 ab 36"
data="0b c4 08 84 00 26 07 65 01 02 03 04 05 06 07 08"
packet="${eth} ${ip} ${data}"

for i in 1 2 3 4 5; do
  NS_CHECK_EXEC([at_ns0],
                [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])
done

dnl Update checksum and source address in original packet for comparison.
packet=$(echo "$packet" | sed -e 's/ //g' -e 's/0765/0666/g' -e \
       's/fc000000000000000000000000000001/fc000000000000000000000000000100/g')
OVS_WAIT_UNTIL([test $(ovs-pcap p1.pcap | grep -c "${packet}") -eq 5])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([MPLS])

AT_SETUP([mpls - encap header dp-support])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_SKIP_IF([! ovs-appctl dpif/show-dp-features br0 2>&1 | grep "MPLS Label add: Yes" >/dev/null])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

dnl The flow will encap a mpls header to the ip packet
dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])

dnl Check the expected mpls encapsulated packet on the egress interface.
m4_define([MPLS_HEADER], [m4_join([,],
  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])

OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([mpls - encap header slow-path])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

dnl The flow will encap a mpls header to the ip packet
dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])

dnl Check the expected mpls encapsulated packet on the egress interface.
m4_define([MPLS_HEADER], [m4_join([,],
  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])

OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([mpls_mc - encap header dp-support])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_SKIP_IF([! ovs-appctl dpif/show-dp-features br0 2>&1 | grep "MPLS Label add: Yes" >/dev/null])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

dnl The flow will encap a mpls header to the ip packet
dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])

dnl Check the expected mpls encapsulated packet on the egress interface.
m4_define([MPLS_HEADER], [m4_join([,],
  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8848],
  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])

OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([mpls_mc - encap header slow-path])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

dnl The flow will encap a mpls header to the ip packet
dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x0800 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT')], [0], [ignore])

dnl Check the expected mpls encapsulated packet on the egress interface.
m4_define([MPLS_HEADER], [m4_join([,],
  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8848],
  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])

OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'MPLS_HEADER'),
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([mpls - decap header dp-support])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_SKIP_IF([! ovs-appctl dpif/show-dp-features br0 2>&1 | grep "MPLS Label add: Yes" >/dev/null])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

dnl The flow will decap a mpls header which in turn carries a icmp packet
dnl eth/mpls/eth/ip/icmp --> OVS --> eth/ip/icmp

AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([MPLS_HEADER], [m4_join([,],
  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

dnl The packet is an eth/mpls/eth/ip/icmp sent from p0(at_ns0) interface
dnl directed to p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    "$(ovs-ofctl compose-packet --bare 'MPLS_HEADER')"  \
    "$(ovs-ofctl compose-packet --bare 'ICMP_PKT')"],
  [0], [ignore])

dnl Check the expected decapsulated on the egress interface.
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
    "^$(ovs-ofctl compose-packet --bare 'ICMP_PKT')\$"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([mpls - decap header slow-path])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", 36:b1:ee:7c:01:03)
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", 36:b1:ee:7c:01:02)

dnl The flow will decap a mpls header which in turn carries a icmp packet
dnl eth/mpls/eth/ip/icmp --> OVS --> eth/ip/icmp

AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([MPLS_HEADER], [m4_join([,],
  [eth_src=00:00:00:00:00:01,eth_dst=00:00:00:00:00:02,eth_type=0x8847],
  [mpls_label=2,mpls_ttl=64,mpls_bos=1])])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=36:b1:ee:7c:01:03,eth_dst=36:b1:ee:7c:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

dnl The packet is an eth/mpls/eth/ip/icmp sent from p0(at_ns0) interface
dnl directed to p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    "$(ovs-ofctl compose-packet --bare 'MPLS_HEADER')"  \
    "$(ovs-ofctl compose-packet --bare 'ICMP_PKT')"],
  [0], [ignore])

dnl Check the expected decapsulated on the egress interface.
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
    "^$(ovs-ofctl compose-packet --bare 'ICMP_PKT')\$"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([QoS])

AT_SETUP([QoS - basic configuration])
OVS_CHECK_TC_QDISC()
AT_SKIP_IF([test $HAVE_ETHTOOL = "no"])
OVS_TRAFFIC_VSWITCHD_START()

AT_CHECK([ip tuntap add ovs-tap0 mode tap])
on_exit 'ip link del ovs-tap0'
AT_CHECK([ip tuntap add ovs-tap1 mode tap])
on_exit 'ip link del ovs-tap1'

dnl Set maximum link speed to 5Gb.
AT_CHECK([ethtool -s ovs-tap0 speed 5000 duplex full])
AT_CHECK([ip link set dev ovs-tap0 up])
AT_CHECK([ethtool -s ovs-tap1 speed 5000 duplex full])
AT_CHECK([ip link set dev ovs-tap1 up])

AT_CHECK([ovs-vsctl add-port br0 ovs-tap0 -- set int ovs-tap0 type=tap])
AT_CHECK([ovs-vsctl add-port br0 ovs-tap1 -- set int ovs-tap1 type=tap])

dnl Adding a custom qdisc to ovs-tap1, ovs-tap0 will have the default qdisc.
AT_CHECK([tc qdisc add dev ovs-tap1 root noqueue])
AT_CHECK([tc qdisc show dev ovs-tap1 | grep -q noqueue])

dnl Configure the same QoS for both ports:
dnl queue0 uses fixed max-rate.
dnl queue1 relies on underlying link speed.
AT_CHECK([ovs-vsctl dnl
            -- --id=@queue0 create queue dnl
               other_config:min-rate=2000000 other_config:max-rate=3000000 dnl
               other_config:burst=3000000 dnl
            -- --id=@queue1 create queue dnl
               other_config:min-rate=4000000 other_config:burst=4000000 dnl
            -- --id=@qos create qos dnl
               type=linux-htb queues:0=@queue0 dnl
               queues:1=@queue1 -- dnl
            -- set port ovs-tap0 qos=@qos -- set port ovs-tap1 qos=@qos],
         [ignore], [ignore])

dnl Wait for qdiscs to be applied.
OVS_WAIT_UNTIL([tc qdisc show dev ovs-tap0 | grep -q htb])
OVS_WAIT_UNTIL([tc qdisc show dev ovs-tap1 | grep -q htb])

dnl Check the configuration.
m4_define([HTB_CONF0], [rate 2Mbit ceil 3Mbit burst 375000b cburst 375000b])
m4_define([HTB_CONF1], [rate 4Mbit ceil 5Gbit burst 500000b cburst 500000b])
AT_CHECK([tc class show dev ovs-tap0 | grep -q 'class htb .* HTB_CONF0'])
AT_CHECK([tc class show dev ovs-tap0 | grep -q 'class htb .* HTB_CONF1'])
AT_CHECK([tc class show dev ovs-tap1 | grep -q 'class htb .* HTB_CONF0'])
AT_CHECK([tc class show dev ovs-tap1 | grep -q 'class htb .* HTB_CONF1'])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([QoS - 64bit])
OVS_CHECK_TC_QDISC()
AT_SKIP_IF([test $HAVE_TCA_HTB_RATE64 = no])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Configure the QoS with rates that require 64bits, i.e: > 34Gbps.
AT_CHECK([ovs-vsctl set port ovs-p0 qos=@qos -- set port ovs-p1 qos=@qos dnl
            -- --id=@qos create qos dnl
               type=linux-htb other-config:max-rate=50000000000 queues:0=@queue dnl
            -- --id=@queue create queue dnl
               other_config:min-rate=40000000000 other_config:max-rate=50000000000 dnl
               other_config:burst=5000000],
         [ignore], [ignore])

OVS_WAIT_UNTIL([tc qdisc show dev ovs-p0 | grep -q htb])
OVS_WAIT_UNTIL([tc qdisc show dev ovs-p1 | grep -q htb])

m4_define([HTB_CONF], [rate 40Gbit ceil 50Gbit burst 620000b cburst 618750b])
AT_CHECK([tc class show dev ovs-p0 | grep -q 'class htb .* HTB_CONF'])
AT_CHECK([tc class show dev ovs-p1 | grep -q 'class htb .* HTB_CONF'])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([Ingress Policing - 64-bit])
OVS_CHECK_TC_QDISC()
AT_SKIP_IF([test $HAVE_TCA_POLICE_PKTRATE64 = no])
OVS_TRAFFIC_VSWITCHD_START()
ADD_NAMESPACES(ns0)
ADD_VETH(p0, ns0, br0, "10.1.1.1/24")

AT_CHECK([ovs-vsctl set interface ovs-p0 ingress_policing_rate=50000000])
AT_CHECK([ovs-vsctl set interface ovs-p0 ingress_policing_burst=400000])

AT_CHECK([tc -o -s -d filter show dev ovs-p0 ingress |
  sed -n 's/.*\(rate [[0-9]]*[[a-zA-Z]]* burst [[0-9]]*[[a-zA-Z]]*\).*/\1/; T; p; q'],
  [0],[dnl
rate 50Gbit burst 74500000b
])

AT_CHECK([tc -s -d filter show dev ovs-p0 ingress |
            grep -E "basic|matchall" > /dev/null], [0])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([conntrack])

AT_SETUP([conntrack - controller])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg ofproto_dpif_upcall:dbg])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,udp,action=ct(commit),controller
priority=100,in_port=2,ct_state=-trk,udp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk+est,udp,action=controller
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CAPTURE_FILE([ofctl_monitor.log])
AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])

dnl Send an unsolicited reply from port 2. This should be dropped.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 ct\(table=0\) '50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000'])

dnl OK, now start a new connection from port 1.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 1 ct\(commit\),controller '50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000'])

dnl Now try a reply from port 2.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 ct\(table=0\) '50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000'])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

dnl Check this output. We only see the latter two packets, not the first.
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN2 (xid=0x0): total_len=42 in_port=1 (via action) data_len=42 (unbuffered)
udp,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=1,tp_dst=2 udp_csum:0
NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=42 ct_state=est|rpl|trk,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ip,in_port=2 (via action) data_len=42 (unbuffered)
udp,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=2,tp_dst=1 udp_csum:0
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - force commit])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg ofproto_dpif_upcall:dbg])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,udp,action=ct(force,commit),controller
priority=100,in_port=2,ct_state=-trk,udp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk+est,udp,action=ct(force,commit,table=1)
table=1,in_port=2,ct_state=+trk,udp,action=controller
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CAPTURE_FILE([ofctl_monitor.log])
AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])

dnl Send an unsolicited reply from port 2. This should be dropped.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])

dnl OK, now start a new connection from port 1.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

dnl Now try a reply from port 2.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl revalidator/purge], [0])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

dnl Check this output. We only see the latter two packets, not the first.
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=42 in_port=1 (via action) data_len=42 (unbuffered)
udp,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=1,tp_dst=2 udp_csum:0
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=42 ct_state=new|trk,ct_nw_src=10.1.1.2,ct_nw_dst=10.1.1.1,ct_nw_proto=17,ct_tp_src=2,ct_tp_dst=1,ip,in_port=2 (via action) data_len=42 (unbuffered)
udp,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=2,tp_dst=1 udp_csum:0
])

dnl
dnl Check that the directionality has been changed by force commit.
dnl
AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.2,"], [], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2)
])

dnl OK, now send another packet from port 1 and see that it switches again
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-appctl revalidator/purge], [0])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1,"], [], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ct flush])
CHECK_CONNTRACK()
CHECK_CONNTRACK_SCTP()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,ip,action=ct(commit,exec(set_field:0xaa->ct_mark)),2
priority=100,in_port=2,ip,action=ct(zone=5,commit,exec(set_field:0xaa00000000->ct_label)),1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
dp=$(ovs-appctl dpctl/dump-dps)

m4_foreach([FLUSH_CMD], [[ovs-appctl dpctl/flush-conntrack],
                         [ovs-appctl dpctl/flush-conntrack $dp],
                         [ovs-ofctl ct-flush br0]], [
AS_BOX([Testing with FLUSH_CMD])

dnl Test UDP from port 1
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1,"], [], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
])

AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.2,ct_nw_dst=10.1.1.1,ct_nw_proto=17,ct_tp_src=2,ct_tp_dst=1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1,"], [1])


dnl Test UDP from port 2
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.2,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD zone=5 'ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0])

dnl Test ICMP traffic
NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -W 2 10.1.1.1 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.2,"], [0], [stdout])
AT_CHECK([cat stdout | FORMAT_CT(10.1.1.1)], [0],[dnl
icmp,orig=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=8,code=0),reply=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=0,code=0),zone=5,labels=0xaa00000000
])

ICMP_ID=`cat stdout | cut -d ',' -f4 | cut -d '=' -f2`
ICMP_TUPLE=ct_nw_src=10.1.1.2,ct_nw_dst=10.1.1.1,ct_nw_proto=1,icmp_id=$ICMP_ID,icmp_type=8,icmp_code=0
AT_CHECK([FLUSH_CMD zone=5 $ICMP_TUPLE])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.2,"], [1], [dnl
])

dnl Test UDP from port 1 and 2, partial flush by src port
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_src=1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_src=2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test UDP from port 1 and 2, partial flush by dst port
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_dst=2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_dst=1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test UDP from port 1 and 2, partial flush by src address
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test UDP from port 1 and 2, partial flush by dst address
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_dst=10.1.1.2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_dst=10.1.1.1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test UDP from port 1 and 2, partial flush by src address in reply direction
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD '' 'ct_nw_src=10.1.1.2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD zone=5 '' 'ct_nw_src=10.1.1.1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test UDP from port 1 and 2, flush without arguments
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test SCTP flush based on port.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500003400010000408464410a0101010a01010200010002000000009178f7d30100001470e18ccc00000000000a000a00000000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000950540000000a08004500003400010000408464410a0101020a010101000200010000000098f29e470100001470e18ccc00000000000a000a00000000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sed "s/,protoinfo=.*$//" | sort], [0], [dnl
sctp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
sctp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.1,ct_nw_proto=132,ct_tp_src=1,ct_tp_dst=2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sed "s/,protoinfo=.*$//" | sort], [0], [dnl
sctp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.2,ct_nw_proto=132,ct_tp_src=2,ct_tp_dst=1'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test UDP from port 1 and 2, partial flush by mark and labels.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD mark=0xaa])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD labels=0xaa00000000])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD mark=2/2])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD labels=0x0200000000/0x0200000000])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])

dnl Test flush with invalid arguments.

AT_CHECK([FLUSH_CMD zone=invalid 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1'], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "failed to parse zone" stderr])

AT_CHECK([FLUSH_CMD zone=1 'ct_nw_src=10.1.1.1,invalid=invalid' 'ct_nw_dst=10.1.1.1'], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "invalid conntrack tuple field: invalid" stderr])

AT_CHECK([FLUSH_CMD zone=1 'ct_nw_src=invalid' 'ct_nw_dst=10.1.1.1'], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "failed to parse field ct_nw_src" stderr])

AT_CHECK([FLUSH_CMD zone=1 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "invalid arguments" stderr])

AT_CHECK([FLUSH_CMD zone=1 mark=1 labels=1 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid invalid], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "command takes at most 6 arguments" stderr])

AT_CHECK([FLUSH_CMD mark=invalid], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "failed to parse mark" stderr])

AT_CHECK([FLUSH_CMD labels=invalid], [ignore], [ignore], [stderr])
AT_CHECK([grep -q "failed to parse labels" stderr])

dnl Test UDP from port 1 and 2, partial flush by zone.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])


AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD zone=5])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
])

AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])

AT_CHECK([FLUSH_CMD zone=0])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [0], [dnl
udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
])

AT_CHECK([FLUSH_CMD])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1,"], [1])
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 ping])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,icmp,action=ct(commit),2
priority=100,in_port=2,icmp,ct_state=-trk,action=ct(table=0)
priority=100,in_port=2,icmp,ct_state=+trk+est,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Pings from ns0->ns1 should work fine.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0)
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack 'ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
])

dnl Pings from ns1->ns0 should fail.
NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | FORMAT_PING], [0], [dnl
7 packets transmitted, 0 received, 100% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - get_nconns and get/set_maxconns])
CHECK_CONNTRACK()
CHECK_CT_DPIF_SET_GET_MAXCONNS()
CHECK_CT_DPIF_GET_NCONNS()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,icmp,action=ct(commit),2
priority=100,in_port=2,icmp,ct_state=-trk,action=ct(table=0)
priority=100,in_port=2,icmp,ct_state=+trk+est,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Pings from ns0->ns1 should work fine.
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0)
])

AT_CHECK([ovs-appctl dpctl/ct-set-maxconns one-bad-dp], [2], [], [dnl
ovs-vswitchd: maxconns missing or malformed (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-set-maxconns a], [2], [], [dnl
ovs-vswitchd: maxconns missing or malformed (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-set-maxconns one-bad-dp 10], [2], [], [dnl
ovs-vswitchd: datapath not found (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-get-maxconns one-bad-dp], [2], [], [dnl
ovs-vswitchd: datapath not found (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-get-nconns one-bad-dp], [2], [], [dnl
ovs-vswitchd: datapath not found (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-get-nconns], [], [dnl
1
])

AT_CHECK([ovs-appctl dpctl/ct-get-maxconns], [], [dnl
3000000
])

AT_CHECK([ovs-appctl dpctl/ct-set-maxconns 10], [], [dnl
setting maxconns successful
])

AT_CHECK([ovs-appctl dpctl/ct-get-maxconns], [], [dnl
10
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

AT_CHECK([ovs-appctl dpctl/ct-get-nconns], [], [dnl
0
])

AT_CHECK([ovs-appctl dpctl/ct-get-maxconns], [], [dnl
10
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 ping])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

AT_DATA([flows.txt], [dnl

dnl ICMPv6 echo request and reply go to table 1.  The rest of the traffic goes
dnl through normal action.
table=0,priority=10,icmp6,icmp_type=128,action=goto_table:1
table=0,priority=10,icmp6,icmp_type=129,action=goto_table:1
table=0,priority=1,action=normal

dnl Allow everything from ns0->ns1. Only allow return traffic from ns1->ns0.
table=1,priority=100,in_port=1,icmp6,action=ct(commit),2
table=1,priority=100,in_port=2,icmp6,ct_state=-trk,action=ct(table=0)
table=1,priority=100,in_port=2,icmp6,ct_state=+trk+est,action=1
table=1,priority=1,action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

dnl The above ping creates state in the connection tracker.  We're not
dnl interested in that state.
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl Pings from ns1->ns0 should fail.
NS_CHECK_EXEC([at_ns1], [ping6 -q -c 3 -i 0.3 -w 2 fc00::1 | FORMAT_PING], [0], [dnl
7 packets transmitted, 0 received, 100% packet loss, time 0ms
])

dnl Pings from ns0->ns1 should work fine.
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
icmpv6,orig=(src=fc00::1,dst=fc00::2,id=<cleared>,type=128,code=0),reply=(src=fc00::2,dst=fc00::1,id=<cleared>,type=129,code=0)
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack 'ct_ipv6_src=fc00::1,ct_ipv6_dst=fc00::2'])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - preserve registers])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow any traffic from ns0->ns1, ns2->ns3.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(commit,table=0)
priority=100,in_port=1,tcp,ct_state=+trk,action=2
priority=100,in_port=2,tcp,ct_state=-trk,action=ct(table=0)
priority=100,in_port=2,tcp,ct_state=+trk,action=1
priority=100,in_port=3,tcp,ct_state=-trk,action=load:0->NXM_NX_REG0[[]],ct(table=0)
priority=100,in_port=3,tcp,ct_state=+trk,reg0=0,action=load:1->NXM_NX_REG0[[]],ct(commit,table=0)
priority=100,in_port=3,tcp,ct_state=+trk,reg0=1,action=4
priority=100,in_port=4,tcp,ct_state=-trk,action=ct(commit,table=0)
priority=100,in_port=4,tcp,ct_state=+trk,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl HTTP requests from p2->p3 should work fine.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [0], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - invalid])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Pass traffic from ns0->ns1 without committing, but attempt to track in
dnl the opposite direction. This should fail.
dnl Pass traffic from ns3->ns4 without committing, and this time match
dnl invalid traffic and allow it through.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=ct(),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk+new,tcp,action=1
priority=100,in_port=3,tcp,action=ct(),4
priority=100,in_port=4,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=4,ct_state=+trk+inv,tcp,action=3
priority=100,in_port=4,ct_state=+trk+new,tcp,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl We set up our rules to allow the request without committing. The return
dnl traffic can't be identified, because the initial request wasn't committed.
dnl For the first pair of ports, this means that the connection fails.
OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [28], [ignore], [ignore])

dnl For the second pair, we allow packets from invalid connections, so it works.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [0], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - zones])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow any traffic from ns0->ns1. Allow return traffic, matching on zone.
dnl For ns2->ns3, use a different zone and see that the match fails.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=ct(commit,zone=1),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=1)
priority=100,in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
priority=100,in_port=3,tcp,action=ct(commit,zone=2),4
priority=100,in_port=4,ct_state=-trk,tcp,action=ct(table=0,zone=2)
priority=100,in_port=4,ct_state=+trk,ct_zone=1,tcp,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

dnl HTTP requests from p2->p3 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [28], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.4)], [0], [dnl
tcp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.4,dst=10.1.1.3,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - zones from field])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=load:0x1001->NXM_NX_REG0[[0..15]],ct(commit,zone=NXM_NX_REG0[[0..15]]),2
priority=100,in_port=2,ct_state=-trk,tcp,action=load:0x1001->NXM_NX_REG0[[0..15]],ct(table=0,zone=NXM_NX_REG0[[0..15]])
priority=100,in_port=2,ct_state=+trk,ct_zone=0x1001,tcp,action=1
priority=100,in_port=3,tcp,action=load:0x1002->NXM_NX_REG0[[0..15]],ct(commit,zone=NXM_NX_REG0[[0..15]]),4
priority=100,in_port=4,ct_state=-trk,tcp,action=load:0x1002->NXM_NX_REG0[[0..15]],ct(table=0,zone=NXM_NX_REG0[[0..15]])
priority=100,in_port=4,ct_state=+trk,ct_zone=0x1001,tcp,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=4097,protoinfo=(state=<cleared>)
])

dnl HTTP requests from p2->p3 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [28], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.4)], [0], [dnl
tcp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.4,dst=10.1.1.3,sport=<cleared>,dport=<cleared>),zone=4098,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - zones from other field])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(zone=5,table=0)
priority=100,in_port=1,tcp,ct_state=+trk,action=ct(commit,zone=NXM_NX_CT_ZONE[]),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=5)
priority=100,in_port=2,ct_state=+trk,ct_zone=5,tcp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,dnl
orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),dnl
reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),dnl
zone=5,protoinfo=(state=<cleared>)
])

dnl This is to test when the zoneid is set by a field variable like
dnl NXM_NX_CT_ZONE, the OVS xlate should generate a megaflow with a form of
dnl "ct_zone(5), ...  actions: ct(commit, zone=5)".  The match "ct_zone(5)"
dnl is needed as if we changes the zoneid into 15 in the following, the old
dnl "ct_zone(5), ... actions: ct(commit, zone=5)" megaflow will not get hit,
dnl and OVS will generate a new megaflow with the match "ct_zone(0xf)".
dnl This will make sure that the new packets are committing to zoneid 15
dnl rather than old 5.
AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
              | grep "+trk" | grep -q "ct_zone(0x5)" ], [0], [])

AT_CHECK([ovs-ofctl mod-flows br0 dnl
            'priority=100,ct_state=-trk,tcp,in_port="ovs-p0" actions=ct(table=0,zone=15)'])

dnl Wait for a flow flush as some datapaths (read TC) might take time to clear.
AT_CHECK([ovs-appctl revalidator/wait], [0])

NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
              | grep "+trk" | grep -q "ct_zone(0xf)" ], [0], [])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - zones from other field, more tests])
CHECK_CONNTRACK()
OVS_CHECK_GITHUB_ACTION()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(zone=5,table=0,commit,exec(load:0xffff0005->NXM_NX_CT_LABEL[[0..31]]))
priority=100,in_port=1,tcp,ct_state=+trk,action=ct(commit,zone=NXM_NX_CT_LABEL[[0..15]]),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=5)
priority=100,in_port=2,ct_state=+trk,ct_zone=5,tcp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,dnl
orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),dnl
reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),dnl
zone=5,labels=0xffff0005,protoinfo=(state=<cleared>)
])

AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
              | grep "+trk" | sed 's/0xffff0005\/0xffff/0x5\/0xffff/' dnl
              | grep -q "ct_label(0x5/0xffff)" ], [0], [])

AT_CHECK([ovs-ofctl mod-flows br0 'priority=100,ct_state=-trk,tcp,in_port="ovs-p0" actions=ct(table=0,zone=15,commit,exec(load:0xffff000f->NXM_NX_CT_LABEL[[0..31]]))'])

dnl Wait for a flow flush as some datapaths (read TC) might take time to clear.
AT_CHECK([ovs-appctl revalidator/wait], [0])

NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
              | grep "+trk" | sed 's/0xffff000f\/0xffff/0xf\/0xffff/' dnl
              | grep -q "ct_label(0xf/0xffff)" ], [0], [])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - multiple bridges])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START(
   [_ADD_BR([br1]) --\
    add-port br0 patch+ -- set int patch+ type=patch options:peer=patch- --\
    add-port br1 patch- -- set int patch- type=patch options:peer=patch+ --])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")

dnl Allow any traffic from ns0->br1, allow established in reverse.
AT_DATA([flows-br0.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=2,tcp,ct_state=-trk,action=ct(commit,zone=1),1
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(table=0,zone=1)
priority=100,in_port=1,tcp,ct_state=+trk+est,ct_zone=1,action=2
])

dnl Allow any traffic from br0->ns1, allow established in reverse.
AT_DATA([flows-br1.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(table=0,zone=2)
priority=100,in_port=1,tcp,ct_state=+trk+new,ct_zone=2,action=ct(commit,zone=2),2
priority=100,in_port=1,tcp,ct_state=+trk+est,ct_zone=2,action=2
priority=100,in_port=2,tcp,ct_state=-trk,action=ct(table=0,zone=2)
priority=100,in_port=2,tcp,ct_state=+trk+est,ct_zone=2,action=ct(commit,zone=2),1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
AT_CHECK([ovs-ofctl --bundle add-flows br1 flows-br1.txt])

dnl HTTP requests from p0->p1 should work fine.
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - multiple zones])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=ct(commit,zone=1),ct(commit,zone=2),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=2)
priority=100,in_port=2,ct_state=+trk,ct_zone=2,tcp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl (again) HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - multiple namespaces, internal ports])
CHECK_CONNTRACK()
CHECK_CONNTRACK_LOCAL_STACK()
CHECK_NO_TC_OFFLOAD()
OVS_TRAFFIC_VSWITCHD_START(
   [set-fail-mode br0 secure -- ])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_INT(p0, at_ns0, br0, "10.1.1.1/24")
ADD_INT(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
dnl
dnl If skb->nfct is leaking from inside the namespace, this test will fail.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(commit,zone=1),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=1)
priority=100,in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl (again) HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP(["dnl
/ioctl(SIOCGIFINDEX) on .* device failed: No such device/d
/removing policing failed: No such device/d"])
AT_CLEANUP

AT_SETUP([conntrack - ct_mark])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow traffic between ns0<->ns1 using the ct_mark.
dnl Check that different marks do not match for traffic between ns2<->ns3.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=ct(commit,exec(set_field:1->ct_mark)),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk,ct_mark=1,tcp,action=1
priority=100,in_port=3,tcp,action=ct(commit,exec(set_field:2->ct_mark)),4
priority=100,in_port=4,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=4,ct_state=+trk,ct_mark=1,tcp,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),mark=1,protoinfo=(state=<cleared>)
])

dnl HTTP requests from p2->p3 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.4)], [0], [dnl
tcp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.4,dst=10.1.1.3,sport=<cleared>,dport=<cleared>),mark=2,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ct_mark bit-fiddling])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow traffic between ns0<->ns1 using the ct_mark. Return traffic should
dnl cause an additional bit to be set in the connection (and be allowed).
AT_DATA([flows.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(table=1)
table=0,priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=1,commit,exec(set_field:0x2/0x6->ct_mark))
table=1,in_port=1,ct_state=+new,tcp,action=ct(commit,exec(set_field:0x5/0x5->ct_mark)),2
table=1,in_port=1,ct_state=-new,tcp,action=2
table=1,in_port=2,ct_state=+trk,ct_mark=3,tcp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),mark=3,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ct_mark from register])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=load:1->NXM_NX_REG0[[0..31]],ct(commit,exec(move:NXM_NX_REG0[[0..31]]->NXM_NX_CT_MARK[[]])),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk,ct_mark=1,tcp,action=1
priority=100,in_port=3,tcp,action=load:2->NXM_NX_REG0[[0..31]],ct(commit,exec(move:NXM_NX_REG0[[0..31]]->NXM_NX_CT_MARK[[]])),4
priority=100,in_port=4,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=4,ct_state=+trk,ct_mark=1,tcp,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),mark=1,protoinfo=(state=<cleared>)
])

dnl HTTP requests from p2->p3 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.4)], [0], [dnl
tcp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.4,dst=10.1.1.3,sport=<cleared>,dport=<cleared>),mark=2,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ct_label])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow traffic between ns0<->ns1 using the ct_label.
dnl Check that different labels do not match for traffic between ns2<->ns3.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=ct(commit,exec(set_field:0x0a000d000005000001->ct_label)),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk,ct_label=0x0a000d000005000001,tcp,action=1
priority=100,in_port=3,tcp,action=ct(commit,exec(set_field:0x2->ct_label)),4
priority=100,in_port=4,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=4,ct_state=+trk,ct_label=0x0a000d000005000001,tcp,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl HTTP requests from p2->p3 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [28], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ct_label bit-fiddling])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow traffic between ns0<->ns1 using the ct_labels. Return traffic should
dnl cause an additional bit to be set in the connection labels (and be allowed)
AT_DATA([flows.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(table=1)
table=0,priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=1,commit,exec(set_field:0x200000000/0x200000004->ct_label))
table=1,in_port=1,tcp,ct_state=+new,action=ct(commit,exec(set_field:0x5/0x5->ct_label)),2
table=1,in_port=1,tcp,ct_state=-new,action=2
table=1,in_port=2,ct_state=+trk,ct_label=0x200000001,tcp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),labels=0x200000001,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ct metadata, multiple zones])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow traffic between ns0<->ns1 using the ct_mark and ct_labels in zone=1,
dnl but do *not* set any of these for the ct() in zone=2. Traffic should pass,
dnl and we should see that the conntrack entries only apply the ct_mark and
dnl ct_labels to the connection in zone=1.
AT_DATA([flows.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(zone=1,table=1)
table=0,priority=100,in_port=2,ct_state=-trk,tcp,action=ct(zone=1,table=1,commit,exec(set_field:0x200000000/0x200000004->ct_label,set_field:0x2/0x6->ct_mark))
table=1,in_port=1,tcp,ct_state=+new,action=ct(zone=1,commit,exec(set_field:0x5/0x5->ct_label,set_field:0x5/0x5->ct_mark)),ct(commit,zone=2),2
table=1,in_port=1,tcp,ct_state=-new,action=ct(zone=2),2
table=1,in_port=2,tcp,action=ct(zone=2),1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,mark=3,labels=0x200000001,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - new connections])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows1.txt], [dnl
table=0, priority=1,action=drop
table=0, priority=10,arp,action=normal
table=0, priority=100,tcp,action=ct(table=1)
table=0, priority=100,udp,action=ct(table=1)
table=1, priority=100,in_port=1,tcp,ct_state=+trk+new,action=ct(commit)
table=1, priority=100,in_port=1,udp,ct_state=+trk+new,action=ct(commit)
table=1, priority=100,in_port=1,ct_state=+trk+est,action=2
table=1, priority=100,in_port=2,ct_state=+trk+est,action=1
])

ovs-appctl vlog/set dbg

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows1.txt])

dnl TCP traffic from ns0 to ns1 should fail.
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [28], [ignore], [ignore])

dnl Send UDP packet on port 1 twice.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

dnl There should not be any packet that matches the established ct_state.
AT_CHECK([ovs-ofctl dump-flows br0 "table=1 in_port=1,ct_state=+trk+est" | ofctl_strip], [0], [dnl
NXST_FLOW reply:
 table=1, priority=100,ct_state=+est+trk,in_port=1 actions=output:2
])

dnl Send a 3rd UDP packet on port 1
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

dnl There still should not be any packet that matches the established ct_state.
AT_CHECK([ovs-ofctl dump-flows br0 "table=1 in_port=1,ct_state=+trk+est" | ofctl_strip], [0], [dnl
NXST_FLOW reply:
 table=1, priority=100,ct_state=+est+trk,in_port=1 actions=output:2
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - generic IP protocol])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg ofproto_dpif_upcall:dbg])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
table=0, priority=1,action=drop
table=0, priority=10,arp,action=normal
table=0, priority=100,ip,action=ct(table=1)
table=1, priority=100,in_port=1,ip,ct_state=+trk+new,action=ct(commit)
table=1, priority=100,in_port=1,ct_state=+trk+est,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=01005e00001200005e000101080045c0002800000000ff7019cdc0a8001ee0000012210164010001ba52c0a800010000000000000000000000000000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=192\.168\.0\.30,"], [], [dnl
112,orig=(src=192.168.0.30,dst=224.0.0.18,sport=0,dport=0),reply=(src=224.0.0.18,dst=192.168.0.30,sport=0,dport=0)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP related])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow UDP traffic from ns0->ns1. Only allow related ICMP responses back.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,udp,action=ct(commit,exec(set_field:1->ct_mark)),2
priority=100,in_port=2,icmp,ct_state=-trk,action=ct(table=0)
priority=100,in_port=2,icmp,ct_state=+trk+rel,ct_mark=1,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response.
NS_CHECK_EXEC([at_ns0], [echo a | nc $NC_EOF_OPT -u 10.1.1.2 10000])

AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort | grep -v drop], [0], [dnl
 n_packets=1, n_bytes=44, priority=100,udp,in_port=1 actions=ct(commit,exec(load:0x1->NXM_NX_CT_MARK[[]])),output:2
 n_packets=1, n_bytes=72, priority=100,ct_state=+rel+trk,ct_mark=0x1,icmp,in_port=2 actions=output:1
 n_packets=1, n_bytes=72, priority=100,ct_state=-trk,icmp,in_port=2 actions=ct(table=0)
 n_packets=2, n_bytes=84, priority=10,arp actions=NORMAL
NXST_FLOW reply:
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP related to original direction])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow UDP traffic from ns0->ns1. Only allow related ICMP responses back.
AT_DATA([flows.txt], [dnl
priority=1000,arp,action=normal
priority=100,ip,action=ct(table=1)
priority=1,action=drop
table=1,ip,action=ct(zone=34673,table=2)
table=2,in_port=2,udp,action=ct(commit,zone=34673),1
table=2,in_port=1,udp,action=ct(commit,zone=34673),2
table=2,in_port=2,ct_state=+rel,icmp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl 1. Send and UDP packet to port 53 (src=192.100.1.8,dst=192.100.2.5)
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 resubmit\(,0\) '00010200020400232211223308004500001c000100004011f6fac0640108c06402050035003500087b9e'])

dnl 2. Send and UDP packet to port 53 (src=192.100.2.5,dst=192.100.1.8)
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 1 resubmit\(,0\) '00232211223300010200020408004500001c000100004011f6fac0640205c06401080035003500087b9e'])

dnl 3. Send an ICMP port unreach reply for port 53, related to the 2nd
dnl packet, but in the original direction of the conntrack entry created
dnl for the 1st packet.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 resubmit\(,0\) '000102000204002322112233080045000038000100003f01f7eec0640108c0640205030a80e5ffffffff4500001c000100003f11f7fac0640205c06401080035003500087b9e'])

AT_CHECK([ovs-appctl revalidator/purge], [0])

dnl 4. Repeat 3.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 resubmit\(,0\) '000102000204002322112233080045000038000100003f01f7eec0640108c0640205030a80e5ffffffff4500001c000100003f11f7fac0640205c06401080035003500087b9e'])

AT_CHECK([ovs-appctl revalidator/purge], [0])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort | grep -v drop], [0], [dnl
 n_packets=4, n_bytes=224, priority=100,ip actions=ct(table=1)
 priority=1000,arp actions=NORMAL
 table=1, n_packets=4, n_bytes=224, ip actions=ct(table=2,zone=34673)
 table=2, n_packets=1, n_bytes=42, udp,in_port=1 actions=ct(commit,zone=34673),output:2
 table=2, n_packets=1, n_bytes=42, udp,in_port=2 actions=ct(commit,zone=34673),output:1
 table=2, n_packets=2, n_bytes=140, ct_state=+rel,icmp,in_port=2 actions=output:1
NXST_FLOW reply:
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.100.1.8)], [0], [dnl
udp,orig=(src=192.100.1.8,dst=192.100.2.5,sport=<cleared>,dport=<cleared>),reply=(src=192.100.2.5,dst=192.100.1.8,sport=<cleared>,dport=<cleared>),zone=34673
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP related 2])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "172.16.0.1/24")
ADD_VETH(p1, at_ns1, br0, "172.16.0.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
table=0,ip,action=ct(commit,table=1)
table=1,ip,action=controller
])

AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows.txt])

AT_CAPTURE_FILE([ofctl_monitor.log])
AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])

dnl 1. Send an ICMP port unreach reply for port 8738, without any previous request
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 resubmit\(,0\) 'f64c473528c9c6f54ecb72db080045c0003d2e8700004001f351ac100004ac1000030303da490000000045000021317040004011b138ac100003ac10000411112222000d20966369616f0a'])

dnl 2. Send and UDP packet to port 5555
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 1 resubmit\(,0\) 'c6f94ecb72dbe64c473528c9080045000021317040004011b138ac100001ac100002a28e15b3000d20966369616f0a'])

dnl 3. Send an ICMP port unreach reply from a path midpoint for port 5555, related to the first packet
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 resubmit\(,0\) 'e64c473528c9c6f94ecb72db080045c0003d2e8700004001f354ac100003ac1000010303553f0000000045000021317040004011b138ac100001ac100002a28e15b3000d20966369616f0a'])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

dnl Check this output. We only see the latter two packets, not the first.
AT_CHECK([cat ofctl_monitor.log | grep -v ff02 | grep -v fe80 | grep -v no_match], [0], [dnl
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=75 ct_state=inv|trk,ip,in_port=2 (via action) data_len=75 (unbuffered)
icmp,vlan_tci=0x0000,dl_src=c6:f5:4e:cb:72:db,dl_dst=f6:4c:47:35:28:c9,nw_src=172.16.0.4,nw_dst=172.16.0.3,nw_tos=192,nw_ecn=0,nw_ttl=64,nw_frag=no,icmp_type=3,icmp_code=3 icmp_csum:da49
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=47 ct_state=new|trk,ct_nw_src=172.16.0.1,ct_nw_dst=172.16.0.2,ct_nw_proto=17,ct_tp_src=41614,ct_tp_dst=5555,ip,in_port=1 (via action) data_len=47 (unbuffered)
udp,vlan_tci=0x0000,dl_src=e6:4c:47:35:28:c9,dl_dst=c6:f9:4e:cb:72:db,nw_src=172.16.0.1,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,tp_src=41614,tp_dst=5555 udp_csum:2096
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=75 ct_state=rel|rpl|trk,ct_nw_src=172.16.0.1,ct_nw_dst=172.16.0.2,ct_nw_proto=17,ct_tp_src=41614,ct_tp_dst=5555,ip,in_port=2 (via action) data_len=75 (unbuffered)
icmp,vlan_tci=0x0000,dl_src=c6:f9:4e:cb:72:db,dl_dst=e6:4c:47:35:28:c9,nw_src=172.16.0.3,nw_dst=172.16.0.1,nw_tos=192,nw_ecn=0,nw_ttl=64,nw_frag=no,icmp_type=3,icmp_code=3 icmp_csum:553f
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1)], [0], [dnl
udp,orig=(src=172.16.0.1,dst=172.16.0.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>)
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.3)], [0], [dnl
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP related NAT with single port])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")

AT_DATA([flows.txt], [dnl
table=0,ip,ct_state=-trk,actions=ct(table=0,nat)
table=0,in_port=ovs-p0,ct_state=+trk+new,udp,actions=ct(commit,nat(dst=10.1.1.2:8080)),ovs-p1
table=0,in_port=ovs-p1,ct_state=+trk+rel+rpl,icmp,actions=ovs-p0
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

rm p0.pcap
NETNS_DAEMONIZE([at_ns0], [tcpdump -n -l -U -i p0 -w p0.pcap 2> tcpdump0_err], [tcpdump0.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump0_err])

dnl Send UDP packet from 10.1.1.1:1234 to 10.1.1.240:80
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-p0,packet=f00000010102f0000001010108004500002944c140004011df100a0101010a0101f004d2005000156b24646573745f756e72656163680a,actions=resubmit(,0)"])
dnl Send "destination unreachable" response
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-p1,packet=f00000010101f00000010102080045c000456a3700004001f9bc0a0101020a01010103031328000000004500002944c140004011dffe0a0101010a01010204d21f9000154cd2646573745f756e72656163680a,actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1," | sort], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.240,sport=1234,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=8080,dport=1234)
])

OVS_WAIT_UNTIL([ovs-pcap p0.pcap | grep -q "f00000010101f00000010102080045c000456a3700004001f8ce0a0101f00a01010103031416000000004500002944c140004011df100a0101010a0101f004d2005000156b24646573745f756e72656163680a"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,icmp,action=ct(commit,zone=9),2
priority=100,in_port=2,ct_state=-trk,icmp,action=ct(table=0,zone=9)
priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Modify userspace conntrack fragmentation handling.
DPCTL_MODIFY_FRAGMENTATION()

dnl Ipv4 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv4 larger fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Check userspace conntrack fragmentation counters.
DPCTL_CHECK_FRAGMENTATION_PASS()

dnl Ipv4 max packet size fragmentation dropped.
NS_EXEC([at_ns0], [ping -s 65507 -q -c 1 -W 0.5 10.1.1.2])
OVS_CHECK_FRAG_LARGE()

OVS_TRAFFIC_VSWITCHD_STOP(["/Unsupported big reassembled v4 packet/d"])
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation with ct orig match])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,ip,ct_state=-trk,action=ct(table=0)
priority=100,in_port=2,icmp,ct_state=+rpl,action=1
priority=100,in_port=1,ip,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ct_state=+new+trk,action=ct(commit)
priority=100,in_port=1,ip,ct_nw_proto=1,ct_tp_src=8,ct_tp_dst=0,ct_state=+new+trk,action=ct(commit),2
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Packet content:
dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
dnl       Type: IPv4 (0x0800)
dnl   Internet Protocol Version 4, Src: 10.1.1.1, Dst: 10.1.1.2
dnl       Total Length: 1420
dnl       Identification: 0x0001 (1)
dnl       001. .... = Flags: 0x1, More fragments
dnl           0... .... = Reserved bit: Not set
dnl           .0.. .... = Don't fragment: Not set
dnl           ..1. .... = More fragments: Set
dnl       ...0 0000 0000 0000 = Fragment Offset: 0
dnl       Time to Live: 64
dnl       Protocol: UDP (17)
dnl   User Datagram Protocol, Src Port: 1, Dst Port: 2
dnl       Source Port: 1
dnl       Destination Port: 2
dnl       Length: 1608
dnl       UDP payload (1392 bytes)
dnl   Data (1392 bytes)
eth="50 54 00 00 00 09 50 54 00 00 00 0a 08 00"
ip="45 00 05 8c 00 01 20 00 40 11 3f 5c 0a 01 01 01 0a 01 01 02"
udp="00 01 00 02 06 48 dd 56"
data_len=$(seq 1392)
data=$(printf '00 %.0s' ${data_len})
packet="${eth} ${ip} ${udp} ${data}"
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])

dnl Packet content:
dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
dnl       Type: IPv4 (0x0800)
dnl   Internet Protocol Version 4, Src: 10.1.1.1, Dst: 10.1.1.2
dnl       0100 .... = Version: 4
dnl       .... 0101 = Header Length: 20 bytes (5)
dnl       Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
dnl           0000 00.. = Differentiated Services Codepoint: Default (0)
dnl           .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
dnl       Total Length: 228
dnl       Identification: 0x0001 (1)
dnl       000. .... = Flags: 0x0
dnl           0... .... = Reserved bit: Not set
dnl           .0.. .... = Don't fragment: Not set
dnl           ..0. .... = More fragments: Not set
dnl       ...0 0000 1010 1111 = Fragment Offset: 1400
dnl       Time to Live: 64
dnl       Protocol: UDP (17)
dnl   Data (208 bytes)
eth="50 54 00 00 00 09 50 54 00 00 00 0a 08 00"
ip="45 00 00 e4 00 01 00 af 40 11 63 55 0a 01 01 01 0a 01 01 02"
data_len=$(seq 208)
data=$(printf '00 %.0s' ${data_len})
packet="${eth} ${ip} ${data}"
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])

NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 1 -W 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0)
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation expiry])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal

dnl Only allow non-fragmented messages and 1st fragments of each message
priority=100,in_port=1,icmp,ip_frag=no,action=ct(commit,zone=9),2
priority=100,in_port=1,icmp,ip_frag=first,action=ct(commit,zone=9),2
priority=100,in_port=2,ct_state=-trk,icmp,action=ct(table=0,zone=9)
priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Modify userspace conntrack fragmentation handling.
DPCTL_MODIFY_FRAGMENTATION()

dnl Ipv4 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 1 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
7 packets transmitted, 0 received, 100% packet loss, time 0ms
])

dnl Check userspace conntrack fragmentation counters.
DPCTL_CHECK_FRAGMENTATION_FAIL()

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation + vlan])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VLAN(p0, at_ns0, 100, "10.2.2.1/24")
ADD_VLAN(p1, at_ns1, 100, "10.2.2.2/24")

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,icmp,action=ct(commit,zone=9),2
priority=100,in_port=2,ct_state=-trk,icmp,action=ct(table=0,zone=9)
priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Modify userspace conntrack fragmentation handling.
DPCTL_MODIFY_FRAGMENTATION()

dnl Ipv4 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv4 larger fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Check userspace conntrack fragmentation counters.
DPCTL_CHECK_FRAGMENTATION_PASS()

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation + cvlan])
CHECK_CONNTRACK()
CHECK_NO_TC_OFFLOAD()
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

ADD_SVLAN(p0, at_ns0, 4094, "10.255.2.1/24")
ADD_SVLAN(p1, at_ns1, 4094, "10.255.2.2/24")

ADD_CVLAN(p0.4094, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p1.4094, at_ns1, 100, "10.2.2.2/24")

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,icmp,action=ct(commit,zone=9),2
priority=100,in_port=2,ct_state=-trk,icmp,action=ct(table=0,zone=9)
priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])

dnl Ipv4 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv4 fragmentation connectivity check. (outer svlan)
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.255.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv4 larger fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv4 larger fragmentation connectivity check. (outer svlan)
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.255.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation incomplete reassembled packet])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()


ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([bundle.txt], [dnl
packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809,  actions=ct(commit)
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
])

dnl Send the second fragment in order to avoid keeping the first fragment
dnl in the queue until the expiration occurs. Fragments already queued, if resent,
dnl may lead to failures on the kernel datapath.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1, packet=50540000000a505400000009080045000030000100320011a4860a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit)"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

dnl Uses same first fragment as above 'incomplete reassembled packet' test.
AT_SETUP([conntrack - IPv4 fragmentation with fragments specified])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([bundle.txt], [dnl
packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809,  actions=ct(commit)
packet-out in_port=1, packet=50540000000a505400000009080045000030000100320011a4860a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit)
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation out of order])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([bundle.txt], [dnl
packet-out in_port=1, packet=50540000000a505400000009080045000030000100320011a4860a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit)
packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809,  actions=ct(commit)
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet])
CHECK_CONNTRACK()
CHECK_CONNTRACK_FRAG_OVERLAP()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([bundle.txt], [dnl
packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809,  actions=ct(commit)
packet-out in_port=1, packet=50540000000a505400000009080045000030000100310011a4870a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit)
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])
dnl There is one byte of overlap, hence no packet gets thru. conntrack.
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet out of order])
CHECK_CONNTRACK()
CHECK_CONNTRACK_FRAG_OVERLAP()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([bundle.txt], [dnl
packet-out in_port=1, packet=50540000000a505400000009080045000030000100310011a4870a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit)
packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809,  actions=ct(commit)
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])
dnl There is one byte of overlap, hence no packet gets thru. conntrack.
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,in_port=1,ipv6,action=ct(commit,zone=9),2
priority=10,in_port=2,ct_state=-trk,ipv6,action=ct(table=0,zone=9)
priority=10,in_port=2,ct_state=+trk+est-new,ipv6,action=1
priority=100,icmp6,icmp_type=135,action=normal
priority=100,icmp6,icmp_type=136,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

dnl Ipv6 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv6 larger fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv6 max packet size fragmentation dropped.
NS_EXEC([at_ns0], [ping6 -s 65487 -q -c 1 -W 0.5 fc00::2])
OVS_CHECK_FRAG_LARGE()

OVS_TRAFFIC_VSWITCHD_STOP(["/Unsupported big reassembled v6 packet/d"])
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation with ct orig match])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96", "50:54:00:00:00:09", [], "nodad")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", "50:54:00:00:00:0a", [], "nodad")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,ipv6,ct_state=-trk,action=ct(table=0)
priority=10,in_port=2,ipv6,ct_tp_src=128,ct_state=+trk+est+rpl,action=1
priority=10,in_port=1,ipv6,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ct_state=+new+trk,action=ct(commit)
priority=10,in_port=1,ipv6,ct_nw_proto=58,ct_tp_src=128,ct_tp_dst=0,ct_state=+new+trk,action=ct(commit),2
priority=100,icmp6,icmp_type=135,action=normal
priority=100,icmp6,icmp_type=136,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Packet content:
dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
dnl       Type: IPv6 (0x86dd)
dnl   Internet Protocol Version 6, Src: fc00::1, Dst: fc00::2
dnl       Payload Length: 1344
dnl       Next Header: Fragment Header for IPv6 (44)
dnl       Hop Limit: 64
dnl       Fragment Header for IPv6
dnl           Next header: UDP (17)
dnl           Reserved octet: 0x00
dnl           0000 0000 0000 0... = Offset: 0 (0 bytes)
dnl           .... .... .... .00. = Reserved bits: 0
dnl           .... .... .... ...1 = More Fragments: Yes
dnl           Identification: 0x9bdb1fa7
dnl   User Datagram Protocol, Src Port: 1, Dst Port: 2
dnl       Source Port: 1
dnl       Destination Port: 2
dnl       Length: 1608
dnl       UDP payload (1328 bytes)
dnl   Data (1328 bytes)
eth="50 54 00 00 00 09 50 54 00 00 00 0a 86 dd"
ipv6="60 00 00 00 05 40 2c 40 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 \
      fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 11 00 00 01 9b db 1f a7"
udp="00 01 00 02 06 48 fb 56"
data_len=$(seq 1328)
data=$(printf '00 %.0s' ${data_len})
packet="${eth} ${ipv6} ${udp} ${data}"
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])

dnl IPv6 Packet content
dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
dnl       Type: IPv6 (0x86dd)
dnl   Internet Protocol Version 6, Src: fc00::1, Dst: fc00::2
dnl       Payload Length: 280
dnl       Next Header: Fragment Header for IPv6 (44)
dnl       Hop Limit: 64
dnl       Fragment Header for IPv6
dnl           Next header: UDP (17)
dnl           Reserved octet: 0x00
dnl           0000 0101 0011 1... = Offset: 167 (1336 bytes)
dnl           .... .... .... .00. = Reserved bits: 0
dnl           .... .... .... ...0 = More Fragments: No
dnl           Identification: 0x9bdb1fa7
dnl   Data (272 bytes)
eth="50 54 00 00 00 09 50 54 00 00 00 0a 86 dd"
ipv6="60 00 00 00 01 18 2c 40 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 \
      fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 11 00 05 38 9b db 1f a7"
data_len=$(seq 272)
data=$(printf '00 %.0s' ${data_len})
packet="${eth} ${ipv6} ${data}"
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])

dnl Send also fragmented ICMPv6.
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 1 -W 1 fc00::2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2) | sort], [0], [dnl
icmpv6,orig=(src=fc00::1,dst=fc00::2,id=<cleared>,type=128,code=0),reply=(src=fc00::2,dst=fc00::1,id=<cleared>,type=129,code=0)
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation expiry])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

AT_DATA([flows.txt], [dnl
priority=1,action=drop

dnl Only allow non-fragmented messages and 1st fragments of each message
priority=10,in_port=1,ipv6,ip_frag=first,action=ct(commit,zone=9),2
priority=10,in_port=1,ipv6,ip_frag=no,action=ct(commit,zone=9),2
priority=10,in_port=2,ct_state=-trk,ipv6,action=ct(table=0,zone=9)
priority=10,in_port=2,ct_state=+trk+est-new,ipv6,action=1

dnl Neighbour Discovery
priority=100,icmp6,icmp_type=135,action=normal
priority=100,icmp6,icmp_type=136,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

dnl Send an IPv6 fragment. Some time later, it should expire.
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 1 -i 0.3 -w 2 fc00::2 | FORMAT_PING], [0], [dnl
7 packets transmitted, 0 received, 100% packet loss, time 0ms
])

dnl At this point, the kernel will either crash or everything is OK.

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation + vlan])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

ADD_VLAN(p0, at_ns0, 100, "fc00:1::3/96")
ADD_VLAN(p1, at_ns1, 100, "fc00:1::4/96")

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,in_port=1,ipv6,action=ct(commit,zone=9),2
priority=10,in_port=2,ct_state=-trk,ipv6,action=ct(table=0,zone=9)
priority=10,in_port=2,ct_state=+trk+est-new,ipv6,action=1
priority=100,icmp6,icmp_type=135,action=normal
priority=100,icmp6,icmp_type=136,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

dnl Ipv4 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00:1::4 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv4 larger fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00:1::4 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation + cvlan])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

ADD_SVLAN(p0, at_ns0, 4094, "fc00:ffff::3/96")
ADD_SVLAN(p1, at_ns1, 4094, "fc00:ffff::4/96")

ADD_CVLAN(p0.4094, at_ns0, 100, "fc00:1::3/96")
ADD_CVLAN(p1.4094, at_ns1, 100, "fc00:1::4/96")

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,in_port=1,ipv6,action=ct(commit,zone=9),2
priority=10,in_port=2,ct_state=-trk,ipv6,action=ct(table=0,zone=9)
priority=10,in_port=2,ct_state=+trk+est-new,ipv6,action=1
priority=100,icmp6,icmp_type=135,action=normal
priority=100,icmp6,icmp_type=136,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00:1::4])

dnl Ipv6 fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00:1::4 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv6 fragmentation connectivity check. (outer svlan)
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00:ffff::4 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv6 larger fragmentation connectivity check.
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00:1::4 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Ipv6 larger fragmentation connectivity check. (outer svlan)
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00:ffff::4 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation incomplete reassembled packet])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

AT_DATA([bundle.txt], [dnl
packet-out in_port=1, packet=50540000000a50540000000986dd6000000005002cfffc000000000000000000000000000001fc0000000000000000000000000000021100000100000001000100020008f62900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809001020304050607080900102030405060708090010203040506070809001020304050607080900102030405060708090010203040506070,  actions=ct(commit)
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation with fragments specified])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

AT_DATA([bundle.txt], [dnl
[packet-out in_port=1, packet=50540000000A50540000000986DD6000000005002CFFFC00]dnl
[0000000000000000000000000001FC00000000000000000000000000000211000001000000010]dnl
[00100020008267100010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900010203040506070809000102030405060]dnl
[70809000102030405060708090001020304050607080900102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900010203040506070809000102030405060]dnl
[70809000102030405060708090001020304050607080900010203040506070809000102030405]dnl
[06070809000102030405060708090001020304050607080900010203040506070809000102030]dnl
[40506070809000102030405060708090001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900010203040506070809000102030405060]dnl
[70809000102030405060708090001020304050607080900010203040506070809000102030405]dnl
[06070809000102030405060708090001020304050607080900010203040506070809000102030]dnl
[40506070809000102030405060708090001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809000]dnl
[10203040506070809000102030405060708090001020304050607080900010203040506070809]dnl
[00010203040506070809000102030405060708090001020304050607080900010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809001020304050607080900102030405060708090010203040506]dnl
[07080900102030405060708090010203040506070809001020304050607080900102030405060]dnl
[70,  actions=ct(commit, zone=1)]
[packet-out in_port=1, packet=50540000000A50540000000986DD6000000000242CFFFC00]dnl
[0000000000000000000000000001FC000000000000000000000000000002110004F8000000010]dnl
0010002000800000001020304050607080900010203040506070809, ]dnl
[actions=ct(commit, zone=1)]
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=1 | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=1
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation out of order])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

AT_DATA([bundle.txt], [dnl
[packet-out in_port=1, packet=50540000000A50540000000986DD6000000000242CFFFC00]dnl
[0000000000000000000000000001FC000000000000000000000000000002110004F8000000010]dnl
[0010002000800000001020304050607080900010203040506070809, ]dnl
[actions=ct(commit, zone=2)]
[packet-out in_port=1, packet=50540000000A50540000000986DD6000000005002CFFFC00]dnl
[0000000000000000000000000001FC00000000000000000000000000000211000001000000010]dnl
[00100020008267100010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900010203040506070809000102030405060]dnl
[70809000102030405060708090001020304050607080900102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900010203040506070809000102030405060]dnl
[70809000102030405060708090001020304050607080900010203040506070809000102030405]dnl
[06070809000102030405060708090001020304050607080900010203040506070809000102030]dnl
[40506070809000102030405060708090001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900010203040506070809000102030405060]dnl
[70809000102030405060708090001020304050607080900010203040506070809000102030405]dnl
[06070809000102030405060708090001020304050607080900010203040506070809000102030]dnl
[40506070809000102030405060708090001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809000]dnl
[10203040506070809000102030405060708090001020304050607080900010203040506070809]dnl
[00010203040506070809000102030405060708090001020304050607080900010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809001020304050607080900102030405060708090010203040506]dnl
[07080900102030405060708090010203040506070809001020304050607080900102030405060]dnl
[70,  actions=ct(commit, zone=2)]
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=2 | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=2
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

# Add different extension headers
AT_DATA([bundle.txt], [dnl
[packet-out in_port=1, packet=50540000000A50540000000986DD60000000050800FFFC00]dnl
[0000000000000000000000000001FC0000000000000000000000000000022C000000000000001]dnl
[10000010000000100010002000826710001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809000]dnl
[10203040506070809000102030405060708090001020304050607080900010203040506070809]dnl
[00010203040506070809000102030405060708090001020304050607080900010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900102030405060708090010203040506070]dnl
[80900102030405060708090010203040506070809001020304050607080900102030405060708]dnl
[090010203040506070,  actions=ct(commit, zone=3)]
[packet-out in_port=1, packet=50540000000a50540000000986dd60000000002c00fffc00]dnl
[0000000000000000000000000001fc0000000000000000000000000000022c000000000000001]dnl
[10004f80000000100010002000800000001020304050607080900010203040506070809, ]dnl
[actions=ct(commit, zone=3)]
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=3 | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=3
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers + out of order])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

# Add different extension headers
AT_DATA([bundle.txt], [dnl
[packet-out in_port=1, packet=50540000000a50540000000986dd60000000002c00fffc00]dnl
[0000000000000000000000000001fc0000000000000000000000000000022c000000000000001]dnl
[10004f80000000100010002000800000001020304050607080900010203040506070809, ]dnl
[actions=ct(commit, zone=4)]
[packet-out in_port=1, packet=50540000000A50540000000986DD60000000050800FFFC00]dnl
[0000000000000000000000000001FC0000000000000000000000000000022C000000000000001]dnl
[10000010000000100010002000826710001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809000]dnl
[10203040506070809000102030405060708090001020304050607080900010203040506070809]dnl
[00010203040506070809000102030405060708090001020304050607080900010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900102030405060708090010203040506070]dnl
[80900102030405060708090010203040506070809001020304050607080900102030405060708]dnl
[090010203040506070,  actions=ct(commit, zone=4)]
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=4 | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=4
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

# Add different extension headers
AT_DATA([bundle.txt], [dnl
[packet-out in_port=1, packet=50540000000A50540000000986DD60000000050800FFFC00]dnl
[0000000000000000000000000001FC0000000000000000000000000000022C000000050200001]dnl
[10000010000000100010002000826710001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809000]dnl
[10203040506070809000102030405060708090001020304050607080900010203040506070809]dnl
[00010203040506070809000102030405060708090001020304050607080900010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900102030405060708090010203040506070]dnl
[80900102030405060708090010203040506070809001020304050607080900102030405060708]dnl
[090010203040506070,  actions=ct(commit, zone=5)]
[packet-out in_port=1, packet=50540000000a50540000000986dd60000000002c00fffc00]dnl
[0000000000000000000000000001fc0000000000000000000000000000022c000000050200001]dnl
[10004f80000000100010002000800000001020304050607080900010203040506070809, ]dnl
[actions=ct(commit, zone=5)]
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=5 | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=5
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2 + out of order])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
DPCTL_SET_MIN_FRAG_SIZE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

# Add different extension headers
AT_DATA([bundle.txt], [dnl
[packet-out in_port=1, packet=50540000000a50540000000986dd60000000002c00fffc00]dnl
[0000000000000000000000000001fc0000000000000000000000000000022c000000050200001]dnl
[10004f80000000100010002000800000001020304050607080900010203040506070809, ]dnl
[actions=ct(commit, zone=6)]
[packet-out in_port=1, packet=50540000000A50540000000986DD60000000050800FFFC00]dnl
[0000000000000000000000000001FC0000000000000000000000000000022C000000050200001]dnl
[10000010000000100010002000826710001020304050607080900010203040506070809000102]dnl
[03040506070809000102030405060708090001020304050607080900010203040506070809000]dnl
[10203040506070809000102030405060708090001020304050607080900010203040506070809]dnl
[00010203040506070809000102030405060708090001020304050607080900010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090010203040506070]dnl
[80900010203040506070809000102030405060708090001020304050607080900010203040506]dnl
[07080900010203040506070809000102030405060708090001020304050607080900010203040]dnl
[50607080900010203040506070809000102030405060708090001020304050607080900010203]dnl
[04050607080900010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090010203040506070809000102030405060708090001020304050607080900010]dnl
[20304050607080900010203040506070809000102030405060708090001020304050607080900]dnl
[01020304050607080900010203040506070809000102030405060708090001020304050607080]dnl
[90001020304050607080900010203040506070809000102030405060708090001020304050607]dnl
[08090001020304050607080900010203040506070809000102030405060708090001020304050]dnl
[60708090001020304050607080900010203040506070809000102030405060708090001020304]dnl
[05060708090001020304050607080900010203040506070809000102030405060708090001020]dnl
[30405060708090001020304050607080900010203040506070809000102030405060708090001]dnl
[02030405060708090001020304050607080900010203040506070809000102030405060708090]dnl
[00102030405060708090001020304050607080900010203040506070809000102030405060708]dnl
[09000102030405060708090001020304050607080900102030405060708090010203040506070]dnl
[80900102030405060708090010203040506070809001020304050607080900102030405060708]dnl
[090010203040506070,  actions=ct(commit, zone=6)]
])

AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=6 | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=6
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - Fragmentation over vxlan])
OVS_CHECK_VXLAN()
CHECK_CONNTRACK()
CHECK_CONNTRACK_LOCAL_STACK()
CHECK_NO_TC_OFFLOAD()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,icmp,action=ct(commit,zone=9),LOCAL
priority=100,in_port=LOCAL,icmp,action=ct(table=1,zone=9)
table=1,in_port=LOCAL,ct_state=+trk+est,icmp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [id 0 dstport 4789])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 Fragmentation over vxlan])
OVS_CHECK_VXLAN()
CHECK_CONNTRACK()
CHECK_CONNTRACK_LOCAL_STACK()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay])
AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])

ADD_NAMESPACES(at_ns0)

dnl Sending ping through conntrack
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=100,in_port=1,ipv6,action=ct(commit,zone=9),LOCAL
priority=100,in_port=LOCAL,ipv6,action=ct(table=1,zone=9)
table=1,in_port=LOCAL,ct_state=+trk+est,ipv6,action=1

dnl Neighbour Discovery
priority=1000,icmp6,icmp_type=135,action=normal
priority=1000,icmp6,icmp_type=136,action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], ["fc00::2/96"])
ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], ["fc00::1/96"],
                  [id 0 dstport 4789])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay with different packet sizes
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -W 2 fc00::2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 Fragmentation + NAT])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
CHECK_CONNTRACK()

OVS_TRAFFIC_VSWITCHD_START(
   [set-fail-mode br0 secure -- ])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.2.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.2.1.2/24")

dnl Create a dummy route for NAT
NS_CHECK_EXEC([at_ns1], [ip addr add 10.1.1.2/32 dev lo])
NS_CHECK_EXEC([at_ns0], [ip route add 10.1.1.0/24 via 10.2.1.2])
NS_CHECK_EXEC([at_ns1], [ip route add 10.1.1.0/24 via 10.2.1.1])

dnl Solely for debugging when things go wrong
NETNS_DAEMONIZE([at_ns0], [tcpdump -l -n -xx -U -i p0 -w p0.pcap >tcpdump.out 2>/dev/null], [tcpdump_0.pid])
NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 -w p1.pcap >tcpdump.out 2>/dev/null], [tcpdump_1.pid])

AT_DATA([flows.txt], [dnl
table=0,arp,actions=normal
table=0,ct_state=-trk,ip,in_port=ovs-p0, actions=ct(table=1, nat)
table=0,ct_state=-trk,ip,in_port=ovs-p1, actions=ct(table=1, nat)
table=1,ct_state=+trk+new,ip,in_port=ovs-p0, actions=ct(commit, nat(src=10.1.1.1)),ovs-p1
table=1,ct_state=+trk+est,ip,in_port=ovs-p0, actions=ovs-p1
table=1,ct_state=+trk+est,ip,in_port=ovs-p1, actions=ovs-p0
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl Check connectivity
NS_CHECK_EXEC([at_ns0], [ping -c 1 10.1.1.2 -M dont -s 4500 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - resubmit to ct multiple times])
CHECK_CONNTRACK()

OVS_TRAFFIC_VSWITCHD_START(
   [set-fail-mode br0 secure -- ])

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
table=0,priority=150,arp,action=normal
table=0,priority=100,ip,in_port=1,action=resubmit(,1),resubmit(,2)

table=1,ip,action=ct(table=3)
table=2,ip,action=ct(table=3)

table=3,ip,action=drop
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

NS_CHECK_EXEC([at_ns0], [ping -q -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 0 received, 100% packet loss, time 0ms
])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 n_packets=1, n_bytes=98, priority=100,ip,in_port=1 actions=resubmit(,1),resubmit(,2)
 n_packets=2, n_bytes=84, priority=150,arp actions=NORMAL
 table=1, n_packets=1, n_bytes=98, ip actions=ct(table=3)
 table=2, n_packets=1, n_bytes=98, ip actions=ct(table=3)
 table=3, n_packets=2, n_bytes=196, ip actions=drop
NXST_FLOW reply:
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - zone-based timeout policy])
CHECK_CONNTRACK()
CHECK_CONNTRACK_TIMEOUT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,ip,action=ct(zone=5, table=1)
priority=100,in_port=2,ip,action=ct(zone=5, table=1)
table=1,in_port=2,ip,ct_state=+trk+est,action=1
table=1,in_port=1,ip,ct_state=+trk+new,action=ct(commit,zone=5),2
table=1,in_port=1,ip,ct_state=+trk+est,action=2
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Test with default timeout
dnl The default udp_single and icmp_first timeouts are 30 seconds in
dnl kernel DP, and 60 seconds in userspace DP.

dnl Send ICMP and UDP traffic
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

sleep 4

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=5
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=5
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl Shorten the udp_single and icmp_first timeout in zone 5
dnl Userspace datapath uses udp_first and icmp_reply, and
dnl kernel datapath uses udp_single and icmp_first
VSCTL_ADD_DATAPATH_TABLE()

dnl Creating more timeout policies
for i in `seq 1 255`; do
ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=$i udp_first=$i udp_single=$i icmp_first=$i icmp_reply=$i;
done
AT_CHECK([ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=5 udp_first=1 udp_single=1 icmp_first=1 icmp_reply=1])

dnl Send ICMP and UDP traffic
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=5
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=5
])

dnl Wait until the timeout expire.
dnl We intend to wait a bit longer, because conntrack does not recycle the entry right after it is expired.
sleep 6

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
])

dnl Re-send ICMP and UDP traffic to test conntrack cache
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=5
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=5
])

dnl Wait until the timeout expire.
dnl We intend to wait a bit longer, because conntrack does not recycle the entry right after it is expired.
sleep 6

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
])

dnl Set the timeout policy to default again.
AT_CHECK([ovs-vsctl del-zone-tp $DP_TYPE zone=5])

dnl Send ICMP and UDP traffic
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])

sleep 1

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=5
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=5
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - SCTP SNAT with port range])
CHECK_CONNTRACK()
CHECK_CONNTRACK_SCTP()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])

dnl Allow any traffic from ns0->ns1. Only allow return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
table=0,priority=100,in_port=1,sctp,action=ct(commit,zone=1,nat(src=10.1.1.240:34567)),controller
table=0,priority=100,in_port=2,ct_state=-trk,sctp,tp_dst=34567,action=ct(table=1,zone=1,nat)
table=0,priority=0,action=drop
table=1,priority=100,in_port=2,ct_state=+trk+rpl,ct_zone=1,sctp,action=controller
table=1,priority=0,action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CAPTURE_FILE([ofctl_monitor.log])
AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])

dnl Simple SCTP association local and remote single homing
dnl Send INIT.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=e666c1222222e666c111111108004502004400004000408424300a0101010a010102d6b9303900000000c5cc426b0100002470e18ccc0001a000000affff7ae1c142000c00060005000080000004c0000004 actions=resubmit(,0)"])
dnl Reply INIT_ACK.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=e666c1111111e666c122222208004502012400004000408422610a0101020a0101f03039870770e18ccc97abd49a0200010425bb9dfa0001a000000a000abb90fba5000700e827a048cd1474b111490710816ec95cfc501126b200000000000000000000000000000000fa9dbb25cc8ce17000000000000000002b953b0e1d346d160a000a00a5fb90bb020087070a0101f00000000000000000000000000000000000000000393001000000000080020024fbb82eae13af8d70329bc42bb7cd7e6458d60ff1a181e9b41167c2cab54471bf0000000000000000000000000000000000000000000000000000000000000000000000000100002470e18ccc0001a000000affff7ae1c142000c00060005000080000004c00000040000000000000000000000000000000080000004c0000004 actions=resubmit(,0)"])
dnl Send COOKIE_ECHO.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=e666c1222222e666c1111111080045020108000040004084236c0a0101010a010102d6b9303925bb9dfaf2c860300a0000e827a048cd1474b111490710816ec95cfc501126b200000000000000000000000000000000fa9dbb25cc8ce17000000000000000002b953b0e1d346d160a000a00a5fb90bb020087070a0101f00000000000000000000000000000000000000000393001000000000080020024fbb82eae13af8d70329bc42bb7cd7e6458d60ff1a181e9b41167c2cab54471bf0000000000000000000000000000000000000000000000000000000000000000000000000100002470e18ccc0001a000000affff7ae1c142000c00060005000080000004c000000400000000000000000000000000000000 actions=resubmit(,0)"])
dnl Reply COOKIE_ACK.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=e666c1111111e666c122222208004502002400004000408423610a0101020a0101f03039870770e18ccc0391398b0b000004 actions=resubmit(,0)"])
dnl Send DATA.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=e666c1222222e666c1111111080045020034000140004084243f0a0101010a010102d6b9303925bb9dfabc366345000300147ae1c1420000000000000000666f6f0a actions=resubmit(,0)"])
dnl Reply SACK.
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=e666c1111111e666c122222208004502003042c840004084e08c0a0101020a0101f03039870770e18ccc6a990714030000107ae1c14200019ffc00000000 actions=resubmit(,0)"])
dnl ABORT the association. The association cannot be gracefully terminated because of
dnl a small timeouts in SHUTDOWN_SENT in the kernel datapath that would make the test unreliable
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=e666c1222222e666c111111108004500002400010000408464510a0101010a010102d6b9303925bb9dfae3b82c3806000004 actions=resubmit(,0)"])

AT_CHECK([ovs-appctl revalidator/purge], [0])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=82 in_port=1 (via action) data_len=82 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:11:11:11,dl_dst=e6:66:c1:22:22:22,nw_src=10.1.1.240,nw_dst=10.1.1.2,nw_tos=0,nw_ecn=2,nw_ttl=64,nw_frag=no,tp_src=34567,tp_dst=12345 sctp_csum:9670267b
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=306 ct_state=est|rpl|trk|dnat,ct_zone=1,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=132,ct_tp_src=54969,ct_tp_dst=12345,ip,in_port=2 (via action) data_len=306 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:22:22:22,dl_dst=e6:66:c1:11:11:11,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_tos=0,nw_ecn=2,nw_ttl=64,nw_frag=no,tp_src=12345,tp_dst=54969 sctp_csum:49864886
NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=278 in_port=1 (via action) data_len=278 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:11:11:11,dl_dst=e6:66:c1:22:22:22,nw_src=10.1.1.240,nw_dst=10.1.1.2,nw_tos=0,nw_ecn=2,nw_ttl=64,nw_frag=no,tp_src=34567,tp_dst=12345 sctp_csum:8c816918
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=50 ct_state=est|rpl|trk|dnat,ct_zone=1,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=132,ct_tp_src=54969,ct_tp_dst=12345,ip,in_port=2 (via action) data_len=50 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:22:22:22,dl_dst=e6:66:c1:11:11:11,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_tos=0,nw_ecn=2,nw_ttl=64,nw_frag=no,tp_src=12345,tp_dst=54969 sctp_csum:ef4749fc
NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=66 in_port=1 (via action) data_len=66 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:11:11:11,dl_dst=e6:66:c1:22:22:22,nw_src=10.1.1.240,nw_dst=10.1.1.2,nw_tos=0,nw_ecn=2,nw_ttl=64,nw_frag=no,tp_src=34567,tp_dst=12345 sctp_csum:eb2b2c17
NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=62 ct_state=est|rpl|trk|dnat,ct_zone=1,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=132,ct_tp_src=54969,ct_tp_dst=12345,ip,in_port=2 (via action) data_len=62 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:22:22:22,dl_dst=e6:66:c1:11:11:11,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_tos=0,nw_ecn=2,nw_ttl=64,nw_frag=no,tp_src=12345,tp_dst=54969 sctp_csum:9b67e853
NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=50 in_port=1 (via action) data_len=50 (unbuffered)
sctp,vlan_tci=0x0000,dl_src=e6:66:c1:11:11:11,dl_dst=e6:66:c1:22:22:22,nw_src=10.1.1.240,nw_dst=10.1.1.2,nw_tos=0,nw_ecn=0,nw_ttl=64,nw_frag=no,tp_src=34567,tp_dst=12345 sctp_csum:4bb49f65
])

dnl Check the ct entry
dnl protoinfo has to be removed in order to normalize the current difference between user and kernel output
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed 's/,protoinfo=.*$//' ], [], [dnl
sctp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),zone=1
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

dnl Check kernel datapath to make sure conntrack fills in L3 and L4
dnl protocol information
AT_SETUP([conntrack - fragment reassembly with L3 L4 protocol information])
CHECK_CONNTRACK()
CHECK_L3L4_CONNTRACK_REASM()
OVS_TRAFFIC_VSWITCHD_START()

AT_DATA([flows.txt], [dnl
action=normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl packet-out br0 "in_port=42,packet=52540003287c525400444ab586dd6006f70605b02c4020010001000000000000000000000020200100010000000000000000000000101100000134e88deb13891389080803136161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616"dnl
"16161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161"dnl
"61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616"dnl
"1616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161, actions=ct(table=1)"])

AT_CHECK([ovs-ofctl packet-out br0 "in_port=42,packet=52540003287c525400444ab586dd6006f70602682c402001000100000000000000000000002020010001000000000000000000000010110005a834e88deb6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616"dnl
"161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161, actions=ct(table=1)"])

AT_CHECK([ovs-ofctl packet-out br0 "in_port=42,packet=52540003287c525400444ab586dd6006f706033d1140200100010000000000000000000000202001000100000000000000000000001013891389033d923861616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616"dnl
"1616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a, actions=ct(table=1)"])

AT_CHECK([ovs-appctl dpctl/dump-flows | head -2 | tail -1 | grep -q -e ["]udp[(]src=5001["]])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([conntrack - L7])

AT_SETUP([conntrack - IPv4 HTTP])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,action=ct(commit),2
priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk+est,tcp,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns0], [http])
OVS_START_L7([at_ns1], [http])

dnl HTTP requests from ns0->ns1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

dnl HTTP requests from ns1->ns0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_HTTP([10.1.1.1]), [28], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 HTTP])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96", [], [], "nodad")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", [], [], "nodad")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,icmp6,action=normal
priority=100,in_port=1,tcp6,action=ct(commit),2
priority=100,in_port=2,ct_state=-trk,tcp6,action=ct(table=0)
priority=100,in_port=2,ct_state=+trk+est,tcp6,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

OVS_START_L7([at_ns0], [http6])
OVS_START_L7([at_ns1], [http6])

dnl HTTP requests from ns0->ns1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([[http://[[fc00::2]]]]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

dnl HTTP requests from ns1->ns0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_HTTP([[http://[[fc00::1]]]]), [28], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - commit, recirc])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2, at_ns3)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.4/24")

dnl Allow any traffic from ns0->ns1, ns2->ns3.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=10,icmp,action=normal
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(commit,table=0)
priority=100,in_port=1,tcp,ct_state=+trk,action=2
priority=100,in_port=2,tcp,ct_state=-trk,action=ct(table=0)
priority=100,in_port=2,tcp,ct_state=+trk,action=1
priority=100,in_port=3,tcp,ct_state=-trk,action=set_field:0->metadata,ct(table=0)
priority=100,in_port=3,tcp,ct_state=+trk,metadata=0,action=set_field:1->metadata,ct(commit,table=0)
priority=100,in_port=3,tcp,ct_state=+trk,metadata=1,action=4
priority=100,in_port=4,tcp,ct_state=-trk,action=ct(commit,table=0)
priority=100,in_port=4,tcp,ct_state=+trk,action=3
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns1], [http])
OVS_START_L7([at_ns3], [http])

dnl HTTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl HTTP requests from p2->p3 should work fine.
NS_CHECK_EXEC([at_ns2], OVS_GET_HTTP([10.1.1.4]), [0], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - multiple zones, local])
CHECK_EXTERNAL_CT()
CHECK_CONNTRACK()
CHECK_CONNTRACK_LOCAL_STACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_EXTERNAL_CT([br0])
ADD_NAMESPACES(at_ns0)

AT_CHECK([ip addr add dev br0 "10.1.1.1/24"])
AT_CHECK([ip link set dev br0 up])
on_exit 'ip addr del dev br0 "10.1.1.1/24"'
ADD_VETH(p0, at_ns0, br0, "10.1.1.2/24")

dnl Allow traffic from local stack to ns0. Only allow neighbour discovery,
dnl return traffic from ns0 back to the local stack.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=LOCAL,ip,ct_state=-trk,action=drop
priority=100,in_port=LOCAL,ip,ct_state=+trk+new,action=ct(commit,zone=1),ct(commit,zone=2),1
priority=100,in_port=LOCAL,ip,ct_state=+trk+est,action=ct(commit,zone=1),ct(commit,zone=2),1
priority=100,in_port=1,ip,ct_state=-trk,action=ct(table=1,zone=1)
table=1,in_port=1,ip,ct_state=+trk+est,ct_zone=1,action=ct(table=2,zone=2)
table=2,in_port=1,ip,ct_state=+trk+est,ct_zone=2,action=LOCAL
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CHECK([ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_START_L7([at_ns0], [http])

dnl HTTP requests from root namespace to p0 should work fine.
AT_CHECK(OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl (again) HTTP requests from root namespace to p0 should work fine.
AT_CHECK(OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | grep "zone"], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=1
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=2
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - multi-stage pipeline, local])
CHECK_EXTERNAL_CT()
CHECK_CONNTRACK()
CHECK_CONNTRACK_LOCAL_STACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_EXTERNAL_CT([br0])
ADD_NAMESPACES(at_ns0)

AT_CHECK([ip addr add dev br0 "10.1.1.1/24"])
AT_CHECK([ip link set dev br0 up])
on_exit 'ip addr del dev br0 "10.1.1.1/24"'
ADD_VETH(p0, at_ns0, br0, "10.1.1.2/24")

dnl Allow traffic from local stack to ns0. Only allow neighbour discovery,
dnl return traffic from ns0 back to the local stack.
AT_DATA([flows.txt], [dnl
dnl default
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal

dnl Load the output port to REG0
table=0,priority=100,ip,in_port=LOCAL,action=load:1->NXM_NX_REG0[[0..15]],goto_table:1
table=0,priority=100,ip,in_port=1,action=load:65534->NXM_NX_REG0[[0..15]],goto_table:1

dnl Ingress pipeline
dnl - Allow all connections from LOCAL port (commit and proceed to egress)
dnl - All other connections go through conntracker using the input port as
dnl   a connection tracking zone.
table=1,priority=150,in_port=LOCAL,ip,ct_state=+trk+new,action=ct(commit,table=2,zone=OXM_OF_IN_PORT[[0..15]])
table=1,priority=100,ip,action=ct(table=2,zone=OXM_OF_IN_PORT[[0..15]])
table=1,priority=1,action=drop

dnl Egress pipeline
dnl - Allow all connections from LOCAL port (commit and skip to output)
dnl - Allow other established connections to go through conntracker using
dnl   output port as a connection tracking zone.
table=2,priority=150,in_port=LOCAL,ip,ct_state=+trk+new,action=ct(commit,table=4,zone=NXM_NX_REG0[[0..15]])
table=2,priority=100,ip,ct_state=+trk+est,action=ct(table=3,zone=NXM_NX_REG0[[0..15]])
table=2,priority=1,action=drop

dnl Only allow established traffic from egress ct lookup
table=3,priority=100,ip,ct_state=+trk+est,action=goto_table:4
table=3,priority=1,action=drop

dnl output table
table=4,priority=100,ip,action=output:NXM_NX_REG0[[]]
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

AT_CHECK([ping -q -c 3 -i 0.3 -W 2 10.1.1.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_START_L7([at_ns0], [http])

dnl HTTP requests from root namespace to p0 should work fine.
AT_CHECK(OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

dnl (again) HTTP requests from root namespace to p0 should work fine.
AT_CHECK(OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | grep "zone"], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=1
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0),zone=65534
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=65534,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - limit by zone])
CHECK_CONNTRACK()
OVS_CHECK_GITHUB_ACTION()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,arp,action=normal
priority=100,in_port=1,udp,action=ct(zone=1,commit),2
priority=100,in_port=2,udp,action=ct(zone=3,commit),1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Test values out of range for the default limit.
dnl Try to set a negative value.
AT_CHECK([ovs-appctl dpctl/ct-set-limits default=-1], [2], [ignore], [dnl
ovs-vswitchd: invalid default limit (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

dnl Try to set UINT32_MAX.
AT_CHECK([ovs-appctl dpctl/ct-set-limits default=4294967296], [2], [ignore], [dnl
ovs-vswitchd: invalid default limit (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

dnl Same range checks for zones.
AT_CHECK([ovs-appctl dpctl/ct-set-limits zone=1,limit=-1], [2], [ignore], [dnl
ovs-vswitchd: failed to parse field limit (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-set-limits zone=1,limit=4294967296], [2], [ignore], [dnl
ovs-vswitchd: failed to parse field limit (Invalid argument)
ovs-appctl: ovs-vswitchd: server returned an error
])

dnl Double check no limits have been applied.
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [],[dnl
default limit=0
])

m4_define([UDP_PKT], [m4_join([,],
  [eth_src=50:54:00:00:00:0$1,eth_dst=50:54:00:00:00:0$2,dl_type=0x0800],
  [nw_src=10.1.1.$1,nw_dst=10.1.1.$2],
  [nw_proto=17,nw_ttl=64,nw_frag=no],
  [udp_src=1,udp_dst=$3])])

AT_CHECK([ovs-appctl dpctl/ct-set-limits zone=1,limit=0])
pkt=$(ovs-ofctl compose-packet --bare "UDP_PKT([1], [2], [2])")
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=${pkt} actions=resubmit(,0)"])

dnl Double check the zl entry exists but no connection was added.
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [],[dnl
default limit=0
zone=1,limit=0,count=0
])

dnl Remove limit for zone=1.
AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=1])

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=3])
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [],[dnl
default limit=3
])

dnl Send 5 packets from each port in order to hit the default zone limit.
for i in $(seq 2 6); do
    pkt=$(ovs-ofctl compose-packet --bare "UDP_PKT([1], [2], [$i])")
    AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=${pkt} actions=resubmit(,0)"])
done

AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=1], [],[dnl
default limit=3
zone=1,limit=3,count=3
])

for i in $(seq 2 6); do
    pkt=$(ovs-ofctl compose-packet --bare "UDP_PKT([3], [4], [$i])")
    AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=${pkt} actions=resubmit(,0)"])
done

AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=1,3], [],[dnl
default limit=3
zone=1,limit=3,count=3
zone=3,limit=3,count=3
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10 zone=1,limit=5 zone=2,limit=3 zone=3,limit=3 zone=4,limit=15])
AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=2,4,5])
AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=1,2,3,4], [],[dnl
default limit=10
zone=1,limit=5,count=0
zone=2,limit=10,count=0
zone=3,limit=3,count=0
zone=4,limit=10,count=0
])

dnl Test UDP from port 1
for i in $(seq 2 10); do
    pkt=$(ovs-ofctl compose-packet --bare "UDP_PKT([1], [2], [$i])")
    AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=${pkt} actions=resubmit(,0)"])
done

AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=1,2,3,4,5], [0], [dnl
default limit=10
zone=1,limit=5,count=5
zone=2,limit=10,count=0
zone=3,limit=3,count=0
zone=4,limit=10,count=0
zone=5,limit=10,count=0
])

dnl Test ct-get-limits for all zones
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=10
zone=1,limit=5,count=5
zone=3,limit=3,count=0
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1," | sort ], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),zone=1
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=3),reply=(src=10.1.1.2,dst=10.1.1.1,sport=3,dport=1),zone=1
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=4),reply=(src=10.1.1.2,dst=10.1.1.1,sport=4,dport=1),zone=1
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=5),reply=(src=10.1.1.2,dst=10.1.1.1,sport=5,dport=1),zone=1
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=6),reply=(src=10.1.1.2,dst=10.1.1.1,sport=6,dport=1),zone=1
])

dnl Test UDP from port 2
for i in $(seq 2 6); do
    pkt=$(ovs-ofctl compose-packet --bare "UDP_PKT([3], [4], [$i])")
    AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=${pkt} actions=resubmit(,0)"])
done

AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=1,3], [0], [dnl
default limit=10
zone=1,limit=5,count=5
zone=3,limit=3,count=3
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl
udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3
udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3
udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3
])

dnl Test ct-del-limits for default zone.

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=4,limit=4])
AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=4], [0], [dnl
default limit=15
zone=4,limit=4,count=0
])

AT_CHECK([ovs-appctl dpctl/ct-del-limits default])
AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=4], [0], [dnl
default limit=0
zone=4,limit=4,count=0
])

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15])
AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=4], [0], [dnl
default limit=15
zone=4,limit=4,count=0
])

AT_CHECK([ovs-appctl dpctl/ct-del-limits default zone=4])
AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=4], [0], [dnl
default limit=0
zone=4,limit=0,count=0
])

dnl Test limit set via database.
VSCTL_ADD_DATAPATH_TABLE()

AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1])
AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=3])

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10])
AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=3])
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=10
zone=1,limit=5,count=0
])

AT_CHECK([ovs-vsctl set-zone-limit $DP_TYPE 1 3])
AT_CHECK([ovs-vsctl set-zone-limit $DP_TYPE 3 3])

OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl
default limit=10
zone=1,limit=3,count=0
zone=3,limit=3,count=0])

for i in $(seq 2 6); do
    pkt=$(ovs-ofctl compose-packet --bare "UDP_PKT([3], [4], [$i])")
    AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=${pkt} actions=resubmit(,0)"])
done

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl
udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3
udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3
udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3
])

AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=10
zone=1,limit=3,count=0
zone=3,limit=3,count=3
])

AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE 3])
OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl
default limit=10
zone=1,limit=3,count=0])

AT_CHECK([ovs-vsctl set-zone-limit $DP_TYPE default 5])
OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl
default limit=5
zone=1,limit=3,count=0])

AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE default])
OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl
default limit=0
zone=1,limit=3,count=0])

dnl Try to overwrite the zone limit via dpctl command.
AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=3,limit=5 zone=1,limit=5], [2], [ignore], [dnl
ovs-vswitchd: the zone limits are set via database, dnl
use 'ovs-vsctl set-zone-limit <...>' instead. (Operation not permitted)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=0
zone=1,limit=3,count=0
])

AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=1], [2], [ignore], [dnl
ovs-vswitchd: the zone limits are set via database, dnl
use 'ovs-vsctl del-zone-limit <...>' instead. (Operation not permitted)
ovs-appctl: ovs-vswitchd: server returned an error
])

AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=0
zone=1,limit=3,count=0
])

AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE 1])
AT_CHECK([ovs-vsctl set-zone-limit $DP_TYPE default 10])
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=10
])

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=1,limit=5], [2], [ignore], [dnl
ovs-vswitchd: the zone limits are set via database, dnl
use 'ovs-vsctl set-zone-limit <...>' instead. (Operation not permitted)
ovs-appctl: ovs-vswitchd: server returned an error
])

dnl Delete all zones from DB, that should remove the protection.
AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE default])

AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=1,limit=5])
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=15
zone=1,limit=5,count=0
])

AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=1])
AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
default limit=15
])

OVS_TRAFFIC_VSWITCHD_STOP(["dnl
/could not create datapath/d
/(Cannot allocate memory) on packet/d"])
AT_CLEANUP

AT_SETUP([FTP - no conntrack])
AT_SKIP_IF([test $HAVE_FTP = no])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
table=0,action=normal
])

AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows.txt])

NETNS_DAEMONIZE([at_ns0], [[$PYTHON3 $srcdir/test-l7.py ftp]], [ftp1.pid])
NETNS_DAEMONIZE([at_ns1], [[$PYTHON3 $srcdir/test-l7.py ftp]], [ftp0.pid])
OVS_WAIT_UNTIL([ip netns exec at_ns1 netstat -l | grep ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2], [-o index.html]), [0], [ignore], [ignore])

AT_CHECK([find -name index.html], [0], [dnl
./index.html
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - FTP])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows1.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(alg=ftp,commit),2
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk+rel,action=1
])

dnl Similar policy but without allowing all traffic from ns0->ns1.
AT_DATA([flows2.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal

dnl Allow outgoing TCP connections, and treat them as FTP
table=0,priority=100,in_port=1,tcp,action=ct(table=1)
table=1,in_port=1,tcp,ct_state=+trk+new,action=ct(commit,alg=ftp),2
table=1,in_port=1,tcp,ct_state=+trk+est,action=2

dnl Allow incoming FTP data connections and responses to existing connections
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+new+rel,action=ct(commit),1
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk-new+rel,action=1
])

dnl flows3 is same as flows1, except no ALG is specified.
AT_DATA([flows3.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(commit),2
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk+rel,action=1
])

AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows1.txt])

OVS_START_L7([at_ns0], [ftp])
OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p1->p0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_FTP_ACTIVE([10.1.1.1]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

dnl Try the second set of flows.
AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows2.txt])
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl FTP requests from p1->p0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_FTP_ACTIVE([10.1.1.1]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl Active FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl Passive FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

dnl Try the third set of flows, without alg specifier.
AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows3.txt])
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl FTP control requests from p0->p1 should work fine, but helper will not be assigned.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - FTP non-standard port])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows1.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(alg=ftp,commit),2
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk+rel,action=1
])

dnl Similar policy but without allowing all traffic from ns0->ns1.
AT_DATA([flows2.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal

dnl Allow outgoing TCP connections, and treat them as FTP
table=0,priority=100,in_port=1,tcp,action=ct(table=1)
table=1,in_port=1,tcp,ct_state=+trk+new,action=ct(commit,alg=ftp),2
table=1,in_port=1,tcp,ct_state=+trk+est,action=2

dnl Allow incoming FTP data connections and responses to existing connections
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+new+rel,action=ct(commit),1
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk-new+rel,action=1
])

dnl flows3 is same as flows1, except no ALG is specified.
AT_DATA([flows3.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(commit),2
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk+rel,action=1
])

AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows1.txt])

OVS_START_L7([at_ns0], [ftp], [11111])
OVS_START_L7([at_ns1], [ftp], [11111])

dnl FTP requests from p1->p0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_FTP_ACTIVE([10.1.1.1:11111]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2:11111]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

dnl Try the second set of flows.
AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows2.txt])
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl FTP requests from p1->p0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_FTP_ACTIVE([10.1.1.1:11111]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl Active FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2:11111]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl Passive FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([10.1.1.2:11111]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

dnl Try the third set of flows, without alg specifier.
AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows3.txt])
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl FTP control requests from p0->p1 should work fine, but helper will not be assigned.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2:11111]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - FTP with expectation dump])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
CHECK_CONNTRACK_DUMP_EXPECTATIONS()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,tcp,action=ct(alg=ftp,commit),2
table=0,priority=100,in_port=2,tcp,action=ct(table=1)
table=1,in_port=2,tcp,ct_state=+trk+est,action=1
table=1,in_port=2,tcp,ct_state=+trk+rel,action=1
])

AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows.txt])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

dnl Verify that a dump with zero entries in a zone doesn't return any entry.
AT_CHECK([ovs-appctl dpctl/dump-conntrack-exp zone=42], [0], [dnl
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack-exp | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),parent=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - FTP over IPv6])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96", [], [], "nodad")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", [], [], "nodad")

dnl Allow any traffic from ns0->ns1.
dnl Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
dnl Track all IPv6 traffic and drop the rest.
dnl Allow ICMPv6 both ways.  No commit, so pings will not be tracked.
table=0 priority=100 in_port=1 icmp6, action=2
table=0 priority=100 in_port=2 icmp6, action=1
table=0 priority=10 ip6, action=ct(table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new TCPv6 FTP control connections from port 1.
table=1 in_port=1 ct_state=+new, tcp6, tp_dst=21, action=ct(alg=ftp,commit),2
dnl Allow related TCPv6 connections from port 2.
table=1 in_port=2 ct_state=+new+rel, tcp6, action=ct(commit),1
dnl Allow established TCPv6 connections both ways.
table=1 in_port=1 ct_state=+est, tcp6, action=2
table=1 in_port=2 ct_state=+est, tcp6, action=1
dnl Drop everything else.
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([[[[fc00::2]]]], [--ipv6]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),reply=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 FTP Passive])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96", [], [], "nodad")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", [], [], "nodad")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:88:88:88:88:99])
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::2 lladdr 80:88:88:88:88:99 dev p0])
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::1 lladdr 80:88:88:88:88:88 dev p1])

dnl Allow any traffic from ns0->ns1.
dnl Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
dnl Track all IPv6 traffic and drop the rest.
dnl Allow ICMPv6 both ways.  No commit, so pings will not be tracked.
table=0 priority=100 in_port=1 icmp6, action=2
table=0 priority=100 in_port=2 icmp6, action=1
table=0 priority=10 ip6, action=ct(table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new TCPv6 FTP control connections from port 1.
table=1 in_port=1 ct_state=+new, tcp6, tp_dst=21, action=ct(alg=ftp,commit),2
dnl Allow related TCPv6 connections from port 1.
table=1 in_port=1 ct_state=+new+rel, tcp6, action=ct(commit),2
dnl Allow established TCPv6 connections both ways.
table=1 in_port=1 ct_state=+est, tcp6, action=2
table=1 in_port=2 ct_state=+est, tcp6, action=1
dnl Drop everything else.
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP passive requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([[[[fc00::2]]]], [--ipv6]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - FTP with multiple expectations])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Dual-firewall, allow all from ns1->ns2, allow established and ftp ns2->ns1.
AT_DATA([flows.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal

dnl Traffic from ns1
table=0,priority=100,in_port=1,tcp,action=ct(table=1,zone=1)
table=1,in_port=1,tcp,ct_zone=1,ct_state=+trk+new-rel,action=ct(commit,alg=ftp,zone=1),ct(commit,alg=ftp,zone=2),2
table=1,in_port=1,tcp,ct_zone=1,ct_state=+trk+new+rel,action=ct(commit,zone=1),ct(commit,zone=2),2
table=1,in_port=1,tcp,ct_zone=1,ct_state=+trk+est,action=ct(table=2,zone=2)
table=2,in_port=1,tcp,ct_zone=2,ct_state=+trk+est,action=2

dnl Traffic from ns2
table=0,priority=100,in_port=2,tcp,action=ct(table=1,zone=2)
table=1,in_port=2,tcp,ct_zone=2,ct_state=+trk+rel,action=ct(commit,zone=2),ct(commit,zone=1),1
table=1,in_port=2,tcp,ct_zone=2,ct_state=+trk+est,action=ct(table=2,zone=1)
table=2,in_port=2,tcp,ct_zone=1,ct_state=+trk+rel,action=ct(commit,zone=2),ct(commit,zone=1),1
table=2,in_port=2,tcp,ct_zone=1,ct_state=+trk+est,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

OVS_START_L7([at_ns0], [ftp])
OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p1->p0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
NS_CHECK_EXEC([at_ns1], OVS_GET_FTP_ACTIVE([10.1.1.1]), [28], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl Active FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>)
])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl Passive FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([10.1.1.2]), [0], [ignore], [ignore])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=2,protoinfo=(state=<cleared>),helper=ftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - TFTP])
AT_SKIP_IF([test $HAVE_TFTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows1.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal
table=0,priority=100,in_port=1,udp,action=ct(alg=tftp,commit),2
table=0,priority=100,in_port=2,udp,action=ct(table=1)
table=1,in_port=2,udp,ct_state=+trk+est,action=1
table=1,in_port=2,udp,ct_state=+trk+rel,action=1
])

dnl Similar policy but without allowing all traffic from ns0->ns1.
AT_DATA([flows2.txt], [dnl
table=0,priority=1,action=drop
table=0,priority=10,arp,action=normal
table=0,priority=10,icmp,action=normal

dnl Allow outgoing UDP connections, and treat them as TFTP
table=0,priority=100,in_port=1,udp,action=ct(table=1)
table=1,in_port=1,udp,ct_state=+trk+new-rel,action=ct(commit,alg=tftp),2
table=1,in_port=1,udp,ct_state=+trk+new+rel,action=ct(commit),2
table=1,in_port=1,udp,ct_state=+trk+est,action=2

dnl Allow incoming TFTP data connections and responses to existing connections
table=0,priority=100,in_port=2,udp,action=ct(table=1)
table=1,in_port=2,udp,ct_state=+trk+est,action=1
table=1,in_port=2,udp,ct_state=+trk+new+rel,action=1
])

AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows1.txt])

OVS_START_L7([at_ns0], [tftp])
OVS_START_L7([at_ns1], [tftp])

dnl TFTP requests from p1->p0 should fail due to network failure.
NS_CHECK_EXEC([at_ns1], [[curl $CURL_OPT tftp://10.1.1.1/flows1.txt -o foo 2>curl0.log]], [28])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl TFTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], [[curl $CURL_OPT tftp://10.1.1.2/flows1.txt -o foo 2>curl1.log]])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),helper=tftp
])

dnl Try the second set of flows.
AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows2.txt])
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

dnl TFTP requests from p1->p0 should fail due to network failure.
NS_CHECK_EXEC([at_ns1], [[curl $CURL_OPT tftp://10.1.1.1/flows1.txt -o foo 2>curl2.log]], [28])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
])

dnl TFTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], [[curl $CURL_OPT tftp://10.1.1.2/flows1.txt -o foo 2>curl3.log]])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),helper=tftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([conntrack - NAT])

AT_SETUP([conntrack - simple SNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
in_port=1,ip,action=ct(commit,zone=1,nat(src=10.1.1.240-10.1.1.254)),2
in_port=2,ct_state=-trk,ip,action=ct(table=0,zone=1,nat)
in_port=2,ct_state=+trk,ct_zone=1,ip,action=1
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a0101f0/0xfffffff0,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl HTTP requests from p0->p1 should work fine.
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/' | uniq], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - SNAT with ct_mark change on reply])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.240 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
in_port=1,ip,action=ct(commit,zone=1,nat(src=10.1.1.240)),2
in_port=2,ct_state=-trk,ip,action=ct(table=0,zone=1,nat)
dnl
dnl Setting the mark fails if the datapath can't find the existing conntrack
dnl entry after NAT has been reversed and the skb was lost due to an upcall.
dnl
in_port=2,ct_state=+trk,ct_zone=1,ip,action=ct(table=1,commit,zone=1,exec(set_field:1->ct_mark)),1
table=1,in_port=2,ct_mark=1,ct_state=+rpl,ct_zone=1,ip,action=1
dnl
priority=0,action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl ICMP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], [ping -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/'], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.2XX,id=<cleared>,type=0,code=0),zone=1,mark=1
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - SNAT with port range])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
in_port=1,tcp,action=ct(commit,zone=1,nat(src=10.1.1.240-10.1.1.254:34567-34568,random)),2
in_port=2,ct_state=-trk,tcp,tp_dst=34567,action=ct(table=0,zone=1,nat)
in_port=2,ct_state=-trk,tcp,tp_dst=34568,action=ct(table=0,zone=1,nat)
in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a0101f0/0xfffffff0,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl HTTP requests from p0->p1 should work fine.
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/' | uniq], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - SNAT with port range using ICMP])
dnl Check PAT is not attempted on ICMP packets causing corrupted packets.
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
in_port=1,ip,action=ct(commit,zone=1,nat(src=10.1.1.240-10.1.1.254:20000)),2
in_port=2,ct_state=-trk,ip,action=ct(table=0,zone=1,nat)
in_port=2,ct_state=+trk,ct_zone=1,action=1
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a0101f0/0xfffffff0,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl ICMP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], [ping -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/'], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.2XX,id=<cleared>,type=0,code=0),zone=1
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - SNAT with port range with exhaustion])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:89:89:89:89:89])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
in_port=1,tcp,action=ct(commit,zone=1,nat(src=10.1.1.240:34568)),2
in_port=2,ct_state=-trk,tcp,tp_dst=34568,action=ct(table=0,zone=1,nat)
in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a0101f0/0xfffffff0,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl HTTP requests from p0->p1 should work fine.
OVS_START_L7([at_ns1], [http])

dnl Send a valid SYN to make conntrack pick it up.
dnl The source port used is 123 to prevent unwanted reuse in the next HTTP request.
syn_pkt=$(ovs-ofctl compose-packet --bare "eth_src=80:88:88:88:88:88,eth_dst=80:89:89:89:89:89,\
  dl_type=0x0800,nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_proto=6,nw_ttl=64,nw_frag=no,tcp_flags=syn,\
  tcp_src=123,tcp_dst=80")
AT_CHECK([ovs-ofctl packet-out br0 "packet=${syn_pkt} actions=ct(commit,zone=1,nat(src=10.1.1.240:34568))"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | uniq], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [28], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | uniq], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP(["dnl
/Unable to NAT due to tuple space exhaustion - if DoS attack, use firewalling and\/or zone partitioning./d
/Dropped .* log messages in last .* seconds \(most recently, .* seconds ago\) due to excessive rate/d
/|WARN|.* execute ct.* failed/d"])
AT_CLEANUP

AT_SETUP([conntrack - more complex SNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
dnl Track all IP traffic, NAT existing connections.
priority=100 ip action=ct(table=1,zone=1,nat)
dnl
dnl Allow ARP, but generate responses for NATed addresses
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0 action=drop
dnl
dnl Allow any traffic from ns0->ns1. SNAT ns0 to 10.1.1.240-10.1.1.254
table=1 priority=100 in_port=1 ip ct_state=+trk+new-est action=ct(commit,zone=1,nat(src=10.1.1.240-10.1.1.254)),2
table=1 priority=100 in_port=1 ip ct_state=+trk-new+est action=2
dnl Only allow established traffic from ns1->ns0.
table=1 priority=100 in_port=2 ip ct_state=+trk-new+est action=1
table=1 priority=0 action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8 priority=100 reg2=0x0a0101f0/0xfffffff0 action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
dnl Zero result means not found.
table=8 priority=0 action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl ARP TPA IP in reg2.
table=10 priority=100 arp xreg0=0 action=normal
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=10 arp arp_op=1 action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl HTTP requests from p0->p1 should work fine.
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/' | uniq], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([conntrack - all-zero IP SNAT])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_ZEROIP_SNAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns0], [ip route add 172.1.1.0/24 via 10.1.1.2])

OVS_START_L7([at_ns1], [http])

AT_DATA([flows.txt], [dnl
table=0,priority=30,ct_state=-trk,ip,action=ct(table=0)
table=0,priority=20,ct_state=-rpl,ip,nw_dst=10.1.1.0/24,actions=ct(commit,nat(src=0.0.0.0),table=10)
table=0,priority=20,ct_state=+rpl,ip,nw_dst=10.1.1.0/24,actions=resubmit(,10)
table=0,priority=20,ip,nw_dst=172.1.1.2,actions=ct(commit,nat(dst=10.1.1.2),table=10)
table=0,priority=10,arp,action=normal
table=0,priority=1,action=drop
table=10,priority=20,ct_state=+rpl,ip,nw_dst=10.1.1.0/24 actions=ct(table=20,nat)
table=10,priority=10,ip,nw_dst=10.1.1.0/24 actions=resubmit(,20)
table=20,priority=10,ip,nw_dst=10.1.1.1,action=1
table=20,priority=10,ip,nw_dst=10.1.1.2,action=2
])
AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl - Test to make sure src nat is NOT done when not needed
NS_CHECK_EXEC([at_ns0], [echo "TEST" | nc -p 30000 10.1.1.2 80 > nc-1.log])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1,"], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=30000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=30000),protoinfo=(state=TIME_WAIT)
])

dnl - Test to make sure src nat is done when needed
NS_CHECK_EXEC([at_ns0], [echo "TEST2" | nc -p 30001 172.1.1.2 80 > nc-2.log])
NS_CHECK_EXEC([at_ns0], [echo "TEST3" | nc -p 30001 10.1.1.2 80 > nc-3.log])
AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 30001 | grep "orig=.src=10\.1\.1\.1," | sed -e 's/port=30001/port=<clnt_s_port>/g' -e 's/sport=80,dport=[[0-9]]\+/sport=80,dport=<rnd_port>/g' | sort], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<clnt_s_port>,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=<rnd_port>),protoinfo=(state=TIME_WAIT)
tcp,orig=(src=10.1.1.1,dst=172.1.1.2,sport=<clnt_s_port>,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=<clnt_s_port>),protoinfo=(state=TIME_WAIT)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([conntrack - simple DNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:88:88:88:88:88])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=100 in_port=1,ip,nw_dst=10.1.1.64,action=ct(zone=1,nat(dst=10.1.1.2),commit),2
priority=10 in_port=1,ip,action=ct(commit,zone=1),2
priority=100 in_port=2,ct_state=-trk,ip,action=ct(table=0,nat,zone=1)
priority=100 in_port=2,ct_state=+trk+est,ct_zone=1,ip,action=1
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a010140,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
dnl Zero result means not found.
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
table=10 priority=100 arp xreg0=0 action=normal
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Should work with the virtual IP address through NAT
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.64]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.64)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.64,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

dnl Should work with the assigned IP address as well
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - DNAT with additional SNAT])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns0], [ip route add 172.1.1.0/24 via 10.1.1.2])

OVS_START_L7([at_ns1], [http])

AT_DATA([flows.txt], [dnl
table=0,priority=30,in_port=1,ip,nw_dst=172.1.1.2,actions=ct(commit,nat(dst=10.1.1.2:80),table=1)
table=0,priority=20,in_port=2,ip,actions=ct(nat),1
table=0,priority=10,arp,actions=NORMAL
table=0,priority=1,actions=drop
dnl Be sure all ct() actions but src nat are executed
table=1,ip,actions=ct(commit,nat(src=10.1.1.240),exec(set_field:0xac->ct_mark,set_field:0xac->ct_label),table=2)
table=2,in_port=1,ip,ct_mark=0xac,ct_label=0xac,actions=2
])
AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([http://172.1.1.2:8080]), [0], [ignore], [ignore])

dnl - make sure only dst nat has been performed
AT_CHECK([ovs-appctl dpctl/dump-conntrack |  FORMAT_CT(10.1.1.240)], [0], [dnl
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=172.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),mark=172,labels=0xac,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - more complex DNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:88:88:88:88:88])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
dnl Track all IP traffic
table=0 priority=100 ip action=ct(table=1,zone=1,nat)
dnl
dnl Allow ARP, but generate responses for NATed addresses
table=0 priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
table=0 priority=10 arp action=normal
table=0 priority=0 action=drop
dnl
dnl Allow any IP traffic from ns0->ns1. DNAT ns0 from 10.1.1.64 to 10.1.1.2
table=1 priority=100 in_port=1 ct_state=+new ip nw_dst=10.1.1.64 action=ct(zone=1,nat(dst=10.1.1.2),commit),2
table=1 priority=10 in_port=1 ct_state=+new ip action=ct(commit,zone=1),2
table=1 priority=100 in_port=1 ct_state=+est ct_zone=1 action=2
dnl Only allow established traffic from ns1->ns0.
table=1 priority=100 in_port=2 ct_state=+est ct_zone=1 action=1
table=1 priority=0 action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a010140,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
dnl Zero result means not found.
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
table=10 priority=100 arp xreg0=0 action=normal
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Should work with the virtual IP address through NAT
OVS_START_L7([at_ns1], [http])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.64]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.64)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.64,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

dnl Should work with the assigned IP address as well
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([10.1.1.2]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP related with NAT])
AT_SKIP_IF([test $HAVE_NC = no])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow UDP traffic from ns0->ns1. Only allow related ICMP responses back.
dnl Make sure ICMP responses are reverse-NATted.
AT_DATA([flows.txt], [dnl
in_port=1,udp,action=ct(commit,nat(src=10.1.1.240-10.1.1.254),exec(set_field:1->ct_mark)),2
in_port=2,icmp,ct_state=-trk,action=ct(table=0,nat)
in_port=2,icmp,nw_dst=10.1.1.1,ct_state=+trk+rel,ct_mark=1,action=1
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a0101f0/0xfffffff0,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

rm p0.pcap
OVS_DAEMONIZE([tcpdump -n -U -i ovs-p0 -w p0.pcap], [tcpdump.pid])
sleep 1

dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response.
NS_CHECK_EXEC([at_ns0], [echo a | nc $NC_EOF_OPT -u 10.1.1.2 10000])

AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-flows br0 | ofctl_strip | sort | grep -v drop], [0], [dnl
 n_packets=1, n_bytes=42, priority=10,arp actions=NORMAL
 n_packets=1, n_bytes=44, udp,in_port=1 actions=ct(commit,nat(src=10.1.1.240-10.1.1.254),exec(set_field:0x1->ct_mark)),output:2
 n_packets=1, n_bytes=72, ct_state=+rel+trk,ct_mark=0x1,icmp,in_port=2,nw_dst=10.1.1.1 actions=output:1
 n_packets=1, n_bytes=72, ct_state=-trk,icmp,in_port=2 actions=ct(table=0,nat)
 n_packets=2, n_bytes=84, priority=100,arp,arp_op=1 actions=move:NXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
 table=10, n_packets=1, n_bytes=42, priority=10,arp,arp_op=1 actions=set_field:2->arp_op,move:NXM_NX_ARP_SHA[[]]->NXM_NX_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_NX_ARP_SHA[[]],move:NXM_OF_ARP_SPA[[]]->NXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->NXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],set_field:0->in_port,output:NXM_NX_REG3[[0..15]]
 table=10, n_packets=1, n_bytes=42, priority=100,arp,reg0=0,reg1=0 actions=NORMAL
 table=8, n_packets=1, n_bytes=42, priority=0 actions=set_field:0->xreg0
 table=8, n_packets=1, n_bytes=42, reg2=0xa0101f0/0xfffffff0 actions=set_field:0x808888888888->xreg0
OFPST_FLOW reply (OF1.5):
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/'], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>),mark=1
])

AT_CHECK([tcpdump -n -v "icmp" -r p0.pcap 2>/dev/null | grep -E 'wrong|bad'], [1], [ignore-nolog])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP related with SNAT])
AT_SKIP_IF([test $HAVE_NC = no])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
OVS_CHECK_MIN_KERNEL(6, 7)
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

dnl Allow IP traffic from ns0->ns1, rewrite source IP with SNAT to 10.1.1.254.
dnl Only allow related ICMP responses back and undo NAT to restore original IP.
AT_DATA([flows.txt], [dnl
ct_state=-trk,ip actions=ct(table=0)
ct_state=+trk,ip,in_port=1 actions=ct(commit,nat(src=10.1.1.254)),2
ct_state=+rel+trk,icmp,in_port=2,nw_dst=10.1.1.254 actions=ct(commit,table=1,nat)
dnl
dnl Handle ICMP related packets.
dnl These should match first rule with original IPs before SNAT.
dnl The second rule, which matches on the SNAT IP, shouldn't match any packets.
table=1,in_port=2,ct_state=+rel+trk,icmp,nw_src=10.1.1.2,nw_dst=10.1.1.1 action=1
table=1,in_port=2,ct_state=+rel+trk,icmp,nw_dst=10.1.1.254 action=goto_table:2
table=1,priority=0,action=drop
dnl
dnl Drop any ICMP related packets that incorrectly reach this table.
table=2,priority=0,action=drop
dnl
dnl ARP
priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
priority=10 arp action=normal
priority=0,action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a0101f0/0xfffffff0,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

rm p0.pcap
OVS_DAEMONIZE([tcpdump -n -U -i ovs-p0 -w p0.pcap], [tcpdump.pid])
sleep 1

dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response.
NS_CHECK_EXEC([at_ns0], [echo a | nc $NC_EOF_OPT -u 10.1.1.2 10000])

dnl Flush conntrack state.
dnl To verify related packets are handled exactly the same as before flushing.
AT_CHECK([ovs-appctl dpctl/flush-conntrack], [0])

dnl Solicit another "destination unreachable" response.
dnl To verify that after flushing, the same openflow rules are matched.
NS_CHECK_EXEC([at_ns0], [echo a | nc $NC_EOF_OPT -u 10.1.1.2 10000])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/'], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>)
])

AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-flows br0 | ofctl_strip | ofctl_strip_bytes | sort | grep -v drop], [0], [dnl
 n_packets=1, priority=10,arp actions=NORMAL
 n_packets=2, ct_state=+rel+trk,icmp,in_port=2,nw_dst=10.1.1.254 actions=ct(commit,table=1,nat)
 n_packets=2, ct_state=+trk,ip,in_port=1 actions=ct(commit,nat(src=10.1.1.254)),output:2
 n_packets=2, priority=100,arp,arp_op=1 actions=move:NXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
 n_packets=4, ct_state=-trk,ip actions=ct(table=0)
 table=1, ct_state=+rel+trk,icmp,in_port=2,nw_dst=10.1.1.254 actions=goto_table:2
 table=1, n_packets=2, ct_state=+rel+trk,icmp,in_port=2,nw_src=10.1.1.2,nw_dst=10.1.1.1 actions=output:1
 table=10, n_packets=1, priority=10,arp,arp_op=1 actions=set_field:2->arp_op,move:NXM_NX_ARP_SHA[[]]->NXM_NX_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_NX_ARP_SHA[[]],move:NXM_OF_ARP_SPA[[]]->NXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->NXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],set_field:0->in_port,output:NXM_NX_REG3[[0..15]]
 table=10, n_packets=1, priority=100,arp,reg0=0,reg1=0 actions=NORMAL
 table=8, n_packets=1, priority=0 actions=set_field:0->xreg0
 table=8, n_packets=1, reg2=0xa0101f0/0xfffffff0 actions=set_field:0x808888888888->xreg0
OFPST_FLOW reply (OF1.5):
])

AT_CHECK([tcpdump -n -v "icmp" -r p0.pcap 2>/dev/null | grep -E 'wrong|bad'], [1], [ignore-nolog])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

dnl CHECK_FTP_NAT(TITLE, IP_ADDR, FLOWS, CT_DUMP)
dnl
dnl Checks the implementation of conntrack with FTP ALGs in combination with
dnl NAT, using the provided flow table.
m4_define([CHECK_FTP_NAT],
   [AT_SETUP([conntrack - FTP $1])
    AT_SKIP_IF([test $HAVE_FTP = no])
    AT_SKIP_IF([test $HAVE_LFTP = no])
    CHECK_CONNTRACK()
    CHECK_CONNTRACK_NAT()
    CHECK_CONNTRACK_ALG()

    OVS_TRAFFIC_VSWITCHD_START()

    ADD_NAMESPACES(at_ns0, at_ns1)

    ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
    NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
    ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

    dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
    AT_DATA([flows.txt], [$3])

    AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

    OVS_START_L7([at_ns1], [ftp])

    dnl FTP requests from p0->p1 should work fine.
    AT_DATA([ftp.cmd], [dnl
set net:max-retries 1
set net:timeout 1
set ftp:passive-mode off
cache off
connect ftp://anonymous:@10.1.1.2
ls
ls
ls
ls
])
    NS_CHECK_EXEC([at_ns0], [lftp -f ftp.cmd > lftp.log])

    dnl Discards CLOSE_WAIT and CLOSING
    AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [$4])

    OVS_TRAFFIC_VSWITCHD_STOP
    AT_CLEANUP])

dnl CHECK_FTP_SNAT_PRE_RECIRC(TITLE, IP_ADDR, IP_ADDR_AS_HEX)
dnl
dnl Checks the implementation of conntrack with FTP ALGs in combination with
dnl NAT, with flow tables that implement the NATing as part of handling of
dnl initial incoming packets - ie, the first flow is ct(nat,table=foo).
dnl
dnl IP_ADDR must specify the NAT address in standard "10.1.1.x" format,
dnl and IP_ADDR_AS_HEX must specify the same address as hex, eg 0x0a0101xx.
m4_define([CHECK_FTP_SNAT_PRE_RECIRC], [dnl
    CHECK_FTP_NAT([SNAT prerecirc $1], [$2], [dnl
dnl track all IP traffic, de-mangle non-NEW connections
table=0 in_port=1, ip, action=ct(table=1,nat)
table=0 in_port=2, ip, action=ct(table=2,nat)
dnl
dnl ARP
dnl
table=0 priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
table=0 priority=10 arp action=normal
table=0 priority=0 action=drop
dnl
dnl Table 1: port 1 -> 2
dnl
dnl Allow new FTP connections. These need to be commited.
table=1 ct_state=+new, tcp, tp_dst=21, nw_src=10.1.1.1, action=ct(alg=ftp,commit,nat(src=$2)),2
dnl Allow established TCP connections, make sure they are NATted already.
table=1 ct_state=+est, tcp, nw_src=$2,     action=2
dnl
dnl Table 1: droppers
dnl
table=1 priority=10, tcp, action=drop
table=1 priority=0,action=drop
dnl
dnl Table 2: port 2 -> 1
dnl
dnl Allow established TCP connections, make sure they are reverse NATted
table=2 ct_state=+est, tcp, nw_dst=10.1.1.1, action=1
dnl Allow (new) related (data) connections.  These need to be commited.
table=2 ct_state=+new+rel, tcp, nw_dst=$2, action=ct(commit,nat),1
dnl Allow related ICMP packets, make sure they are reverse NATted
table=2 ct_state=+rel, icmp, nw_dst=10.1.1.1, action=1
dnl
dnl Table 2: droppers
dnl
table=2 priority=10, tcp, action=drop
table=2 priority=0, action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
dnl
table=8,reg2=$3/0xffffffff,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=$2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=$2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])
])

dnl Check that ct(nat,table=foo) works without TCP sequence adjustment.
CHECK_FTP_SNAT_PRE_RECIRC([], [10.1.1.9], [0x0a010109])

dnl Check that ct(nat,table=foo) works with TCP sequence adjustment.
dnl
dnl The FTP PORT command includes the ASCII representation of the address,
dnl so when these messages need to be NATed between addresses that have
dnl different lengths when represented in ASCII (such as the original address
dnl of 10.1.1.1 used in the test and 10.1.1.240 here), the FTP NAT ALG must
dnl resize the packet and adjust TCP sequence numbers. This test is kept
dnl separate from the above to easier identify issues in this code on different
dnl kernels.
CHECK_FTP_SNAT_PRE_RECIRC([seqadj], [10.1.1.240], [0x0a0101f0])

dnl CHECK_FTP_SNAT_POST_RECIRC(TITLE, IP_ADDR, IP_ADDR_AS_HEX)
dnl
dnl Checks the implementation of conntrack with FTP ALGs in combination with
dnl NAT, with flow tables that implement the NATing after the first round
dnl of recirculation - that is, the first flow ct(table=foo) then a subsequent
dnl flow will implement the NATing with ct(nat..),output:foo.
dnl
dnl IP_ADDR must specify the NAT address in standard "10.1.1.x" format,
dnl and IP_ADDR_AS_HEX must specify the same address as hex, eg 0x0a0101xx.
m4_define([CHECK_FTP_SNAT_POST_RECIRC], [dnl
    CHECK_FTP_NAT([SNAT postrecirc $1], [$2], [dnl
dnl track all IP traffic (this includes a helper call to non-NEW packets.)
table=0 ip, action=ct(table=1)
dnl
dnl ARP
dnl
table=0 priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
table=0 priority=10 arp action=normal
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new FTP connections. These need to be commited.
dnl This does helper for new packets.
table=1 in_port=1 ct_state=+new, tcp, tp_dst=21, action=ct(alg=ftp,commit,nat(src=$2)),2
dnl Allow and NAT established TCP connections
table=1 in_port=1 ct_state=+est, tcp,     action=ct(nat),2
table=1 in_port=2 ct_state=+est, tcp,     action=ct(nat),1
dnl Allow and NAT (new) related active (data) connections.
dnl These need to be commited.
table=1 in_port=2 ct_state=+new+rel, tcp, action=ct(commit,nat),1
dnl Allow related ICMP packets.
table=1 in_port=2 ct_state=+rel, icmp,    action=ct(nat),1
dnl Drop everything else.
table=1 priority=0, action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
dnl
table=8,reg2=$3/0xffffffff,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=$2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=$2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])
])

dnl Check that ct(nat,table=foo) works without TCP sequence adjustment.
CHECK_FTP_SNAT_POST_RECIRC([], [10.1.1.9], [0x0a010109])

dnl Check that ct(nat,table=foo) works with TCP sequence adjustment.
dnl
dnl The FTP PORT command includes the ASCII representation of the address,
dnl so when these messages need to be NATed between addresses that have
dnl different lengths when represented in ASCII (such as the original address
dnl of 10.1.1.1 used in the test and 10.1.1.240 here), the FTP NAT ALG must
dnl resize the packet and adjust TCP sequence numbers. This test is kept
dnl separate from the above to easier identify issues in this code on different
dnl kernels.
CHECK_FTP_SNAT_POST_RECIRC([seqadj], [10.1.1.240], [0x0a0101f0])


dnl CHECK_FTP_SNAT_ORIG_TUPLE(TITLE, IP_ADDR, IP_ADDR_AS_HEX)
dnl
dnl Checks the implementation of conntrack original direction tuple matching
dnl with FTP ALGs in combination with NAT, with flow tables that implement
dnl the NATing before the first round of recirculation - that is, the first
dnl flow ct(nat, table=foo) then a subsequent flow will implement the
dnl commiting of NATed and other connections with ct(nat..),output:foo.
dnl
dnl IP_ADDR must specify the NAT address in standard "10.1.1.x" format,
dnl and IP_ADDR_AS_HEX must specify the same address as hex, eg 0x0a0101xx.
m4_define([CHECK_FTP_SNAT_ORIG_TUPLE], [dnl
    CHECK_FTP_NAT([SNAT orig tuple $1], [$2], [dnl
dnl Store zone in reg4 and packet direction in reg3 (IN=1, OUT=2).
dnl NAT is only applied to OUT-direction packets, so that ACL
dnl processing can be done with non-NATted headers.
dnl
dnl Track all IP traffic in the IN-direction (IN from Port 1).
table=0 in_port=1, ip, action=set_field:1->reg4,set_field:1->reg3,ct(zone=NXM_NX_REG4[[0..15]],table=1)
dnl Track all IP traffic in the OUT-direction (OUT to the Port 1).
table=0 in_port=2, ip, action=set_field:1->reg4,set_field:2->reg3,ct(zone=NXM_NX_REG4[[0..15]],nat,table=1)
dnl
dnl ARP
dnl
table=0 priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
table=0 priority=10 arp action=normal
table=0 priority=0 action=drop
dnl
dnl Pass tracked traffic through ACL, drop everything else.
dnl Non-REPLY/RELATED packets get the ACL lookup with the packet headers
dnl in the actual packet direction in reg0 (IN=1, OUT=2).  REPLY packets
dnl get the ACL lookup using the conntrack tuple and the inverted direction.
dnl RELATED packets get ACL lookup using the conntrack tuple in the direction
dnl of the parent connection, as stored in ct_label[0].
dnl
dnl Incoming non-related packet in the original direction (ACL IN)
table=1 reg3=1, ip, ct_state=-rel-rpl+trk-inv action=set_field:1->reg0,resubmit(,3),goto_table:5
dnl Incoming non-related reply packet (CT ACL OUT)
table=1 reg3=1, ip, ct_state=-rel+rpl+trk-inv action=set_field:2->reg0,resubmit(,3,ct),goto_table:4
dnl Outgoing non-related packet (ACL OUT)
table=1 reg3=2, ip, ct_state=-rel-rpl+trk-inv action=set_field:2->reg0,resubmit(,3),goto_table:5
dnl Outgoing non-related reply packet (CT ACL IN)
table=1 reg3=2, ip, ct_state=-rel+rpl+trk-inv action=set_field:1->reg0,resubmit(,3,ct),goto_table:4
dnl
dnl Related packet (CT ACL in the direction of the parent connection.)
table=1 ip, ct_state=+rel+trk-inv, action=move:NXM_NX_CT_LABEL[[0]]->NXM_NX_REG0[[0]],resubmit(,3,ct),goto_table:4
dnl Drop everything else.
table=1 priority=0, action=drop
dnl
dnl "ACL table"
dnl
dnl Stateful accept (1->reg2) all incoming (reg0=1) IP connections with
dnl IP source address '10.1.1.1'.  Store rule ID (1234) in reg1, verdict
dnl in reg2.
table=3 priority=10, reg0=1, ip, nw_src=10.1.1.1 action=set_field:1234->reg1,set_field:1->reg2
dnl Stateless drop (0->reg2) everything else in both directions. (Rule ID: 1235)
table=3 priority=0, action=set_field:1235->reg1,set_field:0->reg2
dnl
dnl Re-process stateful traffic that was not accepted by a stateful rule as
dnl normal traffic in the current direction.  This should also delete the
dnl now stale conntrack state, so that new state can be created in it's place.
dnl
dnl Stateful accepts go to next table.
table=4 priority=100 reg2=1, action=goto_table:5
dnl Everything else is reprocessed disregarding the CT state, using the actual
dnl packet direction.
table=4 priority=0 action=move:NXM_NX_REG3[[]]->NXM_NX_REG0[[]],resubmit(,3),goto_table:5
dnl
dnl "ACL verdict processing table."
dnl
dnl Handle stateful (reg2=1) / stateless (reg2=2) accepts and drops (reg2=0)
dnl
dnl Drop all non-accepted packets.
table=5 reg2=0 priority=1000 action=drop
dnl
dnl Commit new incoming FTP control connections with SNAT range.  Must match on
dnl 'tcp' when setting 'alg=ftp'.  Store the directionality of non-related
dnl connections to ct_label[0]  Store the rule ID to ct_label[96..127].
table=5 priority=100 reg2=1 reg3=1 ct_state=+new-rel, tcp, tp_dst=21, action=ct(zone=NXM_NX_REG4[[0..15]],alg=ftp,commit,nat(src=$2),exec(move:NXM_NX_REG3[[0]]->NXM_NX_CT_LABEL[[0]],move:NXM_NX_REG1[[0..31]]->NXM_NX_CT_LABEL[[96..127]])),goto_table:6
dnl Commit other new incoming non-related IP connections with SNAT range.
table=5 priority=10 reg2=1 reg3=1 ct_state=+new-rel, ip, action=ct(zone=NXM_NX_REG4[[0..15]],commit,nat(src=$2),exec(move:NXM_NX_REG3[[0]]->NXM_NX_CT_LABEL[[0]],move:NXM_NX_REG1[[0..31]]->NXM_NX_CT_LABEL[[96..127]])),goto_table:6
dnl Commit non-related outgoing new IP connections with DNAT range.
dnl (This should not get any packets in this test.)
table=5 priority=10 reg2=1 reg3=2 ct_state=+new-rel, ip, action=ct(zone=NXM_NX_REG4[[0..15]],commit,nat(dst=$2),exec(move:NXM_NX_REG3[[0]]->NXM_NX_CT_LABEL[[0]],move:NXM_NX_REG1[[0..31]]->NXM_NX_CT_LABEL[[96..127]])),goto_table:6
dnl Commit new related connections in either direction, which need 'nat'
dnl and which inherit the label (the direction of the original direction
dnl parent tuple) from the parent connection.
table=5 priority=10 reg2=1 ct_state=+new+rel, ip, action=ct(zone=NXM_NX_REG4[[0..15]],commit,nat,exec(move:NXM_NX_REG1[[0..31]]->NXM_NX_CT_LABEL[[96..127]])),goto_table:6
dnl
dnl NAT incoming non-NEW packets. Outgoing packets were NATted in table 0.
dnl
table=5 priority=10 ct_state=-new+trk-inv reg3=1 ip, action=ct(zone=NXM_NX_REG4[[0..15]],nat),goto_table:6
dnl Forward everything else, including stateless accepts.
table=5 priority=0 action=goto_table:6
dnl
dnl "Forwarding table"
dnl
table=6 in_port=1 action=2
table=6 in_port=2 action=1
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
dnl
table=8,reg2=$3,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=100 arp xreg0=0 action=normal
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=drop
], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=$2,sport=<cleared>,dport=<cleared>),zone=1,labels=0x4d2000000000000000000000001,protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=$2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),zone=1,labels=0x4d2000000000000000000000001,protoinfo=(state=<cleared>)
])
])

dnl Check that ct(nat,table=foo) works without TCP sequence adjustment with
dnl an ACL table based on matching on conntrack original direction tuple only.
CHECK_FTP_SNAT_ORIG_TUPLE([], [10.1.1.9], [0x0a010109])

dnl Check that ct(nat,table=foo) works with TCP sequence adjustment with
dnl an ACL table based on matching on conntrack original direction tuple only.
CHECK_FTP_SNAT_ORIG_TUPLE([seqadj], [10.1.1.240], [0x0a0101f0])

AT_SETUP([conntrack - IPv4 FTP Passive with SNAT])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.240 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1.
AT_DATA([flows.txt], [dnl
dnl track all IPv4 traffic and NAT any established traffic.
table=0 priority=10 ip, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new FTP control connections.
table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21  action=ct(alg=ftp,commit,nat(src=10.1.1.240)),2
dnl Allow related TCP connections from port 1.
table=1 in_port=1 ct_state=+new+rel tcp nw_src=10.1.1.1 action=ct(commit,nat),2
dnl Allow established TCP connections both ways, post-NAT match.
table=1 in_port=1 ct_state=+est tcp nw_src=10.1.1.240 action=2
table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1

dnl Allow ICMP both ways.
table=1 priority=100 in_port=1 icmp, action=2
table=1 priority=100 in_port=2 icmp, action=1
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Check that the stacks working to avoid races.
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([10.1.1.2]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 FTP Passive with DNAT])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.240 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.1.240/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1.
AT_DATA([flows.txt], [dnl
dnl track all IPv4 traffic and NAT any established traffic.
table=0 priority=10 ip, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new FTP control connections.
table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.1.240)),2
dnl Allow related TCP connections from port 1.
table=1 in_port=1 ct_state=+new+rel tcp nw_src=10.1.1.1 action=ct(commit,nat),2
dnl Allow established TCP connections both ways, post-NAT match.
table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.1.240 action=2
table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1

dnl Allow ICMP both ways.
table=1 priority=100 in_port=1 icmp, action=2
table=1 priority=100 in_port=2 icmp, action=1
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Check that the stacks working to avoid races.
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.240 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([10.1.1.2]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.240,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.240,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 FTP Passive with DNAT 2])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/16")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.200 e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.100.1 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.100.1/16")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1.
AT_DATA([flows.txt], [dnl
dnl track all IPv4 traffic and NAT any established traffic.
table=0 priority=10 ip, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new FTP control connections.
table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.100.1)),2
dnl Allow related TCP connections from port 1.
table=1 in_port=1 ct_state=+new+rel tcp nw_src=10.1.1.1 action=ct(commit,nat),2
dnl Allow established TCP connections both ways, post-NAT match.
table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.100.1 action=2
table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1

dnl Allow ICMP both ways.
table=1 priority=100 in_port=1 icmp, action=2
table=1 priority=100 in_port=2 icmp, action=1
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Check that the stacks working to avoid races.
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.100.1 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([10.1.1.200]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.200)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.200,sport=<cleared>,dport=<cleared>),reply=(src=10.1.100.1,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.200,sport=<cleared>,dport=<cleared>),reply=(src=10.1.100.1,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 FTP Active with DNAT])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.240 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.1.240/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1.
AT_DATA([flows.txt], [dnl
dnl track all IPv4 traffic and NAT any established traffic.
table=0 priority=10 ip, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new FTP control connections.
table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.1.240)),2
dnl Allow related TCP connections from port 1.
table=1 in_port=2 ct_state=+new+rel tcp nw_src=10.1.1.240 action=ct(commit,nat),1
dnl Allow established TCP connections both ways, post-NAT match.
table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.1.240 action=2
table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1

dnl Allow ICMP both ways.
table=1 priority=100 in_port=1 icmp, action=2
table=1 priority=100 in_port=2 icmp, action=1
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Check that the stacks working to avoid races.
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.240 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.1.2]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.240,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.240,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 FTP Active with DNAT with reverse skew])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/16")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.120.240 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.1.2/16")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1.
AT_DATA([flows.txt], [dnl
dnl track all IPv4 traffic and NAT any established traffic.
table=0 priority=10 ip, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new FTP control connections.
table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.1.2)),2
dnl Allow related TCP connections from port 1.
table=1 in_port=2 ct_state=+new+rel tcp nw_src=10.1.1.2 action=ct(commit,nat),1
dnl Allow established TCP connections both ways, post-NAT match.
table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.1.2 action=2
table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1

dnl Allow ICMP both ways.
table=1 priority=100 in_port=1 icmp, action=2
table=1 priority=100 in_port=2 icmp, action=1
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Check that the stacks working to avoid races.
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([10.1.120.240]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.120.240)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.120.240,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.120.240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 HTTP with SNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::240 lladdr 80:88:88:88:88:88 dev p1])
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::241 lladdr 80:88:88:88:88:88 dev p1])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=1,action=drop
priority=10,icmp6,action=normal
priority=100,in_port=1,ip6,action=ct(commit,nat(src=fc00::240-fc00::241)),2
priority=100,in_port=2,ct_state=-trk,ip6,action=ct(nat,table=0)
priority=100,in_port=2,ct_state=+trk+est,ip6,action=1
priority=200,in_port=2,ct_state=+trk+new,icmp6,icmpv6_code=0,icmpv6_type=135,nd_target=fc00::240,action=ct(commit,nat(dst=fc00::1)),1
priority=200,in_port=2,ct_state=+trk+new,icmp6,icmpv6_code=0,icmpv6_type=135,nd_target=fc00::241,action=ct(commit,nat(dst=fc00::1)),1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

dnl HTTP requests from ns0->ns1 should work fine.
OVS_START_L7([at_ns1], [http6])

NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([[http://[[fc00::2]]]]), [0], [ignore], [ignore])

dnl HTTP requests from ns1->ns0 should fail due to network failure.
dnl Try 3 times, in 1 second intervals.
OVS_START_L7([at_ns0], [http6])
NS_CHECK_EXEC([at_ns1], OVS_GET_HTTP([[http://[[fc00::1]]]]), [28], [ignore], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 HTTP with DNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")
NS_CHECK_EXEC([at_ns0], [ip -6 link set dev p0 address 80:88:88:88:88:77])
NS_CHECK_EXEC([at_ns1], [ip -6 link set dev p1 address 80:88:88:88:88:88])
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::240 lladdr 80:88:88:88:88:88 dev p0])
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::1 lladdr 80:88:88:88:88:77 dev p1])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=100 in_port=1,ip6,ipv6_dst=fc00::240,action=ct(zone=1,nat(dst=fc00::2),commit),2
priority=100 in_port=2,ct_state=-trk,ip6,action=ct(table=0,nat,zone=1)
priority=100 in_port=2,ct_state=+trk+est,ct_zone=1,ip6,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::240])

NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -W 2 fc00::240 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Should work with the virtual IP address through NAT
OVS_START_L7([at_ns1], [http6])
NS_CHECK_EXEC([at_ns0], OVS_GET_HTTP([[http://[[fc00::240]]]]), [0], [ignore], [ignore])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::1)], [0], [dnl
icmpv6,orig=(src=fc00::1,dst=fc00::240,id=<cleared>,type=128,code=0),reply=(src=fc00::2,dst=fc00::1,id=<cleared>,type=129,code=0),zone=1
tcp,orig=(src=fc00::1,dst=fc00::240,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>),zone=1,protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 ICMP6 Related with SNAT])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")
NS_CHECK_EXEC([at_ns0], [ip -6 link set dev p0 address 80:88:88:88:88:77])
NS_CHECK_EXEC([at_ns1], [ip -6 link set dev p1 address 80:88:88:88:88:88])

NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::2 lladdr 80:88:88:88:88:88 dev p0])
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::3 lladdr 80:88:88:88:88:88 dev p0])
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::240 lladdr 80:88:88:88:88:77 dev p1])
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::1 lladdr 80:88:88:88:88:77 dev p1])

NS_CHECK_EXEC([at_ns0], [ip -6 route add default via fc00::2])

dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
priority=100 in_port=1,ip6,action=ct(nat(src=fc00::240),commit),2
priority=100 in_port=2,ct_state=-trk,ip6,action=ct(table=0,nat)
priority=100 in_port=2,ct_state=+trk+est,ip6,action=1
priority=100 in_port=2,ct_state=+trk+rel,ip6,action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])

AT_CHECK([ovs-appctl dpctl/flush-conntrack])

rm p0.pcap
OVS_DAEMONIZE([tcpdump -n -U -i ovs-p0 -w p0.pcap], [tcpdump.pid])
sleep 1

dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response.
NS_CHECK_EXEC([at_ns0], [echo a | nc -6 $NC_EOF_OPT -u fc00::2 1])

AT_CHECK([tcpdump -n -v "icmp6" -r p0.pcap 2>/dev/null | grep -E 'wrong|bad'], [1], [ignore-nolog])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMPv6 related NAT with single port])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96", "f0:00:00:01:01:01", [], "nodad")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", "f0:00:00:01:01:02", [], "nodad")

AT_DATA([flows.txt], [dnl
table=0,ipv6,ct_state=-trk,actions=ct(table=0,nat)
table=0,in_port=ovs-p0,ct_state=+trk+new,udp6,actions=ct(commit,nat(dst=[[fc00::2]]:8080)),ovs-p1
table=0,in_port=ovs-p1,ct_state=+trk+rel+rpl,icmp6,actions=ovs-p0
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

rm p0.pcap
NETNS_DAEMONIZE([at_ns0], [tcpdump -n -l -U -i p0 -w p0.pcap 2> tcpdump0_err], [tcpdump0.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump0_err])

dnl Send UDP packet from [[fc00::1]]:1234 to [[fc00::240]]:80
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-p0,packet=f00000010102f0000001010186dd60066ced00151140fc000000000000000000000000000001fc00000000000000000000000000024004d20050001587d4646573745f756e72656163680a,actions=resubmit(,0)"])
dnl Send "destination unreachable" response
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-p1,packet=f00000010101f0000001010286dd600733ed00453a40fc000000000000000000000000000002fc000000000000000000000000000001010428550000000060066ced00151140fc000000000000000000000000000001fc00000000000000000000000000000204d21f9000156ad2646573745f756e72656163680a,actions=resubmit(,0)"])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=fc00::1," | sort], [0], [dnl
udp,orig=(src=fc00::1,dst=fc00::240,sport=1234,dport=80),reply=(src=fc00::2,dst=fc00::1,sport=8080,dport=1234)
])

OVS_WAIT_UNTIL([ovs-pcap p0.pcap | grep -q "f00000010101f0000001010286dd600733ed00453a40fc000000000000000000000000000240fc000000000000000000000000000001010426170000000060066ced00151140fc000000000000000000000000000001fc00000000000000000000000000024004d20050001587d4646573745f756e72656163680a"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 FTP with SNAT])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")
dnl Would be nice if NAT could translate neighbor discovery messages, too.
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::240 lladdr 80:88:88:88:88:88 dev p1])

dnl Allow any traffic from ns0->ns1.
dnl Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
dnl track all IPv6 traffic (this includes NAT & help to non-NEW packets.)
table=0 priority=10 ip6, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new TCPv6 FTP control connections.
table=1 in_port=1 ct_state=+new tcp6 ipv6_src=fc00::1 tp_dst=21  action=ct(alg=ftp,commit,nat(src=fc00::240)),2
dnl Allow related TCPv6 connections from port 2 to the NATted address.
table=1 in_port=2 ct_state=+new+rel tcp6 ipv6_dst=fc00::240 action=ct(commit,nat),1
dnl Allow established TCPv6 connections both ways, enforce NATting
table=1 in_port=1 ct_state=+est tcp6 ipv6_src=fc00::240   action=2
table=1 in_port=2 ct_state=+est tcp6 ipv6_dst=fc00::1     action=1
dnl Allow other ICMPv6 both ways (without commit).
table=1 priority=100 in_port=1 icmp6, action=2
table=1 priority=100 in_port=2 icmp6, action=1
dnl Drop everything else.
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([[[[fc00::2]]]], [--ipv6]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>),reply=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 FTP Passive with SNAT])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:88:88:88:88:99])
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::2 lladdr 80:88:88:88:88:99 dev p0])
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::240 lladdr 80:88:88:88:88:88 dev p1])

dnl Allow any traffic from ns0->ns1.
dnl Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
dnl track all IPv6 traffic (this includes NAT & help to non-NEW packets.)
table=0 priority=10 ip6, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow new TCPv6 FTP control connections.
table=1 in_port=1 ct_state=+new tcp6 ipv6_src=fc00::1 tp_dst=21  action=ct(alg=ftp,commit,nat(src=fc00::240)),2
dnl Allow related TCPv6 connections from port 1.
table=1 in_port=1 ct_state=+new+rel tcp6 ipv6_dst=fc00::2 action=ct(commit,nat),2
dnl Allow established TCPv6 connections both ways, enforce NATting
table=1 in_port=1 ct_state=+est tcp6 ipv6_src=fc00::240 action=2
table=1 in_port=2 ct_state=+est tcp6 ipv6_dst=fc00::1 action=1
dnl Allow other ICMPv6 both ways (without commit).
table=1 priority=100 in_port=1 icmp6, action=2
table=1 priority=100 in_port=2 icmp6, action=1
dnl Drop everything else.
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2 >/dev/null])

OVS_START_L7([at_ns1], [ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP([[[[fc00::2]]]], [--ipv6]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv6 FTP with SNAT - orig tuple])
AT_SKIP_IF([test $HAVE_FTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88])
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")
dnl Would be nice if NAT could translate neighbor discovery messages, too.
NS_CHECK_EXEC([at_ns1], [ip -6 neigh add fc00::240 lladdr 80:88:88:88:88:88 dev p1])

dnl Allow any traffic from ns0->ns1.
dnl Only allow nd, return traffic from ns1->ns0.
AT_DATA([flows.txt], [dnl
dnl track all IPv6 traffic (this includes NAT & help to non-NEW packets.)
table=0 priority=10 ip6, action=ct(nat,table=1)
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl
dnl Allow other ICMPv6 both ways (without commit).
table=1 priority=100 in_port=1 icmp6, action=2
table=1 priority=100 in_port=2 icmp6, action=1
dnl Allow new TCPv6 FTP control connections.
table=1 priority=10 in_port=1 ct_state=+new+trk-inv tcp6 ct_nw_proto=6 ct_ipv6_src=fc00::1 ct_tp_dst=21  action=ct(alg=ftp,commit,nat(src=fc00::240)),2
dnl Allow related TCPv6 connections from port 2 to the NATted address.
table=1 priority=10 in_port=2 ct_state=+new+rel+trk-inv ipv6 ct_nw_proto=6 ct_ipv6_src=fc00::1 ct_tp_dst=21 action=ct(commit,nat),1
dnl Allow established TCPv6 connections both ways, enforce NATting
table=1 priority=10 in_port=1 ct_state=+est+trk-inv ipv6 ct_nw_proto=6 ct_ipv6_src=fc00::1 ct_tp_dst=21 action=2
table=1 priority=10 in_port=2 ct_state=+est+trk-inv ipv6 ct_nw_proto=6 ct_ipv6_src=fc00::1 ct_tp_dst=21 action=1
dnl Drop everything else.
table=1 priority=0, action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Linux seems to take a little time to get its IPv6 stack in order. Without
dnl waiting, we get occasional failures due to the following error:
dnl "connect: Cannot assign requested address"
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2 >/dev/null])

NETNS_DAEMONIZE([at_ns1], [[$PYTHON3 $srcdir/test-l7.py ftp]], [ftp0.pid])
OVS_WAIT_UNTIL([ip netns exec at_ns1 netstat -l | grep ftp])

dnl FTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], OVS_GET_FTP_ACTIVE([[[[fc00::2]]]], [--ipv6]), [0], [ignore], [ignore])

dnl Discards CLOSE_WAIT and CLOSING
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
tcp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
tcp,orig=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>),reply=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - IPv4 TFTP with SNAT])
AT_SKIP_IF([test $HAVE_TFTP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_ALG()

OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22])

ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11])
NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.240 e6:66:c1:11:11:11])

dnl Allow any traffic from ns0->ns1.
AT_DATA([flows.txt], [dnl
dnl track all IPv4 traffic.
table=0 priority=10 ip, action=ct(table=1)
dnl drop everything else.
table=0 priority=0 action=drop
dnl
dnl Table 1
dnl Allow ICMP both ways.
table=1 priority=100 in_port=1 icmp, action=2
table=1 priority=100 in_port=2 icmp, action=1
dnl
dnl Allow new TFTP control connections.
table=1 in_port=1 ct_state=+new udp nw_src=10.1.1.1 tp_dst=69  action=ct(alg=tftp,commit,nat(src=10.1.1.240)),2
dnl Allow related UDP connections from port 1.
table=1 in_port=2 ct_state=+new+rel udp nw_src=10.1.1.2 action=ct(commit,nat),1
dnl Allow established and NAT them.
table=1 in_port=1 ct_state=+est udp nw_src=10.1.1.1 action=ct(nat,table=2)
table=1 in_port=2 ct_state=+est udp nw_src=10.1.1.2 action=ct(nat,table=2)
dnl
table=1 priority=0, action=drop
dnl
table=2 in_port=1 ct_state=+est udp nw_src=10.1.1.240 action=2
table=2 in_port=2 ct_state=+est udp nw_dst=10.1.1.1 action=1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Check that the stacks working to avoid races.
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2 >/dev/null])

OVS_START_L7([at_ns0], [tftp])
OVS_START_L7([at_ns1], [tftp])

dnl TFTP requests from p0->p1 should work fine.
NS_CHECK_EXEC([at_ns0], [[curl $CURL_OPT tftp://10.1.1.2/flows.txt -o foo 2>curl0.log]])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),helper=tftp
udp,orig=(src=10.1.1.2,dst=10.1.1.240,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - DNAT load balancing])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns1, at_ns2, at_ns3, at_ns4)

ADD_VETH(p1, at_ns1, br0, "10.1.1.1/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.2/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.3/24")
ADD_VETH(p4, at_ns4, br0, "10.1.1.4/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:88:88:88:88:11])
NS_CHECK_EXEC([at_ns2], [ip link set dev p2 address 80:88:88:88:88:22])
NS_CHECK_EXEC([at_ns3], [ip link set dev p3 address 80:88:88:88:88:33])
NS_CHECK_EXEC([at_ns4], [ip link set dev p4 address 80:88:88:88:88:44])

dnl Select group for load balancing.  One bucket per server.  Each bucket
dnl tracks and NATs the connection and recirculates to table 4 for egress
dnl routing.  Packets of existing connections are always NATted based on
dnl connection state, only new connections are NATted according to the
dnl specific NAT parameters in each bucket.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-group br0 "group_id=234,type=select,bucket=weight=100,ct(nat(dst=10.1.1.2),commit,table=4),bucket=weight=100,ct(nat(dst=10.1.1.3),commit,table=4),bucket=weight=100,ct(nat(dst=10.1.1.4),commit,table=4)"])

AT_DATA([flows.txt], [dnl
dnl Track connections to the virtual IP address.
table=0 priority=100 ip nw_dst=10.1.1.64 action=group:234
dnl All other IP traffic is allowed but the connection state is no commited.
table=0 priority=90 ip action=ct(table=4,nat)
dnl
dnl Allow ARP, but generate responses for virtual addresses
table=0 priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
table=0 priority=10 arp action=normal
table=0 priority=0 action=drop
dnl
dnl Routing table
dnl
table=4,ip,nw_dst=10.1.1.1 action=mod_dl_dst:80:88:88:88:88:11,output:1
table=4,ip,nw_dst=10.1.1.2 action=mod_dl_dst:80:88:88:88:88:22,output:2
table=4,ip,nw_dst=10.1.1.3 action=mod_dl_dst:80:88:88:88:88:33,output:3
table=4,ip,nw_dst=10.1.1.4 action=mod_dl_dst:80:88:88:88:88:44,output:4
table=4 priority=0 action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a010140,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
dnl Zero result means not found.
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
table=10 priority=100 arp xreg0=0 action=normal
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=controller
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Start web servers
OVS_START_L7([at_ns2], [http])
OVS_START_L7([at_ns3], [http])
OVS_START_L7([at_ns4], [http])

on_exit 'ovs-ofctl -O OpenFlow15 dump-flows br0'
on_exit 'ovs-appctl revalidator/purge'
on_exit 'ovs-appctl dpif/dump-flows br0'

dnl Should work with the virtual IP address through NAT
for i in $(seq 1 50); do
    echo Request $i
    NS_CHECK_EXEC([at_ns1], OVS_GET_HTTP([10.1.1.64]), [0], [ignore], [ignore])
done

dnl Each server should have at least one connection.
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.64)], [0], [dnl
tcp,orig=(src=10.1.1.1,dst=10.1.1.64,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.64,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.3,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
tcp,orig=(src=10.1.1.1,dst=10.1.1.64,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.4,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
])

ovs-appctl dpif/dump-flows br0
ovs-appctl revalidator/purge
ovs-ofctl -O OpenFlow15 dump-flows br0
ovs-ofctl -O OpenFlow15 dump-group-stats br0

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([conntrack - DNAT load balancing with NC])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns1, at_ns2, at_ns3, at_ns4, at_ns5)

ADD_VETH(p1, at_ns1, br0, "10.1.1.1/24")
ADD_VETH(p2, at_ns2, br0, "10.1.1.2/24")
ADD_VETH(p3, at_ns3, br0, "10.1.1.3/24")
ADD_VETH(p4, at_ns4, br0, "10.1.1.4/24")
ADD_VETH(p5, at_ns5, br0, "10.1.1.5/24")
NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:88:88:88:88:11])
NS_CHECK_EXEC([at_ns2], [ip link set dev p2 address 80:88:88:88:88:22])
NS_CHECK_EXEC([at_ns3], [ip link set dev p3 address 80:88:88:88:88:33])
NS_CHECK_EXEC([at_ns4], [ip link set dev p4 address 80:88:88:88:88:44])
NS_CHECK_EXEC([at_ns5], [ip link set dev p5 address 80:88:88:88:88:55])

dnl Select group for load balancing.  One bucket per server.  Each bucket
dnl tracks and NATs the connection and recirculates to table 4 for egress
dnl routing.  Packets of existing connections are always NATted based on
dnl connection state, only new connections are NATted according to the
dnl specific NAT parameters in each bucket.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-group br0 "group_id=234,type=select,bucket=weight=100,ct(nat(dst=10.1.1.2),commit,table=4),bucket=weight=100,ct(nat(dst=10.1.1.3),commit,table=4),bucket=weight=100,ct(nat(dst=10.1.1.4),commit,table=4)"])

AT_DATA([flows.txt], [dnl
dnl Track connections to the virtual IP address.
table=0 priority=100 ip nw_dst=10.1.1.64 action=group:234
dnl All other IP traffic is allowed but the connection state is no commited.
table=0 priority=90 ip action=ct(table=4,nat)
dnl
dnl Allow ARP, but generate responses for virtual addresses
table=0 priority=100 arp arp_op=1 action=move:OXM_OF_ARP_TPA[[]]->NXM_NX_REG2[[]],resubmit(,8),goto_table:10
table=0 priority=10 arp action=normal
table=0 priority=0 action=drop
dnl
dnl Routing table
dnl
table=4,ip,nw_dst=10.1.1.1 action=mod_dl_dst:80:88:88:88:88:11,output:1
table=4,ip,nw_dst=10.1.1.2 action=mod_dl_dst:80:88:88:88:88:22,output:2
table=4,ip,nw_dst=10.1.1.3 action=mod_dl_dst:80:88:88:88:88:33,output:3
table=4,ip,nw_dst=10.1.1.4 action=mod_dl_dst:80:88:88:88:88:44,output:4
table=4,ip,nw_dst=10.1.1.5 action=mod_dl_dst:80:88:88:88:88:55,output:5
table=4 priority=0 action=drop
dnl
dnl MAC resolution table for IP in reg2, stores mac in OXM_OF_PKT_REG0
table=8,reg2=0x0a010140,action=load:0x808888888888->OXM_OF_PKT_REG0[[]]
dnl Zero result means not found.
table=8,priority=0,action=load:0->OXM_OF_PKT_REG0[[]]
dnl ARP responder mac filled in at OXM_OF_PKT_REG0, or 0 for normal action.
dnl TPA IP in reg2.
table=10 priority=100 arp xreg0=0 action=normal
dnl Swaps the fields of the ARP message to turn a query to a response.
table=10 priority=10,arp,arp_op=1,action=load:2->OXM_OF_ARP_OP[[]],move:OXM_OF_ARP_SHA[[]]->OXM_OF_ARP_THA[[]],move:OXM_OF_PKT_REG0[[0..47]]->OXM_OF_ARP_SHA[[]],move:OXM_OF_ARP_SPA[[]]->OXM_OF_ARP_TPA[[]],move:NXM_NX_REG2[[]]->OXM_OF_ARP_SPA[[]],move:NXM_OF_ETH_SRC[[]]->NXM_OF_ETH_DST[[]],move:OXM_OF_PKT_REG0[[0..47]]->NXM_OF_ETH_SRC[[]],move:NXM_OF_IN_PORT[[]]->NXM_NX_REG3[[0..15]],load:0->NXM_OF_IN_PORT[[]],output:NXM_NX_REG3[[0..15]]
table=10 priority=0 action=controller
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl Start web servers
OVS_START_L7([at_ns2], [http])
OVS_START_L7([at_ns3], [http])
OVS_START_L7([at_ns4], [http])

on_exit 'ovs-ofctl -O OpenFlow15 dump-flows br0'
on_exit 'ovs-appctl revalidator/purge'
on_exit 'ovs-appctl dpif/dump-flows br0'

sleep 5

dnl Should work with the virtual IP address through NAT
for i in 1 2 3 4 5 6 7 8 9; do
    echo Request $i
    NS_CHECK_EXEC([at_ns1], [echo "TEST1" | nc -p 4100$i 10.1.1.64 80 > nc-1-$i.log])
    NS_CHECK_EXEC([at_ns5], [echo "TEST5" | nc -p 4100$i 10.1.1.64 80 > nc-5-$i.log])
done

conntrack -L 2>&1

ovs-appctl dpif/dump-flows br0
ovs-appctl revalidator/purge
ovs-ofctl -O OpenFlow15 dump-flows br0
ovs-ofctl -O OpenFlow15 dump-group-stats br0

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - floating IP])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_CT_CLEAR()

ADD_NAMESPACES(at_ns0, at_ns1)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01") dnl FIP 10.254.254.1
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02") dnl FIP 10.254.254.2

dnl Static ARPs
NS_CHECK_EXEC([at_ns0], [ip neigh add 10.1.1.2 lladdr f0:00:00:01:01:02 dev p0])
NS_CHECK_EXEC([at_ns1], [ip neigh add 10.1.1.1 lladdr f0:00:00:01:01:01 dev p1])

dnl Static ARP and route entries for the FIP "gateway"
NS_CHECK_EXEC([at_ns0], [ip neigh add 10.1.1.254 lladdr f0:00:00:01:01:FE dev p0])
NS_CHECK_EXEC([at_ns1], [ip neigh add 10.1.1.254 lladdr f0:00:00:01:01:FE dev p1])
NS_CHECK_EXEC([at_ns0], [ip route add default nexthop via 10.1.1.254])
NS_CHECK_EXEC([at_ns1], [ip route add default nexthop via 10.1.1.254])

NETNS_DAEMONIZE([at_ns0], [nc -l -k 1234 > /dev/null], [nc0.pid])

AT_DATA([flows.txt], [dnl
table=0,priority=10  ip action=ct(table=1)
table=0,priority=1   action=drop
dnl dst FIP
table=1,priority=20  ip,ct_state=+trk+est,nw_dst=10.254.254.0/24 action=goto_table:10
table=1,priority=20  ip,ct_state=+trk+new,nw_dst=10.254.254.0/24 action=ct(commit,table=10)
dnl dst local
table=1,priority=10  ip,ct_state=+trk+est action=goto_table:20
table=1,priority=10  ip,ct_state=+trk+new action=ct(commit,table=20)
table=1,priority=1   ip,ct_state=+trk+inv action=drop
dnl
dnl FIP translation (dst FIP, src local) --> (dst local, src FIP)
table=10             ip,nw_dst=10.254.254.1 action=set_field:10.1.1.1->nw_dst,goto_table:11
table=10             ip,nw_dst=10.254.254.2 action=set_field:10.1.1.2->nw_dst,goto_table:11
table=11             ip,nw_src=10.1.1.1 action=set_field:10.254.254.1->nw_src,goto_table:12
table=11             ip,nw_src=10.1.1.2 action=set_field:10.254.254.2->nw_src,goto_table:12
dnl clear conntrack and do another lookup since we changed the tuple
table=12,priority=10 ip action=ct_clear,ct(table=13)
table=12,priority=1  action=drop
table=13             ip,ct_state=+trk+est action=goto_table:20
table=13             ip,ct_state=+trk+new action=ct(commit,table=20)
table=13             ip,ct_state=+trk+inv action=drop
dnl
dnl Output
table=20             ip,nw_src=10.1.1.1 action=set_field:f0:00:00:01:01:01->eth_src,goto_table:21
table=20             ip,nw_src=10.1.1.2 action=set_field:f0:00:00:01:01:02->eth_src,goto_table:21
table=20             ip,nw_src=10.254.254.0/24 action=set_field:f0:00:00:01:01:FE->eth_src,goto_table:21
table=21             ip,nw_dst=10.1.1.1 action=set_field:f0:00:00:01:01:01->eth_dst,output:ovs-p0
table=21             ip,nw_dst=10.1.1.2 action=set_field:f0:00:00:01:01:02->eth_dst,output:ovs-p1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl non-FIP case
NS_CHECK_EXEC([at_ns1], [echo "foobar" |nc $NC_EOF_OPT 10.1.1.1 1234])
OVS_WAIT_UNTIL([[ovs-appctl dpctl/dump-conntrack | sed -e 's/port=[0-9]*/port=<cleared>/g' -e 's/id=[0-9]*/id=<cleared>/g' |
grep "tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=TIME_WAIT)"
]])

dnl Check that the full session ends as expected (i.e. TIME_WAIT). Otherwise it
dnl means the datapath didn't process the ct_clear action. Ending in SYN_RECV
dnl (OVS maps to ESTABLISHED) means the initial frame was committed, but not a
dnl second time after the FIP translation (because ct_clear didn't occur).
NS_CHECK_EXEC([at_ns1], [echo "foobar" |nc $NC_EOF_OPT 10.254.254.1 1234])
OVS_WAIT_UNTIL([[ovs-appctl dpctl/dump-conntrack | sed -e 's/port=[0-9]*/port=<cleared>/g' -e 's/id=[0-9]*/id=<cleared>/g' |
grep "tcp,orig=(src=10.254.254.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.254.254.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=TIME_WAIT)"
]])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - negative test for recirculation optimization])
dnl This test will fail if 'conn' caching is being used, because the tuple
dnl has been changed outside of conntrack.
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_CT_CLEAR()

ADD_NAMESPACES(at_ns0, at_ns1)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01") dnl FIP 10.254.254.1
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02") dnl FIP 10.254.254.2

dnl Static ARPs
NS_CHECK_EXEC([at_ns0], [ip neigh add 10.1.1.2 lladdr f0:00:00:01:01:02 dev p0])
NS_CHECK_EXEC([at_ns1], [ip neigh add 10.1.1.1 lladdr f0:00:00:01:01:01 dev p1])

dnl Static ARP and route entries for the FIP "gateway"
NS_CHECK_EXEC([at_ns0], [ip neigh add 10.1.1.254 lladdr f0:00:00:01:01:FE dev p0])
NS_CHECK_EXEC([at_ns1], [ip neigh add 10.1.1.254 lladdr f0:00:00:01:01:FE dev p1])
NS_CHECK_EXEC([at_ns0], [ip route add default nexthop via 10.1.1.254])
NS_CHECK_EXEC([at_ns1], [ip route add default nexthop via 10.1.1.254])

NETNS_DAEMONIZE([at_ns0], [nc -l -k 1234 > /dev/null], [nc0.pid])

AT_DATA([flows.txt], [dnl
table=0,priority=10  ip action=ct(table=1)
dnl dst FIP
table=1,priority=20  ip,ct_state=+trk+est,nw_dst=10.254.254.0/24 action=goto_table:2
table=1,priority=20  ip,ct_state=+trk+new,nw_dst=10.254.254.0/24 action=ct(commit,exec(set_field:1->ct_mark),table=2)
dnl
dnl FIP translation (dst FIP, src local) --> (dst local, src FIP)
table=2             ip,nw_dst=10.254.254.1 action=set_field:10.1.1.1->nw_dst,goto_table:3
table=2             ip,nw_dst=10.254.254.2 action=set_field:10.1.1.2->nw_dst,goto_table:3
table=3             ip,nw_src=10.1.1.1 action=set_field:10.254.254.1->nw_src,goto_table:4
table=3             ip,nw_src=10.1.1.2 action=set_field:10.254.254.2->nw_src,goto_table:4
table=4             ip,nw_dst=10.1.1.1 action=set_field:f0:00:00:01:01:01->eth_dst,goto_table:5
table=4             ip,nw_dst=10.1.1.2 action=set_field:f0:00:00:01:01:02->eth_dst,goto_table:5
table=5             ip,nw_src=10.254.254.0/24 action=set_field:f0:00:00:01:01:FE->eth_src,goto_table:6
dnl
dnl Tuple has been changed outside of conntrack
table=6,priority=10 ip action=ct(table=7)
dnl
table=7             ip,ct_state=+trk+est action=goto_table:8
table=7             ip,ct_mark=0x0,ct_state=+trk+new action=ct(commit,exec(set_field:2->ct_mark),table=8)
dnl
table=8             ip,nw_dst=10.1.1.1 action=output:ovs-p0
table=8             ip,nw_dst=10.1.1.2 action=output:ovs-p1
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

NS_CHECK_EXEC([at_ns1], [echo "foobar" |nc $NC_EOF_OPT 10.254.254.1 1234])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.254.254)], [0], [dnl
tcp,orig=(src=10.1.1.2,dst=10.254.254.1,sport=<cleared>,dport=<cleared>),reply=(src=10.254.254.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),mark=1,protoinfo=(state=<cleared>)
tcp,orig=(src=10.254.254.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.254.254.2,sport=<cleared>,dport=<cleared>),mark=2,protoinfo=(state=<cleared>)
])

ovs-appctl dpif/dump-flows br0

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - Multiple ICMP traverse])
dnl This tracks sending ICMP packets via conntrack multiple times for the
dnl same packet
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_CT_CLEAR()

ADD_NAMESPACES(at_ns0, at_ns1)
ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
dnl setup ct flows
AT_DATA([flows.txt], [dnl
table=0,priority=10  ip,icmp,ct_state=-trk action=ct(zone=1,table=1)
table=0,priority=0   action=drop
table=1,priority=10  ct_state=-est+trk+new,ip,ct_zone=1,in_port=1 action=ct(commit,table=2)
table=1,priority=10  ct_state=+est-new+trk,ct_zone=1,in_port=1 action=resubmit(,2)
table=1,priority=0   action=drop
table=2,priority=10  ct_state=+trk+new,in_port=1 action=drop
table=2,priority=10  ct_state=+trk+est action=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

m4_define([ICMP_PKT], [m4_join([,],
  [eth_src=f0:00:00:01:01:01,eth_dst=f0:00:00:01:01:02,eth_type=0x0800],
  [nw_src=10.1.1.1,nw_dst=10.1.1.2],
  [nw_proto=1,nw_ttl=64,nw_frag=no],
  [icmp_type=8,icmp_code=0])])

# Sending ICMP packets, first and second.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT' '')], [0], [ignore])

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'ICMP_PKT' '')], [0], [ignore])

sleep 1

dnl ensure CT picked up the packet
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0)
])

AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE | sed 's/n_bytes=70,/n_bytes=84,/'],
         [0], [dnl
 cookie=0x0, duration=<cleared>, table=2, n_packets=2, n_bytes=84, idle_age=<cleared>, priority=10,ct_state=+new+trk,in_port=1 actions=drop
 cookie=0x0, duration=<cleared>, table=2, n_packets=0, n_bytes=0, idle_age=<cleared>, priority=10,ct_state=+est+trk actions=drop
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - can match and clear ct_state from outside OVS])
CHECK_EXTERNAL_CT()
CHECK_CONNTRACK_LOCAL_STACK()
OVS_CHECK_GENEVE()

OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-underlay], [set bridge br-underlay other-config:hwaddr=\"f0:00:00:01:01:02\"])

AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=100,ct_state=+trk,actions=ct_clear,resubmit(,0)"])
AT_CHECK([ovs-ofctl add-flow br-underlay "priority=10,actions=normal"])

ADD_EXTERNAL_CT([br0])
ADD_NAMESPACES(at_ns0)

dnl Set up underlay link from host into the namespace using veth pair.
ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24", "f0:00:00:01:01:01")
AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
AT_CHECK([ip link set dev br-underlay up])

dnl Set up tunnel endpoints on OVS outside the namespace and with a native
dnl linux device inside the namespace.
ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24])
ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24],
                  [vni 0])

dnl First, check the underlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Okay, now check the overlay
NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl Confirm that the ct_state and ct_clear action found its way to the dp
AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep ct_clear | sort | dnl
          grep 'eth(src=f0:00:00:01:01:02,dst=f0:00:00:01:01:01)' | dnl
          strip_stats | strip_used | dnl
          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
                     [0], [dnl
recirc_id(0),in_port(br-underlay),ct_state(+trk),eth(src=f0:00:00:01:01:02,dst=f0:00:00:01:01:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct_clear,ovs-p0
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - ICMP from different source related with NAT])
AT_SKIP_IF([test $HAVE_NC = no])
AT_SKIP_IF([test $HAVE_TCPDUMP = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(client, server)

ADD_VETH(client, client, br0, "192.168.20.10/24", "00:00:00:00:20:10")
ADD_VETH(server, server, br0, "192.168.10.20/24", "00:00:00:00:10:20")

dnl Send traffic from client to CT, do DNAT if the traffic is new otherwise send it to server
AT_DATA([flows.txt], [dnl
table=0,ip,actions=ct(table=1,zone=42,nat)
table=1,in_port=ovs-client,ip,ct_state=+trk+new,actions=ct(commit,table=2,zone=42,nat(dst=192.168.10.20)
table=1,icmp,ct_state=+trk+rel-rpl,actions=ct(commit,table=2,zone=42,nat)
table=1,ip,actions=resubmit(,2)
table=2,in_port=ovs-client,ip,ct_state=+trk+new,actions=output:ovs-server
table=2,in_port=ovs-client,icmp,ct_state=+trk+rel,actions=output:ovs-server
table=2,in_port=ovs-server,icmp,ct_state=+trk+rel,actions=output:ovs-client
table=2,in_port=ovs-server,ip,ct_state=+trk+rpl,actions=output:ovs-client
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

rm server.pcap
NETNS_DAEMONIZE([server], [tcpdump -n -l -U -i server -w server.pcap 2>tcpdump0_err], [tcpdump0.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump0_err])

dnl Send UDP client->server
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-client,\
packet=00000000102000000000201008004500001C000040000A11C762C0A8140AC0A814140001000200080000,actions=resubmit(,0)"])
dnl Send UDP response server->client
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-server,\
packet=00000000201000000000102008004500001C000040000A11D162C0A80A14C0A8140A0002000100080000,actions=resubmit(,0)"])
dnl Fake router sending ICMP need frag router->server
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-client,\
packet=000000001020000000002000080045000038011F0000FF011140C0A81401C0A814140304F778000005784500001C000040000A11C762C0A81414C0A8140A0002000100080000,\
actions=resubmit(,0)"
])

AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-flows br0 | ofctl_strip | sort ], [0], [dnl
 n_packets=3, n_bytes=154, reset_counts ip actions=ct(table=1,zone=42,nat)
 table=1, n_packets=1, n_bytes=42, reset_counts ct_state=+new+trk,ip,in_port=1 actions=ct(commit,table=2,zone=42,nat(dst=192.168.10.20))
 table=1, n_packets=1, n_bytes=42, reset_counts ip actions=resubmit(,2)
 table=1, n_packets=1, n_bytes=70, reset_counts ct_state=+rel-rpl+trk,icmp actions=ct(commit,table=2,zone=42,nat)
 table=2, n_packets=1, n_bytes=42, reset_counts ct_state=+new+trk,ip,in_port=1 actions=output:2
 table=2, n_packets=1, n_bytes=42, reset_counts ct_state=+rpl+trk,ip,in_port=2 actions=output:1
 table=2, n_packets=1, n_bytes=70, reset_counts ct_state=+rel+trk,icmp,in_port=1 actions=output:2
 table=2, reset_counts ct_state=+rel+trk,icmp,in_port=2 actions=output:1
OFPST_FLOW reply (OF1.5):
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "192.168.20.10"], [0], [dnl
udp,orig=(src=192.168.20.10,dst=192.168.20.20,sport=1,dport=2),reply=(src=192.168.10.20,dst=192.168.20.10,sport=2,dport=1),zone=42
])

OVS_WAIT_UNTIL([ovs-pcap server.pcap | grep 000000001020000000002000])

AT_CHECK([ovs-pcap server.pcap | grep 000000001020000000002000], [0], [dnl
000000001020000000002000080045000038011f0000ff011b40c0a81401c0a80a140304f778000005784500001c000040000a11d162c0a80a14c0a8140a0002000100080000
])

dnl Check the ICMP error in reply direction
AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=42])

rm client.pcap
NETNS_DAEMONIZE([client], [tcpdump -n -l -U -i client -w client.pcap 2>tcpdump1_err], [tcpdump1.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump1_err])

dnl Send UDP client->server
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-client,\
packet=00000000102000000000201008004500001C000040000A11C762C0A8140AC0A814140001000200080000,actions=resubmit(,0)"])
dnl Fake router sending ICMP need frag router->client
AT_CHECK([ovs-ofctl packet-out br0 "in_port=ovs-server,\
packet=000000002010000000002000080045000038011F0000FF01114AC0A81401C0A8140A0304F778000005784500001C000040000A11D162C0A8140AC0A80A140001000200080000,\
actions=resubmit(,0)"
])

AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-flows br0 | ofctl_strip | sort ], [0], [dnl
 n_packets=5, n_bytes=266, reset_counts ip actions=ct(table=1,zone=42,nat)
 table=1, n_packets=1, n_bytes=70, reset_counts ct_state=+rel-rpl+trk,icmp actions=ct(commit,table=2,zone=42,nat)
 table=1, n_packets=2, n_bytes=112, reset_counts ip actions=resubmit(,2)
 table=1, n_packets=2, n_bytes=84, reset_counts ct_state=+new+trk,ip,in_port=1 actions=ct(commit,table=2,zone=42,nat(dst=192.168.10.20))
 table=2, n_packets=1, n_bytes=42, reset_counts ct_state=+rpl+trk,ip,in_port=2 actions=output:1
 table=2, n_packets=1, n_bytes=70, reset_counts ct_state=+rel+trk,icmp,in_port=1 actions=output:2
 table=2, n_packets=1, n_bytes=70, reset_counts ct_state=+rel+trk,icmp,in_port=2 actions=output:1
 table=2, n_packets=2, n_bytes=84, reset_counts ct_state=+new+trk,ip,in_port=1 actions=output:2
OFPST_FLOW reply (OF1.5):
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "192.168.20.10"], [0], [dnl
udp,orig=(src=192.168.20.10,dst=192.168.20.20,sport=1,dport=2),reply=(src=192.168.10.20,dst=192.168.20.10,sport=2,dport=1),zone=42
])

OVS_WAIT_UNTIL([ovs-pcap client.pcap | grep 000000002010000000002000])

AT_CHECK([ovs-pcap client.pcap | grep 000000002010000000002000], [0], [dnl
000000002010000000002000080045000038011f0000ff011137c0a81414c0a8140a0304f778000005784500001c000040000a11c762c0a8140ac0a814140001000200080000
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([conntrack - Flush many conntrack entries by port])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_DATA([flows.txt], [dnl
priority=100,in_port=1,udp,action=ct(zone=1,commit),2
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])

dnl 20 packets from port 1 and 1 packet from port 2.
flow_l3="\
    eth_src=50:54:00:00:00:09,eth_dst=50:54:00:00:00:0a,dl_type=0x0800,\
    nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_proto=17,nw_ttl=64,nw_frag=no"

for i in $(seq 1 20); do
    frame=$(ovs-ofctl compose-packet --bare "$flow_l3, udp_src=1,udp_dst=$i")
    AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=$frame actions=resubmit(,0)"])
done
frame=$(ovs-ofctl compose-packet --bare "$flow_l3, udp_src=2,udp_dst=1")
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=$frame actions=resubmit(,0)"])

: > conntrack

for i in $(seq 1 20); do
    echo "udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=${i}),reply=(src=10.1.1.2,dst=10.1.1.1,sport=${i},dport=1),zone=1" >> conntrack
done
echo "udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=2,dport=1),reply=(src=10.1.1.2,dst=10.1.1.1,sport=1,dport=2),zone=1" >> conntrack

sort conntrack > expout

AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=1 | grep -F "src=10.1.1.1," | sort ], [0], [expout])

dnl Check that flushing conntrack by port 1 flush all ct for port 1 but keeps ct for port 2.
AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1 'ct_nw_proto=17,ct_tp_src=1'])
AT_CHECK([ovs-appctl dpctl/dump-conntrack zone=1 | grep -F "src=10.1.1.1," | sort ], [0], [dnl
udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=2,dport=1),reply=(src=10.1.1.2,dst=10.1.1.1,sport=1,dport=2),zone=1
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([IGMP])

AT_SETUP([IGMP - flood under normal action])

OVS_TRAFFIC_VSWITCHD_START()
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")

AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"])

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl
f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
00 00 00 00 > /dev/null])

AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep -e .*ipv4 | sort | dnl
          strip_stats | strip_used | strip_recirc | dnl
          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
                     [0], [dnl
recirc_id(<recirc>),in_port(ovs-p1),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,ovs-p2
])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([IGMP - forward with ICMP])

OVS_TRAFFIC_VSWITCHD_START()
ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")

AT_DATA([flows.txt], [dnl
table=0, arp actions=NORMAL
table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
table=0, in_port=2 actions=output:1
table=1, ip,ct_state=+trk+inv actions=drop
table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
])
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
00 00 00 00 > /dev/null])

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl
01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])

sleep 1

dnl Prefer the OpenFlow rules, because different datapaths will behave slightly
dnl differently with respect to the exact dp rules.
dnl
dnl This is also why we clear n_bytes / n_packets - some kernels with ipv6
dnl enabled will bump some of these counters non-deterministically

AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl
          strip_duration | grep -v arp | grep -v n_packets=0 | dnl
          grep -v 'in_port=2 actions=output:1' | dnl
          sed 's/n_bytes=[[0-9]]*/n_bytes=0/
               s/idle_age=[[0-9]]*/idle_age=0/
               s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl
 cookie=0x0,  table=0, n_packets=0, n_bytes=0, idle_age=0, ip,in_port=1 actions=ct(table=1,zone=64000)
 cookie=0x0,  table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,icmp,in_port=1 actions=output:2
 cookie=0x0,  table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,ip,in_port=1 actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([802.1ad])

AT_SETUP([802.1ad - vlan_limit])
OVS_CHECK_GITHUB_ACTION()
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

ADD_SVLAN(p0, at_ns0, 4094, "10.255.2.1/24")
ADD_SVLAN(p1, at_ns1, 4094, "10.255.2.2/24")

ADD_CVLAN(p0.4094, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p1.4094, at_ns1, 100, "10.2.2.2/24")

AT_CHECK([ovs-ofctl add-flow br0 "priority=1 action=normal"])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])

dnl CVLAN traffic should match the flow and drop
AT_CHECK([ovs-appctl revalidator/purge])
AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:vlan-limit=1])
AT_CHECK([ovs-ofctl add-flow br0 "priority=100 dl_type=0x8100 action=drop"])
NS_CHECK_EXEC([at_ns0], [ping -q -c 1 -W 3 10.2.2.2], [1], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([802.1ad - push/pop outer 802.1ad])
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_BR([br1])
ADD_BR([br2])
ADD_NAMESPACES(at_ns0, at_ns1)

AT_CHECK([ip link add ovs-p0 type veth peer name ovs-p1])
AT_CHECK([ip link set dev ovs-p0 up])
AT_CHECK([ip link set dev ovs-p1 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p0])
AT_CHECK([ovs-vsctl add-port br1 ovs-p1])
on_exit 'ip link del ovs-p0'

AT_CHECK([ip link add ovs-p2 type veth peer name ovs-p3])
AT_CHECK([ip link set dev ovs-p2 up])
AT_CHECK([ip link set dev ovs-p3 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p2])
AT_CHECK([ovs-vsctl add-port br2 ovs-p3])
on_exit 'ip link del ovs-p2'

ADD_VETH(p4, at_ns0, br1, "10.1.1.1/24")
ADD_VETH(p5, at_ns1, br2, "10.1.1.2/24")
ADD_CVLAN(p4, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p5, at_ns1, 100, "10.2.2.2/24")

AT_DATA([flows-br0.txt], [dnl
priority=1 action=drop
priority=100 in_port=1 action=push_vlan:0x88a8,mod_vlan_vid=4094,output:2
priority=100 in_port=2 action=push_vlan:0x88a8,mod_vlan_vid=4094,output:1
])

AT_DATA([flows-customer-br.txt], [dnl
priority=1 action=normal
priority=100 in_port=1 vlan_tci=0x1000/0x1000 action=pop_vlan,normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
AT_CHECK([ovs-ofctl --bundle add-flows br1 flows-customer-br.txt])
AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([802.1ad - push/pop outer 802.1q])
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_BR([br1])
ADD_BR([br2])
ADD_NAMESPACES(at_ns0, at_ns1)

AT_CHECK([ip link add ovs-p0 type veth peer name ovs-p1])
AT_CHECK([ip link set dev ovs-p0 up])
AT_CHECK([ip link set dev ovs-p1 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p0])
AT_CHECK([ovs-vsctl add-port br1 ovs-p1])
on_exit 'ip link del ovs-p0'

AT_CHECK([ip link add ovs-p2 type veth peer name ovs-p3])
AT_CHECK([ip link set dev ovs-p2 up])
AT_CHECK([ip link set dev ovs-p3 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p2])
AT_CHECK([ovs-vsctl add-port br2 ovs-p3])
on_exit 'ip link del ovs-p2'

ADD_VETH(p4, at_ns0, br1, "10.1.1.1/24")
ADD_VETH(p5, at_ns1, br2, "10.1.1.2/24")
ADD_CVLAN(p4, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p5, at_ns1, 100, "10.2.2.2/24")

AT_DATA([flows-br0.txt], [dnl
priority=1 action=drop
priority=100 in_port=1 action=push_vlan:0x8100,mod_vlan_vid=4094,output:2
priority=100 in_port=2 action=push_vlan:0x8100,mod_vlan_vid=4094,output:1
])

AT_DATA([flows-customer-br.txt], [dnl
priority=1 action=normal
priority=100 in_port=1 vlan_tci=0x1000/0x1000 action=pop_vlan,normal
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
AT_CHECK([ovs-ofctl --bundle add-flows br1 flows-customer-br.txt])
AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([802.1ad - 802.1q tunnel])
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_BR([br1])
ADD_BR([br2])
ADD_NAMESPACES(at_ns0, at_ns1)

AT_CHECK([ip link add ovs-p0 type veth peer name ovs-p1])
AT_CHECK([ip link set dev ovs-p0 up])
AT_CHECK([ip link set dev ovs-p1 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p0])
AT_CHECK([ovs-vsctl add-port br1 ovs-p1])
on_exit 'ip link del ovs-p0'

AT_CHECK([ip link add ovs-p2 type veth peer name ovs-p3])
AT_CHECK([ip link set dev ovs-p2 up])
AT_CHECK([ip link set dev ovs-p3 up])
AT_CHECK([ovs-vsctl add-port br0 ovs-p2])
AT_CHECK([ovs-vsctl add-port br2 ovs-p3])
on_exit 'ip link del ovs-p2'

ADD_VETH(p4, at_ns0, br1, "10.1.1.1/24")
ADD_VETH(p5, at_ns1, br2, "10.1.1.2/24")
ADD_CVLAN(p4, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p5, at_ns1, 100, "10.2.2.2/24")
ADD_CVLAN(p4, at_ns0, 200, "10.3.2.1/24")
ADD_CVLAN(p5, at_ns1, 200, "10.3.2.2/24")
ADD_CVLAN(p4, at_ns0, 300, "10.4.2.1/24")
ADD_CVLAN(p5, at_ns1, 300, "10.4.2.2/24")

AT_CHECK([ovs-ofctl add-flow br0 action=normal])
AT_CHECK([ovs-ofctl add-flow br1 action=normal])
AT_CHECK([ovs-ofctl add-flow br2 action=normal])
AT_CHECK([ovs-vsctl set port ovs-p0 vlan_mode=dot1q-tunnel tag=4094 cvlans=100,200])
AT_CHECK([ovs-vsctl set port ovs-p2 vlan_mode=dot1q-tunnel tag=4094 cvlans=100,200])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.3.2.2])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.3.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.3.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

dnl CVLAN 300 is not permitted by dot1q-tunnel
NS_CHECK_EXEC([at_ns0], [ping -q -c 1 -W 3 10.4.2.2], [1], [ignore])

OVS_TRAFFIC_VSWITCHD_STOP(["/dropping VLAN \(0\|300\) packet received on dot1q-tunnel port/d"])
AT_CLEANUP

AT_SETUP([802.1ad - double vlan match])
OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0])
OVS_CHECK_8021AD()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

ADD_SVLAN(p0, at_ns0, 4094, "10.255.2.1/24")
ADD_SVLAN(p1, at_ns1, 4094, "10.255.2.2/24")

ADD_CVLAN(p0.4094, at_ns0, 100, "10.2.2.1/24")
ADD_CVLAN(p1.4094, at_ns1, 100, "10.2.2.2/24")

AT_DATA([flows-br0.txt], [dnl
table=0,priority=1                action=drop
table=0,priority=100 dl_vlan=4094 action=pop_vlan,goto_table:1
table=1,priority=100 dl_vlan=100  action=push_vlan:0x88a8,mod_vlan_vid:4094,normal
])
AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])

OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2])

NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -W 2 10.2.2.2 | FORMAT_PING], [0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_BANNER([nsh-datapath])

AT_SETUP([nsh - encap header])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "0.0.0.0")
ADD_VETH(p1, at_ns1, br0, "0.0.0.0")

dnl The flow will encap a nsh header to the TCP syn packet
dnl eth/ip/tcp --> OVS --> eth/nsh/eth/ip/tcp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,ip,actions=encap(nsh(md_type=1)),set_field:0x1234->nsh_spi,set_field:0x11223344->nsh_c1,encap(ethernet),set_field:f2:ff:00:00:00:02->dl_dst,set_field:f2:ff:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([TCP_SYN_PKT], [m4_join([,],
  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
  [nw_proto=6,nw_ttl=64,nw_frag=no],
  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

dnl Send the TCP SYN packet from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')], [0], [ignore])

m4_define([NSH_HEADER], [m4_join([,],
  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
  [nsh_ttl=63,nsh_np=3,nsh_spi=0x1234,nsh_si=255],
  [nsh_mdtype=1,nsh_c1=0x11223344])])

OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'NSH_HEADER'),
    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([nsh - decap header])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "0.0.0.0")
ADD_VETH(p1, at_ns1, br0, "0.0.0.0")

dnl The flow will decap a nsh header which in turn carries a TCP syn packet
dnl eth/nsh/eth/ip/tcp --> OVS --> eth/ip/tcp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,dl_type=0x894f, actions=decap(),decap(), ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([TCP_SYN_PKT], [m4_join([,],
  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
  [nw_proto=6,nw_ttl=64,nw_frag=no],
  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

m4_define([NSH_HEADER], [m4_join([,],
  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
  [nsh_ttl=63,nsh_np=3,nsh_spi=0x1234,nsh_si=255],
  [nsh_mdtype=1,nsh_c1=0x11223344])])

dnl Send the NSH packet with TCP SYN payload from p0(at_ns0) interface directed
dnl to p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER')" \
    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
  [0], [ignore])

dnl Check the expected de-capsulated TCP packet on the egress interface
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
    "^$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')\$"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([nsh - replace header])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "0.0.0.0")
ADD_VETH(p1, at_ns1, br0, "0.0.0.0")

dnl The flow will decap a nsh header and encap a new nsh header
dnl eth/nsh-X/eth/ip/tcp --> OVS --> eth/nsh-Y/eth/ip/tcp
dnl The flow will add another NSH header with nsh_spi=0x101, nsh_si=4,
dnl nsh_ttl=7 and change the md1 context
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x03,actions=decap(),decap(),encap(nsh(md_type=1)),set_field:0x07->nsh_ttl,set_field:0x0101->nsh_spi,set_field:0x04->nsh_si,set_field:0x100f0e0d->nsh_c1,set_field:0x0c0b0a09->nsh_c2,set_field:0x08070605->nsh_c3,set_field:0x04030201->nsh_c4,encap(ethernet),set_field:f2:ff:00:00:00:02->dl_dst,set_field:f2:ff:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

m4_define([TCP_SYN_PKT], [m4_join([,],
  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
  [nw_proto=6,nw_ttl=64,nw_frag=no],
  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

m4_define([NSH_HEADER_1], [m4_join([,],
  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
  [nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=3,nsh_mdtype=1],
  [nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])

dnl Send the NSH packet with TCP SYN payload from p0(at_ns0) interface directed
dnl to p1(at_ns1) interface.
dnl The nsh_ttl is 8, nsh_spi is 0x100 and nsh_si is 3.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1')" \
    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
  [0], [ignore])

m4_define([NSH_HEADER_2], [m4_join([,],
  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
  [nsh_ttl=7,nsh_np=3,nsh_spi=0x101,nsh_si=4,nsh_mdtype=1],
  [nsh_c1=0x100f0e0d,nsh_c2=0x0c0b0a09,nsh_c3=0x08070605,nsh_c4=0x04030201])])

dnl Check the expected NSH packet with new fields in the header.
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'NSH_HEADER_2'),
    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([nsh - forward])
OVS_TRAFFIC_VSWITCHD_START()

ADD_NAMESPACES(at_ns0, at_ns1, at_ns2)

ADD_VETH(p0, at_ns0, br0, "0.0.0.0")
ADD_VETH(p1, at_ns1, br0, "0.0.0.0")
ADD_VETH(p2, at_ns2, br0, "0.0.0.0")

dnl Push two flows to OVS. #1 will check on SPI=0X100, SI=2 and send the
dnl packet to at_ns1. #2 will check on SPI=0X100, SI=1 and send the
dnl packet to to at_ns2.
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x02,actions=ovs-p1"])
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x01,actions=ovs-p2"])

NETNS_DAEMONIZE([at_ns1],
  [tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
NETNS_DAEMONIZE([at_ns2],
  [tcpdump -l -n -xx -U -i p2 -w p2.pcap 2>tcpdump2_err], [tcpdump2.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump2_err])

m4_define([TCP_SYN_PKT], [m4_join([,],
  [eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
  [nw_src=192.168.0.10,nw_dst=10.0.0.10],
  [nw_proto=6,nw_ttl=64,nw_frag=no],
  [tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2.
m4_define([NSH_HEADER_1], [m4_join([,],
  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
  [nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=2,nsh_mdtype=1],
  [nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1')" \
    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
  [0], [ignore])

dnl Check for the above packet on p1 interface.
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'NSH_HEADER_1'),
    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

dnl Send the second packet from at_ns1 --> OVS with SPI=0x100 and SI=1.
m4_define([NSH_HEADER_2], [m4_join([,],
  [eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
  [nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=1,nsh_mdtype=1],
  [nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])

NS_CHECK_EXEC([at_ns1], [$PYTHON3 $srcdir/sendpkt.py p1 \
    "$(ovs-ofctl compose-packet --bare 'NSH_HEADER_2')" \
    "$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
  [0], [ignore])

dnl Check for the above packet on p2 interface.
OVS_WAIT_UNTIL([ovs-pcap p2.pcap | grep -q "m4_join([], [^],
    $(ovs-ofctl compose-packet --bare 'NSH_HEADER_2'),
    $(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_BANNER([local-sampling])

m4_define([SAMPLE_ACTION],
    [sample(probability=65535,collector_set_id=$1,obs_domain_id=$2,obs_point_id=$3)]dnl
)

AT_SETUP([psample - sanity check])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_PSAMPLE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \
                    -- create Flow_Sample_Collector_Set id=1 bridge=@br0 \
                       local-group-id=10 \
                    -- create Flow_Sample_Collector_Set id=2 bridge=@br0 \
                       local-group-id=12],
         [0], [ignore])

AT_DATA([flows.txt], [dnl
arp actions=NORMAL
in_port=ovs-p0,ip actions=SAMPLE_ACTION(1, 2853183536, 2856341600),ovs-p1
in_port=ovs-p1,ip actions=SAMPLE_ACTION(2, 3138396208, 3141554272),ovs-p0
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

OVS_DAEMONIZE([ovstest test-psample > psample.out], [psample.pid])
OVS_WAIT_UNTIL([grep -q "Listening for psample events" psample.out])

NS_CHECK_EXEC([at_ns0], [ping -q -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

AT_CHECK([ovs-appctl dpctl/dump-flows -m --names], [0], [stdout])
AT_CHECK([grep -q 'actions:psample(group=10,cookie=0xaa102030aa405060),ovs-p1' stdout])
AT_CHECK([grep -q 'actions:psample(group=12,cookie=0xbb102030bb405060),ovs-p0' stdout])

m4_define([SAMPLE1], [m4_join([ ],
    [group_id=0xa,prob=4294967295],
    [obs_domain=0xaa102030,obs_point=0xaa405060],
    [.*icmp.*nw_src=10.1.1.1,nw_dst=10.1.1.2])])

m4_define([SAMPLE2], [m4_join([ ],
    [group_id=0xc,prob=4294967295],
    [obs_domain=0xbb102030,obs_point=0xbb405060],
    [.*icmp.*nw_src=10.1.1.2,nw_dst=10.1.1.1])])

OVS_WAIT_UNTIL([grep -qE 'SAMPLE1' psample.out])
OVS_WAIT_UNTIL([grep -qE 'SAMPLE2' psample.out])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([psample - sanity check IPv6])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_PSAMPLE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "fc00::1/96")
ADD_VETH(p1, at_ns1, br0, "fc00::2/96")

AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \
                    -- create Flow_Sample_Collector_Set id=1 bridge=@br0 \
                       local-group-id=10 \
                    -- create Flow_Sample_Collector_Set id=2 bridge=@br0 \
                       local-group-id=12],
         [0], [ignore])

AT_DATA([flows.txt], [dnl
priority=100,in_port=ovs-p0,ip6,icmp6,icmpv6_type=128 actions=SAMPLE_ACTION(1, 2853183536, 2856341600),ovs-p1
priority=100,in_port=ovs-p1,ip6,icmp6,icmpv6_type=129 actions=SAMPLE_ACTION(2, 3138396208, 3141554272),ovs-p0
priority=0 actions=NORMAL
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

OVS_DAEMONIZE([ovstest test-psample > psample.out], [psample.pid])
OVS_WAIT_UNTIL([grep -q "Listening for psample events" psample.out])

OVS_WAIT_UNTIL_EQUAL([ip netns exec at_ns0 ping6 -I fc00::1 -q -W 2 -c 1 fc00::2 | FORMAT_PING], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms])

AT_CHECK([ovs-appctl dpctl/dump-flows -m --names], [0], [stdout])
AT_CHECK([grep -q 'actions:psample(group=10,cookie=0xaa102030aa405060),ovs-p1' stdout])
AT_CHECK([grep -q 'actions:psample(group=12,cookie=0xbb102030bb405060),ovs-p0' stdout])

m4_define([SAMPLE1], [m4_join([ ],
    [group_id=0xa,prob=4294967295],
    [obs_domain=0xaa102030,obs_point=0xaa405060],
    [.*icmp6.*ipv6_src=fc00::1,ipv6_dst=fc00::2])])
m4_define([SAMPLE2], [m4_join([ ],
    [group_id=0xc,prob=4294967295],
    [obs_domain=0xbb102030,obs_point=0xbb405060],
    [.*icmp6.*ipv6_src=fc00::2,ipv6_dst=fc00::1])])

OVS_WAIT_UNTIL([grep -qE 'SAMPLE1' psample.out])
OVS_WAIT_UNTIL([grep -qE 'SAMPLE2' psample.out])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([psample - slow])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_PSAMPLE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \
                    -- create Flow_Sample_Collector_Set id=1 bridge=@br0 \
                       local-group-id=10 \
                    -- create Flow_Sample_Collector_Set id=2 bridge=@br0 \
                       local-group-id=12],
         [0], [ignore])

AT_DATA([flows.txt], [dnl
arp actions=NORMAL
in_port=ovs-p0,ip actions=SAMPLE_ACTION(1, 2853183536, 2856341600),output(port=ovs-p1,max_len=200)
in_port=ovs-p1,ip actions=SAMPLE_ACTION(2, 3138396208, 3141554272),output(port=ovs-p0,max_len=200)
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl Disable datapath truncate support to force actions to run in slow path.
AT_CHECK([ovs-appctl dpif/set-dp-features br0 trunc false], [0])

AT_CHECK([ovs-appctl ofproto/trace br0 \
    'in_port=ovs-p0,dl_src=e4:11:22:33:44:55,dl_dst=e4:11:22:33:44:66,dl_type=0x0800,nw_src=10.1.1.1,nw_dst=10.1.1.12'],
    [0], [stdout])

AT_CHECK([tail -3 stdout], [0], [dnl
Datapath actions: psample(group=10,cookie=0xaa102030aa405060),trunc(200),3
This flow is handled by the userspace slow path because it:
  - Uses action(s) not supported by datapath.
])

OVS_DAEMONIZE([ovstest test-psample > psample.out], [psample.pid])
OVS_WAIT_UNTIL([grep -q "Listening for psample events" psample.out])

NS_CHECK_EXEC([at_ns0], [ping -q -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

m4_define([SAMPLE1], [m4_join([ ],
    [group_id=0xa,prob=4294967295],
    [obs_domain=0xaa102030,obs_point=0xaa405060],
    [.*icmp.*nw_src=10.1.1.1,nw_dst=10.1.1.2])])

m4_define([SAMPLE2], [m4_join([ ],
    [group_id=0xc,prob=4294967295],
    [obs_domain=0xbb102030,obs_point=0xbb405060],
    [.*icmp.*nw_src=10.1.1.2,nw_dst=10.1.1.1])])

AT_CHECK([grep -qE 'SAMPLE1' psample.out])
AT_CHECK([grep -qE 'SAMPLE2' psample.out])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([psample - slow with probability])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_PSAMPLE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \
                    -- create Flow_Sample_Collector_Set id=1 bridge=@br0 \
                       local-group-id=10],
         [0], [ignore])

dnl A probability != 100% but still pretty high (99.99847%). This ensures that
dnl the outer sample action is not optimized out.
m4_define([PROBABLE_SAMPLE_ACTION],
    [sample(probability=65534,collector_set_id=$1,obs_domain_id=$2,obs_point_id=$3)]dnl
)

AT_DATA([flows.txt], [dnl
arp actions=NORMAL
in_port=ovs-p0,ip actions=PROBABLE_SAMPLE_ACTION(1, 2853183536, 2856341600),output(port=ovs-p1,max_len=200)
in_port=ovs-p1,ip actions=PROBABLE_SAMPLE_ACTION(1, 2853183536, 2856341600),output(port=ovs-p0,max_len=200)
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl Disable datapath truncate support to force actions to run in slow path.
AT_CHECK([ovs-appctl dpif/set-dp-features br0 trunc false], [0])

AT_CHECK([ovs-appctl ofproto/trace br0 \
    'in_port=ovs-p0,dl_src=e4:11:22:33:44:55,dl_dst=e4:11:22:33:44:66,dl_type=0x0800,nw_src=10.1.1.1,nw_dst=10.1.1.12'],
    [0], [stdout])

AT_CHECK([tail -3 stdout], [0], [dnl
Datapath actions: sample(sample=100.0%,actions(psample(group=10,cookie=0xaa102030aa405060))),trunc(200),3
This flow is handled by the userspace slow path because it:
  - Uses action(s) not supported by datapath.
])

OVS_DAEMONIZE([ovstest test-psample > psample.out], [psample.pid])
OVS_WAIT_UNTIL([grep -q "Listening for psample events" psample.out])

dnl Sending 10 packets to decrease even more the odds of not sampling a packet.
NS_CHECK_EXEC([at_ns0], [ping -q -i 0.1 -c 10 10.1.1.2 | FORMAT_PING], [0], [dnl
10 packets transmitted, 10 received, 0% packet loss, time 0ms
])

m4_define([SAMPLE], [m4_join([ ],
    [group_id=0xa,prob=4294901758],
    [obs_domain=0xaa102030,obs_point=0xaa405060],
    [.*icmp.*nw_src=10.1.1.1,nw_dst=10.1.1.2])])

AT_CHECK([grep -qE 'SAMPLE' psample.out])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([psample - with IPFIX])
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_PSAMPLE()

ADD_NAMESPACES(at_ns0, at_ns1)

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")

AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \
                    -- --id=@i create IPFIX targets=\"127.0.0.1:4739\" \
                    -- create Flow_Sample_Collector_Set id=1 ipfix=@i \
                       bridge=@br0 local-group-id=10 \
                    -- create Flow_Sample_Collector_Set id=2 ipfix=@i \
                       bridge=@br0 local-group-id=12],
         [0], [ignore])

AT_DATA([flows.txt], [dnl
arp actions=NORMAL
in_port=ovs-p0,ip actions=SAMPLE_ACTION(1, 2853183536, 2856341600),ovs-p1
in_port=ovs-p1,ip actions=SAMPLE_ACTION(2, 3138396208, 3141554272),ovs-p0
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

AT_CHECK([ovs-appctl ofproto/trace br0 \
    'in_port=ovs-p0,dl_src=e4:11:22:33:44:55,dl_dst=e4:11:22:33:44:66,dl_type=0x0800,nw_src=10.1.1.1,nw_dst=10.1.1.12'],
    [0], [stdout])

m4_define([ACTIONS], [m4_join([],
    [psample(group=10,cookie=0xaa102030aa405060),],
    [userspace(pid=4294967295,],
        [flow_sample(probability=65535,],
        [collector_set_id=1,],
        [obs_domain_id=2853183536,],
        [obs_point_id=2856341600,],
        [output_port=4294967295)),],
    [3])])

AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: ACTIONS
])

OVS_DAEMONIZE([ovstest test-psample > psample.out], [psample.pid])
OVS_WAIT_UNTIL([grep -q "Listening for psample events" psample.out])

NS_CHECK_EXEC([at_ns0], [ping -q -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

m4_define([SAMPLE1], [m4_join([ ],
    [group_id=0xa,prob=4294967295],
    [obs_domain=0xaa102030,obs_point=0xaa405060],
    [.*icmp.*nw_src=10.1.1.1,nw_dst=10.1.1.2])])

m4_define([SAMPLE2], [m4_join([ ],
    [group_id=0xc,prob=4294967295],
    [obs_domain=0xbb102030,obs_point=0xbb405060],
    [.*icmp.*nw_src=10.1.1.2,nw_dst=10.1.1.1])])

OVS_WAIT_UNTIL([grep -qE 'SAMPLE1' psample.out])
OVS_WAIT_UNTIL([grep -qE 'SAMPLE2' psample.out])

dnl Check IPFIX samples have been received.
dnl Entries can be unsorted and IFPIX packets might not have been sent (or
dnl at least tried to be sent) yet.
OVS_WAIT_UNTIL_EQUAL([ovs-ofctl dump-ipfix-flow br0 | \
                sed 's/tx pkts=[[0-9]]*/tx pkts=24/' | \
                sed 's/tx errs=[[0-9]]*/tx errs=0/' | \
                sed 's/id   [[1-2]]:/id   ?:/'], [dnl
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
  id   ?: flows=1, current flows=0, sampled pkts=1, ipv4 ok=1, ipv6 ok=0, tx pkts=24
          pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
  id   ?: flows=1, current flows=0, sampled pkts=1, ipv4 ok=1, ipv6 ok=0, tx pkts=24
          pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0])

dnl OVS will fail to send IPFIX packets because the target is localhost
dnl and the port is closed. Ignore the message it generates.
OVS_TRAFFIC_VSWITCHD_STOP(["/sending to collector failed/d"])
AT_CLEANUP

AT_SETUP([psample - from ct label])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START()
OVS_CHECK_PSAMPLE()

ADD_NAMESPACES(at_ns0, at_ns1)
NS_CHECK_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore])
NS_CHECK_EXEC([at_ns1], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore])

ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "e4:11:22:33:44:55")
ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24", "e4:11:22:33:44:66")

AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \
                    -- --id=@ipfix create IPFIX targets=\"127.0.0.1:4739\" \
                    -- create Flow_Sample_Collector_Set id=1 bridge=@br0 \
                       ipfix=@ipfix, local-group-id=10 \
                    -- create Flow_Sample_Collector_Set id=2 bridge=@br0 \
                       ipfix=@ipfix, local-group-id=12],
         [0], [ignore])

m4_define([CT_STORE_ACT],
    [ct(zone=5,commit,exec(load:0x0bb102030->NXM_NX_CT_LABEL[[0..31]],load:0xbb405060->NXM_NX_CT_LABEL[[32..63]]))])

AT_DATA([flows.txt], [dnl
priority=100,ip actions=ct(zone=5, table=10)
priority=0 actions=NORMAL
table=10,priority=100,ip,ct_state=+trk+new action=SAMPLE_ACTION(1, 2853183536, 2856341600),CT_STORE_ACT,NORMAL
table=10,priority=100,ip,ct_state=+trk-new action=SAMPLE_ACTION(2, NXM_NX_CT_LABEL[[[0..31]]], NXM_NX_CT_LABEL[[[32..63]]]),NORMAL
table=10, priority=50, ip, actions=DROP
])

AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

OVS_DAEMONIZE([ovstest test-psample > psample.out], [psample1.pid])
OVS_WAIT_UNTIL([grep -q "Listening for psample events" psample.out])

NS_CHECK_EXEC([at_ns0], [ping -q -c 1 10.1.1.2 | FORMAT_PING], [0], [dnl
1 packets transmitted, 1 received, 0% packet loss, time 0ms
])

m4_define([SAMPLE1], [m4_join([ ],
    [group_id=0xa,prob=4294967295],
    [obs_domain=0xaa102030,obs_point=0xaa405060],
    [.*icmp.*nw_src=10.1.1.1,nw_dst=10.1.1.2])])

m4_define([SAMPLE2], [m4_join([ ],
    [group_id=0xc,prob=4294967295],
    [obs_domain=0xbb102030,obs_point=0xbb405060],
    [.*icmp.*nw_src=10.1.1.2,nw_dst=10.1.1.1])])
AT_CHECK([grep -qE 'SAMPLE1' psample.out])
AT_CHECK([grep -qE 'SAMPLE2' psample.out])

m4_define([FLOW_MATCH], [m4_join([],
    [ct_label(0xbb405060bb102030/0xffffffffffffffff).*actions:],
    [actions:psample(group=12,cookie=0xbb102030bb405060),],
    [userspace(pid=[[0-9]]+,flow_sample(.*obs_domain_id=3138396208,obs_point_id=3141554272.*))]
)])

AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p1 \
          | grep -qE 'FLOW_MATCH' ], [0], [])

dnl Check IPFIX samples have been received.
dnl Entries can be unsorted and IFPIX packets might not have been sent (or
dnl at least tried to be sent) yet.
OVS_WAIT_UNTIL_EQUAL([ovs-ofctl dump-ipfix-flow br0 | \
                sed 's/tx pkts=[[0-9]]*/tx pkts=24/' | \
                sed 's/tx errs=[[0-9]]*/tx errs=0/' | \
                sed 's/id   [[1-2]]:/id   ?:/'], [dnl
NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
  id   ?: flows=1, current flows=0, sampled pkts=1, ipv4 ok=1, ipv6 ok=0, tx pkts=24
          pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0
  id   ?: flows=1, current flows=0, sampled pkts=1, ipv4 ok=1, ipv6 ok=0, tx pkts=24
          pkts errs=0, ipv4 errs=0, ipv6 errs=0, tx errs=0])

dnl OVS will fail to send IPFIX packets because the target is localhost
dnl and the port is closed. Ignore the message it generates.
OVS_TRAFFIC_VSWITCHD_STOP(["/sending to collector failed/d"])
AT_CLEANUP
