[ovs-dev] conntrack: Support conntrack flush by ct 5-tuple

Message ID 1518472957-6020-1-git-send-email-yihung.wei@gmail.com
State Accepted
Headers show
Series
  • [ovs-dev] conntrack: Support conntrack flush by ct 5-tuple
Related show

Commit Message

Yi-Hung Wei Feb. 12, 2018, 10:02 p.m.
This patch adds support of flushing a conntrack entry specified by the
conntrack 5-tuple in dpif-netdev.

Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
---
Respin this patch since userspace conntrack now clears out the expectation
when a conntrack entry is deleted.
---
 lib/conntrack.c                  | 72 ++++++++++++++++++++++++++++++++++++++++
 lib/conntrack.h                  |  3 ++
 lib/dpif-netdev.c                |  2 +-
 tests/system-kmod-macros.at      |  8 -----
 tests/system-traffic.at          |  1 -
 tests/system-userspace-macros.at | 10 ------
 6 files changed, 76 insertions(+), 20 deletions(-)

Comments

Darrell Ball Feb. 13, 2018, 12:26 a.m. | #1
Thanks Yi-hung

I will try it out.

Darrell

On Mon, Feb 12, 2018 at 2:02 PM, Yi-Hung Wei <yihung.wei@gmail.com> wrote:

> This patch adds support of flushing a conntrack entry specified by the
> conntrack 5-tuple in dpif-netdev.
>
> Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
> ---
> Respin this patch since userspace conntrack now clears out the expectation
> when a conntrack entry is deleted.
> ---
>  lib/conntrack.c                  | 72 ++++++++++++++++++++++++++++++
> ++++++++++
>  lib/conntrack.h                  |  3 ++
>  lib/dpif-netdev.c                |  2 +-
>  tests/system-kmod-macros.at      |  8 -----
>  tests/system-traffic.at          |  1 -
>  tests/system-userspace-macros.at | 10 ------
>  6 files changed, 76 insertions(+), 20 deletions(-)
>
> diff --git a/lib/conntrack.c b/lib/conntrack.c
> index fe5fd0fe8be1..c05b3901d7af 100644
> --- a/lib/conntrack.c
> +++ b/lib/conntrack.c
> @@ -2368,6 +2368,10 @@ delete_conn(struct conn *conn)
>      free(conn);
>  }
>
> +/* Convert a conntrack address 'a' into an IP address 'b' based on
> 'dl_type'.
> + *
> + * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
> + * in network-byte order. */
>  static void
>  ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
>                                   union ct_dpif_inet_addr *b,
> @@ -2380,6 +2384,22 @@ ct_endpoint_to_ct_dpif_inet_addr(const struct
> ct_addr *a,
>      }
>  }
>
> +/* Convert an IP address 'a' into a conntrack address 'b' based on
> 'dl_type'.
> + *
> + * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
> + * in network-byte order. */
> +static void
> +ct_dpif_inet_addr_to_ct_endpoint(const union ct_dpif_inet_addr *a,
> +                                 struct ct_addr *b,
> +                                 ovs_be16 dl_type)
> +{
> +    if (dl_type == htons(ETH_TYPE_IP)) {
> +        b->ipv4_aligned = a->ip;
> +    } else if (dl_type == htons(ETH_TYPE_IPV6)){
> +        b->ipv6_aligned = a->in6;
> +    }
> +}
> +
>  static void
>  conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple *tuple)
>  {
> @@ -2405,6 +2425,35 @@ conn_key_to_tuple(const struct conn_key *key,
> struct ct_dpif_tuple *tuple)
>  }
>
>  static void
> +tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone,
> +                  struct conn_key *key)
> +{
> +    if (tuple->l3_type == AF_INET) {
> +        key->dl_type = htons(ETH_TYPE_IP);
> +    } else if (tuple->l3_type == AF_INET6) {
> +        key->dl_type = htons(ETH_TYPE_IPV6);
> +    }
> +    key->nw_proto = tuple->ip_proto;
> +    ct_dpif_inet_addr_to_ct_endpoint(&tuple->src, &key->src.addr,
> +                                     key->dl_type);
> +    ct_dpif_inet_addr_to_ct_endpoint(&tuple->dst, &key->dst.addr,
> +                                     key->dl_type);
> +
> +    if (tuple->ip_proto == IPPROTO_ICMP || tuple->ip_proto ==
> IPPROTO_ICMPV6) {
> +        key->src.icmp_id = tuple->icmp_id;
> +        key->src.icmp_type = tuple->icmp_type;
> +        key->src.icmp_code = tuple->icmp_code;
> +        key->dst.icmp_id = tuple->icmp_id;
> +        key->dst.icmp_type = reverse_icmp_type(tuple->icmp_type);
> +        key->dst.icmp_code = tuple->icmp_code;
> +    } else {
> +        key->src.port = tuple->src_port;
> +        key->dst.port = tuple->dst_port;
> +    }
> +    key->zone = zone;
> +}
> +
> +static void
>  conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry
> *entry,
>                        long long now, int bkt)
>  {
> @@ -2517,6 +2566,29 @@ conntrack_flush(struct conntrack *ct, const
> uint16_t *zone)
>  }
>
>  int
> +conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple
> *tuple,
> +                      uint16_t zone)
> +{
> +    struct conn_lookup_ctx ctx;
> +    int error = 0;
> +
> +    memset(&ctx, 0, sizeof(ctx));
> +    tuple_to_conn_key(tuple, zone, &ctx.key);
> +    ctx.hash = conn_key_hash(&ctx.key, ct->hash_basis);
> +    unsigned bucket = hash_to_bucket(ctx.hash);
> +
> +    ct_lock_lock(&ct->buckets[bucket].lock);
> +    conn_key_lookup(&ct->buckets[bucket], &ctx, time_msec());
> +    if (ctx.conn) {
> +        conn_clean(ct, ctx.conn, &ct->buckets[bucket]);
> +    } else {
> +        error = ENOENT;
> +    }
> +    ct_lock_unlock(&ct->buckets[bucket].lock);
> +    return error;
> +}
> +
> +int
>  conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns)
>  {
>      atomic_store_relaxed(&ct->n_conn_limit, maxconns);
> diff --git a/lib/conntrack.h b/lib/conntrack.h
> index ac650304a41f..e3a5dcc8023f 100644
> --- a/lib/conntrack.h
> +++ b/lib/conntrack.h
> @@ -109,6 +109,7 @@ struct conntrack_dump {
>  };
>
>  struct ct_dpif_entry;
> +struct ct_dpif_tuple;
>
>  int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,
>                           const uint16_t *pzone, int *);
> @@ -116,6 +117,8 @@ int conntrack_dump_next(struct conntrack_dump *,
> struct ct_dpif_entry *);
>  int conntrack_dump_done(struct conntrack_dump *);
>
>  int conntrack_flush(struct conntrack *, const uint16_t *zone);
> +int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple
> *,
> +                          uint16_t zone);
>  int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns);
>  int conntrack_get_maxconns(struct conntrack *ct, uint32_t *maxconns);
>  int conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns);
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index ba62128c758c..b06caa281afc 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -5842,7 +5842,7 @@ dpif_netdev_ct_flush(struct dpif *dpif, const
> uint16_t *zone,
>      struct dp_netdev *dp = get_dp_netdev(dpif);
>
>      if (tuple) {
> -        return EOPNOTSUPP;
> +        return conntrack_flush_tuple(&dp->conntrack, tuple, zone ? *zone
> : 0);
>      }
>      return conntrack_flush(&dp->conntrack, zone);
>  }
> diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
> index 12b0adf7190e..f23a4063375c 100644
> --- a/tests/system-kmod-macros.at
> +++ b/tests/system-kmod-macros.at
> @@ -97,14 +97,6 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK])
>  #
>  m4_define([CHECK_CONNTRACK_NAT])
>
> -# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
> -#
> -# Perform requirements checks for running ovs-dpctl flush-conntrack by
> -# conntrack 5-tuple test. The kernel datapath does support this
> -# feature. Will remove this check after both kernel and userspace datapath
> -# support it.
> -m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE])
> -
>  # CHECK_CT_DPIF_SET_GET_MAXCONNS()
>  #
>  # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> index dbd56405d1fd..2afadec15827 100644
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -834,7 +834,6 @@ AT_CLEANUP
>
>  AT_SETUP([conntrack - ct flush by 5-tuple])
>  CHECK_CONNTRACK()
> -CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
>  OVS_TRAFFIC_VSWITCHD_START()
>
>  ADD_NAMESPACES(at_ns0, at_ns1)
> diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-
> macros.at
> index 20a8635f9e39..00e1f817ff78 100644
> --- a/tests/system-userspace-macros.at
> +++ b/tests/system-userspace-macros.at
> @@ -100,16 +100,6 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK],
>  #
>  m4_define([CHECK_CONNTRACK_NAT])
>
> -# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
> -#
> -# Perform requirements checks for running ovs-dpctl flush-conntrack by
> -# conntrack 5-tuple test. The userspace datapath does not support
> -# this feature yet.
> -m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE],
> -[
> -    AT_SKIP_IF([:])
> -])
> -
>  # CHECK_CT_DPIF_SET_GET_MAXCONNS()
>  #
>  # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
> --
> 2.7.4
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Darrell Ball Feb. 13, 2018, 1:12 a.m. | #2
Nice.

Acked-by: Darrell Ball <dlu998@gmail.com>

On Mon, Feb 12, 2018 at 4:26 PM, Darrell Ball <dlu998@gmail.com> wrote:

> Thanks Yi-hung
>
> I will try it out.
>
> Darrell
>
> On Mon, Feb 12, 2018 at 2:02 PM, Yi-Hung Wei <yihung.wei@gmail.com> wrote:
>
>> This patch adds support of flushing a conntrack entry specified by the
>> conntrack 5-tuple in dpif-netdev.
>>
>> Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
>> ---
>> Respin this patch since userspace conntrack now clears out the expectation
>> when a conntrack entry is deleted.
>> ---
>>  lib/conntrack.c                  | 72 ++++++++++++++++++++++++++++++
>> ++++++++++
>>  lib/conntrack.h                  |  3 ++
>>  lib/dpif-netdev.c                |  2 +-
>>  tests/system-kmod-macros.at      |  8 -----
>>  tests/system-traffic.at          |  1 -
>>  tests/system-userspace-macros.at | 10 ------
>>  6 files changed, 76 insertions(+), 20 deletions(-)
>>
>> diff --git a/lib/conntrack.c b/lib/conntrack.c
>> index fe5fd0fe8be1..c05b3901d7af 100644
>> --- a/lib/conntrack.c
>> +++ b/lib/conntrack.c
>> @@ -2368,6 +2368,10 @@ delete_conn(struct conn *conn)
>>      free(conn);
>>  }
>>
>> +/* Convert a conntrack address 'a' into an IP address 'b' based on
>> 'dl_type'.
>> + *
>> + * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
>> + * in network-byte order. */
>>  static void
>>  ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
>>                                   union ct_dpif_inet_addr *b,
>> @@ -2380,6 +2384,22 @@ ct_endpoint_to_ct_dpif_inet_addr(const struct
>> ct_addr *a,
>>      }
>>  }
>>
>> +/* Convert an IP address 'a' into a conntrack address 'b' based on
>> 'dl_type'.
>> + *
>> + * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
>> + * in network-byte order. */
>> +static void
>> +ct_dpif_inet_addr_to_ct_endpoint(const union ct_dpif_inet_addr *a,
>> +                                 struct ct_addr *b,
>> +                                 ovs_be16 dl_type)
>> +{
>> +    if (dl_type == htons(ETH_TYPE_IP)) {
>> +        b->ipv4_aligned = a->ip;
>> +    } else if (dl_type == htons(ETH_TYPE_IPV6)){
>> +        b->ipv6_aligned = a->in6;
>> +    }
>> +}
>> +
>>  static void
>>  conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple
>> *tuple)
>>  {
>> @@ -2405,6 +2425,35 @@ conn_key_to_tuple(const struct conn_key *key,
>> struct ct_dpif_tuple *tuple)
>>  }
>>
>>  static void
>> +tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone,
>> +                  struct conn_key *key)
>> +{
>> +    if (tuple->l3_type == AF_INET) {
>> +        key->dl_type = htons(ETH_TYPE_IP);
>> +    } else if (tuple->l3_type == AF_INET6) {
>> +        key->dl_type = htons(ETH_TYPE_IPV6);
>> +    }
>> +    key->nw_proto = tuple->ip_proto;
>> +    ct_dpif_inet_addr_to_ct_endpoint(&tuple->src, &key->src.addr,
>> +                                     key->dl_type);
>> +    ct_dpif_inet_addr_to_ct_endpoint(&tuple->dst, &key->dst.addr,
>> +                                     key->dl_type);
>> +
>> +    if (tuple->ip_proto == IPPROTO_ICMP || tuple->ip_proto ==
>> IPPROTO_ICMPV6) {
>> +        key->src.icmp_id = tuple->icmp_id;
>> +        key->src.icmp_type = tuple->icmp_type;
>> +        key->src.icmp_code = tuple->icmp_code;
>> +        key->dst.icmp_id = tuple->icmp_id;
>> +        key->dst.icmp_type = reverse_icmp_type(tuple->icmp_type);
>> +        key->dst.icmp_code = tuple->icmp_code;
>> +    } else {
>> +        key->src.port = tuple->src_port;
>> +        key->dst.port = tuple->dst_port;
>> +    }
>> +    key->zone = zone;
>> +}
>> +
>> +static void
>>  conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry
>> *entry,
>>                        long long now, int bkt)
>>  {
>> @@ -2517,6 +2566,29 @@ conntrack_flush(struct conntrack *ct, const
>> uint16_t *zone)
>>  }
>>
>>  int
>> +conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple
>> *tuple,
>> +                      uint16_t zone)
>> +{
>> +    struct conn_lookup_ctx ctx;
>> +    int error = 0;
>> +
>> +    memset(&ctx, 0, sizeof(ctx));
>> +    tuple_to_conn_key(tuple, zone, &ctx.key);
>> +    ctx.hash = conn_key_hash(&ctx.key, ct->hash_basis);
>> +    unsigned bucket = hash_to_bucket(ctx.hash);
>> +
>> +    ct_lock_lock(&ct->buckets[bucket].lock);
>> +    conn_key_lookup(&ct->buckets[bucket], &ctx, time_msec());
>> +    if (ctx.conn) {
>> +        conn_clean(ct, ctx.conn, &ct->buckets[bucket]);
>> +    } else {
>> +        error = ENOENT;
>> +    }
>> +    ct_lock_unlock(&ct->buckets[bucket].lock);
>> +    return error;
>> +}
>> +
>> +int
>>  conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns)
>>  {
>>      atomic_store_relaxed(&ct->n_conn_limit, maxconns);
>> diff --git a/lib/conntrack.h b/lib/conntrack.h
>> index ac650304a41f..e3a5dcc8023f 100644
>> --- a/lib/conntrack.h
>> +++ b/lib/conntrack.h
>> @@ -109,6 +109,7 @@ struct conntrack_dump {
>>  };
>>
>>  struct ct_dpif_entry;
>> +struct ct_dpif_tuple;
>>
>>  int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,
>>                           const uint16_t *pzone, int *);
>> @@ -116,6 +117,8 @@ int conntrack_dump_next(struct conntrack_dump *,
>> struct ct_dpif_entry *);
>>  int conntrack_dump_done(struct conntrack_dump *);
>>
>>  int conntrack_flush(struct conntrack *, const uint16_t *zone);
>> +int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple
>> *,
>> +                          uint16_t zone);
>>  int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns);
>>  int conntrack_get_maxconns(struct conntrack *ct, uint32_t *maxconns);
>>  int conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns);
>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>> index ba62128c758c..b06caa281afc 100644
>> --- a/lib/dpif-netdev.c
>> +++ b/lib/dpif-netdev.c
>> @@ -5842,7 +5842,7 @@ dpif_netdev_ct_flush(struct dpif *dpif, const
>> uint16_t *zone,
>>      struct dp_netdev *dp = get_dp_netdev(dpif);
>>
>>      if (tuple) {
>> -        return EOPNOTSUPP;
>> +        return conntrack_flush_tuple(&dp->conntrack, tuple, zone ?
>> *zone : 0);
>>      }
>>      return conntrack_flush(&dp->conntrack, zone);
>>  }
>> diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
>> index 12b0adf7190e..f23a4063375c 100644
>> --- a/tests/system-kmod-macros.at
>> +++ b/tests/system-kmod-macros.at
>> @@ -97,14 +97,6 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK])
>>  #
>>  m4_define([CHECK_CONNTRACK_NAT])
>>
>> -# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
>> -#
>> -# Perform requirements checks for running ovs-dpctl flush-conntrack by
>> -# conntrack 5-tuple test. The kernel datapath does support this
>> -# feature. Will remove this check after both kernel and userspace
>> datapath
>> -# support it.
>> -m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE])
>> -
>>  # CHECK_CT_DPIF_SET_GET_MAXCONNS()
>>  #
>>  # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>> index dbd56405d1fd..2afadec15827 100644
>> --- a/tests/system-traffic.at
>> +++ b/tests/system-traffic.at
>> @@ -834,7 +834,6 @@ AT_CLEANUP
>>
>>  AT_SETUP([conntrack - ct flush by 5-tuple])
>>  CHECK_CONNTRACK()
>> -CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
>>  OVS_TRAFFIC_VSWITCHD_START()
>>
>>  ADD_NAMESPACES(at_ns0, at_ns1)
>> diff --git a/tests/system-userspace-macros.at b/tests/
>> system-userspace-macros.at
>> index 20a8635f9e39..00e1f817ff78 100644
>> --- a/tests/system-userspace-macros.at
>> +++ b/tests/system-userspace-macros.at
>> @@ -100,16 +100,6 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK],
>>  #
>>  m4_define([CHECK_CONNTRACK_NAT])
>>
>> -# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
>> -#
>> -# Perform requirements checks for running ovs-dpctl flush-conntrack by
>> -# conntrack 5-tuple test. The userspace datapath does not support
>> -# this feature yet.
>> -m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE],
>> -[
>> -    AT_SKIP_IF([:])
>> -])
>> -
>>  # CHECK_CT_DPIF_SET_GET_MAXCONNS()
>>  #
>>  # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
>> --
>> 2.7.4
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>
>
Ben Pfaff Feb. 14, 2018, 10:03 p.m. | #3
Thanks Yi-Hung and Darrell.  I applied this to master.

On Mon, Feb 12, 2018 at 05:12:24PM -0800, Darrell Ball wrote:
> Nice.
> 
> Acked-by: Darrell Ball <dlu998@gmail.com>
> 
> On Mon, Feb 12, 2018 at 4:26 PM, Darrell Ball <dlu998@gmail.com> wrote:
> 
> > Thanks Yi-hung
> >
> > I will try it out.
> >
> > Darrell
> >
> > On Mon, Feb 12, 2018 at 2:02 PM, Yi-Hung Wei <yihung.wei@gmail.com> wrote:
> >
> >> This patch adds support of flushing a conntrack entry specified by the
> >> conntrack 5-tuple in dpif-netdev.
> >>
> >> Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
> >> ---
> >> Respin this patch since userspace conntrack now clears out the expectation
> >> when a conntrack entry is deleted.
> >> ---
> >>  lib/conntrack.c                  | 72 ++++++++++++++++++++++++++++++
> >> ++++++++++
> >>  lib/conntrack.h                  |  3 ++
> >>  lib/dpif-netdev.c                |  2 +-
> >>  tests/system-kmod-macros.at      |  8 -----
> >>  tests/system-traffic.at          |  1 -
> >>  tests/system-userspace-macros.at | 10 ------
> >>  6 files changed, 76 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/lib/conntrack.c b/lib/conntrack.c
> >> index fe5fd0fe8be1..c05b3901d7af 100644
> >> --- a/lib/conntrack.c
> >> +++ b/lib/conntrack.c
> >> @@ -2368,6 +2368,10 @@ delete_conn(struct conn *conn)
> >>      free(conn);
> >>  }
> >>
> >> +/* Convert a conntrack address 'a' into an IP address 'b' based on
> >> 'dl_type'.
> >> + *
> >> + * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
> >> + * in network-byte order. */
> >>  static void
> >>  ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
> >>                                   union ct_dpif_inet_addr *b,
> >> @@ -2380,6 +2384,22 @@ ct_endpoint_to_ct_dpif_inet_addr(const struct
> >> ct_addr *a,
> >>      }
> >>  }
> >>
> >> +/* Convert an IP address 'a' into a conntrack address 'b' based on
> >> 'dl_type'.
> >> + *
> >> + * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
> >> + * in network-byte order. */
> >> +static void
> >> +ct_dpif_inet_addr_to_ct_endpoint(const union ct_dpif_inet_addr *a,
> >> +                                 struct ct_addr *b,
> >> +                                 ovs_be16 dl_type)
> >> +{
> >> +    if (dl_type == htons(ETH_TYPE_IP)) {
> >> +        b->ipv4_aligned = a->ip;
> >> +    } else if (dl_type == htons(ETH_TYPE_IPV6)){
> >> +        b->ipv6_aligned = a->in6;
> >> +    }
> >> +}
> >> +
> >>  static void
> >>  conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple
> >> *tuple)
> >>  {
> >> @@ -2405,6 +2425,35 @@ conn_key_to_tuple(const struct conn_key *key,
> >> struct ct_dpif_tuple *tuple)
> >>  }
> >>
> >>  static void
> >> +tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone,
> >> +                  struct conn_key *key)
> >> +{
> >> +    if (tuple->l3_type == AF_INET) {
> >> +        key->dl_type = htons(ETH_TYPE_IP);
> >> +    } else if (tuple->l3_type == AF_INET6) {
> >> +        key->dl_type = htons(ETH_TYPE_IPV6);
> >> +    }
> >> +    key->nw_proto = tuple->ip_proto;
> >> +    ct_dpif_inet_addr_to_ct_endpoint(&tuple->src, &key->src.addr,
> >> +                                     key->dl_type);
> >> +    ct_dpif_inet_addr_to_ct_endpoint(&tuple->dst, &key->dst.addr,
> >> +                                     key->dl_type);
> >> +
> >> +    if (tuple->ip_proto == IPPROTO_ICMP || tuple->ip_proto ==
> >> IPPROTO_ICMPV6) {
> >> +        key->src.icmp_id = tuple->icmp_id;
> >> +        key->src.icmp_type = tuple->icmp_type;
> >> +        key->src.icmp_code = tuple->icmp_code;
> >> +        key->dst.icmp_id = tuple->icmp_id;
> >> +        key->dst.icmp_type = reverse_icmp_type(tuple->icmp_type);
> >> +        key->dst.icmp_code = tuple->icmp_code;
> >> +    } else {
> >> +        key->src.port = tuple->src_port;
> >> +        key->dst.port = tuple->dst_port;
> >> +    }
> >> +    key->zone = zone;
> >> +}
> >> +
> >> +static void
> >>  conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry
> >> *entry,
> >>                        long long now, int bkt)
> >>  {
> >> @@ -2517,6 +2566,29 @@ conntrack_flush(struct conntrack *ct, const
> >> uint16_t *zone)
> >>  }
> >>
> >>  int
> >> +conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple
> >> *tuple,
> >> +                      uint16_t zone)
> >> +{
> >> +    struct conn_lookup_ctx ctx;
> >> +    int error = 0;
> >> +
> >> +    memset(&ctx, 0, sizeof(ctx));
> >> +    tuple_to_conn_key(tuple, zone, &ctx.key);
> >> +    ctx.hash = conn_key_hash(&ctx.key, ct->hash_basis);
> >> +    unsigned bucket = hash_to_bucket(ctx.hash);
> >> +
> >> +    ct_lock_lock(&ct->buckets[bucket].lock);
> >> +    conn_key_lookup(&ct->buckets[bucket], &ctx, time_msec());
> >> +    if (ctx.conn) {
> >> +        conn_clean(ct, ctx.conn, &ct->buckets[bucket]);
> >> +    } else {
> >> +        error = ENOENT;
> >> +    }
> >> +    ct_lock_unlock(&ct->buckets[bucket].lock);
> >> +    return error;
> >> +}
> >> +
> >> +int
> >>  conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns)
> >>  {
> >>      atomic_store_relaxed(&ct->n_conn_limit, maxconns);
> >> diff --git a/lib/conntrack.h b/lib/conntrack.h
> >> index ac650304a41f..e3a5dcc8023f 100644
> >> --- a/lib/conntrack.h
> >> +++ b/lib/conntrack.h
> >> @@ -109,6 +109,7 @@ struct conntrack_dump {
> >>  };
> >>
> >>  struct ct_dpif_entry;
> >> +struct ct_dpif_tuple;
> >>
> >>  int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,
> >>                           const uint16_t *pzone, int *);
> >> @@ -116,6 +117,8 @@ int conntrack_dump_next(struct conntrack_dump *,
> >> struct ct_dpif_entry *);
> >>  int conntrack_dump_done(struct conntrack_dump *);
> >>
> >>  int conntrack_flush(struct conntrack *, const uint16_t *zone);
> >> +int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple
> >> *,
> >> +                          uint16_t zone);
> >>  int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns);
> >>  int conntrack_get_maxconns(struct conntrack *ct, uint32_t *maxconns);
> >>  int conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns);
> >> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> >> index ba62128c758c..b06caa281afc 100644
> >> --- a/lib/dpif-netdev.c
> >> +++ b/lib/dpif-netdev.c
> >> @@ -5842,7 +5842,7 @@ dpif_netdev_ct_flush(struct dpif *dpif, const
> >> uint16_t *zone,
> >>      struct dp_netdev *dp = get_dp_netdev(dpif);
> >>
> >>      if (tuple) {
> >> -        return EOPNOTSUPP;
> >> +        return conntrack_flush_tuple(&dp->conntrack, tuple, zone ?
> >> *zone : 0);
> >>      }
> >>      return conntrack_flush(&dp->conntrack, zone);
> >>  }
> >> diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
> >> index 12b0adf7190e..f23a4063375c 100644
> >> --- a/tests/system-kmod-macros.at
> >> +++ b/tests/system-kmod-macros.at
> >> @@ -97,14 +97,6 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK])
> >>  #
> >>  m4_define([CHECK_CONNTRACK_NAT])
> >>
> >> -# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
> >> -#
> >> -# Perform requirements checks for running ovs-dpctl flush-conntrack by
> >> -# conntrack 5-tuple test. The kernel datapath does support this
> >> -# feature. Will remove this check after both kernel and userspace
> >> datapath
> >> -# support it.
> >> -m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE])
> >> -
> >>  # CHECK_CT_DPIF_SET_GET_MAXCONNS()
> >>  #
> >>  # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
> >> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> >> index dbd56405d1fd..2afadec15827 100644
> >> --- a/tests/system-traffic.at
> >> +++ b/tests/system-traffic.at
> >> @@ -834,7 +834,6 @@ AT_CLEANUP
> >>
> >>  AT_SETUP([conntrack - ct flush by 5-tuple])
> >>  CHECK_CONNTRACK()
> >> -CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
> >>  OVS_TRAFFIC_VSWITCHD_START()
> >>
> >>  ADD_NAMESPACES(at_ns0, at_ns1)
> >> diff --git a/tests/system-userspace-macros.at b/tests/
> >> system-userspace-macros.at
> >> index 20a8635f9e39..00e1f817ff78 100644
> >> --- a/tests/system-userspace-macros.at
> >> +++ b/tests/system-userspace-macros.at
> >> @@ -100,16 +100,6 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK],
> >>  #
> >>  m4_define([CHECK_CONNTRACK_NAT])
> >>
> >> -# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
> >> -#
> >> -# Perform requirements checks for running ovs-dpctl flush-conntrack by
> >> -# conntrack 5-tuple test. The userspace datapath does not support
> >> -# this feature yet.
> >> -m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE],
> >> -[
> >> -    AT_SKIP_IF([:])
> >> -])
> >> -
> >>  # CHECK_CT_DPIF_SET_GET_MAXCONNS()
> >>  #
> >>  # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
> >> --
> >> 2.7.4
> >>
> >> _______________________________________________
> >> dev mailing list
> >> dev@openvswitch.org
> >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >>
> >
> >
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Patch

diff --git a/lib/conntrack.c b/lib/conntrack.c
index fe5fd0fe8be1..c05b3901d7af 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -2368,6 +2368,10 @@  delete_conn(struct conn *conn)
     free(conn);
 }
 
+/* Convert a conntrack address 'a' into an IP address 'b' based on 'dl_type'.
+ *
+ * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
+ * in network-byte order. */
 static void
 ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
                                  union ct_dpif_inet_addr *b,
@@ -2380,6 +2384,22 @@  ct_endpoint_to_ct_dpif_inet_addr(const struct ct_addr *a,
     }
 }
 
+/* Convert an IP address 'a' into a conntrack address 'b' based on 'dl_type'.
+ *
+ * Note that 'dl_type' should be either "ETH_TYPE_IP" or "ETH_TYPE_IPv6"
+ * in network-byte order. */
+static void
+ct_dpif_inet_addr_to_ct_endpoint(const union ct_dpif_inet_addr *a,
+                                 struct ct_addr *b,
+                                 ovs_be16 dl_type)
+{
+    if (dl_type == htons(ETH_TYPE_IP)) {
+        b->ipv4_aligned = a->ip;
+    } else if (dl_type == htons(ETH_TYPE_IPV6)){
+        b->ipv6_aligned = a->in6;
+    }
+}
+
 static void
 conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple *tuple)
 {
@@ -2405,6 +2425,35 @@  conn_key_to_tuple(const struct conn_key *key, struct ct_dpif_tuple *tuple)
 }
 
 static void
+tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone,
+                  struct conn_key *key)
+{
+    if (tuple->l3_type == AF_INET) {
+        key->dl_type = htons(ETH_TYPE_IP);
+    } else if (tuple->l3_type == AF_INET6) {
+        key->dl_type = htons(ETH_TYPE_IPV6);
+    }
+    key->nw_proto = tuple->ip_proto;
+    ct_dpif_inet_addr_to_ct_endpoint(&tuple->src, &key->src.addr,
+                                     key->dl_type);
+    ct_dpif_inet_addr_to_ct_endpoint(&tuple->dst, &key->dst.addr,
+                                     key->dl_type);
+
+    if (tuple->ip_proto == IPPROTO_ICMP || tuple->ip_proto == IPPROTO_ICMPV6) {
+        key->src.icmp_id = tuple->icmp_id;
+        key->src.icmp_type = tuple->icmp_type;
+        key->src.icmp_code = tuple->icmp_code;
+        key->dst.icmp_id = tuple->icmp_id;
+        key->dst.icmp_type = reverse_icmp_type(tuple->icmp_type);
+        key->dst.icmp_code = tuple->icmp_code;
+    } else {
+        key->src.port = tuple->src_port;
+        key->dst.port = tuple->dst_port;
+    }
+    key->zone = zone;
+}
+
+static void
 conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry,
                       long long now, int bkt)
 {
@@ -2517,6 +2566,29 @@  conntrack_flush(struct conntrack *ct, const uint16_t *zone)
 }
 
 int
+conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple *tuple,
+                      uint16_t zone)
+{
+    struct conn_lookup_ctx ctx;
+    int error = 0;
+
+    memset(&ctx, 0, sizeof(ctx));
+    tuple_to_conn_key(tuple, zone, &ctx.key);
+    ctx.hash = conn_key_hash(&ctx.key, ct->hash_basis);
+    unsigned bucket = hash_to_bucket(ctx.hash);
+
+    ct_lock_lock(&ct->buckets[bucket].lock);
+    conn_key_lookup(&ct->buckets[bucket], &ctx, time_msec());
+    if (ctx.conn) {
+        conn_clean(ct, ctx.conn, &ct->buckets[bucket]);
+    } else {
+        error = ENOENT;
+    }
+    ct_lock_unlock(&ct->buckets[bucket].lock);
+    return error;
+}
+
+int
 conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns)
 {
     atomic_store_relaxed(&ct->n_conn_limit, maxconns);
diff --git a/lib/conntrack.h b/lib/conntrack.h
index ac650304a41f..e3a5dcc8023f 100644
--- a/lib/conntrack.h
+++ b/lib/conntrack.h
@@ -109,6 +109,7 @@  struct conntrack_dump {
 };
 
 struct ct_dpif_entry;
+struct ct_dpif_tuple;
 
 int conntrack_dump_start(struct conntrack *, struct conntrack_dump *,
                          const uint16_t *pzone, int *);
@@ -116,6 +117,8 @@  int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *);
 int conntrack_dump_done(struct conntrack_dump *);
 
 int conntrack_flush(struct conntrack *, const uint16_t *zone);
+int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple *,
+                          uint16_t zone);
 int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns);
 int conntrack_get_maxconns(struct conntrack *ct, uint32_t *maxconns);
 int conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns);
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index ba62128c758c..b06caa281afc 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -5842,7 +5842,7 @@  dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone,
     struct dp_netdev *dp = get_dp_netdev(dpif);
 
     if (tuple) {
-        return EOPNOTSUPP;
+        return conntrack_flush_tuple(&dp->conntrack, tuple, zone ? *zone : 0);
     }
     return conntrack_flush(&dp->conntrack, zone);
 }
diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
index 12b0adf7190e..f23a4063375c 100644
--- a/tests/system-kmod-macros.at
+++ b/tests/system-kmod-macros.at
@@ -97,14 +97,6 @@  m4_define([CHECK_CONNTRACK_LOCAL_STACK])
 #
 m4_define([CHECK_CONNTRACK_NAT])
 
-# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
-#
-# Perform requirements checks for running ovs-dpctl flush-conntrack by
-# conntrack 5-tuple test. The kernel datapath does support this
-# feature. Will remove this check after both kernel and userspace datapath
-# support it.
-m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE])
-
 # CHECK_CT_DPIF_SET_GET_MAXCONNS()
 #
 # Perform requirements checks for running ovs-dpctl ct-set-maxconns or
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index dbd56405d1fd..2afadec15827 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -834,7 +834,6 @@  AT_CLEANUP
 
 AT_SETUP([conntrack - ct flush by 5-tuple])
 CHECK_CONNTRACK()
-CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
 OVS_TRAFFIC_VSWITCHD_START()
 
 ADD_NAMESPACES(at_ns0, at_ns1)
diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at
index 20a8635f9e39..00e1f817ff78 100644
--- a/tests/system-userspace-macros.at
+++ b/tests/system-userspace-macros.at
@@ -100,16 +100,6 @@  m4_define([CHECK_CONNTRACK_LOCAL_STACK],
 #
 m4_define([CHECK_CONNTRACK_NAT])
 
-# CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE()
-#
-# Perform requirements checks for running ovs-dpctl flush-conntrack by
-# conntrack 5-tuple test. The userspace datapath does not support
-# this feature yet.
-m4_define([CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE],
-[
-    AT_SKIP_IF([:])
-])
-
 # CHECK_CT_DPIF_SET_GET_MAXCONNS()
 #
 # Perform requirements checks for running ovs-dpctl ct-set-maxconns or