summaryrefslogtreecommitdiff
path: root/ovn/controller
diff options
context:
space:
mode:
Diffstat (limited to 'ovn/controller')
-rw-r--r--ovn/controller/chassis.c15
-rw-r--r--ovn/controller/chassis.h5
-rw-r--r--ovn/controller/ofctrl.c163
-rw-r--r--ovn/controller/ofctrl.h5
-rw-r--r--ovn/controller/ovn-controller.c19
5 files changed, 176 insertions, 31 deletions
diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c
index 502e74d50..a1545ecdd 100644
--- a/ovn/controller/chassis.c
+++ b/ovn/controller/chassis.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015 Nicira, Inc.
+/* Copyright (c) 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,11 +64,13 @@ get_bridge_mappings(const struct smap *ext_ids)
return bridge_mappings ? bridge_mappings : "";
}
-void
+/* Returns this chassis's Chassis record, if it is available and is currently
+ * amenable to a transaction. */
+const struct sbrec_chassis *
chassis_run(struct controller_ctx *ctx, const char *chassis_id)
{
if (!ctx->ovnsb_idl_txn) {
- return;
+ return NULL;
}
const struct ovsrec_open_vswitch *cfg;
@@ -78,14 +80,14 @@ chassis_run(struct controller_ctx *ctx, const char *chassis_id)
cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
if (!cfg) {
VLOG_INFO("No Open_vSwitch row defined.");
- return;
+ return NULL;
}
encap_type = smap_get(&cfg->external_ids, "ovn-encap-type");
encap_ip = smap_get(&cfg->external_ids, "ovn-encap-ip");
if (!encap_type || !encap_ip) {
VLOG_INFO("Need to specify an encap type and ip");
- return;
+ return NULL;
}
char *tokstr = xstrdup(encap_type);
@@ -144,7 +146,7 @@ chassis_run(struct controller_ctx *ctx, const char *chassis_id)
if (same) {
/* Nothing changed. */
inited = true;
- return;
+ return chassis_rec;
} else if (!inited) {
struct ds cur_encaps = DS_EMPTY_INITIALIZER;
for (int i = 0; i < chassis_rec->n_encaps; i++) {
@@ -190,6 +192,7 @@ chassis_run(struct controller_ctx *ctx, const char *chassis_id)
free(encaps);
inited = true;
+ return chassis_rec;
}
/* Returns true if the database is all cleaned up, false if more work is
diff --git a/ovn/controller/chassis.h b/ovn/controller/chassis.h
index 26017d06c..a14da1cf3 100644
--- a/ovn/controller/chassis.h
+++ b/ovn/controller/chassis.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015 Nicira, Inc.
+/* Copyright (c) 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,8 @@ struct ovsdb_idl;
struct ovsrec_bridge;
void chassis_register_ovs_idl(struct ovsdb_idl *);
-void chassis_run(struct controller_ctx *, const char *chassis_id);
+const struct sbrec_chassis *chassis_run(struct controller_ctx *,
+ const char *chassis_id);
bool chassis_cleanup(struct controller_ctx *, const char *chassis_id);
#endif /* ovn/chassis.h */
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index f0451b7c1..95f84d18a 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -68,14 +68,9 @@ 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 *);
-static ovs_be32 queue_msg(struct ofpbuf *);
-static void queue_flow_mod(struct ofputil_flow_mod *);
-
/* OpenFlow connection to the switch. */
static struct rconn *swconn;
-static void queue_group_mod(struct ofputil_group_mod *);
-
/* Last seen sequence number for 'swconn'. When this differs from
* rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
static unsigned int seqno;
@@ -93,6 +88,30 @@ enum ofctrl_state {
#undef STATE
};
+/* An in-flight update to the switch's flow table.
+ *
+ * When we receive a barrier reply from the switch with the given 'xid', we
+ * know that the switch is caught up to northbound database sequence number
+ * 'nb_cfg' (and make that available to the client via ofctrl_get_cur_cfg(), so
+ * that it can store it into our Chassis record's nb_cfg column). */
+struct ofctrl_flow_update {
+ struct ovs_list list_node; /* In 'flow_updates'. */
+ ovs_be32 xid; /* OpenFlow transaction ID for barrier. */
+ int64_t nb_cfg; /* Northbound database sequence number. */
+};
+
+static struct ofctrl_flow_update *
+ofctrl_flow_update_from_list_node(const struct ovs_list *list_node)
+{
+ return CONTAINER_OF(list_node, struct ofctrl_flow_update, list_node);
+}
+
+/* Currently in-flight updates. */
+static struct ovs_list flow_updates;
+
+/* nb_cfg of latest committed flow update. */
+static int64_t cur_cfg;
+
/* Current state. */
static enum ofctrl_state state;
@@ -116,10 +135,14 @@ static struct group_table *groups;
* S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */
static enum mf_field_id mff_ovn_geneve;
+static ovs_be32 queue_msg(struct ofpbuf *);
+
static void ovn_flow_table_destroy(void);
+static struct ofpbuf *encode_flow_mod(struct ofputil_flow_mod *);
static void ovn_group_table_clear(struct group_table *group_table,
bool existing);
+static struct ofpbuf *encode_group_mod(const struct ofputil_group_mod *);
static void ofctrl_recv(const struct ofp_header *, enum ofptype);
@@ -132,6 +155,7 @@ ofctrl_init(void)
swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
tx_counter = rconn_packet_counter_create();
hmap_init(&installed_flows);
+ ovs_list_init(&flow_updates);
}
/* S_NEW, for a new connection.
@@ -330,16 +354,17 @@ run_S_CLEAR_FLOWS(void)
.table_id = OFPTT_ALL,
.command = OFPFC_DELETE,
};
- queue_flow_mod(&fm);
+ queue_msg(encode_flow_mod(&fm));
VLOG_DBG("clearing all flows");
+ /* Send a group_mod to delete all groups. */
struct ofputil_group_mod gm;
memset(&gm, 0, sizeof gm);
gm.command = OFPGC11_DELETE;
gm.group_id = OFPG_ALL;
gm.command_bucket_id = OFPG15_BUCKET_ALL;
ovs_list_init(&gm.buckets);
- queue_group_mod(&gm);
+ queue_msg(encode_group_mod(&gm));
ofputil_bucket_list_destroy(&gm.buckets);
/* Clear installed_flows, to match the state of the switch. */
@@ -350,6 +375,13 @@ run_S_CLEAR_FLOWS(void)
ovn_group_table_clear(groups, true);
}
+ /* All flow updates are irrelevant now. */
+ struct ofctrl_flow_update *fup, *next;
+ LIST_FOR_EACH_SAFE (fup, next, list_node, &flow_updates) {
+ ovs_list_remove(&fup->list_node);
+ free(fup);
+ }
+
state = S_UPDATE_FLOWS;
}
@@ -378,7 +410,19 @@ run_S_UPDATE_FLOWS(void)
static void
recv_S_UPDATE_FLOWS(const struct ofp_header *oh, enum ofptype type)
{
- ofctrl_recv(oh, type);
+ if (type == OFPTYPE_BARRIER_REPLY && !ovs_list_is_empty(&flow_updates)) {
+ struct ofctrl_flow_update *fup = ofctrl_flow_update_from_list_node(
+ ovs_list_front(&flow_updates));
+ if (fup->xid == oh->xid) {
+ if (fup->nb_cfg >= cur_cfg) {
+ cur_cfg = fup->nb_cfg;
+ }
+ ovs_list_remove(&fup->list_node);
+ free(fup);
+ }
+ } else {
+ ofctrl_recv(oh, type);
+ }
}
/* Runs the OpenFlow state machine against 'br_int', which is local to the
@@ -476,6 +520,12 @@ ofctrl_destroy(void)
ovn_flow_table_destroy();
rconn_packet_counter_destroy(tx_counter);
}
+
+int64_t
+ofctrl_get_cur_cfg(void)
+{
+ return cur_cfg;
+}
static ovs_be32
queue_msg(struct ofpbuf *msg)
@@ -765,15 +815,21 @@ ovn_flow_table_destroy(void)
/* Flow table update. */
-static void
-queue_flow_mod(struct ofputil_flow_mod *fm)
+static struct ofpbuf *
+encode_flow_mod(struct ofputil_flow_mod *fm)
{
fm->buffer_id = UINT32_MAX;
fm->out_port = OFPP_ANY;
fm->out_group = OFPG_ANY;
- queue_msg(ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM));
+ return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM);
}
+static void
+add_flow_mod(struct ofputil_flow_mod *fm, struct ovs_list *msgs)
+{
+ struct ofpbuf *msg = encode_flow_mod(fm);
+ ovs_list_push_back(msgs, &msg->list_node);
+}
/* group_table. */
@@ -811,10 +867,17 @@ ovn_group_table_clear(struct group_table *group_table, bool existing)
}
}
+static struct ofpbuf *
+encode_group_mod(const struct ofputil_group_mod *gm)
+{
+ return ofputil_encode_group_mod(OFP13_VERSION, gm);
+}
+
static void
-queue_group_mod(struct ofputil_group_mod *gm)
+add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs)
{
- queue_msg(ofputil_encode_group_mod(OFP13_VERSION, gm));
+ struct ofpbuf *msg = encode_group_mod(gm);
+ ovs_list_push_back(msgs, &msg->list_node);
}
@@ -829,7 +892,7 @@ queue_group_mod(struct ofputil_group_mod *gm)
*
* This should be called after ofctrl_run() within the main loop. */
void
-ofctrl_put(struct group_table *group_table)
+ofctrl_put(struct group_table *group_table, int64_t nb_cfg)
{
if (!groups) {
groups = group_table;
@@ -845,6 +908,9 @@ ofctrl_put(struct group_table *group_table)
return;
}
+ /* OpenFlow messages to send to the switch to bring it up-to-date. */
+ struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
+
/* Iterate through all the desired groups. If there are new ones,
* add them to the switch. */
struct group_info *desired;
@@ -862,7 +928,7 @@ ofctrl_put(struct group_table *group_table)
ds_cstr(&group_string),
&usable_protocols);
if (!error) {
- queue_group_mod(&gm);
+ add_group_mod(&gm, &msgs);
} else {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
VLOG_ERR_RL(&rl, "new group %s %s", error,
@@ -890,7 +956,7 @@ ofctrl_put(struct group_table *group_table)
.table_id = i->table_id,
.command = OFPFC_DELETE_STRICT,
};
- queue_flow_mod(&fm);
+ add_flow_mod(&fm, &msgs);
ovn_flow_log(i, "removing installed");
hmap_remove(&installed_flows, &i->match_hmap_node);
@@ -917,7 +983,7 @@ ofctrl_put(struct group_table *group_table)
.ofpacts_len = d->ofpacts_len,
.command = OFPFC_MODIFY_STRICT,
};
- queue_flow_mod(&fm);
+ add_flow_mod(&fm, &msgs);
ovn_flow_log(i, "updating installed");
/* Replace 'i''s actions by 'd''s. */
@@ -950,7 +1016,7 @@ ofctrl_put(struct group_table *group_table)
.ofpacts_len = d->ofpacts_len,
.command = OFPFC_ADD,
};
- queue_flow_mod(&fm);
+ add_flow_mod(&fm, &msgs);
ovn_flow_log(d, "adding installed");
/* Copy 'd' from 'flow_table' to installed_flows. */
@@ -977,7 +1043,7 @@ ofctrl_put(struct group_table *group_table)
ds_cstr(&group_string),
&usable_protocols);
if (!error) {
- queue_group_mod(&gm);
+ add_group_mod(&gm, &msgs);
} else {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
VLOG_ERR_RL(&rl, "Error deleting group %d: %s",
@@ -1009,4 +1075,63 @@ ofctrl_put(struct group_table *group_table)
free(desired);
}
}
+
+ if (!ovs_list_is_empty(&msgs)) {
+ /* Add a barrier to the list of messages. */
+ struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP13_VERSION);
+ const struct ofp_header *oh = barrier->data;
+ ovs_be32 xid = oh->xid;
+ ovs_list_push_back(&msgs, &barrier->list_node);
+
+ /* Queue the messages. */
+ struct ofpbuf *msg;
+ LIST_FOR_EACH_POP (msg, list_node, &msgs) {
+ queue_msg(msg);
+ }
+
+ /* Track the flow update. */
+ struct ofctrl_flow_update *fup, *prev;
+ LIST_FOR_EACH_REVERSE_SAFE (fup, prev, list_node, &flow_updates) {
+ if (nb_cfg < fup->nb_cfg) {
+ /* This ofctrl_flow_update is for a configuration later than
+ * 'nb_cfg'. This should not normally happen, because it means
+ * that 'nb_cfg' in the SB_Global table of the southbound
+ * database decreased, and it should normally be monotonically
+ * increasing. */
+ VLOG_WARN("nb_cfg regressed from %"PRId64" to %"PRId64,
+ fup->nb_cfg, nb_cfg);
+ ovs_list_remove(&fup->list_node);
+ free(fup);
+ } else if (nb_cfg == fup->nb_cfg) {
+ /* This ofctrl_flow_update is for the same configuration as
+ * 'nb_cfg'. Probably, some change to the physical topology
+ * means that we had to revise the OpenFlow flow table even
+ * though the logical topology did not change. Update fp->xid,
+ * so that we don't send a notification that we're up-to-date
+ * until we're really caught up. */
+ VLOG_DBG("advanced xid target for nb_cfg=%"PRId64, nb_cfg);
+ fup->xid = xid;
+ goto done;
+ } else {
+ break;
+ }
+ }
+
+ /* Add a flow update. */
+ fup = xmalloc(sizeof *fup);
+ ovs_list_push_back(&flow_updates, &fup->list_node);
+ fup->xid = xid;
+ fup->nb_cfg = nb_cfg;
+ done:;
+ } else if (!ovs_list_is_empty(&flow_updates)) {
+ /* Getting up-to-date with 'nb_cfg' didn't require any extra flow table
+ * changes, so whenever we get up-to-date with the most recent flow
+ * table update, we're also up-to-date with 'nb_cfg'. */
+ struct ofctrl_flow_update *fup = ofctrl_flow_update_from_list_node(
+ ovs_list_back(&flow_updates));
+ fup->nb_cfg = nb_cfg;
+ } else {
+ /* We were completely up-to-date before and still are. */
+ cur_cfg = nb_cfg;
+ }
}
diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h
index 49b95b0fd..befae0175 100644
--- a/ovn/controller/ofctrl.h
+++ b/ovn/controller/ofctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015 Nicira, Inc.
+/* Copyright (c) 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,9 +32,10 @@ struct group_table;
/* Interface for OVN main loop. */
void ofctrl_init(void);
enum mf_field_id ofctrl_run(const struct ovsrec_bridge *br_int);
-void ofctrl_put(struct group_table *group_table);
+void ofctrl_put(struct group_table *group_table, int64_t nb_cfg);
void ofctrl_wait(void);
void ofctrl_destroy(void);
+int64_t ofctrl_get_cur_cfg(void);
struct ovn_flow *ofctrl_dup_flow(struct ovn_flow *source);
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 4d9490a5a..ecf13063f 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -299,6 +299,13 @@ update_ct_zones(struct sset *lports, struct hmap *patched_datapaths,
sset_destroy(&all_users);
}
+static int64_t
+get_nb_cfg(struct ovsdb_idl *idl)
+{
+ const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl);
+ return sb ? sb->nb_cfg : 0;
+}
+
/* Contains "struct local_datapath" nodes whose hash values are the
* tunnel_key of datapaths with at least one local port binding. */
static struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
@@ -378,6 +385,7 @@ main(int argc, char *argv[])
char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
+ ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg);
/* Track the southbound idl. */
ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
@@ -422,8 +430,9 @@ main(int argc, char *argv[])
const struct ovsrec_bridge *br_int = get_br_int(&ctx);
const char *chassis_id = get_chassis_id(ctx.ovs_idl);
+ const struct sbrec_chassis *chassis = NULL;
if (chassis_id) {
- chassis_run(&ctx, chassis_id);
+ chassis = chassis_run(&ctx, chassis_id);
encaps_run(&ctx, br_int, chassis_id);
binding_run(&ctx, br_int, chassis_id, &local_datapaths);
}
@@ -448,7 +457,13 @@ main(int argc, char *argv[])
br_int, chassis_id, &ct_zones,
&local_datapaths, &patched_datapaths);
- ofctrl_put(&group_table);
+ ofctrl_put(&group_table, get_nb_cfg(ctx.ovnsb_idl));
+ if (ctx.ovnsb_idl_txn) {
+ int64_t cur_cfg = ofctrl_get_cur_cfg();
+ if (cur_cfg && cur_cfg != chassis->nb_cfg) {
+ sbrec_chassis_set_nb_cfg(chassis, cur_cfg);
+ }
+ }
}
sset_destroy(&all_lports);