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