[ovs-dev] [PATCH ovn v4 1/9] ovn: Add tunnel_key concept to Bindings table, assign in ovn-northd.
Ben Pfaff
blp at nicira.com
Wed Apr 29 17:12:27 UTC 2015
When packets travel among nodes in OVN over tunnels, a tunnel key value is
needed to convey the logical port to which the packet is destined. This
commit adds a tunnel_key column to the Bindings table and adds code to
ovn-northd to assign a unique tunnel_key value to each logical port.
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
ovn/northd/ovn-northd.c | 104 ++++++++++++++++++++++++++++++++++++++----------
ovn/ovn-sb.ovsschema | 6 ++-
ovn/ovn-sb.xml | 14 +++++++
3 files changed, 102 insertions(+), 22 deletions(-)
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 34ac995..0b5becf 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -444,6 +444,45 @@ tags_equal(const struct sbrec_bindings *binding,
return binding->n_tag ? (binding->tag[0] == lport->tag[0]) : true;
}
+struct binding_hash_node {
+ struct hmap_node lp_node; /* In 'lp_map', by binding->logical_port. */
+ struct hmap_node tk_node; /* In 'tk_map', by binding->tunnel_key. */
+ const struct sbrec_bindings *binding;
+};
+
+static bool
+tunnel_key_in_use(const struct hmap *tk_hmap, uint16_t tunnel_key)
+{
+ const struct binding_hash_node *hash_node;
+
+ HMAP_FOR_EACH_IN_BUCKET (hash_node, tk_node, hash_int(tunnel_key, 0),
+ tk_hmap) {
+ if (hash_node->binding->tunnel_key == tunnel_key) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Chooses and returns a positive tunnel key that is not already in use in
+ * 'tk_hmap'. Returns 0 if all tunnel keys are in use. */
+static uint16_t
+choose_tunnel_key(const struct hmap *tk_hmap)
+{
+ static uint16_t prev;
+
+ for (uint16_t key = prev + 1; key != prev; key++) {
+ if (!tunnel_key_in_use(tk_hmap, key)) {
+ prev = key;
+ return key;
+ }
+ }
+
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&rl, "all tunnel keys exhausted");
+ return 0;
+}
+
/*
* When a change has occurred in the OVN_Northbound database, we go through and
* make sure that the contents of the Bindings table in the OVN_Southbound
@@ -453,38 +492,41 @@ tags_equal(const struct sbrec_bindings *binding,
static void
set_bindings(struct northd_context *ctx)
{
- struct hmap bindings_hmap;
const struct sbrec_bindings *binding;
const struct nbrec_logical_port *lport;
- struct binding_hash_node {
- struct hmap_node node;
- const struct sbrec_bindings *binding;
- } *hash_node, *hash_node_next;
-
/*
* We will need to look up a binding for every logical port. We don't want
* to have to do an O(n) search for every binding, so start out by hashing
* them on the logical port.
*
* As we go through every logical port, we will update the binding if it
- * exists or create one otherwise. When the update is done, we'll remove it
- * from the hashmap. At the end, any bindings left in the hashmap are for
- * logical ports that have been deleted.
+ * exists or create one otherwise. When the update is done, we'll remove
+ * it from the hashmap. At the end, any bindings left in the hashmap are
+ * for logical ports that have been deleted.
+ *
+ * We index the logical_port column because that's the shared key between
+ * the OVN_NB and OVN_SB databases. We index the tunnel_key column to
+ * allow us to choose a unique tunnel key for any Binding rows we have to
+ * add.
*/
- hmap_init(&bindings_hmap);
+ struct hmap lp_hmap = HMAP_INITIALIZER(&lp_hmap);
+ struct hmap tk_hmap = HMAP_INITIALIZER(&tk_hmap);
SBREC_BINDINGS_FOR_EACH(binding, ctx->ovnsb_idl) {
- hash_node = xzalloc(sizeof *hash_node);
+ struct binding_hash_node *hash_node = xzalloc(sizeof *hash_node);
hash_node->binding = binding;
- hmap_insert(&bindings_hmap, &hash_node->node,
- hash_string(binding->logical_port, 0));
+ hmap_insert(&lp_hmap, &hash_node->lp_node,
+ hash_string(binding->logical_port, 0));
+ hmap_insert(&tk_hmap, &hash_node->tk_node,
+ hash_int(binding->tunnel_key, 0));
}
NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->ovnnb_idl) {
+ struct binding_hash_node *hash_node;
binding = NULL;
- HMAP_FOR_EACH_WITH_HASH(hash_node, node,
- hash_string(lport->name, 0), &bindings_hmap) {
+ HMAP_FOR_EACH_WITH_HASH(hash_node, lp_node,
+ hash_string(lport->name, 0), &lp_hmap) {
if (!strcmp(lport->name, hash_node->binding->logical_port)) {
binding = hash_node->binding;
break;
@@ -502,9 +544,7 @@ set_bindings(struct northd_context *ctx)
/* We found an existing binding for this logical port. Update its
* contents. */
- hmap_remove(&bindings_hmap, &hash_node->node);
- free(hash_node);
- hash_node = NULL;
+ hmap_remove(&lp_hmap, &hash_node->lp_node);
if (!macs_equal(binding->mac, binding->n_mac,
lport->macs, lport->n_macs)) {
@@ -524,6 +564,11 @@ set_bindings(struct northd_context *ctx)
} else {
/* There is no binding for this logical port, so create one. */
+ uint16_t tunnel_key = choose_tunnel_key(&tk_hmap);
+ if (!tunnel_key) {
+ continue;
+ }
+
binding = sbrec_bindings_insert(ctx->ovnsb_txn);
sbrec_bindings_set_logical_port(binding, lport->name);
sbrec_bindings_set_mac(binding,
@@ -533,16 +578,32 @@ set_bindings(struct northd_context *ctx)
sbrec_bindings_set_tag(binding, lport->tag, lport->n_tag);
}
+ sbrec_bindings_set_tunnel_key(binding, tunnel_key);
sbrec_bindings_set_logical_datapath(binding, logical_datapath);
+
+ /* Add the tunnel key to the tk_hmap so that we don't try to use it
+ * for another port. (We don't want it in the lp_hmap because that
+ * would just get the Bindings record deleted later.) */
+ struct binding_hash_node *hash_node = xzalloc(sizeof *hash_node);
+ hash_node->binding = binding;
+ hmap_insert(&tk_hmap, &hash_node->tk_node,
+ hash_int(binding->tunnel_key, 0));
}
}
- HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &bindings_hmap) {
- hmap_remove(&bindings_hmap, &hash_node->node);
+ struct binding_hash_node *hash_node;
+ HMAP_FOR_EACH (hash_node, lp_node, &lp_hmap) {
+ hmap_remove(&lp_hmap, &hash_node->lp_node);
sbrec_bindings_delete(hash_node->binding);
+ }
+ hmap_destroy(&lp_hmap);
+
+ struct binding_hash_node *hash_node_next;
+ HMAP_FOR_EACH_SAFE (hash_node, hash_node_next, tk_node, &tk_hmap) {
+ hmap_remove(&tk_hmap, &hash_node->tk_node);
free(hash_node);
}
- hmap_destroy(&bindings_hmap);
+ hmap_destroy(&tk_hmap);
}
static void
@@ -733,6 +794,7 @@ main(int argc, char *argv[])
ovsdb_idl_add_column(ovnsb_idl, &sbrec_bindings_col_tag);
ovsdb_idl_add_column(ovnsb_idl, &sbrec_bindings_col_parent_port);
ovsdb_idl_add_column(ovnsb_idl, &sbrec_bindings_col_logical_datapath);
+ ovsdb_idl_add_column(ovnsb_idl, &sbrec_bindings_col_tunnel_key);
ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_logical_datapath);
ovsdb_idl_omit_alert(ovnsb_idl, &sbrec_pipeline_col_logical_datapath);
ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_table_id);
diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema
index 5f2d1a4..9fd5363 100644
--- a/ovn/ovn-sb.ovsschema
+++ b/ovn/ovn-sb.ovsschema
@@ -47,6 +47,10 @@
"columns": {
"logical_datapath": {"type": "uuid"},
"logical_port": {"type": "string"},
+ "tunnel_key": {
+ "type": {"key": {"type": "integer",
+ "minInteger": 1,
+ "maxInteger": 65535}}},
"parent_port": {"type": {"key": "string", "min": 0, "max": 1}},
"tag": {
"type": {"key": {"type": "integer",
@@ -57,6 +61,6 @@
"mac": {"type": {"key": "string",
"min": 0,
"max": "unlimited"}}},
- "indexes": [["logical_port"]],
+ "indexes": [["logical_port"], ["tunnel_key"]],
"isRoot": true}},
"version": "1.0.0"}
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 1a27617..31ee871 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -665,6 +665,20 @@
prescribe a particular format for the logical port ID.
</column>
+ <column name="tunnel_key">
+ <p>
+ A number that represents the logical port in the key (e.g. VXLAN VNI or
+ STT key) field carried within tunnel protocol packets. (This avoids
+ wasting space for a whole UUID in tunneled packets. It also allows OVN
+ to support encapsulations that cannot fit an entire UUID in their
+ tunnel keys.)
+ </p>
+
+ <p>
+ Tunnel ID 0 is reserved for internal use within OVN.
+ </p>
+ </column>
+
<column name="parent_port">
For containers created inside a VM, this is taken from
<ref table="Logical_Port" column="parent_name" db="OVN_Northbound"/>
--
2.1.3
More information about the dev
mailing list