On Wed, Oct 25, 2023 at 12:25 AM Ilya Maximets <i.maxim...@ovn.org> wrote:

> On 10/18/23 08:28, Ales Musil wrote:
> > Extend the current NX_CT_FLUSH with four additional fields,
> > that allow to match on CT entry "mark" or "labels". This
> > is encoded as separate TLV values which is backward compatible.
> > Versions that do not support them will simply ignore it.
>
> Hmm.  Just noticed that.  This doesn't seem right.  If unknown
> property is passed, OVS should fail with OFPPROP_UNKNOWN().
> This probably should be a separate fix that we'll need to
> backport to stable versions.  If user requests flushing a
> specific label, we should not flush everything just because
> we do not understand the request.
>
> Some more comments inline.
>
> Best regards, Ilya Maximets.
>

Hi Ilya,

thank you for the review. It makes sense to report unknown values, it's a
bit unfortunate because now we will probably need an additional feature
flag to indicate that this is supported WDYT?
I'll wait with v4 until the feature flag is resolved.


>
> >
> > Extend also the ovs-dpctl and ovs-ofctl command line tools with
> > option to specify those two matching parameters for the "ct-flush"
> > command.
> >
> > Reported-at: https://issues.redhat.com/browse/FDP-55
> > Signed-off-by: Ales Musil <amu...@redhat.com>
> > ---
> > v3: Rebase on top of current master.
> > v2: Make sure that the mask decoding matches the dpctl/ovs-ofctl
> interface.
> > ---
> >  include/openflow/nicira-ext.h |   4 +
> >  include/openvswitch/ofp-ct.h  |   9 +-
> >  lib/ct-dpif.c                 |  12 ++-
> >  lib/dpctl.c                   |   5 +-
> >  lib/ofp-ct.c                  | 151 +++++++++++++++++++++++++++++++++-
> >  tests/ofp-print.at            |  56 +++++++++++++
> >  tests/ovs-ofctl.at            |  32 +++++++
> >  tests/system-traffic.at       | 112 ++++++++++++++++---------
> >  utilities/ovs-ofctl.8.in      |  13 +--
> >  utilities/ovs-ofctl.c         |   5 +-
> >  10 files changed, 344 insertions(+), 55 deletions(-)
>
> The change needs a NEWS entry.
>
> >
> > diff --git a/include/openflow/nicira-ext.h
> b/include/openflow/nicira-ext.h
> > index 768775898..959845ce6 100644
> > --- a/include/openflow/nicira-ext.h
> > +++ b/include/openflow/nicira-ext.h
> > @@ -1075,6 +1075,10 @@ enum nx_ct_flush_tlv_type {
> >                                  * by 'enum nx_ct_flush_tuple_tlv_type'*/
> >      /* Primitive types. */
> >      NXT_CT_ZONE_ID = 2,        /* be16 zone id. */
> > +    NXT_CT_MARK = 3,           /* be32 mark. */
> > +    NXT_CT_MARK_MASK = 4,      /* be32 mark mask. */
> > +    NXT_CT_LABELS = 5,         /* be128 labels. */
> > +    NXT_CT_LABELS_MASK = 6,    /* be128 labels mask. */
> >  };
> >
> >  /* CT flush nested TLVs. */
> > diff --git a/include/openvswitch/ofp-ct.h b/include/openvswitch/ofp-ct.h
> > index cd6192e6f..d57b62678 100644
> > --- a/include/openvswitch/ofp-ct.h
> > +++ b/include/openvswitch/ofp-ct.h
> > @@ -51,11 +51,16 @@ struct ofp_ct_match {
> >
> >      struct ofp_ct_tuple tuple_orig;
> >      struct ofp_ct_tuple tuple_reply;
> > +
> > +    uint32_t mark;
> > +    uint32_t mark_mask;
> > +
> > +    ovs_u128 labels;
> > +    ovs_u128 labels_mask;
> >  };
> >
> >  bool ofp_ct_match_is_zero(const struct ofp_ct_match *);
> > -bool ofp_ct_tuple_is_zero(const struct ofp_ct_tuple *, uint8_t
> ip_proto);
> > -bool ofp_ct_tuple_is_five_tuple(const struct ofp_ct_tuple *, uint8_t
> ip_proto);
> > +bool ofp_ct_match_is_five_tuple(const struct ofp_ct_match *);
> >
> >  void ofp_ct_match_format(struct ds *, const struct ofp_ct_match *);
> >  bool ofp_ct_match_parse(const char **, int argc, struct ds *,
> > diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
> > index f59c6e560..0fd14b99f 100644
> > --- a/lib/ct-dpif.c
> > +++ b/lib/ct-dpif.c
> > @@ -269,6 +269,15 @@ ct_dpif_entry_cmp(const struct ct_dpif_entry *entry,
> >          return false;
> >      }
> >
> > +    if ((match->mark & match->mark_mask) != (entry->mark &
> match->mark_mask)) {
> > +        return false;
> > +    }
> > +
> > +    if (!ovs_u128_equals(ovs_u128_and(match->labels,
> match->labels_mask),
> > +                         ovs_u128_and(entry->labels,
> match->labels_mask))) {
> > +        return false;
> > +    }
> > +
> >      return true;
> >  }
> >
> > @@ -295,8 +304,7 @@ ct_dpif_flush_tuple(struct dpif *dpif, const
> uint16_t *zone,
> >
> >      /* If we have full five tuple in original and empty reply tuple just
> >       * do the flush over original tuple directly. */
> > -    if (ofp_ct_tuple_is_five_tuple(&match->tuple_orig, match->ip_proto)
> &&
> > -        ofp_ct_tuple_is_zero(&match->tuple_reply, match->ip_proto)) {
> > +    if (ofp_ct_match_is_five_tuple(match)) {
> >          struct ct_dpif_tuple tuple;
> >
> >          ct_dpif_tuple_from_ofp_ct_tuple(&match->tuple_orig, &tuple,
> > diff --git a/lib/dpctl.c b/lib/dpctl.c
> > index bbab5881e..9d28a91ba 100644
> > --- a/lib/dpctl.c
> > +++ b/lib/dpctl.c
> > @@ -2981,8 +2981,9 @@ static const struct dpctl_command all_commands[] =
> {
> >        0, 4, dpctl_dump_conntrack, DP_RO },
> >      { "dump-conntrack-exp", "[dp] [zone=N]",
> >        0, 2, dpctl_dump_conntrack_exp, DP_RO },
> > -    { "flush-conntrack", "[dp] [zone=N] [ct-orig-tuple]
> [ct-reply-tuple]",
> > -      0, 4, dpctl_flush_conntrack, DP_RW },
> > +    { "flush-conntrack", "[dp] [zone=N] [mark=X[/M]] [labels=Y[/N]] "
> > +                         "[ct-orig-tuple [ct-reply-tuple]]",
> > +      0, 6, dpctl_flush_conntrack, DP_RW },
> >      { "cache-get-size", "[dp]", 0, 1, dpctl_cache_get_size, DP_RO },
> >      { "cache-set-size", "dp cache <size>", 3, 3, dpctl_cache_set_size,
> DP_RW },
> >      { "ct-stats-show", "[dp] [zone=N]",
> > diff --git a/lib/ofp-ct.c b/lib/ofp-ct.c
> > index 32aeb5455..344f7a0b2 100644
> > --- a/lib/ofp-ct.c
> > +++ b/lib/ofp-ct.c
> > @@ -50,7 +50,7 @@ ofp_ct_tuple_format(struct ds *ds, const struct
> ofp_ct_tuple *tuple,
> >      }
> >  }
> >
> > -bool
> > +static bool
> >  ofp_ct_tuple_is_zero(const struct ofp_ct_tuple *tuple, uint8_t ip_proto)
> >  {
> >      bool is_zero = ipv6_is_zero(&tuple->src) &&
> ipv6_is_zero(&tuple->dst);
> > @@ -62,7 +62,7 @@ ofp_ct_tuple_is_zero(const struct ofp_ct_tuple *tuple,
> uint8_t ip_proto)
> >      return is_zero;
> >  }
> >
> > -bool
> > +static bool
> >  ofp_ct_tuple_is_five_tuple(const struct ofp_ct_tuple *tuple, uint8_t
> ip_proto)
> >  {
> >      /* First check if we have address. */
> > @@ -75,17 +75,63 @@ ofp_ct_tuple_is_five_tuple(const struct ofp_ct_tuple
> *tuple, uint8_t ip_proto)
> >      return five_tuple;
> >  }
> >
> > +static bool
> > +ofp_ct_match_mark_is_zero(const struct ofp_ct_match *match)
> > +{
> > +    return !match->mark && !match->mark_mask;
>
> If the mask is zero, why do we care about the value?
>

We don't, but I don't see any harm in checking both.


>
> > +}
> > +
> > +static bool
> > +ofp_ct_match_labels_is_zero(const struct ofp_ct_match *match)
> > +{
> > +    return ovs_u128_is_zero(match->labels) &&
> > +           ovs_u128_is_zero(match->labels_mask);
>
> ditto.
>
> > +}
> > +
> > +bool
> > +ofp_ct_match_is_five_tuple(const struct ofp_ct_match *match)
> > +{
> > +    return ofp_ct_tuple_is_five_tuple(&match->tuple_orig,
> match->ip_proto) &&
> > +           ofp_ct_tuple_is_zero(&match->tuple_reply, match->ip_proto) &&
> > +           ofp_ct_match_mark_is_zero(match) &&
> > +           ofp_ct_match_labels_is_zero(match);
> > +}
> > +
> >  bool
> >  ofp_ct_match_is_zero(const struct ofp_ct_match *match)
> >  {
> >      return !match->ip_proto && !match->l3_type &&
> >             ofp_ct_tuple_is_zero(&match->tuple_orig, match->ip_proto) &&
> > -           ofp_ct_tuple_is_zero(&match->tuple_reply, match->ip_proto);
> > +           ofp_ct_tuple_is_zero(&match->tuple_reply, match->ip_proto) &&
> > +           ofp_ct_match_mark_is_zero(match) &&
> > +           ofp_ct_match_labels_is_zero(match);
> >  }
> >
> >  void
> >  ofp_ct_match_format(struct ds *ds, const struct ofp_ct_match *match)
> >  {
> > +    if (!ofp_ct_match_mark_is_zero(match)) {
> > +        ds_put_format(ds, "mark=%#"PRIx32, match->mark);
> > +        if (match->mark_mask != UINT32_MAX) {
> > +            ds_put_format(ds, "/%#"PRIx32, match->mark_mask);
> > +        }
> > +        ds_put_char(ds, ' ');
> > +    }
> > +
> > +    if (!ofp_ct_match_labels_is_zero(match)) {
> > +        ovs_be128 be_value = hton128(match->labels);
> > +        ovs_be128 be_mask = hton128(match->labels_mask);
> > +
> > +        ds_put_cstr(ds, "labels=");
> > +        ds_put_hex(ds, &be_value, sizeof be_value);
> > +
> > +        if (!ovs_u128_is_ones(match->labels_mask)) {
> > +            ds_put_char(ds, '/');
> > +            ds_put_hex(ds, &be_mask, sizeof be_mask);
> > +        }
> > +        ds_put_char(ds, ' ');
> > +    }
> > +
> >      ds_put_cstr(ds, "'");
> >      ofp_ct_tuple_format(ds, &match->tuple_orig, match->ip_proto,
> >                          match->l3_type);
> > @@ -95,6 +141,23 @@ ofp_ct_match_format(struct ds *ds, const struct
> ofp_ct_match *match)
> >      ds_put_cstr(ds, "'");
> >  }
> >
> > +static inline bool
> > +ofp_ct_masked_parse(const char *s, uint8_t *val, size_t val_len,
> > +                    uint8_t *mask, size_t mask_len)
> > +{
> > +    char *tail;
> > +    if (!parse_int_string(s, val, val_len, &tail)) {
> > +        if (*tail != '/' || parse_int_string(tail + 1, mask,
> > +                                             mask_len, &tail)) {
> > +            memset(mask, UINT8_MAX, mask_len);
> > +        }
> > +
> > +        return true;
> > +    }
> > +
> > +    return false;
> > +}
> > +
> >  /* Parses a specification of a conntrack 5-tuple from 's' into 'tuple'.
> >   * Returns true on success.  Otherwise, returns false and puts the error
> >   * message in 'ds'. */
> > @@ -236,6 +299,40 @@ ofp_ct_match_parse(const char **argv, int argc,
> struct ds *ds,
> >          args--;
> >      }
> >
> > +    /* Parse mark. */
> > +    if (args && !strncmp(argv[argc - args], "mark=", 5)) {
> > +        const char *s = argv[argc - args] + 5;
> > +        ovs_be32 mark_be;
> > +        ovs_be32 mask_be;
> > +
> > +        if (ofp_ct_masked_parse(s, (uint8_t *) &mark_be, sizeof mark_be,
> > +                                (uint8_t *) &mask_be, sizeof mask_be)) {
> > +            match->mark = ntohl(mark_be);
> > +            match->mark_mask = ntohl(mask_be);
> > +        } else {
> > +            ds_put_cstr(ds, "failed to parse mark");
> > +            return false;
> > +        }
> > +        args--;
> > +    }
> > +
> > +    /* Parse labels. */
> > +    if (args && !strncmp(argv[argc - args], "labels=", 7)) {
> > +        const char *s = argv[argc - args] + 7;
> > +        ovs_be128 labels_be;
> > +        ovs_be128 mask_be;
> > +
> > +        if (ofp_ct_masked_parse(s, (uint8_t *) &labels_be, sizeof
> labels_be,
> > +                                 (uint8_t *) &mask_be, sizeof mask_be))
> {
> > +            match->labels = ntoh128(labels_be);
> > +            match->labels_mask = ntoh128(mask_be);
> > +        } else {
> > +            ds_put_cstr(ds, "failed to parse labels");
> > +            return false;
> > +        }
> > +        args--;
> > +    }
> > +
> >      /* Parse ct tuples. */
> >      for (int i = 0; i < 2; i++) {
> >          if (!args) {
> > @@ -382,6 +479,7 @@ enum ofperr
> >  ofp_ct_match_decode(struct ofp_ct_match *match, bool *with_zone,
> >                      uint16_t *zone_id, const struct ofp_header *oh)
> >  {
> > +    uint32_t tlv_flags = 0;
> >      struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
> >      ofpraw_pull_assert(&msg);
> >
> > @@ -422,11 +520,43 @@ ofp_ct_match_decode(struct ofp_ct_match *match,
> bool *with_zone,
> >              }
> >              error = ofpprop_parse_u16(&property, zone_id);
> >              break;
> > +
> > +        case NXT_CT_MARK:
> > +            error = ofpprop_parse_u32(&property, &match->mark);
> > +            break;
> > +
> > +        case NXT_CT_MARK_MASK:
> > +            error = ofpprop_parse_u32(&property, &match->mark_mask);
> > +            break;
> > +
> > +        case NXT_CT_LABELS:
> > +            error = ofpprop_parse_u128(&property, &match->labels);
> > +            break;
> > +
> > +        case NXT_CT_LABELS_MASK:
> > +            error = ofpprop_parse_u128(&property, &match->labels_mask);
> > +            break;
> >          }
> >
> >          if (error) {
> >              return error;
> >          }
> > +
> > +        if (type < (sizeof tlv_flags * CHAR_BIT)) {
> > +            tlv_flags |= (1 << type);
>
> The right size of this expression will have the type 'int', which is
> signed.  Left side is unsigned.  Better use UINT32_C(1).
> Same below.
>
> > +        }
> > +    }
> > +
> > +    /* Consider the mask being all ones if it's not present but the
> value
> > +     * is specified. */
> > +    if (tlv_flags & (1 << NXT_CT_MARK) &&
> > +        !(tlv_flags & (1 << NXT_CT_MARK_MASK))) {
> > +        match->mark_mask = UINT32_MAX;
> > +    }
> > +
> > +    if (tlv_flags & (1 << NXT_CT_LABELS) &&
> > +        !(tlv_flags & (1 << NXT_CT_LABELS_MASK))) {
> > +        match->labels_mask = OVS_U128_MAX;
> >      }
> >
> >      return 0;
> > @@ -450,5 +580,20 @@ ofp_ct_match_encode(const struct ofp_ct_match
> *match, uint16_t *zone_id,
> >          ofpprop_put_u16(msg, NXT_CT_ZONE_ID, *zone_id);
> >      }
> >
> > +    if (match->mark) {
> > +        ofpprop_put_u32(msg, NXT_CT_MARK, match->mark);
> > +    }
> > +    if (match->mark_mask) {
> > +        ofpprop_put_u32(msg, NXT_CT_MARK_MASK, match->mark_mask);
> > +    }
> > +
> > +    if (!ovs_u128_is_zero(match->labels)) {
> > +        ofpprop_put_u128(msg, NXT_CT_LABELS, match->labels);
> > +    }
> > +
> > +    if (!ovs_u128_is_zero(match->labels_mask)) {
> > +        ofpprop_put_u128(msg, NXT_CT_LABELS_MASK, match->labels_mask);
> > +    }
>
> These seem to be not very user-friendly.  There is no way to distinguish
> a zero value for a non-provided one.  Users should, probbaly, always
> provide a mask here, and so the function will only check for a mask
> to be non-zero and put both fields.  In case of a full mask, the mask
> itself can probably be omitted from the mesage.
>
> > +
> >      return msg;
> >  }
> > diff --git a/tests/ofp-print.at b/tests/ofp-print.at
> > index 14aa55416..b96ad1fba 100644
> > --- a/tests/ofp-print.at
> > +++ b/tests/ofp-print.at
> > @@ -4093,6 +4093,62 @@ AT_CHECK([ovs-ofctl ofp-print "\
> >  NXT_CT_FLUSH (xid=0x3): zone=13
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> >  ])
> >
> > +AT_CHECK([ovs-ofctl ofp-print "\
> > +01 04 00 20 00 00 00 03 00 00 23 20 00 00 00 20 \
> > +06 \
> > +00 00 00 00 00 00 00 \
> > +00 03 00 08 00 00 00 ab \
> > +"], [0], [dnl
> > +NXT_CT_FLUSH (xid=0x3): zone=0 mark=0xab
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> > +])
> > +
> > +AT_CHECK([ovs-ofctl ofp-print "\
> > +01 04 00 20 00 00 00 03 00 00 23 20 00 00 00 20 \
> > +06 \
> > +00 00 00 00 00 00 00 \
> > +00 04 00 08 00 00 00 cd \
> > +"], [0], [dnl
> > +NXT_CT_FLUSH (xid=0x3): zone=0 mark=0/0xcd
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> > +])
> > +
> > +AT_CHECK([ovs-ofctl ofp-print "\
> > +01 04 00 28 00 00 00 03 00 00 23 20 00 00 00 20 \
> > +06 \
> > +00 00 00 00 00 00 00 \
> > +00 03 00 08 00 00 00 ab \
> > +00 04 00 08 00 00 00 cd \
> > +"], [0], [dnl
> > +NXT_CT_FLUSH (xid=0x3): zone=0 mark=0xab/0xcd
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> > +])
> > +
> > +AT_CHECK([ovs-ofctl ofp-print "\
> > +01 04 00 30 00 00 00 03 00 00 23 20 00 00 00 20 \
> > +06 \
> > +00 00 00 00 00 00 00 \
> > +00 05 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ab 00 00 00 00 00
> \
> > +"], [0], [dnl
> > +NXT_CT_FLUSH (xid=0x3): zone=0 labels=0xffab00
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> > +])
> > +
> > +AT_CHECK([ovs-ofctl ofp-print "\
> > +01 04 00 30 00 00 00 03 00 00 23 20 00 00 00 20 \
> > +06 \
> > +00 00 00 00 00 00 00 \
> > +00 06 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ff cd 00 00 00 00 00
> \
> > +"], [0], [dnl
> > +NXT_CT_FLUSH (xid=0x3): zone=0 labels=0/0xffcd00
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> > +])
> > +
> > +AT_CHECK([ovs-ofctl ofp-print "\
> > +01 04 00 48 00 00 00 03 00 00 23 20 00 00 00 20 \
> > +06 \
> > +00 00 00 00 00 00 00 \
> > +00 05 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ab 00 00 00 00 00
> \
> > +00 06 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ff cd 00 00 00 00 00
> \
> > +"], [0], [dnl
> > +NXT_CT_FLUSH (xid=0x3): zone=0 labels=0xffab00/0xffcd00
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0,ct_nw_proto=6'
> 'ct_ipv6_src=::,ct_ipv6_dst=::,ct_tp_src=0,ct_tp_dst=0'
> > +])
> > +
>
> Maybe add a case with both mark and labeles together?
> Might also make sense to have some inproperly fomatted message.
>
> >  AT_CHECK([ovs-ofctl ofp-print "\
> >  01 04 00 68 00 00 00 03 00 00 23 20 00 00 00 20 \
> >  06 \
> > diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
> > index 8531b2e2e..39afdb1ab 100644
> > --- a/tests/ovs-ofctl.at
> > +++ b/tests/ovs-ofctl.at
> > @@ -3307,5 +3307,37 @@ AT_CHECK([ovs-ofctl ct-flush br0])
> >  OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 5])
> >  AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: <all>" ovs-vswitchd.log])
> >
> > +AT_CHECK([ovs-ofctl ct-flush br0 mark=0])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 6])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=0 mark=0"
> ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 mark=0/0x5])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 7])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=0 mark=0/0x5"
> ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 mark=0xabc/0xdef])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 8])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=0 mark=0xabc/0xdef"
> ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 labels=0])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 9])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=0 labels=0"
> ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 labels=0/0x5])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 10])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=0 labels=0/0x5"
> ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 labels=0xabc/0xdef])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 11])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=0 labels=0xabc/0xdef"
> ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 zone=5 mark=25 labels=25])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 12])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=5 mark=0x19
> labels=0x19" ovs-vswitchd.log])
> > +
> > +AT_CHECK([ovs-ofctl ct-flush br0 zone=5 mark=30/25 labels=30/25])
> > +OVS_WAIT_UNTIL([test $(grep -c "|ct_dpif|DBG|.*ct_flush"
> ovs-vswitchd.log) -eq 13])
> > +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone=5 mark=0x1e/0x19
> labels=0x1e/0x19" ovs-vswitchd.log])
> > +
>
> Same here.
>
> >  OVS_VSWITCHD_STOP
> >  AT_CLEANUP
> > diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> > index ec65ca5de..c71e25eac 100644
> > --- a/tests/system-traffic.at
> > +++ b/tests/system-traffic.at
> > @@ -2527,8 +2527,8 @@ ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
> >  AT_DATA([flows.txt], [dnl
> >  priority=1,action=drop
> >  priority=10,arp,action=normal
> > -priority=100,in_port=1,ip,action=ct(commit),2
> > -priority=100,in_port=2,ip,action=ct(zone=5,commit),1
> >
> +priority=100,in_port=1,ip,action=ct(commit,exec(set_field:0xaa->ct_mark)),2
> >
> +priority=100,in_port=2,ip,action=ct(zone=5,commit,exec(set_field:0xaa00000000->ct_label)),1
> >  ])
> >
> >  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
> > @@ -2543,7 +2543,7 @@ dnl Test UDP from port 1
> >  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1
> packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000
> actions=resubmit(,0)"])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep
> "orig=.src=10\.1\.1\.1,"], [], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD
> 'ct_nw_src=10.1.1.2,ct_nw_dst=10.1.1.1,ct_nw_proto=17,ct_tp_src=2,ct_tp_dst=1'])
> > @@ -2555,7 +2555,7 @@ dnl Test UDP from port 2
> >  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2
> packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000
> actions=resubmit(,0)"])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep
> "orig=.src=10\.1\.1\.2,"], [0], [dnl
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD zone=5
> 'ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2'])
> > @@ -2569,7 +2569,7 @@ NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2
> 10.1.1.1 | FORMAT_PING], [0],
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep
> "orig=.src=10\.1\.1\.2,"], [0], [stdout])
> >  AT_CHECK([cat stdout | FORMAT_CT(10.1.1.1)], [0],[dnl
> >
> -icmp,orig=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=8,code=0),reply=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=0,code=0),zone=5
> >
> +icmp,orig=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=8,code=0),reply=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=0,code=0),zone=5,labels=0xaa00000000
> >  ])
> >
> >  ICMP_ID=`cat stdout | cut -d ',' -f4 | cut -d '=' -f2`
> > @@ -2585,14 +2585,14 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=2 packet=50540000000a5
> >
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_src=1'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_src=2'])
> > @@ -2605,14 +2605,14 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=2 packet=50540000000a5
> >
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_dst=2'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_proto=17,ct_tp_dst=1'])
> > @@ -2625,14 +2625,14 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=2 packet=50540000000a5
> >
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.1'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_src=10.1.1.2'])
> > @@ -2645,14 +2645,14 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=2 packet=50540000000a5
> >
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_dst=10.1.1.2'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD 'ct_nw_dst=10.1.1.1'])
> > @@ -2665,14 +2665,14 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=2 packet=50540000000a5
> >
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD '' 'ct_nw_src=10.1.1.2'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD zone=5 '' 'ct_nw_src=10.1.1.1'])
> > @@ -2685,8 +2685,8 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=2 packet=50540000000a5
> >
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> -udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD])
> > @@ -2698,46 +2698,80 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0
> "in_port=1 packet=50540000000a5
> >  AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2
> packet=50540000000950540000000a08004500003400010000408464410a0101020a010101000200010000000098f29e470100001470e18ccc00000000000a000a00000000
> actions=resubmit(,0)"])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sed
> "s/,protoinfo=.*$//" | sort], [0], [dnl
> >
> -sctp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
> >
> -sctp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +sctp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +sctp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD
> 'ct_nw_src=10.1.1.1,ct_nw_proto=132,ct_tp_src=1,ct_tp_dst=2'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sed
> "s/,protoinfo=.*$//" | sort], [0], [dnl
> >
> -sctp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
> >
> +sctp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> >  AT_CHECK([FLUSH_CMD
> 'ct_nw_src=10.1.1.2,ct_nw_proto=132,ct_tp_src=2,ct_tp_dst=1'])
> >
> >  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
> > +
> > +dnl Test UDP from port 1 and 2, partial flush by mark and labels
> > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1
> packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000
> actions=resubmit(,0)"])
> > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2
> packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000
> actions=resubmit(,0)"])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> > +])
> > +
> > +AT_CHECK([FLUSH_CMD mark=0xaa])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> > +])
> > +
> > +AT_CHECK([FLUSH_CMD labels=0xaa00000000])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
> > +
> > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1
> packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000
> actions=resubmit(,0)"])
> > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2
> packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000
> actions=resubmit(,0)"])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort],
> [0], [dnl
> >
> +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),mark=170
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> > +])
> > +
> > +AT_CHECK([FLUSH_CMD mark=2/2])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [0],
> [dnl
> >
> +udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5,labels=0xaa00000000
> >  ])
> >
> > -dnl Test flush with invalid arguments
> > +AT_CHECK([FLUSH_CMD labels=0x0200000000/0x0200000000])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
> > +
> > +dnl Test flush with invalid arguments.
> >
> > -AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=invalid
> 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1'], [2], [ignore], [stderr])
> > +AT_CHECK([FLUSH_CMD zone=invalid 'ct_nw_src=10.1.1.1'
> 'ct_nw_dst=10.1.1.1'], [ignore], [ignore], [stderr])
> >  AT_CHECK([grep -q "failed to parse zone" stderr])
> >
> > -AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1
> 'ct_nw_src=10.1.1.1,invalid=invalid' 'ct_nw_dst=10.1.1.1'], [2], [ignore],
> [stderr])
> > +AT_CHECK([FLUSH_CMD zone=1 'ct_nw_src=10.1.1.1,invalid=invalid'
> 'ct_nw_dst=10.1.1.1'], [ignore], [ignore], [stderr])
> >  AT_CHECK([grep -q "invalid conntrack tuple field: invalid" stderr])
> >
> > -AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1 'ct_nw_src=invalid'
> 'ct_nw_dst=10.1.1.1'], [2], [ignore], [stderr])
> > +AT_CHECK([FLUSH_CMD zone=1 'ct_nw_src=invalid' 'ct_nw_dst=10.1.1.1'],
> [ignore], [ignore], [stderr])
> >  AT_CHECK([grep -q "failed to parse field ct_nw_src" stderr])
> >
> > -AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1 'ct_nw_src=10.1.1.1'
> 'ct_nw_dst=10.1.1.1' invalid], [2], [ignore], [stderr])
> > +AT_CHECK([FLUSH_CMD zone=1 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1'
> invalid], [ignore], [ignore], [stderr])
> >  AT_CHECK([grep -q "invalid arguments" stderr])
> >
> > -AT_CHECK([ovs-appctl dpctl/flush-conntrack $dp zone=1
> 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [2], [ignore], [stderr])
> > -AT_CHECK([grep -q "command takes at most 4 arguments" stderr])
> > +AT_CHECK([FLUSH_CMD zone=1 mark=1 labels=1 'ct_nw_src=10.1.1.1'
> 'ct_nw_dst=10.1.1.1' invalid invalid], [ignore], [ignore], [stderr])
> > +AT_CHECK([grep -q "command takes at most 6 arguments" stderr])
> >
> > -AT_CHECK([ovs-appctl dpctl/flush-conntrack $dp 'ct_nw_src=10.1.1.1'
> 'ct_nw_dst=10.1.1.1' invalid], [2], [ignore], [stderr])
> > -AT_CHECK([grep -q "invalid arguments" stderr])
> > -
> > -AT_CHECK([ovs-ofctl ct-flush br0 zone=1 'ct_nw_src=10.1.1.1'
> 'ct_nw_dst=10.1.1.1' invalid], [1], [ignore], [stderr])
> > -AT_CHECK([grep -q "command takes at most 4 arguments" stderr])
> > +AT_CHECK([FLUSH_CMD mark=invalid], [ignore], [ignore], [stderr])
> > +AT_CHECK([grep -q "failed to parse mark" stderr])
> >
> > -AT_CHECK([ovs-ofctl ct-flush br0 'ct_nw_src=10.1.1.1'
> 'ct_nw_dst=10.1.1.1' invalid], [1], [ignore], [stderr])
> > -AT_CHECK([grep -q "invalid arguments" stderr])
> > +AT_CHECK([FLUSH_CMD labels=invalid], [ignore], [ignore], [stderr])
> > +AT_CHECK([grep -q "failed to parse labels" stderr])
> > +])
> >
> >  OVS_TRAFFIC_VSWITCHD_STOP
> >  AT_CLEANUP
> > diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
> > index 0a611b2ee..9995895ca 100644
> > --- a/utilities/ovs-ofctl.8.in
> > +++ b/utilities/ovs-ofctl.8.in
> > @@ -296,17 +296,20 @@ Flushes the connection tracking entries in
> \fIzone\fR on \fIswitch\fR.
> >  This command uses an Open vSwitch extension that is only in Open
> >  vSwitch 2.6 and later.
> >  .
> > -.IP "\fBct\-flush \fIswitch [zone=N] [ct-orig-tuple [ct-reply-tuple]]\fR
> > -Flushes the connection entries on \fIswitch\fR based on \fIzone\fR and
> > -connection tracking tuples \fIct-[orig|reply]-tuple\fR.
> > +.IP "\fBct\-flush \fIswitch [zone=N] [zone=N] [mark=X[/M]]
> [labels=Y[/N]] [ct-orig-tuple [ct-reply-tuple]]\fR
>
> The zone is repeated twice.
>
> > +Flushes the connection entries on \fIswitch\fR based on \fIzone\fR,
> > +\fImark\fR, \fIlabels\fR and connection tracking tuples
> > +\fIct-[orig|reply]-tuple\fR.
> >  .IP
> >  If \fIct-[orig|reply]-tuple\fR is not provided, flushes all the
> connection
> >  entries.  If \fIzone\fR is specified, only flushes the connections in
> > -\fIzone\fR.
> > +\fIzone\fR. if \fImark\fR or \fIlabels\fR is provided, it will flush
> > +only entries that are matching specific \fImark/labels\fR.
> >  .IP
> >  If \fIct-[orig|reply]-tuple\fR is provided, flushes the connection entry
> >  specified by \fIct-[orig|reply]-tuple\fR in \fIzone\fR.  The zone
> defaults
> > -to 0 if it is not provided.  The userspace connection tracker requires
> flushing
> > +to 0 if it is not provided. The \fImark\fR and \fIlabel\fR defaults to
> "0/0"
>
> label*s*
>
> > +if it is not provided. The userspace connection tracker requires
> flushing
> >  with the original pre-NATed tuple and a warning log will be otherwise
> >  generated.  The tuple can be partial and will remove all connections
> that are
> >  matching on the specified fields.  In order to specify only
> > diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> > index 79d42dd0b..de734e9f5 100644
> > --- a/utilities/ovs-ofctl.c
> > +++ b/utilities/ovs-ofctl.c
> > @@ -5092,8 +5092,9 @@ static const struct ovs_cmdl_command
> all_commands[] = {
> >      { "ct-flush-zone", "switch zone",
> >        2, 2, ofctl_ct_flush_zone, OVS_RO },
> >
> > -    { "ct-flush", "switch [zone=N] [ct-orig-tuple [ct-reply-tuple]]",
> > -      1, 4, ofctl_ct_flush, OVS_RO },
> > +    { "ct-flush", "switch [zone=N] [mark=X[/M]] [labels=Y[/N]] "
> > +                  "[ct-orig-tuple [ct-reply-tuple]]",
> > +      1, 6, ofctl_ct_flush, OVS_RO },
>
> Not an issue of this patch, but these commands should be RW.
>

I'll address that in a separate patch possible with the UNKNOWN error to
make it easily backportable.


> Also, you missed the update for usage() function.
>
> >
> >      { "ofp-parse", "file",
> >        1, 1, ofctl_ofp_parse, OVS_RW },
>
>
Thanks,
Ales

-- 

Ales Musil

Senior Software Engineer - OVN Core

Red Hat EMEA <https://www.redhat.com>

amu...@redhat.com
<https://red.ht/sig>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to