@@ -15,6 +15,7 @@
#include <config.h>
+#include "en-global-config.h"
#include "lib/inc-proc-eng.h"
#include "lib/ovn-nb-idl.h"
#include "lib/ovn-sb-idl.h"
@@ -100,15 +101,10 @@ aging_context_handle_timestamp(struct aging_context *ctx, int64_t timestamp)
static uint32_t
get_removal_limit(struct engine_node *node, const char *name)
{
- const struct nbrec_nb_global_table *nb_global_table =
- EN_OVSDB_GET(engine_get_input("NB_nb_global", node));
- const struct nbrec_nb_global *nb =
- nbrec_nb_global_table_first(nb_global_table);
- if (!nb) {
- return 0;
- }
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
- return smap_get_uint(&nb->options, name, 0);
+ return smap_get_uint(&global_config->nb_options, name, 0);
}
/* MAC binding aging */
@@ -142,11 +138,14 @@ en_mac_binding_aging_run(struct engine_node *node, void *data OVS_UNUSED)
{
const struct engine_context *eng_ctx = engine_get_context();
struct northd_data *northd_data = engine_get_input_data("northd", node);
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
+
struct aging_waker *waker =
engine_get_input_data("mac_binding_aging_waker", node);
if (!eng_ctx->ovnsb_idl_txn ||
- !northd_data->features.mac_binding_timestamp ||
+ !global_config->features.mac_binding_timestamp ||
time_msec() < waker->next_wake_msec) {
return;
}
@@ -271,9 +270,11 @@ en_fdb_aging_run(struct engine_node *node, void *data OVS_UNUSED)
const struct engine_context *eng_ctx = engine_get_context();
struct northd_data *northd_data = engine_get_input_data("northd", node);
struct aging_waker *waker = engine_get_input_data("fdb_aging_waker", node);
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
if (!eng_ctx->ovnsb_idl_txn ||
- !northd_data->features.fdb_timestamp ||
+ !global_config->features.fdb_timestamp ||
time_msec() < waker->next_wake_msec) {
return;
}
@@ -8,6 +8,8 @@ northd_ovn_northd_SOURCES = \
northd/northd.c \
northd/northd.h \
northd/ovn-northd.c \
+ northd/en-global-config.c \
+ northd/en-global-config.h \
northd/en-northd.c \
northd/en-northd.h \
northd/en-lflow.c \
new file mode 100644
@@ -0,0 +1,588 @@
+/*
+ * 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 <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* OVS includes */
+#include "openvswitch/vlog.h"
+
+/* OVN includes */
+#include "debug.h"
+#include "en-global-config.h"
+#include "include/ovn/features.h"
+#include "ipam.h"
+#include "lib/ovn-nb-idl.h"
+#include "lib/ovn-sb-idl.h"
+#include "northd.h"
+
+
+VLOG_DEFINE_THIS_MODULE(en_global_config);
+
+/* static function declarations. */
+static void northd_enable_all_features(struct ed_type_global_config *);
+static void build_chassis_features(const struct sbrec_chassis_table *,
+ struct chassis_features *);
+static bool chassis_features_changed(const struct chassis_features *,
+ const struct chassis_features *);
+static bool config_out_of_sync(const struct smap *config,
+ const struct smap *saved_config,
+ const char *key, bool must_be_present);
+static bool check_nb_options_out_of_sync(const struct nbrec_nb_global *,
+ struct ed_type_global_config *);
+static void update_sb_config_options_to_sbrec(struct ed_type_global_config *,
+ const struct sbrec_sb_global *);
+
+void *
+en_global_config_init(struct engine_node *node OVS_UNUSED,
+ struct engine_arg *args OVS_UNUSED)
+{
+ struct ed_type_global_config *data = xzalloc(sizeof *data);
+ smap_init(&data->nb_options);
+ smap_init(&data->sb_options);
+ northd_enable_all_features(data);
+ return data;
+}
+
+void
+en_global_config_run(struct engine_node *node , void *data)
+{
+ const struct engine_context *eng_ctx = engine_get_context();
+ if (!eng_ctx->ovnnb_idl_txn || !eng_ctx->ovnsb_idl_txn) {
+ return;
+ }
+
+ const struct nbrec_nb_global_table *nb_global_table =
+ EN_OVSDB_GET(engine_get_input("NB_nb_global", node));
+ const struct sbrec_sb_global_table *sb_global_table =
+ EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
+ const struct sbrec_chassis_table *sbrec_chassis_table =
+ EN_OVSDB_GET(engine_get_input("SB_chassis", node));
+
+ en_global_config_clear_tracked_data(data);
+
+ struct ed_type_global_config *config_data = data;
+
+ /* Sync ipsec configuration.
+ * Copy nb_cfg from northbound to southbound database.
+ * Also set up to update sb_cfg once our southbound transaction commits. */
+ const struct nbrec_nb_global *nb =
+ nbrec_nb_global_table_first(nb_global_table);
+ if (!nb) {
+ nb = nbrec_nb_global_insert(eng_ctx->ovnnb_idl_txn);
+ }
+
+ const char *mac_addr_prefix = set_mac_prefix(smap_get(&nb->options,
+ "mac_prefix"));
+
+ const char *monitor_mac = smap_get(&nb->options, "svc_monitor_mac");
+ if (monitor_mac) {
+ if (eth_addr_from_string(monitor_mac,
+ &config_data->svc_monitor_mac_ea)) {
+ snprintf(config_data->svc_monitor_mac,
+ sizeof config_data->svc_monitor_mac,
+ ETH_ADDR_FMT,
+ ETH_ADDR_ARGS(config_data->svc_monitor_mac_ea));
+ } else {
+ monitor_mac = NULL;
+ }
+ }
+
+ struct smap *options = &config_data->nb_options;
+ smap_destroy(options);
+ smap_clone(options, &nb->options);
+
+ smap_replace(options, "mac_prefix", mac_addr_prefix);
+
+ if (!monitor_mac) {
+ eth_addr_random(&config_data->svc_monitor_mac_ea);
+ snprintf(config_data->svc_monitor_mac,
+ sizeof config_data->svc_monitor_mac, ETH_ADDR_FMT,
+ ETH_ADDR_ARGS(config_data->svc_monitor_mac_ea));
+ smap_replace(options, "svc_monitor_mac",
+ config_data->svc_monitor_mac);
+ }
+
+ char *max_tunid = xasprintf("%d",
+ get_ovn_max_dp_key_local(sbrec_chassis_table));
+ smap_replace(options, "max_tunid", max_tunid);
+ free(max_tunid);
+
+ char *ovn_internal_version = ovn_get_internal_version();
+ if (strcmp(ovn_internal_version,
+ smap_get_def(options, "northd_internal_version", ""))) {
+ smap_replace(options, "northd_internal_version",
+ ovn_internal_version);
+ config_data->ovn_internal_version_changed = true;
+ } else {
+ config_data->ovn_internal_version_changed = false;
+ }
+
+ free(ovn_internal_version);
+
+ if (!smap_equal(&nb->options, options)) {
+ nbrec_nb_global_verify_options(nb);
+ nbrec_nb_global_set_options(nb, options);
+ }
+
+ if (smap_get_bool(&nb->options, "ignore_chassis_features", false)) {
+ northd_enable_all_features(config_data);
+ } else {
+ build_chassis_features(sbrec_chassis_table, &config_data->features);
+ }
+
+ init_debug_config(nb);
+
+ const struct sbrec_sb_global *sb =
+ sbrec_sb_global_table_first(sb_global_table);
+ if (!sb) {
+ sb = sbrec_sb_global_insert(eng_ctx->ovnsb_idl_txn);
+ }
+ if (nb->ipsec != sb->ipsec) {
+ sbrec_sb_global_set_ipsec(sb, nb->ipsec);
+ }
+
+ /* Set up SB_Global (depends on chassis features). */
+ update_sb_config_options_to_sbrec(config_data, sb);
+
+ engine_set_node_state(node, EN_UPDATED);
+}
+
+void en_global_config_cleanup(void *data OVS_UNUSED)
+{
+ struct ed_type_global_config *config_data = data;
+ smap_destroy(&config_data->nb_options);
+ smap_destroy(&config_data->sb_options);
+ destroy_debug_config();
+}
+
+void
+en_global_config_clear_tracked_data(void *data)
+{
+ struct ed_type_global_config *config_data = data;
+ config_data->tracked = false;
+ config_data->tracked_data.nb_options_changed = false;
+ config_data->tracked_data.chassis_features_changed = false;
+}
+
+bool
+global_config_nb_global_handler(struct engine_node *node, void *data)
+{
+ const struct nbrec_nb_global_table *nb_global_table =
+ EN_OVSDB_GET(engine_get_input("NB_nb_global", node));
+ const struct sbrec_sb_global_table *sb_global_table =
+ EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
+
+ const struct nbrec_nb_global *nb =
+ nbrec_nb_global_table_first(nb_global_table);
+ if (!nb) {
+ return false;
+ }
+
+ const struct sbrec_sb_global *sb =
+ sbrec_sb_global_table_first(sb_global_table);
+ if (!sb) {
+ return false;
+ }
+
+ /* We are only interested in ipsec and options column. */
+ bool changes_relevant = false;
+ if (nbrec_nb_global_is_updated(nb, NBREC_NB_GLOBAL_COL_IPSEC)
+ || nbrec_nb_global_is_updated(nb, NBREC_NB_GLOBAL_COL_OPTIONS)) {
+ changes_relevant = true;
+ }
+
+ if (!changes_relevant) {
+ return true;
+ }
+
+ const struct engine_context *eng_ctx = engine_get_context();
+ if (!eng_ctx->ovnsb_idl_txn) {
+ return false;
+ }
+
+ if (nb->ipsec != sb->ipsec) {
+ sbrec_sb_global_set_ipsec(sb, nb->ipsec);
+ }
+
+ struct ed_type_global_config *config_data = data;
+ config_data->tracked = true;
+
+ if (smap_equal(&nb->options, &config_data->nb_options)) {
+ return true;
+ }
+
+ /* Return false if an option is out of sync and requires updating the
+ * NB config. (Like svc_monitor_mac, max_tunid and mac_prefix). */
+ /* Check if svc_monitor_mac has changed or not. */
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "svc_monitor_mac", true)) {
+ return false;
+ }
+
+ /* Check if max_tunid has changed or not. */
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "max_tunid", true)) {
+ return false;
+ }
+
+ /* Check if mac_prefix has changed or not. */
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "mac_prefix", true)) {
+ return false;
+ }
+
+ /* Check if ignore_chassis_features has changed or not. */
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "ignore_chassis_features", false)) {
+ return false;
+ }
+
+ /* Check if northd_internal_version has changed or not. */
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "northd_internal_version", false)) {
+ return false;
+ }
+
+ if (check_nb_options_out_of_sync(nb, config_data)) {
+ config_data->tracked_data.nb_options_changed = true;
+ }
+
+ smap_destroy(&config_data->nb_options);
+ smap_clone(&config_data->nb_options, &nb->options);
+
+ update_sb_config_options_to_sbrec(config_data, sb);
+
+ engine_set_node_state(node, EN_UPDATED);
+ return true;
+}
+
+bool
+global_config_sb_global_handler(struct engine_node *node, void *data)
+{
+ const struct sbrec_sb_global_table *sb_global_table =
+ EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
+
+ const struct sbrec_sb_global *sb =
+ sbrec_sb_global_table_first(sb_global_table);
+ if (!sb) {
+ return false;
+ }
+
+ struct ed_type_global_config *config_data = data;
+
+ if (!smap_equal(&sb->options, &config_data->sb_options)) {
+ return false;
+ }
+
+ /* No need to update the engine node. */
+ return true;
+}
+
+bool
+global_config_sb_chassis_handler(struct engine_node *node, void *data)
+{
+ struct ed_type_global_config *config_data = data;
+
+ const struct sbrec_chassis_table *sbrec_chassis_table =
+ EN_OVSDB_GET(engine_get_input("SB_chassis", node));
+ const struct sbrec_chassis *chassis;
+
+ SBREC_CHASSIS_TABLE_FOR_EACH_TRACKED (chassis, sbrec_chassis_table) {
+ if (sbrec_chassis_is_new(chassis)
+ || sbrec_chassis_is_deleted(chassis)
+ || sbrec_chassis_is_updated(chassis,
+ SBREC_CHASSIS_COL_ENCAPS)) {
+ return false;
+ }
+
+ for (size_t i = 0; i < chassis->n_encaps; i++) {
+ if (sbrec_encap_row_get_seqno(chassis->encaps[i],
+ OVSDB_IDL_CHANGE_MODIFY) > 0) {
+ return false;
+ }
+ }
+ }
+
+ if (smap_get_bool(&config_data->nb_options, "ignore_chassis_features",
+ false)) {
+ return true;
+ }
+
+ bool reevaluate_chassis_features = false;
+
+ /* Check and evaluate chassis features. */
+ SBREC_CHASSIS_TABLE_FOR_EACH_TRACKED (chassis, sbrec_chassis_table) {
+ if (sbrec_chassis_is_updated(chassis,
+ SBREC_CHASSIS_COL_OTHER_CONFIG)) {
+ reevaluate_chassis_features = true;
+ break;
+ }
+ }
+
+ if (!reevaluate_chassis_features) {
+ return true;
+ }
+
+ struct chassis_features present_features = config_data->features;
+
+ /* Enable all features before calling build_chassis_features() as
+ * build_chassis_features() only sets the feature flags to false. */
+ northd_enable_all_features(config_data);
+ build_chassis_features(sbrec_chassis_table, &config_data->features);
+
+ if (chassis_features_changed(&present_features, &config_data->features)) {
+ config_data->tracked_data.chassis_features_changed = true;
+ config_data->tracked = true;
+ engine_set_node_state(node, EN_UPDATED);
+ }
+
+ return true;
+}
+
+/* generic global config handler for any engine node which has global_config
+ * has an input node . */
+bool
+node_global_config_handler(struct engine_node *node, void *data OVS_UNUSED)
+{
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
+
+ if (!global_config->tracked
+ || global_config->tracked_data.chassis_features_changed
+ || global_config->tracked_data.nb_options_changed) {
+ return false;
+ }
+
+ return true;
+}
+
+/* static functions. */
+static void
+northd_enable_all_features(struct ed_type_global_config *data)
+{
+ data->features = (struct chassis_features) {
+ .ct_no_masked_label = true,
+ .mac_binding_timestamp = true,
+ .ct_lb_related = true,
+ .fdb_timestamp = true,
+ .ls_dpg_column = true,
+ };
+}
+
+static void
+build_chassis_features(const struct sbrec_chassis_table *sbrec_chassis_table,
+ struct chassis_features *chassis_features)
+{
+ const struct sbrec_chassis *chassis;
+
+ SBREC_CHASSIS_TABLE_FOR_EACH (chassis, sbrec_chassis_table) {
+ /* Only consider local AZ chassis. Remote ones don't install
+ * flows generated by the local northd.
+ */
+ if (smap_get_bool(&chassis->other_config, "is-remote", false)) {
+ continue;
+ }
+
+ bool ct_no_masked_label =
+ smap_get_bool(&chassis->other_config,
+ OVN_FEATURE_CT_NO_MASKED_LABEL,
+ false);
+ if (!ct_no_masked_label && chassis_features->ct_no_masked_label) {
+ chassis_features->ct_no_masked_label = false;
+ }
+
+ bool mac_binding_timestamp =
+ smap_get_bool(&chassis->other_config,
+ OVN_FEATURE_MAC_BINDING_TIMESTAMP,
+ false);
+ if (!mac_binding_timestamp &&
+ chassis_features->mac_binding_timestamp) {
+ chassis_features->mac_binding_timestamp = false;
+ }
+
+ bool ct_lb_related =
+ smap_get_bool(&chassis->other_config,
+ OVN_FEATURE_CT_LB_RELATED,
+ false);
+ if (!ct_lb_related &&
+ chassis_features->ct_lb_related) {
+ chassis_features->ct_lb_related = false;
+ }
+
+ bool fdb_timestamp =
+ smap_get_bool(&chassis->other_config,
+ OVN_FEATURE_FDB_TIMESTAMP,
+ false);
+ if (!fdb_timestamp &&
+ chassis_features->fdb_timestamp) {
+ chassis_features->fdb_timestamp = false;
+ }
+
+ bool ls_dpg_column =
+ smap_get_bool(&chassis->other_config,
+ OVN_FEATURE_LS_DPG_COLUMN,
+ false);
+ if (!ls_dpg_column &&
+ chassis_features->ls_dpg_column) {
+ chassis_features->ls_dpg_column = false;
+ }
+ }
+}
+
+static bool
+config_out_of_sync(const struct smap *config, const struct smap *saved_config,
+ const char *key, bool must_be_present)
+{
+ const char *value = smap_get(config, key);
+ if (!value && must_be_present) {
+ return true;
+ }
+
+ const char *saved_value = smap_get(saved_config, key);
+ if (!saved_value && must_be_present) {
+ return true;
+ }
+
+ if (!value && !saved_value) {
+ return false;
+ }
+
+ if ((!value && saved_value) || (value && !saved_value)) {
+ return true;
+ }
+
+ return strcmp(value, saved_value);
+}
+
+static bool
+check_nb_options_out_of_sync(const struct nbrec_nb_global *nb,
+ struct ed_type_global_config *config_data)
+{
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "mac_binding_removal_limit", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "fdb_removal_limit", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "controller_event", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "ignore_lsp_down", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "use_ct_inv_match", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "default_acl_drop", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "debug_drop_domain_id", false)) {
+ init_debug_config(nb);
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "debug_drop_collector_set", false)) {
+ init_debug_config(nb);
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "use_common_zone", false)) {
+ return true;
+ }
+
+ if (config_out_of_sync(&nb->options, &config_data->nb_options,
+ "install_ls_lb_from_router", false)) {
+ return true;
+ }
+
+ return false;
+}
+
+static void
+update_sb_config_options_to_sbrec(struct ed_type_global_config *config_data,
+ const struct sbrec_sb_global *sb)
+{
+ struct smap *options = &config_data->sb_options;
+
+ smap_destroy(options);
+ smap_clone(options, &config_data->nb_options);
+
+ /* Inform ovn-controllers whether LB flows will use ct_mark (i.e., only
+ * if all chassis support it). If not explicitly present in the database
+ * the default value to be used for this option is 'true'.
+ */
+ if (!config_data->features.ct_no_masked_label) {
+ smap_replace(options, "lb_hairpin_use_ct_mark", "false");
+ } else {
+ smap_remove(options, "lb_hairpin_use_ct_mark");
+ }
+
+ /* Hackaround SB_global.options overwrite by NB_Global.options for
+ * 'sbctl_probe_interval' option.
+ */
+ const char *sip = smap_get(&sb->options, "sbctl_probe_interval");
+ if (sip) {
+ smap_replace(options, "sbctl_probe_interval", sip);
+ }
+
+ if (!smap_equal(&sb->options, options)) {
+ sbrec_sb_global_set_options(sb, options);
+ }
+}
+
+static bool
+chassis_features_changed(const struct chassis_features *present,
+ const struct chassis_features *updated)
+{
+ if (present->ct_no_masked_label != updated->ct_no_masked_label) {
+ return true;
+ }
+
+ if (present->mac_binding_timestamp != updated->mac_binding_timestamp) {
+ return true;
+ }
+
+ if (present->ct_lb_related != updated->ct_lb_related) {
+ return true;
+ }
+
+ if (present->fdb_timestamp != updated->fdb_timestamp) {
+ return true;
+ }
+
+ if (present->ls_dpg_column != updated->ls_dpg_column) {
+ return true;
+ }
+
+ return false;
+}
new file mode 100644
@@ -0,0 +1,65 @@
+#ifndef EN_GLOBAL_CONFIG_H
+#define EN_GLOBAL_CONFIG_H 1
+
+#include <config.h>
+
+/* OVS includes. */
+#include "lib/packets.h"
+#include "lib/smap.h"
+
+/* OVN includes. */
+#include "lib/inc-proc-eng.h"
+
+struct nbrec_nb_global;
+struct sbrec_sb_global;
+
+struct chassis_features {
+ bool ct_no_masked_label;
+ bool mac_binding_timestamp;
+ bool ct_lb_related;
+ bool fdb_timestamp;
+ bool ls_dpg_column;
+};
+
+struct global_config_tracked_data {
+ bool nb_options_changed;
+ bool chassis_features_changed;
+};
+
+/* struct which maintains the data of the engine node global_config. */
+struct ed_type_global_config {
+ struct smap nb_options;
+ struct smap sb_options;
+ const struct nbrec_nb_global *nb_global;
+ const struct sbrec_sb_global *sb_global;
+
+ /* MAC allocated for service monitor usage. Just one mac is allocated
+ * for this purpose and ovn-controller's on each chassis will make use
+ * of this mac when sending out the packets to monitor the services
+ * defined in Service_Monitor Southbound table. Since these packets
+ * are locally handled, having just one mac is good enough. */
+ char svc_monitor_mac[ETH_ADDR_STRLEN + 1];
+ struct eth_addr svc_monitor_mac_ea;
+
+ struct chassis_features features;
+
+ bool ovn_internal_version_changed;
+
+ bool tracked;
+ struct global_config_tracked_data tracked_data;
+};
+
+void *en_global_config_init(struct engine_node *, struct engine_arg *);
+void en_global_config_run(struct engine_node *, void *data);
+void en_global_config_cleanup(void *data);
+void en_global_config_clear_tracked_data(void *data);
+
+bool global_config_nb_global_handler(struct engine_node *, void *data);
+bool global_config_sb_global_handler(struct engine_node *, void *data);
+bool global_config_sb_chassis_handler(struct engine_node *, void *data);
+
+/* generic global config handler for any engine node which has global_config
+ * has an input node . */
+bool node_global_config_handler(struct engine_node *, void *data);
+
+#endif /* EN_GLOBAL_CONFIG_H */
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include "en-global-config.h"
#include "en-lflow.h"
#include "en-lr-nat.h"
#include "en-lr-stateful.h"
@@ -77,10 +78,14 @@ lflow_get_input_data(struct engine_node *node,
lflow_input->meter_groups = &sync_meters_data->meter_groups;
lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map;
lflow_input->svc_monitor_map = &northd_data->svc_monitor_map;
- lflow_input->features = &northd_data->features;
- lflow_input->ovn_internal_version_changed =
- northd_data->ovn_internal_version_changed;
lflow_input->bfd_connections = NULL;
+
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
+ lflow_input->features = &global_config->features;
+ lflow_input->ovn_internal_version_changed =
+ global_config->ovn_internal_version_changed;
+ lflow_input->svc_monitor_mac = global_config->svc_monitor_mac;
}
void en_lflow_run(struct engine_node *node, void *data)
@@ -19,6 +19,7 @@
#include <stdio.h>
#include "coverage.h"
+#include "en-global-config.h"
#include "en-northd.h"
#include "en-lb-data.h"
#include "lib/inc-proc-eng.h"
@@ -65,8 +66,6 @@ northd_get_input_data(struct engine_node *node,
engine_get_input("SB_fdb", node),
"sbrec_fdb_by_dp_and_port");
- input_data->nbrec_nb_global_table =
- EN_OVSDB_GET(engine_get_input("NB_nb_global", node));
input_data->nbrec_logical_switch_table =
EN_OVSDB_GET(engine_get_input("NB_logical_switch", node));
input_data->nbrec_logical_router_table =
@@ -78,8 +77,6 @@ northd_get_input_data(struct engine_node *node,
input_data->nbrec_mirror_table =
EN_OVSDB_GET(engine_get_input("NB_mirror", node));
- input_data->sbrec_sb_global_table =
- EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
input_data->sbrec_datapath_binding_table =
EN_OVSDB_GET(engine_get_input("SB_datapath_binding", node));
input_data->sbrec_port_binding_table =
@@ -109,6 +106,14 @@ northd_get_input_data(struct engine_node *node,
engine_get_input_data("lb_data", node);
input_data->lbs = &lb_data->lbs;
input_data->lbgrps = &lb_data->lbgrps;
+
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
+ input_data->nb_options = &global_config->nb_options;
+ input_data->sb_options = &global_config->sb_options;
+ input_data->svc_monitor_mac = global_config->svc_monitor_mac;
+ input_data->svc_monitor_mac_ea = global_config->svc_monitor_mac_ea;
+ input_data->features = &global_config->features;
}
void
@@ -129,31 +134,6 @@ en_northd_run(struct engine_node *node, void *data)
eng_ctx->ovnsb_idl_txn);
stopwatch_stop(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec());
engine_set_node_state(node, EN_UPDATED);
-
-}
-
-bool
-northd_nb_nb_global_handler(struct engine_node *node,
- void *data OVS_UNUSED)
-{
- const struct nbrec_nb_global_table *nb_global_table
- = EN_OVSDB_GET(engine_get_input("NB_nb_global", node));
-
- const struct nbrec_nb_global *nb =
- nbrec_nb_global_table_first(nb_global_table);
-
- if (!nb) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "NB_Global is updated but has no record.");
- return false;
- }
-
- /* We care about the 'options' and 'ipsec' columns only. */
- if (nbrec_nb_global_is_updated(nb, NBREC_NB_GLOBAL_COL_OPTIONS) ||
- nbrec_nb_global_is_updated(nb, NBREC_NB_GLOBAL_COL_IPSEC)) {
- return false;
- }
- return true;
}
bool
@@ -242,6 +222,20 @@ northd_lb_data_handler(struct engine_node *node, void *data)
return true;
}
+bool
+northd_global_config_handler(struct engine_node *node, void *data OVS_UNUSED)
+{
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
+
+ if (!global_config->tracked
+ || global_config->tracked_data.nb_options_changed) {
+ return false;
+ }
+
+ return true;
+}
+
void
*en_northd_init(struct engine_node *node OVS_UNUSED,
struct engine_arg *arg OVS_UNUSED)
@@ -14,7 +14,7 @@ void *en_northd_init(struct engine_node *node OVS_UNUSED,
struct engine_arg *arg);
void en_northd_cleanup(void *data);
void en_northd_clear_tracked_data(void *data);
-bool northd_nb_nb_global_handler(struct engine_node *, void *data OVS_UNUSED);
+bool northd_global_config_handler(struct engine_node *, void *data OVS_UNUSED);
bool northd_nb_logical_switch_handler(struct engine_node *, void *data);
bool northd_nb_logical_router_handler(struct engine_node *, void *data);
bool northd_sb_port_binding_handler(struct engine_node *, void *data);
@@ -22,6 +22,7 @@
#include "openvswitch/util.h"
#include "en-lr-nat.h"
+#include "en-global-config.h"
#include "en-lr-stateful.h"
#include "en-sync-sb.h"
#include "lib/inc-proc-eng.h"
@@ -42,7 +43,8 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
const struct nbrec_address_set_table *,
const struct nbrec_port_group_table *,
const struct sbrec_address_set_table *,
- const struct lr_stateful_table *);
+ const struct lr_stateful_table *,
+ const char *svc_monitor_macp);
static const struct sbrec_address_set *sb_address_set_lookup_by_name(
struct ovsdb_idl_index *, const char *name);
static void update_sb_addr_set(struct sorted_array *,
@@ -90,9 +92,12 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED)
const struct engine_context *eng_ctx = engine_get_context();
const struct ed_type_lr_stateful *lr_stateful_data =
engine_get_input_data("lr_stateful", node);
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table,
nb_port_group_table, sb_address_set_table,
- &lr_stateful_data->lr_sful_table);
+ &lr_stateful_data->lr_sful_table,
+ global_config->svc_monitor_mac);
engine_set_node_state(node, EN_UPDATED);
}
@@ -218,12 +223,14 @@ en_sync_to_sb_lb_run(struct engine_node *node, void *data OVS_UNUSED)
{
const struct sbrec_load_balancer_table *sb_load_balancer_table =
EN_OVSDB_GET(engine_get_input("SB_load_balancer", node));
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
const struct engine_context *eng_ctx = engine_get_context();
struct northd_data *northd_data = engine_get_input_data("northd", node);
sync_lbs(eng_ctx->ovnsb_idl_txn, sb_load_balancer_table,
&northd_data->ls_datapaths, &northd_data->lr_datapaths,
- &northd_data->lb_datapaths_map, &northd_data->features);
+ &northd_data->lb_datapaths_map, &global_config->features);
engine_set_node_state(node, EN_UPDATED);
}
@@ -369,7 +376,8 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
const struct nbrec_address_set_table *nb_address_set_table,
const struct nbrec_port_group_table *nb_port_group_table,
const struct sbrec_address_set_table *sb_address_set_table,
- const struct lr_stateful_table *lr_statefuls)
+ const struct lr_stateful_table *lr_statefuls,
+ const char *svc_monitor_macp)
{
struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets);
@@ -380,8 +388,10 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
}
/* Service monitor MAC. */
- const char *svc_monitor_macp = northd_get_svc_monitor_mac();
- struct sorted_array svc = sorted_array_create(&svc_monitor_macp, 1, false);
+ struct sorted_array svc = {
+ .arr = &svc_monitor_macp,
+ .n = 1,
+ };
sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc, &sb_address_sets);
sorted_array_destroy(&svc);
@@ -30,6 +30,7 @@
#include "openvswitch/poll-loop.h"
#include "openvswitch/vlog.h"
#include "inc-proc-northd.h"
+#include "en-global-config.h"
#include "en-lb-data.h"
#include "en-lr-stateful.h"
#include "en-lr-nat.h"
@@ -149,6 +150,7 @@ static ENGINE_NODE(fdb_aging, "fdb_aging");
static ENGINE_NODE(fdb_aging_waker, "fdb_aging_waker");
static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb");
static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb");
+static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(global_config, "global_config");
static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data");
static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat");
static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_stateful, "lr_stateful");
@@ -168,11 +170,17 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
engine_add_input(&en_lb_data, &en_nb_logical_router,
lb_data_logical_router_handler);
+ engine_add_input(&en_global_config, &en_nb_nb_global,
+ global_config_nb_global_handler);
+ engine_add_input(&en_global_config, &en_sb_sb_global,
+ global_config_sb_global_handler);
+ engine_add_input(&en_global_config, &en_sb_chassis,
+ global_config_sb_chassis_handler);
+
engine_add_input(&en_northd, &en_nb_mirror, 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);
engine_add_input(&en_northd, &en_sb_mirror, NULL);
engine_add_input(&en_northd, &en_sb_meter, NULL);
@@ -185,11 +193,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
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_northd, &en_global_config,
+ northd_global_config_handler);
engine_add_input(&en_northd, &en_sb_port_binding,
northd_sb_port_binding_handler);
- engine_add_input(&en_northd, &en_nb_nb_global,
- northd_nb_nb_global_handler);
engine_add_input(&en_northd, &en_nb_logical_switch,
northd_nb_logical_switch_handler);
engine_add_input(&en_northd, &en_nb_logical_router,
@@ -207,15 +215,17 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
engine_add_input(&en_ls_stateful, &en_port_group,
ls_stateful_port_group_handler);
- 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);
engine_add_input(&en_mac_binding_aging, &en_mac_binding_aging_waker, NULL);
+ engine_add_input(&en_mac_binding_aging, &en_global_config,
+ node_global_config_handler);
- engine_add_input(&en_fdb_aging, &en_nb_nb_global, NULL);
engine_add_input(&en_fdb_aging, &en_sb_fdb, NULL);
engine_add_input(&en_fdb_aging, &en_northd, NULL);
engine_add_input(&en_fdb_aging, &en_fdb_aging_waker, NULL);
+ engine_add_input(&en_fdb_aging, &en_global_config,
+ node_global_config_handler);
engine_add_input(&en_sync_meters, &en_nb_acl, NULL);
engine_add_input(&en_sync_meters, &en_nb_meter, NULL);
@@ -229,18 +239,22 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
engine_add_input(&en_lflow, &en_sb_multicast_group, NULL);
engine_add_input(&en_lflow, &en_sb_igmp_group, NULL);
engine_add_input(&en_lflow, &en_sb_logical_dp_group, NULL);
+ engine_add_input(&en_lflow, &en_global_config,
+ node_global_config_handler);
engine_add_input(&en_lflow, &en_northd, lflow_northd_handler);
engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler);
engine_add_input(&en_lflow, &en_lr_stateful, lflow_lr_stateful_handler);
engine_add_input(&en_lflow, &en_ls_stateful, lflow_ls_stateful_handler);
+ engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL);
+ engine_add_input(&en_sync_to_sb_addr_set, &en_lr_stateful, NULL);
+ engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL);
engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set,
sync_to_sb_addr_set_nb_address_set_handler);
engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group,
sync_to_sb_addr_set_nb_port_group_handler);
- engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL);
- engine_add_input(&en_sync_to_sb_addr_set, &en_lr_stateful, NULL);
- engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL);
+ engine_add_input(&en_sync_to_sb_addr_set, &en_global_config,
+ node_global_config_handler);
engine_add_input(&en_port_group, &en_nb_port_group,
port_group_nb_port_group_handler);
@@ -250,6 +264,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
* table too (because of the explicit dependency in the schema). */
engine_add_input(&en_port_group, &en_northd, engine_noop_handler);
+ engine_add_input(&en_sync_to_sb_lb, &en_global_config,
+ node_global_config_handler);
engine_add_input(&en_sync_to_sb_lb, &en_northd,
sync_to_sb_lb_northd_handler);
engine_add_input(&en_sync_to_sb_lb, &en_sb_load_balancer,
@@ -354,11 +370,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
"sbrec_fdb_by_dp_and_port",
sbrec_fdb_by_dp_and_port);
- struct northd_data *northd_data =
- engine_get_internal_data(&en_northd);
+ struct ed_type_global_config *global_config =
+ engine_get_internal_data(&en_global_config);
unixctl_command_register("debug/chassis-features-list", "", 0, 0,
chassis_features_list,
- &northd_data->features);
+ &global_config->features);
}
/* Returns true if the incremental processing ended up updating nodes. */
@@ -43,6 +43,7 @@
#include "lflow-mgr.h"
#include "memory.h"
#include "northd.h"
+#include "en-global-config.h"
#include "en-lb-data.h"
#include "en-lr-nat.h"
#include "en-lr-stateful.h"
@@ -77,14 +78,6 @@ static bool install_ls_lb_from_router;
/* Use common zone for SNAT and DNAT if this option is set to "true". */
static bool use_common_zone = false;
-/* MAC allocated for service monitor usage. Just one mac is allocatedg5534
- * for this purpose and ovn-controller's on each chassis will make use
- * of this mac when sending out the packets to monitor the services
- * defined in Service_Monitor Southbound table. Since these packets
- * all locally handled, having just one mac is good enough. */
-static char svc_monitor_mac[ETH_ADDR_STRLEN + 1];
-static struct eth_addr svc_monitor_mac_ea;
-
/* If this option is 'true' northd will make use of ct.inv match fields.
* Otherwise, it will avoid using it. The default is true. */
static bool use_ct_inv_match = true;
@@ -295,66 +288,6 @@ ovn_stage_to_datapath_type(enum ovn_stage stage)
}
}
-static void
-build_chassis_features(const struct sbrec_chassis_table *sbrec_chassis_table,
- struct chassis_features *chassis_features)
-{
- const struct sbrec_chassis *chassis;
-
- SBREC_CHASSIS_TABLE_FOR_EACH (chassis, sbrec_chassis_table) {
- /* Only consider local AZ chassis. Remote ones don't install
- * flows generated by the local northd.
- */
- if (smap_get_bool(&chassis->other_config, "is-remote", false)) {
- continue;
- }
-
- bool ct_no_masked_label =
- smap_get_bool(&chassis->other_config,
- OVN_FEATURE_CT_NO_MASKED_LABEL,
- false);
- if (!ct_no_masked_label && chassis_features->ct_no_masked_label) {
- chassis_features->ct_no_masked_label = false;
- }
-
- bool mac_binding_timestamp =
- smap_get_bool(&chassis->other_config,
- OVN_FEATURE_MAC_BINDING_TIMESTAMP,
- false);
- if (!mac_binding_timestamp &&
- chassis_features->mac_binding_timestamp) {
- chassis_features->mac_binding_timestamp = false;
- }
-
- bool ct_lb_related =
- smap_get_bool(&chassis->other_config,
- OVN_FEATURE_CT_LB_RELATED,
- false);
- if (!ct_lb_related &&
- chassis_features->ct_lb_related) {
- chassis_features->ct_lb_related = false;
- }
-
- bool fdb_timestamp =
- smap_get_bool(&chassis->other_config,
- OVN_FEATURE_FDB_TIMESTAMP,
- false);
- if (!fdb_timestamp &&
- chassis_features->fdb_timestamp) {
- chassis_features->fdb_timestamp = false;
- }
-
- bool ls_dpg_column =
- smap_get_bool(&chassis->other_config,
- OVN_FEATURE_LS_DPG_COLUMN,
- false);
- if (!ls_dpg_column &&
- chassis_features->ls_dpg_column) {
- chassis_features->ls_dpg_column = false;
- }
- }
-}
-
static uint32_t
allocate_queueid(unsigned long *queue_id_bitmap)
{
@@ -946,7 +879,7 @@ is_vxlan_mode(const struct sbrec_chassis_table *sbrec_chassis_table)
return false;
}
-static uint32_t
+uint32_t
get_ovn_max_dp_key_local(const struct sbrec_chassis_table *sbrec_chassis_table)
{
if (is_vxlan_mode(sbrec_chassis_table)) {
@@ -3354,6 +3287,8 @@ create_or_get_service_mon(struct ovsdb_idl_txn *ovnsb_txn,
static void
ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
const struct ovn_northd_lb *lb,
+ const char *svc_monitor_mac,
+ const struct eth_addr *svc_monitor_mac_ea,
struct hmap *monitor_map, struct hmap *ls_ports,
struct sset *svc_monitor_lsps)
{
@@ -3399,7 +3334,7 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
struct eth_addr ea;
if (!mon_info->sbrec_mon->src_mac ||
!eth_addr_from_string(mon_info->sbrec_mon->src_mac, &ea) ||
- !eth_addr_equals(ea, svc_monitor_mac_ea)) {
+ !eth_addr_equals(ea, *svc_monitor_mac_ea)) {
sbrec_service_monitor_set_src_mac(mon_info->sbrec_mon,
svc_monitor_mac);
}
@@ -3724,6 +3659,8 @@ static void
build_lb_svcs(
struct ovsdb_idl_txn *ovnsb_txn,
const struct sbrec_service_monitor_table *sbrec_service_monitor_table,
+ const char *svc_monitor_mac,
+ const struct eth_addr *svc_monitor_mac_ea,
struct hmap *ls_ports, struct hmap *lb_dps_map,
struct sset *svc_monitor_lsps,
struct hmap *svc_monitor_map)
@@ -3742,7 +3679,8 @@ build_lb_svcs(
struct ovn_lb_datapaths *lb_dps;
HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
- ovn_lb_svc_create(ovnsb_txn, lb_dps->lb, svc_monitor_map, ls_ports,
+ ovn_lb_svc_create(ovnsb_txn, lb_dps->lb, svc_monitor_mac,
+ svc_monitor_mac_ea, svc_monitor_map, ls_ports,
svc_monitor_lsps);
}
@@ -3834,13 +3772,16 @@ static void
build_lb_port_related_data(
struct ovsdb_idl_txn *ovnsb_txn,
const struct sbrec_service_monitor_table *sbrec_service_monitor_table,
+ const char *svc_monitor_mac,
+ const struct eth_addr *svc_monitor_mac_ea,
struct ovn_datapaths *lr_datapaths, struct hmap *ls_ports,
struct hmap *lb_dps_map, struct hmap *lb_group_dps_map,
struct sset *svc_monitor_lsps,
struct hmap *svc_monitor_map)
{
build_lrouter_lbs_check(lr_datapaths);
- build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map,
+ build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, svc_monitor_mac,
+ svc_monitor_mac_ea, ls_ports, lb_dps_map,
svc_monitor_lsps, svc_monitor_map);
build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map);
}
@@ -9378,6 +9319,7 @@ build_lswitch_arp_nd_responder_default(struct ovn_datapath *od,
static void
build_lswitch_arp_nd_service_monitor(const struct ovn_northd_lb *lb,
const struct hmap *ls_ports,
+ const char *svc_monitor_mac,
struct lflow_table *lflows,
struct ds *actions,
struct ds *match,
@@ -15783,6 +15725,7 @@ struct lswitch_flow_build_info {
struct ds match;
struct ds actions;
size_t thread_lflow_counter;
+ const char *svc_monitor_mac;
};
/* Helper function to combine all lflow generation which is iterated by
@@ -16010,6 +15953,7 @@ build_lflows_thread(void *arg)
}
build_lswitch_arp_nd_service_monitor(lb_dps->lb,
lsi->ls_ports,
+ lsi->svc_monitor_mac,
lsi->lflows,
&lsi->match,
&lsi->actions,
@@ -16133,7 +16077,8 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
const struct hmap *lb_dps_map,
const struct hmap *svc_monitor_map,
const struct hmap *bfd_connections,
- const struct chassis_features *features)
+ const struct chassis_features *features,
+ const char *svc_monitor_mac)
{
char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
@@ -16166,6 +16111,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
lsiv[index].features = features;
lsiv[index].svc_check_match = svc_check_match;
lsiv[index].thread_lflow_counter = 0;
+ lsiv[index].svc_monitor_mac = svc_monitor_mac;
ds_init(&lsiv[index].match);
ds_init(&lsiv[index].actions);
@@ -16205,6 +16151,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
.bfd_connections = bfd_connections,
.features = features,
.svc_check_match = svc_check_match,
+ .svc_monitor_mac = svc_monitor_mac,
.match = DS_EMPTY_INITIALIZER,
.actions = DS_EMPTY_INITIALIZER,
};
@@ -16247,6 +16194,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths,
stopwatch_start(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
build_lswitch_arp_nd_service_monitor(lb_dps->lb, lsi.ls_ports,
+ lsi.svc_monitor_mac,
lsi.lflows, &lsi.actions,
&lsi.match,
lb_dps->lflow_ref);
@@ -16365,7 +16313,8 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn,
input_data->lb_datapaths_map,
input_data->svc_monitor_map,
input_data->bfd_connections,
- input_data->features);
+ input_data->features,
+ input_data->svc_monitor_mac);
if (parallelization_state == STATE_INIT_HASH_SIZES) {
parallelization_state = STATE_USE_PARALLELIZATION;
@@ -16634,6 +16583,7 @@ lflow_handle_northd_lb_changes(struct ovsdb_idl_txn *ovnsb_txn,
struct ds actions = DS_EMPTY_INITIALIZER;
build_lswitch_arp_nd_service_monitor(lb_dps->lb, lflow_input->ls_ports,
+ lflow_input->svc_monitor_mac,
lflows, &actions,
&match, lb_dps->lflow_ref);
build_lrouter_defrag_flows_for_lb(lb_dps, lflows,
@@ -17411,18 +17361,6 @@ destroy_datapaths_and_ports(struct ovn_datapaths *ls_datapaths,
ovn_datapaths_destroy(lr_datapaths);
}
-static void
-northd_enable_all_features(struct northd_data *data)
-{
- data->features = (struct chassis_features) {
- .ct_no_masked_label = true,
- .mac_binding_timestamp = true,
- .ct_lb_related = true,
- .fdb_timestamp = true,
- .ls_dpg_column = true,
- };
-}
-
void
northd_init(struct northd_data *data)
{
@@ -17433,8 +17371,6 @@ northd_init(struct northd_data *data)
hmap_init(&data->lb_datapaths_map);
hmap_init(&data->lb_group_datapaths_map);
ovs_list_init(&data->lr_list);
- northd_enable_all_features(data);
- data->ovn_internal_version_changed = false;
sset_init(&data->svc_monitor_lsps);
hmap_init(&data->svc_monitor_map);
init_northd_tracked_data(data);
@@ -17474,7 +17410,6 @@ northd_destroy(struct northd_data *data)
destroy_datapaths_and_ports(&data->ls_datapaths, &data->lr_datapaths,
&data->ls_ports, &data->lr_ports,
&data->lr_list);
- destroy_debug_config();
sset_destroy(&data->svc_monitor_lsps);
destroy_northd_tracked_data(data);
@@ -17491,83 +17426,22 @@ ovnnb_db_run(struct northd_input *input_data,
}
stopwatch_start(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
- /* Sync ipsec configuration.
- * Copy nb_cfg from northbound to southbound database.
- * Also set up to update sb_cfg once our southbound transaction commits. */
- const struct nbrec_nb_global *nb = nbrec_nb_global_table_first(
- input_data->nbrec_nb_global_table);
- if (!nb) {
- nb = nbrec_nb_global_insert(ovnnb_txn);
- }
-
- const char *mac_addr_prefix = set_mac_prefix(smap_get(&nb->options,
- "mac_prefix"));
-
- const char *monitor_mac = smap_get(&nb->options, "svc_monitor_mac");
- if (monitor_mac) {
- if (eth_addr_from_string(monitor_mac, &svc_monitor_mac_ea)) {
- snprintf(svc_monitor_mac, sizeof svc_monitor_mac,
- ETH_ADDR_FMT, ETH_ADDR_ARGS(svc_monitor_mac_ea));
- } else {
- monitor_mac = NULL;
- }
- }
-
- struct smap options;
- smap_clone(&options, &nb->options);
-
- smap_replace(&options, "mac_prefix", mac_addr_prefix);
-
- if (!monitor_mac) {
- eth_addr_random(&svc_monitor_mac_ea);
- snprintf(svc_monitor_mac, sizeof svc_monitor_mac,
- ETH_ADDR_FMT, ETH_ADDR_ARGS(svc_monitor_mac_ea));
- smap_replace(&options, "svc_monitor_mac", svc_monitor_mac);
- }
-
- char *max_tunid = xasprintf("%d",
- get_ovn_max_dp_key_local(input_data->sbrec_chassis_table));
- smap_replace(&options, "max_tunid", max_tunid);
- free(max_tunid);
-
- char *ovn_internal_version = ovn_get_internal_version();
- if (!strcmp(ovn_internal_version,
- smap_get_def(&options, "northd_internal_version", ""))) {
- data->ovn_internal_version_changed = false;
- } else {
- smap_replace(&options, "northd_internal_version",
- ovn_internal_version);
- }
- free(ovn_internal_version);
-
- if (!smap_equal(&nb->options, &options)) {
- nbrec_nb_global_verify_options(nb);
- nbrec_nb_global_set_options(nb, &options);
- }
-
- use_ct_inv_match = smap_get_bool(&nb->options,
+ use_ct_inv_match = smap_get_bool(input_data->nb_options,
"use_ct_inv_match", true);
/* deprecated, use --event instead */
- controller_event_en = smap_get_bool(&nb->options,
+ controller_event_en = smap_get_bool(input_data->nb_options,
"controller_event", false);
- check_lsp_is_up = !smap_get_bool(&nb->options,
+ check_lsp_is_up = !smap_get_bool(input_data->nb_options,
"ignore_lsp_down", true);
- default_acl_drop = smap_get_bool(&nb->options, "default_acl_drop", false);
+ default_acl_drop = smap_get_bool(input_data->nb_options,
+ "default_acl_drop", false);
- install_ls_lb_from_router = smap_get_bool(&nb->options,
+ install_ls_lb_from_router = smap_get_bool(input_data->nb_options,
"install_ls_lb_from_router",
false);
- use_common_zone = smap_get_bool(&nb->options, "use_common_zone", false);
-
- if (smap_get_bool(&nb->options, "ignore_chassis_features", false)) {
- northd_enable_all_features(data);
- } else {
- build_chassis_features(input_data->sbrec_chassis_table,
- &data->features);
- }
-
- init_debug_config(nb);
+ use_common_zone = smap_get_bool(input_data->nb_options, "use_common_zone",
+ false);
build_datapaths(ovnsb_txn,
input_data->nbrec_logical_switch_table,
@@ -17592,6 +17466,8 @@ ovnnb_db_run(struct northd_input *input_data,
&data->ls_ports, &data->lr_ports);
build_lb_port_related_data(ovnsb_txn,
input_data->sbrec_service_monitor_table,
+ input_data->svc_monitor_mac,
+ &input_data->svc_monitor_mac_ea,
&data->lr_datapaths, &data->ls_ports,
&data->lb_datapaths_map,
&data->lb_group_datapaths_map,
@@ -17624,38 +17500,6 @@ ovnnb_db_run(struct northd_input *input_data,
&data->ls_datapaths.datapaths);
stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
- /* Set up SB_Global (depends on chassis features). */
- const struct sbrec_sb_global *sb = sbrec_sb_global_table_first(
- input_data->sbrec_sb_global_table);
- if (!sb) {
- sb = sbrec_sb_global_insert(ovnsb_txn);
- }
- if (nb->ipsec != sb->ipsec) {
- sbrec_sb_global_set_ipsec(sb, nb->ipsec);
- }
-
- /* Inform ovn-controllers whether LB flows will use ct_mark (i.e., only
- * if all chassis support it). If not explicitly present in the database
- * the default value to be used for this option is 'true'.
- */
- if (!data->features.ct_no_masked_label) {
- smap_replace(&options, "lb_hairpin_use_ct_mark", "false");
- } else {
- smap_remove(&options, "lb_hairpin_use_ct_mark");
- }
-
- /* Hackaround SB_global.options overwrite by NB_Global.options for
- * 'sbctl_probe_interval' option.
- */
- const char *sip = smap_get(&sb->options, "sbctl_probe_interval");
- if (sip) {
- smap_replace(&options, "sbctl_probe_interval", sip);
- }
-
- if (!smap_equal(&sb->options, &options)) {
- sbrec_sb_global_set_options(sb, &options);
- }
- smap_destroy(&options);
}
/* Stores the set of chassis which references an ha_chassis_group.
@@ -17946,12 +17790,6 @@ ovnsb_db_run(struct ovsdb_idl_txn *ovnnb_txn,
ovn_update_ipv6_prefix(lr_ports);
}
-const char *
-northd_get_svc_monitor_mac(void)
-{
- return svc_monitor_mac;
-}
-
const struct ovn_datapath *
northd_get_datapath_for_port(const struct hmap *ls_ports,
const char *port_name)
@@ -27,7 +27,6 @@
struct northd_input {
/* Northbound table references */
- const struct nbrec_nb_global_table *nbrec_nb_global_table;
const struct nbrec_logical_switch_table *nbrec_logical_switch_table;
const struct nbrec_logical_router_table *nbrec_logical_router_table;
const struct nbrec_static_mac_binding_table
@@ -37,7 +36,6 @@ struct northd_input {
const struct nbrec_mirror_table *nbrec_mirror_table;
/* Southbound table references */
- const struct sbrec_sb_global_table *sbrec_sb_global_table;
const struct sbrec_datapath_binding_table *sbrec_datapath_binding_table;
const struct sbrec_port_binding_table *sbrec_port_binding_table;
const struct sbrec_mac_binding_table *sbrec_mac_binding_table;
@@ -57,6 +55,13 @@ struct northd_input {
const struct hmap *lbs;
const struct hmap *lbgrps;
+ /* Global config data node inputs. */
+ const struct smap *nb_options;
+ const struct smap *sb_options;
+ const char *svc_monitor_mac;
+ struct eth_addr svc_monitor_mac_ea;
+ const struct chassis_features *features;
+
/* Indexes */
struct ovsdb_idl_index *sbrec_chassis_by_name;
struct ovsdb_idl_index *sbrec_chassis_by_hostname;
@@ -66,14 +71,6 @@ struct northd_input {
struct ovsdb_idl_index *sbrec_fdb_by_dp_and_port;
};
-struct chassis_features {
- bool ct_no_masked_label;
- bool mac_binding_timestamp;
- bool ct_lb_related;
- bool fdb_timestamp;
- bool ls_dpg_column;
-};
-
/* A collection of datapaths. E.g. all logical switch datapaths, or all
* logical router datapaths. */
struct ovn_datapaths {
@@ -208,8 +205,6 @@ struct northd_data {
struct hmap lb_datapaths_map;
struct hmap lb_group_datapaths_map;
struct ovs_list lr_list;
- bool ovn_internal_version_changed;
- struct chassis_features features;
struct sset svc_monitor_lsps;
struct hmap svc_monitor_map;
@@ -246,6 +241,7 @@ struct lflow_input {
const struct chassis_features *features;
const struct hmap *svc_monitor_map;
bool ovn_internal_version_changed;
+ const char *svc_monitor_mac;
};
extern int parallelization_state;
@@ -764,8 +760,6 @@ void bfd_cleanup_connections(const struct nbrec_bfd_table *,
struct hmap *bfd_map);
void run_update_worker_pool(int n_threads);
-const char *northd_get_svc_monitor_mac(void);
-
const struct ovn_datapath *northd_get_datapath_for_port(
const struct hmap *ls_ports, const char *port_name);
void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *,
@@ -829,4 +823,6 @@ bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr);
bool lrouter_port_ipv6_reachable(const struct ovn_port *,
const struct in6_addr *);
+uint32_t get_ovn_max_dp_key_local(const struct sbrec_chassis_table *);
+
#endif /* NORTHD_H */
@@ -8704,7 +8704,7 @@ AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [d
table=??(ls_in_lb ), priority=0 , match=(1), action=(next;)
])
-ovn-nbctl --wait=sb set NB_Global . options:install_ls_lb_from_router=true
+check ovn-nbctl --wait=sb set NB_Global . options:install_ls_lb_from_router=true
ovn-sbctl dump-flows S0 > S0flows
ovn-sbctl dump-flows S1 > S1flows
@@ -8723,6 +8723,7 @@ AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [d
table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
])
+
ovn-sbctl get datapath S0 _uuid > dp_uuids
ovn-sbctl get datapath S1 _uuid >> dp_uuids
lb_dp_group=$(ovn-sbctl --bare --columns ls_datapath_group find Load_Balancer name=lb0)
@@ -8731,7 +8732,7 @@ AT_CHECK_UNQUOTED([ovn-sbctl --bare --columns _uuid,datapaths find Logical_DP_Gr
$(cat dp_uuids | sort)
])
-ovn-nbctl --wait=sb set NB_Global . options:install_ls_lb_from_router=false
+check ovn-nbctl --wait=sb set NB_Global . options:install_ls_lb_from_router=false
ovn-sbctl dump-flows S0 > S0flows
ovn-sbctl dump-flows S1 > S1flows
@@ -9088,12 +9089,11 @@ $4
AS_BOX([Create new PG1 and PG2])
check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
check ovn-nbctl --wait=sb -- pg-add pg1 -- pg-add pg2
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl The port_group node recomputes every time a NB port group is added/deleted.
@@ -9126,12 +9126,11 @@ check ovn-nbctl --wait=sb \
check_column "sw1.1" sb:Port_Group ports name="${sw1_key}_pg1"
check_column "sw2.1" sb:Port_Group ports name="${sw2_key}_pg1"
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl The port_group node recomputes also every time a port from a new switch
@@ -9163,12 +9162,11 @@ check_column "sw2.1" sb:Port_Group ports name="${sw2_key}_pg1"
check_column "sw1.2" sb:Port_Group ports name="${sw1_key}_pg2"
check_column "sw2.2" sb:Port_Group ports name="${sw2_key}_pg2"
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl The port_group node recomputes also every time a port from a new switch
@@ -9201,12 +9199,11 @@ check_column "sw2.1 sw2.3" sb:Port_Group ports name="${sw2_key}_pg1"
check_column "sw1.2 sw1.3" sb:Port_Group ports name="${sw1_key}_pg2"
check_column "sw2.2 sw2.3" sb:Port_Group ports name="${sw2_key}_pg2"
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl We did not change the set of switches a pg is applied to, there should be
@@ -9244,7 +9241,7 @@ dnl though, therefore "compute: 1".
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl We did not change the set of switches a pg is applied to, there should be
@@ -9276,12 +9273,11 @@ check_column "sw1.2" sb:Port_Group ports name="${sw1_key}_pg2"
AT_CHECK([fetch_column sb:Port_Group ports name="${sw2_key}_pg2"], [0], [
])
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl We changed the set of switches a pg is applied to, there should be
@@ -9314,12 +9310,11 @@ check_column "sw1.2" sb:Port_Group ports name="${sw1_key}_pg2"
AT_CHECK([fetch_column sb:Port_Group ports name="${sw2_key}_pg2"], [0], [
])
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl We changed the set of switches a pg is applied to, there should be
@@ -9352,12 +9347,11 @@ check_column "sw2.1" sb:Port_Group ports name="${sw2_key}_pg1"
check_column "sw1.2" sb:Port_Group ports name="${sw1_key}_pg2"
check_column "sw2.2" sb:Port_Group ports name="${sw2_key}_pg2"
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl We changed the set of switches a pg is applied to, there should be a
@@ -9392,12 +9386,11 @@ check_column "sw1.2" sb:Port_Group ports name="${sw1_key}_pg2"
AT_CHECK([fetch_column sb:Port_Group ports name="${sw2_key}_pg2"], [0], [
])
-dnl The northd node should not recompute, it should handle nb_global update
-dnl though, therefore "compute: 1".
+dnl The northd node should not recompute,.
AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd], [0], [dnl
Node: northd
- recompute: 0
-- compute: 1
+- compute: 0
- abort: 0
])
dnl We changed the set of switches a pg is applied to, there should be a
@@ -11343,3 +11336,212 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE
OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([NB_Global and SB_Global incremental processing])
+
+ovn_start
+
+check_engine_stats() {
+ node=$1
+ recompute=$2
+ compute=$3
+
+ echo "__file__:__line__: Checking engine stats for node $node : recompute - \
+$recompute : compute - $compute"
+
+ node_stat=$(as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats $node)
+ # node_stat will be of this format :
+ # - Node: lflow - recompute: 3 - compute: 0 - abort: 0
+ node_recompute_ct=$(echo $node_stat | cut -d '-' -f2 | cut -d ':' -f2)
+ node_compute_ct=$(echo $node_stat | cut -d '-' -f3 | cut -d ':' -f2)
+
+ if [[ "$recompute" == "norecompute" ]]; then
+ # node should not be recomputed
+ echo "Expecting $node recompute count - $node_recompute_ct to be 0"
+ check test "$node_recompute_ct" -eq "0"
+ else
+ echo "Expecting $node recompute count - $node_recompute_ct not to be 0"
+ check test "$node_recompute_ct" -ne "0"
+ fi
+
+ if [[ "$compute" == "nocompute" ]]; then
+ # node should not be computed
+ echo "Expecting $node compute count - $node_compute_ct to be 0"
+ check test "$node_compute_ct" -eq "0"
+ else
+ echo "Expecting $node compute count - $node_compute_ct not to be 0"
+ check test "$node_compute_ct" -ne "0"
+ fi
+}
+
+check ovn-nbctl ls-add sw0
+check ovn-nbctl lr-add lr0
+check ovn-nbctl lsp-add sw0 sw0-p1 -- lsp-set-addresses sw0-p1 "00:00:20:20:00:03 10.0.0.3"
+check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:20:20:12:14 10.0.0.1/24
+check ovn-nbctl lsp-add sw0 sw0-lr0
+check ovn-nbctl lsp-set-type sw0-lr0 router
+check ovn-nbctl lsp-set-addresses sw0-lr0 router
+check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+
+# This should not result in recomputes.
+check ovn-nbctl --wait=sb set NB_Global . options:foo=bar
+check_engine_stats global_config norecompute compute
+check_engine_stats northd norecompute compute
+check_engine_stats lflow norecompute compute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+# This should result in recomputes.
+check ovn-sbctl set SB_Global . options:bar=foo
+check_engine_stats global_config recompute compute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+# Clears an nb option and checks that recomputes were triggered
+# and the option was added back by ovn-northd or not depending
+# on the 'added_back' argument.
+clear_nb_option() {
+ option=$1
+ add_back=$2
+ echo "clearing the nb option - $option"
+ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+ check ovn-nbctl --wait=sb remove NB_Global . options $option
+ check_engine_stats global_config recompute compute
+ check_engine_stats northd recompute nocompute
+ check_engine_stats lflow recompute nocompute
+
+ local retval=1
+ if [ "$add_back" == "true" ]; then
+ retval=0
+ fi
+ AT_CHECK([ovn-nbctl get NB_Global . options:$option], [$retval], [ignore], [ignore])
+}
+
+# Clear svc_monitor_mac and few other options which result in recompute.
+# and ovn-northd should update the nb options back.
+clear_nb_option svc_monitor_mac true
+clear_nb_option max_tunid true
+clear_nb_option mac_prefix true
+clear_nb_option northd_internal_version true
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb set NB_Global . options:ignore_chassis_features=true
+check_engine_stats global_config recompute compute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+clear_nb_option ignore_chassis_features false
+
+set_nb_option_lflow_recompute() {
+ local option=$1
+ local value=$2
+ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+ check ovn-nbctl --wait=sb set NB_Global . options:$option=$value
+ check_engine_stats global_config norecompute compute
+ check_engine_stats northd recompute nocompute
+ check_engine_stats lflow recompute nocompute
+ check_engine_stats mac_binding_aging recompute nocompute
+ CHECK_NO_CHANGE_AFTER_RECOMPUTE
+}
+
+clear_nb_option_lflow_recompute() {
+ local option=$1
+ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+ check ovn-nbctl --wait=sb remove NB_Global . options $option
+ check_engine_stats global_config norecompute compute
+ check_engine_stats northd recompute nocompute
+ check_engine_stats lflow recompute nocompute
+ check_engine_stats mac_binding_aging recompute nocompute
+ CHECK_NO_CHANGE_AFTER_RECOMPUTE
+}
+
+set_nb_option_lflow_recompute debug_drop_domain_id 1
+clear_nb_option_lflow_recompute debug_drop_domain_id
+
+set_nb_option_lflow_recompute debug_drop_collector_set 1
+clear_nb_option_lflow_recompute debug_drop_collector_set
+
+set_nb_option_lflow_recompute mac_binding_removal_limit 100
+clear_nb_option_lflow_recompute mac_binding_removal_limit
+
+set_nb_option_lflow_recompute fdb_removal_limit 100
+clear_nb_option_lflow_recompute fdb_removal_limit
+
+set_nb_option_lflow_recompute controller_event true
+clear_nb_option_lflow_recompute controller_event
+
+set_nb_option_lflow_recompute ignore_lsp_down true
+clear_nb_option_lflow_recompute ignore_lsp_down
+
+set_nb_option_lflow_recompute use_ct_inv_match true
+clear_nb_option_lflow_recompute use_ct_inv_match
+
+set_nb_option_lflow_recompute default_acl_drop true
+clear_nb_option_lflow_recompute default_acl_drop
+
+set_nb_option_lflow_recompute use_common_zone true
+clear_nb_option_lflow_recompute use_common_zone
+
+set_nb_option_lflow_recompute install_ls_lb_from_router true
+clear_nb_option_lflow_recompute install_ls_lb_from_router
+
+# Now test changes to chassis for feature changes.
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-sbctl chassis-add ch1 geneve 127.0.0.1
+check ovn-nbctl --wait=sb sync
+check_engine_stats global_config recompute compute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-sbctl chassis-add ch2 geneve 127.0.0.2
+check ovn-nbctl --wait=sb sync
+check_engine_stats global_config recompute compute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+AT_CHECK([ovn-nbctl get NB_Global . options:max_tunid | \
+sed s/":"//g | sed s/\"//g], [0], [16711680
+], [])
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-sbctl chassis-del ch2
+check ovn-nbctl --wait=sb sync
+check_engine_stats global_config recompute compute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-sbctl set encap . type=vxlan
+check ovn-nbctl --wait=sb sync
+check_engine_stats global_config recompute compute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+AT_CHECK([ovn-nbctl get NB_Global . options:max_tunid | \
+sed s/":"//g | sed s/\"//g], [0], [4095
+], [])
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-sbctl set chassis . other_config:foo=bar
+check ovn-nbctl --wait=sb sync
+check_engine_stats global_config norecompute compute
+check_engine_stats mac_binding_aging recompute nocompute
+check_engine_stats fdb_aging recompute nocompute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-sbctl set chassis . other_config:ct-no-masked-label=true
+check ovn-nbctl --wait=sb sync
+check_engine_stats global_config norecompute compute
+check_engine_stats mac_binding_aging recompute nocompute
+check_engine_stats fdb_aging recompute nocompute
+check_engine_stats northd recompute nocompute
+check_engine_stats lflow recompute nocompute
+
+AT_CLEANUP
+])