With the comments below, Acked-by: Jarno Rajahalme <jrajaha...@nicira.com>
Sorry for repeating some comments over and over, no offense intended. > On Sep 9, 2015, at 7:00 PM, Joe Stringer <joestrin...@nicira.com> wrote: > > This patch adds support for specifying a "helper" or ALG to assist > connection tracking for protocols that consist of multiple streams. > Initially, only support for FTP is included. > > Below is an example set of flows to allow FTP control connections from > port 1->2 to establish active data connections in the reverse direction: > > priority=1,action=drop > priority=10,arp,action=normal > in_port=1,tcp,action=ct(alg=ftp,commit),2 > in_port=2,tcp,ct_state=-trk,action=ct(table=1) > table=1,in_port=2,tcp,ct_state=+trk-new+est,action=1 +est would be sufficient? > table=1,in_port=2,tcp,ct_state=+trk+rel,action=ct(commit),1 +rel would be sufficient? Also, will this try to commit all the packets, or only the first one? > > Signed-off-by: Joe Stringer <joestrin...@nicira.com> > --- > datapath/linux/compat/include/linux/openvswitch.h | 3 + > include/sparse/netinet/in.h | 2 + > include/windows/netinet/in.h | 1 + > lib/netlink.c | 11 ++ > lib/netlink.h | 2 + > lib/odp-util.c | 28 ++++- > lib/ofp-actions.c | 18 +++ > lib/ofp-parse.c | 15 +++ > lib/ofp-parse.h | 1 + > ofproto/ofproto-dpif-xlate.c | 16 +++ > tests/atlocal.in | 7 ++ > tests/odp.at | 1 + > tests/system-traffic.at | 145 ++++++++++++++++++++++ > utilities/ovs-ofctl.8.in | 11 ++ > 14 files changed, 260 insertions(+), 1 deletion(-) > > diff --git a/datapath/linux/compat/include/linux/openvswitch.h > b/datapath/linux/compat/include/linux/openvswitch.h > index 39a321e..bbc6ca4 100644 > --- a/datapath/linux/compat/include/linux/openvswitch.h > +++ b/datapath/linux/compat/include/linux/openvswitch.h > @@ -669,6 +669,7 @@ struct ovs_action_push_tnl { > * @OVS_CT_ATTR_LABEL: %OVS_CT_LABEL_LEN value followed by %OVS_CT_LABEL_LEN > * mask. For each bit set in the mask, the corresponding bit in the value is > * copied to the connection tracking label field in the connection. > + * @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG. > */ > enum ovs_ct_attr { > OVS_CT_ATTR_UNSPEC, > @@ -676,6 +677,8 @@ enum ovs_ct_attr { > OVS_CT_ATTR_ZONE, /* u16 zone id. */ > OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ > OVS_CT_ATTR_LABEL, /* label to associate with this connection. */ > + OVS_CT_ATTR_HELPER, /* netlink helper to assist detection of > + related connections. */ > __OVS_CT_ATTR_MAX > }; > > diff --git a/include/sparse/netinet/in.h b/include/sparse/netinet/in.h > index f66f205..1223553 100644 > --- a/include/sparse/netinet/in.h > +++ b/include/sparse/netinet/in.h > @@ -74,6 +74,8 @@ struct sockaddr_in6 { > #define IPPROTO_DSTOPTS 60 > #define IPPROTO_SCTP 132 > > +#define IPPORT_FTP 21 > + > /* All the IP options documented in Linux ip(7). */ > #define IP_ADD_MEMBERSHIP 0 > #define IP_DROP_MEMBERSHIP 1 > diff --git a/include/windows/netinet/in.h b/include/windows/netinet/in.h > index 7143cf5..e416999 100644 > --- a/include/windows/netinet/in.h > +++ b/include/windows/netinet/in.h > @@ -18,5 +18,6 @@ > #define __NETINET_IN_H 1 > > #define IPPROTO_GRE 47 > +#define IPPORT_FTP 21 > > #endif /* netinet/in.h */ > diff --git a/lib/netlink.c b/lib/netlink.c > index 09723b2..66b4927 100644 > --- a/lib/netlink.c > +++ b/lib/netlink.c > @@ -316,6 +316,17 @@ nl_msg_put_odp_port(struct ofpbuf *msg, uint16_t type, > odp_port_t value) > nl_msg_put_u32(msg, type, odp_to_u32(value)); > } > > +/* Appends a Netlink attribute of the given 'type' with the 'len' characters > + * of 'value', followed by the null byte to 'msg'. */ > +void > +nl_msg_put_string__(struct ofpbuf *msg, uint16_t type, const char *value, > + size_t len) > +{ > + char *data = nl_msg_put_unspec_uninit(msg, type, len + 1); > + > + memcpy(data, value, len); > + data[len] = '\0'; > +} > > /* Appends a Netlink attribute of the given 'type' and the given > * null-terminated string 'value' to 'msg'. */ > diff --git a/lib/netlink.h b/lib/netlink.h > index 6068f5d..210cab5 100644 > --- a/lib/netlink.h > +++ b/lib/netlink.h > @@ -70,6 +70,8 @@ void nl_msg_put_be16(struct ofpbuf *, uint16_t type, > ovs_be16 value); > void nl_msg_put_be32(struct ofpbuf *, uint16_t type, ovs_be32 value); > void nl_msg_put_be64(struct ofpbuf *, uint16_t type, ovs_be64 value); > void nl_msg_put_odp_port(struct ofpbuf *, uint16_t type, odp_port_t value); > +void nl_msg_put_string__(struct ofpbuf *, uint16_t type, const char *value, > + size_t len); > void nl_msg_put_string(struct ofpbuf *, uint16_t type, const char *value); > > size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type); > diff --git a/lib/odp-util.c b/lib/odp-util.c > index fa5bc86..43c5816 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -52,6 +52,7 @@ VLOG_DEFINE_THIS_MODULE(odp_util); > /* The set of characters that may separate one action or one key attribute > * from another. */ > static const char *delimiters = ", \t\r\n"; > +static const char *delimiters_end = ", \t\r\n)"; > > struct attr_len_tbl { > int len; > @@ -546,6 +547,8 @@ static const struct nl_policy ovs_conntrack_policy[] = { > .min_len = sizeof(uint32_t) * 2 }, > [OVS_CT_ATTR_LABEL] = { .type = NL_A_UNSPEC, .optional = true, > .min_len = sizeof(ovs_u128) * 2 }, > + [OVS_CT_ATTR_HELPER] = { .type = NL_A_STRING, .optional = true, > + .min_len = 1, .max_len = 16 }, > }; > > static void > @@ -554,6 +557,7 @@ format_odp_conntrack_action(struct ds *ds, const struct > nlattr *attr) > struct nlattr *a[ARRAY_SIZE(ovs_conntrack_policy)]; > const ovs_u128 *label; > const uint32_t *mark; > + const char *helper; > uint32_t flags; > uint16_t zone; > > @@ -566,9 +570,10 @@ format_odp_conntrack_action(struct ds *ds, const struct > nlattr *attr) > zone = a[OVS_CT_ATTR_ZONE] ? nl_attr_get_u16(a[OVS_CT_ATTR_ZONE]) : 0; > mark = a[OVS_CT_ATTR_MARK] ? nl_attr_get(a[OVS_CT_ATTR_MARK]) : NULL; > label = a[OVS_CT_ATTR_LABEL] ? nl_attr_get(a[OVS_CT_ATTR_LABEL]): NULL; > + helper = a[OVS_CT_ATTR_HELPER] ? nl_attr_get(a[OVS_CT_ATTR_HELPER]) : > NULL; > > ds_put_format(ds, "ct"); > - if (flags || zone || mark || label) { > + if (flags || zone || mark || label || helper) { > ds_put_cstr(ds, "("); > if (flags & OVS_CT_F_COMMIT) { > ds_put_format(ds, "commit"); > @@ -595,6 +600,12 @@ format_odp_conntrack_action(struct ds *ds, const struct > nlattr *attr) > ds_put_char(ds, '/'); > ds_put_hex(ds, (label + 1), sizeof(*label)); > } > + if (helper) { > + if (ds_last(ds) != '(') { > + ds_put_char(ds, ','); > + } > + ds_put_format(ds, "helper=%s", helper); > + } > ds_put_cstr(ds, ")"); > } > } > @@ -1053,6 +1064,7 @@ parse_conntrack_action(const char *s_, struct ofpbuf > *actions) > const char *s = s_; > > if (ovs_scan(s, "ct")) { > + const char *helper = NULL; > uint32_t flags = 0; > uint16_t zone = 0; > struct { > @@ -1063,6 +1075,7 @@ parse_conntrack_action(const char *s_, struct ofpbuf > *actions) > struct ovs_key_ct_label value; > struct ovs_key_ct_label mask; > } ct_label; > + size_t helper_len; > size_t start; > char *end; > > @@ -1112,6 +1125,15 @@ parse_conntrack_action(const char *s_, struct ofpbuf > *actions) > s = tail; > continue; > } > + if (ovs_scan(s, "helper=%n", &n)) { > + s += n; > + helper_len = strcspn(s, delimiters_end); > + if (helper_len > 15) { > + return -EINVAL; > + } > + helper = s; > + s += helper_len; > + } Will this accept zero-length helper string/name? > > if (n < 0) { > return -EINVAL; > @@ -1135,6 +1157,10 @@ parse_conntrack_action(const char *s_, struct ofpbuf > *actions) > nl_msg_put_unspec(actions, OVS_CT_ATTR_LABEL, &ct_label, > sizeof(ct_label)); > } > + if (helper) { > + nl_msg_put_string__(actions, OVS_CT_ATTR_HELPER, helper, > + helper_len); > + } > nl_msg_end_nested(actions, start); > } > > diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c > index 52a8502..28ab521 100644 > --- a/lib/ofp-actions.c > +++ b/lib/ofp-actions.c > @@ -15,6 +15,8 @@ > */ > > #include <config.h> > +#include <netinet/in.h> > + > #include "ofp-actions.h" > #include "bundle.h" > #include "byte-order.h" > @@ -4632,6 +4634,8 @@ parse_CT(char *arg, struct ofpbuf *ofpacts, > return error; > } > } > + } else if (!strcmp(key, "alg")) { > + error = str_to_connhelper(value, &oc->alg); > } else if (!strcmp(key, "exec")) { > /* Hide existing actions from ofpacts_parse_actions(), so the > * nesting can be handled transparently. */ > @@ -4665,6 +4669,18 @@ append_comma(struct ds *s, bool *first) > } > > static void > +format_alg(int port, struct ds *s, bool *first) > +{ > + if (port == IPPORT_FTP) { > + append_comma(s, first); > + ds_put_format(s, "alg=ftp,"); > + } else if (port) { > + append_comma(s, first); > + ds_put_format(s, "alg=%d,", port); > + } > +} > + > +static void > format_CT(const struct ofpact_conntrack *a, struct ds *s) > { > bool first = true; > @@ -4678,6 +4694,7 @@ format_CT(const struct ofpact_conntrack *a, struct ds > *s) > append_comma(s, &first); > ds_put_format(s, "table=%"PRIu8, a->recirc_table); > } > + format_alg(a->alg, s, &first); > if (a->zone_src.field) { > append_comma(s, &first); > ds_put_format(s, "zone="); > @@ -4686,6 +4703,7 @@ format_CT(const struct ofpact_conntrack *a, struct ds > *s) > append_comma(s, &first); > ds_put_format(s, "zone=%"PRIu16, a->zone_imm); > } > + format_alg(a->alg, s, &first); > if (ofpact_ct_get_action_len(a)) { > append_comma(s, &first); > ds_put_cstr(s, "exec("); > diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c > index 75762b8..33df1ef 100644 > --- a/lib/ofp-parse.c > +++ b/lib/ofp-parse.c > @@ -21,6 +21,7 @@ > #include <ctype.h> > #include <errno.h> > #include <stdlib.h> > +#include <netinet/in.h> > > #include "byte-order.h" > #include "dynamic-string.h" > @@ -168,6 +169,20 @@ str_to_ip(const char *str, ovs_be32 *ip) > return NULL; > } > > +/* Parses 'str' as a conntrack helper into 'alg'. > + * > + * Returns NULL if successful, otherwise a malloc()'d string describing the > + * error. The caller is responsible for freeing the returned string. */ > +char * OVS_WARN_UNUSED_RESULT > +str_to_connhelper(const char *str, uint16_t *alg) > +{ > + if (!strcmp(str, "ftp")) { > + *alg = IPPORT_FTP; > + return NULL; > + } > + return xasprintf("invalid conntrack helper \"%s\"", str); > +} > + > struct protocol { > const char *name; > uint16_t dl_type; > diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h > index b64a32e..36f9acc 100644 > --- a/lib/ofp-parse.h > +++ b/lib/ofp-parse.h > @@ -99,5 +99,6 @@ char *str_to_u64(const char *str, uint64_t *valuep) > OVS_WARN_UNUSED_RESULT; > char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT; > char *str_to_mac(const char *str, struct eth_addr *mac) > OVS_WARN_UNUSED_RESULT; > char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT; > +char *str_to_connhelper(const char *str, uint16_t *alg) > OVS_WARN_UNUSED_RESULT; > > #endif /* ofp-parse.h */ > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index 5da8f2f..509e94e 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -4207,6 +4207,21 @@ put_ct_label(const struct flow *flow, struct flow > *base_flow, > } > > static void > +put_connhelper(struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc) > +{ > + if (ofc->alg) { > + if (ofc->alg == IPPORT_FTP) { > + const char *helper = "ftp"; > + > + nl_msg_put_string__(odp_actions, OVS_CT_ATTR_HELPER, helper, > + strlen(helper)); > + } else { > + VLOG_WARN("Cannot serialize connhelper %d\n", ofc->alg); > + } > + } > +} > + > +static void > compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc) > { > uint32_t flags = 0; > @@ -4234,6 +4249,7 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct > ofpact_conntrack *ofc) > nl_msg_put_u16(ctx->odp_actions, OVS_CT_ATTR_ZONE, zone); > put_ct_mark(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc); > put_ct_label(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc); > + put_connhelper(ctx->odp_actions, ofc); > nl_msg_end_nested(ctx->odp_actions, ct_offset); > > if (ofc->recirc_table == NX_CT_RECIRC_NONE) { > diff --git a/tests/atlocal.in b/tests/atlocal.in > index 8e9fd9b..095bc40 100644 > --- a/tests/atlocal.in > +++ b/tests/atlocal.in > @@ -117,3 +117,10 @@ if test x`which conntrack` != x; then > else > HAVE_CONNTRACK="no" > fi > + > +if test "$HAVE_PYTHON" = "yes" \ > + && test "x`$PYTHON $abs_top_srcdir/tests/test-l7.py --help | grep 'ftp'`" > != x; then > + HAVE_PYFTPDLIB="yes" > +else > + HAVE_PYFTPDLIB="no" > +fi > diff --git a/tests/odp.at b/tests/odp.at > index 702d44c..e4e95a0 100644 > --- a/tests/odp.at > +++ b/tests/odp.at > @@ -309,6 +309,7 @@ > tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:1 > ct > ct(commit) > ct(commit,zone=5) > +ct(commit,helper=ftp) > ]) > AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], > [`cat actions.txt` > diff --git a/tests/system-traffic.at b/tests/system-traffic.at > index 8c198f9..cdd0315 100644 > --- a/tests/system-traffic.at > +++ b/tests/system-traffic.at > @@ -778,3 +778,148 @@ > icmp,vlan_tci=0x0000,dl_src=c6:f9:4e:cb:72:db,dl_dst=e6:4c:47:35:28:c9,nw_src=17 > > OVS_TRAFFIC_VSWITCHD_STOP > AT_CLEANUP > + > +AT_SETUP([conntrack - FTP]) > +AT_SKIP_IF([test $HAVE_PYFTPDLIB = no]) > +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([flows1.txt], [dnl > +priority=1,action=drop > +priority=10,arp,action=normal > +priority=10,icmp,action=normal > +in_port=1,tcp,action=ct(alg=ftp,commit),2 > +in_port=2,tcp,ct_state=-trk,action=ct(table=0) > +in_port=2,tcp,ct_state=+trk-new+est,action=1 +est should be sufficient? > +in_port=2,tcp,ct_state=+trk+rel,action=1 +rel is enough? > +]) > + > +dnl Similar policy but without allowing all traffic from ns0->ns1. > +AT_DATA([flows2.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) > +in_port=1,tcp,ct_state=+trk+new,action=ct(commit,alg=ftp),2 > +in_port=1,tcp,ct_state=+trk+est,action=2 > +in_port=2,tcp,ct_state=-trk,action=ct(table=0) > +in_port=2,tcp,ct_state=+trk+new+rel,action=ct(commit),1 > +in_port=2,tcp,ct_state=+trk-new+est,action=1 > +in_port=2,tcp,ct_state=+trk-new+rel,action=1 explicit priorities would be nice. > +]) > + > +AT_CHECK([ovs-ofctl add-flows br0 flows1.txt]) > + > +NETNS_DAEMONIZE([at_ns0], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp1.pid]) > +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp0.pid]) > + > +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], [wget ftp://10.1.1.1 --no-passive-ftp -t 3 -T 1 -v > -o wget1.log], [4]) > +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.1)], [0], [dnl > +]) > + > +dnl FTP requests from p0->p1 should work fine. > +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 > --retry-connrefused -v -o wget0.log]) > +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [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 > helper=ftp use=1 > +]) > + > +dnl Try the second set of flows. > +conntrack -F > +AT_CHECK([ovs-ofctl del-flows br0]) > +AT_CHECK([ovs-ofctl add-flows br0 flows2.txt]) > + > +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], [wget ftp://10.1.1.1 --no-passive-ftp -t 3 -T 1 -v > -o wget1.log], [4]) > +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.1)], [0], [dnl > +]) > + > +dnl Active FTP requests from p0->p1 should work fine. > +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 > --retry-connrefused -v -o wget0.log]) > +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [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 > helper=ftp use=2 > +TIME_WAIT src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> > src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 > use=1 > +]) > + > +AT_CHECK([conntrack -F 2>/dev/null]) > + > +dnl Passive FTP requests from p0->p1 should work fine. > +NS_CHECK_EXEC([at_ns0], [wget ftp://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) | grep -v "FIN"], [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 > helper=ftp use=2 > +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 > +]) > + > +OVS_TRAFFIC_VSWITCHD_STOP > +AT_CLEANUP > + > +AT_SETUP([conntrack - FTP with multiple expectations]) > +AT_SKIP_IF([test $HAVE_PYFTPDLIB = no]) > +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 Dual-firewall, allow all from ns1->ns2, allow established and ftp > ns2->ns1. > +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(table=0,zone=1) > +in_port=1,tcp,ct_zone=1,ct_state=+trk+new,action=ct(commit,alg=ftp,zone=1),ct(commit,alg=ftp,zone=2),2 > +in_port=1,tcp,ct_zone=1,ct_state=+trk+est,action=ct(table=0,zone=2) > +in_port=1,tcp,ct_zone=2,ct_state=+trk+new,action=ct(commit,alg=ftp,zone=2) > +in_port=1,tcp,ct_zone=2,ct_state=+trk+est,action=2 > +in_port=2,tcp,ct_state=-trk,action=ct(table=0,zone=2) > +in_port=2,tcp,ct_zone=2,ct_state=+trk+rel,action=ct(commit,zone=2),ct(commit,zone=1),1 > +in_port=2,tcp,ct_zone=2,ct_state=+trk-new+est,action=ct(table=0,zone=1) > +in_port=2,tcp,ct_zone=1,ct_state=+trk+rel,action=ct(commit,zone=2),ct(commit,zone=1),1 > +in_port=2,tcp,ct_zone=1,ct_state=+trk-new+est,action=1 priorities, also +trk is redundant in most cases. > +]) > + > +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) > + > +NETNS_DAEMONIZE([at_ns0], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp1.pid]) > +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp0.pid]) > + > +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], [wget ftp://10.1.1.1 --no-passive-ftp -t 3 -T 1 -v > -o wget1.log], [4]) > +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.1)], [0], [dnl > +]) > + > +dnl Active FTP requests from p0->p1 should work fine. > +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 > --retry-connrefused -v -o wget0.log]) > +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [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 helper=ftp use=2 > +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 helper=ftp use=2 > +TIME_WAIT src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> > src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 > zone=1 use=1 > +TIME_WAIT src=10.1.1.2 dst=10.1.1.1 sport=<cleared> dport=<cleared> > src=10.1.1.1 dst=10.1.1.2 sport=<cleared> dport=<cleared> [[ASSURED]] mark=0 > zone=2 use=1 > +]) > + > +AT_CHECK([conntrack -F 2>/dev/null]) > + > +dnl Passive FTP requests from p0->p1 should work fine. > +NS_CHECK_EXEC([at_ns0], [wget ftp://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) | grep -v "FIN"], [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 helper=ftp use=2 > +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 > +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 helper=ftp use=2 > +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 I had to install pyftpdlib to run these tests, would be nice to have that documented somewhere. > diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in > index b1ee36e..3d3bacb 100644 > --- a/utilities/ovs-ofctl.8.in > +++ b/utilities/ovs-ofctl.8.in > @@ -1638,6 +1638,17 @@ specified in the \fBct\fR action. > Store a 128-bit metadata value (masked by \fImask\fR) with the connection. > This will populate the \fBct_label\fR flow field if the \fBtable\fR is > specified in the \fBct\fR action. > +.IP \fBalg=\fR\fIalg\fR > +Specify application layer gateway \fIalg\fR to track specific connection > +types. Supported types include: > +. > +.RS > +.IP \fBftp\fR > +Look for negotiation of FTP data connections. If a subsequent FTP data > +connection arrives which is related, the \fBct\fR action will mark such > +packets with the \fBrel\fR flag in the \fBct_state\fR field. > +.RE > +. > .RE > .IP > Currently, connection tracking is only available on Linux kernels with 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