On Wed, Jun 30, 2021 at 7:01 AM Dumitru Ceara <dce...@redhat.com> wrote: > > It's valid that port_groups contain non-vif ports, they can actually > contain any type of logical_switch_port. > > Also, there's no need to allocate a new sset containing the local ports' > names every time the I-P engine processes a change. We were already > maintaining a set of "local_lport_ids". These correspond to port > bindings that are relevant locally (including non-vif ports). Extend > it to include the locally relevant lport names too and rename the > structure an its helper functions to related_lport*. > > Reported-at: https://github.com/ovn-org/ovn/pull/61#issuecomment-865094163 > Reported-by: Antonio Ojea <ao...@redhat.com> > Fixes: 0cfeba6b55e3 ("ovn-controller: Fix port group conjunction flow explosion problem.") > Signed-off-by: Dumitru Ceara <dce...@redhat.com> > --- > v2: > - Addressed Numan's and Han's comments: > - add struct related_lports > - add test case. > --- > controller/binding.c | 79 ++++++++++++++++++------------------- > controller/binding.h | 31 ++++++++------- > controller/lflow.c | 2 +- > controller/lflow.h | 2 +- > controller/ovn-controller.c | 48 +++++++++------------- > tests/ovn.at | 44 +++++++++++++++++++++ > 6 files changed, 120 insertions(+), 86 deletions(-) > > diff --git a/controller/binding.c b/controller/binding.c > index 7fde0fdbb..594babc98 100644 > --- a/controller/binding.c > +++ b/controller/binding.c > @@ -531,38 +531,41 @@ remove_local_lports(const char *iface_id, struct binding_ctx_out *b_ctx) > } > } > > -/* Add a port binding ID (of the form "dp-key"_"port-key") to the set of local > - * lport IDs. Also track if the set has changed. > +/* Add a port binding to the set of locally relevant lports. > + * Also track if the set has changed. > */ > static void > -update_local_lport_ids(const struct sbrec_port_binding *pb, > - struct binding_ctx_out *b_ctx) > +update_related_lport(const struct sbrec_port_binding *pb, > + struct binding_ctx_out *b_ctx) > { > char buf[16]; > get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key, > buf, sizeof(buf)); > - if (sset_add(b_ctx->local_lport_ids, buf) != NULL) { > - b_ctx->local_lport_ids_changed = true; > + if (sset_add(&b_ctx->related_lports->lport_ids, buf) != NULL) { > + b_ctx->related_lports_changed = true; > > if (b_ctx->tracked_dp_bindings) { > /* Add the 'pb' to the tracked_datapaths. */ > tracked_binding_datapath_lport_add(pb, b_ctx->tracked_dp_bindings); > } > } > + sset_add(&b_ctx->related_lports->lport_names, pb->logical_port); > } > > -/* Remove a port binding id from the set of local lport IDs. Also track if > - * the set has changed. > +/* Remove a port binding id from the set of locally relevant lports. > + * Also track if the set has changed. > */ > static void > -remove_local_lport_ids(const struct sbrec_port_binding *pb, > - struct binding_ctx_out *b_ctx) > +remove_related_lport(const struct sbrec_port_binding *pb, > + struct binding_ctx_out *b_ctx) > { > char buf[16]; > get_unique_lport_key(pb->datapath->tunnel_key, pb->tunnel_key, > buf, sizeof(buf)); > - if (sset_find_and_delete(b_ctx->local_lport_ids, buf)) { > - b_ctx->local_lport_ids_changed = true; > + sset_find_and_delete(&b_ctx->related_lports->lport_names, > + pb->logical_port); > + if (sset_find_and_delete(&b_ctx->related_lports->lport_ids, buf)) { > + b_ctx->related_lports_changed = true; > > if (b_ctx->tracked_dp_bindings) { > /* Add the 'pb' to the tracked_datapaths. */ > @@ -678,6 +681,20 @@ static struct binding_lport *binding_lport_check_and_cleanup( > > static char *get_lport_type_str(enum en_lport_type lport_type); > > +void > +related_lports_init(struct related_lports *rp) > +{ > + sset_init(&rp->lport_names); > + sset_init(&rp->lport_ids); > +} > + > +void > +related_lports_destroy(struct related_lports *rp) > +{ > + sset_destroy(&rp->lport_names); > + sset_destroy(&rp->lport_ids); > +} > + > void > local_binding_data_init(struct local_binding_data *lbinding_data) > { > @@ -1172,7 +1189,7 @@ release_binding_lport(const struct sbrec_chassis *chassis_rec, > struct binding_ctx_out *b_ctx_out) > { > if (is_binding_lport_this_chassis(b_lport, chassis_rec)) { > - remove_local_lport_ids(b_lport->pb, b_ctx_out); > + remove_related_lport(b_lport->pb, b_ctx_out); > if (!release_lport(b_lport->pb, sb_readonly, > b_ctx_out->tracked_dp_bindings, > b_ctx_out->if_mgr)) { > @@ -1214,7 +1231,7 @@ consider_vif_lport_(const struct sbrec_port_binding *pb, > pb->datapath, false, > b_ctx_out->local_datapaths, > b_ctx_out->tracked_dp_bindings); > - update_local_lport_ids(pb, b_ctx_out); > + update_related_lport(pb, b_ctx_out); > update_local_lports(pb->logical_port, b_ctx_out); > if (b_lport->lbinding->iface && qos_map && b_ctx_in->ovs_idl_txn) { > get_qos_params(pb, qos_map); > @@ -1405,7 +1422,7 @@ consider_virtual_lport(const struct sbrec_port_binding *pb, > * its entry from the local_lport_ids if present. This is required > * when a virtual port moves from one chassis to other.*/ > if (!virtual_b_lport) { > - remove_local_lport_ids(pb, b_ctx_out); > + remove_related_lport(pb, b_ctx_out); > } > > return true; > @@ -1430,7 +1447,7 @@ consider_nonvif_lport_(const struct sbrec_port_binding *pb, > b_ctx_out->local_datapaths, > b_ctx_out->tracked_dp_bindings); > > - update_local_lport_ids(pb, b_ctx_out); > + update_related_lport(pb, b_ctx_out); > return claim_lport(pb, NULL, b_ctx_in->chassis_rec, NULL, > !b_ctx_in->ovnsb_idl_txn, false, > b_ctx_out->tracked_dp_bindings, > @@ -1482,7 +1499,7 @@ consider_localnet_lport(const struct sbrec_port_binding *pb, > get_qos_params(pb, qos_map); > } > > - update_local_lport_ids(pb, b_ctx_out); > + update_related_lport(pb, b_ctx_out); > } > > static bool > @@ -1512,7 +1529,7 @@ consider_ha_lport(const struct sbrec_port_binding *pb, > pb->datapath, false, > b_ctx_out->local_datapaths, > b_ctx_out->tracked_dp_bindings); > - update_local_lport_ids(pb, b_ctx_out); > + update_related_lport(pb, b_ctx_out); > } > > return consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in, b_ctx_out); > @@ -1634,7 +1651,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) > case LP_PATCH: > case LP_LOCALPORT: > case LP_VTEP: > - update_local_lport_ids(pb, b_ctx_out); > + update_related_lport(pb, b_ctx_out); > break; > > case LP_VIF: > @@ -1895,7 +1912,7 @@ remove_pb_from_local_datapath(const struct sbrec_port_binding *pb, > struct binding_ctx_out *b_ctx_out, > struct local_datapath *ld) > { > - remove_local_lport_ids(pb, b_ctx_out); > + remove_related_lport(pb, b_ctx_out); > if (!strcmp(pb->type, "patch") || > !strcmp(pb->type, "l3gateway")) { > remove_local_datapath_peer_port(pb, ld, b_ctx_out->local_datapaths); > @@ -2502,7 +2519,7 @@ delete_done: > case LP_PATCH: > case LP_LOCALPORT: > case LP_VTEP: > - update_local_lport_ids(pb, b_ctx_out); > + update_related_lport(pb, b_ctx_out); > if (lport_type == LP_PATCH) { > if (!ld) { > /* If 'ld' for this lport is not present, then check if > @@ -2926,23 +2943,3 @@ cleanup: > > return b_lport; > } > - > -struct sset * > -binding_collect_local_binding_lports(struct local_binding_data *lbinding_data) > -{ > - struct sset *lports = xzalloc(sizeof *lports); > - sset_init(lports); > - struct shash_node *shash_node; > - SHASH_FOR_EACH (shash_node, &lbinding_data->lports) { > - struct binding_lport *b_lport = shash_node->data; > - sset_add(lports, b_lport->name); > - } > - return lports; > -} > - > -void > -binding_destroy_local_binding_lports(struct sset *lports) > -{ > - sset_destroy(lports); > - free(lports); > -} > diff --git a/controller/binding.h b/controller/binding.h > index 8f3289476..a08011ae2 100644 > --- a/controller/binding.h > +++ b/controller/binding.h > @@ -22,6 +22,7 @@ > #include "openvswitch/hmap.h" > #include "openvswitch/uuid.h" > #include "openvswitch/list.h" > +#include "sset.h" > > struct hmap; > struct ovsdb_idl; > @@ -56,6 +57,19 @@ struct binding_ctx_in { > const struct ovsrec_interface_table *iface_table; > }; > > +/* Locally relevant port bindings, e.g., VIFs that might be bound locally, > + * patch ports. > + */ > +struct related_lports { > + struct sset lport_names; /* Set of port names. */ > + struct sset lport_ids; /* Set of <datapath-tunnel-key>_<port-tunnel-key> > + * IDs for fast lookup. > + */ > +}; > + > +void related_lports_init(struct related_lports *); > +void related_lports_destroy(struct related_lports *); > + > struct binding_ctx_out { > struct hmap *local_datapaths; > struct local_binding_data *lbinding_data; > @@ -65,11 +79,9 @@ struct binding_ctx_out { > /* Track if local_lports have been updated. */ > bool local_lports_changed; > > - /* sset of local lport ids in the format > - * <datapath-tunnel-key>_<port-tunnel-key>. */ > - struct sset *local_lport_ids; > - /* Track if local_lport_ids has been updated. */ > - bool local_lport_ids_changed; > + /* Port bindings that are relevant to the local chassis. */ > + struct related_lports *related_lports; > + bool related_lports_changed; > > /* Track if non-vif port bindings (e.g., patch, external) have been > * added/deleted. > @@ -133,13 +145,4 @@ bool binding_handle_port_binding_changes(struct binding_ctx_in *, > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > void binding_dump_local_bindings(struct local_binding_data *, struct ds *); > - > -/* Generates a sset of lport names from local_binding_data. > - * Note: the caller is responsible for destroying and freeing the returned > - * sset, by calling binding_detroy_local_binding_lports(). */ > -struct sset *binding_collect_local_binding_lports(struct local_binding_data *); > - > -/* Destroy and free the lports sset returned by > - * binding_collect_local_binding_lports(). */ > -void binding_destroy_local_binding_lports(struct sset *lports); > #endif /* controller/binding.h */ > diff --git a/controller/lflow.c b/controller/lflow.c > index 34eca135a..abb01f0ce 100644 > --- a/controller/lflow.c > +++ b/controller/lflow.c > @@ -625,7 +625,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, > get_unique_lport_key(dp_id, port_id, buf, sizeof(buf)); > lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_PORTBINDING, buf, > &lflow->header_.uuid); > - if (!sset_contains(l_ctx_in->local_lport_ids, buf)) { > + if (!sset_contains(l_ctx_in->related_lport_ids, buf)) { > VLOG_DBG("lflow "UUID_FMT > " port %s in match is not local, skip", > UUID_ARGS(&lflow->header_.uuid), > diff --git a/controller/lflow.h b/controller/lflow.h > index e98edf81d..699f9c2d5 100644 > --- a/controller/lflow.h > +++ b/controller/lflow.h > @@ -144,7 +144,7 @@ struct lflow_ctx_in { > const struct shash *addr_sets; > const struct shash *port_groups; > const struct sset *active_tunnels; > - const struct sset *local_lport_ids; > + const struct sset *related_lport_ids; > }; > > struct lflow_ctx_out { > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > index b6afb8fb9..3bb8b22eb 100644 > --- a/controller/ovn-controller.c > +++ b/controller/ovn-controller.c > @@ -1014,9 +1014,10 @@ struct ed_type_runtime_data { > * local hypervisor, and localnet ports. */ > struct sset local_lports; > > - /* Contains the same ports as local_lports, but in the format: > - * <datapath-tunnel-key>_<port-tunnel-key> */ > - struct sset local_lport_ids; > + /* Port bindings that are relevant to the local chassis (VIFs bound > + * localy, patch ports). > + */ > + struct related_lports related_lports; > struct sset active_tunnels; > > /* runtime data engine private data. */ > @@ -1109,7 +1110,7 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED, > > hmap_init(&data->local_datapaths); > sset_init(&data->local_lports); > - sset_init(&data->local_lport_ids); > + related_lports_init(&data->related_lports); > sset_init(&data->active_tunnels); > sset_init(&data->egress_ifaces); > smap_init(&data->local_iface_ids); > @@ -1127,7 +1128,7 @@ en_runtime_data_cleanup(void *data) > struct ed_type_runtime_data *rt_data = data; > > sset_destroy(&rt_data->local_lports); > - sset_destroy(&rt_data->local_lport_ids); > + related_lports_destroy(&rt_data->related_lports); > sset_destroy(&rt_data->active_tunnels); > sset_destroy(&rt_data->egress_ifaces); > smap_destroy(&rt_data->local_iface_ids); > @@ -1219,8 +1220,8 @@ init_binding_ctx(struct engine_node *node, > b_ctx_out->local_datapaths = &rt_data->local_datapaths; > b_ctx_out->local_lports = &rt_data->local_lports; > b_ctx_out->local_lports_changed = false; > - b_ctx_out->local_lport_ids = &rt_data->local_lport_ids; > - b_ctx_out->local_lport_ids_changed = false; > + b_ctx_out->related_lports = &rt_data->related_lports; > + b_ctx_out->related_lports_changed = false; > b_ctx_out->non_vif_ports_changed = false; > b_ctx_out->egress_ifaces = &rt_data->egress_ifaces; > b_ctx_out->lbinding_data = &rt_data->lbinding_data; > @@ -1235,7 +1236,6 @@ en_runtime_data_run(struct engine_node *node, void *data) > struct ed_type_runtime_data *rt_data = data; > struct hmap *local_datapaths = &rt_data->local_datapaths; > struct sset *local_lports = &rt_data->local_lports; > - struct sset *local_lport_ids = &rt_data->local_lport_ids; > struct sset *active_tunnels = &rt_data->active_tunnels; > > static bool first_run = true; > @@ -1252,12 +1252,12 @@ en_runtime_data_run(struct engine_node *node, void *data) > hmap_clear(local_datapaths); > local_binding_data_destroy(&rt_data->lbinding_data); > sset_destroy(local_lports); > - sset_destroy(local_lport_ids); > + related_lports_destroy(&rt_data->related_lports); > sset_destroy(active_tunnels); > sset_destroy(&rt_data->egress_ifaces); > smap_destroy(&rt_data->local_iface_ids); > sset_init(local_lports); > - sset_init(local_lport_ids); > + related_lports_init(&rt_data->related_lports); > sset_init(active_tunnels); > sset_init(&rt_data->egress_ifaces); > smap_init(&rt_data->local_iface_ids); > @@ -1327,7 +1327,7 @@ runtime_data_sb_port_binding_handler(struct engine_node *node, void *data) > } > > rt_data->local_lports_changed = b_ctx_out.local_lports_changed; > - if (b_ctx_out.local_lport_ids_changed || > + if (b_ctx_out.related_lports_changed || > b_ctx_out.non_vif_ports_changed || > b_ctx_out.local_lports_changed || > !hmap_is_empty(b_ctx_out.tracked_dp_bindings)) { > @@ -1638,11 +1638,8 @@ en_port_groups_run(struct engine_node *node, void *data) > struct ed_type_runtime_data *rt_data = > engine_get_input_data("runtime_data", node); > > - struct sset *local_b_lports = binding_collect_local_binding_lports( > - &rt_data->lbinding_data); > - port_groups_init(pg_table, local_b_lports, &pg->port_group_ssets, > - &pg->port_groups_cs_local); > - binding_destroy_local_binding_lports(local_b_lports); > + port_groups_init(pg_table, &rt_data->related_lports.lport_names, > + &pg->port_group_ssets, &pg->port_groups_cs_local); > > engine_set_node_state(node, EN_UPDATED); > } > @@ -1659,12 +1656,9 @@ port_groups_sb_port_group_handler(struct engine_node *node, void *data) > struct ed_type_runtime_data *rt_data = > engine_get_input_data("runtime_data", node); > > - struct sset *local_b_lports = binding_collect_local_binding_lports( > - &rt_data->lbinding_data); > - port_groups_update(pg_table, local_b_lports, &pg->port_group_ssets, > - &pg->port_groups_cs_local, &pg->new, &pg->deleted, > - &pg->updated); > - binding_destroy_local_binding_lports(local_b_lports); > + port_groups_update(pg_table, &rt_data->related_lports.lport_names, > + &pg->port_group_ssets, &pg->port_groups_cs_local, > + &pg->new, &pg->deleted, &pg->updated); > > if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) || > !sset_is_empty(&pg->updated)) { > @@ -1697,9 +1691,6 @@ port_groups_runtime_data_handler(struct engine_node *node, void *data) > goto out; > } > > - struct sset *local_b_lports = binding_collect_local_binding_lports( > - &rt_data->lbinding_data); > - > const struct sbrec_port_group *pg_sb; > SBREC_PORT_GROUP_TABLE_FOR_EACH (pg_sb, pg_table) { > struct sset *pg_lports = shash_find_data(&pg->port_group_ssets, > @@ -1726,13 +1717,12 @@ port_groups_runtime_data_handler(struct engine_node *node, void *data) > if (need_update) { > expr_const_sets_add_strings(&pg->port_groups_cs_local, pg_sb->name, > (const char *const *) pg_sb->ports, > - pg_sb->n_ports, local_b_lports); > + pg_sb->n_ports, > + &rt_data->related_lports.lport_names); > sset_add(&pg->updated, pg_sb->name); > } > } > > - binding_destroy_local_binding_lports(local_b_lports); > - > out: > if (!sset_is_empty(&pg->new) || !sset_is_empty(&pg->deleted) || > !sset_is_empty(&pg->updated)) { > @@ -2042,7 +2032,7 @@ init_lflow_ctx(struct engine_node *node, > l_ctx_in->addr_sets = addr_sets; > l_ctx_in->port_groups = port_groups; > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > - l_ctx_in->local_lport_ids = &rt_data->local_lport_ids; > + l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; > > l_ctx_out->flow_table = &fo->flow_table; > l_ctx_out->group_table = &fo->group_table; > diff --git a/tests/ovn.at b/tests/ovn.at > index db1a0a35c..7a718d4b6 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -26805,6 +26805,50 @@ OVN_CLEANUP([hv1]) > AT_CLEANUP > ]) > > +# Tests that ACLs referencing port groups that include ports connected to > +# logical routers are correctly applied. > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([ovn -- ACL with Port Group including router ports]) > +ovn_start > +net_add n1 > + > +sim_add hv1 > +as hv1 > +ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > + > +check ovn-nbctl \ > + -- lr-add lr \ > + -- ls-add ls \ > + -- lrp-add lr lrp_ls 00:00:00:00:00:01 42.42.42.1/24 \ > + -- lsp-add ls ls_lr \ > + -- lsp-set-addresses ls_lr router \ > + -- lsp-set-type ls_lr router \ > + -- lsp-set-options ls_lr router-port=lr_ls \ > + -- lsp-add ls vm1 > + > +check ovn-nbctl pg-add pg ls_lr \ > + -- acl-add pg from-lport 1 'inport == @pg && ip4.dst == 42.42.42.42' drop > + > +check ovs-vsctl add-port br-int vm1 \ > + -- set interface vm1 external_ids:iface-id=vm1 > + > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +dp_key=$(fetch_column Datapath_Binding tunnel_key external_ids:name=ls) > +rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=ls_lr) > + > +# Check that ovn-controller adds a flow to drop packets with dest IP > +# 42.42.42.42 coming from the router port. > +AT_CHECK([ovs-ofctl dump-flows br-int table=17 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=drop" -c], [0], [dnl > +1 > +]) > + > +OVN_CLEANUP([hv1]) > +AT_CLEANUP > +]) > + > OVN_FOR_EACH_NORTHD([ > AT_SETUP([ovn -- Static route with discard nexthop]) > ovn_start > -- > 2.27.0 >
Thanks Dumitru! Acked-by: Han Zhou <hz...@ovn.org> Not sure if Numan would like to take a second look as well, so let's wait for one or two days before merging. _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev