From: Numan Siddique <[email protected]> OVN recommends updating/upgrading ovn-controllers first and then ovn-northd and OVN DB ovsdb-servers. This is to ensure that new any functionality specified by the database or logical flows created by ovn-northd is understood by ovn-controller.
However certain deployments may upgrade ovn-northd services first and then ovn-controllers. In a large scal deployment, this can result in downtime during upgrades as old ovn-controllers may not understand new logical flows or new actions added by ovn-northd. Even with upgrading ovn-controllers first can result in ovn-controllers rejecting some of the logical flows if an existing OVN action is changed. One such example is ct_commit action which recently was updated to take new arguments. To avoid such downtimes during upgrades, this patch adds the functionality of pinning ovn-controller and ovn-northd to a specific version. An internal OVN version is generated and this version is stored by ovn-northd in the Southbound SB_Global table's options:northd_internal_version. When ovn-controller notices that the internal version has changed, it stops handling the database changes - both Southbound and OVS. All the existing OF flows are preserved. When ovn-controller is upgraded to the same version as ovn-northd services, it will process the database changes. This feature is made optional and disabled by default. Any CMS can enable it by configuring the OVS local database with the option - ignore_northd_version=false. Signed-off-by: Numan Siddique <[email protected]> --- Note: This patch lacks documentation and test cases. These will be added in v2. I submitted this patch so that it can be considered for 20.12 release and today being the soft freeze data. controller/ovn-controller.c | 56 +++++++++++++++++++++++++++++++++++-- lib/ovn-util.c | 18 ++++++++++++ lib/ovn-util.h | 4 +++ northd/ovn-northd.c | 18 +++++++++--- 4 files changed, 89 insertions(+), 7 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index a06cae3ccb..569bf3202a 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2136,6 +2136,35 @@ struct ovn_controller_exit_args { bool *restart; }; +static bool +is_check_northd_version(struct ovsdb_idl *ovs_idl) +{ + const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl); + return !cfg ? false : !smap_get_bool(&cfg->external_ids, + "ignore_northd_version", true); +} + +static bool +is_northd_version_mismatch(const struct sbrec_sb_global *sb, + const char *my_version) +{ + if (!sb) { + return false; + } + + const char *northd_version = + smap_get_def(&sb->options, "northd_internal_version", ""); + + bool mismatch = strcmp(northd_version, my_version); + if (mismatch) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "controller version [%s] mismatch with northd [%s]", + my_version, northd_version); + } + + return mismatch; +} + int main(int argc, char *argv[]) { @@ -2428,10 +2457,14 @@ main(int argc, char *argv[]) .enable_lflow_cache = true }; + char *ovn_internal_version = ovn_get_internal_version(); + VLOG_INFO("OVN internal version is : [%s]", ovn_internal_version); + /* Main loop. */ exiting = false; restart = false; bool sb_monitor_all = false; + bool version_mismatch_with_northd = false; while (!exiting) { /* If we're paused just run the unixctl server and skip most of the * processing loop. @@ -2442,8 +2475,6 @@ main(int argc, char *argv[]) goto loop_done; } - engine_init_run(); - struct ovsdb_idl_txn *ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop); unsigned int new_ovs_cond_seqno = ovsdb_idl_get_condition_seqno(ovs_idl_loop.idl); @@ -2473,6 +2504,22 @@ main(int argc, char *argv[]) ovnsb_cond_seqno = new_ovnsb_cond_seqno; } + bool version_mismatched = false; + if (is_check_northd_version(ovs_idl_loop.idl)) { + version_mismatched = is_northd_version_mismatch( + sbrec_sb_global_first(ovnsb_idl_loop.idl), + ovn_internal_version); + } else { + version_mismatched = false; + } + + if (version_mismatch_with_northd != version_mismatched) { + version_mismatch_with_northd = version_mismatched; + engine_set_force_recompute(true); + } + + engine_init_run(); + struct engine_context eng_ctx = { .ovs_idl_txn = ovs_idl_txn, .ovnsb_idl_txn = ovnsb_idl_txn, @@ -2481,7 +2528,8 @@ main(int argc, char *argv[]) engine_set_context(&eng_ctx); - if (ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl)) { + if (ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl) && + !version_mismatch_with_northd) { /* Contains the transport zones that this Chassis belongs to */ struct sset transport_zones = SSET_INITIALIZER(&transport_zones); sset_from_delimited_string(&transport_zones, @@ -2770,6 +2818,7 @@ loop_done: } } + free(ovn_internal_version); unixctl_server_destroy(unixctl); lflow_destroy(); ofctrl_destroy(); @@ -2822,6 +2871,7 @@ parse_options(int argc, char *argv[]) case 'V': ovs_print_version(OFP15_VERSION, OFP15_VERSION); + printf("SB DB Schema %s\n", sbrec_get_db_version()); exit(EXIT_SUCCESS); VLOG_OPTION_HANDLERS diff --git a/lib/ovn-util.c b/lib/ovn-util.c index 18aac8da34..aa90fd09a0 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -20,6 +20,7 @@ #include <unistd.h> #include "daemon.h" +#include "include/ovn/actions.h" #include "openvswitch/ofp-parse.h" #include "openvswitch/vlog.h" #include "ovn-dirs.h" @@ -713,3 +714,20 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address, *addr_family = ss.ss_family; return true; } + + +#define N_OVN_ACTIONS N_OVNACTS +BUILD_ASSERT_DECL(N_OVN_ACTIONS == 47); + +/* Increment this for any logical flow changes or if existing OVN action is + * modified. */ +#define OVN_INTERNAL_MINOR_VER 0 + +/* Returns the OVN version. The caller must free the returned value. */ +char * +ovn_get_internal_version(void) +{ + return xasprintf("%s-%s-%d.%d", OVN_PACKAGE_VERSION, + sbrec_get_db_version(), + N_OVN_ACTIONS, OVN_INTERNAL_MINOR_VER); +} diff --git a/lib/ovn-util.h b/lib/ovn-util.h index 3496673b26..7edd301802 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -221,4 +221,8 @@ char *str_tolower(const char *orig); bool ip_address_and_port_from_lb_key(const char *key, char **ip_address, uint16_t *port, int *addr_family); +/* Returns the internal OVN version. The caller must free the returned + * value. */ +char *ovn_get_internal_version(void); + #endif diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 4d4190cb9b..2475605cc0 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -12062,7 +12062,8 @@ ovnnb_db_run(struct northd_context *ctx, struct ovsdb_idl_loop *sb_loop, struct hmap *datapaths, struct hmap *ports, struct ovs_list *lr_list, - int64_t loop_start_time) + int64_t loop_start_time, + const char *ovn_internal_version) { if (!ctx->ovnsb_txn || !ctx->ovnnb_txn) { return; @@ -12139,6 +12140,8 @@ ovnnb_db_run(struct northd_context *ctx, smap_replace(&options, "max_tunid", max_tunid); free(max_tunid); + smap_replace(&options, "northd_internal_version", ovn_internal_version); + nbrec_nb_global_verify_options(nb); nbrec_nb_global_set_options(nb, &options); @@ -12746,7 +12749,8 @@ ovnsb_db_run(struct northd_context *ctx, static void ovn_db_run(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, - struct ovsdb_idl_loop *ovnsb_idl_loop) + struct ovsdb_idl_loop *ovnsb_idl_loop, + const char *ovn_internal_version) { struct hmap datapaths, ports; struct ovs_list lr_list; @@ -12756,7 +12760,8 @@ ovn_db_run(struct northd_context *ctx, int64_t start_time = time_wall_msec(); ovnnb_db_run(ctx, sbrec_chassis_by_name, ovnsb_idl_loop, - &datapaths, &ports, &lr_list, start_time); + &datapaths, &ports, &lr_list, start_time, + ovn_internal_version); ovnsb_db_run(ctx, ovnsb_idl_loop, &ports, start_time); destroy_datapaths_and_ports(&datapaths, &ports, &lr_list); } @@ -13113,6 +13118,9 @@ main(int argc, char *argv[]) unixctl_command_register("sb-connection-status", "", 0, 0, ovn_conn_show, ovnsb_idl_loop.idl); + char *ovn_internal_version = ovn_get_internal_version(); + VLOG_INFO("OVN internal version is : [%s]", ovn_internal_version); + /* Main loop. */ exiting = false; state.had_lock = false; @@ -13154,7 +13162,8 @@ main(int argc, char *argv[]) } if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { - ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop); + ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop, + ovn_internal_version); if (ctx.ovnsb_txn) { check_and_add_supported_dhcp_opts_to_sb_db(&ctx); check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx); @@ -13216,6 +13225,7 @@ main(int argc, char *argv[]) } } + free(ovn_internal_version); unixctl_server_destroy(unixctl); ovsdb_idl_loop_destroy(&ovnnb_idl_loop); ovsdb_idl_loop_destroy(&ovnsb_idl_loop); -- 2.28.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
