On 10/5/22 07:20, Han Zhou wrote:
> On Fri, Sep 30, 2022 at 7:01 AM Dumitru Ceara <[email protected]> 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.
>>
>> Signed-off-by: Dumitru Ceara <[email protected]>
>> ---
>>  controller/lflow.c          |  336
> ++++++++++---------------------------------
>>  controller/lflow.h          |   67 +--------
>>  controller/ovn-controller.c |   55 +++++--
>>  lib/automake.mk             |    2
>>  lib/objdep.c                |  261 +++++++++++++++++++++++++++++++++
>>  lib/objdep.h                |  121 +++++++++++++++
>>  6 files changed, 510 insertions(+), 332 deletions(-)
>>  create mode 100644 lib/objdep.c
>>  create mode 100644 lib/objdep.h
>>
>> diff --git a/controller/lflow.c b/controller/lflow.c
>> index cc0f31db0..f9f2e6286 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,
>> @@ -371,8 +211,8 @@ bool
>>  lflow_handle_changed_flows(struct lflow_ctx_in *l_ctx_in,
>>                             struct lflow_ctx_out *l_ctx_out)
>>  {
>> -    bool ret = true;
>>      const struct sbrec_logical_flow *lflow;
>> +    bool ret = true;
>>
>>      /* Flood remove the flows for all the tracked lflows.  Its possible
> that
>>       * lflow_add_flows_for_datapath() may have been called before calling
>> @@ -400,15 +240,14 @@ 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. */
>>          lflow = sbrec_logical_flow_table_get_for_uuid(
>>              l_ctx_in->logical_flow_table, &ofrn->uuid);
>>          if (lflow) {
>> -            VLOG_DBG("re-add lflow "UUID_FMT,
>> -                     UUID_ARGS(&lflow->header_.uuid));
>> +            VLOG_DBG("re-add lflow "UUID_FMT,
> UUID_ARGS(&lflow->header_.uuid));
>>
>>              /* For the extra lflows that need to be reprocessed because
> of the
>>               * flood remove, remove it from lflows_processed. */
>> @@ -537,7 +376,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 +384,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 +430,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 +626,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 +637,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 +665,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 +676,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;
>> @@ -849,60 +689,33 @@ done:
>>      return ret;
>>  }
>>
>> -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)
>> +void
>> +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 +723,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 +742,6 @@ 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;
>>  }
>>
>>  static void
>> @@ -985,7 +796,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 +911,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 +925,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 +977,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 +1044,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 +1052,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 +1084,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 +1158,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 +2261,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 +2327,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 +2366,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 +2394,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 8cbe312ca..a9a0f7506 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);
>> +void lflow_handle_changed_ref(enum objdep_type 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 9969d317f..32a24a076 100644
>> --- a/controller/ovn-controller.c
>> +++ b/controller/ovn-controller.c
>> @@ -2582,8 +2582,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;
>>
>> @@ -2742,7 +2742,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;
>> @@ -2758,7 +2758,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);
>> @@ -2782,7 +2782,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);
>> @@ -2818,7 +2818,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) {
>> @@ -2827,7 +2827,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);
>>      }
>>
>> @@ -2958,8 +2958,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) {
>> @@ -2973,7 +2976,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;
>>              }
>> @@ -2983,8 +2990,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) {
>> @@ -3015,8 +3025,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) {
>> @@ -3024,8 +3037,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) {
>> @@ -3033,8 +3049,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 60bead6a6..15d4f84bb 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 000000000..0224a5d06
>> --- /dev/null
>> +++ b/lib/objdep.c
>> @@ -0,0 +1,261 @@
>> +/* 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. */
>> +    handler(type, res_name, &objs_todo, in_arg, out_arg);
>> +    return true;
>> +}
>> +
>> +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 000000000..059a11a62
>> --- /dev/null
>> +++ b/lib/objdep.h
>> @@ -0,0 +1,121 @@
>> +/* 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. */
>> +typedef void (*objdep_change_handler)(enum objdep_type 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.resource_to_object_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 entires 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.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 type,
> 
> nit: According to coding style, "type" can be omitted. Same for the other
> occurrences.
> 
>> +                    const char *res_name, const struct uuid *);
>> +void objdep_mgr_add_with_refcount(struct objdep_mgr *,
>> +                                  enum objdep_type 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 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 type,
>> +                              const char *res_name,
>> +                              objdep_change_handler handler,
> 
> Same here.
> 
> Acked-by: Han Zhou <[email protected]>
> 

Thanks for the review!

I fixed the things you pointed out and added your Ack to the v2 version
of this patch.

>> +                              struct uuidset *objs_processed,
>> +                              const void *in_arg, void *out_arg,
>> +                              bool *changed);
>> +
>> +const char *objdep_type_name(enum objdep_type type);
>> +
>> +#endif /* lib/objdep.h */
>>
> 

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to