summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ovn/expr.h5
-rw-r--r--ovn/controller/lflow.c147
-rw-r--r--ovn/controller/lflow.h52
-rw-r--r--ovn/controller/ovn-controller.c13
-rw-r--r--ovn/lib/actions.c2
-rw-r--r--ovn/lib/expr.c21
-rw-r--r--ovn/utilities/ovn-trace.c2
-rw-r--r--tests/test-ovn.c7
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);