/
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
> + * 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
> + *
> + * 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