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. > > 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? > +} > + > +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. Also, you missed the update for usage() function. > > { "ofp-parse", "file", > 1, 1, ofctl_ofp_parse, OVS_RW }, _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev