Joe,

Below some comments on the tests,

  Jarno

> --- a/tests/atlocal.in
> +++ b/tests/atlocal.in
> @@ -110,3 +110,10 @@ fi
> if test "$IS_WIN32" = "yes"; then
>     HAVE_PYTHON="no"
> fi
> +
> +# Conntrack test requirements
> +if test x`which conntrack` != x; then
> +    HAVE_CONNTRACK="yes"
> +else
> +    HAVE_CONNTRACK="no"
> +fi
> diff --git a/tests/automake.mk b/tests/automake.mk
> index 4198039..cef67c0 100644
> --- a/tests/automake.mk
> +++ b/tests/automake.mk
> @@ -337,6 +337,7 @@ CHECK_PYFILES = \
>       tests/test-daemon.py \
>       tests/test-json.py \
>       tests/test-jsonrpc.py \
> +     tests/test-l7.py \
>       tests/test-ovsdb.py \
>       tests/test-reconnect.py \
>       tests/MockXenAPI.py \
> diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
> index e9af63f..43108e7 100644
> --- a/tests/dpif-netdev.at
> +++ b/tests/dpif-netdev.at
> @@ -82,7 +82,7 @@ AT_CHECK([cat ovs-vswitchd.log | grep -A 1 'miss upcall' | 
> tail -n 1], [0], [dnl
> skb_priority(0),skb_mark(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
> ])
> AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
> -pkt_mark=0,recirc_id=0,dp_hash=0,skb_priority=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0,
>  actions: <del>
> +pkt_mark=0,recirc_id=0,dp_hash=0,skb_priority=0,ct_state=0,ct_zone=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0,
>  actions: <del>
> recirc_id=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_frag=no,
>  actions: <del>
> ])
> 
> diff --git a/tests/odp.at b/tests/odp.at
> index 61edde3..74d44ff 100644
> --- a/tests/odp.at
> +++ b/tests/odp.at
> @@ -86,6 +86,11 @@ sed '/bos=0/{
> s/^/ODP_FIT_TOO_LITTLE: /
> }' < odp-in.txt > odp-out.txt
> 
> +dnl Some fields are always printed for this test, because wildcards aren't
> +dnl specified. We can skip these.
> +sed -i 's/\(skb_mark(0)\),\(ct\)/\1,ct_state(0),ct_zone(0),\2/' odp-out.txt
> +sed -i 's/\(skb_mark([[^)]]*)\),\(recirc\)/\1,ct_state(0),ct_zone(0),\2/' 
> odp-out.txt
> +
> AT_CHECK_UNQUOTED([ovstest test-odp parse-keys < odp-in.txt], [0], [`cat 
> odp-out.txt`
> ])
> AT_CLEANUP
> @@ -153,6 +158,10 @@ 
> s/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99,pcp=7),encap(/
> s/$/)/' odp-base.txt
> 
>  echo
> + echo '# Valid forms with conntrack fields.'
> + sed 's/\(eth([[^)]]*),?\)/\1,ct_state(+trk),/' odp-base.txt
> +
> + echo
>  echo '# Valid forms with IP first fragment.'
> sed -n 's/,frag=no),/,frag=first),/p' odp-base.txt
> 
> @@ -293,6 +302,9 @@ 
> tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:1
> tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(oam,vni=0x1c7)),out_port(1))
> tnl_push(tnl_port(6),header(size=58,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x1c7,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(1))
> tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x1c7)),out_port(1))
> +ct
> +ct(commit)
> +ct(commit,zone=5)
> ])
> AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0],
>   [`cat actions.txt`
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index eb8647b..1e3013b 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -6486,8 +6486,8 @@ for i in 1 2 3 4; do
> done
> sleep 1
> AT_CHECK([cat ovs-vswitchd.log | STRIP_UFID | FILTER_FLOW_INSTALL | 
> STRIP_USED], [0], [dnl
> -pkt_mark=0,recirc_id=0,dp_hash=0,skb_priority=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0,
>  actions:2
> -pkt_mark=0,recirc_id=0,dp_hash=0,skb_priority=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_src=10.0.0.4,nw_dst=10.0.0.3,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0,
>  actions:drop
> +pkt_mark=0,recirc_id=0,dp_hash=0,skb_priority=0,ct_state=0,ct_zone=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0,
>  actions:2
> +pkt_mark=0,recirc_id=0,dp_hash=0,skb_priority=0,ct_state=0,ct_zone=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_src=10.0.0.4,nw_dst=10.0.0.3,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0,
>  actions:drop
> ])
> AT_CHECK([cat ovs-vswitchd.log | STRIP_UFID | FILTER_FLOW_DUMP | grep 
> 'packets:3'], [0], [dnl
> skb_priority(0),skb_mark(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0),
>  packets:3, bytes:180, used:0.0s, actions:2
> diff --git a/tests/ofproto.at b/tests/ofproto.at
> index 7e80293..c522a85 100644
> --- a/tests/ofproto.at
> +++ b/tests/ofproto.at
> @@ -1609,6 +1609,8 @@ head_table () {
>       in_port_oxm: exact match or wildcard
>       actset_output: exact match or wildcard
>       pkt_mark: arbitrary mask
> +      ct_state: arbitrary mask
> +      ct_zone: exact match or wildcard
>       reg0: arbitrary mask
>       reg1: arbitrary mask
>       reg2: arbitrary mask
> diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at
> index c5691e7..8f3b318 100644
> --- a/tests/system-common-macros.at
> +++ b/tests/system-common-macros.at
> @@ -118,3 +118,21 @@ m4_define([ADD_NATIVE_TUNNEL],
> # Strip variant pieces from ping output so the output can be reliably 
> compared.
> #
> m4_define([FORMAT_PING], [grep "transmitted" | sed 's/time.*ms$/time 0ms/'])
> +
> +# FORMAT_CT()
> +#
> +# Strip content from the piped input which would differ from test to test.
> +#
> +m4_define([FORMAT_CT],
> +    [[grep "dst=$1" | sed -e 's/port=[0-9]*/port=<cleared>/g' -e 's/  */ /g' 
> -e 's/secctx[^ ]* //' | cut -d' ' -f4- | sort | uniq]])
> +
> +# NETNS_DAEMONIZE([namespace], [command], [pidfile])
> +#
> +# Run 'command' as a background process within 'namespace' and record its pid
> +# to 'pidfile' to allow cleanup on exit.
> +#
> +m4_define([NETNS_DAEMONIZE],
> +   [ip netns exec $1 $2 & echo $! > $3
> +     echo "kill \`cat $3\`" >> cleanup
> +   ]
> +)
> diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
> index 1216db8..a48e8d9 100644
> --- a/tests/system-kmod-macros.at
> +++ b/tests/system-kmod-macros.at
> @@ -43,3 +43,19 @@ m4_define([OVS_TRAFFIC_VSWITCHD_STOP],
>   [OVS_VSWITCHD_STOP([$1])
>    AT_CHECK([:; $2])
>   ])
> +
> +# CHECK_CONNTRACK()
> +#
> +# Perform requirements checks for running conntrack tests, and flush the
> +# kernel conntrack tables when the test is finished.
> +#
> +m4_define([CHECK_CONNTRACK],
> +    [AT_SKIP_IF([test $HAVE_CONNTRACK = no])
> +     AT_SKIP_IF([test $HAVE_PYTHON = no])
> +     m4_foreach([mod], [[nf_conntrack_ipv4], [nf_conntrack_ipv6]],
> +                [modprobe mod || echo "Module mod not loaded."
> +                 on_exit 'modprobe -r mod'
> +                ])
> +     on_exit 'conntrack -F'
> +    ]
> +)
> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> index 7dbed68..de6b016 100644
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -139,3 +139,472 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 
> 2 10.1.1.100 | FORMAT_PI
> 
> OVS_TRAFFIC_VSWITCHD_STOP
> AT_CLEANUP
> +
> +AT_SETUP([conntrack - controller])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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
> +in_port=1,udp,action=ct(commit),controller
> +in_port=2,ct_state=-trk,udp,action=ct(table=0)
> +in_port=2,ct_state=+trk+est-new,udp,action=controller

ct_state=+est should be sufficient here?

> +])
> +
> +AT_CHECK([ovs-ofctl 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\) 
> '50540000000a50540000000908004500001c00000000001100000a0101020a0101010002000100080000'])
> +
> +dnl OK, now start a new connection from port 1.
> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 1 ct\(commit\),controller 
> '50540000000a50540000000908004500001c00000000001100000a0101010a0101020001000200080000'])
> +
> +dnl Now try a reply from port 2.
> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 ct\(table=0\) 
> '50540000000a50540000000908004500001c00000000001100000a0101020a0101010002000100080000'])
> +
> +dnl Check this output. We only see the latter two packets, not the first.
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (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,tp_src=1,tp_dst=2
>  udp_csum:0
> +NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=42 
> ct_state=est|rpl|trk,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,tp_src=2,tp_dst=1
>  udp_csum:0
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - IPv4 HTTP])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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
> +in_port=1,tcp,action=ct(commit),2
> +in_port=2,ct_state=-trk,tcp,action=ct(table=0)
> +in_port=2,ct_state=+trk+est-new,tcp,action=1

Having explicit priorities here as well would be helpful. The comment above 
about “+est” should apply here as well.

> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl Basic connectivity check.
> +NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 >/dev/null])
> +
> +dnl HTTP requests from ns0->ns1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])


wget was trying to resolve the proxy I had configured in the “http_proxy” 
environment variable. The resolution from the netns failed, making the test 
case fail. I had to clear “http_proxy" to make the test work.

> +
> +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2)], [0], [dnl
> +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> 
> src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 
> use=1

Do you know how/if [ASSURED] maps to ct_state flags?

> +])
> +
> +dnl HTTP requests from ns1->ns0 should fail due to network failure.
> +dnl Try 3 times, in 1 second intervals.
> +NETNS_DAEMONIZE([at_ns0], [[$PYTHON $srcdir/test-l7.py]], [http1.pid])
> +NS_CHECK_EXEC([at_ns1], [wget 10.1.1.1 -t 3 -T 1 -v -o wget1.log], [4])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - IPv6 HTTP])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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 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
> +in_port=1,tcp6,action=ct(commit),2
> +in_port=2,ct_state=-trk,tcp6,action=ct(table=0)
> +in_port=2,ct_state=+trk+est-new,tcp6,action=1

Ditto.

> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl Without this sleep, we get occasional failures due to the following 
> error:
> +dnl "connect: Cannot assign requested address"
> +sleep 2;
> +
> +dnl HTTP requests from ns0->ns1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py http6]], [http0.pid])
> +
> +NS_CHECK_EXEC([at_ns0], [wget http://[[fc00::2]] -t 3 -T 1 
> --retry-connrefused -v -o wget0.log])
> +
> +dnl HTTP requests from ns1->ns0 should fail due to network failure.
> +dnl Try 3 times, in 1 second intervals.
> +NETNS_DAEMONIZE([at_ns0], [[$PYTHON $srcdir/test-l7.py http6]], [http1.pid])
> +NS_CHECK_EXEC([at_ns1], [wget http://[[fc00::1]] -t 3 -T 1 -v -o wget1.log], 
> [4])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - commit, recirc])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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
> +in_port=1,tcp,ct_state=-trk,action=ct(commit,table=0)

Maybe some of the test cases should use non-zero table?

> +in_port=1,tcp,ct_state=+trk,action=2
> +in_port=2,tcp,ct_state=-trk,action=ct(table=0)
> +in_port=2,tcp,ct_state=+trk,action=1
> +in_port=3,tcp,ct_state=-trk,action=set_field:0->metadata,ct(table=0)
> +in_port=3,tcp,ct_state=+trk,metadata=0,action=set_field:1->metadata,ct(commit,table=0)
> +in_port=3,tcp,ct_state=+trk,metadata=1,action=4
> +in_port=4,tcp,ct_state=-trk,action=ct(commit,table=0)
> +in_port=4,tcp,ct_state=+trk,action=3
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl HTTP requests from p0->p1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +dnl HTTP requests from p2->p3 should work fine.
> +NETNS_DAEMONIZE([at_ns3], [[$PYTHON $srcdir/test-l7.py]], [http1.pid])
> +NS_CHECK_EXEC([at_ns2], [wget 10.1.1.4 -t 3 -T 1 --retry-connrefused -v -o 
> wget1.log])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - preserve registers])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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
> +in_port=1,tcp,ct_state=-trk,action=ct(commit,table=0)
> +in_port=1,tcp,ct_state=+trk,action=2
> +in_port=2,tcp,ct_state=-trk,action=ct(table=0)
> +in_port=2,tcp,ct_state=+trk,action=1
> +in_port=3,tcp,ct_state=-trk,action=load:0->NXM_NX_REG0[[]],ct(table=0)
> +in_port=3,tcp,ct_state=+trk,reg0=0,action=load:1->NXM_NX_REG0[[]],ct(commit,table=0)
> +in_port=3,tcp,ct_state=+trk,reg0=1,action=4
> +in_port=4,tcp,ct_state=-trk,action=ct(commit,table=0)
> +in_port=4,tcp,ct_state=+trk,action=3
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl HTTP requests from p0->p1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +dnl HTTP requests from p2->p3 should work fine.
> +NETNS_DAEMONIZE([at_ns3], [[$PYTHON $srcdir/test-l7.py]], [http1.pid])
> +NS_CHECK_EXEC([at_ns2], [wget 10.1.1.4 -t 3 -T 1 --retry-connrefused -v -o 
> wget1.log])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - invalid])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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.

Update comment?

> +AT_DATA([flows.txt], [dnl
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +priority=10,icmp,action=normal
> +in_port=1,tcp,action=ct(),2
> +in_port=2,ct_state=-trk,tcp,action=ct(table=0)
> +in_port=2,ct_state=+trk+new,tcp,action=1

Here “+new” should be sufficient, in general, “+trk” is not needed if any of 
the other bits are matched for being set, right?

> +in_port=3,tcp,action=ct(),4
> +in_port=4,ct_state=-trk,tcp,action=ct(table=0)
> +in_port=4,ct_state=+trk+inv,tcp,action=3
> +in_port=4,ct_state=+trk+new,tcp,action=3
> +])
> +
> +AT_CHECK([ovs-ofctl 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.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log], [4])
> +
> +dnl For the second pair, we allow packets from invalid connections, so it 
> works.
> +NETNS_DAEMONIZE([at_ns3], [[$PYTHON $srcdir/test-l7.py]], [http1.pid])
> +NS_CHECK_EXEC([at_ns2], [wget 10.1.1.4 -t 3 -T 1 --retry-connrefused -v -o 
> wget1.log])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - zones])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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.

Does this comment need an update?

> +AT_DATA([flows.txt], [dnl
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +priority=10,icmp,action=normal
> +in_port=1,tcp,action=ct(commit,zone=1),2
> +in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=1)
> +in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
> +in_port=3,tcp,action=ct(commit,zone=2),4
> +in_port=4,ct_state=-trk,tcp,action=ct(table=0,zone=2)
> +in_port=4,ct_state=+trk,ct_zone=1,tcp,action=3
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl HTTP requests from p0->p1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2)], [0], [dnl
> +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> 
> src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 
> zone=1 use=1
> +])
> +
> +dnl HTTP requests from p2->p3 should fail due to network failure.
> +dnl Try 3 times, in 1 second intervals.
> +NETNS_DAEMONIZE([at_ns3], [[$PYTHON $srcdir/test-l7.py]], [http1.pid])
> +NS_CHECK_EXEC([at_ns2], [wget 10.1.1.4 -t 3 -T 1 -v -o wget1.log], [4])
> +
> +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.4)], [0], [dnl
> +SYN_RECV src=10.1.1.3 dst=10.1.1.4 sport=<cleared> dport=<cleared> 
> src=10.1.1.4 dst=10.1.1.3 sport=<cleared> dport=<cleared> mark=0 zone=2 use=1
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - zones from field])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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
> +in_port=1,tcp,action=load:1->NXM_NX_REG0[[0..15]],ct(commit,zone=NXM_NX_REG0[[0..15]]),2
> +in_port=2,ct_state=-trk,tcp,action=load:1->NXM_NX_REG0[[0..15]],ct(table=0,zone=NXM_NX_REG0[[0..15]])
> +in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1
> +in_port=3,tcp,action=load:2->NXM_NX_REG0[[0..15]],ct(commit,zone=NXM_NX_REG0[[0..15]]),4
> +in_port=4,ct_state=-trk,tcp,action=load:2->NXM_NX_REG0[[0..15]],ct(table=0,zone=NXM_NX_REG0[[0..15]])
> +in_port=4,ct_state=+trk,ct_zone=1,tcp,action=3
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl HTTP requests from p0->p1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2)], [0], [dnl
> +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> 
> src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 
> zone=1 use=1
> +])
> +
> +dnl HTTP requests from p2->p3 should fail due to network failure.
> +dnl Try 3 times, in 1 second intervals.
> +NETNS_DAEMONIZE([at_ns3], [[$PYTHON $srcdir/test-l7.py]], [http1.pid])
> +NS_CHECK_EXEC([at_ns2], [wget 10.1.1.4 -t 3 -T 1 -v -o wget1.log], [4])
> +
> +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.4)], [0], [dnl
> +SYN_RECV src=10.1.1.3 dst=10.1.1.4 sport=<cleared> dport=<cleared> 
> src=10.1.1.4 dst=10.1.1.3 sport=<cleared> dport=<cleared> mark=0 zone=2 use=1
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - multiple bridges])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone --\
> +    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->ns1, allow established in reverse.
> +AT_DATA([flows-br0.txt], [dnl
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +priority=10,icmp,action=normal
> +in_port=2,tcp,ct_state=-trk,action=ct(commit,zone=1),1
> +in_port=1,tcp,ct_state=-trk,action=ct(table=0,zone=1)
> +in_port=1,tcp,ct_state=+trk+est,ct_zone=1,action=2
> +])
> +
> +dnl Allow any traffic from ns0->ns1, allow established in reverse.

Should this comment be different from the one above??

> +AT_DATA([flows-br1.txt], [dnl
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +priority=10,icmp,action=normal
> +in_port=1,tcp,ct_state=-trk,action=ct(table=0,zone=2)
> +in_port=1,tcp,ct_state=+trk+new,ct_zone=2,action=ct(commit,zone=2),2
> +in_port=1,tcp,ct_state=+trk+est,ct_zone=2,action=2
> +in_port=2,tcp,ct_state=-trk,action=ct(table=0,zone=2)
> +in_port=2,tcp,ct_state=+trk+est,ct_zone=2,action=ct(commit,zone=2),1
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows-br0.txt])
> +AT_CHECK([ovs-ofctl add-flows br1 flows-br1.txt])
> +
> +dnl HTTP requests from p0->p1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - multiple zones])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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.

How about ns2 and ns3?

> +AT_DATA([flows.txt], [dnl
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +priority=10,icmp,action=normal
> +in_port=1,tcp,action=ct(commit,zone=1),ct(commit,zone=2),2
> +in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=2)
> +in_port=2,ct_state=+trk,ct_zone=2,tcp,action=1
> +])
> +
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl HTTP requests from p0->p1 should work fine.
> +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py]], [http0.pid])
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +dnl (again) HTTP requests from p0->p1 should work fine.
> +NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o 
> wget0.log])
> +
> +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2)], [0], [dnl
> +SYN_SENT src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> 
> [[UNREPLIED]] src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> 
> mark=0 zone=1 use=1
> +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> 
> src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 
> zone=2 use=1
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([conntrack - ICMP related 2])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> +   [set-fail-mode br0 standalone -- ])
> +
> +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
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +in_port=1,ct_state=-trk,udp,action=ct(commit,table=0)
> +in_port=1,ct_state=+trk,actions=controller
> +in_port=2,ct_state=-trk,action=ct(table=0)
> +in_port=2,ct_state=+trk-inv-new,action=controller

Could there be a match on +rel here?

> +])
> +
> +AT_CHECK([ovs-ofctl 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 1. Send an ICMP port unreach reply for port 8738, without any previous 
> request
> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 ct\(table=0\) 
> 'f64c473528c9c6f54ecb72db080045c0003d2e8700004001f355ac100004ac1000030303553f0000000045000021317040004011b138ac100003ac10000411112222000d20966369616f0a'])
> +
> +dnl 2. Send and UDP packet to port 5555
> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 1 ct\(commit,table=0\) 
> 'c6f94ecb72dbe64c473528c9080045000021317040004011b138ac100001ac100002a28e15b3000d20966369616f0a'])
> +
> +dnl 3. Send an ICMP port unreach reply for port 5555, related to the first 
> packet
> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 2 ct\(table=0\) 
> 'e64c473528c9c6f94ecb72db080045c0003d2e8700004001f355ac100002ac1000010303553f0000000045000021317040004011b138ac100001ac100002a28e15b3000d20966369616f0a'])
> +
> +dnl Check this output. We only see the latter two packets, not the first.
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=47 ct_state=new|trk,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,tp_src=41614,tp_dst=5555
>  udp_csum:2096
> +NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=75 
> ct_state=rel|rpl|trk,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.2,nw_dst=172.16.0.1,nw_tos=192,nw_ecn=0,nw_ttl=64,icmp_type=3,icmp_code=3
>  icmp_csum:553f
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> diff --git a/tests/system-userspace-macros.at 
> b/tests/system-userspace-macros.at
> index fca26f7..16256cb 100644
> --- a/tests/system-userspace-macros.at
> +++ b/tests/system-userspace-macros.at
> @@ -37,3 +37,12 @@ m4_define([OVS_TRAFFIC_VSWITCHD_STOP],
> /dpif_netlink.*Generic Netlink family 'ovs_datapath' does not exist. The Open 
> vSwitch kernel module is probably not loaded./d"])
>    AT_CHECK([:; $2])
>   ])
> +
> +# CHECK_CONNTRACK()
> +#
> +# Perform requirements checks for running conntrack tests, and flush the
> +# kernel conntrack tables when the test is finished.
> +#
> +m4_define([CHECK_CONNTRACK],
> +    [AT_SKIP_IF(true)]
> +)
> diff --git a/tests/test-l7.py b/tests/test-l7.py
> new file mode 100755
> index 0000000..65c6c2a
> --- /dev/null
> +++ b/tests/test-l7.py
> @@ -0,0 +1,72 @@
> +# Copyright (c) 2015 Nicira, Inc.
> +#
> +# Licensed under the Apache License, Version 2.0 (the "License");
> +# you may not use this file except in compliance with the License.
> +# You may obtain a copy of the License at:
> +#
> +#     http://www.apache.org/licenses/LICENSE-2.0
> +#
> +# Unless required by applicable law or agreed to in writing, software
> +# distributed under the License is distributed on an "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +# See the License for the specific language governing permissions and
> +# limitations under the License.
> +
> +import argparse
> +import socket
> +
> +from BaseHTTPServer import HTTPServer
> +from SimpleHTTPServer import SimpleHTTPRequestHandler
> +from SocketServer import TCPServer
> +
> +
> +class TCPServerV6(HTTPServer):
> +    address_family = socket.AF_INET6
> +
> +
> +def get_ftpd():
> +    try:
> +        from pyftpdlib.authorizers import DummyAuthorizer
> +        from pyftpdlib.handlers import FTPHandler
> +        from pyftpdlib.servers import FTPServer
> +
> +        class OVSFTPHandler(FTPHandler):
> +            authorizer = DummyAuthorizer()
> +            authorizer.add_anonymous("/tmp")
> +        server = [FTPServer, OVSFTPHandler, 21]
> +    except ImportError:
> +        server = None
> +        pass
> +    return server
> +
> +
> +def main():
> +    SERVERS = {
> +        'http':  [TCPServer,   SimpleHTTPRequestHandler, 80],
> +        'http6': [TCPServerV6, SimpleHTTPRequestHandler, 80],
> +    }
> +
> +    ftpd = get_ftpd()
> +    if ftpd is not None:
> +        SERVERS['ftp'] = ftpd
> +
> +    protocols = [srv for srv in SERVERS]
> +    parser = argparse.ArgumentParser(
> +            description='Run basic application servers.')
> +    parser.add_argument('proto', default='http', nargs='?',
> +            help='protocol to serve (%s)' % protocols)
> +    args = parser.parse_args()
> +
> +    if args.proto not in SERVERS:
> +        parser.print_help()
> +        exit(1)
> +
> +    constructor = SERVERS[args.proto][0]
> +    handler = SERVERS[args.proto][1]
> +    port = SERVERS[args.proto][2]
> +    srv = constructor(('', port), handler)
> +    srv.serve_forever()
> +
> +
> +if __name__ == '__main__':
> +    main()
> diff --git a/tests/test-odp.c b/tests/test-odp.c
> index 3e7939e..cb245d6 100644
> --- a/tests/test-odp.c
> +++ b/tests/test-odp.c
> @@ -57,7 +57,10 @@ parse_keys(bool wc_keys)
>             struct odp_flow_key_parms odp_parms = {
>                 .flow = &flow,
>                 .support = {
> +                    .max_mpls_depth = SIZE_MAX,

Why this?

>                     .recirc = true,
> +                    .ct_state = true,
> +                    .ct_zone = true,
>                 },
>             };
> 
> diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
> index 8bb3715..7e5fcaa 100644
> --- a/utilities/ovs-ofctl.8.in
> +++ b/utilities/ovs-ofctl.8.in
> @@ -1305,6 +1305,65 @@ is used only with the \fBconjunction\fR action (see 
> below).
> .IP
> This field was introduced in Open vSwitch 2.4.
> .
> +.IP \fBct_state=\fIflags\fB/\fImask\fR
> +.IQ \fBct_state=\fR[\fB+\fIflag\fR...][\fB-\fIflag\fR...]
> +Bitwise match on connection state flags.  The flags are only available
> +after a call to the \fBct\fR action with the \fBtable\fR specified.
> +
> +.IP
> +The \fIflags\fR and \fImask\fR are 8-bit numbers written in decimal or
> +in hexadecimal prefixed by \fB0x\fR.  Each 1-bit in \fImask\fR requires
> +that the corresponding bit in \fIflags\fR must match.  Each 0-bit in
> +\fImask\fR causes the corresponding bit to be ignored.
> +.IP
> +Alternatively, the flags can be specified by their symbolic names
> +(listed below), each preceded by either \fB+\fR for a flag that must
> +be set, or \fB\-\fR for a flag that must be unset, without any other
> +delimiters between the flags.  Flags not mentioned are wildcarded.  For
> +example, \fBtcp,ct_state=+trk\-new\fR matches TCP packets that
> +have been run through the connection tracker and do not establish a new
> +flow.
> +.IP
> +The following flags describe the state of the tracking:
> +.RS
> +.IP "\fB0x80: trk\fR"
> +Connection tracking has occurred.
> +.IP "\fB0x40: rpl\fR"
> +The flow is in the reply direction, meaning it did not initiate the
> +connection.
> +.IP "\fB0x20: inv\fR"
> +The flow is invalid, meaning that the connection tracker couldn't identify 
> the
> +connection.
> +.RS
> +.PP
> +This flag may be set for the following reasons:
> +.RS
> +L3/L4 protocol handler is not loaded/unavailable. With the Linux kernel
> +datapath, this may mean that the "nf_conntrack_ipv4" or "nf_conntrack_ipv6"
> +modules are not loaded.
> +.PP
> +L3/L4 protocol handler determines that the packet is malformed or invalid.
> +.PP
> +Packets are unexpected length for protocol.
> +.RE
> +.RE
> +.IP "\fB0x01: new\fR"
> +This is the beginning of a new connection.
> +.IP "\fB0x02: est\fR"
> +This is part of an already existing connection.
> +.IP "\fB0x04: rel\fR"
> +This is a connection that is related to an existing connection, for
> +instance ICMP "destination unreachable" messages or FTP data connections.
> +.RE
> +.
> +.PP
> +The following fields are data associated with the connection tracker and
> +can only be matched or set after running through the connection tracker
> +by using the \fBct\fR action.
> +.
> +.IP \fBct_zone=\fIvalue
> +Matches connection zone \fIvalue\fR exactly.
> +.
> .PP
> Defining IPv6 flows (those with \fBdl_type\fR equal to 0x86dd) requires
> support for NXM.  The following shorthand notations are available for
> @@ -1542,6 +1601,32 @@ OpenFlow implementations do not support queuing at all.
> Restores the queue to the value it was before any \fBset_queue\fR
> actions were applied.
> .
> +.IP \fBct\fR
> +.IQ \fBct\fB(\fR[\fIargument\fR][\fB,\fIargument\fR...]\fB)
> +Send the packet through the connection tracker.  The following arguments
> +are supported:
> +
> +.RS
> +.IP \fBcommit\fR
> +Commit the flow to the connection tracking module.
> +.IP \fBtable=\fInumber\fR
> +After ct processing, the packet should be re-inserted into OpenFlow pipeline
> +processing in table \fInumber\fR, with the \fBct_state\fR and other ct match
> +fields set. It is strongly recommended to use a table later than the current
> +table to prevent loops.
> +.IP \fBzone=\fIvalue\fR
> +.IQ \fBzone=\fIsrc\fB[\fIstart\fB..\fIend\fB]\fR
> +A 16-bit context id that can be used to isolate connections into separate
> +domains, allowing overlapping network addresses in different zones. If a zone
> +is not provided, then the default is to use zone zero. The \fBzone\fR may be
> +specified either as an immediate 16-bit \fIvalue\fR, or may be provided from 
> an
> +NXM field \fIsrc\fR. The \fIstart\fR and \fIend\fR pair are inclusive, and 
> must
> +specify a 16-bit range within the field.
> +.RE
> +.IP
> +Currently, connection tracking is only available on Linux kernels with the
> +conntrack module loaded.
> +.
> .IP \fBdec_ttl\fR
> .IQ \fBdec_ttl\fB[\fR(\fIid1,id2\fI)\fR]\fR
> Decrement TTL of IPv4 packet or hop limit of IPv6 packet.  If the
> -- 
> 2.1.4
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to