@@ -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;
@@ -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
@@ -81,59 +84,6 @@ struct uuid;
#define OFTABLE_ECMP_NH 77
#define OFTABLE_CHK_LB_AFFINITY 78
-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;
@@ -170,7 +120,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;
@@ -182,10 +132,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;
@@ -195,6 +143,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,
@@ -2600,8 +2600,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;
@@ -2760,7 +2760,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;
@@ -2776,7 +2776,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);
@@ -2800,7 +2800,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);
@@ -2836,7 +2836,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) {
@@ -2845,7 +2845,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);
}
@@ -2976,8 +2976,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) {
@@ -2991,7 +2994,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;
}
@@ -3001,8 +3008,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) {
@@ -3033,8 +3043,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) {
@@ -3042,8 +3055,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) {
@@ -3051,8 +3067,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) {
@@ -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 \
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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 */