@@ -520,6 +520,9 @@ struct ovnact_encode_params {
/* A struct to figure out the meter_id for meter actions. */
struct ovn_extend_table *meter_table;
+ /* The logical flow uuid that drove this action. */
+ struct uuid lflow_uuid;
+
/* OVN maps each logical flow table (ltable), one-to-one, onto a physical
* OpenFlow flow table (ptable). A number of parameters describe this
* mapping and data related to flow tables:
@@ -62,7 +62,7 @@ struct condition_aux {
const struct sset *active_tunnels;
};
-static void consider_logical_flow(
+static bool consider_logical_flow(
struct ovsdb_idl_index *sbrec_chassis_by_name,
struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
struct ovsdb_idl_index *sbrec_port_binding_by_name,
@@ -76,10 +76,10 @@ static void consider_logical_flow(
const struct shash *port_groups,
const struct sset *active_tunnels,
const struct sset *local_lport_ids,
- uint32_t *conj_id_ofs,
- struct hmap *flow_table,
+ struct ovn_desired_flow_table *,
struct ovn_extend_table *group_table,
- struct ovn_extend_table *meter_table);
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs);
static bool
lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp)
@@ -153,11 +153,11 @@ add_logical_flows(
const struct shash *port_groups,
const struct sset *active_tunnels,
const struct sset *local_lport_ids,
- struct hmap *flow_table,
+ struct ovn_desired_flow_table *flow_table,
struct ovn_extend_table *group_table,
- struct ovn_extend_table *meter_table)
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs)
{
- uint32_t conj_id_ofs = 1;
const struct sbrec_logical_flow *lflow;
struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
@@ -180,14 +180,19 @@ add_logical_flows(
nd_ra_opts_init(&nd_ra_opts);
SBREC_LOGICAL_FLOW_TABLE_FOR_EACH (lflow, logical_flow_table) {
- consider_logical_flow(sbrec_chassis_by_name,
- sbrec_multicast_group_by_name_datapath,
- sbrec_port_binding_by_name,
- lflow, local_datapaths,
- chassis, &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
- addr_sets, port_groups, active_tunnels,
- local_lport_ids, &conj_id_ofs,
- flow_table, group_table, meter_table);
+ if (!consider_logical_flow(sbrec_chassis_by_name,
+ sbrec_multicast_group_by_name_datapath,
+ sbrec_port_binding_by_name,
+ lflow, local_datapaths,
+ chassis, &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
+ addr_sets, port_groups, active_tunnels,
+ local_lport_ids, flow_table,
+ group_table, meter_table,
+ 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));
+ }
}
dhcp_opts_destroy(&dhcp_opts);
@@ -195,7 +200,102 @@ add_logical_flows(
nd_ra_opts_destroy(&nd_ra_opts);
}
-static void
+bool
+lflow_handle_changed_flows(
+ struct ovsdb_idl_index *sbrec_chassis_by_name,
+ struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
+ struct ovsdb_idl_index *sbrec_port_binding_by_name,
+ const struct sbrec_dhcp_options_table *dhcp_options_table,
+ const struct sbrec_dhcpv6_options_table *dhcpv6_options_table,
+ const struct sbrec_logical_flow_table *logical_flow_table,
+ const struct hmap *local_datapaths,
+ const struct sbrec_chassis *chassis,
+ const struct shash *addr_sets,
+ const struct shash *port_groups,
+ const struct sset *active_tunnels,
+ const struct sset *local_lport_ids,
+ struct ovn_desired_flow_table *flow_table,
+ struct ovn_extend_table *group_table,
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs)
+{
+ bool ret = true;
+ const struct sbrec_logical_flow *lflow;
+
+ struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
+ struct hmap dhcpv6_opts = HMAP_INITIALIZER(&dhcpv6_opts);
+ const struct sbrec_dhcp_options *dhcp_opt_row;
+ SBREC_DHCP_OPTIONS_TABLE_FOR_EACH (dhcp_opt_row, dhcp_options_table) {
+ dhcp_opt_add(&dhcp_opts, dhcp_opt_row->name, dhcp_opt_row->code,
+ dhcp_opt_row->type);
+ }
+
+
+ const struct sbrec_dhcpv6_options *dhcpv6_opt_row;
+ SBREC_DHCPV6_OPTIONS_TABLE_FOR_EACH (dhcpv6_opt_row,
+ dhcpv6_options_table) {
+ dhcp_opt_add(&dhcpv6_opts, dhcpv6_opt_row->name, dhcpv6_opt_row->code,
+ dhcpv6_opt_row->type);
+ }
+
+ struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts);
+ nd_ra_opts_init(&nd_ra_opts);
+
+ /* Handle removed flows first, and then other flows, so that when
+ * the flows being added and removed have same match conditions
+ * can be processed in the proper order */
+ SBREC_LOGICAL_FLOW_TABLE_FOR_EACH_TRACKED (lflow, logical_flow_table) {
+ /* Remove any flows that should be removed. */
+ if (sbrec_logical_flow_is_deleted(lflow)) {
+ VLOG_DBG("handle deleted lflow "UUID_FMT,
+ UUID_ARGS(&lflow->header_.uuid));
+ ofctrl_remove_flows(flow_table, &lflow->header_.uuid);
+ }
+ }
+ SBREC_LOGICAL_FLOW_TABLE_FOR_EACH_TRACKED (lflow, logical_flow_table) {
+ if (!sbrec_logical_flow_is_deleted(lflow)) {
+ /* Now, add/modify existing flows. If the logical
+ * flow is a modification, just remove the flows
+ * for this row, and then add new flows. */
+ if (!sbrec_logical_flow_is_new(lflow)) {
+ VLOG_DBG("handle updated lflow "UUID_FMT,
+ UUID_ARGS(&lflow->header_.uuid));
+ ofctrl_remove_flows(flow_table, &lflow->header_.uuid);
+ }
+ VLOG_DBG("handle new lflow "UUID_FMT,
+ UUID_ARGS(&lflow->header_.uuid));
+ if (!consider_logical_flow(sbrec_chassis_by_name,
+ sbrec_multicast_group_by_name_datapath,
+ sbrec_port_binding_by_name,
+ lflow, local_datapaths,
+ chassis, &dhcp_opts, &dhcpv6_opts, &nd_ra_opts,
+ addr_sets, port_groups, active_tunnels,
+ local_lport_ids, flow_table,
+ group_table, meter_table,
+ conj_id_ofs)) {
+ ret = false;
+ break;
+ }
+ }
+ }
+ dhcp_opts_destroy(&dhcp_opts);
+ dhcp_opts_destroy(&dhcpv6_opts);
+ nd_ra_opts_destroy(&nd_ra_opts);
+ return ret;
+}
+
+static bool
+update_conj_id_ofs(uint32_t *conj_id_ofs, uint32_t n_conjs)
+{
+ if (*conj_id_ofs + n_conjs < *conj_id_ofs) {
+ /* overflow */
+ return false;
+ }
+ *conj_id_ofs += n_conjs;
+ return true;
+}
+
+static bool
consider_logical_flow(
struct ovsdb_idl_index *sbrec_chassis_by_name,
struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
@@ -210,20 +310,24 @@ consider_logical_flow(
const struct shash *port_groups,
const struct sset *active_tunnels,
const struct sset *local_lport_ids,
- uint32_t *conj_id_ofs,
- struct hmap *flow_table,
+ struct ovn_desired_flow_table *flow_table,
struct ovn_extend_table *group_table,
- struct ovn_extend_table *meter_table)
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs)
{
/* Determine translation of logical table IDs to physical table IDs. */
bool ingress = !strcmp(lflow->pipeline, "ingress");
const struct sbrec_datapath_binding *ldp = lflow->logical_datapath;
if (!ldp) {
- return;
+ VLOG_DBG("lflow "UUID_FMT" has no datapath binding, skip",
+ UUID_ARGS(&lflow->header_.uuid));
+ return true;
}
if (!get_local_datapath(local_datapaths, ldp->tunnel_key)) {
- return;
+ VLOG_DBG("lflow "UUID_FMT" is not for local datapath, skip",
+ UUID_ARGS(&lflow->header_.uuid));
+ return true;
}
/* Determine translation of logical table IDs to physical table IDs. */
@@ -261,7 +365,7 @@ consider_logical_flow(
free(error);
ovnacts_free(ovnacts.data, ovnacts.size);
ofpbuf_uninit(&ovnacts);
- return;
+ return true;
}
/* Translate OVN match into table of OpenFlow matches. */
@@ -285,7 +389,7 @@ consider_logical_flow(
free(error);
ovnacts_free(ovnacts.data, ovnacts.size);
ofpbuf_uninit(&ovnacts);
- return;
+ return true;
}
struct lookup_port_aux aux = {
@@ -307,10 +411,12 @@ consider_logical_flow(
expr_destroy(expr);
if (hmap_is_empty(&matches)) {
+ VLOG_DBG("lflow "UUID_FMT" matches are empty, skip",
+ UUID_ARGS(&lflow->header_.uuid));
ovnacts_free(ovnacts.data, ovnacts.size);
ofpbuf_uninit(&ovnacts);
expr_matches_destroy(&matches);
- return;
+ return true;
}
/* Encode OVN logical actions into OpenFlow. */
@@ -322,6 +428,7 @@ consider_logical_flow(
.is_switch = is_switch(ldp),
.group_table = group_table,
.meter_table = meter_table,
+ .lflow_uuid = lflow->header_.uuid,
.pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
.ingress_ptable = OFTABLE_LOG_INGRESS_PIPELINE,
@@ -350,13 +457,18 @@ consider_logical_flow(
char buf[16];
snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64, dp_id, port_id);
if (!sset_contains(local_lport_ids, buf)) {
+ VLOG_DBG("lflow "UUID_FMT
+ " port %s in match is not local, skip",
+ UUID_ARGS(&lflow->header_.uuid),
+ buf);
continue;
}
}
}
if (!m->n) {
ofctrl_add_flow(flow_table, ptable, lflow->priority,
- lflow->header_.uuid.parts[0], &m->match, &ofpacts);
+ lflow->header_.uuid.parts[0], &m->match, &ofpacts,
+ &lflow->header_.uuid);
} else {
uint64_t conj_stubs[64 / 8];
struct ofpbuf conj;
@@ -372,7 +484,7 @@ consider_logical_flow(
dst->n_clauses = src->n_clauses;
}
ofctrl_add_flow(flow_table, ptable, lflow->priority, 0, &m->match,
- &conj);
+ &conj, &lflow->header_.uuid);
ofpbuf_uninit(&conj);
}
}
@@ -380,7 +492,7 @@ consider_logical_flow(
/* Clean up. */
expr_matches_destroy(&matches);
ofpbuf_uninit(&ofpacts);
- *conj_id_ofs += n_conjs;
+ return update_conj_id_ofs(conj_id_ofs, n_conjs);
}
static void
@@ -398,7 +510,7 @@ put_load(const uint8_t *data, size_t len,
static void
consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
const struct sbrec_mac_binding *b,
- struct hmap *flow_table)
+ struct ovn_desired_flow_table *flow_table)
{
const struct sbrec_port_binding *pb
= lport_lookup_by_name(sbrec_port_binding_by_name, b->logical_port);
@@ -440,7 +552,8 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
uint64_t stub[1024 / 8];
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
put_load(mac.ea, sizeof mac.ea, MFF_ETH_DST, 0, 48, &ofpacts);
- ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100, 0, &match, &ofpacts);
+ ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100, 0, &match, &ofpacts,
+ &b->header_.uuid);
ofpbuf_uninit(&ofpacts);
}
@@ -449,7 +562,7 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
static void
add_neighbor_flows(struct ovsdb_idl_index *sbrec_port_binding_by_name,
const struct sbrec_mac_binding_table *mac_binding_table,
- struct hmap *flow_table)
+ struct ovn_desired_flow_table *flow_table)
{
const struct sbrec_mac_binding *b;
SBREC_MAC_BINDING_TABLE_FOR_EACH (b, mac_binding_table) {
@@ -473,9 +586,10 @@ lflow_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
const struct shash *port_groups,
const struct sset *active_tunnels,
const struct sset *local_lport_ids,
- struct hmap *flow_table,
+ struct ovn_desired_flow_table *flow_table,
struct ovn_extend_table *group_table,
- struct ovn_extend_table *meter_table)
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs)
{
COVERAGE_INC(lflow_run);
@@ -485,7 +599,7 @@ lflow_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
dhcpv6_options_table, logical_flow_table,
local_datapaths, chassis, addr_sets, port_groups,
active_tunnels, local_lport_ids, flow_table, group_table,
- meter_table);
+ meter_table, conj_id_ofs);
add_neighbor_flows(sbrec_port_binding_by_name, mac_binding_table,
flow_table);
}
@@ -37,6 +37,7 @@
struct ovn_extend_table;
struct ovsdb_idl_index;
+struct ovn_desired_flow_table;
struct hmap;
struct sbrec_chassis;
struct sbrec_dhcp_options_table;
@@ -78,9 +79,29 @@ void lflow_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
const struct shash *port_groups,
const struct sset *active_tunnels,
const struct sset *local_lport_ids,
- struct hmap *flow_table,
+ struct ovn_desired_flow_table *,
struct ovn_extend_table *group_table,
- struct ovn_extend_table *meter_table);
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs);
+
+bool lflow_handle_changed_flows(
+ struct ovsdb_idl_index *sbrec_chassis_by_name,
+ struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
+ struct ovsdb_idl_index *sbrec_port_binding_by_name,
+ const struct sbrec_dhcp_options_table *,
+ const struct sbrec_dhcpv6_options_table *,
+ const struct sbrec_logical_flow_table *,
+ const struct hmap *local_datapaths,
+ const struct sbrec_chassis *,
+ const struct shash *addr_sets,
+ const struct shash *port_groups,
+ const struct sset *active_tunnels,
+ const struct sset *local_lport_ids,
+ struct ovn_desired_flow_table *,
+ struct ovn_extend_table *group_table,
+ struct ovn_extend_table *meter_table,
+ uint32_t *conj_id_ofs);
+
void lflow_destroy(void);
#endif /* ovn/lflow.h */
@@ -20,6 +20,7 @@
#include "dp-packet.h"
#include "flow.h"
#include "hash.h"
+#include "hindex.h"
#include "lflow.h"
#include "ofctrl.h"
#include "openflow/openflow.h"
@@ -52,7 +53,8 @@ VLOG_DEFINE_THIS_MODULE(ofctrl);
/* An OpenFlow flow. */
struct ovn_flow {
- struct hmap_node hmap_node; /* For match based hashing. */
+ struct hmap_node match_hmap_node; /* For match based hashing. */
+ struct hindex_node uuid_hindex_node; /* For uuid based hashing. */
struct ovs_list list_node; /* For handling lists of flows. */
/* Key. */
@@ -61,14 +63,16 @@ struct ovn_flow {
struct minimatch match;
/* Data. */
+ struct uuid sb_uuid;
struct ofpact *ofpacts;
size_t ofpacts_len;
uint64_t cookie;
};
-static uint32_t ovn_flow_hash(const struct ovn_flow *);
+static uint32_t ovn_flow_match_hash(const struct ovn_flow *);
static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
- const struct ovn_flow *target);
+ const struct ovn_flow *target,
+ bool cmp_sb_uuid);
static char *ovn_flow_to_string(const struct ovn_flow *);
static void ovn_flow_log(const struct ovn_flow *, const char *action);
static void ovn_flow_destroy(struct ovn_flow *);
@@ -146,6 +150,10 @@ static struct ovn_extend_table *meters;
* S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */
static enum mf_field_id mff_ovn_geneve;
+/* Indicates if flows need to be reinstalled for scenarios when ovs
+ * is restarted, even if there is no change in the desired flow table. */
+static bool need_reinstall_flows;
+
static ovs_be32 queue_msg(struct ofpbuf *);
static struct ofpbuf *encode_flow_mod(struct ofputil_flow_mod *);
@@ -154,8 +162,8 @@ static struct ofpbuf *encode_group_mod(const struct ofputil_group_mod *);
static struct ofpbuf *encode_meter_mod(const struct ofputil_meter_mod *);
-static void ovn_flow_table_clear(struct hmap *flow_table);
-static void ovn_flow_table_destroy(struct hmap *flow_table);
+static void ovn_installed_flow_table_clear(void);
+static void ovn_installed_flow_table_destroy(void);
static void ofctrl_recv(const struct ofp_header *, enum ofptype);
@@ -375,6 +383,7 @@ run_S_CLEAR_FLOWS(void)
{
VLOG_DBG("clearing all flows");
+ need_reinstall_flows = true;
/* Send a flow_mod to delete all flows. */
struct ofputil_flow_mod fm = {
.table_id = OFPTT_ALL,
@@ -384,9 +393,6 @@ run_S_CLEAR_FLOWS(void)
queue_msg(encode_flow_mod(&fm));
minimatch_destroy(&fm.match);
- /* Clear installed_flows, to match the state of the switch. */
- ovn_flow_table_clear(&installed_flows);
-
/* Send a group_mod to delete all groups. */
struct ofputil_group_mod gm;
memset(&gm, 0, sizeof gm);
@@ -397,6 +403,9 @@ run_S_CLEAR_FLOWS(void)
queue_msg(encode_group_mod(&gm));
ofputil_uninit_group_mod(&gm);
+ /* Clear installed_flows, to match the state of the switch. */
+ ovn_installed_flow_table_clear();
+
/* Clear existing groups, to match the state of the switch. */
if (groups) {
ovn_extend_table_clear(groups, true);
@@ -580,7 +589,7 @@ void
ofctrl_destroy(void)
{
rconn_destroy(swconn);
- ovn_flow_table_destroy(&installed_flows);
+ ovn_installed_flow_table_destroy();
rconn_packet_counter_destroy(tx_counter);
expr_symtab_destroy(&symtab);
shash_destroy(&symtab);
@@ -632,14 +641,17 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
* the OpenFlow table numbered 'table_id' with the given 'priority' and
* OpenFlow 'cookie'. The caller retains ownership of 'match' and 'actions'.
*
+ * The flow is also added to a hash index based on sb_uuid.
+ *
* This just assembles the desired flow table in memory. Nothing is actually
* sent to the switch until a later call to ofctrl_put().
*
* The caller should initialize its own hmap to hold the flows. */
void
-ofctrl_add_flow(struct hmap *desired_flows,
+ofctrl_add_flow(struct ovn_desired_flow_table *flow_table,
uint8_t table_id, uint16_t priority, uint64_t cookie,
- const struct match *match, const struct ofpbuf *actions)
+ const struct match *match, const struct ofpbuf *actions,
+ const struct uuid *sb_uuid)
{
struct ovn_flow *f = xmalloc(sizeof *f);
f->table_id = table_id;
@@ -647,10 +659,14 @@ ofctrl_add_flow(struct hmap *desired_flows,
minimatch_init(&f->match, match);
f->ofpacts = xmemdup(actions->data, actions->size);
f->ofpacts_len = actions->size;
- f->hmap_node.hash = ovn_flow_hash(f);
+ f->sb_uuid = *sb_uuid;
+ f->match_hmap_node.hash = ovn_flow_match_hash(f);
+ f->uuid_hindex_node.hash = uuid_hash(&f->sb_uuid);
f->cookie = cookie;
- if (ovn_flow_lookup(desired_flows, f)) {
+ ovn_flow_log(f, "ofctrl_add_flow");
+
+ if (ovn_flow_lookup(&flow_table->match_flow_table, f, true)) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
if (!VLOG_DROP_DBG(&rl)) {
char *s = ovn_flow_to_string(f);
@@ -662,19 +678,44 @@ ofctrl_add_flow(struct hmap *desired_flows,
return;
}
- hmap_insert(desired_flows, &f->hmap_node, f->hmap_node.hash);
+ hmap_insert(&flow_table->match_flow_table, &f->match_hmap_node,
+ f->match_hmap_node.hash);
+ hindex_insert(&flow_table->uuid_flow_table, &f->uuid_hindex_node,
+ f->uuid_hindex_node.hash);
+}
+
+/* Removes a bundles of flows from the flow table. */
+void
+ofctrl_remove_flows(struct ovn_desired_flow_table *flow_table,
+ const struct uuid *sb_uuid)
+{
+ struct ovn_flow *f, *next;
+ HINDEX_FOR_EACH_WITH_HASH_SAFE (f, next, uuid_hindex_node,
+ uuid_hash(sb_uuid),
+ &flow_table->uuid_flow_table) {
+ if (uuid_equals(&f->sb_uuid, sb_uuid)) {
+ ovn_flow_log(f, "ofctrl_remove_flow");
+ hmap_remove(&flow_table->match_flow_table,
+ &f->match_hmap_node);
+ hindex_remove(&flow_table->uuid_flow_table, &f->uuid_hindex_node);
+ ovn_flow_destroy(f);
+ }
+ }
+
+ /* remove any related group and meter info */
+ ovn_extend_table_remove_desired(groups, sb_uuid);
+ ovn_extend_table_remove_desired(meters, sb_uuid);
}
/* ovn_flow. */
-/* Returns a hash of the key in 'f'. */
+/* Returns a hash of the match key in 'f'. */
static uint32_t
-ovn_flow_hash(const struct ovn_flow *f)
+ovn_flow_match_hash(const struct ovn_flow *f)
{
return hash_2words((f->table_id << 16) | f->priority,
minimatch_hash(&f->match, 0));
-
}
/* Duplicate an ovn_flow structure. */
@@ -687,23 +728,28 @@ ofctrl_dup_flow(struct ovn_flow *src)
minimatch_clone(&dst->match, &src->match);
dst->ofpacts = xmemdup(src->ofpacts, src->ofpacts_len);
dst->ofpacts_len = src->ofpacts_len;
- dst->hmap_node.hash = ovn_flow_hash(dst);
+ dst->sb_uuid = src->sb_uuid;
+ dst->match_hmap_node.hash = ovn_flow_match_hash(dst);
+ dst->uuid_hindex_node.hash = uuid_hash(&src->sb_uuid);
return dst;
}
/* Finds and returns an ovn_flow in 'flow_table' whose key is identical to
* 'target''s key, or NULL if there is none. */
static struct ovn_flow *
-ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target)
+ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target,
+ bool cmp_sb_uuid)
{
struct ovn_flow *f;
- HMAP_FOR_EACH_WITH_HASH (f, hmap_node, target->hmap_node.hash,
+ HMAP_FOR_EACH_WITH_HASH (f, match_hmap_node, target->match_hmap_node.hash,
flow_table) {
if (f->table_id == target->table_id
&& f->priority == target->priority
&& minimatch_equal(&f->match, &target->match)) {
- return f;
+ if (!cmp_sb_uuid || uuid_equals(&target->sb_uuid, &f->sb_uuid)) {
+ return f;
+ }
}
}
return NULL;
@@ -713,6 +759,7 @@ static char *
ovn_flow_to_string(const struct ovn_flow *f)
{
struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_format(&s, "sb_uuid="UUID_FMT", ", UUID_ARGS(&f->sb_uuid));
ds_put_format(&s, "table_id=%"PRIu8", ", f->table_id);
ds_put_format(&s, "priority=%"PRIu16", ", f->priority);
minimatch_format(&f->match, NULL, NULL, &s, OFP_DEFAULT_PRIORITY);
@@ -743,22 +790,48 @@ ovn_flow_destroy(struct ovn_flow *f)
}
/* Flow tables of struct ovn_flow. */
+void
+ovn_desired_flow_table_init(struct ovn_desired_flow_table *flow_table)
+{
+ hmap_init(&flow_table->match_flow_table);
+ hindex_init(&flow_table->uuid_flow_table);
+}
+
+void
+ovn_desired_flow_table_clear(struct ovn_desired_flow_table *flow_table)
+{
+ struct ovn_flow *f, *next;
+ HMAP_FOR_EACH_SAFE (f, next, match_hmap_node,
+ &flow_table->match_flow_table) {
+ hmap_remove(&flow_table->match_flow_table, &f->match_hmap_node);
+ hindex_remove(&flow_table->uuid_flow_table, &f->uuid_hindex_node);
+ ovn_flow_destroy(f);
+ }
+}
+
+void
+ovn_desired_flow_table_destroy(struct ovn_desired_flow_table *flow_table)
+{
+ ovn_desired_flow_table_clear(flow_table);
+ hmap_destroy(&flow_table->match_flow_table);
+ hindex_destroy(&flow_table->uuid_flow_table);
+}
static void
-ovn_flow_table_clear(struct hmap *flow_table)
+ovn_installed_flow_table_clear(void)
{
struct ovn_flow *f, *next;
- HMAP_FOR_EACH_SAFE (f, next, hmap_node, flow_table) {
- hmap_remove(flow_table, &f->hmap_node);
+ HMAP_FOR_EACH_SAFE (f, next, match_hmap_node, &installed_flows) {
+ hmap_remove(&installed_flows, &f->match_hmap_node);
ovn_flow_destroy(f);
}
}
static void
-ovn_flow_table_destroy(struct hmap *flow_table)
+ovn_installed_flow_table_destroy(void)
{
- ovn_flow_table_clear(flow_table);
- hmap_destroy(flow_table);
+ ovn_installed_flow_table_clear();
+ hmap_destroy(&installed_flows);
}
/* Flow table update. */
@@ -823,7 +896,7 @@ add_ct_flush_zone(uint16_t zone_id, struct ovs_list *msgs)
* in the correct state and not backlogged with existing flow_mods. (Our
* criteria for being backlogged appear very conservative, but the socket
* between ovn-controller and OVS provides some buffering.) */
-bool
+static bool
ofctrl_can_put(void)
{
if (state != S_UPDATE_FLOWS
@@ -838,9 +911,7 @@ ofctrl_can_put(void)
* with ofctrl_add_flow().
*
* Replaces the group table and meter table on the switch, if possible, by the
- * contents of 'groups->desired'. Regardless of whether the group table
- * is updated, this deletes all the groups from the 'groups->desired' and frees
- * them. (The hmap itself isn't destroyed.)
+ * contents of 'desired'.
*
* Sends conntrack flush messages to each zone in 'pending_ct_zones' that
* is in the CT_ZONE_OF_QUEUED state and then moves the zone into the
@@ -848,16 +919,42 @@ ofctrl_can_put(void)
*
* This should be called after ofctrl_run() within the main loop. */
void
-ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
- int64_t nb_cfg)
+ofctrl_put(struct ovn_desired_flow_table *flow_table,
+ struct shash *pending_ct_zones,
+ int64_t nb_cfg,
+ bool flow_changed)
{
+ static bool skipped_last_time = false;
+ static int64_t old_nb_cfg = 0;
+ bool need_put = false;
+ if (flow_changed || skipped_last_time || need_reinstall_flows) {
+ need_put = true;
+ } else if (nb_cfg != old_nb_cfg) {
+ /* nb_cfg changed since last ofctrl_put() call */
+ if (cur_cfg == old_nb_cfg) {
+ /* we were up-to-date already, so just update with the
+ * new nb_cfg */
+ cur_cfg = nb_cfg;
+ } else {
+ need_put = true;
+ }
+ }
+
+ old_nb_cfg = nb_cfg;
+
+ if (!need_put) {
+ VLOG_DBG("ofctrl_put not needed");
+ return;
+ }
if (!ofctrl_can_put()) {
- ovn_flow_table_clear(flow_table);
- ovn_extend_table_clear(groups, false);
- ovn_extend_table_clear(meters, false);
+ VLOG_DBG("ofctrl_put can't be performed");
+ skipped_last_time = true;
return;
}
+ skipped_last_time = false;
+ need_reinstall_flows = false;
+
/* OpenFlow messages to send to the switch to bring it up-to-date. */
struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
@@ -921,8 +1018,9 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
* longer desired, delete them; if any of them should have different
* actions, update them. */
struct ovn_flow *i, *next;
- HMAP_FOR_EACH_SAFE (i, next, hmap_node, &installed_flows) {
- struct ovn_flow *d = ovn_flow_lookup(flow_table, i);
+ HMAP_FOR_EACH_SAFE (i, next, match_hmap_node, &installed_flows) {
+ struct ovn_flow *d = ovn_flow_lookup(&flow_table->match_flow_table,
+ i, false);
if (!d) {
/* Installed flow is no longer desirable. Delete it from the
* switch and from installed_flows. */
@@ -935,9 +1033,13 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
add_flow_mod(&fm, &msgs);
ovn_flow_log(i, "removing installed");
- hmap_remove(&installed_flows, &i->hmap_node);
+ hmap_remove(&installed_flows, &i->match_hmap_node);
ovn_flow_destroy(i);
} else {
+ if (!uuid_equals(&i->sb_uuid, &d->sb_uuid)) {
+ /* Update installed flow's UUID. */
+ i->sb_uuid = d->sb_uuid;
+ }
if (!ofpacts_equal(i->ofpacts, i->ofpacts_len,
d->ofpacts, d->ofpacts_len)) {
/* Update actions in installed flow. */
@@ -954,38 +1056,37 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
/* Replace 'i''s actions by 'd''s. */
free(i->ofpacts);
- i->ofpacts = d->ofpacts;
+ i->ofpacts = xmemdup(d->ofpacts, d->ofpacts_len);
i->ofpacts_len = d->ofpacts_len;
- d->ofpacts = NULL;
- d->ofpacts_len = 0;
}
- hmap_remove(flow_table, &d->hmap_node);
- ovn_flow_destroy(d);
}
}
- /* The previous loop removed from 'flow_table' all of the flows that are
- * already installed. Thus, any flows remaining in 'flow_table' need to
- * be added to the flow table. */
+ /* Iterate through the desired flows and add those that aren't found
+ * in the installed flow table. */
struct ovn_flow *d;
- HMAP_FOR_EACH_SAFE (d, next, hmap_node, flow_table) {
- /* Send flow_mod to add flow. */
- struct ofputil_flow_mod fm = {
- .match = d->match,
- .priority = d->priority,
- .table_id = d->table_id,
- .ofpacts = d->ofpacts,
- .ofpacts_len = d->ofpacts_len,
- .new_cookie = htonll(d->cookie),
- .command = OFPFC_ADD,
- };
- add_flow_mod(&fm, &msgs);
- ovn_flow_log(d, "adding installed");
-
- /* Move 'd' from 'flow_table' to installed_flows. */
- hmap_remove(flow_table, &d->hmap_node);
- hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash);
+ HMAP_FOR_EACH (d, match_hmap_node, &flow_table->match_flow_table) {
+ i = ovn_flow_lookup(&installed_flows, d, false);
+ if (!i) {
+ /* Send flow_mod to add flow. */
+ struct ofputil_flow_mod fm = {
+ .match = d->match,
+ .priority = d->priority,
+ .table_id = d->table_id,
+ .ofpacts = d->ofpacts,
+ .ofpacts_len = d->ofpacts_len,
+ .new_cookie = htonll(d->cookie),
+ .command = OFPFC_ADD,
+ };
+ add_flow_mod(&fm, &msgs);
+ ovn_flow_log(d, "adding installed");
+
+ /* Copy 'd' from 'flow_table' to installed_flows. */
+ struct ovn_flow *new_node = ofctrl_dup_flow(d);
+ hmap_insert(&installed_flows, &new_node->match_hmap_node,
+ new_node->match_hmap_node.hash);
+ }
}
/* Iterate through the installed groups from previous runs. If they
@@ -1010,11 +1111,11 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
}
free(group_string);
ofputil_uninit_group_mod(&gm);
- ovn_extend_table_remove(groups, installed);
+ ovn_extend_table_remove_existing(groups, installed);
}
- /* Move the contents of groups->desired to groups->existing. */
- ovn_extend_table_move(groups);
+ /* Sync the contents of groups->desired to groups->existing. */
+ ovn_extend_table_sync(groups);
/* Iterate through the installed meters from previous runs. If they
* are not needed delete them. */
@@ -1037,11 +1138,11 @@ ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
free(error);
}
free(meter_string);
- ovn_extend_table_remove(meters, m_installed);
+ ovn_extend_table_remove_existing(meters, m_installed);
}
- /* Move the contents of meters->desired to meters->existing. */
- ovn_extend_table_move(meters);
+ /* Sync the contents of meters->desired to meters->existing. */
+ ovn_extend_table_sync(meters);
if (!ovs_list_is_empty(&msgs)) {
/* Add a barrier to the list of messages. */
@@ -21,6 +21,7 @@
#include "openvswitch/meta-flow.h"
#include "ovsdb-idl.h"
+#include "hindex.h"
struct ovn_extend_table;
struct hmap;
@@ -29,15 +30,24 @@ struct ofpbuf;
struct ovsrec_bridge;
struct shash;
+struct ovn_desired_flow_table {
+ /* Hash map flow table using flow match conditions as hash key.*/
+ struct hmap match_flow_table;
+
+ /* SB uuid index for the nodes in match_flow_table.*/
+ struct hindex uuid_flow_table;
+};
+
/* Interface for OVN main loop. */
void ofctrl_init(struct ovn_extend_table *group_table,
struct ovn_extend_table *meter_table);
void ofctrl_run(const struct ovsrec_bridge *br_int,
struct shash *pending_ct_zones);
enum mf_field_id ofctrl_get_mf_field_id(void);
-bool ofctrl_can_put(void);
-void ofctrl_put(struct hmap *flow_table, struct shash *pending_ct_zones,
- int64_t nb_cfg);
+void ofctrl_put(struct ovn_desired_flow_table *,
+ struct shash *pending_ct_zones,
+ int64_t nb_cfg,
+ bool flow_changed);
void ofctrl_wait(void);
void ofctrl_destroy(void);
int64_t ofctrl_get_cur_cfg(void);
@@ -51,8 +61,15 @@ char *ofctrl_inject_pkt(const struct ovsrec_bridge *br_int,
const struct shash *port_groups);
/* Flow table interfaces to the rest of ovn-controller. */
-void ofctrl_add_flow(struct hmap *desired_flows, uint8_t table_id,
+void ofctrl_add_flow(struct ovn_desired_flow_table *, uint8_t table_id,
uint16_t priority, uint64_t cookie,
- const struct match *, const struct ofpbuf *ofpacts);
+ const struct match *, const struct ofpbuf *ofpacts,
+ const struct uuid *);
+
+void ofctrl_remove_flows(struct ovn_desired_flow_table *, const struct uuid *);
+
+void ovn_desired_flow_table_init(struct ovn_desired_flow_table *);
+void ovn_desired_flow_table_clear(struct ovn_desired_flow_table *);
+void ovn_desired_flow_table_destroy(struct ovn_desired_flow_table *);
#endif /* ovn/ofctrl.h */
@@ -795,11 +795,13 @@ en_runtime_data_run(struct engine_node *node)
struct ed_type_flow_output {
/* desired flows */
- struct hmap flow_table;
+ struct ovn_desired_flow_table flow_table;
/* group ids for load balancing */
struct ovn_extend_table group_table;
/* meter ids for QoS */
struct ovn_extend_table meter_table;
+ /* conjunction id offset */
+ uint32_t conj_id_ofs;
};
static void
@@ -807,9 +809,10 @@ en_flow_output_init(struct engine_node *node)
{
struct ed_type_flow_output *data =
(struct ed_type_flow_output *)node->data;
- hmap_init(&data->flow_table);
+ ovn_desired_flow_table_init(&data->flow_table);
ovn_extend_table_init(&data->group_table);
ovn_extend_table_init(&data->meter_table);
+ data->conj_id_ofs = 1;
}
static void
@@ -817,7 +820,7 @@ en_flow_output_cleanup(struct engine_node *node)
{
struct ed_type_flow_output *data =
(struct ed_type_flow_output *)node->data;
- hmap_destroy(&data->flow_table);
+ ovn_desired_flow_table_destroy(&data->flow_table);
ovn_extend_table_destroy(&data->group_table);
ovn_extend_table_destroy(&data->meter_table);
}
@@ -849,22 +852,27 @@ en_flow_output_run(struct engine_node *node)
engine_ovsdb_node_get_index(
engine_get_input("SB_chassis", node),
"name");
- const struct sbrec_chassis *chassis
- = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
+ const struct sbrec_chassis *chassis = NULL;
+ if (chassis_id) {
+ chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
+ }
ovs_assert(br_int && chassis);
struct ed_type_flow_output *fo =
(struct ed_type_flow_output *)node->data;
- struct hmap *flow_table = &fo->flow_table;
+ struct ovn_desired_flow_table *flow_table = &fo->flow_table;
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;
static bool first_run = true;
if (first_run) {
first_run = false;
} else {
- hmap_clear(flow_table);
+ ovn_desired_flow_table_clear(flow_table);
+ ovn_extend_table_clear(group_table, false /* desired */);
+ ovn_extend_table_clear(meter_table, false /* desired */);
}
struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath =
@@ -893,6 +901,7 @@ en_flow_output_run(struct engine_node *node)
(struct sbrec_mac_binding_table *)EN_OVSDB_GET(
engine_get_input("SB_mac_binding", node));
+ *conj_id_ofs = 1;
lflow_run(sbrec_chassis_by_name,
sbrec_multicast_group_by_name_datapath,
sbrec_port_binding_by_name,
@@ -901,7 +910,7 @@ 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);
+ flow_table, group_table, meter_table, conj_id_ofs);
enum mf_field_id mff_ovn_geneve = ofctrl_get_mf_field_id();
@@ -923,9 +932,84 @@ en_flow_output_run(struct engine_node *node)
local_datapaths, local_lports,
active_tunnels,
flow_table);
+
node->changed = true;
}
+static bool
+flow_output_sb_logical_flow_handler(struct engine_node *node)
+{
+ struct ed_type_runtime_data *data =
+ (struct ed_type_runtime_data *)engine_get_input(
+ "runtime_data", node)->data;
+ struct hmap *local_datapaths = &data->local_datapaths;
+ struct sset *local_lport_ids = &data->local_lport_ids;
+ struct sset *active_tunnels = &data->active_tunnels;
+ struct shash *addr_sets = &data->addr_sets;
+ struct shash *port_groups = &data->port_groups;
+
+ struct ovsrec_open_vswitch_table *ovs_table =
+ (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET(
+ engine_get_input("OVS_open_vswitch", node));
+ struct ovsrec_bridge_table *bridge_table =
+ (struct ovsrec_bridge_table *)EN_OVSDB_GET(
+ engine_get_input("OVS_bridge", node));
+ const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table);
+ const char *chassis_id = get_chassis_id(ovs_table);
+
+ struct ovsdb_idl_index *sbrec_chassis_by_name =
+ engine_ovsdb_node_get_index(
+ engine_get_input("SB_chassis", node),
+ "name");
+ const struct sbrec_chassis *chassis = NULL;
+ if (chassis_id) {
+ chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
+ }
+
+ ovs_assert(br_int && chassis);
+
+ struct ed_type_flow_output *fo =
+ (struct ed_type_flow_output *)node->data;
+ struct ovn_desired_flow_table *flow_table = &fo->flow_table;
+ 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 ovsdb_idl_index *sbrec_multicast_group_by_name_datapath =
+ engine_ovsdb_node_get_index(
+ engine_get_input("SB_multicast_group", node),
+ "name_datapath");
+
+ struct ovsdb_idl_index *sbrec_port_binding_by_name =
+ engine_ovsdb_node_get_index(
+ engine_get_input("SB_port_binding", node),
+ "name");
+
+ struct sbrec_dhcp_options_table *dhcp_table =
+ (struct sbrec_dhcp_options_table *)EN_OVSDB_GET(
+ engine_get_input("SB_dhcp_options", node));
+
+ struct sbrec_dhcpv6_options_table *dhcpv6_table =
+ (struct sbrec_dhcpv6_options_table *)EN_OVSDB_GET(
+ engine_get_input("SB_dhcpv6_options", node));
+
+ struct sbrec_logical_flow_table *logical_flow_table =
+ (struct sbrec_logical_flow_table *)EN_OVSDB_GET(
+ engine_get_input("SB_logical_flow", node));
+
+ bool handled = lflow_handle_changed_flows(sbrec_chassis_by_name,
+ sbrec_multicast_group_by_name_datapath,
+ sbrec_port_binding_by_name,
+ dhcp_table, dhcpv6_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);
+
+ node->changed = true;
+ return handled;
+}
+
int
main(int argc, char *argv[])
{
@@ -1021,13 +1105,11 @@ main(int argc, char *argv[])
engine_add_input(&en_flow_output, &en_sb_chassis, NULL);
engine_add_input(&en_flow_output, &en_sb_encap, NULL);
- engine_add_input(&en_flow_output, &en_sb_address_set, NULL);
- engine_add_input(&en_flow_output, &en_sb_port_group, NULL);
engine_add_input(&en_flow_output, &en_sb_multicast_group, NULL);
engine_add_input(&en_flow_output, &en_sb_datapath_binding, NULL);
engine_add_input(&en_flow_output, &en_sb_port_binding, NULL);
engine_add_input(&en_flow_output, &en_sb_mac_binding, NULL);
- engine_add_input(&en_flow_output, &en_sb_logical_flow, NULL);
+ engine_add_input(&en_flow_output, &en_sb_logical_flow, flow_output_sb_logical_flow_handler);
engine_add_input(&en_flow_output, &en_sb_dhcp_options, NULL);
engine_add_input(&en_flow_output, &en_sb_dhcpv6_options, NULL);
engine_add_input(&en_flow_output, &en_sb_dns, NULL);
@@ -1059,6 +1141,7 @@ main(int argc, char *argv[])
uint64_t engine_run_id = 0;
uint64_t old_engine_run_id = 0;
+
/* Main loop. */
exiting = false;
while (!exiting) {
@@ -1137,29 +1220,24 @@ main(int argc, char *argv[])
sbrec_chassis_table_get(ovnsb_idl_loop.idl),
chassis_id);
- if (ofctrl_can_put()) {
- stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME,
- time_msec());
- engine_run(&en_flow_output, ++engine_run_id);
- stopwatch_stop(CONTROLLER_LOOP_STOPWATCH_NAME,
- time_msec());
-
- if (ovs_idl_txn) {
- commit_ct_zones(br_int, &ed_runtime_data.pending_ct_zones);
- bfd_run(sbrec_chassis_by_name,
- sbrec_port_binding_by_datapath,
- ovsrec_interface_table_get(ovs_idl_loop.idl),
- br_int, chassis,
- &ed_runtime_data.local_datapaths);
- }
- if (en_flow_output.changed) {
- ofctrl_put(&ed_flow_output.flow_table,
- &ed_runtime_data.pending_ct_zones,
- get_nb_cfg(sbrec_sb_global_table_get(
- ovnsb_idl_loop.idl)));
- }
+ stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME,
+ time_msec());
+ engine_run(&en_flow_output, ++engine_run_id);
+ stopwatch_stop(CONTROLLER_LOOP_STOPWATCH_NAME,
+ time_msec());
+ if (ovs_idl_txn) {
+ commit_ct_zones(br_int, &ed_runtime_data.pending_ct_zones);
+ bfd_run(sbrec_chassis_by_name,
+ sbrec_port_binding_by_datapath,
+ ovsrec_interface_table_get(ovs_idl_loop.idl),
+ br_int, chassis,
+ &ed_runtime_data.local_datapaths);
}
-
+ ofctrl_put(&ed_flow_output.flow_table,
+ &ed_runtime_data.pending_ct_zones,
+ get_nb_cfg(sbrec_sb_global_table_get(
+ ovnsb_idl_loop.idl)),
+ en_flow_output.changed);
pinctrl_run(ovnsb_idl_txn, sbrec_chassis_by_name,
sbrec_datapath_binding_by_key,
sbrec_port_binding_by_datapath,
@@ -1171,9 +1249,11 @@ main(int argc, char *argv[])
&ed_runtime_data.local_datapaths,
&ed_runtime_data.active_tunnels);
- update_sb_monitors(ovnsb_idl_loop.idl, chassis,
- &ed_runtime_data.local_lports,
- &ed_runtime_data.local_datapaths);
+ if (en_runtime_data.changed) {
+ update_sb_monitors(ovnsb_idl_loop.idl, chassis,
+ &ed_runtime_data.local_lports,
+ &ed_runtime_data.local_datapaths);
+ }
}
if (old_engine_run_id == engine_run_id) {
@@ -44,6 +44,9 @@
VLOG_DEFINE_THIS_MODULE(physical);
+/* UUID to identify OF flows not associated with ovsdb rows. */
+static struct uuid *hc_uuid = NULL;
+
void
physical_register_ovs_idl(struct ovsdb_idl *ovs_idl)
{
@@ -188,9 +191,10 @@ get_zone_ids(const struct sbrec_port_binding *binding,
}
static void
-put_local_common_flows(uint32_t dp_key, uint32_t port_key,
+put_local_common_flows(struct ovn_desired_flow_table *flow_table,
+ uint32_t dp_key, uint32_t port_key,
bool nested_container, const struct zone_ids *zone_ids,
- struct ofpbuf *ofpacts_p, struct hmap *flow_table)
+ struct ofpbuf *ofpacts_p)
{
struct match match;
@@ -224,7 +228,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
/* Resubmit to table 34. */
put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
/* Table 34, Priority 100.
* =======================
@@ -239,7 +243,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, port_key);
match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
/* Table 64, Priority 100.
* =======================
@@ -263,7 +267,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p);
put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
}
static void
@@ -299,8 +303,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
const struct hmap *local_datapaths,
const struct sbrec_port_binding *binding,
const struct sbrec_chassis *chassis,
- struct ofpbuf *ofpacts_p,
- struct hmap *flow_table)
+ struct ovn_desired_flow_table *flow_table,
+ struct ofpbuf *ofpacts_p)
{
uint32_t dp_key = binding->datapath->tunnel_key;
uint32_t port_key = binding->tunnel_key;
@@ -328,8 +332,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
}
struct zone_ids binding_zones = get_zone_ids(binding, ct_zones);
- put_local_common_flows(dp_key, port_key, false, &binding_zones,
- ofpacts_p, flow_table);
+ put_local_common_flows(flow_table, dp_key, port_key, false,
+ &binding_zones, ofpacts_p);
match_init_catchall(&match);
ofpbuf_clear(ofpacts_p);
@@ -356,7 +360,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
ofpact_finish_CLONE(ofpacts_p, &clone);
ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
return;
}
@@ -425,7 +429,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
}
ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
goto out;
}
@@ -523,8 +527,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
*/
struct zone_ids zone_ids = get_zone_ids(binding, ct_zones);
- put_local_common_flows(dp_key, port_key, nested_container, &zone_ids,
- ofpacts_p, flow_table);
+ put_local_common_flows(flow_table, dp_key, port_key, nested_container,
+ &zone_ids, ofpacts_p);
/* Table 0, Priority 150 and 100.
* ==============================
@@ -568,7 +572,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
/* Resubmit to first logical ingress pipeline table. */
put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p);
ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG,
- tag ? 150 : 100, 0, &match, ofpacts_p);
+ tag ? 150 : 100, 0, &match, ofpacts_p, hc_uuid);
if (!tag && (!strcmp(binding->type, "localnet")
|| !strcmp(binding->type, "l2gateway"))) {
@@ -578,7 +582,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
* action. */
ofpbuf_pull(ofpacts_p, ofpacts_orig_size);
match_set_dl_tci_masked(&match, 0, htons(VLAN_CFI));
- ofctrl_add_flow(flow_table, 0, 100, 0, &match, ofpacts_p);
+ ofctrl_add_flow(flow_table, 0, 100, 0, &match, ofpacts_p, hc_uuid);
}
/* Table 65, Priority 100.
@@ -606,7 +610,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
ofpact_put_STRIP_VLAN(ofpacts_p);
}
ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
} else if (!tun && !is_ha_remote) {
/* Remote port connected by localnet port */
/* Table 33, priority 100.
@@ -629,7 +633,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
/* Resubmit to table 33. */
put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
} else {
/* Remote port connected by tunnel */
@@ -720,7 +724,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_chassis_by_name,
ofpact_finish_BUNDLE(ofpacts_p, &bundle);
}
ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
}
out:
if (gateway_chassis) {
@@ -736,7 +740,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
const struct sbrec_multicast_group *mc,
struct ofpbuf *ofpacts_p,
struct ofpbuf *remote_ofpacts_p,
- struct hmap *flow_table)
+ struct ovn_desired_flow_table *flow_table)
{
uint32_t dp_key = mc->datapath->tunnel_key;
if (!get_local_datapath(local_datapaths, dp_key)) {
@@ -812,7 +816,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
put_load(mc->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
- &match, ofpacts_p);
+ &match, ofpacts_p, hc_uuid);
}
/* Table 32, priority 100.
@@ -850,7 +854,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
put_resubmit(OFTABLE_LOCAL_OUTPUT, remote_ofpacts_p);
}
ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, 0,
- &match, remote_ofpacts_p);
+ &match, remote_ofpacts_p, hc_uuid);
}
}
sset_destroy(&remote_chassis);
@@ -879,8 +883,13 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
const struct hmap *local_datapaths,
const struct sset *local_lports,
const struct sset *active_tunnels,
- struct hmap *flow_table)
+ struct ovn_desired_flow_table *flow_table)
{
+ if (!hc_uuid) {
+ hc_uuid = xmalloc(sizeof(struct uuid));
+ uuid_generate(hc_uuid);
+ }
+
/* This bool tracks physical mapping changes. */
bool physical_map_changed = false;
@@ -1004,7 +1013,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
mff_ovn_geneve, ct_zones,
active_tunnels,
local_datapaths, binding, chassis,
- &ofpacts, flow_table);
+ flow_table, &ofpacts);
}
/* Handle output to multicast groups, in tables 32 and 33. */
@@ -1054,7 +1063,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0, &match,
- &ofpacts);
+ &ofpacts, hc_uuid);
}
/* Add flows for VXLAN encapsulations. Due to the limited amount of
@@ -1087,7 +1096,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts);
ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0, &match,
- &ofpacts);
+ &ofpacts, hc_uuid);
}
}
@@ -1108,7 +1117,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
ofpbuf_clear(&ofpacts);
put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
- &match, &ofpacts);
+ &match, &ofpacts, hc_uuid);
/* Table 32, priority 150.
* =======================
@@ -1122,7 +1131,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
ofpbuf_clear(&ofpacts);
put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
- &match, &ofpacts);
+ &match, &ofpacts, hc_uuid);
/* Table 32, priority 150.
* =======================
@@ -1145,7 +1154,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, pb->tunnel_key);
match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
- &match, &ofpacts);
+ &match, &ofpacts, hc_uuid);
}
}
@@ -1157,7 +1166,8 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
match_init_catchall(&match);
ofpbuf_clear(&ofpacts);
put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
- ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match, &ofpacts);
+ ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match, &ofpacts,
+ hc_uuid);
/* Table 34, Priority 0.
* =======================
@@ -1172,7 +1182,7 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
}
put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE, &ofpacts);
ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 0, 0, &match,
- &ofpacts);
+ &ofpacts, hc_uuid);
/* Table 64, Priority 0.
* =======================
@@ -1182,7 +1192,8 @@ physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
match_init_catchall(&match);
ofpbuf_clear(&ofpacts);
put_resubmit(OFTABLE_LOG_TO_PHY, &ofpacts);
- ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 0, 0, &match, &ofpacts);
+ ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 0, 0, &match, &ofpacts,
+ hc_uuid);
ofpbuf_uninit(&ofpacts);
@@ -54,6 +54,6 @@ void physical_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
const struct hmap *local_datapaths,
const struct sset *local_lports,
const struct sset *active_tunnels,
- struct hmap *flow_table);
+ struct ovn_desired_flow_table *);
#endif /* ovn/physical.h */
@@ -1049,7 +1049,8 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
recirc_table, zone_reg);
}
- table_id = ovn_extend_table_assign_id(ep->group_table, &ds);
+ table_id = ovn_extend_table_assign_id(ep->group_table, &ds,
+ ep->lflow_uuid);
ds_destroy(&ds);
if (table_id == EXT_TABLE_ID_INVALID) {
return;
@@ -2228,7 +2229,8 @@ encode_SET_METER(const struct ovnact_set_meter *cl,
cl->rate);
}
- table_id = ovn_extend_table_assign_id(ep->meter_table, &ds);
+ table_id = ovn_extend_table_assign_id(ep->meter_table, &ds,
+ ep->lflow_uuid);
if (table_id == EXT_TABLE_ID_INVALID) {
ds_destroy(&ds);
return;
@@ -17,6 +17,7 @@
#include <config.h>
#include "bitmap.h"
#include "hash.h"
+#include "lib/uuid.h"
#include "openvswitch/vlog.h"
#include "ovn/lib/extend-table.h"
@@ -89,9 +90,10 @@ ovn_extend_table_clear(struct ovn_extend_table *table, bool existing)
}
}
+/* Remove an entry from existing table */
void
-ovn_extend_table_remove(struct ovn_extend_table *table,
- struct ovn_extend_table_info *existing)
+ovn_extend_table_remove_existing(struct ovn_extend_table *table,
+ struct ovn_extend_table_info *existing)
{
/* Remove 'existing' from 'groups->existing' */
hmap_remove(&table->existing, &existing->hmap_node);
@@ -102,21 +104,50 @@ ovn_extend_table_remove(struct ovn_extend_table *table,
free(existing);
}
+/* Remove entries in desired table that are created by the lflow_uuid */
void
-ovn_extend_table_move(struct ovn_extend_table *table)
+ovn_extend_table_remove_desired(struct ovn_extend_table *table,
+ const struct uuid *lflow_uuid)
+{
+ struct ovn_extend_table_info *e, *next_e;
+ HMAP_FOR_EACH_SAFE (e, next_e, hmap_node, &table->desired) {
+ if (uuid_equals(&e->lflow_uuid, lflow_uuid)) {
+ hmap_remove(&table->desired, &e->hmap_node);
+ ds_destroy(&e->info);
+ if (e->new_table_id) {
+ bitmap_set0(table->table_ids, e->table_id);
+ }
+ free(e);
+ }
+ }
+
+}
+
+static struct ovn_extend_table_info*
+ovn_extend_info_clone(struct ovn_extend_table_info *source)
+{
+ struct ovn_extend_table_info *clone = xmalloc(sizeof *clone);
+ ds_clone(&clone->info, &source->info);
+ clone->table_id = source->table_id;
+ clone->new_table_id = source->new_table_id;
+ clone->hmap_node.hash = source->hmap_node.hash;
+ clone->lflow_uuid = source->lflow_uuid;
+ return clone;
+}
+
+void
+ovn_extend_table_sync(struct ovn_extend_table *table)
{
struct ovn_extend_table_info *desired, *next;
- /* Move the contents of desired to existing. */
+ /* Copy the contents of desired to existing. */
HMAP_FOR_EACH_SAFE (desired, next, hmap_node, &table->desired) {
- hmap_remove(&table->desired, &desired->hmap_node);
-
if (!ovn_extend_table_lookup(&table->existing, desired)) {
- hmap_insert(&table->existing, &desired->hmap_node,
- desired->hmap_node.hash);
- } else {
- ds_destroy(&desired->info);
- free(desired);
+ desired->new_table_id = false;
+ struct ovn_extend_table_info *clone =
+ ovn_extend_info_clone(desired);
+ hmap_insert(&table->existing, &clone->hmap_node,
+ clone->hmap_node.hash);
}
}
}
@@ -124,7 +155,8 @@ ovn_extend_table_move(struct ovn_extend_table *table)
/* Assign a new table ID for the table information from the bitmap.
* If it already exists, return the old ID. */
uint32_t
-ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds)
+ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds,
+ struct uuid lflow_uuid)
{
uint32_t table_id = 0, hash;
struct ovn_extend_table_info *table_info;
@@ -133,7 +165,8 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds)
/* Check whether we have non installed but allocated group_id. */
HMAP_FOR_EACH_WITH_HASH (table_info, hmap_node, hash, &table->desired) {
- if (!strcmp(ds_cstr(&table_info->info), ds_cstr(ds))) {
+ if (!strcmp(ds_cstr(&table_info->info), ds_cstr(ds)) &&
+ table_info->new_table_id) {
return table_info->table_id;
}
}
@@ -165,6 +198,7 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, struct ds *ds)
table_info->table_id = table_id;
table_info->hmap_node.hash = hash;
table_info->new_table_id = new_table_id;
+ table_info->lflow_uuid = lflow_uuid;
hmap_insert(&table->desired,
&table_info->hmap_node, table_info->hmap_node.hash);
@@ -23,6 +23,7 @@
#include "openvswitch/dynamic-string.h"
#include "openvswitch/hmap.h"
#include "openvswitch/list.h"
+#include "openvswitch/uuid.h"
/* Used to manage expansion tables associated with Flow table,
* such as the Group Table or Meter Table. */
@@ -37,6 +38,7 @@ struct ovn_extend_table {
struct ovn_extend_table_info {
struct hmap_node hmap_node;
struct ds info; /* Details string for the table entity. */
+ struct uuid lflow_uuid;
uint32_t table_id;
bool new_table_id; /* 'True' if 'table_id' was reserved from
* ovn_extend_table's 'table_ids' bitmap. */
@@ -51,14 +53,18 @@ struct ovn_extend_table_info *ovn_extend_table_lookup(
void ovn_extend_table_clear(struct ovn_extend_table *, bool);
-void ovn_extend_table_remove(struct ovn_extend_table *,
- struct ovn_extend_table_info *);
+void ovn_extend_table_remove_existing(struct ovn_extend_table *,
+ struct ovn_extend_table_info *);
-/* Move the contents of desired to existing. */
-void ovn_extend_table_move(struct ovn_extend_table *);
+void ovn_extend_table_remove_desired(struct ovn_extend_table *,
+ const struct uuid *lflow_uuid);
+
+/* Copy the contents of desired to existing. */
+void ovn_extend_table_sync(struct ovn_extend_table *);
uint32_t ovn_extend_table_assign_id(struct ovn_extend_table *,
- struct ds *);
+ struct ds *,
+ struct uuid lflow_uuid);
/* Iterates 'DESIRED' through all of the 'ovn_extend_table_info's in
* 'TABLE'->desired that are not in 'TABLE'->existing. (The loop body
Persistents flow-table and implements change handler of flow_output for SB lflow changes. Signed-off-by: Han Zhou <hzhou8@ebay.com> --- include/ovn/actions.h | 3 + ovn/controller/lflow.c | 180 ++++++++++++++++++++++++------ ovn/controller/lflow.h | 25 ++++- ovn/controller/ofctrl.c | 241 ++++++++++++++++++++++++++++------------ ovn/controller/ofctrl.h | 27 ++++- ovn/controller/ovn-controller.c | 152 +++++++++++++++++++------ ovn/controller/physical.c | 73 ++++++------ ovn/controller/physical.h | 2 +- ovn/lib/actions.c | 6 +- ovn/lib/extend-table.c | 60 +++++++--- ovn/lib/extend-table.h | 16 ++- 11 files changed, 587 insertions(+), 198 deletions(-)