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

Reply via email to