diff --git a/qdevices/qdevice-net-algorithm.c b/qdevices/qdevice-net-algorithm.c index cd2111a9..ee7be160 100644 --- a/qdevices/qdevice-net-algorithm.c +++ b/qdevices/qdevice-net-algorithm.c @@ -311,20 +311,3 @@ qdevice_net_algorithm_register_all(void) return (0); } - -const char * -qdevice_net_algorithm_type_to_str(enum tlv_decision_algorithm_type algo_type) -{ - - switch (algo_type) { - case TLV_DECISION_ALGORITHM_TYPE_TEST: return ("Test"); break; - case TLV_DECISION_ALGORITHM_TYPE_FFSPLIT: return ("Fifty-Fifty split"); break; - case TLV_DECISION_ALGORITHM_TYPE_2NODELMS: return ("2 Node LMS"); break; - case TLV_DECISION_ALGORITHM_TYPE_LMS: return ("LMS"); break; - /* - * Default is not defined intentionally. Compiler shows warning when new model is added - */ - } - - return ("Unknown algorithm"); -} diff --git a/qdevices/qdevice-net-algorithm.h b/qdevices/qdevice-net-algorithm.h index 1102efc3..e105fd43 100644 --- a/qdevices/qdevice-net-algorithm.h +++ b/qdevices/qdevice-net-algorithm.h @@ -126,9 +126,6 @@ extern int qdevice_net_algorithm_register( extern int qdevice_net_algorithm_register_all(void); -extern const char *qdevice_net_algorithm_type_to_str( - enum tlv_decision_algorithm_type algo_type); - #ifdef __cplusplus } #endif diff --git a/qdevices/qdevice-net-cast-vote-timer.c b/qdevices/qdevice-net-cast-vote-timer.c index b14b748a..0583c50d 100644 --- a/qdevices/qdevice-net-cast-vote-timer.c +++ b/qdevices/qdevice-net-cast-vote-timer.c @@ -60,6 +60,7 @@ qdevice_net_cast_vote_timer_callback(void *data1, void *data2) case TLV_VOTE_ASK_LATER: case TLV_VOTE_WAIT_FOR_REPLY: case TLV_VOTE_NO_CHANGE: + case TLV_VOTE_UNDEFINED: /* * Shouldn't happen */ @@ -98,6 +99,8 @@ qdevice_net_cast_vote_timer_update(struct qdevice_net_instance *instance, enum t case_processed = 0; switch (vote) { + case TLV_VOTE_UNDEFINED: + break; case TLV_VOTE_ACK: case TLV_VOTE_NACK: case_processed = 1; diff --git a/qdevices/qdevice-net-ipc-cmd.c b/qdevices/qdevice-net-ipc-cmd.c index cf8d4854..7d266e0f 100644 --- a/qdevices/qdevice-net-ipc-cmd.c +++ b/qdevices/qdevice-net-ipc-cmd.c @@ -115,7 +115,7 @@ qdevice_net_ipc_cmd_status_add_basic_info(struct qdevice_net_instance *instance, } if (dynar_str_catf(outbuf, "Algorithm:\t\t%s\n", - qdevice_net_algorithm_type_to_str(instance->decision_algorithm)) == -1) { + tlv_decision_algorithm_type_to_str(instance->decision_algorithm)) == -1) { return (0); } diff --git a/qdevices/qnetd-client-msg-received.c b/qdevices/qnetd-client-msg-received.c index 31c016ca..ad488ff6 100644 --- a/qdevices/qnetd-client-msg-received.c +++ b/qdevices/qnetd-client-msg-received.c @@ -784,6 +784,9 @@ qnetd_client_msg_received_node_list(struct qnetd_instance *instance, struct qnet return (-1); } + client->config_version_set = msg->config_version_set; + client->config_version = msg->config_version; + break; case TLV_NODE_LIST_TYPE_MEMBERSHIP: case_processed = 1; @@ -818,6 +821,14 @@ qnetd_client_msg_received_node_list(struct qnetd_instance *instance, struct qnet exit(1); } + /* + * Store result vote + */ + client->last_sent_vote = result_vote; + if (result_vote == TLV_VOTE_ACK || result_vote == TLV_VOTE_NACK) { + client->last_sent_ack_nack_vote = result_vote; + } + send_buffer = send_buffer_list_get_new(&client->send_buffer_list); if (send_buffer == NULL) { qnetd_log(LOG_ERR, "Can't alloc node list reply msg from list. " @@ -888,6 +899,14 @@ qnetd_client_msg_received_ask_for_vote(struct qnetd_instance *instance, struct q return (0); } + /* + * Store result vote + */ + client->last_sent_vote = result_vote; + if (result_vote == TLV_VOTE_ACK || result_vote == TLV_VOTE_NACK) { + client->last_sent_ack_nack_vote = result_vote; + } + qnetd_log_debug_ask_for_vote_received(client, msg->seq_number); reply_error_code = qnetd_algorithm_ask_for_vote_received(client, msg->seq_number, diff --git a/qdevices/qnetd-client-send.c b/qdevices/qnetd-client-send.c index dc8f9553..059a5a3f 100644 --- a/qdevices/qnetd-client-send.c +++ b/qdevices/qnetd-client-send.c @@ -75,6 +75,14 @@ qnetd_client_send_vote_info(struct qnetd_client *client, uint32_t msg_seq_number { struct send_buffer_list_entry *send_buffer; + /* + * Store result vote + */ + client->last_sent_vote = vote; + if (vote == TLV_VOTE_ACK || vote == TLV_VOTE_NACK) { + client->last_sent_ack_nack_vote = vote; + } + qnetd_log_debug_send_vote_info(client, msg_seq_number, vote); send_buffer = send_buffer_list_get_new(&client->send_buffer_list); diff --git a/qdevices/qnetd-client.h b/qdevices/qnetd-client.h index 3bc0799a..cf31ece6 100644 --- a/qdevices/qnetd-client.h +++ b/qdevices/qnetd-client.h @@ -72,6 +72,8 @@ struct qnetd_client { enum tlv_reply_error_code skipping_msg_reason; void *algorithm_data; struct node_list configuration_node_list; + uint8_t config_version_set; + uint64_t config_version; struct node_list last_membership_node_list; struct node_list last_quorum_node_list; struct tlv_ring_id last_ring_id; @@ -83,6 +85,8 @@ struct qnetd_client { int schedule_disconnect; uint32_t dpd_time_since_last_check; uint32_t dpd_msg_received_since_last_check; + enum tlv_vote last_sent_vote; + enum tlv_vote last_sent_ack_nack_vote; TAILQ_ENTRY(qnetd_client) entries; TAILQ_ENTRY(qnetd_client) cluster_entries; }; diff --git a/qdevices/qnetd-ipc-cmd.c b/qdevices/qnetd-ipc-cmd.c index 771f2940..e9aa16c6 100644 --- a/qdevices/qnetd-ipc-cmd.c +++ b/qdevices/qnetd-ipc-cmd.c @@ -81,3 +81,207 @@ qnetd_ipc_cmd_status(struct qnetd_instance *instance, struct dynar *outbuf, int return (0); } + +static int +qnetd_ipc_cmd_add_tie_breaker(const struct qnetd_client *client, + struct dynar *outbuf) +{ + + if (dynar_str_catf(outbuf, " Tie-breaker:\t") == -1) { + return (0); + } + + switch (client->tie_breaker.mode) { + case TLV_TIE_BREAKER_MODE_LOWEST: + if (dynar_str_catf(outbuf, "Node with lowest node ID") == -1) { + return (0); + } + break; + case TLV_TIE_BREAKER_MODE_HIGHEST: + if (dynar_str_catf(outbuf, "Node with highest node ID") == -1) { + return (0); + } + break; + case TLV_TIE_BREAKER_MODE_NODE_ID: + if (dynar_str_catf(outbuf, "Node with node ID "UTILS_PRI_NODE_ID, + client->tie_breaker.node_id) == -1) { + return (0); + } + break; + } + + return (dynar_str_catf(outbuf, "\n") != -1); +} + +static int +qnetd_ipc_cmd_list_add_node_list(struct dynar *outbuf, int verbose, const struct node_list *nlist) +{ + struct node_list_entry *node_info; + int i; + + i = 0; + + TAILQ_FOREACH(node_info, nlist, entries) { + if (i != 0) { + if (dynar_str_catf(outbuf, ", ") == -1) { + return (-1); + } + } + + if (dynar_str_catf(outbuf, UTILS_PRI_NODE_ID, node_info->node_id) == -1) { + return (-1); + } + + if (node_info->data_center_id != 0) { + if (dynar_str_catf(outbuf, " (" UTILS_PRI_DATACENTER_ID ")", + node_info->data_center_id) == -1) { + return (-1); + } + + } + + i++; + } + + return (0); +} + +static int +qnetd_ipc_cmd_list_add_client_info(const struct qnetd_client *client, struct dynar *outbuf, + int verbose, size_t client_no) +{ + + if (dynar_str_catf(outbuf, " Node ID "UTILS_PRI_NODE_ID":\n", + client->node_id) == -1) { + return (-1); + } + + if (dynar_str_catf(outbuf, " Client address:\t\t%s\n", + client->addr_str) == -1) { + return (-1); + } + + if (verbose) { + if (dynar_str_catf(outbuf, " HB interval:\t\t%"PRIu32"ms\n", + client->heartbeat_interval) == -1) { + return (-1); + } + } + + if (client->config_version_set) { + if (dynar_str_catf(outbuf, " Configuration version:\t" + UTILS_PRI_CONFIG_VERSION"\n", client->config_version) == -1) { + return (-1); + } + } + + if (!node_list_is_empty(&client->configuration_node_list)) { + if ((dynar_str_catf(outbuf, " Configured node list:\t") == -1) || + (qnetd_ipc_cmd_list_add_node_list(outbuf, verbose, + &client->configuration_node_list) == -1) || + (dynar_str_catf(outbuf, "\n") == -1)) { + return (-1); + } + } + + if (verbose) { + if (dynar_str_catf(outbuf, " Ring ID:\t\t"UTILS_PRI_RING_ID"\n", + client->last_ring_id.node_id, client->last_ring_id.seq) == -1) { + return (-1); + } + } + + if (!node_list_is_empty(&client->last_membership_node_list)) { + if ((dynar_str_catf(outbuf, " Membership node list:\t") == -1) || + (qnetd_ipc_cmd_list_add_node_list(outbuf, verbose, + &client->last_membership_node_list) == -1) || + (dynar_str_catf(outbuf, "\n") == -1)) { + return (-1); + } + } + + if (verbose) { + if (dynar_str_catf(outbuf, " TLS active:\t\t%s", + (client->tls_started ? "Yes" : "No")) == -1) { + return (-1); + } + + if (client->tls_started && client->tls_peer_certificate_verified) { + if (dynar_str_catf(outbuf, " (client certificate verified)") == -1) { + return (-1); + } + } + + if (dynar_str_catf(outbuf, "\n") == -1) { + return (-1); + } + } + + if (client->last_sent_vote != TLV_VOTE_UNDEFINED) { + if (dynar_str_catf(outbuf, " Vote:\t\t\t%s", + tlv_vote_to_str(client->last_sent_vote)) == -1) { + return (-1); + } + + if (client->last_sent_ack_nack_vote != TLV_VOTE_UNDEFINED) { + if (dynar_str_catf(outbuf, " (%s)", + tlv_vote_to_str(client->last_sent_ack_nack_vote)) == -1) { + return (-1); + } + } + + if (dynar_str_catf(outbuf, "\n") == -1) { + return (-1); + } + } + + return (0); +} + +int +qnetd_ipc_cmd_list(struct qnetd_instance *instance, struct dynar *outbuf, int verbose, + const char *cluster_name) +{ + struct qnetd_cluster *cluster; + struct qnetd_client *client; + size_t cluster_no, client_no; + + cluster_no = 0; + TAILQ_FOREACH(cluster, &instance->clusters, entries) { + if (cluster_name != NULL && strcmp(cluster_name, "") != 0 && + strcmp(cluster_name, cluster->cluster_name) != 0) { + continue ; + } + + if (dynar_str_catf(outbuf, "Cluster \"%s\":\n", cluster->cluster_name) == -1) { + return (-1); + } + + client_no = 0; + + TAILQ_FOREACH(client, &cluster->client_list, cluster_entries) { + if (client_no == 0) { + if (dynar_str_catf(outbuf, " Algorithm:\t\t%s\n", + tlv_decision_algorithm_type_to_str( + client->decision_algorithm)) == -1) { + return (-1); + } + + if (!qnetd_ipc_cmd_add_tie_breaker(client, outbuf)) { + return (-1); + } + } + + if (qnetd_ipc_cmd_list_add_client_info(client, outbuf, verbose, + client_no) == -1) { + return (-1); + } + + client_no++; + } + + cluster_no++; + } + + return (0); +} diff --git a/qdevices/qnetd-ipc-cmd.h b/qdevices/qnetd-ipc-cmd.h index bbdb2058..dbbf705e 100644 --- a/qdevices/qnetd-ipc-cmd.h +++ b/qdevices/qnetd-ipc-cmd.h @@ -45,6 +45,9 @@ extern "C" { extern int qnetd_ipc_cmd_status(struct qnetd_instance *instance, struct dynar *outbuf, int verbose); +extern int qnetd_ipc_cmd_list(struct qnetd_instance *instance, + struct dynar *outbuf, int verbose, const char *cluster_name); + #ifdef __cplusplus } #endif diff --git a/qdevices/qnetd-ipc.c b/qdevices/qnetd-ipc.c index 90a7857a..ce08c2a9 100644 --- a/qdevices/qnetd-ipc.c +++ b/qdevices/qnetd-ipc.c @@ -223,6 +223,7 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client char *str; struct qnetd_ipc_user_data *ipc_user_data; int verbose; + char *cluster_name; ipc_user_data = (struct qnetd_ipc_user_data *)client->user_data; @@ -230,15 +231,10 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client token = dynar_simple_lex_token_next(&lex); verbose = 0; + cluster_name = NULL; if (token == NULL) { - qnetd_log(LOG_ERR, "Can't alloc memory for simple lex"); - - if (qnetd_ipc_send_error(instance, client, "Command too long") != 0) { - client->schedule_disconnect = 1; - } - - return; + goto exit_err_low_mem; } str = dynar_data(token); @@ -257,6 +253,10 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client } } else if (strcasecmp(str, "status") == 0) { token = dynar_simple_lex_token_next(&lex); + if (token == NULL) { + goto exit_err_low_mem; + } + str = dynar_data(token); if (token != NULL && strcmp(str, "") != 0) { @@ -274,6 +274,35 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client client->schedule_disconnect = 1; } } + } else if (strcasecmp(str, "list") == 0) { + while (((token = dynar_simple_lex_token_next(&lex)) != NULL) && + (str = dynar_data(token), strcmp(str, "") != 0)) { + if (strcasecmp(str, "verbose") == 0) { + verbose = 1; + } else if (strcasecmp(str, "cluster") == 0) { + token = dynar_simple_lex_token_next(&lex); + if (token == NULL) { + goto exit_err_low_mem; + } + + if ((cluster_name = strdup(dynar_data(token))) == NULL) { + goto exit_err_low_mem; + } + } else { + break; + } + } + + if (qnetd_ipc_cmd_list(instance, &client->send_buffer, verbose, cluster_name) != 0) { + if (qnetd_ipc_send_error(instance, client, "Can't get QNetd cluster list") != 0) { + client->schedule_disconnect = 1; + } + } else { + if (qnetd_ipc_send_buffer(instance, client) != 0) { + client->schedule_disconnect = 1; + } + } + free(cluster_name); cluster_name = NULL; } else { qnetd_log(LOG_DEBUG, "IPC client sent unknown command"); if (qnetd_ipc_send_error(instance, client, "Unknown command '%s'", str) != 0) { @@ -282,6 +311,15 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client } dynar_simple_lex_destroy(&lex); + + return ; + +exit_err_low_mem: + qnetd_log(LOG_ERR, "Can't alloc memory for simple lex"); + + if (qnetd_ipc_send_error(instance, client, "Command too long") != 0) { + client->schedule_disconnect = 1; + } } void diff --git a/qdevices/tlv.c b/qdevices/tlv.c index b1583c00..143876b2 100644 --- a/qdevices/tlv.c +++ b/qdevices/tlv.c @@ -985,6 +985,7 @@ tlv_vote_to_str(enum tlv_vote vote) { switch (vote) { + case TLV_VOTE_UNDEFINED: break; case TLV_VOTE_ACK: return ("ACK"); break; case TLV_VOTE_NACK: return ("NACK"); break; case TLV_VOTE_ASK_LATER: return ("Ask later"); break; @@ -1009,7 +1010,7 @@ tlv_node_state_to_str(enum tlv_node_state state) return ("Unhandled node state"); } -extern const char * +const char * tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported) { @@ -1021,3 +1022,17 @@ tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported) return ("Unhandled tls supported state"); } + +const char * +tlv_decision_algorithm_type_to_str(enum tlv_decision_algorithm_type algorithm) +{ + + switch (algorithm) { + case TLV_DECISION_ALGORITHM_TYPE_TEST: return ("Test"); break; + case TLV_DECISION_ALGORITHM_TYPE_FFSPLIT: return ("Fifty-Fifty split"); break; + case TLV_DECISION_ALGORITHM_TYPE_2NODELMS: return ("2 Node LMS"); break; + case TLV_DECISION_ALGORITHM_TYPE_LMS: return ("LMS"); break; + } + + return ("Unknown algorithm"); +} diff --git a/qdevices/tlv.h b/qdevices/tlv.h index 703b3ee0..06feb9fc 100644 --- a/qdevices/tlv.h +++ b/qdevices/tlv.h @@ -123,6 +123,7 @@ enum tlv_node_list_type { }; enum tlv_vote { + TLV_VOTE_UNDEFINED = 0, TLV_VOTE_ACK = 1, TLV_VOTE_NACK = 2, TLV_VOTE_ASK_LATER = 3, @@ -327,6 +328,9 @@ extern const char * tlv_node_state_to_str(enum tlv_node_state state); extern const char * tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported); +extern const char * tlv_decision_algorithm_type_to_str( + enum tlv_decision_algorithm_type algorithm); + #ifdef __cplusplus } #endif