On Wed, Feb 23, 2022 at 2:44 PM Numan Siddique <[email protected]> wrote:
>
> /
>
> On Wed, Feb 9, 2022 at 12:56 PM Han Zhou <[email protected]> wrote:
> >
> > To avoid reprocessing the lflow when a referenced address set has new
> > addresses added, this patch generates a fake address set that only
> > contains the added addresses for flow generation, and then eliminates
> > the flows that are not related to the newly added addresses.
> >
> > Scale test shows obvious performance gains because the time complexity
> > changed from O(n) to O(1). The bigger the size of address set, the more
> > CPU savings. With the AS size of 10k, the test shows ~40x speed up.
> >
> > Test setup:
> > CPU: Intel(R) Core(TM) i9-7920X CPU @ 2.90GHz.
> > 5 ACL all referencing an address set of 10,000 IPs.
> >
> > Measure the time spent by ovn-controller for handling one IP
> > addition from the address set.
> >
> > Before: ~400ms
> > After: 11-12ms
> >
> > Signed-off-by: Han Zhou <[email protected]>
>
> Hi Han,
>
> I found a couple of small typos which you can consider fixing while
> applying the patches.
>
> Please see the patch 0 which has my Ack.
>
> Thanks
> Numan
>
> > ---
> > controller/lflow-conj-ids.c | 20 ++
> > controller/lflow-conj-ids.h | 1 +
> > controller/lflow.c | 360 ++++++++++++++++++++++++++++++++++--
> > controller/ovn-controller.c | 8 +
> > include/ovn/expr.h | 1 +
> > lib/expr.c | 2 +-
> > tests/ovn-controller.at | 41 ++--
> > 7 files changed, 397 insertions(+), 36 deletions(-)
> >
> > diff --git a/controller/lflow-conj-ids.c b/controller/lflow-conj-ids.c
> > index bfe63862a..372391e5a 100644
> > --- a/controller/lflow-conj-ids.c
> > +++ b/controller/lflow-conj-ids.c
> > @@ -157,6 +157,26 @@ lflow_conj_ids_alloc_specified(struct conj_ids
*conj_ids,
> > return true;
> > }
> >
> > +/* Find and return the start id that is allocated to the logical flow.
Return
> > + * 0 if not found. */
> > +uint32_t
> > +lflow_conj_ids_find(struct conj_ids *conj_ids, const struct uuid
*lflow_uuid)
> > +{
> > + struct lflow_conj_node *lflow_conj;
> > + bool found = false;
> > + HMAP_FOR_EACH_WITH_HASH (lflow_conj, hmap_node,
uuid_hash(lflow_uuid),
> > + &conj_ids->lflow_conj_ids) {
> > + if (uuid_equals(&lflow_conj->lflow_uuid, lflow_uuid)) {
> > + found = true;
> > + break;
> > + }
> > + }
> > + if (!found) {
> > + return 0;
> > + }
> > + return lflow_conj->start_conj_id;
> > +}
> > +
> > /* Frees the conjunction IDs used by lflow_uuid. */
> > void
> > lflow_conj_ids_free(struct conj_ids *conj_ids, const struct uuid
*lflow_uuid)
> > diff --git a/controller/lflow-conj-ids.h b/controller/lflow-conj-ids.h
> > index 6da0a612c..a1f7a95a5 100644
> > --- a/controller/lflow-conj-ids.h
> > +++ b/controller/lflow-conj-ids.h
> > @@ -35,6 +35,7 @@ bool lflow_conj_ids_alloc_specified(struct conj_ids *,
> > const struct uuid *lflow_uuid,
> > uint32_t start_conj_id, uint32_t
n_conjs);
> > void lflow_conj_ids_free(struct conj_ids *, const struct uuid
*lflow_uuid);
> > +uint32_t lflow_conj_ids_find(struct conj_ids *, const struct uuid
*lflow_uuid);
> > void lflow_conj_ids_init(struct conj_ids *);
> > void lflow_conj_ids_destroy(struct conj_ids *);
> > void lflow_conj_ids_clear(struct conj_ids *);
> > diff --git a/controller/lflow.c b/controller/lflow.c
> > index 9b1184c0e..658b3109b 100644
> > --- a/controller/lflow.c
> > +++ b/controller/lflow.c
> > @@ -74,6 +74,19 @@ struct condition_aux {
> > struct lflow_resource_ref *lfrr;
> > };
> >
> > +static struct expr *
> > +convert_match_to_expr(const struct sbrec_logical_flow *,
> > + const struct sbrec_datapath_binding *,
> > + struct expr **prereqs, const struct shash
*addr_sets,
> > + const struct shash *port_groups,
> > + struct lflow_resource_ref *, bool
*pg_addr_set_ref);
> > +static void
> > +add_matches_to_flow_table(const struct sbrec_logical_flow *,
> > + const struct sbrec_datapath_binding *,
> > + struct hmap *matches, uint8_t ptable,
> > + uint8_t output_ptable, struct ofpbuf
*ovnacts,
> > + bool ingress, struct lflow_ctx_in *,
> > + struct lflow_ctx_out *);
> > static void
> > consider_logical_flow(const struct sbrec_logical_flow *lflow,
> > struct hmap *dhcp_opts, struct hmap *dhcpv6_opts,
> > @@ -513,6 +526,262 @@ as_info_from_expr_const(const char *as_name,
const union expr_constant *c,
> > return true;
> > }
> >
> > +/* Parses the lflow regarding the changed address set 'as_name', and
gererates/
> s/gererates/generates
>
Ack.
>
> > + * ovs flows for the newly added addresses in 'as_diff_added' only. It
is
> > + * similar to consider_logical_flow__, with the below differences:
> > + *
> > + * - It has one more arg 'as_ref_count' to deduce how many flows are
expected
> > + * to be added.
> > + * - It uses a small fake address set that contains only the added
addresses
> > + * to replace the original address set temporarily and restores it
after
> > + * parsing.
> > + * - It doesn't check or touch lflow-cache, because lflow-cache is
disabled
> > + * when address-sets/port-groups are used.
> > + * - It doesn't check non-local lports because it should have been
checked
> > + * when the lflow is initially parsed, and if it is non-local and
skipped
> > + * then it wouldn't have the address set parsed and referenced.
> > + *
> > + * Because of these differences, it is just cleaner to keep it as a
separate
> > + * function. */
> > +static bool
> > +consider_lflow_for_added_as_ips__(
> > + const struct sbrec_logical_flow *lflow,
> > + const struct sbrec_datapath_binding *dp,
> > + const char *as_name,
> > + size_t as_ref_count,
> > + const struct expr_constant_set *as_diff_added,
> > + struct hmap *dhcp_opts,
> > + struct hmap *dhcpv6_opts,
> > + struct hmap *nd_ra_opts,
> > + struct controller_event_options
*controller_event_opts,
> > + struct lflow_ctx_in *l_ctx_in,
> > + struct lflow_ctx_out *l_ctx_out)
> > +{
> > + bool handled = true;
> > + if (!get_local_datapath(l_ctx_in->local_datapaths,
dp->tunnel_key)) {
> > + VLOG_DBG("Skip lflow "UUID_FMT" for non-local datapath
%"PRId64,
> > + UUID_ARGS(&lflow->header_.uuid), dp->tunnel_key);
> > + return true;
> > + }
> > +
> > + /* Determine translation of logical table IDs to physical table
IDs. */
> > + bool ingress = !strcmp(lflow->pipeline, "ingress");
> > +
> > + /* Determine translation of logical table IDs to physical table
IDs. */
> > + uint8_t first_ptable = (ingress
> > + ? OFTABLE_LOG_INGRESS_PIPELINE
> > + : OFTABLE_LOG_EGRESS_PIPELINE);
> > + uint8_t ptable = first_ptable + lflow->table_id;
> > + uint8_t output_ptable = (ingress
> > + ? OFTABLE_REMOTE_OUTPUT
> > + : OFTABLE_SAVE_INPORT);
> > +
> > + uint64_t ovnacts_stub[1024 / 8];
> > + struct ofpbuf ovnacts = OFPBUF_STUB_INITIALIZER(ovnacts_stub);
> > + struct ovnact_parse_params pp = {
> > + .symtab = &symtab,
> > + .dhcp_opts = dhcp_opts,
> > + .dhcpv6_opts = dhcpv6_opts,
> > + .nd_ra_opts = nd_ra_opts,
> > + .controller_event_opts = controller_event_opts,
> > +
> > + .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
> > + .n_tables = LOG_PIPELINE_LEN,
> > + .cur_ltable = lflow->table_id,
> > + };
> > + struct expr *prereqs = NULL;
> > + char *error;
> > +
> > + error = ovnacts_parse_string(lflow->actions, &pp, &ovnacts,
&prereqs);
> > + if (error) {
> > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> > + VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",
> > + lflow->actions, error);
> > + free(error);
> > + ovnacts_free(ovnacts.data, ovnacts.size);
> > + ofpbuf_uninit(&ovnacts);
> > + return true;
> > + }
> > +
> > + struct lookup_port_aux aux = {
> > + .sbrec_multicast_group_by_name_datapath
> > + = l_ctx_in->sbrec_multicast_group_by_name_datapath,
> > + .sbrec_port_binding_by_name =
l_ctx_in->sbrec_port_binding_by_name,
> > + .dp = dp,
> > + .lflow = lflow,
> > + .lfrr = l_ctx_out->lfrr,
> > + };
> > + struct condition_aux cond_aux = {
> > + .sbrec_port_binding_by_name =
l_ctx_in->sbrec_port_binding_by_name,
> > + .dp = dp,
> > + .chassis = l_ctx_in->chassis,
> > + .active_tunnels = l_ctx_in->active_tunnels,
> > + .lflow = lflow,
> > + .lfrr = l_ctx_out->lfrr,
> > + };
> > +
> > + struct hmap matches = HMAP_INITIALIZER(&matches);
> > + const struct expr_constant_set *fake_as = as_diff_added;
> > + struct expr_constant_set *new_fake_as = NULL;
> > + struct in6_addr dummy_ip;
> > + bool has_dummy_ip = false;
> > + ovs_assert(as_diff_added->n_values);
> > +
> > + /* When there is only 1 element, we append a dummy address and
create a
> > + * fake address set with 2 elements, so that the lflow parsing
would
> > + * generate exactly the same format of flows as it would when
parsing with
> > + * the original address set. */
> > + if (as_diff_added->n_values == 1) {
> > + new_fake_as = xzalloc(sizeof *new_fake_as);
> > + new_fake_as->values = xzalloc(sizeof *new_fake_as->values * 2);
> > + new_fake_as->n_values = 2;
> > + new_fake_as->values[0] = new_fake_as->values[1] =
> > + as_diff_added->values[0];
> > + /* Make a dummy ip that is different from the real one. */
> > + new_fake_as->values[1].value.u8_val++;
> > + dummy_ip = new_fake_as->values[1].value.ipv6;
> > + has_dummy_ip = true;
> > + fake_as = new_fake_as;
> > + }
> > +
> > + /* Temporarily replace the address set in addr_sets with the
fake_as, so
> > + * that the cost of lflow parsing is related to the delta but not
the
> > + * original size of the address set. It is possible that there are
other
> > + * address sets used by this logical flow and their size can be
big. In
> > + * such case the parsing cost is still high. In practice, big
address
> > + * sets are likely to be updated more frequently that small
address sets,
> > + * so this approach should still be effetive overall.
>
> s/effetive/effective
Ack.
All fixed. Thanks Numan.
>
> > + *
> > + * XXX: if necessary, we can optimize this by checking all the
address set
> > + * references in this lflow, and replace all the "big" address
sets with a
> > + * small faked one. */
> > + struct expr_constant_set *real_as =
> > + shash_replace((struct shash *)l_ctx_in->addr_sets, as_name,
fake_as);
> > + /* We are here because of the address set update, so it must be
found. */
> > + ovs_assert(real_as);
> > +
> > + struct expr *expr = convert_match_to_expr(lflow, dp, &prereqs,
> > + l_ctx_in->addr_sets,
> > + l_ctx_in->port_groups,
> > + l_ctx_out->lfrr, NULL);
> > + shash_replace((struct shash *)l_ctx_in->addr_sets, as_name,
real_as);
> > + if (new_fake_as) {
> > + expr_constant_set_destroy(new_fake_as);
> > + free(new_fake_as);
> > + }
> > + if (!expr) {
> > + goto done;
> > + }
> > +
> > + expr = expr_evaluate_condition(expr, is_chassis_resident_cb,
> > + &cond_aux);
> > + expr = expr_normalize(expr);
> > +
> > + uint32_t start_conj_id = 0;
> > + uint32_t n_conjs = 0;
> > + n_conjs = expr_to_matches(expr, lookup_port_cb, &aux, &matches);
> > + if (hmap_is_empty(&matches)) {
> > + VLOG_DBG("lflow "UUID_FMT" matches are empty, skip",
> > + UUID_ARGS(&lflow->header_.uuid));
> > + goto done;
> > + }
> > +
> > + /* Discard the matches unrelated to the added addresses in the AS
> > + * 'as_name'. */
> > + struct expr_match *m, *m_next;
> > + HMAP_FOR_EACH_SAFE (m, m_next, hmap_node, &matches) {
> > + if (!m->as_name || strcmp(m->as_name, as_name) ||
> > + (has_dummy_ip && !memcmp(&m->as_ip, &dummy_ip, sizeof
dummy_ip))) {
> > + hmap_remove(&matches, &m->hmap_node);
> > + expr_match_destroy(m);
> > + continue;
> > + }
> > + }
> > +
> > + /* The number of matches generated by the new addresses should
match the
> > + * number of items in the as_diff_added and the reference count of
the AS
> > + * in this lflow. Otherwise, it means we hit some complex/corner
cases that
> > + * the generated matches can't be mapped from the items in the
> > + * as_diff_added. So we need to fall back to reprocessing the
lflow.
> > + */
> > + if (hmap_count(&matches) != as_ref_count *
as_diff_added->n_values) {
> > + VLOG_DBG("lflow "UUID_FMT", addrset %s: Generated flows count "
> > + "(%"PRIuSIZE") " "doesn't match added addresses count
"
> > + "(%"PRIuSIZE") and ref_count (%"PRIuSIZE"). "
> > + "Need reprocessing.",
> > + UUID_ARGS(&lflow->header_.uuid), as_name,
> > + hmap_count(&matches), as_diff_added->n_values,
as_ref_count);
> > + handled = false;
> > + goto done;
> > + }
> > + if (n_conjs) {
> > + start_conj_id = lflow_conj_ids_find(l_ctx_out->conj_ids,
> > + &lflow->header_.uuid);
> > + if (!start_conj_id) {
> > + VLOG_DBG("lflow "UUID_FMT" didn't have conjunctions. "
> > + "Need reprocessing",
UUID_ARGS(&lflow->header_.uuid));
> > + handled = false;
> > + goto done;
> > + }
> > + expr_matches_prepare(&matches, start_conj_id - 1);
> > + }
> > + add_matches_to_flow_table(lflow, dp, &matches, ptable,
output_ptable,
> > + &ovnacts, ingress, l_ctx_in, l_ctx_out);
> > +done:
> > + expr_destroy(prereqs);
> > + ovnacts_free(ovnacts.data, ovnacts.size);
> > + ofpbuf_uninit(&ovnacts);
> > + expr_destroy(expr);
> > + expr_matches_destroy(&matches);
> > + return handled;
> > +}
> > +
> > +static bool
> > +consider_lflow_for_added_as_ips(
> > + const struct sbrec_logical_flow *lflow,
> > + const char *as_name,
> > + size_t as_ref_count,
> > + const struct expr_constant_set *as_diff_added,
> > + struct hmap *dhcp_opts,
> > + struct hmap *dhcpv6_opts,
> > + struct hmap *nd_ra_opts,
> > + struct controller_event_options
*controller_event_opts,
> > + struct lflow_ctx_in *l_ctx_in,
> > + struct lflow_ctx_out *l_ctx_out)
> > +{
> > + const struct sbrec_logical_dp_group *dp_group =
lflow->logical_dp_group;
> > + const struct sbrec_datapath_binding *dp = lflow->logical_datapath;
> > +
> > + if (!dp_group && !dp) {
> > + VLOG_DBG("lflow "UUID_FMT" has no datapath binding, skip",
> > + UUID_ARGS(&lflow->header_.uuid));
> > + return true;
> > + }
> > + ovs_assert(!dp_group || !dp);
> > +
> > + if (dp) {
> > + return consider_lflow_for_added_as_ips__(lflow, dp, as_name,
> > + as_ref_count,
as_diff_added,
> > + dhcp_opts,
dhcpv6_opts,
> > + nd_ra_opts,
> > + controller_event_opts,
> > + l_ctx_in, l_ctx_out);
> > + }
> > + for (size_t i = 0; dp_group && i < dp_group->n_datapaths; i++) {
> > + if (!consider_lflow_for_added_as_ips__(lflow,
dp_group->datapaths[i],
> > + as_name, as_ref_count,
> > + as_diff_added,
dhcp_opts,
> > + dhcpv6_opts, nd_ra_opts,
> > + controller_event_opts,
l_ctx_in,
> > + l_ctx_out)) {
> > + return false;
> > + }
> > + }
> > + return true;
> > +}
> > +
> > +/* Check if an address set update can be handled without reprocessing
the
> > + * lflow. */
> > static bool
> > as_update_can_be_handled(const char *as_name, struct addr_set_diff
*as_diff,
> > struct lflow_ctx_in *l_ctx_in)
> > @@ -582,19 +851,18 @@ as_update_can_be_handled(const char *as_name,
struct addr_set_diff *as_diff,
> > * It could have been combined as:
> > *
> > * ip.src == $as1 && tcp.dst == {p1, p2, p3, p4}
> > + *
> > + * Note: addresses additions still can be processed
incrementally in
> > + * this case, although deletions cannot.
> > */
> > bool
> > lflow_handle_addr_set_update(const char *as_name,
> > struct addr_set_diff *as_diff,
> > - struct lflow_ctx_in *l_ctx_in OVS_UNUSED,
> > + struct lflow_ctx_in *l_ctx_in,
> > struct lflow_ctx_out *l_ctx_out,
> > bool *changed)
> > {
> > - if (as_diff->added) {
> > - return false;
> > - }
> > - ovs_assert(as_diff->deleted);
> > -
> > + ovs_assert(as_diff->added || as_diff->deleted);
> > if (!as_update_can_be_handled(as_name, as_diff, l_ctx_in)) {
> > return false;
> > }
> > @@ -609,6 +877,31 @@ lflow_handle_addr_set_update(const char *as_name,
> >
> > *changed = false;
> >
> > + struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
> > + struct hmap dhcpv6_opts = HMAP_INITIALIZER(&dhcpv6_opts);
> > + struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts);
> > + struct controller_event_options controller_event_opts;
> > +
> > + if (as_diff->added) {
> > + const struct sbrec_dhcp_options *dhcp_opt_row;
> > + SBREC_DHCP_OPTIONS_TABLE_FOR_EACH (dhcp_opt_row,
> > +
l_ctx_in->dhcp_options_table) {
> > + dhcp_opt_add(&dhcp_opts, dhcp_opt_row->name,
dhcp_opt_row->code,
> > + dhcp_opt_row->type);
> > + }
> > +
> > + const struct sbrec_dhcpv6_options *dhcpv6_opt_row;
> > + SBREC_DHCPV6_OPTIONS_TABLE_FOR_EACH(dhcpv6_opt_row,
> > +
l_ctx_in->dhcpv6_options_table) {
> > + dhcp_opt_add(&dhcpv6_opts, dhcpv6_opt_row->name,
> > + dhcpv6_opt_row->code, dhcpv6_opt_row->type);
> > + }
> > +
> > + nd_ra_opts_init(&nd_ra_opts);
> > + controller_event_opts_init(&controller_event_opts);
> > + }
> > +
> > + bool ret = true;
> > struct lflow_ref_list_node *lrln;
> > HMAP_FOR_EACH (lrln, hmap_node, &rlfn->lflow_uuids) {
> > if (lflows_processed_find(l_ctx_out->lflows_processed,
> > @@ -617,21 +910,56 @@ lflow_handle_addr_set_update(const char *as_name,
> > UUID_ARGS(&lrln->lflow_uuid));
> > continue;
> > }
> > - for (size_t i = 0; i < as_diff->deleted->n_values; i++) {
> > - union expr_constant *c = &as_diff->deleted->values[i];
> > + const struct sbrec_logical_flow *lflow =
> > +
sbrec_logical_flow_table_get_for_uuid(l_ctx_in->logical_flow_table,
> > + &lrln->lflow_uuid);
> > + if (!lflow) {
> > + /* lflow deletion should be handled in the corresponding
input
> > + * handler, so we can skip here. */
> > + VLOG_DBG("lflow "UUID_FMT" not found while handling
updates of "
> > + "address set %s, skip.",
> > + UUID_ARGS(&lrln->lflow_uuid), as_name);
> > + continue;
> > + }
> > + *changed = true;
> > +
> > + if (as_diff->deleted) {
> > struct addrset_info as_info;
> > - if (!as_info_from_expr_const(as_name, c, &as_info)) {
> > - continue;
> > + for (size_t i = 0; i < as_diff->deleted->n_values; i++) {
> > + union expr_constant *c = &as_diff->deleted->values[i];
> > + if (!as_info_from_expr_const(as_name, c, &as_info)) {
> > + continue;
> > + }
> > + if
(!ofctrl_remove_flows_for_as_ip(l_ctx_out->flow_table,
> > + &lrln->lflow_uuid,
&as_info,
> > + lrln->ref_count)) {
> > + ret = false;
> > + goto done;
> > + }
> > }
> > - if (!ofctrl_remove_flows_for_as_ip(l_ctx_out->flow_table,
> > - &lrln->lflow_uuid,
&as_info,
> > - lrln->ref_count)) {
> > - return false;
> > + }
> > +
> > + if (as_diff->added) {
> > + if (!consider_lflow_for_added_as_ips(lflow, as_name,
> > + lrln->ref_count,
> > + as_diff->added,
&dhcp_opts,
> > + &dhcpv6_opts,
&nd_ra_opts,
> > +
&controller_event_opts,
> > + l_ctx_in, l_ctx_out))
{
> > + ret = false;
> > + goto done;
> > }
> > - *changed = true;
> > }
> > }
> > - return true;
> > +
> > +done:
> > + if (as_diff->added) {
> > + dhcp_opts_destroy(&dhcp_opts);
> > + dhcp_opts_destroy(&dhcpv6_opts);
> > + nd_ra_opts_destroy(&nd_ra_opts);
> > + controller_event_opts_destroy(&controller_event_opts);
> > + }
> > + return ret;
> > }
> >
> > bool
> > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> > index 5119a3277..b8cd11378 100644
> > --- a/controller/ovn-controller.c
> > +++ b/controller/ovn-controller.c
> > @@ -3263,6 +3263,14 @@ main(int argc, char *argv[])
> > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL);
> > engine_add_input(&en_pflow_output, &en_ovs_bridge, NULL);
> >
> > + /* Keep en_addr_sets before en_runtime_data because
> > + * lflow_output_runtime_data_handler may *partially* reprocess a
lflow when
> > + * the lflow is attached to a DP group and a new DP in that DP
group is
> > + * added locally, i.e. reprocessing the lflow for the new DP only
but not
> > + * for the other DPs in the group. If we handle en_addr_sets after
this,
> > + * incrementally processing an updated address set for the added
IPs may
> > + * end up adding redundant flows/conjunctions for the lflow agaist
the new
> > + * DP because it has been processed on the DP already. */
> > engine_add_input(&en_lflow_output, &en_addr_sets,
> > lflow_output_addr_sets_handler);
> > engine_add_input(&en_lflow_output, &en_port_groups,
> > diff --git a/include/ovn/expr.h b/include/ovn/expr.h
> > index cb3baf001..3b141b034 100644
> > --- a/include/ovn/expr.h
> > +++ b/include/ovn/expr.h
> > @@ -484,6 +484,7 @@ uint32_t expr_to_matches(const struct expr *,
> > unsigned int *portp),
> > const void *aux,
> > struct hmap *matches);
> > +void expr_match_destroy(struct expr_match *);
> > void expr_matches_destroy(struct hmap *matches);
> > size_t expr_matches_prepare(struct hmap *matches, uint32_t
conj_id_ofs);
> > void expr_matches_print(const struct hmap *matches, FILE *);
> > diff --git a/lib/expr.c b/lib/expr.c
> > index 2c178d87f..47ef6108e 100644
> > --- a/lib/expr.c
> > +++ b/lib/expr.c
> > @@ -3054,7 +3054,7 @@ expr_match_new(const struct match *m, uint8_t
clause, uint8_t n_clauses,
> > return match;
> > }
> >
> > -static void
> > +void
> > expr_match_destroy(struct expr_match *match)
> > {
> > free(match->as_name);
> > diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
> > index b5f19b442..260986f15 100644
> > --- a/tests/ovn-controller.at
> > +++ b/tests/ovn-controller.at
> > @@ -904,7 +904,7 @@
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3
actions=dr
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > # Remove the IPs from as1, 1 IP each time.
> > @@ -955,7 +955,8 @@
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3
actions=dr
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +# When change from 0 to 2, still reprocessing.
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > ])
> >
> > # Add and remove IPs at the same time.
> > @@ -973,7 +974,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep -c 10\.0\.0\.22], [0], [1
> > AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10],
[1], [ignore])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Add 1 and remove 2
> > @@ -988,7 +989,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep -c 10\.0\.0\.10], [0], [1
> > ])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Add 1 and remove 1
> > @@ -1002,7 +1003,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep -c 10\.0\.0\.21], [0], [1
> > AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10],
[1], [ignore])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Add 2 and remove 2
> > @@ -1019,7 +1020,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep 10\.0\.0\.8], [1], [ignore
> > AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.9],
[1], [ignore])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > OVN_CLEANUP([hv1])
> > @@ -1093,7 +1094,7 @@
priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,tp_dst=333
actions=conjun
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > # Remove the IPs from as1, 1 IP each time.
> > @@ -1150,7 +1151,7 @@
priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,tp_dst=333
actions=conjun
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > ])
> >
> > # Add and remove IPs at the same time.
> > @@ -1168,7 +1169,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep -c 10\.0\.0\.22], [0], [1
> > AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10],
[1], [ignore])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Add 1 and remove 2
> > @@ -1183,7 +1184,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep -c 10\.0\.0\.10], [0], [1
> > ])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Add 1 and remove 1
> > @@ -1197,7 +1198,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep -c 10\.0\.0\.21], [0], [1
> > AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10],
[1], [ignore])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Add 2 and remove 2
> > @@ -1214,7 +1215,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=44 |
grep 10\.0\.0\.8], [1], [ignore
> > AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.9],
[1], [ignore])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > OVN_CLEANUP([hv1])
> > @@ -1288,7 +1289,7 @@
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3
actions=co
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > # Remove the IPs from as1 and as2, 1 IP each time.
> > @@ -1341,7 +1342,7 @@
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3,nw_dst=10.
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[9
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > ])
> >
> > # Add 1 more IP back to as2
> > @@ -1639,7 +1640,7 @@
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3
actions=co
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > # Remove the IPs from as1, 1 IP each time.
> > @@ -1697,7 +1698,7 @@
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3
actions=co
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[10
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[1
> > ])
> >
> > # Test the case when there are two references to the same AS but one
of the
> > @@ -1842,7 +1843,7 @@
priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,tp_dst=202
actions=conjun
> > ])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[0
> > ])
> >
> > # Remove those 2 IPs from each AS, should return to the initial state
> > @@ -1870,6 +1871,8 @@
priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,tp_dst=202
actions=conjun
> > ])
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > +# Because of the combined conjunction, AS cannot be tracked for the
flow for
> > +# 10.0.0.33, so removing would trigger reprocessing.
> > AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > @@ -1926,7 +1929,7 @@
priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:03
acti
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[5
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > # Remove the MACs from as1.
> > @@ -2007,7 +2010,7 @@
priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::3
actions=d
> > done
> >
> > reprocess_count_new=$(read_counter consider_logical_flow)
> > -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[5
> > +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0],
[2
> > ])
> >
> > # Remove the IPs from as1, 1 IP each time.
> > --
> > 2.30.2
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev