[ovs-dev] [PATCH 6/9] netlink-conntrack: Add support for querying conntrack exp

Greg Rose gvrose8192 at gmail.com
Fri Sep 1 17:53:25 UTC 2017


On 08/25/2017 03:51 PM, Yi-Hung Wei wrote:
> The ct_state of an uncommmited new flow is marked as related if the flow
> is in the conntrack expectation table. In order for ofproto/trace to
> identify the ct_state of a new related flow, this patch utilizes
> NFNL_SUBSYS_CTNETLINK_EXP netlink subsystem to query the conntrack
> expectation table, therefore, we can mark the ct_state of a related flow
> correctly.
> 
> Signed-off-by: Yi-Hung Wei <yihung.wei at gmail.com>
> ---
>   lib/ct-dpif.h           |  13 ++++
>   lib/netlink-conntrack.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++
>   lib/netlink-conntrack.h |   2 +
>   tests/atlocal.in        |   3 +
>   tests/system-traffic.at | 137 ++++++++++++++++++++++++++++++++
>   5 files changed, 358 insertions(+)
> 
> diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
> index f4ca07b5e776..9122e8cd752b 100644
> --- a/lib/ct-dpif.h
> +++ b/lib/ct-dpif.h
> @@ -177,6 +177,19 @@ struct ct_dpif_info {
>       uint32_t ct_state;
>   };
>   
> +struct ct_dpif_exp_entry {
> +    struct ct_dpif_tuple tuple;
> +    struct ct_dpif_tuple tuple_mask;
> +    struct ct_dpif_tuple tuple_master;
> +    struct ct_dpif_tuple tuple_nat;
> +    struct ct_dpif_helper helper;
> +    uint32_t timeout;
> +    uint32_t id;
> +    uint32_t nat_dir;
> +    uint32_t exp_flags;
> +    uint32_t exp_class;
> +};
> +
>   enum {
>       CT_STATS_UDP,
>       CT_STATS_TCP,
> diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c
> index 93cd0ac2c34f..de1e467dc61a 100644
> --- a/lib/netlink-conntrack.c
> +++ b/lib/netlink-conntrack.c
> @@ -70,6 +70,15 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>   #define CTA_TIMESTAMP_START 1
>   #define CTA_TIMESTAMP_STOP  2
>   
> +#define CTA_EXPECT_ZONE   (CTA_EXPECT_HELP_NAME + 1)
> +#define CTA_EXPECT_FLAGS  (CTA_EXPECT_HELP_NAME + 2)
> +#define CTA_EXPECT_CLASS  (CTA_EXPECT_HELP_NAME + 3)
> +#define CTA_EXPECT_NAT    (CTA_EXPECT_HELP_NAME + 4)
> +#define CTA_EXPECT_FN     (CTA_EXPECT_HELP_NAME + 5)

These are duplicates of enums from /usr/include/linux/netfilter/nfnetlink_conntrack.h:

-----
enum ctattr_expect {
         CTA_EXPECT_UNSPEC,
         CTA_EXPECT_MASTER,
         CTA_EXPECT_TUPLE,
         CTA_EXPECT_MASK,
         CTA_EXPECT_TIMEOUT,
         CTA_EXPECT_ID,
         CTA_EXPECT_HELP_NAME,
         CTA_EXPECT_ZONE,
         CTA_EXPECT_FLAGS,
         CTA_EXPECT_CLASS,
         CTA_EXPECT_NAT,
         CTA_EXPECT_FN,
         __CTA_EXPECT_MAX
};
#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)


> +
> +#define CTA_EXPECT_NAT_DIR      1
> +#define CTA_EXPECT_NAT_TUPLE    2
> +

These are also duplicates from /usr/include/linux/netfilter/nfnetlink_conntrack.h.

>   #define IPS_TEMPLATE_BIT 11
>   #define IPS_TEMPLATE (1 << IPS_TEMPLATE_BIT)
>   
> @@ -99,6 +108,20 @@ static const struct nl_policy nfnlgrp_conntrack_policy[] = {
>        * CTA_LABELS_MASK are not received from kernel. */
>   };
>   
> +static const struct nl_policy nfnlgrp_conntrack_exp_policy[] = {
> +    [CTA_EXPECT_MASTER] = { .type = NL_A_NESTED, .optional = false },
> +    [CTA_EXPECT_TUPLE] = { .type = NL_A_NESTED, .optional = false },
> +    [CTA_EXPECT_MASK] = { .type = NL_A_NESTED, .optional = false },
> +    [CTA_EXPECT_TIMEOUT] = { .type = NL_A_U32, .optional = false },
> +    [CTA_EXPECT_ID] = { .type = NL_A_U32, .optional = false },
> +    [CTA_EXPECT_HELP_NAME] = { .type = NL_A_STRING, .optional = true },
> +    [CTA_EXPECT_ZONE] = { .type = NL_A_U16, .optional = true },
> +    [CTA_EXPECT_FLAGS] = { .type = NL_A_U32, .optional = false },
> +    [CTA_EXPECT_CLASS] = { .type = NL_A_U32, .optional = false },
> +    [CTA_EXPECT_NAT] = { .type = NL_A_NESTED, .optional = true },
> +    [CTA_EXPECT_FN] = { .type = NL_A_STRING, .optional = true },
> +};
> +
>   /* Declarations for conntrack netlink dumping. */
>   static void nl_msg_put_nfgenmsg(struct ofpbuf *msg, size_t expected_payload,
>                                   int family, uint8_t subsystem, uint8_t cmd,
> @@ -108,13 +131,22 @@ static bool nl_ct_parse_header_policy(struct ofpbuf *buf,
>           enum nl_ct_event_type *event_type,
>           uint8_t *nfgen_family,
>           struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)]);
> +static bool nl_ct_parse_ct_exp_policy(struct ofpbuf *buf,
> +        uint8_t *nfgen_family,
> +        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_exp_policy)]);
>   
>   static bool nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
>           struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)],
>           uint8_t nfgen_family);
> +static bool nl_ct_exp_attrs_to_ct_dpif_exp_entry(
> +        struct ct_dpif_exp_entry *entry,
> +        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_exp_policy)],
> +        uint8_t nfgen_family);
>   
>   static bool nl_ct_put_ct_tuple(struct ofpbuf *, struct ct_dpif_tuple *,
>                                  enum ctattr_type);
> +static bool nl_ct_put_ct_exp_tuple(struct ofpbuf *, struct ct_dpif_tuple *,
> +                                   enum ctattr_expect);
>   
>   struct nl_ct_dump_state {
>       struct nl_dump dump;
> @@ -385,6 +417,51 @@ nl_ct_get_ct_state(struct ct_dpif_tuple *tuple, struct ct_dpif_entry *entry,
>       }
>   }
>   
> +/* Searches nf_conntrack's expectation table for 'tuple' in 'zone'.
> + * Sets 'exp' and returns 0 if we successfully find a match. Otherwise,
> + * returns non-zero errno. */
> +int
> +nl_ct_get_expect(struct ct_dpif_tuple *tuple, uint16_t zone,
> +                    struct ct_dpif_exp_entry *exp)
> +{
> +    struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_exp_policy)];
> +    struct ofpbuf request, *reply;
> +    uint8_t nfgen_family;
> +    int err;
> +
> +    ofpbuf_init(&request, NL_DUMP_BUFSIZE);
> +
> +    nl_msg_put_nfgenmsg(&request, 0, tuple->l3_type, NFNL_SUBSYS_CTNETLINK_EXP,
> +                       IPCTNL_MSG_EXP_GET, NLM_F_REQUEST);
> +    nl_msg_put_be16(&request, CTA_EXPECT_ZONE, htons(zone));
> +    if (!nl_ct_put_ct_exp_tuple(&request, tuple, CTA_EXPECT_TUPLE)) {
> +        ofpbuf_uninit(&request);
> +        return EOPNOTSUPP;
> +    }
> +
> +    err = nl_transact(NETLINK_NETFILTER, &request, &reply);
> +    ofpbuf_uninit(&request);
> +    if (err) {
> +        return err;
> +    }
> +
> +    if (!nl_ct_parse_ct_exp_policy(reply, &nfgen_family, attrs)) {
> +        goto out;
> +    }
> +
> +    memset(exp, 0, sizeof(*exp));
> +    if (!nl_ct_exp_attrs_to_ct_dpif_exp_entry(exp, attrs, nfgen_family)) {
> +        goto out;
> +    }
> +
> +    ofpbuf_delete(reply);
> +    return 0;
> +
> +out:
> +    ofpbuf_delete(reply);
> +    return EOPNOTSUPP;
> +}
> +
>   int
>   nl_ct_get_info(struct ct_dpif_tuple *tuple, uint16_t zone,
>                  struct ct_dpif_info *info)
> @@ -392,10 +469,17 @@ nl_ct_get_info(struct ct_dpif_tuple *tuple, uint16_t zone,
>       struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
>       struct ofpbuf request, *reply;
>       struct ct_dpif_entry entry;
> +    struct ct_dpif_exp_entry exp;
>       enum nl_ct_event_type type;
>       uint8_t nfgen_family;
>       int err;
>   
> +    if (nl_ct_get_expect(tuple, zone, &exp) == 0) {
> +        info->ct_state = CS_TRACKED | CS_NEW | CS_RELATED;
> +        free(exp.helper.name);

I feel like nl_ct_get_expect() should clean up after itself and not expect the caller to free this.

> +        return 0;
> +    }
> +
>       ofpbuf_init(&request, NL_DUMP_BUFSIZE);
>       nl_msg_put_nfgenmsg(&request, 0, tuple->l3_type, NFNL_SUBSYS_CTNETLINK,
>                           IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
> @@ -721,6 +805,23 @@ nl_ct_put_ct_tuple(struct ofpbuf *buf, struct ct_dpif_tuple *tuple,
>       return true;
>   }
>   
> +static bool
> +nl_ct_put_ct_exp_tuple(struct ofpbuf *buf, struct ct_dpif_tuple *tuple,
> +                       enum ctattr_expect type)
> +{
> +    size_t offset = nl_msg_start_nested(buf, type);
> +
> +    if (type != CTA_EXPECT_TUPLE && type != CTA_EXPECT_MASTER) {
> +        return false;
> +    }

I would not call nl_msg_start_nested() until after the check above.

> +    if (!nl_ct_put_tuple(buf, tuple)) {
> +        return false;
> +    }
> +
> +    nl_msg_end_nested(buf, offset);
> +    return true;
> +}
> +
>   /* Translate netlink TCP state to CT_DPIF_TCP state. */
>   static uint8_t
>   nl_ct_tcp_state_to_dpif(uint8_t state)
> @@ -945,6 +1046,42 @@ nl_ct_parse_header_policy(struct ofpbuf *buf,
>   }
>   
>   static bool
> +nl_ct_parse_ct_exp_policy(struct ofpbuf *buf, uint8_t *nfgen_family,
> +        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_exp_policy)])
> +{
> +    struct nlmsghdr *nlh;
> +    struct nfgenmsg *nfm;
> +
> +    nlh = ofpbuf_at(buf, 0, NLMSG_HDRLEN);
> +    nfm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *nfm);
> +    if (!nfm) {
> +        VLOG_ERR_RL(&rl, "Received bad nfnl message (no nfgenmsg).");
> +        return false;
> +    }
> +    if (NFNL_SUBSYS_ID(nlh->nlmsg_type) != NFNL_SUBSYS_CTNETLINK_EXP) {
> +        VLOG_ERR_RL(&rl, "Received non-conntrack message (subsystem: %u).",
> +                 NFNL_SUBSYS_ID(nlh->nlmsg_type));
> +        return false;
> +    }
> +    if (nfm->version != NFNETLINK_V0) {
> +        VLOG_ERR_RL(&rl, "Received unsupported nfnetlink version (%u).",
> +                 NFNL_MSG_TYPE(nfm->version));
> +        return false;
> +    }
> +
> +    if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof *nfm,
> +                         nfnlgrp_conntrack_exp_policy, attrs,
> +                         ARRAY_SIZE(nfnlgrp_conntrack_exp_policy))) {
> +        VLOG_ERR_RL(&rl, "Received bad nfnl message (policy).");
> +        return false;
> +    }
> +
> +    *nfgen_family = nfm->nfgen_family;
> +
> +    return true;
> +}
> +
> +static bool
>   nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
>           struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)],
>           uint8_t nfgen_family)
> @@ -1008,6 +1145,72 @@ nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
>       return true;
>   }
>   
> +static bool
> +nl_ct_parse_exp_nat(struct nlattr *nla, struct ct_dpif_exp_entry *entry,
> +                    uint16_t l3_type)
> +{
> +    static const struct nl_policy policy[] = {
> +        [CTA_EXPECT_NAT_DIR] = { .type = NL_A_BE32, .optional = false },
> +        [CTA_EXPECT_NAT_TUPLE] = { .type = NL_A_NESTED, .optional = false },
> +    };
> +    struct nlattr *attrs[ARRAY_SIZE(policy)];
> +    bool parsed;
> +
> +    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
> +
> +    if (parsed) {
> +        entry->nat_dir = ntohl(nl_attr_get_be32(attrs[CTA_EXPECT_NAT_DIR]));
> +        if (!nl_ct_parse_tuple(attrs[CTA_EXPECT_NAT_TUPLE], &entry->tuple_nat,
> +                               l3_type)) {
> +            return false;
> +        }
> +    } else {
> +        VLOG_ERR_RL(&rl, "Could not parse nested expect NAT options. "
> +                    "Possibly incompatible Linux kernel version.");
> +    }
> +    return parsed;
> +}
> +
> +static bool
> +nl_ct_exp_attrs_to_ct_dpif_exp_entry(struct ct_dpif_exp_entry *entry,
> +        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_exp_policy)],
> +        uint8_t nfgen_family)
> +{
> +    if (!nl_ct_parse_tuple(attrs[CTA_EXPECT_TUPLE], &entry->tuple,
> +                           nfgen_family)) {
> +        return false;
> +    }
> +    if (!nl_ct_parse_tuple(attrs[CTA_EXPECT_MASK], &entry->tuple_mask,
> +                           nfgen_family)) {
> +        return false;
> +    }
> +    if (!nl_ct_parse_tuple(attrs[CTA_EXPECT_MASTER], &entry->tuple_master,
> +                           nfgen_family)) {
> +        return false;
> +    }
> +    if (attrs[CTA_EXPECT_NAT] &&
> +        !nl_ct_parse_exp_nat(attrs[CTA_EXPECT_NAT], entry, nfgen_family)) {
> +        return false;
> +    }
> +    if (attrs[CTA_EXPECT_TIMEOUT]) {
> +        entry->timeout = ntohl(nl_attr_get_be32(attrs[CTA_EXPECT_TIMEOUT]));
> +    }
> +    if (attrs[CTA_EXPECT_ID]) {
> +        entry->id = ntohl(nl_attr_get_be32(attrs[CTA_EXPECT_ID]));
> +    }
> +    if (attrs[CTA_EXPECT_FLAGS]) {
> +        entry->exp_flags = ntohl(nl_attr_get_be32(attrs[CTA_EXPECT_FLAGS]));
> +    }
> +    if (attrs[CTA_EXPECT_CLASS]) {
> +        entry->exp_class = ntohl(nl_attr_get_be32(attrs[CTA_EXPECT_CLASS]));
> +    }
> +    if (attrs[CTA_EXPECT_HELP_NAME]) {
> +        entry->helper.name = xstrdup(nl_attr_get_string(
> +                                attrs[CTA_EXPECT_HELP_NAME]));
> +    }
> +    return true;
> +}
> +

I think in general you need to provide more comments for your new functions
and struct declarations.

http://docs.openvswitch.org/en/latest/internals/contributing/coding-style/#functions

Thanks,

- Greg

>   bool
>   nl_ct_parse_entry(struct ofpbuf *buf, struct ct_dpif_entry *entry,
>                     enum nl_ct_event_type *event_type)
> diff --git a/lib/netlink-conntrack.h b/lib/netlink-conntrack.h
> index 86d3adab0403..4c5798bdefc8 100644
> --- a/lib/netlink-conntrack.h
> +++ b/lib/netlink-conntrack.h
> @@ -45,6 +45,8 @@ int nl_ct_flush_zone(uint16_t zone);
>   
>   int nl_ct_get_info(struct ct_dpif_tuple *, uint16_t zone,
>                      struct ct_dpif_info *info);
> +int nl_ct_get_expect(struct ct_dpif_tuple *, uint16_t zone,
> +                     struct ct_dpif_exp_entry *);
>   
>   bool nl_ct_parse_entry(struct ofpbuf *, struct ct_dpif_entry *,
>                          enum nl_ct_event_type *);
> diff --git a/tests/atlocal.in b/tests/atlocal.in
> index 7c5e9e3357e5..35a1c7ebc7d0 100644
> --- a/tests/atlocal.in
> +++ b/tests/atlocal.in
> @@ -162,6 +162,9 @@ fi
>   # Set HAVE_TCPDUMP
>   find_command tcpdump
>   
> +# Set HAVE_CONNTRACK
> +find_command conntrack
> +
>   CURL_OPT="-g -v --max-time 1 --retry 2 --retry-delay 1 --connect-timeout 1"
>   
>   # Turn off proxies.
> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> index ccad3fab0ca4..727f97f7a7dd 100644
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -4113,6 +4113,143 @@ AT_CHECK([grep -c 'ct_state=est|rpl|trk' stdout], [0], [2
>   OVS_TRAFFIC_VSWITCHD_STOP
>   AT_CLEANUP
>   
> +AT_SETUP([conntrack - ofproto/trace FTP])
> +AT_SKIP_IF([test $HAVE_FTP = no])
> +AT_SKIP_IF([test $HAVE_CONNTRACK = no])
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_ALG()
> +CHECK_CT_DPIF_GET_INFO()
> +OVS_TRAFFIC_VSWITCHD_START()
> +
> +ADD_NAMESPACES(at_ns0, at_ns1)
> +
> +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
> +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
> +
> +dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
> +AT_DATA([flows1.txt], [dnl
> +table=0,priority=1,action=drop
> +table=0,priority=10,arp,action=normal
> +table=0,priority=10,icmp,action=normal
> +table=0,priority=100,in_port=1,tcp,action=ct(alg=ftp,commit),2
> +table=0,priority=100,in_port=2,tcp,action=ct(table=1)
> +table=1,in_port=2,tcp,ct_state=+trk+est,action=1
> +table=1,in_port=2,tcp,ct_state=+trk+rel,action=1
> +])
> +
> +dnl Similar policy but without allowing all traffic from ns0->ns1.
> +AT_DATA([flows2.txt], [dnl
> +table=0,priority=1,action=drop
> +table=0,priority=10,arp,action=normal
> +table=0,priority=10,icmp,action=normal
> +
> +dnl Allow outgoing TCP connections, and treat them as FTP
> +table=0,priority=100,in_port=1,tcp,action=ct(table=1)
> +table=1,in_port=1,tcp,ct_state=+trk+new,action=ct(commit,alg=ftp),2
> +table=1,in_port=1,tcp,ct_state=+trk+est,action=2
> +
> +dnl Allow incoming FTP data connections and responses to existing connections
> +table=0,priority=100,in_port=2,tcp,action=ct(table=1)
> +table=1,in_port=2,tcp,ct_state=+trk+new+rel,action=ct(commit),1
> +table=1,in_port=2,tcp,ct_state=+trk+est,action=1
> +table=1,in_port=2,tcp,ct_state=+trk-new+rel,action=1
> +])
> +
> +AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows1.txt])
> +
> +OVS_START_L7([at_ns0], [ftp])
> +OVS_START_L7([at_ns1], [ftp])
> +
> +dnl FTP requests from p1->p0 should fail due to network failure.
> +dnl Try 3 times, in 1 second intervals.
> +NS_CHECK_EXEC([at_ns1], [wget ftp://10.1.1.1 --no-passive-ftp  -t 3 -T 1 -v -o wget1.log], [4])
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
> +])
> +
> +dnl FTP requests from p0->p1 should work fine.
> +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0.log])
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
> +tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
> +])
> +
> +dnl Test ofproto/trace
> +DPORT=$(conntrack -L expect | grep 'src=10.1.1.2' | cut -d ' ' -f6 | cut -d '=' -f2)
> +
> +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,dl_type=0x800,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_proto=6,tcp_src=12345,tcp_dst=$DPORT"], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> +  [Datapath actions: 2
> +])
> +AT_CHECK([grep -c 'ct_state=new|rel|trk' stdout], [0], [2
> +])
> +
> +dnl Try the second set of flows.
> +AT_CHECK([ovs-ofctl --bundle replace-flows br0 flows2.txt])
> +AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> +
> +dnl FTP requests from p1->p0 should fail due to network failure.
> +dnl Try 3 times, in 1 second intervals.
> +NS_CHECK_EXEC([at_ns1], [wget ftp://10.1.1.1 --no-passive-ftp  -t 3 -T 1 -v -o wget1.log], [4])
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl
> +])
> +
> +dnl Active FTP requests from p0->p1 should work fine.
> +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0-1.log])
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
> +tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
> +tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>)
> +])
> +
> +dnl Test ofproto/trace
> +ovs-appctl dpctl/dump-conntrack
> +CONNTRACK_INFO=$(ovs-appctl dpctl/dump-conntrack | grep -v 'dport=21)' | grep '(src=10.1.1.2,dst=10.1.1.1,')
> +SPORT=$(echo $CONNTRACK_INFO | cut -d ',' -f4 | cut -d '=' -f2)
> +DPORT=$(echo $CONNTRACK_INFO | cut -d ',' -f5 | cut -d ')' -f1 | cut -d '=' -f2)
> +
> +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,dl_type=0x800,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_proto=6,tcp_src=$SPORT,tcp_dst=$DPORT"], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> +  [Datapath actions: 2
> +])
> +AT_CHECK([grep -c 'ct_state=est|rel|trk' stdout], [0], [2
> +])
> +
> +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_type=0x800,nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_proto=6,tcp_src=$DPORT,tcp_dst=$SPORT"], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> +  [Datapath actions: 3
> +])
> +AT_CHECK([grep -c 'ct_state=est|rel|rpl|trk' stdout], [0], [2
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> +
> +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-2.log])
> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
> +tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),protoinfo=(state=<cleared>),helper=ftp
> +])
> +
> +dnl Test ofproto/trace
> +ovs-appctl dpctl/dump-conntrack
> +CONNTRACK_INFO=$(ovs-appctl dpctl/dump-conntrack | grep -v 'dport=21)' | grep '(src=10.1.1.1,dst=10.1.1.2,')
> +SPORT=$(echo $CONNTRACK_INFO | cut -d ',' -f4 | cut -d '=' -f2)
> +DPORT=$(echo $CONNTRACK_INFO | cut -d ',' -f5 | cut -d ')' -f1 | cut -d '=' -f2)
> +
> +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,dl_type=0x800,nw_src=10.1.1.2,nw_dst=10.1.1.1,nw_proto=6,tcp_src=$DPORT,tcp_dst=$SPORT"], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> +  [Datapath actions: 2
> +])
> +AT_CHECK([grep -c 'ct_state=est|rel|rpl|trk' stdout], [0], [2
> +])
> +
> +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_type=0x800,nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_proto=6,tcp_src=$SPORT,tcp_dst=$DPORT"], [0], [stdout])
> +AT_CHECK([tail -1 stdout], [0],
> +  [Datapath actions: 3
> +])
> +AT_CHECK([grep -c 'ct_state=est|rel|trk' stdout], [0], [2
> +])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
>   AT_SETUP([conntrack - ofproto/trace SNAT])
>   AT_SKIP_IF([test $HAVE_NC = no])
>   CHECK_CONNTRACK()
> 



More information about the dev mailing list