diff options
-rw-r--r-- | include/ovn/expr.h | 5 | ||||
-rw-r--r-- | ovn/controller/lflow.c | 147 | ||||
-rw-r--r-- | ovn/controller/lflow.h | 52 | ||||
-rw-r--r-- | ovn/controller/ovn-controller.c | 13 | ||||
-rw-r--r-- | ovn/lib/actions.c | 2 | ||||
-rw-r--r-- | ovn/lib/expr.c | 21 | ||||
-rw-r--r-- | ovn/utilities/ovn-trace.c | 2 | ||||
-rw-r--r-- | tests/test-ovn.c | 7 |
8 files changed, 231 insertions, 18 deletions
diff --git a/include/ovn/expr.h b/include/ovn/expr.h index a68fd6e1c..22f633e57 100644 --- a/include/ovn/expr.h +++ b/include/ovn/expr.h @@ -66,6 +66,7 @@ struct flow; struct ofpbuf; struct shash; struct simap; +struct sset; /* "Measurement level" of a field. See "Level of Measurement" in the large * comment on struct expr_symbol below for more information. */ @@ -388,10 +389,12 @@ void expr_format(const struct expr *, struct ds *); void expr_print(const struct expr *); struct expr *expr_parse(struct lexer *, const struct shash *symtab, const struct shash *addr_sets, - const struct shash *port_groups); + const struct shash *port_groups, + struct sset *addr_sets_ref); struct expr *expr_parse_string(const char *, const struct shash *symtab, const struct shash *addr_sets, const struct shash *port_groups, + struct sset *addr_sets_ref, char **errorp); struct expr *expr_clone(struct expr *); diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c index 1d7fa8eaa..03de7d5fe 100644 --- a/ovn/controller/lflow.c +++ b/ovn/controller/lflow.c @@ -77,6 +77,7 @@ static bool consider_logical_flow( struct ovn_desired_flow_table *, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *lfrr, uint32_t *conj_id_ofs); static bool @@ -133,6 +134,128 @@ is_switch(const struct sbrec_datapath_binding *ldp) } +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, *rlfn_next; + HMAP_FOR_EACH_SAFE (rlfn, rlfn_next, node, &lfrr->ref_lflow_table) { + free(rlfn->ref_name); + struct lflow_ref_list_node *lrln, *next; + LIST_FOR_EACH_SAFE (lrln, next, ref_list, &rlfn->ref_lflow_head) { + ovs_list_remove(&lrln->ref_list); + ovs_list_remove(&lrln->lflow_list); + free(lrln); + } + hmap_remove(&lfrr->ref_lflow_table, &rlfn->node); + free(rlfn); + } + hmap_destroy(&lfrr->ref_lflow_table); + + struct lflow_ref_node *lfrn, *lfrn_next; + HMAP_FOR_EACH_SAFE (lfrn, lfrn_next, 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) +{ + struct ref_lflow_node *rlfn = ref_lflow_lookup(&lfrr->ref_lflow_table, + type, ref_name); + if (!rlfn) { + rlfn = xzalloc(sizeof *rlfn); + rlfn->node.hash = hash_string(ref_name, type); + rlfn->type = type; + rlfn->ref_name = xstrdup(ref_name); + ovs_list_init(&rlfn->ref_lflow_head); + hmap_insert(&lfrr->ref_lflow_table, &rlfn->node, rlfn->node.hash); + } + + struct lflow_ref_node *lfrn = lflow_ref_lookup(&lfrr->lflow_ref_table, + lflow_uuid); + 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->type = type; + lrln->ref_name = xstrdup(ref_name); + lrln->lflow_uuid = *lflow_uuid; + ovs_list_push_back(&rlfn->ref_lflow_head, &lrln->ref_list); + ovs_list_push_back(&lfrn->lflow_ref_head, &lrln->lflow_list); +} + +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, *next; + LIST_FOR_EACH_SAFE (lrln, next, lflow_list, &lfrn->lflow_ref_head) { + ovs_list_remove(&lrln->ref_list); + ovs_list_remove(&lrln->lflow_list); + free(lrln); + } + free(lfrn); +} + /* Adds the logical flows from the Logical_Flow table to flow tables. */ static void add_logical_flows( @@ -150,6 +273,7 @@ add_logical_flows( struct ovn_desired_flow_table *flow_table, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *lfrr, uint32_t *conj_id_ofs) { const struct sbrec_logical_flow *lflow; @@ -181,7 +305,7 @@ add_logical_flows( &nd_ra_opts, addr_sets, port_groups, active_tunnels, local_lport_ids, flow_table, group_table, meter_table, - conj_id_ofs)) { + lfrr, conj_id_ofs)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); VLOG_ERR_RL(&rl, "Conjunction id overflow when processing lflow " UUID_FMT, UUID_ARGS(&lflow->header_.uuid)); @@ -209,6 +333,7 @@ lflow_handle_changed_flows( struct ovn_desired_flow_table *flow_table, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *lfrr, uint32_t *conj_id_ofs) { bool ret = true; @@ -242,6 +367,8 @@ lflow_handle_changed_flows( VLOG_DBG("handle deleted lflow "UUID_FMT, UUID_ARGS(&lflow->header_.uuid)); ofctrl_remove_flows(flow_table, &lflow->header_.uuid); + /* Delete entries from lflow resource reference. */ + lflow_resource_destroy_lflow(lfrr, &lflow->header_.uuid); } } SBREC_LOGICAL_FLOW_TABLE_FOR_EACH_TRACKED (lflow, logical_flow_table) { @@ -253,6 +380,8 @@ lflow_handle_changed_flows( VLOG_DBG("handle updated lflow "UUID_FMT, UUID_ARGS(&lflow->header_.uuid)); ofctrl_remove_flows(flow_table, &lflow->header_.uuid); + /* Delete entries from lflow resource reference. */ + lflow_resource_destroy_lflow(lfrr, &lflow->header_.uuid); } VLOG_DBG("handle new lflow "UUID_FMT, UUID_ARGS(&lflow->header_.uuid)); @@ -263,7 +392,7 @@ lflow_handle_changed_flows( &nd_ra_opts, addr_sets, port_groups, active_tunnels, local_lport_ids, flow_table, group_table, meter_table, - conj_id_ofs)) { + lfrr, conj_id_ofs)) { ret = false; break; } @@ -303,6 +432,7 @@ consider_logical_flow( struct ovn_desired_flow_table *flow_table, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *lfrr, uint32_t *conj_id_ofs) { /* Determine translation of logical table IDs to physical table IDs. */ @@ -362,8 +492,16 @@ consider_logical_flow( struct hmap matches; struct expr *expr; + struct sset addr_sets_ref = SSET_INITIALIZER(&addr_sets_ref); expr = expr_parse_string(lflow->match, &symtab, addr_sets, port_groups, - &error); + &addr_sets_ref, &error); + const char *addr_set_name; + SSET_FOR_EACH (addr_set_name, &addr_sets_ref) { + lflow_resource_add(lfrr, REF_TYPE_ADDRSET, addr_set_name, + &lflow->header_.uuid); + } + sset_destroy(&addr_sets_ref); + if (!error) { if (prereqs) { expr = expr_combine(EXPR_T_AND, expr, prereqs); @@ -577,6 +715,7 @@ lflow_run(struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath, struct ovn_desired_flow_table *flow_table, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *lfrr, uint32_t *conj_id_ofs) { COVERAGE_INC(lflow_run); @@ -586,7 +725,7 @@ lflow_run(struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath, dhcpv6_options_table, logical_flow_table, local_datapaths, chassis, addr_sets, port_groups, active_tunnels, local_lport_ids, flow_table, group_table, - meter_table, conj_id_ofs); + meter_table, lfrr, conj_id_ofs); add_neighbor_flows(sbrec_port_binding_by_name, mac_binding_table, flow_table); } diff --git a/ovn/controller/lflow.h b/ovn/controller/lflow.h index f9dc11a6b..6f3bc01ea 100644 --- a/ovn/controller/lflow.h +++ b/ovn/controller/lflow.h @@ -34,11 +34,15 @@ */ #include <stdint.h> +#include "openvswitch/hmap.h" +#include "openvswitch/uuid.h" +#include "openvswitch/list.h" struct ovn_extend_table; struct ovsdb_idl_index; struct ovn_desired_flow_table; struct hmap; +struct hmap_node; struct sbrec_chassis; struct sbrec_dhcp_options_table; struct sbrec_dhcpv6_options_table; @@ -65,6 +69,52 @@ struct uuid; /* The number of tables for the ingress and egress pipelines. */ #define LOG_PIPELINE_LEN 24 +enum ref_type { + REF_TYPE_ADDRSET +}; + +/* 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 lflow_list; /* list for same lflow */ + struct ovs_list ref_list; /* list for same ref */ + enum ref_type type; + char *ref_name; + struct uuid lflow_uuid; +}; + +struct ref_lflow_node { + struct hmap_node node; + enum ref_type type; /* key */ + char *ref_name; /* key */ + struct ovs_list ref_lflow_head; +}; + +struct lflow_ref_node { + struct hmap_node node; + struct uuid lflow_uuid; /* key */ + struct ovs_list lflow_ref_head; +}; + +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 *); + void lflow_init(void); void lflow_run(struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath, struct ovsdb_idl_index *sbrec_port_binding_by_name, @@ -81,6 +131,7 @@ void lflow_run(struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath, struct ovn_desired_flow_table *, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *, uint32_t *conj_id_ofs); bool lflow_handle_changed_flows( @@ -98,6 +149,7 @@ bool lflow_handle_changed_flows( struct ovn_desired_flow_table *, struct ovn_extend_table *group_table, struct ovn_extend_table *meter_table, + struct lflow_resource_ref *, uint32_t *conj_id_ofs); void lflow_destroy(void); diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 02c4963a5..eda4fb0ab 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -962,6 +962,8 @@ struct ed_type_flow_output { struct ovn_extend_table meter_table; /* conjunction id offset */ uint32_t conj_id_ofs; + /* lflow resource cross reference */ + struct lflow_resource_ref lflow_resource_ref; }; static void @@ -973,6 +975,7 @@ en_flow_output_init(struct engine_node *node) ovn_extend_table_init(&data->group_table); ovn_extend_table_init(&data->meter_table); data->conj_id_ofs = 1; + lflow_resource_init(&data->lflow_resource_ref); } static void @@ -983,6 +986,7 @@ en_flow_output_cleanup(struct engine_node *node) ovn_desired_flow_table_destroy(&data->flow_table); ovn_extend_table_destroy(&data->group_table); ovn_extend_table_destroy(&data->meter_table); + lflow_resource_destroy(&data->lflow_resource_ref); } static void @@ -1033,6 +1037,7 @@ en_flow_output_run(struct engine_node *node) struct ovn_extend_table *group_table = &fo->group_table; struct ovn_extend_table *meter_table = &fo->meter_table; uint32_t *conj_id_ofs = &fo->conj_id_ofs; + struct lflow_resource_ref *lfrr = &fo->lflow_resource_ref; static bool first_run = true; if (first_run) { @@ -1041,6 +1046,7 @@ en_flow_output_run(struct engine_node *node) ovn_desired_flow_table_clear(flow_table); ovn_extend_table_clear(group_table, false /* desired */); ovn_extend_table_clear(meter_table, false /* desired */); + lflow_resource_clear(lfrr); } struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath = @@ -1077,7 +1083,8 @@ en_flow_output_run(struct engine_node *node) mac_binding_table, chassis, local_datapaths, addr_sets, port_groups, active_tunnels, local_lport_ids, - flow_table, group_table, meter_table, conj_id_ofs); + flow_table, group_table, meter_table, lfrr, + conj_id_ofs); struct sbrec_multicast_group_table *multicast_group_table = (struct sbrec_multicast_group_table *)EN_OVSDB_GET( @@ -1139,6 +1146,7 @@ flow_output_sb_logical_flow_handler(struct engine_node *node) struct ovn_extend_table *group_table = &fo->group_table; struct ovn_extend_table *meter_table = &fo->meter_table; uint32_t *conj_id_ofs = &fo->conj_id_ofs; + struct lflow_resource_ref *lfrr = &fo->lflow_resource_ref; struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath = engine_ovsdb_node_get_index( @@ -1169,7 +1177,8 @@ flow_output_sb_logical_flow_handler(struct engine_node *node) logical_flow_table, local_datapaths, chassis, addr_sets, port_groups, active_tunnels, local_lport_ids, - flow_table, group_table, meter_table, conj_id_ofs); + flow_table, group_table, meter_table, lfrr, + conj_id_ofs); node->changed = true; return handled; diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 4c36b69ab..d132214bf 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -238,7 +238,7 @@ add_prerequisite(struct action_context *ctx, const char *prerequisite) struct expr *expr; char *error; - expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL, + expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL, NULL, &error); ovs_assert(!error); ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr); diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c index e21206120..e4c650f7c 100644 --- a/ovn/lib/expr.c +++ b/ovn/lib/expr.c @@ -467,6 +467,7 @@ struct expr_context { const struct shash *symtab; /* Symbol table. */ const struct shash *addr_sets; /* Address set table. */ const struct shash *port_groups; /* Port group table. */ + struct sset *addr_sets_ref; /* The set of address set referenced. */ bool not; /* True inside odd number of NOT operators. */ unsigned int paren_depth; /* Depth of nested parentheses. */ }; @@ -735,6 +736,10 @@ static bool parse_addr_sets(struct expr_context *ctx, struct expr_constant_set *cs, size_t *allocated_values) { + if (ctx->addr_sets_ref) { + sset_add(ctx->addr_sets_ref, ctx->lexer->token.s); + } + struct expr_constant_set *addr_sets = (ctx->addr_sets ? shash_find_data(ctx->addr_sets, ctx->lexer->token.s) @@ -1277,12 +1282,14 @@ expr_parse__(struct expr_context *ctx) struct expr * expr_parse(struct lexer *lexer, const struct shash *symtab, const struct shash *addr_sets, - const struct shash *port_groups) + const struct shash *port_groups, + struct sset *addr_sets_ref) { struct expr_context ctx = { .lexer = lexer, .symtab = symtab, .addr_sets = addr_sets, - .port_groups = port_groups }; + .port_groups = port_groups, + .addr_sets_ref = addr_sets_ref }; return lexer->error ? NULL : expr_parse__(&ctx); } @@ -1296,13 +1303,15 @@ struct expr * expr_parse_string(const char *s, const struct shash *symtab, const struct shash *addr_sets, const struct shash *port_groups, + struct sset *addr_sets_ref, char **errorp) { struct lexer lexer; lexer_init(&lexer, s); lexer_get(&lexer); - struct expr *expr = expr_parse(&lexer, symtab, addr_sets, port_groups); + struct expr *expr = expr_parse(&lexer, symtab, addr_sets, port_groups, + addr_sets_ref); lexer_force_end(&lexer); *errorp = lexer_steal_error(&lexer); if (*errorp) { @@ -1528,7 +1537,7 @@ expr_get_level(const struct expr *expr) static enum expr_level expr_parse_level(const char *s, const struct shash *symtab, char **errorp) { - struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, errorp); + struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, errorp); enum expr_level level = expr ? expr_get_level(expr) : EXPR_L_NOMINAL; expr_destroy(expr); return level; @@ -1699,7 +1708,7 @@ parse_and_annotate(const char *s, const struct shash *symtab, char *error; struct expr *expr; - expr = expr_parse_string(s, symtab, NULL, NULL, &error); + expr = expr_parse_string(s, symtab, NULL, NULL, NULL, &error); if (expr) { expr = expr_annotate_(expr, symtab, nesting, &error); } @@ -3423,7 +3432,7 @@ expr_parse_microflow(const char *s, const struct shash *symtab, lexer_init(&lexer, s); lexer_get(&lexer); - struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups); + struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups, NULL); lexer_force_end(&lexer); if (e) { diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c index 9718077aa..fff432d61 100644 --- a/ovn/utilities/ovn-trace.c +++ b/ovn/utilities/ovn-trace.c @@ -850,7 +850,7 @@ read_flows(void) char *error; struct expr *match; match = expr_parse_string(sblf->match, &symtab, &address_sets, - &port_groups, &error); + &port_groups, NULL, &error); if (error) { VLOG_WARN("%s: parsing expression failed (%s)", sblf->match, error); diff --git a/tests/test-ovn.c b/tests/test-ovn.c index 7cce9c2ae..450cb9db5 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -285,7 +285,7 @@ test_parse_expr__(int steps) char *error; expr = expr_parse_string(ds_cstr(&input), &symtab, &addr_sets, - &port_groups, &error); + &port_groups, NULL, &error); if (!error && steps > 0) { expr = expr_annotate(expr, &symtab, &error); } @@ -409,7 +409,8 @@ test_evaluate_expr(struct ovs_cmdl_context *ctx) while (!ds_get_test_line(&input, stdin)) { struct expr *expr; - expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL, &error); + expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL, NULL, + &error); if (!error) { expr = expr_annotate(expr, &symtab, &error); } @@ -884,7 +885,7 @@ test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab, char *error; modified = expr_parse_string(ds_cstr(&s), symtab, NULL, - NULL, &error); + NULL, NULL, &error); if (error) { fprintf(stderr, "%s fails to parse (%s)\n", ds_cstr(&s), error); |