Message ID | 166759987050.515460.12406491945779417131.stgit@dceara.remote.csb |
---|---|
State | Changes Requested |
Delegated to: | Mark Michelson |
Headers | show |
Series | Add OVN component templates. | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | warning | apply and check: warning |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
ovsrobot/github-robot-_ovn-kubernetes | success | github build: passed |
Bleep bloop. Greetings Dumitru Ceara, I am a robot and I have tried out your patch. Thanks for your contribution. I encountered some error that I wasn't expecting. See the details below. checkpatch: ERROR: Inappropriate bracing around statement #1187 FILE: lib/objdep.h:52: HMAP_FOR_EACH (NODE, hmap_node, &(MAP)->objs) Lines checked: 1261, Warnings: 0, Errors: 1 Please check this out. If you feel there has been an error, please email aconole@redhat.com Thanks, 0-day Robot
Acked-by: Mark Michelson <mmichels@redhat.com> On 11/4/22 18:11, Dumitru Ceara wrote: > This makes it easier to have an overview of what the code does and at the > same time it allows multiple users to define and manage > "resource <-> object" dependencies. > > Acked-by: Han Zhou <hzhou@ovn.org> > Signed-off-by: Dumitru Ceara <dceara@redhat.com> > --- > V2: > - Addressed Mark's comments: > - Fixed typos in comments in objdep.h. > - Made objdep_change_handler return bool (handled successfully or not). > - Reverted some unrelated style changes. > - Fixed cast style. > - Addressed Han's comments: > - Removed superfluous 'type' argument name in prototypes. > - Added Han's ack. > --- > controller/lflow.c | 330 ++++++++++--------------------------------- > controller/lflow.h | 67 +-------- > controller/ovn-controller.c | 55 +++++-- > lib/automake.mk | 2 > lib/objdep.c | 260 ++++++++++++++++++++++++++++++++++ > lib/objdep.h | 122 ++++++++++++++++ > 6 files changed, 508 insertions(+), 328 deletions(-) > create mode 100644 lib/objdep.c > create mode 100644 lib/objdep.h > > diff --git a/controller/lflow.c b/controller/lflow.c > index cc0f31db06..d4434bdee8 100644 > --- a/controller/lflow.c > +++ b/controller/lflow.c > @@ -61,7 +61,7 @@ struct lookup_port_aux { > struct ovsdb_idl_index *sbrec_port_binding_by_name; > const struct sbrec_datapath_binding *dp; > const struct sbrec_logical_flow *lflow; > - struct lflow_resource_ref *lfrr; > + struct objdep_mgr *deps_mgr; > const struct hmap *chassis_tunnels; > }; > > @@ -72,8 +72,8 @@ struct condition_aux { > const struct sset *active_tunnels; > const struct sbrec_logical_flow *lflow; > /* Resource reference to store the port name referenced > - * in is_chassis_resident() to the logical flow. */ > - struct lflow_resource_ref *lfrr; > + * in is_chassis_resident() to the object (logical flow). */ > + struct objdep_mgr *deps_mgr; > }; > > static struct expr * > @@ -81,7 +81,7 @@ convert_match_to_expr(const struct sbrec_logical_flow *, > const struct local_datapath *ldp, > struct expr **prereqs, const struct shash *addr_sets, > const struct shash *port_groups, > - struct lflow_resource_ref *, bool *pg_addr_set_ref); > + struct objdep_mgr *, bool *pg_addr_set_ref); > static void > add_matches_to_flow_table(const struct sbrec_logical_flow *, > const struct local_datapath *, > @@ -94,17 +94,6 @@ consider_logical_flow(const struct sbrec_logical_flow *lflow, > bool is_recompute, > struct lflow_ctx_in *l_ctx_in, > struct lflow_ctx_out *l_ctx_out); > -static void lflow_resource_add(struct lflow_resource_ref *, enum ref_type, > - const char *ref_name, const struct uuid *, > - size_t ref_count); > -static struct ref_lflow_node *ref_lflow_lookup(struct hmap *ref_lflow_table, > - enum ref_type, > - const char *ref_name); > -static struct lflow_ref_node *lflow_ref_lookup(struct hmap *lflow_ref_table, > - const struct uuid *lflow_uuid); > -static void ref_lflow_node_destroy(struct ref_lflow_node *); > -static void lflow_resource_destroy_lflow(struct lflow_resource_ref *, > - const struct uuid *lflow_uuid); > > static void add_port_sec_flows(const struct shash *binding_lports, > const struct sbrec_chassis *, > @@ -125,8 +114,8 @@ lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp) > /* Store the name that used to lookup the lport to lflow reference, so that > * in the future when the lport's port binding changes, the logical flow > * that references this lport can be reprocessed. */ > - lflow_resource_add(aux->lfrr, REF_TYPE_PORTBINDING, port_name, > - &aux->lflow->header_.uuid, 0); > + objdep_mgr_add(aux->deps_mgr, OBJDEP_TYPE_PORTBINDING, port_name, > + &aux->lflow->header_.uuid); > > const struct sbrec_port_binding *pb > = lport_lookup_by_name(aux->sbrec_port_binding_by_name, port_name); > @@ -141,8 +130,8 @@ lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp) > * this multicast group can be reprocessed. */ > struct ds mg_key = DS_EMPTY_INITIALIZER; > get_mc_group_key(port_name, aux->dp->tunnel_key, &mg_key); > - lflow_resource_add(aux->lfrr, REF_TYPE_MC_GROUP, ds_cstr(&mg_key), > - &aux->lflow->header_.uuid, 0); > + objdep_mgr_add(aux->deps_mgr, OBJDEP_TYPE_MC_GROUP, ds_cstr(&mg_key), > + &aux->lflow->header_.uuid); > ds_destroy(&mg_key); > > const struct sbrec_multicast_group *mg = mcgroup_lookup_by_dp_name( > @@ -180,11 +169,11 @@ is_chassis_resident_cb(const void *c_aux_, const char *port_name) > { > const struct condition_aux *c_aux = c_aux_; > > - /* Store the port name that used to lookup the lport to lflow reference, so > - * that in the future when the lport's port-binding changes the logical > + /* Store the port name that used to lookup the lport to object reference, > + * so that in the future when the lport's port-binding changes the logical > * flow that references this lport can be reprocessed. */ > - lflow_resource_add(c_aux->lfrr, REF_TYPE_PORTBINDING, port_name, > - &c_aux->lflow->header_.uuid, 0); > + objdep_mgr_add(c_aux->deps_mgr, OBJDEP_TYPE_PORTBINDING, port_name, > + &c_aux->lflow->header_.uuid); > > const struct sbrec_port_binding *pb > = lport_lookup_by_name(c_aux->sbrec_port_binding_by_name, port_name); > @@ -207,155 +196,6 @@ is_chassis_resident_cb(const void *c_aux_, const char *port_name) > } > } > > -void > -lflow_resource_init(struct lflow_resource_ref *lfrr) > -{ > - hmap_init(&lfrr->ref_lflow_table); > - hmap_init(&lfrr->lflow_ref_table); > -} > - > -void > -lflow_resource_destroy(struct lflow_resource_ref *lfrr) > -{ > - struct ref_lflow_node *rlfn; > - HMAP_FOR_EACH_SAFE (rlfn, node, &lfrr->ref_lflow_table) { > - struct lflow_ref_list_node *lrln; > - HMAP_FOR_EACH_SAFE (lrln, hmap_node, &rlfn->lflow_uuids) { > - ovs_list_remove(&lrln->list_node); > - hmap_remove(&rlfn->lflow_uuids, &lrln->hmap_node); > - free(lrln); > - } > - hmap_remove(&lfrr->ref_lflow_table, &rlfn->node); > - ref_lflow_node_destroy(rlfn); > - } > - hmap_destroy(&lfrr->ref_lflow_table); > - > - struct lflow_ref_node *lfrn; > - HMAP_FOR_EACH_SAFE (lfrn, node, &lfrr->lflow_ref_table) { > - hmap_remove(&lfrr->lflow_ref_table, &lfrn->node); > - free(lfrn); > - } > - hmap_destroy(&lfrr->lflow_ref_table); > -} > - > -void > -lflow_resource_clear(struct lflow_resource_ref *lfrr) > -{ > - lflow_resource_destroy(lfrr); > - lflow_resource_init(lfrr); > -} > - > -static struct ref_lflow_node* > -ref_lflow_lookup(struct hmap *ref_lflow_table, > - enum ref_type type, const char *ref_name) > -{ > - struct ref_lflow_node *rlfn; > - > - HMAP_FOR_EACH_WITH_HASH (rlfn, node, hash_string(ref_name, type), > - ref_lflow_table) { > - if (rlfn->type == type && !strcmp(rlfn->ref_name, ref_name)) { > - return rlfn; > - } > - } > - return NULL; > -} > - > -static struct lflow_ref_node* > -lflow_ref_lookup(struct hmap *lflow_ref_table, > - const struct uuid *lflow_uuid) > -{ > - struct lflow_ref_node *lfrn; > - > - HMAP_FOR_EACH_WITH_HASH (lfrn, node, uuid_hash(lflow_uuid), > - lflow_ref_table) { > - if (uuid_equals(&lfrn->lflow_uuid, lflow_uuid)) { > - return lfrn; > - } > - } > - return NULL; > -} > - > -static void > -lflow_resource_add(struct lflow_resource_ref *lfrr, enum ref_type type, > - const char *ref_name, const struct uuid *lflow_uuid, > - size_t ref_count) > -{ > - struct ref_lflow_node *rlfn = ref_lflow_lookup(&lfrr->ref_lflow_table, > - type, ref_name); > - struct lflow_ref_node *lfrn = lflow_ref_lookup(&lfrr->lflow_ref_table, > - lflow_uuid); > - if (rlfn && lfrn) { > - /* Check if the mapping already existed before adding a new one. */ > - struct lflow_ref_list_node *n; > - HMAP_FOR_EACH_WITH_HASH (n, hmap_node, uuid_hash(lflow_uuid), > - &rlfn->lflow_uuids) { > - if (uuid_equals(&n->lflow_uuid, lflow_uuid)) { > - return; > - } > - } > - } > - > - if (!rlfn) { > - rlfn = xzalloc(sizeof *rlfn); > - rlfn->node.hash = hash_string(ref_name, type); > - rlfn->type = type; > - rlfn->ref_name = xstrdup(ref_name); > - hmap_init(&rlfn->lflow_uuids); > - hmap_insert(&lfrr->ref_lflow_table, &rlfn->node, rlfn->node.hash); > - } > - > - if (!lfrn) { > - lfrn = xzalloc(sizeof *lfrn); > - lfrn->node.hash = uuid_hash(lflow_uuid); > - lfrn->lflow_uuid = *lflow_uuid; > - ovs_list_init(&lfrn->lflow_ref_head); > - hmap_insert(&lfrr->lflow_ref_table, &lfrn->node, lfrn->node.hash); > - } > - > - struct lflow_ref_list_node *lrln = xzalloc(sizeof *lrln); > - lrln->lflow_uuid = *lflow_uuid; > - lrln->ref_count = ref_count; > - lrln->rlfn = rlfn; > - hmap_insert(&rlfn->lflow_uuids, &lrln->hmap_node, uuid_hash(lflow_uuid)); > - ovs_list_push_back(&lfrn->lflow_ref_head, &lrln->list_node); > -} > - > -static void > -ref_lflow_node_destroy(struct ref_lflow_node *rlfn) > -{ > - free(rlfn->ref_name); > - hmap_destroy(&rlfn->lflow_uuids); > - free(rlfn); > -} > - > -static void > -lflow_resource_destroy_lflow(struct lflow_resource_ref *lfrr, > - const struct uuid *lflow_uuid) > -{ > - struct lflow_ref_node *lfrn = lflow_ref_lookup(&lfrr->lflow_ref_table, > - lflow_uuid); > - if (!lfrn) { > - return; > - } > - > - hmap_remove(&lfrr->lflow_ref_table, &lfrn->node); > - struct lflow_ref_list_node *lrln; > - LIST_FOR_EACH_SAFE (lrln, list_node, &lfrn->lflow_ref_head) { > - ovs_list_remove(&lrln->list_node); > - hmap_remove(&lrln->rlfn->lflow_uuids, &lrln->hmap_node); > - > - /* Clean up the node in ref_lflow_table if the resource is not > - * referred by any logical flows. */ > - if (hmap_is_empty(&lrln->rlfn->lflow_uuids)) { > - hmap_remove(&lfrr->ref_lflow_table, &lrln->rlfn->node); > - ref_lflow_node_destroy(lrln->rlfn); > - } > - > - free(lrln); > - } > - free(lfrn); > -} > - > /* Adds the logical flows from the Logical_Flow table to flow tables. */ > static void > add_logical_flows(struct lflow_ctx_in *l_ctx_in, > @@ -400,7 +240,7 @@ lflow_handle_changed_flows(struct lflow_ctx_in *l_ctx_in, > struct uuidset_node *ofrn; > UUIDSET_FOR_EACH (ofrn, &flood_remove_nodes) { > /* Delete entries from lflow resource reference. */ > - lflow_resource_destroy_lflow(l_ctx_out->lfrr, &ofrn->uuid); > + objdep_mgr_remove_obj(l_ctx_out->lflow_deps_mgr, &ofrn->uuid); > /* Delete conj_ids owned by the lflow. */ > lflow_conj_ids_free(l_ctx_out->conj_ids, &ofrn->uuid); > /* Reprocessing the lflow if the sb record is not deleted. */ > @@ -537,7 +377,7 @@ consider_lflow_for_added_as_ips__( > .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, > .dp = dp, > .lflow = lflow, > - .lfrr = l_ctx_out->lfrr, > + .deps_mgr = l_ctx_out->lflow_deps_mgr, > }; > struct condition_aux cond_aux = { > .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, > @@ -545,7 +385,7 @@ consider_lflow_for_added_as_ips__( > .chassis = l_ctx_in->chassis, > .active_tunnels = l_ctx_in->active_tunnels, > .lflow = lflow, > - .lfrr = l_ctx_out->lfrr, > + .deps_mgr = l_ctx_out->lflow_deps_mgr, > }; > > struct hmap matches = HMAP_INITIALIZER(&matches); > @@ -591,7 +431,7 @@ consider_lflow_for_added_as_ips__( > struct expr *expr = convert_match_to_expr(lflow, ldp, &prereqs, > l_ctx_in->addr_sets, > l_ctx_in->port_groups, > - l_ctx_out->lfrr, NULL); > + l_ctx_out->lflow_deps_mgr, 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); > @@ -787,10 +627,10 @@ lflow_handle_addr_set_update(const char *as_name, > return false; > } > > - struct ref_lflow_node *rlfn = > - ref_lflow_lookup(&l_ctx_out->lfrr->ref_lflow_table, REF_TYPE_ADDRSET, > - as_name); > - if (!rlfn) { > + struct resource_to_objects_node *resource_node = > + objdep_mgr_find_objs(l_ctx_out->lflow_deps_mgr, OBJDEP_TYPE_ADDRSET, > + as_name); > + if (!resource_node) { > *changed = false; > return true; > } > @@ -798,22 +638,23 @@ lflow_handle_addr_set_update(const char *as_name, > *changed = false; > > bool ret = true; > - struct lflow_ref_list_node *lrln; > - HMAP_FOR_EACH (lrln, hmap_node, &rlfn->lflow_uuids) { > - if (uuidset_find(l_ctx_out->lflows_processed, &lrln->lflow_uuid)) { > + struct object_to_resources_list_node *resource_list_node; > + RESOURCE_FOR_EACH_OBJ (resource_list_node, resource_node) { > + const struct uuid *obj_uuid = &resource_list_node->obj_uuid; > + if (uuidset_find(l_ctx_out->lflows_processed, obj_uuid)) { > VLOG_DBG("lflow "UUID_FMT"has been processed, skip.", > - UUID_ARGS(&lrln->lflow_uuid)); > + UUID_ARGS(obj_uuid)); > continue; > } > const struct sbrec_logical_flow *lflow = > sbrec_logical_flow_table_get_for_uuid(l_ctx_in->logical_flow_table, > - &lrln->lflow_uuid); > + obj_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); > + UUID_ARGS(obj_uuid), as_name); > continue; > } > *changed = true; > @@ -825,9 +666,9 @@ lflow_handle_addr_set_update(const char *as_name, > 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)) { > + if (!ofctrl_remove_flows_for_as_ip( > + l_ctx_out->flow_table, obj_uuid, &as_info, > + resource_list_node->ref_count)) { > ret = false; > goto done; > } > @@ -836,7 +677,7 @@ lflow_handle_addr_set_update(const char *as_name, > > if (as_diff->added) { > if (!consider_lflow_for_added_as_ips(lflow, as_name, > - lrln->ref_count, > + resource_list_node->ref_count, > as_diff->added, > l_ctx_in, l_ctx_out)) { > ret = false; > @@ -850,59 +691,32 @@ done: > } > > bool > -lflow_handle_changed_ref(enum ref_type ref_type, const char *ref_name, > - struct lflow_ctx_in *l_ctx_in, > - struct lflow_ctx_out *l_ctx_out, > - bool *changed) > +lflow_handle_changed_ref(enum objdep_type type, const char *res_name, > + struct ovs_list *objs_todo, > + const void *in_arg, void *out_arg) > { > - struct ref_lflow_node *rlfn = > - ref_lflow_lookup(&l_ctx_out->lfrr->ref_lflow_table, ref_type, > - ref_name); > - if (!rlfn) { > - *changed = false; > - return true; > - } > - VLOG_DBG("Handle changed lflow reference for resource type: %d," > - " name: %s.", ref_type, ref_name); > - *changed = false; > - bool ret = true; > - > - struct ovs_list lflows_todo = OVS_LIST_INITIALIZER(&lflows_todo); > - > - struct lflow_ref_list_node *lrln, *lrln_uuid; > - HMAP_FOR_EACH (lrln, hmap_node, &rlfn->lflow_uuids) { > - if (uuidset_find(l_ctx_out->lflows_processed, &lrln->lflow_uuid)) { > - continue; > - } > - /* Use lflow_ref_list_node as list node to store the uuid. > - * Other fields are not used here. */ > - lrln_uuid = xmalloc(sizeof *lrln_uuid); > - lrln_uuid->lflow_uuid = lrln->lflow_uuid; > - ovs_list_push_back(&lflows_todo, &lrln_uuid->list_node); > - } > - if (ovs_list_is_empty(&lflows_todo)) { > - return true; > - } > - *changed = true; > + struct lflow_ctx_in *l_ctx_in = CONST_CAST(struct lflow_ctx_in *, in_arg); > + struct lflow_ctx_out *l_ctx_out = out_arg; > > /* Re-parse the related lflows. */ > /* Firstly, flood remove the flows from desired flow table. */ > + struct object_to_resources_list_node *resource_list_node_uuid; > struct uuidset flood_remove_nodes = > UUIDSET_INITIALIZER(&flood_remove_nodes); > - LIST_FOR_EACH_SAFE (lrln_uuid, list_node, &lflows_todo) { > - VLOG_DBG("Reprocess lflow "UUID_FMT" for resource type: %d," > + LIST_FOR_EACH_SAFE (resource_list_node_uuid, list_node, objs_todo) { > + const struct uuid *obj_uuid = &resource_list_node_uuid->obj_uuid; > + VLOG_DBG("Reprocess lflow "UUID_FMT" for resource type: %s," > " name: %s.", > - UUID_ARGS(&lrln_uuid->lflow_uuid), > - ref_type, ref_name); > - uuidset_insert(&flood_remove_nodes, &lrln_uuid->lflow_uuid); > - free(lrln_uuid); > + UUID_ARGS(obj_uuid), objdep_type_name(type), res_name); > + uuidset_insert(&flood_remove_nodes, obj_uuid); > + free(resource_list_node_uuid); > } > ofctrl_flood_remove_flows(l_ctx_out->flow_table, &flood_remove_nodes); > > /* Secondly, for each lflow that is actually removed, reprocessing it. */ > struct uuidset_node *ofrn; > UUIDSET_FOR_EACH (ofrn, &flood_remove_nodes) { > - lflow_resource_destroy_lflow(l_ctx_out->lfrr, &ofrn->uuid); > + objdep_mgr_remove_obj(l_ctx_out->lflow_deps_mgr, &ofrn->uuid); > lflow_conj_ids_free(l_ctx_out->conj_ids, &ofrn->uuid); > > const struct sbrec_logical_flow *lflow = > @@ -910,9 +724,9 @@ lflow_handle_changed_ref(enum ref_type ref_type, const char *ref_name, > &ofrn->uuid); > if (!lflow) { > VLOG_DBG("lflow "UUID_FMT" not found while reprocessing for" > - " resource type: %d, name: %s.", > + " resource type: %s, name: %s.", > UUID_ARGS(&ofrn->uuid), > - ref_type, ref_name); > + objdep_type_name(type), res_name); > continue; > } > > @@ -929,8 +743,7 @@ lflow_handle_changed_ref(enum ref_type ref_type, const char *ref_name, > consider_logical_flow(lflow, false, l_ctx_in, l_ctx_out); > } > uuidset_destroy(&flood_remove_nodes); > - > - return ret; > + return true; > } > > static void > @@ -985,7 +798,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, > .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, > .dp = ldp->datapath, > .lflow = lflow, > - .lfrr = l_ctx_out->lfrr, > + .deps_mgr = l_ctx_out->lflow_deps_mgr, > .chassis_tunnels = l_ctx_in->chassis_tunnels, > }; > > @@ -1100,7 +913,7 @@ convert_match_to_expr(const struct sbrec_logical_flow *lflow, > struct expr **prereqs, > const struct shash *addr_sets, > const struct shash *port_groups, > - struct lflow_resource_ref *lfrr, > + struct objdep_mgr *mgr, > bool *pg_addr_set_ref) > { > struct shash addr_sets_ref = SHASH_INITIALIZER(&addr_sets_ref); > @@ -1114,14 +927,15 @@ convert_match_to_expr(const struct sbrec_logical_flow *lflow, > &error); > struct shash_node *addr_sets_ref_node; > SHASH_FOR_EACH (addr_sets_ref_node, &addr_sets_ref) { > - lflow_resource_add(lfrr, REF_TYPE_ADDRSET, addr_sets_ref_node->name, > - &lflow->header_.uuid, > - *(size_t *)addr_sets_ref_node->data); > + objdep_mgr_add_with_refcount(mgr, OBJDEP_TYPE_ADDRSET, > + addr_sets_ref_node->name, > + &lflow->header_.uuid, > + *(size_t *) addr_sets_ref_node->data); > } > const char *port_group_name; > SSET_FOR_EACH (port_group_name, &port_groups_ref) { > - lflow_resource_add(lfrr, REF_TYPE_PORTGROUP, port_group_name, > - &lflow->header_.uuid, 0); > + objdep_mgr_add(mgr, OBJDEP_TYPE_PORTGROUP, port_group_name, > + &lflow->header_.uuid); > } > > if (pg_addr_set_ref) { > @@ -1165,8 +979,8 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, > > const char *io_port = smap_get(&lflow->tags, "in_out_port"); > if (io_port) { > - lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_PORTBINDING, io_port, > - &lflow->header_.uuid, 0); > + objdep_mgr_add(l_ctx_out->lflow_deps_mgr, OBJDEP_TYPE_PORTBINDING, > + io_port, &lflow->header_.uuid); > const struct sbrec_port_binding *pb > = lport_lookup_by_name(l_ctx_in->sbrec_port_binding_by_name, > io_port); > @@ -1232,7 +1046,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, > .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, > .dp = dp, > .lflow = lflow, > - .lfrr = l_ctx_out->lfrr, > + .deps_mgr = l_ctx_out->lflow_deps_mgr, > }; > struct condition_aux cond_aux = { > .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, > @@ -1240,7 +1054,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, > .chassis = l_ctx_in->chassis, > .active_tunnels = l_ctx_in->active_tunnels, > .lflow = lflow, > - .lfrr = l_ctx_out->lfrr, > + .deps_mgr = l_ctx_out->lflow_deps_mgr, > }; > > struct lflow_cache_value *lcv = > @@ -1272,7 +1086,8 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, > switch (lcv_type) { > case LCACHE_T_NONE: > expr = convert_match_to_expr(lflow, ldp, &prereqs, l_ctx_in->addr_sets, > - l_ctx_in->port_groups, l_ctx_out->lfrr, > + l_ctx_in->port_groups, > + l_ctx_out->lflow_deps_mgr, > &pg_addr_set_ref); > if (!expr) { > goto done; > @@ -1345,8 +1160,8 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, > /* Cache new entry if caching is enabled. */ > if (lflow_cache_is_enabled(l_ctx_out->lflow_cache)) { > if (cached_expr > - && !lflow_ref_lookup(&l_ctx_out->lfrr->lflow_ref_table, > - &lflow->header_.uuid)) { > + && !objdep_mgr_contains_obj(l_ctx_out->lflow_deps_mgr, > + &lflow->header_.uuid)) { > lflow_cache_add_matches(l_ctx_out->lflow_cache, > &lflow->header_.uuid, start_conj_id, > n_conjs, matches, matches_size); > @@ -2448,7 +2263,7 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, > &lflow->header_.uuid)) { > continue; > } > - /* Don't call lflows_processed_add() because here we process the > + /* Don't call uuidset_insert() because here we process the > * lflow only for one of the DPs in the DP group, which may be > * incomplete. */ > consider_logical_flow__(lflow, dp, l_ctx_in, l_ctx_out); > @@ -2514,7 +2329,11 @@ lflow_handle_flows_for_lport(const struct sbrec_port_binding *pb, > { > bool changed; > > - if (!lflow_handle_changed_ref(REF_TYPE_PORTBINDING, pb->logical_port, > + if (!objdep_mgr_handle_change(l_ctx_out->lflow_deps_mgr, > + OBJDEP_TYPE_PORTBINDING, > + pb->logical_port, > + lflow_handle_changed_ref, > + l_ctx_out->lflows_processed, > l_ctx_in, l_ctx_out, &changed)) { > return false; > } > @@ -2549,7 +2368,11 @@ lflow_handle_changed_port_bindings(struct lflow_ctx_in *l_ctx_in, > && !sbrec_port_binding_is_deleted(pb)) { > continue; > } > - if (!lflow_handle_changed_ref(REF_TYPE_PORTBINDING, pb->logical_port, > + if (!objdep_mgr_handle_change(l_ctx_out->lflow_deps_mgr, > + OBJDEP_TYPE_PORTBINDING, > + pb->logical_port, > + lflow_handle_changed_ref, > + l_ctx_out->lflows_processed, > l_ctx_in, l_ctx_out, &changed)) { > ret = false; > break; > @@ -2573,7 +2396,10 @@ lflow_handle_changed_mc_groups(struct lflow_ctx_in *l_ctx_in, > && !sbrec_multicast_group_is_deleted(mg)) { > continue; > } > - if (!lflow_handle_changed_ref(REF_TYPE_MC_GROUP, ds_cstr(&mg_key), > + if (!objdep_mgr_handle_change(l_ctx_out->lflow_deps_mgr, > + OBJDEP_TYPE_MC_GROUP, ds_cstr(&mg_key), > + lflow_handle_changed_ref, > + l_ctx_out->lflows_processed, > l_ctx_in, l_ctx_out, &changed)) { > ret = false; > break; > diff --git a/controller/lflow.h b/controller/lflow.h > index 8cbe312cac..3f369ebfb6 100644 > --- a/controller/lflow.h > +++ b/controller/lflow.h > @@ -16,6 +16,9 @@ > #ifndef OVN_LFLOW_H > #define OVN_LFLOW_H 1 > > +#include "lib/ovn-util.h" > +#include "lib/objdep.h" > +#include "lib/uuidset.h" > #include "ovn/logical-fields.h" > > /* Logical_Flow table translation to OpenFlow > @@ -80,59 +83,6 @@ struct uuid; > #define OFTABLE_ECMP_NH_MAC 76 > #define OFTABLE_ECMP_NH 77 > > -enum ref_type { > - REF_TYPE_ADDRSET, > - REF_TYPE_PORTGROUP, > - REF_TYPE_PORTBINDING, > - REF_TYPE_MC_GROUP > -}; > - > -struct ref_lflow_node { > - struct hmap_node node; /* node in lflow_resource_ref.ref_lflow_table. */ > - enum ref_type type; /* key */ > - char *ref_name; /* key */ > - struct hmap lflow_uuids; /* Contains lflow_ref_list_node. Use hmap instead > - of list so that lflow_resource_add() can check > - and avoid adding redundant entires in O(1). */ > -}; > - > -struct lflow_ref_node { > - struct hmap_node node; /* node in lflow_resource_ref.lflow_ref_table. */ > - struct uuid lflow_uuid; /* key */ > - struct ovs_list lflow_ref_head; /* Contains lflow_ref_list_node. */ > -}; > - > -/* Maintains the relationship for a pair of named resource and > - * a lflow, indexed by both ref_lflow_table and lflow_ref_table. */ > -struct lflow_ref_list_node { > - struct ovs_list list_node; /* node in lflow_ref_node.lflow_ref_head. */ > - struct hmap_node hmap_node; /* node in ref_lflow_node.lflow_uuids. */ > - struct uuid lflow_uuid; > - size_t ref_count; /* Reference count of the resource by this lflow. > - Currently used for the resource type REF_TYPE_ADDRSET > - only, and for other types it is always 0. */ > - struct ref_lflow_node *rlfn; > -}; > - > -struct lflow_resource_ref { > - /* A map from a referenced resource type & name (e.g. address_set AS1) > - * to a list of lflows that are referencing the named resource. Data > - * type of each node in this hmap is struct ref_lflow_node. The > - * ref_lflow_head in each node points to a list of > - * lflow_ref_list_node.ref_list. */ > - struct hmap ref_lflow_table; > - > - /* A map from a lflow uuid to a list of named resources that are > - * referenced by the lflow. Data type of each node in this hmap is > - * struct lflow_ref_node. The lflow_ref_head in each node points to > - * a list of lflow_ref_list_node.lflow_list. */ > - struct hmap lflow_ref_table; > -}; > - > -void lflow_resource_init(struct lflow_resource_ref *); > -void lflow_resource_destroy(struct lflow_resource_ref *); > -void lflow_resource_clear(struct lflow_resource_ref *); > - > struct lflow_ctx_in { > struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath; > struct ovsdb_idl_index *sbrec_logical_flow_by_logical_datapath; > @@ -169,7 +119,7 @@ struct lflow_ctx_out { > struct ovn_desired_flow_table *flow_table; > struct ovn_extend_table *group_table; > struct ovn_extend_table *meter_table; > - struct lflow_resource_ref *lfrr; > + struct objdep_mgr *lflow_deps_mgr; > struct lflow_cache *lflow_cache; > struct conj_ids *conj_ids; > struct uuidset *lflows_processed; > @@ -181,10 +131,8 @@ void lflow_init(void); > void lflow_run(struct lflow_ctx_in *, struct lflow_ctx_out *); > void lflow_handle_cached_flows(struct lflow_cache *, > const struct sbrec_logical_flow_table *); > -bool lflow_handle_changed_flows(struct lflow_ctx_in *, struct lflow_ctx_out *); > -bool lflow_handle_changed_ref(enum ref_type, const char *ref_name, > - struct lflow_ctx_in *, struct lflow_ctx_out *, > - bool *changed); > +bool lflow_handle_changed_flows(struct lflow_ctx_in *, > + struct lflow_ctx_out *); > > struct addr_set_diff { > struct expr_constant_set *added; > @@ -194,6 +142,9 @@ bool lflow_handle_addr_set_update(const char *as_name, struct addr_set_diff *, > struct lflow_ctx_in *, > struct lflow_ctx_out *, > bool *changed); > +bool lflow_handle_changed_ref(enum objdep_type, const char *res_name, > + struct ovs_list *objs_todo, > + const void *in_arg, void *out_arg); > > void lflow_handle_changed_mac_bindings( > struct ovsdb_idl_index *sbrec_port_binding_by_name, > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > index 8895c7a2bd..f62303e3cb 100644 > --- a/controller/ovn-controller.c > +++ b/controller/ovn-controller.c > @@ -2578,8 +2578,8 @@ struct ed_type_lflow_output { > struct ovn_extend_table group_table; > /* meter ids for QoS */ > struct ovn_extend_table meter_table; > - /* lflow resource cross reference */ > - struct lflow_resource_ref lflow_resource_ref; > + /* lflow <-> resource cross reference */ > + struct objdep_mgr lflow_deps_mgr;; > /* conjunciton ID usage information of lflows */ > struct conj_ids conj_ids; > > @@ -2738,7 +2738,7 @@ init_lflow_ctx(struct engine_node *node, > l_ctx_out->flow_table = &fo->flow_table; > l_ctx_out->group_table = &fo->group_table; > l_ctx_out->meter_table = &fo->meter_table; > - l_ctx_out->lfrr = &fo->lflow_resource_ref; > + l_ctx_out->lflow_deps_mgr = &fo->lflow_deps_mgr; > l_ctx_out->conj_ids = &fo->conj_ids; > l_ctx_out->lflows_processed = &fo->lflows_processed; > l_ctx_out->lflow_cache = fo->pd.lflow_cache; > @@ -2754,7 +2754,7 @@ en_lflow_output_init(struct engine_node *node OVS_UNUSED, > ovn_desired_flow_table_init(&data->flow_table); > ovn_extend_table_init(&data->group_table); > ovn_extend_table_init(&data->meter_table); > - lflow_resource_init(&data->lflow_resource_ref); > + objdep_mgr_init(&data->lflow_deps_mgr); > lflow_conj_ids_init(&data->conj_ids); > uuidset_init(&data->lflows_processed); > simap_init(&data->hd.ids); > @@ -2778,7 +2778,7 @@ en_lflow_output_cleanup(void *data) > ovn_desired_flow_table_destroy(&flow_output_data->flow_table); > ovn_extend_table_destroy(&flow_output_data->group_table); > ovn_extend_table_destroy(&flow_output_data->meter_table); > - lflow_resource_destroy(&flow_output_data->lflow_resource_ref); > + objdep_mgr_destroy(&flow_output_data->lflow_deps_mgr); > lflow_conj_ids_destroy(&flow_output_data->conj_ids); > uuidset_destroy(&flow_output_data->lflows_processed); > lflow_cache_destroy(flow_output_data->pd.lflow_cache); > @@ -2814,7 +2814,7 @@ en_lflow_output_run(struct engine_node *node, void *data) > struct ovn_desired_flow_table *lflow_table = &fo->flow_table; > struct ovn_extend_table *group_table = &fo->group_table; > struct ovn_extend_table *meter_table = &fo->meter_table; > - struct lflow_resource_ref *lfrr = &fo->lflow_resource_ref; > + struct objdep_mgr *lflow_deps_mgr = &fo->lflow_deps_mgr; > > static bool first_run = true; > if (first_run) { > @@ -2823,7 +2823,7 @@ en_lflow_output_run(struct engine_node *node, void *data) > ovn_desired_flow_table_clear(lflow_table); > ovn_extend_table_clear(group_table, false /* desired */); > ovn_extend_table_clear(meter_table, false /* desired */); > - lflow_resource_clear(lfrr); > + objdep_mgr_clear(lflow_deps_mgr); > lflow_conj_ids_clear(&fo->conj_ids); > } > > @@ -2954,8 +2954,11 @@ lflow_output_addr_sets_handler(struct engine_node *node, void *data) > } > > SSET_FOR_EACH (ref_name, &as_data->deleted) { > - if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, ref_name, &l_ctx_in, > - &l_ctx_out, &changed)) { > + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, > + OBJDEP_TYPE_ADDRSET, ref_name, > + lflow_handle_changed_ref, > + l_ctx_out.lflows_processed, > + &l_ctx_in, &l_ctx_out, &changed)) { > return false; > } > if (changed) { > @@ -2969,7 +2972,11 @@ lflow_output_addr_sets_handler(struct engine_node *node, void *data) > &l_ctx_out, &changed)) { > VLOG_DBG("Can't incrementally handle the change of address set %s." > " Reprocess related lflows.", shash_node->name); > - if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, shash_node->name, > + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, > + OBJDEP_TYPE_ADDRSET, > + shash_node->name, > + lflow_handle_changed_ref, > + l_ctx_out.lflows_processed, > &l_ctx_in, &l_ctx_out, &changed)) { > return false; > } > @@ -2979,8 +2986,11 @@ lflow_output_addr_sets_handler(struct engine_node *node, void *data) > } > } > SSET_FOR_EACH (ref_name, &as_data->new) { > - if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, ref_name, &l_ctx_in, > - &l_ctx_out, &changed)) { > + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, > + OBJDEP_TYPE_ADDRSET, ref_name, > + lflow_handle_changed_ref, > + l_ctx_out.lflows_processed, > + &l_ctx_in, &l_ctx_out, &changed)) { > return false; > } > if (changed) { > @@ -3011,8 +3021,11 @@ lflow_output_port_groups_handler(struct engine_node *node, void *data) > } > > SSET_FOR_EACH (ref_name, &pg_data->deleted) { > - if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, > - &l_ctx_out, &changed)) { > + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, > + OBJDEP_TYPE_PORTGROUP, ref_name, > + lflow_handle_changed_ref, > + l_ctx_out.lflows_processed, > + &l_ctx_in, &l_ctx_out, &changed)) { > return false; > } > if (changed) { > @@ -3020,8 +3033,11 @@ lflow_output_port_groups_handler(struct engine_node *node, void *data) > } > } > SSET_FOR_EACH (ref_name, &pg_data->updated) { > - if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, > - &l_ctx_out, &changed)) { > + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, > + OBJDEP_TYPE_PORTGROUP, ref_name, > + lflow_handle_changed_ref, > + l_ctx_out.lflows_processed, > + &l_ctx_in, &l_ctx_out, &changed)) { > return false; > } > if (changed) { > @@ -3029,8 +3045,11 @@ lflow_output_port_groups_handler(struct engine_node *node, void *data) > } > } > SSET_FOR_EACH (ref_name, &pg_data->new) { > - if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, > - &l_ctx_out, &changed)) { > + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, > + OBJDEP_TYPE_PORTGROUP, ref_name, > + lflow_handle_changed_ref, > + l_ctx_out.lflows_processed, > + &l_ctx_in, &l_ctx_out, &changed)) { > return false; > } > if (changed) { > diff --git a/lib/automake.mk b/lib/automake.mk > index 60bead6a6a..15d4f84bbb 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -31,6 +31,8 @@ lib_libovn_la_SOURCES = \ > lib/mcast-group-index.c \ > lib/mcast-group-index.h \ > lib/lex.c \ > + lib/objdep.c \ > + lib/objdep.h \ > lib/ovn-l7.h \ > lib/ovn-l7.c \ > lib/ovn-util.c \ > diff --git a/lib/objdep.c b/lib/objdep.c > new file mode 100644 > index 0000000000..092d4af261 > --- /dev/null > +++ b/lib/objdep.c > @@ -0,0 +1,260 @@ > +/* Copyright (c) 2015, 2016, 2017 Nicira, Inc. > + * Copyright (c) 2022, Red Hat, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > + > +#include "lib/objdep.h" > +#include "lib/hash.h" > +#include "lib/util.h" > +#include "openvswitch/vlog.h" > + > +VLOG_DEFINE_THIS_MODULE(resource_dep); > + > +static void resource_node_destroy(struct resource_to_objects_node *); > + > +void > +objdep_mgr_init(struct objdep_mgr *mgr) > +{ > + hmap_init(&mgr->resource_to_objects_table); > + hmap_init(&mgr->object_to_resources_table); > +} > + > +void > +objdep_mgr_destroy(struct objdep_mgr *mgr) > +{ > + objdep_mgr_clear(mgr); > + > + hmap_destroy(&mgr->resource_to_objects_table); > + hmap_destroy(&mgr->object_to_resources_table); > +} > + > +void > +objdep_mgr_clear(struct objdep_mgr *mgr) > +{ > + struct resource_to_objects_node *resource_node; > + HMAP_FOR_EACH_SAFE (resource_node, node, &mgr->resource_to_objects_table) { > + struct object_to_resources_list_node *object_list_node; > + HMAP_FOR_EACH_SAFE (object_list_node, hmap_node, > + &resource_node->objs) { > + ovs_list_remove(&object_list_node->list_node); > + hmap_remove(&resource_node->objs, &object_list_node->hmap_node); > + free(object_list_node); > + } > + hmap_remove(&mgr->resource_to_objects_table, &resource_node->node); > + resource_node_destroy(resource_node); > + } > + > + struct object_to_resources_node *object_node; > + HMAP_FOR_EACH_SAFE (object_node, node, &mgr->object_to_resources_table) { > + hmap_remove(&mgr->object_to_resources_table, &object_node->node); > + free(object_node); > + } > +} > + > +void > +objdep_mgr_add(struct objdep_mgr *mgr, enum objdep_type type, > + const char *res_name, const struct uuid *obj_uuid) > +{ > + objdep_mgr_add_with_refcount(mgr, type, res_name, obj_uuid, 0); > +} > + > +void > +objdep_mgr_add_with_refcount(struct objdep_mgr *mgr, enum objdep_type type, > + const char *res_name, const struct uuid *obj_uuid, > + size_t ref_count) > +{ > + struct resource_to_objects_node *resource_node = > + objdep_mgr_find_objs(mgr, type, res_name); > + struct object_to_resources_node *object_node = > + objdep_mgr_find_resources(mgr, obj_uuid); > + if (resource_node && object_node) { > + /* Check if the mapping already existed before adding a new one. */ > + struct object_to_resources_list_node *n; > + HMAP_FOR_EACH_WITH_HASH (n, hmap_node, uuid_hash(obj_uuid), > + &resource_node->objs) { > + if (uuid_equals(&n->obj_uuid, obj_uuid)) { > + return; > + } > + } > + } > + > + /* Create the resource node if we didn't have one already (for a > + * different object). */ > + if (!resource_node) { > + resource_node = xzalloc(sizeof *resource_node); > + resource_node->node.hash = hash_string(res_name, type); > + resource_node->type = type; > + resource_node->res_name = xstrdup(res_name); > + hmap_init(&resource_node->objs); > + hmap_insert(&mgr->resource_to_objects_table, > + &resource_node->node, > + resource_node->node.hash); > + } > + > + /* Create the object node if we didn't have one already (for a > + * different resource). */ > + if (!object_node) { > + object_node = xzalloc(sizeof *object_node); > + object_node->node.hash = uuid_hash(obj_uuid); > + object_node->obj_uuid = *obj_uuid; > + ovs_list_init(&object_node->resources_head); > + hmap_insert(&mgr->object_to_resources_table, > + &object_node->node, > + object_node->node.hash); > + } > + > + struct object_to_resources_list_node *resource_list_node = > + xzalloc(sizeof *resource_list_node); > + resource_list_node->obj_uuid = *obj_uuid; > + resource_list_node->ref_count = ref_count; > + resource_list_node->resource_node = resource_node; > + hmap_insert(&resource_node->objs, &resource_list_node->hmap_node, > + uuid_hash(obj_uuid)); > + ovs_list_push_back(&object_node->resources_head, > + &resource_list_node->list_node); > +} > + > +void > +objdep_mgr_remove_obj(struct objdep_mgr *mgr, const struct uuid *obj_uuid) > +{ > + struct object_to_resources_node *object_node = > + objdep_mgr_find_resources(mgr, obj_uuid); > + if (!object_node) { > + return; > + } > + > + hmap_remove(&mgr->object_to_resources_table, &object_node->node); > + > + struct object_to_resources_list_node *resource_list_node; > + LIST_FOR_EACH_SAFE (resource_list_node, list_node, > + &object_node->resources_head) { > + struct resource_to_objects_node *resource_node = > + resource_list_node->resource_node; > + ovs_list_remove(&resource_list_node->list_node); > + hmap_remove(&resource_node->objs, &resource_list_node->hmap_node); > + > + /* Clean up the node in ref_obj_table if the resource is not > + * referred by any logical flows. */ > + if (hmap_is_empty(&resource_node->objs)) { > + hmap_remove(&mgr->resource_to_objects_table, &resource_node->node); > + resource_node_destroy(resource_list_node->resource_node); > + } > + > + free(resource_list_node); > + } > + free(object_node); > +} > + > +struct resource_to_objects_node * > +objdep_mgr_find_objs(struct objdep_mgr *mgr, enum objdep_type type, > + const char *res_name) > +{ > + struct resource_to_objects_node *resource_node; > + > + HMAP_FOR_EACH_WITH_HASH (resource_node, node, hash_string(res_name, type), > + &mgr->resource_to_objects_table) { > + if (resource_node->type == type && > + !strcmp(resource_node->res_name, res_name)) { > + return resource_node; > + } > + } > + return NULL; > +} > + > +struct object_to_resources_node * > +objdep_mgr_find_resources(struct objdep_mgr *mgr, > + const struct uuid *obj_uuid) > +{ > + struct object_to_resources_node *object_node; > + > + HMAP_FOR_EACH_WITH_HASH (object_node, node, uuid_hash(obj_uuid), > + &mgr->object_to_resources_table) { > + if (uuid_equals(&object_node->obj_uuid, obj_uuid)) { > + return object_node; > + } > + } > + return NULL; > +} > + > +bool > +objdep_mgr_contains_obj(struct objdep_mgr *mgr, const struct uuid *obj_uuid) > +{ > + return !!objdep_mgr_find_resources(mgr, obj_uuid); > +} > + > +bool > +objdep_mgr_handle_change(struct objdep_mgr *mgr, > + enum objdep_type type, > + const char *res_name, > + objdep_change_handler handler, > + struct uuidset *objs_processed, > + const void *in_arg, void *out_arg, > + bool *changed) > +{ > + struct resource_to_objects_node *resource_node = > + objdep_mgr_find_objs(mgr, type, res_name); > + if (!resource_node) { > + *changed = false; > + return true; > + } > + VLOG_DBG("Handle changed object reference for resource type: %s," > + " name: %s.", objdep_type_name(type), res_name); > + *changed = false; > + > + struct ovs_list objs_todo = OVS_LIST_INITIALIZER(&objs_todo); > + > + struct object_to_resources_list_node *resource_list_node; > + HMAP_FOR_EACH (resource_list_node, hmap_node, &resource_node->objs) { > + if (uuidset_find(objs_processed, &resource_list_node->obj_uuid)) { > + continue; > + } > + /* Use object_to_resources_list_node as list node to store the uuid. > + * Other fields are not used here. */ > + struct object_to_resources_list_node *resource_list_node_uuid = > + xmalloc(sizeof *resource_list_node_uuid); > + resource_list_node_uuid->obj_uuid = resource_list_node->obj_uuid; > + ovs_list_push_back(&objs_todo, &resource_list_node_uuid->list_node); > + } > + if (ovs_list_is_empty(&objs_todo)) { > + return true; > + } > + *changed = true; > + > + /* This takes ownership of objs_todo. */ > + return handler(type, res_name, &objs_todo, in_arg, out_arg); > +} > + > +const char * > +objdep_type_name(enum objdep_type type) > +{ > + static const char *type_names[OBJDEP_TYPE_MAX] = { > + [OBJDEP_TYPE_ADDRSET] = "Address_Set", > + [OBJDEP_TYPE_PORTGROUP] = "Port_Group", > + [OBJDEP_TYPE_PORTBINDING] = "Port_Binding", > + [OBJDEP_TYPE_MC_GROUP] = "Multicast_Group", > + }; > + > + ovs_assert(type < OBJDEP_TYPE_MAX); > + return type_names[type]; > +} > + > +static void > +resource_node_destroy(struct resource_to_objects_node *resource_node) > +{ > + free(resource_node->res_name); > + hmap_destroy(&resource_node->objs); > + free(resource_node); > +} > diff --git a/lib/objdep.h b/lib/objdep.h > new file mode 100644 > index 0000000000..50c7b01ef1 > --- /dev/null > +++ b/lib/objdep.h > @@ -0,0 +1,122 @@ > +/* Copyright (c) 2015, 2016, 2017 Nicira, Inc. > + * Copyright (c) 2022, Red Hat, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#ifndef OVN_OBJDEP_H > +#define OVN_OBJDEP_H 1 > + > +#include "lib/uuidset.h" > +#include "openvswitch/hmap.h" > +#include "openvswitch/list.h" > + > +enum objdep_type { > + OBJDEP_TYPE_ADDRSET, > + OBJDEP_TYPE_PORTGROUP, > + OBJDEP_TYPE_PORTBINDING, > + OBJDEP_TYPE_MC_GROUP, > + OBJDEP_TYPE_MAX, > +}; > + > +/* Callbacks provided by users to process changes to resources referred by > + * various objects. They should return true if the change has been > + * handled successfully. */ > +typedef bool (*objdep_change_handler)(enum objdep_type, > + const char *res_name, > + struct ovs_list *ref_nodes, > + const void *in_arg, void *out_arg); > + > +/* A node pointing to all objects that refer to a given resource. */ > +struct resource_to_objects_node { > + struct hmap_node node; /* node in objdep_mgr.resource_to_objects_table. */ > + enum objdep_type type; /* key */ > + char *res_name; /* key */ > + struct hmap objs; /* Contains object_to_resources_list_node. > + * Use hmap instead of list so > + * that obj_resource_add() can check and avoid > + * and redundant entries in O(1). */ > +}; > + > +#define RESOURCE_FOR_EACH_OBJ(NODE, MAP) \ > + HMAP_FOR_EACH (NODE, hmap_node, &(MAP)->objs) > + > +/* A node pointing to all resources used by a given object (specified by > + * uuid). > + */ > +struct object_to_resources_node { > + struct hmap_node node; /* node in objdep_mgr.object_to_resources_table. */ > + struct uuid obj_uuid; /* key */ > + struct ovs_list resources_head; /* Contains elements of type > + * object_to_resources_list_node. */ > +}; > + > +/* Maintains the relationship for a pair of named resource and > + * an object, indexed by both resource_to_object_table and > + * object_to_resources_table. */ > +struct object_to_resources_list_node { > + /* node in object_to_resources_node.resources_head. */ > + struct ovs_list list_node; > + struct hmap_node hmap_node; /* node in resource_to_objects_node.objs. */ > + struct uuid obj_uuid; > + size_t ref_count; /* Reference count of the resource by this object. > + * Currently only used for the resource type > + * OBJDEP_TYPE_ADDRSET and for other types always > + * set to 0. */ > + struct resource_to_objects_node *resource_node; > +}; > + > +struct objdep_mgr { > + /* A map from a referenced resource type & name (e.g. address_set AS1) > + * to a list of object UUIDs (e.g., lflow) that are referencing the named > + * resource. Data type of each node in this hmap is struct > + * resource_to_objects_node. The objs in each node point > + * to a map of object_to_resources_list_node.ref_list. */ > + struct hmap resource_to_objects_table; > + > + /* A map from a obj uuid to a list of named resources that are > + * referenced by the object. Data type of each node in this hmap is > + * struct object_to_resources_node. The resources_head in each node > + * points to a list of object_to_resources_list_node.obj_list. */ > + struct hmap object_to_resources_table; > +}; > + > +void objdep_mgr_init(struct objdep_mgr *); > +void objdep_mgr_destroy(struct objdep_mgr *); > +void objdep_mgr_clear(struct objdep_mgr *); > + > +void objdep_mgr_add(struct objdep_mgr *, enum objdep_type, > + const char *res_name, const struct uuid *); > +void objdep_mgr_add_with_refcount(struct objdep_mgr *, > + enum objdep_type, > + const char *res_name, > + const struct uuid *, > + size_t ref_count); > +void objdep_mgr_remove_obj(struct objdep_mgr *, const struct uuid *); > + > +struct resource_to_objects_node *objdep_mgr_find_objs( > + struct objdep_mgr *, enum objdep_type, const char *res_name); > +struct object_to_resources_node *objdep_mgr_find_resources( > + struct objdep_mgr *, const struct uuid *); > +bool objdep_mgr_contains_obj(struct objdep_mgr *, const struct uuid *); > + > +bool objdep_mgr_handle_change(struct objdep_mgr *, enum objdep_type, > + const char *res_name, > + objdep_change_handler handler, > + struct uuidset *objs_processed, > + const void *in_arg, void *out_arg, > + bool *changed); > + > +const char *objdep_type_name(enum objdep_type); > + > +#endif /* lib/objdep.h */ >
diff --git a/controller/lflow.c b/controller/lflow.c index cc0f31db06..d4434bdee8 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -61,7 +61,7 @@ struct lookup_port_aux { struct ovsdb_idl_index *sbrec_port_binding_by_name; const struct sbrec_datapath_binding *dp; const struct sbrec_logical_flow *lflow; - struct lflow_resource_ref *lfrr; + struct objdep_mgr *deps_mgr; const struct hmap *chassis_tunnels; }; @@ -72,8 +72,8 @@ struct condition_aux { const struct sset *active_tunnels; const struct sbrec_logical_flow *lflow; /* Resource reference to store the port name referenced - * in is_chassis_resident() to the logical flow. */ - struct lflow_resource_ref *lfrr; + * in is_chassis_resident() to the object (logical flow). */ + struct objdep_mgr *deps_mgr; }; static struct expr * @@ -81,7 +81,7 @@ convert_match_to_expr(const struct sbrec_logical_flow *, const struct local_datapath *ldp, struct expr **prereqs, const struct shash *addr_sets, const struct shash *port_groups, - struct lflow_resource_ref *, bool *pg_addr_set_ref); + struct objdep_mgr *, bool *pg_addr_set_ref); static void add_matches_to_flow_table(const struct sbrec_logical_flow *, const struct local_datapath *, @@ -94,17 +94,6 @@ consider_logical_flow(const struct sbrec_logical_flow *lflow, bool is_recompute, struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out); -static void lflow_resource_add(struct lflow_resource_ref *, enum ref_type, - const char *ref_name, const struct uuid *, - size_t ref_count); -static struct ref_lflow_node *ref_lflow_lookup(struct hmap *ref_lflow_table, - enum ref_type, - const char *ref_name); -static struct lflow_ref_node *lflow_ref_lookup(struct hmap *lflow_ref_table, - const struct uuid *lflow_uuid); -static void ref_lflow_node_destroy(struct ref_lflow_node *); -static void lflow_resource_destroy_lflow(struct lflow_resource_ref *, - const struct uuid *lflow_uuid); static void add_port_sec_flows(const struct shash *binding_lports, const struct sbrec_chassis *, @@ -125,8 +114,8 @@ lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp) /* Store the name that used to lookup the lport to lflow reference, so that * in the future when the lport's port binding changes, the logical flow * that references this lport can be reprocessed. */ - lflow_resource_add(aux->lfrr, REF_TYPE_PORTBINDING, port_name, - &aux->lflow->header_.uuid, 0); + objdep_mgr_add(aux->deps_mgr, OBJDEP_TYPE_PORTBINDING, port_name, + &aux->lflow->header_.uuid); const struct sbrec_port_binding *pb = lport_lookup_by_name(aux->sbrec_port_binding_by_name, port_name); @@ -141,8 +130,8 @@ lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp) * this multicast group can be reprocessed. */ struct ds mg_key = DS_EMPTY_INITIALIZER; get_mc_group_key(port_name, aux->dp->tunnel_key, &mg_key); - lflow_resource_add(aux->lfrr, REF_TYPE_MC_GROUP, ds_cstr(&mg_key), - &aux->lflow->header_.uuid, 0); + objdep_mgr_add(aux->deps_mgr, OBJDEP_TYPE_MC_GROUP, ds_cstr(&mg_key), + &aux->lflow->header_.uuid); ds_destroy(&mg_key); const struct sbrec_multicast_group *mg = mcgroup_lookup_by_dp_name( @@ -180,11 +169,11 @@ is_chassis_resident_cb(const void *c_aux_, const char *port_name) { const struct condition_aux *c_aux = c_aux_; - /* Store the port name that used to lookup the lport to lflow reference, so - * that in the future when the lport's port-binding changes the logical + /* Store the port name that used to lookup the lport to object reference, + * so that in the future when the lport's port-binding changes the logical * flow that references this lport can be reprocessed. */ - lflow_resource_add(c_aux->lfrr, REF_TYPE_PORTBINDING, port_name, - &c_aux->lflow->header_.uuid, 0); + objdep_mgr_add(c_aux->deps_mgr, OBJDEP_TYPE_PORTBINDING, port_name, + &c_aux->lflow->header_.uuid); const struct sbrec_port_binding *pb = lport_lookup_by_name(c_aux->sbrec_port_binding_by_name, port_name); @@ -207,155 +196,6 @@ is_chassis_resident_cb(const void *c_aux_, const char *port_name) } } -void -lflow_resource_init(struct lflow_resource_ref *lfrr) -{ - hmap_init(&lfrr->ref_lflow_table); - hmap_init(&lfrr->lflow_ref_table); -} - -void -lflow_resource_destroy(struct lflow_resource_ref *lfrr) -{ - struct ref_lflow_node *rlfn; - HMAP_FOR_EACH_SAFE (rlfn, node, &lfrr->ref_lflow_table) { - struct lflow_ref_list_node *lrln; - HMAP_FOR_EACH_SAFE (lrln, hmap_node, &rlfn->lflow_uuids) { - ovs_list_remove(&lrln->list_node); - hmap_remove(&rlfn->lflow_uuids, &lrln->hmap_node); - free(lrln); - } - hmap_remove(&lfrr->ref_lflow_table, &rlfn->node); - ref_lflow_node_destroy(rlfn); - } - hmap_destroy(&lfrr->ref_lflow_table); - - struct lflow_ref_node *lfrn; - HMAP_FOR_EACH_SAFE (lfrn, node, &lfrr->lflow_ref_table) { - hmap_remove(&lfrr->lflow_ref_table, &lfrn->node); - free(lfrn); - } - hmap_destroy(&lfrr->lflow_ref_table); -} - -void -lflow_resource_clear(struct lflow_resource_ref *lfrr) -{ - lflow_resource_destroy(lfrr); - lflow_resource_init(lfrr); -} - -static struct ref_lflow_node* -ref_lflow_lookup(struct hmap *ref_lflow_table, - enum ref_type type, const char *ref_name) -{ - struct ref_lflow_node *rlfn; - - HMAP_FOR_EACH_WITH_HASH (rlfn, node, hash_string(ref_name, type), - ref_lflow_table) { - if (rlfn->type == type && !strcmp(rlfn->ref_name, ref_name)) { - return rlfn; - } - } - return NULL; -} - -static struct lflow_ref_node* -lflow_ref_lookup(struct hmap *lflow_ref_table, - const struct uuid *lflow_uuid) -{ - struct lflow_ref_node *lfrn; - - HMAP_FOR_EACH_WITH_HASH (lfrn, node, uuid_hash(lflow_uuid), - lflow_ref_table) { - if (uuid_equals(&lfrn->lflow_uuid, lflow_uuid)) { - return lfrn; - } - } - return NULL; -} - -static void -lflow_resource_add(struct lflow_resource_ref *lfrr, enum ref_type type, - const char *ref_name, const struct uuid *lflow_uuid, - size_t ref_count) -{ - struct ref_lflow_node *rlfn = ref_lflow_lookup(&lfrr->ref_lflow_table, - type, ref_name); - struct lflow_ref_node *lfrn = lflow_ref_lookup(&lfrr->lflow_ref_table, - lflow_uuid); - if (rlfn && lfrn) { - /* Check if the mapping already existed before adding a new one. */ - struct lflow_ref_list_node *n; - HMAP_FOR_EACH_WITH_HASH (n, hmap_node, uuid_hash(lflow_uuid), - &rlfn->lflow_uuids) { - if (uuid_equals(&n->lflow_uuid, lflow_uuid)) { - return; - } - } - } - - if (!rlfn) { - rlfn = xzalloc(sizeof *rlfn); - rlfn->node.hash = hash_string(ref_name, type); - rlfn->type = type; - rlfn->ref_name = xstrdup(ref_name); - hmap_init(&rlfn->lflow_uuids); - hmap_insert(&lfrr->ref_lflow_table, &rlfn->node, rlfn->node.hash); - } - - if (!lfrn) { - lfrn = xzalloc(sizeof *lfrn); - lfrn->node.hash = uuid_hash(lflow_uuid); - lfrn->lflow_uuid = *lflow_uuid; - ovs_list_init(&lfrn->lflow_ref_head); - hmap_insert(&lfrr->lflow_ref_table, &lfrn->node, lfrn->node.hash); - } - - struct lflow_ref_list_node *lrln = xzalloc(sizeof *lrln); - lrln->lflow_uuid = *lflow_uuid; - lrln->ref_count = ref_count; - lrln->rlfn = rlfn; - hmap_insert(&rlfn->lflow_uuids, &lrln->hmap_node, uuid_hash(lflow_uuid)); - ovs_list_push_back(&lfrn->lflow_ref_head, &lrln->list_node); -} - -static void -ref_lflow_node_destroy(struct ref_lflow_node *rlfn) -{ - free(rlfn->ref_name); - hmap_destroy(&rlfn->lflow_uuids); - free(rlfn); -} - -static void -lflow_resource_destroy_lflow(struct lflow_resource_ref *lfrr, - const struct uuid *lflow_uuid) -{ - struct lflow_ref_node *lfrn = lflow_ref_lookup(&lfrr->lflow_ref_table, - lflow_uuid); - if (!lfrn) { - return; - } - - hmap_remove(&lfrr->lflow_ref_table, &lfrn->node); - struct lflow_ref_list_node *lrln; - LIST_FOR_EACH_SAFE (lrln, list_node, &lfrn->lflow_ref_head) { - ovs_list_remove(&lrln->list_node); - hmap_remove(&lrln->rlfn->lflow_uuids, &lrln->hmap_node); - - /* Clean up the node in ref_lflow_table if the resource is not - * referred by any logical flows. */ - if (hmap_is_empty(&lrln->rlfn->lflow_uuids)) { - hmap_remove(&lfrr->ref_lflow_table, &lrln->rlfn->node); - ref_lflow_node_destroy(lrln->rlfn); - } - - free(lrln); - } - free(lfrn); -} - /* Adds the logical flows from the Logical_Flow table to flow tables. */ static void add_logical_flows(struct lflow_ctx_in *l_ctx_in, @@ -400,7 +240,7 @@ lflow_handle_changed_flows(struct lflow_ctx_in *l_ctx_in, struct uuidset_node *ofrn; UUIDSET_FOR_EACH (ofrn, &flood_remove_nodes) { /* Delete entries from lflow resource reference. */ - lflow_resource_destroy_lflow(l_ctx_out->lfrr, &ofrn->uuid); + objdep_mgr_remove_obj(l_ctx_out->lflow_deps_mgr, &ofrn->uuid); /* Delete conj_ids owned by the lflow. */ lflow_conj_ids_free(l_ctx_out->conj_ids, &ofrn->uuid); /* Reprocessing the lflow if the sb record is not deleted. */ @@ -537,7 +377,7 @@ consider_lflow_for_added_as_ips__( .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, .dp = dp, .lflow = lflow, - .lfrr = l_ctx_out->lfrr, + .deps_mgr = l_ctx_out->lflow_deps_mgr, }; struct condition_aux cond_aux = { .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, @@ -545,7 +385,7 @@ consider_lflow_for_added_as_ips__( .chassis = l_ctx_in->chassis, .active_tunnels = l_ctx_in->active_tunnels, .lflow = lflow, - .lfrr = l_ctx_out->lfrr, + .deps_mgr = l_ctx_out->lflow_deps_mgr, }; struct hmap matches = HMAP_INITIALIZER(&matches); @@ -591,7 +431,7 @@ consider_lflow_for_added_as_ips__( struct expr *expr = convert_match_to_expr(lflow, ldp, &prereqs, l_ctx_in->addr_sets, l_ctx_in->port_groups, - l_ctx_out->lfrr, NULL); + l_ctx_out->lflow_deps_mgr, 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); @@ -787,10 +627,10 @@ lflow_handle_addr_set_update(const char *as_name, return false; } - struct ref_lflow_node *rlfn = - ref_lflow_lookup(&l_ctx_out->lfrr->ref_lflow_table, REF_TYPE_ADDRSET, - as_name); - if (!rlfn) { + struct resource_to_objects_node *resource_node = + objdep_mgr_find_objs(l_ctx_out->lflow_deps_mgr, OBJDEP_TYPE_ADDRSET, + as_name); + if (!resource_node) { *changed = false; return true; } @@ -798,22 +638,23 @@ lflow_handle_addr_set_update(const char *as_name, *changed = false; bool ret = true; - struct lflow_ref_list_node *lrln; - HMAP_FOR_EACH (lrln, hmap_node, &rlfn->lflow_uuids) { - if (uuidset_find(l_ctx_out->lflows_processed, &lrln->lflow_uuid)) { + struct object_to_resources_list_node *resource_list_node; + RESOURCE_FOR_EACH_OBJ (resource_list_node, resource_node) { + const struct uuid *obj_uuid = &resource_list_node->obj_uuid; + if (uuidset_find(l_ctx_out->lflows_processed, obj_uuid)) { VLOG_DBG("lflow "UUID_FMT"has been processed, skip.", - UUID_ARGS(&lrln->lflow_uuid)); + UUID_ARGS(obj_uuid)); continue; } const struct sbrec_logical_flow *lflow = sbrec_logical_flow_table_get_for_uuid(l_ctx_in->logical_flow_table, - &lrln->lflow_uuid); + obj_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); + UUID_ARGS(obj_uuid), as_name); continue; } *changed = true; @@ -825,9 +666,9 @@ lflow_handle_addr_set_update(const char *as_name, 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)) { + if (!ofctrl_remove_flows_for_as_ip( + l_ctx_out->flow_table, obj_uuid, &as_info, + resource_list_node->ref_count)) { ret = false; goto done; } @@ -836,7 +677,7 @@ lflow_handle_addr_set_update(const char *as_name, if (as_diff->added) { if (!consider_lflow_for_added_as_ips(lflow, as_name, - lrln->ref_count, + resource_list_node->ref_count, as_diff->added, l_ctx_in, l_ctx_out)) { ret = false; @@ -850,59 +691,32 @@ done: } bool -lflow_handle_changed_ref(enum ref_type ref_type, const char *ref_name, - struct lflow_ctx_in *l_ctx_in, - struct lflow_ctx_out *l_ctx_out, - bool *changed) +lflow_handle_changed_ref(enum objdep_type type, const char *res_name, + struct ovs_list *objs_todo, + const void *in_arg, void *out_arg) { - struct ref_lflow_node *rlfn = - ref_lflow_lookup(&l_ctx_out->lfrr->ref_lflow_table, ref_type, - ref_name); - if (!rlfn) { - *changed = false; - return true; - } - VLOG_DBG("Handle changed lflow reference for resource type: %d," - " name: %s.", ref_type, ref_name); - *changed = false; - bool ret = true; - - struct ovs_list lflows_todo = OVS_LIST_INITIALIZER(&lflows_todo); - - struct lflow_ref_list_node *lrln, *lrln_uuid; - HMAP_FOR_EACH (lrln, hmap_node, &rlfn->lflow_uuids) { - if (uuidset_find(l_ctx_out->lflows_processed, &lrln->lflow_uuid)) { - continue; - } - /* Use lflow_ref_list_node as list node to store the uuid. - * Other fields are not used here. */ - lrln_uuid = xmalloc(sizeof *lrln_uuid); - lrln_uuid->lflow_uuid = lrln->lflow_uuid; - ovs_list_push_back(&lflows_todo, &lrln_uuid->list_node); - } - if (ovs_list_is_empty(&lflows_todo)) { - return true; - } - *changed = true; + struct lflow_ctx_in *l_ctx_in = CONST_CAST(struct lflow_ctx_in *, in_arg); + struct lflow_ctx_out *l_ctx_out = out_arg; /* Re-parse the related lflows. */ /* Firstly, flood remove the flows from desired flow table. */ + struct object_to_resources_list_node *resource_list_node_uuid; struct uuidset flood_remove_nodes = UUIDSET_INITIALIZER(&flood_remove_nodes); - LIST_FOR_EACH_SAFE (lrln_uuid, list_node, &lflows_todo) { - VLOG_DBG("Reprocess lflow "UUID_FMT" for resource type: %d," + LIST_FOR_EACH_SAFE (resource_list_node_uuid, list_node, objs_todo) { + const struct uuid *obj_uuid = &resource_list_node_uuid->obj_uuid; + VLOG_DBG("Reprocess lflow "UUID_FMT" for resource type: %s," " name: %s.", - UUID_ARGS(&lrln_uuid->lflow_uuid), - ref_type, ref_name); - uuidset_insert(&flood_remove_nodes, &lrln_uuid->lflow_uuid); - free(lrln_uuid); + UUID_ARGS(obj_uuid), objdep_type_name(type), res_name); + uuidset_insert(&flood_remove_nodes, obj_uuid); + free(resource_list_node_uuid); } ofctrl_flood_remove_flows(l_ctx_out->flow_table, &flood_remove_nodes); /* Secondly, for each lflow that is actually removed, reprocessing it. */ struct uuidset_node *ofrn; UUIDSET_FOR_EACH (ofrn, &flood_remove_nodes) { - lflow_resource_destroy_lflow(l_ctx_out->lfrr, &ofrn->uuid); + objdep_mgr_remove_obj(l_ctx_out->lflow_deps_mgr, &ofrn->uuid); lflow_conj_ids_free(l_ctx_out->conj_ids, &ofrn->uuid); const struct sbrec_logical_flow *lflow = @@ -910,9 +724,9 @@ lflow_handle_changed_ref(enum ref_type ref_type, const char *ref_name, &ofrn->uuid); if (!lflow) { VLOG_DBG("lflow "UUID_FMT" not found while reprocessing for" - " resource type: %d, name: %s.", + " resource type: %s, name: %s.", UUID_ARGS(&ofrn->uuid), - ref_type, ref_name); + objdep_type_name(type), res_name); continue; } @@ -929,8 +743,7 @@ lflow_handle_changed_ref(enum ref_type ref_type, const char *ref_name, consider_logical_flow(lflow, false, l_ctx_in, l_ctx_out); } uuidset_destroy(&flood_remove_nodes); - - return ret; + return true; } static void @@ -985,7 +798,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, .dp = ldp->datapath, .lflow = lflow, - .lfrr = l_ctx_out->lfrr, + .deps_mgr = l_ctx_out->lflow_deps_mgr, .chassis_tunnels = l_ctx_in->chassis_tunnels, }; @@ -1100,7 +913,7 @@ convert_match_to_expr(const struct sbrec_logical_flow *lflow, struct expr **prereqs, const struct shash *addr_sets, const struct shash *port_groups, - struct lflow_resource_ref *lfrr, + struct objdep_mgr *mgr, bool *pg_addr_set_ref) { struct shash addr_sets_ref = SHASH_INITIALIZER(&addr_sets_ref); @@ -1114,14 +927,15 @@ convert_match_to_expr(const struct sbrec_logical_flow *lflow, &error); struct shash_node *addr_sets_ref_node; SHASH_FOR_EACH (addr_sets_ref_node, &addr_sets_ref) { - lflow_resource_add(lfrr, REF_TYPE_ADDRSET, addr_sets_ref_node->name, - &lflow->header_.uuid, - *(size_t *)addr_sets_ref_node->data); + objdep_mgr_add_with_refcount(mgr, OBJDEP_TYPE_ADDRSET, + addr_sets_ref_node->name, + &lflow->header_.uuid, + *(size_t *) addr_sets_ref_node->data); } const char *port_group_name; SSET_FOR_EACH (port_group_name, &port_groups_ref) { - lflow_resource_add(lfrr, REF_TYPE_PORTGROUP, port_group_name, - &lflow->header_.uuid, 0); + objdep_mgr_add(mgr, OBJDEP_TYPE_PORTGROUP, port_group_name, + &lflow->header_.uuid); } if (pg_addr_set_ref) { @@ -1165,8 +979,8 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, const char *io_port = smap_get(&lflow->tags, "in_out_port"); if (io_port) { - lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_PORTBINDING, io_port, - &lflow->header_.uuid, 0); + objdep_mgr_add(l_ctx_out->lflow_deps_mgr, OBJDEP_TYPE_PORTBINDING, + io_port, &lflow->header_.uuid); const struct sbrec_port_binding *pb = lport_lookup_by_name(l_ctx_in->sbrec_port_binding_by_name, io_port); @@ -1232,7 +1046,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, .dp = dp, .lflow = lflow, - .lfrr = l_ctx_out->lfrr, + .deps_mgr = l_ctx_out->lflow_deps_mgr, }; struct condition_aux cond_aux = { .sbrec_port_binding_by_name = l_ctx_in->sbrec_port_binding_by_name, @@ -1240,7 +1054,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, .chassis = l_ctx_in->chassis, .active_tunnels = l_ctx_in->active_tunnels, .lflow = lflow, - .lfrr = l_ctx_out->lfrr, + .deps_mgr = l_ctx_out->lflow_deps_mgr, }; struct lflow_cache_value *lcv = @@ -1272,7 +1086,8 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, switch (lcv_type) { case LCACHE_T_NONE: expr = convert_match_to_expr(lflow, ldp, &prereqs, l_ctx_in->addr_sets, - l_ctx_in->port_groups, l_ctx_out->lfrr, + l_ctx_in->port_groups, + l_ctx_out->lflow_deps_mgr, &pg_addr_set_ref); if (!expr) { goto done; @@ -1345,8 +1160,8 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, /* Cache new entry if caching is enabled. */ if (lflow_cache_is_enabled(l_ctx_out->lflow_cache)) { if (cached_expr - && !lflow_ref_lookup(&l_ctx_out->lfrr->lflow_ref_table, - &lflow->header_.uuid)) { + && !objdep_mgr_contains_obj(l_ctx_out->lflow_deps_mgr, + &lflow->header_.uuid)) { lflow_cache_add_matches(l_ctx_out->lflow_cache, &lflow->header_.uuid, start_conj_id, n_conjs, matches, matches_size); @@ -2448,7 +2263,7 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, &lflow->header_.uuid)) { continue; } - /* Don't call lflows_processed_add() because here we process the + /* Don't call uuidset_insert() because here we process the * lflow only for one of the DPs in the DP group, which may be * incomplete. */ consider_logical_flow__(lflow, dp, l_ctx_in, l_ctx_out); @@ -2514,7 +2329,11 @@ lflow_handle_flows_for_lport(const struct sbrec_port_binding *pb, { bool changed; - if (!lflow_handle_changed_ref(REF_TYPE_PORTBINDING, pb->logical_port, + if (!objdep_mgr_handle_change(l_ctx_out->lflow_deps_mgr, + OBJDEP_TYPE_PORTBINDING, + pb->logical_port, + lflow_handle_changed_ref, + l_ctx_out->lflows_processed, l_ctx_in, l_ctx_out, &changed)) { return false; } @@ -2549,7 +2368,11 @@ lflow_handle_changed_port_bindings(struct lflow_ctx_in *l_ctx_in, && !sbrec_port_binding_is_deleted(pb)) { continue; } - if (!lflow_handle_changed_ref(REF_TYPE_PORTBINDING, pb->logical_port, + if (!objdep_mgr_handle_change(l_ctx_out->lflow_deps_mgr, + OBJDEP_TYPE_PORTBINDING, + pb->logical_port, + lflow_handle_changed_ref, + l_ctx_out->lflows_processed, l_ctx_in, l_ctx_out, &changed)) { ret = false; break; @@ -2573,7 +2396,10 @@ lflow_handle_changed_mc_groups(struct lflow_ctx_in *l_ctx_in, && !sbrec_multicast_group_is_deleted(mg)) { continue; } - if (!lflow_handle_changed_ref(REF_TYPE_MC_GROUP, ds_cstr(&mg_key), + if (!objdep_mgr_handle_change(l_ctx_out->lflow_deps_mgr, + OBJDEP_TYPE_MC_GROUP, ds_cstr(&mg_key), + lflow_handle_changed_ref, + l_ctx_out->lflows_processed, l_ctx_in, l_ctx_out, &changed)) { ret = false; break; diff --git a/controller/lflow.h b/controller/lflow.h index 8cbe312cac..3f369ebfb6 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -16,6 +16,9 @@ #ifndef OVN_LFLOW_H #define OVN_LFLOW_H 1 +#include "lib/ovn-util.h" +#include "lib/objdep.h" +#include "lib/uuidset.h" #include "ovn/logical-fields.h" /* Logical_Flow table translation to OpenFlow @@ -80,59 +83,6 @@ struct uuid; #define OFTABLE_ECMP_NH_MAC 76 #define OFTABLE_ECMP_NH 77 -enum ref_type { - REF_TYPE_ADDRSET, - REF_TYPE_PORTGROUP, - REF_TYPE_PORTBINDING, - REF_TYPE_MC_GROUP -}; - -struct ref_lflow_node { - struct hmap_node node; /* node in lflow_resource_ref.ref_lflow_table. */ - enum ref_type type; /* key */ - char *ref_name; /* key */ - struct hmap lflow_uuids; /* Contains lflow_ref_list_node. Use hmap instead - of list so that lflow_resource_add() can check - and avoid adding redundant entires in O(1). */ -}; - -struct lflow_ref_node { - struct hmap_node node; /* node in lflow_resource_ref.lflow_ref_table. */ - struct uuid lflow_uuid; /* key */ - struct ovs_list lflow_ref_head; /* Contains lflow_ref_list_node. */ -}; - -/* Maintains the relationship for a pair of named resource and - * a lflow, indexed by both ref_lflow_table and lflow_ref_table. */ -struct lflow_ref_list_node { - struct ovs_list list_node; /* node in lflow_ref_node.lflow_ref_head. */ - struct hmap_node hmap_node; /* node in ref_lflow_node.lflow_uuids. */ - struct uuid lflow_uuid; - size_t ref_count; /* Reference count of the resource by this lflow. - Currently used for the resource type REF_TYPE_ADDRSET - only, and for other types it is always 0. */ - struct ref_lflow_node *rlfn; -}; - -struct lflow_resource_ref { - /* A map from a referenced resource type & name (e.g. address_set AS1) - * to a list of lflows that are referencing the named resource. Data - * type of each node in this hmap is struct ref_lflow_node. The - * ref_lflow_head in each node points to a list of - * lflow_ref_list_node.ref_list. */ - struct hmap ref_lflow_table; - - /* A map from a lflow uuid to a list of named resources that are - * referenced by the lflow. Data type of each node in this hmap is - * struct lflow_ref_node. The lflow_ref_head in each node points to - * a list of lflow_ref_list_node.lflow_list. */ - struct hmap lflow_ref_table; -}; - -void lflow_resource_init(struct lflow_resource_ref *); -void lflow_resource_destroy(struct lflow_resource_ref *); -void lflow_resource_clear(struct lflow_resource_ref *); - struct lflow_ctx_in { struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath; struct ovsdb_idl_index *sbrec_logical_flow_by_logical_datapath; @@ -169,7 +119,7 @@ struct lflow_ctx_out { struct ovn_desired_flow_table *flow_table; struct ovn_extend_table *group_table; struct ovn_extend_table *meter_table; - struct lflow_resource_ref *lfrr; + struct objdep_mgr *lflow_deps_mgr; struct lflow_cache *lflow_cache; struct conj_ids *conj_ids; struct uuidset *lflows_processed; @@ -181,10 +131,8 @@ void lflow_init(void); void lflow_run(struct lflow_ctx_in *, struct lflow_ctx_out *); void lflow_handle_cached_flows(struct lflow_cache *, const struct sbrec_logical_flow_table *); -bool lflow_handle_changed_flows(struct lflow_ctx_in *, struct lflow_ctx_out *); -bool lflow_handle_changed_ref(enum ref_type, const char *ref_name, - struct lflow_ctx_in *, struct lflow_ctx_out *, - bool *changed); +bool lflow_handle_changed_flows(struct lflow_ctx_in *, + struct lflow_ctx_out *); struct addr_set_diff { struct expr_constant_set *added; @@ -194,6 +142,9 @@ bool lflow_handle_addr_set_update(const char *as_name, struct addr_set_diff *, struct lflow_ctx_in *, struct lflow_ctx_out *, bool *changed); +bool lflow_handle_changed_ref(enum objdep_type, const char *res_name, + struct ovs_list *objs_todo, + const void *in_arg, void *out_arg); void lflow_handle_changed_mac_bindings( struct ovsdb_idl_index *sbrec_port_binding_by_name, diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 8895c7a2bd..f62303e3cb 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2578,8 +2578,8 @@ struct ed_type_lflow_output { struct ovn_extend_table group_table; /* meter ids for QoS */ struct ovn_extend_table meter_table; - /* lflow resource cross reference */ - struct lflow_resource_ref lflow_resource_ref; + /* lflow <-> resource cross reference */ + struct objdep_mgr lflow_deps_mgr;; /* conjunciton ID usage information of lflows */ struct conj_ids conj_ids; @@ -2738,7 +2738,7 @@ init_lflow_ctx(struct engine_node *node, l_ctx_out->flow_table = &fo->flow_table; l_ctx_out->group_table = &fo->group_table; l_ctx_out->meter_table = &fo->meter_table; - l_ctx_out->lfrr = &fo->lflow_resource_ref; + l_ctx_out->lflow_deps_mgr = &fo->lflow_deps_mgr; l_ctx_out->conj_ids = &fo->conj_ids; l_ctx_out->lflows_processed = &fo->lflows_processed; l_ctx_out->lflow_cache = fo->pd.lflow_cache; @@ -2754,7 +2754,7 @@ en_lflow_output_init(struct engine_node *node OVS_UNUSED, ovn_desired_flow_table_init(&data->flow_table); ovn_extend_table_init(&data->group_table); ovn_extend_table_init(&data->meter_table); - lflow_resource_init(&data->lflow_resource_ref); + objdep_mgr_init(&data->lflow_deps_mgr); lflow_conj_ids_init(&data->conj_ids); uuidset_init(&data->lflows_processed); simap_init(&data->hd.ids); @@ -2778,7 +2778,7 @@ en_lflow_output_cleanup(void *data) ovn_desired_flow_table_destroy(&flow_output_data->flow_table); ovn_extend_table_destroy(&flow_output_data->group_table); ovn_extend_table_destroy(&flow_output_data->meter_table); - lflow_resource_destroy(&flow_output_data->lflow_resource_ref); + objdep_mgr_destroy(&flow_output_data->lflow_deps_mgr); lflow_conj_ids_destroy(&flow_output_data->conj_ids); uuidset_destroy(&flow_output_data->lflows_processed); lflow_cache_destroy(flow_output_data->pd.lflow_cache); @@ -2814,7 +2814,7 @@ en_lflow_output_run(struct engine_node *node, void *data) struct ovn_desired_flow_table *lflow_table = &fo->flow_table; struct ovn_extend_table *group_table = &fo->group_table; struct ovn_extend_table *meter_table = &fo->meter_table; - struct lflow_resource_ref *lfrr = &fo->lflow_resource_ref; + struct objdep_mgr *lflow_deps_mgr = &fo->lflow_deps_mgr; static bool first_run = true; if (first_run) { @@ -2823,7 +2823,7 @@ en_lflow_output_run(struct engine_node *node, void *data) ovn_desired_flow_table_clear(lflow_table); ovn_extend_table_clear(group_table, false /* desired */); ovn_extend_table_clear(meter_table, false /* desired */); - lflow_resource_clear(lfrr); + objdep_mgr_clear(lflow_deps_mgr); lflow_conj_ids_clear(&fo->conj_ids); } @@ -2954,8 +2954,11 @@ lflow_output_addr_sets_handler(struct engine_node *node, void *data) } SSET_FOR_EACH (ref_name, &as_data->deleted) { - if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, ref_name, &l_ctx_in, - &l_ctx_out, &changed)) { + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, + OBJDEP_TYPE_ADDRSET, ref_name, + lflow_handle_changed_ref, + l_ctx_out.lflows_processed, + &l_ctx_in, &l_ctx_out, &changed)) { return false; } if (changed) { @@ -2969,7 +2972,11 @@ lflow_output_addr_sets_handler(struct engine_node *node, void *data) &l_ctx_out, &changed)) { VLOG_DBG("Can't incrementally handle the change of address set %s." " Reprocess related lflows.", shash_node->name); - if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, shash_node->name, + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, + OBJDEP_TYPE_ADDRSET, + shash_node->name, + lflow_handle_changed_ref, + l_ctx_out.lflows_processed, &l_ctx_in, &l_ctx_out, &changed)) { return false; } @@ -2979,8 +2986,11 @@ lflow_output_addr_sets_handler(struct engine_node *node, void *data) } } SSET_FOR_EACH (ref_name, &as_data->new) { - if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, ref_name, &l_ctx_in, - &l_ctx_out, &changed)) { + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, + OBJDEP_TYPE_ADDRSET, ref_name, + lflow_handle_changed_ref, + l_ctx_out.lflows_processed, + &l_ctx_in, &l_ctx_out, &changed)) { return false; } if (changed) { @@ -3011,8 +3021,11 @@ lflow_output_port_groups_handler(struct engine_node *node, void *data) } SSET_FOR_EACH (ref_name, &pg_data->deleted) { - if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, - &l_ctx_out, &changed)) { + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, + OBJDEP_TYPE_PORTGROUP, ref_name, + lflow_handle_changed_ref, + l_ctx_out.lflows_processed, + &l_ctx_in, &l_ctx_out, &changed)) { return false; } if (changed) { @@ -3020,8 +3033,11 @@ lflow_output_port_groups_handler(struct engine_node *node, void *data) } } SSET_FOR_EACH (ref_name, &pg_data->updated) { - if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, - &l_ctx_out, &changed)) { + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, + OBJDEP_TYPE_PORTGROUP, ref_name, + lflow_handle_changed_ref, + l_ctx_out.lflows_processed, + &l_ctx_in, &l_ctx_out, &changed)) { return false; } if (changed) { @@ -3029,8 +3045,11 @@ lflow_output_port_groups_handler(struct engine_node *node, void *data) } } SSET_FOR_EACH (ref_name, &pg_data->new) { - if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, - &l_ctx_out, &changed)) { + if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, + OBJDEP_TYPE_PORTGROUP, ref_name, + lflow_handle_changed_ref, + l_ctx_out.lflows_processed, + &l_ctx_in, &l_ctx_out, &changed)) { return false; } if (changed) { diff --git a/lib/automake.mk b/lib/automake.mk index 60bead6a6a..15d4f84bbb 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -31,6 +31,8 @@ lib_libovn_la_SOURCES = \ lib/mcast-group-index.c \ lib/mcast-group-index.h \ lib/lex.c \ + lib/objdep.c \ + lib/objdep.h \ lib/ovn-l7.h \ lib/ovn-l7.c \ lib/ovn-util.c \ diff --git a/lib/objdep.c b/lib/objdep.c new file mode 100644 index 0000000000..092d4af261 --- /dev/null +++ b/lib/objdep.c @@ -0,0 +1,260 @@ +/* Copyright (c) 2015, 2016, 2017 Nicira, Inc. + * Copyright (c) 2022, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> + +#include "lib/objdep.h" +#include "lib/hash.h" +#include "lib/util.h" +#include "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(resource_dep); + +static void resource_node_destroy(struct resource_to_objects_node *); + +void +objdep_mgr_init(struct objdep_mgr *mgr) +{ + hmap_init(&mgr->resource_to_objects_table); + hmap_init(&mgr->object_to_resources_table); +} + +void +objdep_mgr_destroy(struct objdep_mgr *mgr) +{ + objdep_mgr_clear(mgr); + + hmap_destroy(&mgr->resource_to_objects_table); + hmap_destroy(&mgr->object_to_resources_table); +} + +void +objdep_mgr_clear(struct objdep_mgr *mgr) +{ + struct resource_to_objects_node *resource_node; + HMAP_FOR_EACH_SAFE (resource_node, node, &mgr->resource_to_objects_table) { + struct object_to_resources_list_node *object_list_node; + HMAP_FOR_EACH_SAFE (object_list_node, hmap_node, + &resource_node->objs) { + ovs_list_remove(&object_list_node->list_node); + hmap_remove(&resource_node->objs, &object_list_node->hmap_node); + free(object_list_node); + } + hmap_remove(&mgr->resource_to_objects_table, &resource_node->node); + resource_node_destroy(resource_node); + } + + struct object_to_resources_node *object_node; + HMAP_FOR_EACH_SAFE (object_node, node, &mgr->object_to_resources_table) { + hmap_remove(&mgr->object_to_resources_table, &object_node->node); + free(object_node); + } +} + +void +objdep_mgr_add(struct objdep_mgr *mgr, enum objdep_type type, + const char *res_name, const struct uuid *obj_uuid) +{ + objdep_mgr_add_with_refcount(mgr, type, res_name, obj_uuid, 0); +} + +void +objdep_mgr_add_with_refcount(struct objdep_mgr *mgr, enum objdep_type type, + const char *res_name, const struct uuid *obj_uuid, + size_t ref_count) +{ + struct resource_to_objects_node *resource_node = + objdep_mgr_find_objs(mgr, type, res_name); + struct object_to_resources_node *object_node = + objdep_mgr_find_resources(mgr, obj_uuid); + if (resource_node && object_node) { + /* Check if the mapping already existed before adding a new one. */ + struct object_to_resources_list_node *n; + HMAP_FOR_EACH_WITH_HASH (n, hmap_node, uuid_hash(obj_uuid), + &resource_node->objs) { + if (uuid_equals(&n->obj_uuid, obj_uuid)) { + return; + } + } + } + + /* Create the resource node if we didn't have one already (for a + * different object). */ + if (!resource_node) { + resource_node = xzalloc(sizeof *resource_node); + resource_node->node.hash = hash_string(res_name, type); + resource_node->type = type; + resource_node->res_name = xstrdup(res_name); + hmap_init(&resource_node->objs); + hmap_insert(&mgr->resource_to_objects_table, + &resource_node->node, + resource_node->node.hash); + } + + /* Create the object node if we didn't have one already (for a + * different resource). */ + if (!object_node) { + object_node = xzalloc(sizeof *object_node); + object_node->node.hash = uuid_hash(obj_uuid); + object_node->obj_uuid = *obj_uuid; + ovs_list_init(&object_node->resources_head); + hmap_insert(&mgr->object_to_resources_table, + &object_node->node, + object_node->node.hash); + } + + struct object_to_resources_list_node *resource_list_node = + xzalloc(sizeof *resource_list_node); + resource_list_node->obj_uuid = *obj_uuid; + resource_list_node->ref_count = ref_count; + resource_list_node->resource_node = resource_node; + hmap_insert(&resource_node->objs, &resource_list_node->hmap_node, + uuid_hash(obj_uuid)); + ovs_list_push_back(&object_node->resources_head, + &resource_list_node->list_node); +} + +void +objdep_mgr_remove_obj(struct objdep_mgr *mgr, const struct uuid *obj_uuid) +{ + struct object_to_resources_node *object_node = + objdep_mgr_find_resources(mgr, obj_uuid); + if (!object_node) { + return; + } + + hmap_remove(&mgr->object_to_resources_table, &object_node->node); + + struct object_to_resources_list_node *resource_list_node; + LIST_FOR_EACH_SAFE (resource_list_node, list_node, + &object_node->resources_head) { + struct resource_to_objects_node *resource_node = + resource_list_node->resource_node; + ovs_list_remove(&resource_list_node->list_node); + hmap_remove(&resource_node->objs, &resource_list_node->hmap_node); + + /* Clean up the node in ref_obj_table if the resource is not + * referred by any logical flows. */ + if (hmap_is_empty(&resource_node->objs)) { + hmap_remove(&mgr->resource_to_objects_table, &resource_node->node); + resource_node_destroy(resource_list_node->resource_node); + } + + free(resource_list_node); + } + free(object_node); +} + +struct resource_to_objects_node * +objdep_mgr_find_objs(struct objdep_mgr *mgr, enum objdep_type type, + const char *res_name) +{ + struct resource_to_objects_node *resource_node; + + HMAP_FOR_EACH_WITH_HASH (resource_node, node, hash_string(res_name, type), + &mgr->resource_to_objects_table) { + if (resource_node->type == type && + !strcmp(resource_node->res_name, res_name)) { + return resource_node; + } + } + return NULL; +} + +struct object_to_resources_node * +objdep_mgr_find_resources(struct objdep_mgr *mgr, + const struct uuid *obj_uuid) +{ + struct object_to_resources_node *object_node; + + HMAP_FOR_EACH_WITH_HASH (object_node, node, uuid_hash(obj_uuid), + &mgr->object_to_resources_table) { + if (uuid_equals(&object_node->obj_uuid, obj_uuid)) { + return object_node; + } + } + return NULL; +} + +bool +objdep_mgr_contains_obj(struct objdep_mgr *mgr, const struct uuid *obj_uuid) +{ + return !!objdep_mgr_find_resources(mgr, obj_uuid); +} + +bool +objdep_mgr_handle_change(struct objdep_mgr *mgr, + enum objdep_type type, + const char *res_name, + objdep_change_handler handler, + struct uuidset *objs_processed, + const void *in_arg, void *out_arg, + bool *changed) +{ + struct resource_to_objects_node *resource_node = + objdep_mgr_find_objs(mgr, type, res_name); + if (!resource_node) { + *changed = false; + return true; + } + VLOG_DBG("Handle changed object reference for resource type: %s," + " name: %s.", objdep_type_name(type), res_name); + *changed = false; + + struct ovs_list objs_todo = OVS_LIST_INITIALIZER(&objs_todo); + + struct object_to_resources_list_node *resource_list_node; + HMAP_FOR_EACH (resource_list_node, hmap_node, &resource_node->objs) { + if (uuidset_find(objs_processed, &resource_list_node->obj_uuid)) { + continue; + } + /* Use object_to_resources_list_node as list node to store the uuid. + * Other fields are not used here. */ + struct object_to_resources_list_node *resource_list_node_uuid = + xmalloc(sizeof *resource_list_node_uuid); + resource_list_node_uuid->obj_uuid = resource_list_node->obj_uuid; + ovs_list_push_back(&objs_todo, &resource_list_node_uuid->list_node); + } + if (ovs_list_is_empty(&objs_todo)) { + return true; + } + *changed = true; + + /* This takes ownership of objs_todo. */ + return handler(type, res_name, &objs_todo, in_arg, out_arg); +} + +const char * +objdep_type_name(enum objdep_type type) +{ + static const char *type_names[OBJDEP_TYPE_MAX] = { + [OBJDEP_TYPE_ADDRSET] = "Address_Set", + [OBJDEP_TYPE_PORTGROUP] = "Port_Group", + [OBJDEP_TYPE_PORTBINDING] = "Port_Binding", + [OBJDEP_TYPE_MC_GROUP] = "Multicast_Group", + }; + + ovs_assert(type < OBJDEP_TYPE_MAX); + return type_names[type]; +} + +static void +resource_node_destroy(struct resource_to_objects_node *resource_node) +{ + free(resource_node->res_name); + hmap_destroy(&resource_node->objs); + free(resource_node); +} diff --git a/lib/objdep.h b/lib/objdep.h new file mode 100644 index 0000000000..50c7b01ef1 --- /dev/null +++ b/lib/objdep.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2015, 2016, 2017 Nicira, Inc. + * Copyright (c) 2022, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVN_OBJDEP_H +#define OVN_OBJDEP_H 1 + +#include "lib/uuidset.h" +#include "openvswitch/hmap.h" +#include "openvswitch/list.h" + +enum objdep_type { + OBJDEP_TYPE_ADDRSET, + OBJDEP_TYPE_PORTGROUP, + OBJDEP_TYPE_PORTBINDING, + OBJDEP_TYPE_MC_GROUP, + OBJDEP_TYPE_MAX, +}; + +/* Callbacks provided by users to process changes to resources referred by + * various objects. They should return true if the change has been + * handled successfully. */ +typedef bool (*objdep_change_handler)(enum objdep_type, + const char *res_name, + struct ovs_list *ref_nodes, + const void *in_arg, void *out_arg); + +/* A node pointing to all objects that refer to a given resource. */ +struct resource_to_objects_node { + struct hmap_node node; /* node in objdep_mgr.resource_to_objects_table. */ + enum objdep_type type; /* key */ + char *res_name; /* key */ + struct hmap objs; /* Contains object_to_resources_list_node. + * Use hmap instead of list so + * that obj_resource_add() can check and avoid + * and redundant entries in O(1). */ +}; + +#define RESOURCE_FOR_EACH_OBJ(NODE, MAP) \ + HMAP_FOR_EACH (NODE, hmap_node, &(MAP)->objs) + +/* A node pointing to all resources used by a given object (specified by + * uuid). + */ +struct object_to_resources_node { + struct hmap_node node; /* node in objdep_mgr.object_to_resources_table. */ + struct uuid obj_uuid; /* key */ + struct ovs_list resources_head; /* Contains elements of type + * object_to_resources_list_node. */ +}; + +/* Maintains the relationship for a pair of named resource and + * an object, indexed by both resource_to_object_table and + * object_to_resources_table. */ +struct object_to_resources_list_node { + /* node in object_to_resources_node.resources_head. */ + struct ovs_list list_node; + struct hmap_node hmap_node; /* node in resource_to_objects_node.objs. */ + struct uuid obj_uuid; + size_t ref_count; /* Reference count of the resource by this object. + * Currently only used for the resource type + * OBJDEP_TYPE_ADDRSET and for other types always + * set to 0. */ + struct resource_to_objects_node *resource_node; +}; + +struct objdep_mgr { + /* A map from a referenced resource type & name (e.g. address_set AS1) + * to a list of object UUIDs (e.g., lflow) that are referencing the named + * resource. Data type of each node in this hmap is struct + * resource_to_objects_node. The objs in each node point + * to a map of object_to_resources_list_node.ref_list. */ + struct hmap resource_to_objects_table; + + /* A map from a obj uuid to a list of named resources that are + * referenced by the object. Data type of each node in this hmap is + * struct object_to_resources_node. The resources_head in each node + * points to a list of object_to_resources_list_node.obj_list. */ + struct hmap object_to_resources_table; +}; + +void objdep_mgr_init(struct objdep_mgr *); +void objdep_mgr_destroy(struct objdep_mgr *); +void objdep_mgr_clear(struct objdep_mgr *); + +void objdep_mgr_add(struct objdep_mgr *, enum objdep_type, + const char *res_name, const struct uuid *); +void objdep_mgr_add_with_refcount(struct objdep_mgr *, + enum objdep_type, + const char *res_name, + const struct uuid *, + size_t ref_count); +void objdep_mgr_remove_obj(struct objdep_mgr *, const struct uuid *); + +struct resource_to_objects_node *objdep_mgr_find_objs( + struct objdep_mgr *, enum objdep_type, const char *res_name); +struct object_to_resources_node *objdep_mgr_find_resources( + struct objdep_mgr *, const struct uuid *); +bool objdep_mgr_contains_obj(struct objdep_mgr *, const struct uuid *); + +bool objdep_mgr_handle_change(struct objdep_mgr *, enum objdep_type, + const char *res_name, + objdep_change_handler handler, + struct uuidset *objs_processed, + const void *in_arg, void *out_arg, + bool *changed); + +const char *objdep_type_name(enum objdep_type); + +#endif /* lib/objdep.h */