Hi Dumitru, I have a few comments below.
On 11/4/22 18:11, Dumitru Ceara wrote:
Propagate the contents of the NB table to the Southbound.
Signed-off-by: Dumitru Ceara <dce...@redhat.com>
---
Note:
- ovn-trace doesn't support template variables (yet).
V2:
- Fixed TEMPLATE_VAR_TABLE_INITIALIZER definition so that GCC doesn't
complain anymore.
- Addressed Han's comments:
- Rename tables to Chassis_Template_Var.
- Fix man page.
- Simplify function prototypes.
- Changed schema as suggested by Ilya.
---
northd/automake.mk | 4 ++
northd/en-northd.c | 4 ++
northd/inc-proc-northd.c | 8 ++++-
northd/northd.c | 41 +++++++++++++++++++++++++
northd/northd.h | 4 ++
northd/template-var.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++
northd/template-var.h | 58 ++++++++++++++++++++++++++++++++++++
ovn-nb.ovsschema | 17 +++++++++--
ovn-nb.xml | 29 ++++++++++++++++++
ovn-sb.ovsschema | 12 ++++++-
ovn-sb.xml | 15 +++++++++
tests/ovn-northd.at | 35 ++++++++++++++++++++++
utilities/ovn-nbctl.c | 3 ++
utilities/ovn-sbctl.c | 3 ++
14 files changed, 299 insertions(+), 8 deletions(-)
create mode 100644 northd/template-var.c
create mode 100644 northd/template-var.h
diff --git a/northd/automake.mk b/northd/automake.mk
index 81582867dc..31134bc329 100644
--- a/northd/automake.mk
+++ b/northd/automake.mk
@@ -13,7 +13,9 @@ northd_ovn_northd_SOURCES = \
northd/inc-proc-northd.c \
northd/inc-proc-northd.h \
northd/ipam.c \
- northd/ipam.h
+ northd/ipam.h \
+ northd/template-var.c \
+ northd/template-var.h
northd_ovn_northd_LDADD = \
lib/libovn.la \
$(OVSDB_LIBDIR)/libovsdb.la \
diff --git a/northd/en-northd.c b/northd/en-northd.c
index 7fe83db642..030ee25d8f 100644
--- a/northd/en-northd.c
+++ b/northd/en-northd.c
@@ -80,6 +80,8 @@ void en_northd_run(struct engine_node *node, void *data)
EN_OVSDB_GET(engine_get_input("NB_acl", node));
input_data.nbrec_static_mac_binding_table =
EN_OVSDB_GET(engine_get_input("NB_static_mac_binding", node));
+ input_data.nbrec_chassis_template_var_table =
+ EN_OVSDB_GET(engine_get_input("NB_chassis_template_var", node));
input_data.sbrec_sb_global_table =
EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
@@ -113,6 +115,8 @@ void en_northd_run(struct engine_node *node, void *data)
EN_OVSDB_GET(engine_get_input("SB_chassis_private", node));
input_data.sbrec_static_mac_binding_table =
EN_OVSDB_GET(engine_get_input("SB_static_mac_binding", node));
+ input_data.sbrec_chassis_template_var_table =
+ EN_OVSDB_GET(engine_get_input("SB_chassis_template_var", node));
northd_run(&input_data, data,
eng_ctx->ovnnb_idl_txn,
diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
index 54e0ad3b05..da791f035d 100644
--- a/northd/inc-proc-northd.c
+++ b/northd/inc-proc-northd.c
@@ -64,7 +64,8 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_northd);
NB_NODE(ha_chassis_group, "ha_chassis_group") \
NB_NODE(ha_chassis, "ha_chassis") \
NB_NODE(bfd, "bfd") \
- NB_NODE(static_mac_binding, "static_mac_binding")
+ NB_NODE(static_mac_binding, "static_mac_binding") \
+ NB_NODE(chassis_template_var, "chassis_template_var")
enum nb_engine_node {
#define NB_NODE(NAME, NAME_STR) NB_##NAME,
@@ -114,7 +115,8 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_northd);
SB_NODE(load_balancer, "load_balancer") \
SB_NODE(bfd, "bfd") \
SB_NODE(fdb, "fdb") \
- SB_NODE(static_mac_binding, "static_mac_binding")
+ SB_NODE(static_mac_binding, "static_mac_binding") \
+ SB_NODE(chassis_template_var, "chassis_template_var")
enum sb_engine_node {
#define SB_NODE(NAME, NAME_STR) SB_##NAME,
@@ -186,6 +188,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
engine_add_input(&en_northd, &en_nb_ha_chassis_group, NULL);
engine_add_input(&en_northd, &en_nb_ha_chassis, NULL);
engine_add_input(&en_northd, &en_nb_static_mac_binding, NULL);
+ engine_add_input(&en_northd, &en_nb_chassis_template_var, NULL);
engine_add_input(&en_northd, &en_sb_sb_global, NULL);
engine_add_input(&en_northd, &en_sb_chassis, NULL);
@@ -215,6 +218,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
engine_add_input(&en_northd, &en_sb_load_balancer, NULL);
engine_add_input(&en_northd, &en_sb_fdb, NULL);
engine_add_input(&en_northd, &en_sb_static_mac_binding, NULL);
+ engine_add_input(&en_northd, &en_sb_chassis_template_var, NULL);
engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL);
engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL);
engine_add_input(&en_mac_binding_aging, &en_northd, NULL);
diff --git a/northd/northd.c b/northd/northd.c
index b7388afc58..170b4f95c8 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -51,6 +51,7 @@
#include "lib/stopwatch-names.h"
#include "stream.h"
#include "timeval.h"
+#include "template-var.h"
#include "util.h"
#include "uuid.h"
#include "ovs-thread.h"
@@ -15129,6 +15130,44 @@ sync_dns_entries(struct northd_input *input_data,
}
hmap_destroy(&dns_map);
}
+
+static void
+sync_template_vars(struct northd_input *input_data,
+ struct ovsdb_idl_txn *ovnsb_txn)
+{
+ struct template_var_table nb_tvs = TEMPLATE_VAR_TABLE_INITIALIZER(&nb_tvs);
+
+ const struct nbrec_chassis_template_var *nb_tv;
+ const struct sbrec_chassis_template_var *sb_tv;
+ struct template_var *tv;
+
+ NBREC_CHASSIS_TEMPLATE_VAR_TABLE_FOR_EACH (
+ nb_tv, input_data->nbrec_chassis_template_var_table) {
+ template_var_insert(&nb_tvs, nb_tv);
+ }
+
+ SBREC_CHASSIS_TEMPLATE_VAR_TABLE_FOR_EACH_SAFE (
+ sb_tv, input_data->sbrec_chassis_template_var_table) {
+ tv = template_var_find(&nb_tvs, sb_tv->chassis);
+ if (!tv) {
+ sbrec_chassis_template_var_delete(sb_tv);
+ continue;
+ }
+ if (!smap_equal(&sb_tv->variables, &tv->nb->variables)) {
+ sbrec_chassis_template_var_set_variables(sb_tv,
+ &tv->nb->variables);
+ }
I was looking at this and wondering what would happen here if you
skipped the smap_equal() call and just unconditionally called
sbrec_chassis_template_var_set_variables(). My thought here was that it
would save the O(n^2) smap_equal() call, but it would also result in
spurious writes to the SBDB. Those writes would result in more wakeups
of ovn-controller. But ovn-controller has I-P for template vars, so
those wakeups would hopefully not result in many wasted cycles.
So...I'm not really sure here. However, I think this would be a good
(and hopefully easy) candidate for I-P in a future release.
+ template_var_remove(&nb_tvs, tv);
+ template_var_destroy(tv);
+ }
+
+ TEMPLATE_VAR_TABLE_FOR_EACH (tv, &nb_tvs) {
+ sb_tv = sbrec_chassis_template_var_insert(ovnsb_txn);
+ sbrec_chassis_template_var_set_chassis(sb_tv, tv->nb->chassis);
+ sbrec_chassis_template_var_set_variables(sb_tv, &tv->nb->variables);
+ }
+ template_var_table_destroy(&nb_tvs);
+}
static void
destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ports,
@@ -15645,6 +15684,8 @@ ovnnb_db_run(struct northd_input *input_data,
sync_port_groups(input_data, ovnsb_txn, &data->port_groups);
sync_meters(input_data, ovnsb_txn, &data->meter_groups);
sync_dns_entries(input_data, ovnsb_txn, &data->datapaths);
+ sync_template_vars(input_data, ovnsb_txn);
+
cleanup_stale_fdb_entries(input_data, &data->datapaths);
stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
diff --git a/northd/northd.h b/northd/northd.h
index da90e28155..1935c80d40 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -36,6 +36,8 @@ struct northd_input {
const struct nbrec_acl_table *nbrec_acl_table;
const struct nbrec_static_mac_binding_table
*nbrec_static_mac_binding_table;
+ const struct nbrec_chassis_template_var_table
+ *nbrec_chassis_template_var_table;
/* Southbound table references */
const struct sbrec_sb_global_table *sbrec_sb_global_table;
@@ -55,6 +57,8 @@ struct northd_input {
const struct sbrec_chassis_private_table *sbrec_chassis_private_table;
const struct sbrec_static_mac_binding_table
*sbrec_static_mac_binding_table;
+ const struct sbrec_chassis_template_var_table
+ *sbrec_chassis_template_var_table;
/* Indexes */
struct ovsdb_idl_index *sbrec_chassis_by_name;
diff --git a/northd/template-var.c b/northd/template-var.c
new file mode 100644
index 0000000000..a1069a5b51
--- /dev/null
+++ b/northd/template-var.c
@@ -0,0 +1,74 @@
+/* Copyright (c) 2022, Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "template-var.h"
+
+struct template_var_table *
+template_var_table_create(void)
+{
+ struct template_var_table *table = xmalloc(sizeof *table);
+
+ hmap_init(&table->vars);
+ return table;
+}
+
+void
+template_var_table_destroy(struct template_var_table *table)
+{
+ struct template_var *tv;
+
+ HMAP_FOR_EACH_POP (tv, hmap_node, &table->vars) {
+ template_var_destroy(tv);
+ }
+ hmap_destroy(&table->vars);
+}
+
+void
+template_var_insert(struct template_var_table *table,
+ const struct nbrec_chassis_template_var *nbrec_tv)
+{
+ struct template_var *tv = xmalloc(sizeof *tv);
+ tv->nb = nbrec_tv;
+ hmap_insert(&table->vars, &tv->hmap_node,
+ template_var_hash(nbrec_tv->chassis));
+}
+
+struct template_var *
+template_var_find(struct template_var_table *table, const char *chassis_name)
+{
+ struct template_var *tv;
+
+ HMAP_FOR_EACH_WITH_HASH (tv, hmap_node, template_var_hash(chassis_name),
Nit: Since HMAP_FOR_EACH_WITH_HASH() is a macro, you should probably
call template_var_hash() before HMAP_FOR_EACH_WITH_HASH(). Otherwise,
the hash will be recalculated many times unnecessarily (assuming the
compiler doesn't optimize this on its own).
+ &table->vars) {
+ if (!strcmp(chassis_name, tv->nb->chassis)) {
+ return tv;
+ }
+ }
+ return NULL;
+}
+
+void
+template_var_remove(struct template_var_table *table, struct template_var *tv)
+{
+ hmap_remove(&table->vars, &tv->hmap_node);
+}
+
+void
+template_var_destroy(struct template_var *tv)
+{
+ free(tv);
+}
diff --git a/northd/template-var.h b/northd/template-var.h
new file mode 100644
index 0000000000..2de0e6cfe4
--- /dev/null
+++ b/northd/template-var.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2022, Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_NORTHD_TEMPLATE_VAR_H
+#define OVN_NORTHD_TEMPLATE_VAR_H 1
+
+#include "openvswitch/hmap.h"
+#include "lib/ovn-nb-idl.h"
+
+struct template_var {
+ struct hmap_node hmap_node;
+
+ const struct nbrec_chassis_template_var *nb;
+};
+
+struct template_var_table {
+ struct hmap vars;
Question: Why did you choose to use an hmap? This seems like a good fit
for shash to me.
+};
+
+#define TEMPLATE_VAR_TABLE_INITIALIZER(TBL) \
+ { .vars = HMAP_INITIALIZER(&(TBL)->vars) }
+
+#define TEMPLATE_VAR_TABLE_FOR_EACH(NODE, TBL) \
+ HMAP_FOR_EACH (NODE, hmap_node, &(TBL)->vars)
+
+struct template_var_table *template_var_table_create(void);
+void template_var_table_destroy(struct template_var_table *);
+
+static inline uint32_t
+template_var_hash(const char *tv_chassis)
+{
+ return hash_string(tv_chassis, 0);
+}
+
+void template_var_insert(struct template_var_table *,
+ const struct nbrec_chassis_template_var *);
+
+struct template_var *
+template_var_find(struct template_var_table *, const char *chassis_name);
+
+void template_var_remove(struct template_var_table *,
+ struct template_var *);
+
+void template_var_destroy(struct template_var *);
+
+#endif /* OVN_NORTHD_TEMPLATE_VAR_H 1 */
diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
index 174364c8b1..6f9d38f47b 100644
--- a/ovn-nb.ovsschema
+++ b/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Northbound",
- "version": "6.3.0",
- "cksum": "4042813038 31869",
+ "version": "6.4.0",
+ "cksum": "3512158873 32360",
"tables": {
"NB_Global": {
"columns": {
@@ -620,6 +620,17 @@
"mac": {"type": "string"},
"override_dynamic_mac": {"type": "boolean"}},
"indexes": [["logical_port", "ip"]],
- "isRoot": true}
+ "isRoot": true},
+ "Chassis_Template_Var": {
+ "columns": {
+ "chassis": {"type": "string"},
+ "variables": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}},
+ "external_ids": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}}},
+ "indexes": [["chassis"]],
+ "isRoot": true}
}
}
diff --git a/ovn-nb.xml b/ovn-nb.xml
index f41e9d7c0e..45b75e66df 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -4436,4 +4436,33 @@
</column>
</group>
</table>
+
+ <table name="Chassis_Template_Var">
+ <p>
+ One record per chassis, each containing a map, <code>variables</code>,
+ between template variable names and their value for that specific
+ chassis. A template variable has a name and potentially different
+ values on different hypervisors in the OVN cluster. For example,
+ two rows, <code>R1 = (.chassis=C1, variables={(N: V1)}</code> and
+ <code>R2 = (.chassis=C2, variables={(N: V2)}</code> will make
+ <code>ovn-controller</code> running on chassis <code>C1</code> and
+ <code>C2</code> interpret the token <code>N</code> either as
+ <code>V1</code> (on <code>C1</code>) or as <code>V2</code> (on
+ <code>C2</code>). Users can refer to template variables from
+ within other logical components, e.g., within ACL, QoS or
+ Logical_Router_Policy matches or from Load_Balancer VIP and
+ backend definitions.
One thing the documentation does not make clear is what happens if a
chassis template variable is referenced on a chassis for which that
variable is not defined.
+ </p>
+ <column name="chassis">
+ The chassis this set of variable values applies to.
+ </column>
+ <column name="variables">
+ The set of variable values for a given chassis.
+ </column>
+ <group title="Common Columns">
+ <column name="external_ids">
+ See <em>External IDs</em> at the beginning of this document.
+ </column>
+ </group>
+ </table>
</database>
diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
index 576ebbdeb0..95c7c2d7e3 100644
--- a/ovn-sb.ovsschema
+++ b/ovn-sb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
- "version": "20.25.0",
- "cksum": "53184112 28845",
+ "version": "20.26.0",
+ "cksum": "3311869408 29176",
"tables": {
"SB_Global": {
"columns": {
@@ -565,6 +565,14 @@
"key": {"type": "uuid",
"refTable": "Datapath_Binding"}}}},
"indexes": [["logical_port", "ip"]],
+ "isRoot": true},
+ "Chassis_Template_Var": {
+ "columns": {
+ "chassis": {"type": "string"},
+ "variables": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}}},
+ "indexes": [["chassis"]],
"isRoot": true}
}
}
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 315d608534..169a53aaa9 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -4801,4 +4801,19 @@ tcp.flags = RST;
The logical datapath to which the logical router port belongs.
</column>
</table>
+
+ <table name="Chassis_Template_Var">
+ <p>
+ Each record represents the set of template variable instantiations
+ for a given chassis and is populated by <code>ovn-northd</code>
+ from the contents of the <code>OVN_Northbound.Chassis_Template_Var</code>
+ table.
+ </p>
+ <column name="chassis">
+ The chassis this set of variable values applies to.
+ </column>
+ <column name="variables">
+ The set of variable values for a given chassis.
+ </column>
+ </table>
</database>
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 4f399eccb6..c7112b805d 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -7929,3 +7929,38 @@ AT_CHECK([grep "lr_in_arp_resolve" R1flows | grep
priority=90 | sort], [0], [dnl
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([NB to SB Chassis_Template_Var propagation])
+AT_KEYWORDS([templates])
+ovn_start
+
+AT_CHECK([ovn-nbctl create Chassis_Template_Var chassis="hv1"], [0], [ignore])
+AT_CHECK([ovn-nbctl create Chassis_Template_Var chassis="hv2"], [0], [ignore])
+
+check ovn-nbctl set Chassis_Template_Var hv1 variables:tv=v1
+check ovn-nbctl set Chassis_Template_Var hv2 variables:tv=v2
+
+AS_BOX([Ensure values are propagated to SB])
+check ovn-nbctl --wait=sb sync
+check_column "tv=v1" sb:Chassis_Template_Var variables chassis="hv1"
+check_column "tv=v2" sb:Chassis_Template_Var variables chassis="hv2"
+
+AS_BOX([Ensure SB is reconciled])
+check ovn-sbctl --all destroy Chassis_Template_Var
+check ovn-nbctl --wait=sb sync
+check_column "tv=v1" sb:Chassis_Template_Var variables chassis="hv1"
+check_column "tv=v2" sb:Chassis_Template_Var variables chassis="hv2"
+
+AS_BOX([Ensure SB is reconciled - deletion])
+check ovn-nbctl destroy Chassis_Template_Var hv1
+check ovn-nbctl --wait=sb sync
+check_column "tv=v2" sb:Chassis_Template_Var variables chassis="hv2"
+
+AS_BOX([Ensure SB is reconciled - cleanup])
+check ovn-nbctl destroy Chassis_Template_Var hv2
+check ovn-nbctl --wait=sb sync
+check_row_count sb:Chassis_Template_Var 0
+
+AT_CLEANUP
+])
diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
index 811468dc66..d2dee6b31c 100644
--- a/utilities/ovn-nbctl.c
+++ b/utilities/ovn-nbctl.c
@@ -7300,6 +7300,9 @@ static const struct ctl_table_class
tables[NBREC_N_TABLES] = {
[NBREC_TABLE_NAT].row_ids[0]
= {&nbrec_nat_col_external_ip, NULL, NULL},
+ [NBREC_TABLE_CHASSIS_TEMPLATE_VAR].row_ids[0]
+ = {&nbrec_chassis_template_var_col_chassis, NULL, NULL},
+
[NBREC_TABLE_CONNECTION].row_ids[0]
= {&nbrec_connection_col_target, NULL, NULL},
};
diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c
index f60dde1b67..00b2f785a5 100644
--- a/utilities/ovn-sbctl.c
+++ b/utilities/ovn-sbctl.c
@@ -1457,6 +1457,9 @@ static const struct ctl_table_class
tables[SBREC_N_TABLES] = {
[SBREC_TABLE_LOAD_BALANCER].row_ids[0]
= {&sbrec_load_balancer_col_name, NULL, NULL},
+
+ [SBREC_TABLE_CHASSIS_TEMPLATE_VAR].row_ids[0]
+ = {&sbrec_chassis_template_var_col_chassis, NULL, NULL},
};
static const struct ctl_command_syntax sbctl_commands[] = {
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev