exec/cfg.c | 187 ++++++++++++++++++++++++- exec/coroparse.c | 90 ++++++------ exec/logconfig.c | 28 ++++ exec/main.c | 2 +- exec/main.h | 3 +- exec/totemconfig.c | 335 +++++++++++++++++++++++++++++++-------------- include/corosync/cfg.h | 5 +- include/corosync/ipc_cfg.h | 14 +- lib/cfg.c | 41 +++++- tools/corosync-cfgtool.c | 31 ++++- 10 files changed, 578 insertions(+), 158 deletions(-) diff --git a/exec/cfg.c b/exec/cfg.c index 503cde1..f3b2ce0 100644 --- a/exec/cfg.c +++ b/exec/cfg.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2006 MontaVista Software, Inc. - * Copyright (c) 2006-2012 Red Hat, Inc. + * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * @@ -64,13 +64,15 @@ #include <corosync/corodefs.h> #include "service.h" +#include "main.h" LOGSYS_DECLARE_SUBSYS ("CFG"); enum cfg_message_req_types { MESSAGE_REQ_EXEC_CFG_RINGREENABLE = 0, MESSAGE_REQ_EXEC_CFG_KILLNODE = 1, - MESSAGE_REQ_EXEC_CFG_SHUTDOWN = 2 + MESSAGE_REQ_EXEC_CFG_SHUTDOWN = 2, + MESSAGE_REQ_EXEC_CFG_RELOAD_CONFIG = 3 }; #define DEFAULT_SHUTDOWN_TIMEOUT 5 @@ -122,6 +124,10 @@ static void message_handler_req_exec_cfg_shutdown ( const void *message, unsigned int nodeid); +static void message_handler_req_exec_cfg_reload_config ( + const void *message, + unsigned int nodeid); + static void exec_cfg_killnode_endian_convert (void *msg); static void message_handler_req_lib_cfg_ringstatusget ( @@ -152,6 +158,10 @@ static void message_handler_req_lib_cfg_local_get ( void *conn, const void *msg); +static void message_handler_req_lib_cfg_reload_config ( + void *conn, + const void *msg); + /* * Service Handler Definition */ @@ -184,6 +194,10 @@ static struct corosync_lib_handler cfg_lib_engine[] = { /* 6 */ .lib_handler_fn = message_handler_req_lib_cfg_local_get, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 7 */ + .lib_handler_fn = message_handler_req_lib_cfg_reload_config, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED } }; @@ -198,6 +212,9 @@ static struct corosync_exec_handler cfg_exec_engine[] = }, { /* 2 */ .exec_handler_fn = message_handler_req_exec_cfg_shutdown, + }, + { /* 4 */ + .exec_handler_fn = message_handler_req_exec_cfg_reload_config, } }; @@ -231,6 +248,11 @@ struct req_exec_cfg_ringreenable { mar_message_source_t source __attribute__((aligned(8))); }; +struct req_exec_cfg_reload_config { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_message_source_t source __attribute__((aligned(8))); +}; + struct req_exec_cfg_killnode { struct qb_ipc_request_header header __attribute__((aligned(8))); mar_uint32_t nodeid __attribute__((aligned(8))); @@ -526,6 +548,145 @@ static void message_handler_req_exec_cfg_shutdown ( LEAVE(); } +/* strcmp replacement that can handle NULLs */ +static int nullcheck_strcmp(const char* left, const char *right) +{ + if (!left && right) + return -1; + if (left && ! right) + return 1; + + if (!left && !right) + return 0; + + return strcmp(left, right); +} + +static void remove_deleted_entries(icmap_map_t temp_map, const char *prefix) +{ + icmap_iter_t old_iter; + icmap_iter_t new_iter; + const char *old_key, *new_key; + int ret; + + old_iter = icmap_iter_init(prefix); + new_iter = icmap_iter_init_r(temp_map, prefix); + + old_key = icmap_iter_next(old_iter, NULL, NULL); + new_key = icmap_iter_next(new_iter, NULL, NULL); + + while (old_key || new_key) { + ret = nullcheck_strcmp(old_key, new_key); + if ((ret < 0 && old_key) || !new_key) { + /* + * new_key is greater, a line (or more) has been deleted + * Continue until old is >= new + */ + do { + /* Remove it from icmap & send notifications */ + icmap_delete(old_key); + + old_key = icmap_iter_next(old_iter, NULL, NULL); + ret = nullcheck_strcmp(old_key, new_key); + } while (ret < 0 && old_key); + } + else if ((ret > 0 && new_key) || !old_key) { + /* + * old_key is greater, a line (or more) has been added + * Continue until new is >= old + * + * we don't need to do anything special with this like tell + * icmap. That will happen when we copy the values over + */ + do { + new_key = icmap_iter_next(new_iter, NULL, NULL); + ret = nullcheck_strcmp(old_key, new_key); + } while (ret > 0 && new_key); + } + if (ret == 0) { + new_key = icmap_iter_next(new_iter, NULL, NULL); + old_key = icmap_iter_next(old_iter, NULL, NULL); + } + } + icmap_iter_finalize(new_iter); + icmap_iter_finalize(old_iter); +} + +/* + * Reload configuration file + */ +static void message_handler_req_exec_cfg_reload_config ( + const void *message, + unsigned int nodeid) +{ + const struct req_exec_cfg_reload_config *req_exec_cfg_reload_config = message; + struct res_lib_cfg_reload_config res_lib_cfg_reload_config; + icmap_map_t temp_map; + const char *error_string; + int res = CS_OK; + + ENTER(); + + log_printf(LOGSYS_LEVEL_NOTICE, "Config reload requested by node %d", nodeid); + + /* + * Set up a new hastable as a staging area. + */ + if ((res = icmap_init_r(&temp_map)) != CS_OK) { + log_printf(LOGSYS_LEVEL_ERROR, "Unable to create temporary icmap. config file reload cancelled\n"); + goto reload_fini; + } + + /* + * Load new config into the temporary map + */ + res = coroparse_configparse(temp_map, &error_string); + if (res == -1) { + log_printf (LOGSYS_LEVEL_ERROR, "Unable to reload config file: %s", error_string); + res = CS_ERR_LIBRARY; + goto reload_return; + } + + /* Tell interested listeners that we have started a reload */ + icmap_set_uint8("config.reload_in_progress", 1); + + /* Detect deleted entries and remove them from the main icmap hashtable */ + remove_deleted_entries(temp_map, "logging."); + remove_deleted_entries(temp_map, "totem."); + remove_deleted_entries(temp_map, "nodelist."); + remove_deleted_entries(temp_map, "quorum."); + + /* + * Copy new keys into live config. + * If this fails we will have a partially loaded config because some keys (above) might + * have been reset to defaults - I'm not sure what to do here, we might have to quit. + */ + if ( (res = icmap_copy_map(icmap_get_global_map(), temp_map)) != CS_OK) { + log_printf (LOGSYS_LEVEL_ERROR, "Error making new config live. cmap database may be inconsistent\n"); + } + + /* All done - let clients know */ + icmap_set_uint8("config.reload_in_progress", 0); + +reload_fini: + /* Finished with the temporary storage */ + icmap_fini_r(temp_map); + +reload_return: + /* All done, return result to the caller if it was on this system */ + if (nodeid == api->totem_nodeid_get()) { + res_lib_cfg_reload_config.header.size = sizeof(res_lib_cfg_reload_config); + res_lib_cfg_reload_config.header.id = MESSAGE_RES_CFG_RELOAD_CONFIG; + res_lib_cfg_reload_config.header.error = res; + api->ipc_response_send(req_exec_cfg_reload_config->source.conn, + &res_lib_cfg_reload_config, + sizeof(res_lib_cfg_reload_config)); + api->ipc_refcnt_dec(req_exec_cfg_reload_config->source.conn);; + } + + LEAVE(); +} + /* * Library Interface Implementation */ @@ -847,3 +1008,25 @@ static void message_handler_req_lib_cfg_local_get (void *conn, const void *msg) api->ipc_response_send(conn, &res_lib_cfg_local_get, sizeof(res_lib_cfg_local_get)); } + +static void message_handler_req_lib_cfg_reload_config (void *conn, const void *msg) +{ + struct req_exec_cfg_reload_config req_exec_cfg_reload_config; + struct iovec iovec; + + ENTER(); + + req_exec_cfg_reload_config.header.size = + sizeof (struct req_exec_cfg_reload_config); + req_exec_cfg_reload_config.header.id = SERVICE_ID_MAKE (CFG_SERVICE, + MESSAGE_REQ_EXEC_CFG_RELOAD_CONFIG); + api->ipc_source_set (&req_exec_cfg_reload_config.source, conn); + api->ipc_refcnt_inc(conn); + + iovec.iov_base = (char *)&req_exec_cfg_reload_config; + iovec.iov_len = sizeof (struct req_exec_cfg_reload_config); + + assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0); + + LEAVE(); +} diff --git a/exec/coroparse.c b/exec/coroparse.c index af4072d..1ac0cdd 100644 --- a/exec/coroparse.c +++ b/exec/coroparse.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2012 Red Hat, Inc. + * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * @@ -76,6 +76,7 @@ typedef int (*parser_cb_f)(const char *path, char *value, enum parser_cb_type type, const char **error_string, + icmap_map_t config_map, void *user_data); enum main_cp_cb_data_state { @@ -120,7 +121,7 @@ struct main_cp_cb_data { }; static int read_config_file_into_icmap( - const char **error_string); + const char **error_string, icmap_map_t config_map); static char error_string_response[512]; static int uid_determine (const char *req_user) @@ -243,9 +244,9 @@ static char *strchr_rs (const char *haystack, int byte) return ((char *) end_address); } -int coroparse_configparse (const char **error_string) +int coroparse_configparse (icmap_map_t config_map, const char **error_string) { - if (read_config_file_into_icmap(error_string)) { + if (read_config_file_into_icmap(error_string, config_map)) { return -1; } @@ -277,6 +278,7 @@ static int parse_section(FILE *fp, const char **error_string, int depth, parser_cb_f parser_cb, + icmap_map_t config_map, void *user_data) { char line[512]; @@ -286,7 +288,7 @@ static int parse_section(FILE *fp, char new_keyname[ICMAP_KEYNAME_MAXLEN]; if (strcmp(path, "") == 0) { - parser_cb("", NULL, NULL, PARSER_CB_START, error_string, user_data); + parser_cb("", NULL, NULL, PARSER_CB_START, error_string, config_map, user_data); } while (fgets (line, sizeof (line), fp)) { @@ -340,11 +342,11 @@ static int parse_section(FILE *fp, } strcat(new_keyname, section); - if (!parser_cb(new_keyname, NULL, NULL, PARSER_CB_SECTION_START, error_string, user_data)) { + if (!parser_cb(new_keyname, NULL, NULL, PARSER_CB_SECTION_START, error_string, config_map, user_data)) { return -1; } - if (parse_section(fp, new_keyname, error_string, depth + 1, parser_cb, user_data)) + if (parse_section(fp, new_keyname, error_string, depth + 1, parser_cb, config_map, user_data)) return -1; continue ; @@ -369,7 +371,7 @@ static int parse_section(FILE *fp, } strcat(new_keyname, key); - if (!parser_cb(new_keyname, key, value, PARSER_CB_ITEM, error_string, user_data)) { + if (!parser_cb(new_keyname, key, value, PARSER_CB_ITEM, error_string, config_map, user_data)) { return -1; } @@ -383,7 +385,7 @@ static int parse_section(FILE *fp, return -1; } - if (!parser_cb(path, NULL, NULL, PARSER_CB_SECTION_END, error_string, user_data)) { + if (!parser_cb(path, NULL, NULL, PARSER_CB_SECTION_END, error_string, config_map, user_data)) { return -1; } @@ -397,7 +399,7 @@ static int parse_section(FILE *fp, } if (strcmp(path, "") == 0) { - parser_cb("", NULL, NULL, PARSER_CB_END, error_string, user_data); + parser_cb("", NULL, NULL, PARSER_CB_END, error_string, config_map, user_data); } return 0; @@ -456,6 +458,7 @@ static int main_config_parser_cb(const char *path, char *value, enum parser_cb_type type, const char **error_string, + icmap_map_t config_map, void *user_data) { int i; @@ -487,7 +490,7 @@ static int main_config_parser_cb(const char *path, if (safe_atoi(value, &i) != 0) { goto atoi_error; } - icmap_set_uint32(path, i); + icmap_set_uint32_r(config_map, path, i); add_as_string = 0; } break; @@ -499,7 +502,7 @@ static int main_config_parser_cb(const char *path, if (safe_atoi(value, &i) != 0) { goto atoi_error; } - icmap_set_uint32(path, i); + icmap_set_uint32_r(config_map, path, i); add_as_string = 0; } @@ -511,7 +514,7 @@ static int main_config_parser_cb(const char *path, if (safe_atoi(value, &i) != 0) { goto atoi_error; } - icmap_set_uint8(path, i); + icmap_set_uint8_r(config_map, path, i); add_as_string = 0; } break; @@ -521,14 +524,14 @@ static int main_config_parser_cb(const char *path, if (safe_atoi(value, &i) != 0) { goto atoi_error; } - icmap_set_uint32(path, i); + icmap_set_uint32_r(config_map, path, i); add_as_string = 0; } if ((strcmp(path, "quorum.device.master_wins") == 0)) { if (safe_atoi(value, &i) != 0) { goto atoi_error; } - icmap_set_uint8(path, i); + icmap_set_uint8_r(config_map, path, i); add_as_string = 0; } break; @@ -561,14 +564,14 @@ static int main_config_parser_cb(const char *path, if (safe_atoi(value, &i) != 0) { goto atoi_error; } - icmap_set_uint32(path, i); + icmap_set_uint32_r(config_map,path, i); add_as_string = 0; } if (strcmp(path, "totem.config_version") == 0) { if (str_to_ull(value, &ull) != 0) { goto atoi_error; } - icmap_set_uint64(path, ull); + icmap_set_uint64_r(config_map, path, ull); add_as_string = 0; } if (strcmp(path, "totem.ip_version") == 0) { @@ -749,7 +752,7 @@ static int main_config_parser_cb(const char *path, } snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.uid.%u", uid); - icmap_set_uint8(key_name, 1); + icmap_set_uint8_r(config_map, key_name, 1); add_as_string = 0; } else if (strcmp(key, "gid") == 0) { gid = gid_determine(value); @@ -759,7 +762,7 @@ static int main_config_parser_cb(const char *path, } snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.gid.%u", gid); - icmap_set_uint8(key_name, 1); + icmap_set_uint8_r(config_map, key_name, 1); add_as_string = 0; } else { *error_string = "uidgid: Only uid and gid are allowed items"; @@ -803,7 +806,7 @@ static int main_config_parser_cb(const char *path, goto atoi_error; } - icmap_set_uint32(key_name, i); + icmap_set_uint32_r(config_map, key_name, i); add_as_string = 0; } @@ -812,14 +815,14 @@ static int main_config_parser_cb(const char *path, } if (add_as_string) { - icmap_set_string(key_name, value); + icmap_set_string_r(config_map, key_name, value); add_as_string = 0; } break; } if (add_as_string) { - icmap_set_string(path, value); + icmap_set_string_r(config_map, path, value); } break; case PARSER_CB_SECTION_START: @@ -882,7 +885,7 @@ static int main_config_parser_cb(const char *path, if (data->bindnetaddr != NULL) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr", data->ringnumber); - icmap_set_string(key_name, data->bindnetaddr); + icmap_set_string_r(config_map, key_name, data->bindnetaddr); free(data->bindnetaddr); data->bindnetaddr = NULL; @@ -891,7 +894,7 @@ static int main_config_parser_cb(const char *path, if (data->mcastaddr != NULL) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", data->ringnumber); - icmap_set_string(key_name, data->mcastaddr); + icmap_set_string_r(config_map, key_name, data->mcastaddr); free(data->mcastaddr); data->mcastaddr = NULL; @@ -900,7 +903,7 @@ static int main_config_parser_cb(const char *path, if (data->broadcast != NULL) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast", data->ringnumber); - icmap_set_string(key_name, data->broadcast); + icmap_set_string_r(config_map, key_name, data->broadcast); free(data->broadcast); data->broadcast = NULL; @@ -909,13 +912,13 @@ static int main_config_parser_cb(const char *path, if (data->mcastport > -1) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", data->ringnumber); - icmap_set_uint16(key_name, data->mcastport); + icmap_set_uint16_r(config_map, key_name, data->mcastport); } if (data->ttl > -1) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl", data->ringnumber); - icmap_set_uint8(key_name, data->ttl); + icmap_set_uint8_r(config_map, key_name, data->ttl); } i = 0; @@ -925,7 +928,7 @@ static int main_config_parser_cb(const char *path, snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.member.%u", data->ringnumber, i); - icmap_set_string(key_name, kv_item->value); + icmap_set_string_r(config_map, key_name, kv_item->value); iter_next = iter->next; @@ -956,7 +959,7 @@ static int main_config_parser_cb(const char *path, snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logger_subsys.%s.%s", data->subsys, kv_item->key); - icmap_set_string(key_name, kv_item->value); + icmap_set_string_r(config_map, key_name, kv_item->value); iter_next = iter->next; @@ -967,7 +970,7 @@ static int main_config_parser_cb(const char *path, snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logger_subsys.%s.subsys", data->subsys); - icmap_set_string(key_name, data->subsys); + icmap_set_string_r(config_map, key_name, data->subsys); free(data->subsys); @@ -1007,7 +1010,7 @@ static int main_config_parser_cb(const char *path, kv_item->key); } } - icmap_set_string(key_name, kv_item->value); + icmap_set_string_r(config_map, key_name, kv_item->value); iter_next = iter->next; @@ -1020,21 +1023,21 @@ static int main_config_parser_cb(const char *path, if (strcmp(data->logging_daemon_name, "corosync") != 0) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logging_daemon.%s.name", data->logging_daemon_name); - icmap_set_string(key_name, data->logging_daemon_name); + icmap_set_string_r(config_map, key_name, data->logging_daemon_name); } } else { if (strcmp(data->logging_daemon_name, "corosync") == 0) { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logger_subsys.%s.subsys", data->subsys); - icmap_set_string(key_name, data->subsys); + icmap_set_string_r(config_map, key_name, data->subsys); } else { snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logging_daemon.%s.%s.subsys", data->logging_daemon_name, data->subsys); - icmap_set_string(key_name, data->subsys); + icmap_set_string_r(config_map, key_name, data->subsys); snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logging_daemon.%s.%s.name", data->logging_daemon_name, data->subsys); - icmap_set_string(key_name, data->logging_daemon_name); + icmap_set_string_r(config_map, key_name, data->logging_daemon_name); } } @@ -1086,6 +1089,7 @@ static int uidgid_config_parser_cb(const char *path, char *value, enum parser_cb_type type, const char **error_string, + icmap_map_t config_map, void *user_data) { char key_name[ICMAP_KEYNAME_MAXLEN]; @@ -1105,7 +1109,7 @@ static int uidgid_config_parser_cb(const char *path, } snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.uid.%u", uid); - icmap_set_uint8(key_name, 1); + icmap_set_uint8_r(config_map, key_name, 1); } else if (strcmp(path, "uidgid.gid") == 0) { gid = gid_determine(value); if (gid == -1) { @@ -1114,7 +1118,7 @@ static int uidgid_config_parser_cb(const char *path, } snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.gid.%u", gid); - icmap_set_uint8(key_name, 1); + icmap_set_uint8_r(config_map, key_name, 1); } else { *error_string = "uidgid: Only uid and gid are allowed items"; return (0); @@ -1134,7 +1138,8 @@ static int uidgid_config_parser_cb(const char *path, } static int read_uidgid_files_into_icmap( - const char **error_string) + const char **error_string, + icmap_map_t config_map) { FILE *fp; const char *dirname; @@ -1175,7 +1180,7 @@ static int read_uidgid_files_into_icmap( key_name[0] = 0; - res = parse_section(fp, key_name, error_string, 0, uidgid_config_parser_cb, NULL); + res = parse_section(fp, key_name, error_string, 0, uidgid_config_parser_cb, config_map, NULL); fclose (fp); @@ -1194,7 +1199,8 @@ error_exit: /* Read config file and load into icmap */ static int read_config_file_into_icmap( - const char **error_string) + const char **error_string, + icmap_map_t config_map) { FILE *fp; const char *filename; @@ -1220,12 +1226,12 @@ static int read_config_file_into_icmap( key_name[0] = 0; - res = parse_section(fp, key_name, error_string, 0, main_config_parser_cb, &data); + res = parse_section(fp, key_name, error_string, 0, main_config_parser_cb, config_map, &data); fclose(fp); if (res == 0) { - res = read_uidgid_files_into_icmap(error_string); + res = read_uidgid_files_into_icmap(error_string, config_map); } if (res == 0) { diff --git a/exec/logconfig.c b/exec/logconfig.c index 0c9eeb4..e6f984a 100644 --- a/exec/logconfig.c +++ b/exec/logconfig.c @@ -542,6 +542,22 @@ static void main_logging_notify( #endif { const char *error_string; + static int reload_in_progress = 0; + + /* If a full reload happens then suspend updates for individual keys until + * it's all completed + */ + if (strcmp(key_name, "config.reload_in_progress") == 0) { + if (*(uint8_t *)new_val.data == 1) { + reload_in_progress = 1; + } else { + reload_in_progress = 0; + } + } + if (reload_in_progress) { + log_printf(LOGSYS_LEVEL_DEBUG, "Ignoring key change, reload in progress. %s\n", key_name); + return; + } /* * Reload the logsys configuration @@ -562,6 +578,12 @@ static void add_logsys_config_notification(void) main_logging_notify, NULL, &icmap_track); + + icmap_track_add("config.reload_in_progress", + ICMAP_TRACK_ADD | ICMAP_TRACK_MODIFY, + main_logging_notify, + NULL, + &icmap_track); } #else static void add_logsys_config_notification(void) @@ -573,6 +595,12 @@ static void add_logsys_config_notification(void) main_logging_notify, NULL, &cmap_track); + + cmap_track_add(cmap_handle, "config.reload_in_progress", + CMAP_TRACK_ADD | CMAP_TRACK_MODIFY, + main_logging_notify, + NULL, + &cmap_track); } #endif diff --git a/exec/main.c b/exec/main.c index 6c69ee5..dadef97 100644 --- a/exec/main.c +++ b/exec/main.c @@ -1149,7 +1149,7 @@ int main (int argc, char **argv, char **envp) */ api = apidef_get (); - res = coroparse_configparse(&error_string); + res = coroparse_configparse(icmap_get_global_map(), &error_string); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string); corosync_exit_error (COROSYNC_DONE_MAINCONFIGREAD); diff --git a/exec/main.h b/exec/main.h index b65f0ae..12f7bb5 100644 --- a/exec/main.h +++ b/exec/main.h @@ -48,6 +48,7 @@ #include <corosync/hdb.h> #include <qb/qbloop.h> #include <corosync/totem/totempg.h> +#include <corosync/icmap.h> #include <corosync/coroapi.h> extern unsigned long long *(*main_clm_get_by_nodeid) (unsigned int node_id); @@ -121,6 +122,6 @@ extern void cs_ipc_refcnt_dec(void *conn); extern void cs_ipc_allow_connections(int32_t allow); -int coroparse_configparse (const char **error_string); +int coroparse_configparse (icmap_map_t config_map, const char **error_string); #endif /* MAIN_H_DEFINED */ diff --git a/exec/totemconfig.c b/exec/totemconfig.c index 62daeaf..8454c6e 100644 --- a/exec/totemconfig.c +++ b/exec/totemconfig.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2002-2005 MontaVista Software, Inc. - * Copyright (c) 2006-2012 Red Hat, Inc. + * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * @@ -83,6 +83,57 @@ static char error_string_response[512]; static void add_totem_config_notification(struct totem_config *totem_config); + +/* All the volatile parameters are uint32s, luckily */ +static uint32_t *totem_get_param_by_name(struct totem_config *totem_config, const char *param_name) +{ + if (strcmp(param_name, "totem.token") == 0) + return &totem_config->token_timeout; + if (strcmp(param_name, "totem.token_retransmit") == 0) + return &totem_config->token_retransmit_timeout; + if (strcmp(param_name, "totem.hold") == 0) + return &totem_config->token_hold_timeout; + if (strcmp(param_name, "totem.token_retransmits_before_loss_const") == 0) + return &totem_config->token_retransmits_before_loss_const; + if (strcmp(param_name, "totem.join") == 0) + return &totem_config->join_timeout; + if (strcmp(param_name, "totem.send_join") == 0) + return &totem_config->send_join_timeout; + if (strcmp(param_name, "totem.consensus") == 0) + return &totem_config->consensus_timeout; + if (strcmp(param_name, "totem.merge") == 0) + return &totem_config->merge_timeout; + if (strcmp(param_name, "totem.downcheck") == 0) + return &totem_config->downcheck_timeout; + if (strcmp(param_name, "totem.fail_recv_const") == 0) + return &totem_config->fail_to_recv_const; + if (strcmp(param_name, "totem.seqno_unchanged_const") == 0) + return &totem_config->seqno_unchanged_const; + if (strcmp(param_name, "totem.rrp_token_expired_timeout") == 0) + return &totem_config->rrp_token_expired_timeout; + if (strcmp(param_name, "totem.rrp_problem_count_timeout") == 0) + return &totem_config->rrp_problem_count_timeout; + if (strcmp(param_name, "totem.rrp_problem_count_threshold") == 0) + return &totem_config->rrp_problem_count_threshold; + if (strcmp(param_name, "totem.rrp_problem_count_mcast_threshold") == 0) + return &totem_config->rrp_problem_count_mcast_threshold; + if (strcmp(param_name, "totem.rrp_autorecovery_check_timeout") == 0) + return &totem_config->rrp_autorecovery_check_timeout; + if (strcmp(param_name, "totem.heartbeat_failures_allowed") == 0) + return &totem_config->heartbeat_failures_allowed; + if (strcmp(param_name, "totem.max_network_delay") == 0) + return &totem_config->max_network_delay; + if (strcmp(param_name, "totem.window_size") == 0) + return &totem_config->window_size; + if (strcmp(param_name, "totem.max_messages") == 0) + return &totem_config->max_messages; + if (strcmp(param_name, "totem.miss_count_const") == 0) + return &totem_config->miss_count_const; + + return NULL; +} + + static void totem_volatile_config_read (struct totem_config *totem_config) { char *str; @@ -703,80 +754,12 @@ extern int totem_config_read ( return 0; } -int totem_config_validate ( +static int totem_set_volatile_defaults ( struct totem_config *totem_config, const char **error_string) { static char local_error_reason[512]; - char parse_error[512]; const char *error_reason = local_error_reason; - int i; - unsigned int interface_max = INTERFACE_MAX; - - if (totem_config->interface_count == 0) { - error_reason = "No interfaces defined"; - goto parse_error; - } - - for (i = 0; i < totem_config->interface_count; i++) { - /* - * Some error checking of parsed data to make sure its valid - */ - - struct totem_ip_address null_addr; - memset (&null_addr, 0, sizeof (struct totem_ip_address)); - - if ((totem_config->transport_number == 0) && - memcmp (&totem_config->interfaces[i].mcast_addr, &null_addr, - sizeof (struct totem_ip_address)) == 0) { - error_reason = "No multicast address specified"; - goto parse_error; - } - - if (totem_config->interfaces[i].ip_port == 0) { - error_reason = "No multicast port specified"; - goto parse_error; - } - - if (totem_config->interfaces[i].ttl > 255) { - error_reason = "Invalid TTL (should be 0..255)"; - goto parse_error; - } - if (totem_config->transport_number != TOTEM_TRANSPORT_UDP && - totem_config->interfaces[i].ttl != 1) { - error_reason = "Can only set ttl on multicast transport types"; - goto parse_error; - } - - if (totem_config->interfaces[i].mcast_addr.family == AF_INET6 && - totem_config->node_id == 0) { - - error_reason = "An IPV6 network requires that a node ID be specified."; - goto parse_error; - } - - if (totem_config->broadcast_use == 0 && totem_config->transport_number == 0) { - if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) { - error_reason = "Multicast address family does not match bind address family"; - goto parse_error; - } - - if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) { - error_reason = "Not all bind address belong to the same IP family"; - goto parse_error; - } - if (totemip_is_mcast (&totem_config->interfaces[i].mcast_addr) != 0) { - error_reason = "mcastaddr is not a correct multicast address."; - goto parse_error; - } - } - } - - if (totem_config->version != 2) { - error_reason = "This totem parser can only parse version 2 configurations."; - goto parse_error; - } - if (totem_config->token_retransmits_before_loss_const == 0) { totem_config->token_retransmits_before_loss_const = @@ -888,16 +871,15 @@ int totem_config_validate ( goto parse_error; } - /* - * RRP values validation - */ - if (strcmp (totem_config->rrp_mode, "none") && - strcmp (totem_config->rrp_mode, "active") && - strcmp (totem_config->rrp_mode, "passive")) { - snprintf (local_error_reason, sizeof(local_error_reason), - "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config->rrp_mode); - goto parse_error; + if (totem_config->fail_to_recv_const == 0) { + totem_config->fail_to_recv_const = FAIL_TO_RECV_CONST; } + if (totem_config->seqno_unchanged_const == 0) { + totem_config->seqno_unchanged_const = SEQNO_UNCHANGED_CONST; + } + +/* RRP volatile values */ + if (totem_config->rrp_problem_count_timeout == 0) { totem_config->rrp_problem_count_timeout = RRP_PROBLEM_COUNT_TIMEOUT; } @@ -941,54 +923,127 @@ int totem_config_validate ( totem_config->rrp_autorecovery_check_timeout = RRP_AUTORECOVERY_CHECK_TIMEOUT; } - if (strcmp (totem_config->rrp_mode, "none") == 0) { - interface_max = 1; - } - if (interface_max < totem_config->interface_count) { - snprintf (parse_error, sizeof(parse_error), - "%d is too many configured interfaces for the rrp_mode setting %s.", - totem_config->interface_count, - totem_config->rrp_mode); - error_reason = parse_error; + return 0; + +parse_error: + snprintf (error_string_response, sizeof(error_string_response), + "parse error in config: %s\n", error_reason); + *error_string = error_string_response; + return (-1); + +} + +int totem_config_validate ( + struct totem_config *totem_config, + const char **error_string) +{ + static char local_error_reason[512]; + char parse_error[512]; + const char *error_reason = local_error_reason; + int i; + unsigned int interface_max = INTERFACE_MAX; + + if (totem_config->interface_count == 0) { + error_reason = "No interfaces defined"; goto parse_error; } + for (i = 0; i < totem_config->interface_count; i++) { + /* + * Some error checking of parsed data to make sure its valid + */ - if (totem_config->fail_to_recv_const == 0) { - totem_config->fail_to_recv_const = FAIL_TO_RECV_CONST; - } - if (totem_config->seqno_unchanged_const == 0) { - totem_config->seqno_unchanged_const = SEQNO_UNCHANGED_CONST; + struct totem_ip_address null_addr; + memset (&null_addr, 0, sizeof (struct totem_ip_address)); + + if ((totem_config->transport_number == 0) && + memcmp (&totem_config->interfaces[i].mcast_addr, &null_addr, + sizeof (struct totem_ip_address)) == 0) { + error_reason = "No multicast address specified"; + goto parse_error; + } + + if (totem_config->interfaces[i].ip_port == 0) { + error_reason = "No multicast port specified"; + goto parse_error; + } + + if (totem_config->interfaces[i].ttl > 255) { + error_reason = "Invalid TTL (should be 0..255)"; + goto parse_error; + } + if (totem_config->transport_number != TOTEM_TRANSPORT_UDP && + totem_config->interfaces[i].ttl != 1) { + error_reason = "Can only set ttl on multicast transport types"; + goto parse_error; + } + + if (totem_config->interfaces[i].mcast_addr.family == AF_INET6 && + totem_config->node_id == 0) { + + error_reason = "An IPV6 network requires that a node ID be specified."; + goto parse_error; + } + + if (totem_config->broadcast_use == 0 && totem_config->transport_number == 0) { + if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) { + error_reason = "Multicast address family does not match bind address family"; + goto parse_error; + } + + if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) { + error_reason = "Not all bind address belong to the same IP family"; + goto parse_error; + } + if (totemip_is_mcast (&totem_config->interfaces[i].mcast_addr) != 0) { + error_reason = "mcastaddr is not a correct multicast address."; + goto parse_error; + } + } } - if (totem_config->net_mtu == 0) { - totem_config->net_mtu = 1500; + + if (totem_config->version != 2) { + error_reason = "This totem parser can only parse version 2 configurations."; + goto parse_error; } - if ((MESSAGE_QUEUE_MAX) < totem_config->max_messages) { + totem_set_volatile_defaults(totem_config, error_string); + + /* + * RRP values validation + */ + if (strcmp (totem_config->rrp_mode, "none") && + strcmp (totem_config->rrp_mode, "active") && + strcmp (totem_config->rrp_mode, "passive")) { snprintf (local_error_reason, sizeof(local_error_reason), - "The max_messages parameter (%d messages) may not be greater then (%d messages).", - totem_config->max_messages, MESSAGE_QUEUE_MAX); + "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config->rrp_mode); goto parse_error; } - if (totem_config->threads > SEND_THREADS_MAX) { - totem_config->threads = SEND_THREADS_MAX; + if (strcmp (totem_config->rrp_mode, "none") == 0) { + interface_max = 1; } - if (totem_config->net_mtu > FRAME_SIZE_MAX) { - error_reason = "This net_mtu parameter is greater then the maximum frame size"; + if (interface_max < totem_config->interface_count) { + snprintf (parse_error, sizeof(parse_error), + "%d is too many configured interfaces for the rrp_mode setting %s.", + totem_config->interface_count, + totem_config->rrp_mode); + error_reason = parse_error; goto parse_error; } - if (totem_config->vsf_type == NULL) { - totem_config->vsf_type = "none"; + + if (totem_config->net_mtu == 0) { + totem_config->net_mtu = 1500; } - return (0); + return 0; parse_error: snprintf (error_string_response, sizeof(error_string_response), "parse error in config: %s\n", error_reason); *error_string = error_string_response; return (-1); + } static int read_keyfile ( @@ -1107,7 +1162,69 @@ static void totem_change_notify( struct icmap_notify_value old_val, void *user_data) { - totem_volatile_config_read((struct totem_config *)user_data); + uint32_t *param; + const char *error_string; + uint8_t reloading; + + /* + * If a full reload is in progress then don't do anything until it's done and + * can reconfigure it all atomically + */ + if (icmap_get_uint8("config.reload_in_progress", &reloading) == CS_OK && reloading) + return; + + param = totem_get_param_by_name((struct totem_config *)user_data, key_name); + if (!param) + return; + + switch (event) + { + case QB_MAP_NOTIFY_DELETED: + if (new_val.type == ICMAP_VALUETYPE_UINT32) + *param = 0; + totem_set_volatile_defaults((struct totem_config *)user_data, &error_string); + break; + case QB_MAP_NOTIFY_REPLACED: + case QB_MAP_NOTIFY_INSERTED: + if (new_val.type == ICMAP_VALUETYPE_UINT32) + memcpy(param, new_val.data, new_val.len); + /* Other value types not supported, or needed (yet) */ + break; + default: + break; + } +} + +static void totem_reload_notify( + int32_t event, + const char *key_name, + struct icmap_notify_value new_val, + struct icmap_notify_value old_val, + void *user_data) +{ + struct totem_config *totem_config = (struct totem_config *)user_data; + uint32_t local_node_pos; + + /* Reload has completed */ + if (*(uint8_t *)new_val.data == 0) { + int i, j; + + /* Clear out udpu nodelist so we can put the new one in if neede */ + for (i=0; i<totem_config->interface_count; i++) { + for (j=0; j<PROCESSOR_COUNT_MAX; j++) { + memset(&totem_config->interfaces[i].member_list[j], 0, sizeof(struct totem_ip_address)); + } + } + + put_nodelist_members_to_config (totem_config); + totem_volatile_config_read (totem_config); + + /* Reinstate the local_node_pos */ + local_node_pos = find_local_node_in_nodelist(totem_config); + if (local_node_pos != -1) { + icmap_set_uint32("nodelist.local_node_pos", local_node_pos); + } + } } static void add_totem_config_notification(struct totem_config *totem_config) @@ -1119,4 +1236,10 @@ static void add_totem_config_notification(struct totem_config *totem_config) totem_change_notify, totem_config, &icmap_track); + + icmap_track_add("config.reload_in_progress", + ICMAP_TRACK_ADD | ICMAP_TRACK_MODIFY, + totem_reload_notify, + totem_config, + &icmap_track); } diff --git a/include/corosync/cfg.h b/include/corosync/cfg.h index d26d5d1..cacbd6a 100644 --- a/include/corosync/cfg.h +++ b/include/corosync/cfg.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005 MontaVista Software, Inc. - * Copyright (c) 2006-2012 Red Hat, Inc. + * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * @@ -157,6 +157,9 @@ corosync_cfg_local_get ( corosync_cfg_handle_t handle, unsigned int *local_nodeid); +cs_error_t corosync_cfg_reload_config ( + corosync_cfg_handle_t handle); + #ifdef __cplusplus } #endif diff --git a/include/corosync/ipc_cfg.h b/include/corosync/ipc_cfg.h index f5f6748..a12a847 100644 --- a/include/corosync/ipc_cfg.h +++ b/include/corosync/ipc_cfg.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005 MontaVista Software, Inc. - * Copyright (c) 2009-2012 Red Hat, Inc. + * Copyright (c) 2009-2013 Red Hat, Inc. * * All rights reserved. * @@ -55,7 +55,8 @@ enum req_lib_cfg_types { MESSAGE_REQ_CFG_REPLYTOSHUTDOWN = 4, MESSAGE_REQ_CFG_GET_NODE_ADDRS = 5, MESSAGE_REQ_CFG_LOCAL_GET = 6, - MESSAGE_REQ_CFG_CRYPTO_SET = 7 + MESSAGE_REQ_CFG_RELOAD_CONFIG = 7, + MESSAGE_REQ_CFG_CRYPTO_SET = 8 }; enum res_lib_cfg_types { @@ -74,6 +75,7 @@ enum res_lib_cfg_types { MESSAGE_RES_CFG_LOCAL_GET = 12, MESSAGE_RES_CFG_REPLYTOSHUTDOWN = 13, MESSAGE_RES_CFG_CRYPTO_SET = 14, + MESSAGE_RES_CFG_RELOAD_CONFIG = 15 }; struct req_lib_cfg_ringstatusget { @@ -150,6 +152,14 @@ struct res_lib_cfg_local_get { mar_uint32_t local_nodeid __attribute__((aligned(8))); }; +struct req_lib_cfg_reload_config { + struct qb_ipc_request_header header __attribute__((aligned(8))); +}; + +struct res_lib_cfg_reload_config { + struct qb_ipc_response_header header __attribute__((aligned(8))); +}; + typedef enum { AIS_AMF_ADMINISTRATIVETARGET_SERVICEUNIT = 0, AIS_AMF_ADMINISTRATIVETARGET_SERVICEGROUP = 1, diff --git a/lib/cfg.c b/lib/cfg.c index d594324..7bb56de 100644 --- a/lib/cfg.c +++ b/lib/cfg.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2002-2005 MontaVista Software, Inc. - * Copyright (c) 2006-2011 Red Hat, Inc. + * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * @@ -620,3 +620,42 @@ error_exit: return (error); } + +cs_error_t corosync_cfg_reload_config ( + corosync_cfg_handle_t handle) +{ + cs_error_t error; + struct cfg_inst *cfg_inst; + struct iovec iov; + struct req_lib_cfg_reload_config req_lib_cfg_reload_config; + struct res_lib_cfg_reload_config res_lib_cfg_reload_config; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_reload_config.header.size = sizeof (struct qb_ipc_request_header); + req_lib_cfg_reload_config.header.id = MESSAGE_REQ_CFG_RELOAD_CONFIG; + + iov.iov_base = (void *)&req_lib_cfg_reload_config; + iov.iov_len = sizeof (struct req_lib_cfg_reload_config); + + error = qb_to_cs_error (qb_ipcc_sendv_recv ( + cfg_inst->c, + &iov, + 1, + &res_lib_cfg_reload_config, + sizeof (struct res_lib_cfg_reload_config), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cfg_reload_config.header.error; + +error_exit: + (void)hdb_handle_put (&cfg_hdb, handle); + + return (error); +} diff --git a/tools/corosync-cfgtool.c b/tools/corosync-cfgtool.c index 12a66a7..07d318a 100644 --- a/tools/corosync-cfgtool.c +++ b/tools/corosync-cfgtool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2012 Red Hat, Inc. + * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * @@ -137,6 +137,29 @@ static void ringreenable_do (void) (void)corosync_cfg_finalize (handle); } +static void reload_config_do (void) +{ + cs_error_t result; + corosync_cfg_handle_t handle; + + printf ("Reloading corosync.conf...\n"); + result = corosync_cfg_initialize (&handle, NULL); + if (result != CS_OK) { + printf ("Could not initialize corosync configuration API error %d\n", result); + exit (1); + } + + result = corosync_cfg_reload_config (handle); + if (result != CS_OK) { + printf ("Could not reload configuration %d\n", result); + } + else { + printf ("Done\n"); + } + + (void)corosync_cfg_finalize (handle); +} + static void shutdown_do(void) { cs_error_t result; @@ -232,11 +255,12 @@ static void usage_do (void) printf ("\t\tre-enable redundant ring operation.\n"); printf ("\t-a\tDisplay the IP address(es) of a node\n"); printf ("\t-k\tKill a node identified by node id.\n"); + printf ("\t-R\tReload corosync.conf on all nodes.\n"); printf ("\t-H\tShutdown corosync cleanly on this node.\n"); } int main (int argc, char *argv[]) { - const char *options = "i:srk:a:hH"; + const char *options = "i:srRk:a:hH"; int opt; unsigned int nodeid; char interface_name[128] = ""; @@ -253,6 +277,9 @@ int main (int argc, char *argv[]) { case 's': rc = ringstatusget_do (interface_name); break; + case 'R': + reload_config_do (); + break; case 'r': ringreenable_do (); break;
_______________________________________________ discuss mailing list discuss@xxxxxxxxxxxx http://lists.corosync.org/mailman/listinfo/discuss