static int qdevice_net_msg_received_ask_for_vote_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { enum tlv_vote result_vote; int ring_id_is_valid; if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected ask for vote reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (!msg->vote_set || !msg->seq_number_set || !msg->ring_id_set) { qdevice_log(LOG_ERR, "Received node list reply message without " "required options. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } qdevice_log(LOG_DEBUG, "Received ask for vote reply"); qdevice_log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); qdevice_log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); qdevice_log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", msg->ring_id.node_id, msg->ring_id.seq); result_vote = msg->vote; if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { ring_id_is_valid = 0; qdevice_log(LOG_DEBUG, "Received ask for vote reply with old ring id."); } else { ring_id_is_valid = 1; } if (qdevice_net_algorithm_ask_for_vote_reply_received(instance, msg->seq_number, &msg->ring_id, ring_id_is_valid, &result_vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_ASK_FOR_VOTE_REPLY_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); } if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; return (-1); } return (0); }
/* * Called when cmap reload (or nodelist) was requested. * * nlist is node list * config_version is valid only if config_version_set != 0 * * Should return 0 if processing should continue or -1 to call exit */ int qdevice_model_net_config_node_list_changed(struct qdevice_instance *instance, const struct node_list *nlist, int config_version_set, uint64_t config_version) { struct qdevice_net_instance *net_instance; int send_node_list; enum tlv_vote vote; net_instance = instance->model_data; if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { /* * Nodelist changed, but connection to qnetd not initiated yet. */ send_node_list = 0; if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } else { vote = TLV_VOTE_NO_CHANGE; } } else { send_node_list = 1; vote = TLV_VOTE_NO_CHANGE; } if (qdevice_net_algorithm_config_node_list_changed(net_instance, nlist, config_version_set, config_version, &send_node_list, &vote) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error, Disconnecting"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_CONFIG_NODE_LIST_CHANGED_ERR; net_instance->schedule_disconnect = 1; return (0); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s node list and result vote is %s", (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_config_node_list_changed fatal error. " " Can't update cast vote timer vote"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; return (0); } if (send_node_list) { if (qdevice_net_send_config_node_list(net_instance, nlist, config_version_set, config_version, 0) != 0) { net_instance->schedule_disconnect = 1; net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (0); } } return (0); }
int qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance, uint32_t expected_votes) { struct qdevice_net_instance *net_instance; enum tlv_vote vote; net_instance = instance->model_data; qdevice_log(LOG_DEBUG, "qdevice_model_net_votequorum_expected_votes_notify" " (expected votes old=%"PRIu32" / new=%"PRIu32")", net_instance->qdevice_instance_ptr->vq_expected_votes, expected_votes); vote = TLV_VOTE_NO_CHANGE; if (qdevice_net_algorithm_votequorum_expected_votes_notify(net_instance, expected_votes, &vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_EXPECTED_VOTES_NOTIFY_ERR; net_instance->schedule_disconnect = 1; return (0); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_expected_votes_notify fatal error. " " Can't update cast vote timer vote"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; return (0); } return (0); }
static int qdevice_net_msg_received_vote_info(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { struct send_buffer_list_entry *send_buffer; enum tlv_vote result_vote; int ring_id_is_valid; if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected vote info message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (!msg->vote_set || !msg->seq_number_set || !msg->ring_id_set) { qdevice_log(LOG_ERR, "Received node list reply message without " "required options. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } qdevice_log(LOG_DEBUG, "Received vote info"); qdevice_log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); qdevice_log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); qdevice_log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", msg->ring_id.node_id, msg->ring_id.seq); result_vote = msg->vote; if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { ring_id_is_valid = 0; qdevice_log(LOG_DEBUG, "Received vote info with old ring id."); } else { ring_id_is_valid = 1; } if (qdevice_net_algorithm_vote_info_received(instance, msg->seq_number, &msg->ring_id, ring_id_is_valid, &result_vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTE_INFO_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); } if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; return (-1); } /* * Create reply message */ send_buffer = send_buffer_list_get_new(&instance->send_buffer_list); if (send_buffer == NULL) { qdevice_log(LOG_ERR, "Can't allocate send list buffer for " "vote info reply msg"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } if (msg_create_vote_info_reply(&send_buffer->buffer, msg->seq_number) == 0) { qdevice_log(LOG_ERR, "Can't allocate send buffer for " "vote info reply list msg"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; send_buffer_list_discard_new(&instance->send_buffer_list, send_buffer); return (-1); } send_buffer_list_put(&instance->send_buffer_list, send_buffer); return (0); }
static int qdevice_net_msg_received_node_list_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { const char *str; enum tlv_vote result_vote; int res; int case_processed; int ring_id_is_valid; if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected node list reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (!msg->vote_set || !msg->seq_number_set || !msg->node_list_type_set) { qdevice_log(LOG_ERR, "Received node list reply message without " "required options. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (!msg->ring_id_set) { qdevice_log(LOG_ERR, "Received node list reply message " "without ring id set. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } str = NULL; switch (msg->node_list_type) { case TLV_NODE_LIST_TYPE_INITIAL_CONFIG: str = "initial config"; break; case TLV_NODE_LIST_TYPE_CHANGED_CONFIG: str = "changed config"; break; case TLV_NODE_LIST_TYPE_MEMBERSHIP: str ="membership"; break; case TLV_NODE_LIST_TYPE_QUORUM: str ="quorum"; break; /* * Default is not defined intentionally. Compiler shows warning when new node list type * is added */ } if (str == NULL) { qdevice_log(LOG_CRIT, "qdevice_net_msg_received_node_list_reply fatal error. " "Unhandled node_list_type (debug output)"); exit(1); } qdevice_log(LOG_DEBUG, "Received %s node list reply", str); qdevice_log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); qdevice_log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); qdevice_log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", msg->ring_id.node_id, msg->ring_id.seq); /* * Call algorithm */ result_vote = msg->vote; if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { ring_id_is_valid = 0; qdevice_log(LOG_DEBUG, "Received node list reply with old ring id."); } else { ring_id_is_valid = 1; } case_processed = 0; switch (msg->node_list_type) { case TLV_NODE_LIST_TYPE_INITIAL_CONFIG: case TLV_NODE_LIST_TYPE_CHANGED_CONFIG: case_processed = 1; res = qdevice_net_algorithm_config_node_list_reply_received(instance, msg->seq_number, (msg->node_list_type == TLV_NODE_LIST_TYPE_INITIAL_CONFIG), &msg->ring_id, ring_id_is_valid, &result_vote); break; case TLV_NODE_LIST_TYPE_MEMBERSHIP: case_processed = 1; res = qdevice_net_algorithm_membership_node_list_reply_received(instance, msg->seq_number, &msg->ring_id, ring_id_is_valid, &result_vote); break; case TLV_NODE_LIST_TYPE_QUORUM: case_processed = 1; res = qdevice_net_algorithm_quorum_node_list_reply_received(instance, msg->seq_number, &msg->ring_id, ring_id_is_valid, &result_vote); break; /* * Default is not defined intentionally. Compiler shows warning when new node list type * is added */ } if (!case_processed) { qdevice_log(LOG_CRIT, "qdevice_net_msg_received_node_list_reply fatal error. " "Unhandled node_list_type (algorithm call)"); exit(1); } if (res != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_NODE_LIST_REPLY_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); } if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; return (-1); } return (0); }
static int qdevice_net_msg_received_init_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { size_t zi; int res; int send_config_node_list; int send_membership_node_list; int send_quorum_node_list; enum tlv_vote vote; struct tlv_ring_id tlv_rid; enum tlv_quorate quorate; qdevice_log(LOG_DEBUG, "Received init reply msg"); if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_INIT_REPLY) { qdevice_log(LOG_ERR, "Received unexpected init reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (!msg->reply_error_code_set) { qdevice_log(LOG_ERR, "Received init reply message without error code." "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->reply_error_code != TLV_REPLY_ERROR_CODE_NO_ERROR) { qdevice_log(LOG_ERR, "Received init reply message with error code %"PRIu16". " "Disconnecting from server", msg->reply_error_code); if (msg->reply_error_code == TLV_REPLY_ERROR_CODE_DUPLICATE_NODE_ID) { qdevice_log(LOG_ERR, "Duplicate node id may be result of server not yet " "accepted this node disconnect. Retry again."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_DUPLICATE_NODE_ID_ERROR; } else if (msg->reply_error_code == TLV_REPLY_ERROR_CODE_TIE_BREAKER_DIFFERS_FROM_OTHER_NODES) { qdevice_log(LOG_ERR, "Configured tie-breaker differs in cluster. This may be " "result of server not yet accepted this node disconnect. Retry again."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_TIE_BREAKER_DIFFERS_FROM_OTHER_NODES_ERROR; } else if (msg->reply_error_code == TLV_REPLY_ERROR_CODE_ALGORITHM_DIFFERS_FROM_OTHER_NODES) { qdevice_log(LOG_ERR, "Configured algorithm differs in cluster. This may be " "result of server not yet accepted this node disconnect. Retry again."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ALGORITHM_DIFFERS_FROM_OTHER_NODES_ERROR; } else { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ERROR; } return (-1); } if (!msg->server_maximum_request_size_set || !msg->server_maximum_reply_size_set) { qdevice_log(LOG_ERR, "Required maximum_request_size or maximum_reply_size " "option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->supported_messages == NULL || msg->supported_options == NULL) { qdevice_log(LOG_ERR, "Required supported messages or supported options " "option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->supported_decision_algorithms == NULL) { qdevice_log(LOG_ERR, "Required supported decision algorithms option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->server_maximum_request_size < instance->advanced_settings->net_min_msg_send_size) { qdevice_log(LOG_ERR, "Server accepts maximum %zu bytes message but this client minimum " "is %zu bytes.", msg->server_maximum_request_size, instance->advanced_settings->net_min_msg_send_size); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_MSG_SIZE; return (-1); } if (msg->server_maximum_reply_size > instance->advanced_settings->net_max_msg_receive_size) { qdevice_log(LOG_ERR, "Server may send message up to %zu bytes message but this client maximum " "is %zu bytes.", msg->server_maximum_reply_size, instance->advanced_settings->net_max_msg_receive_size); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_MSG_SIZE; return (-1); } /* * Change buffer sizes */ dynar_set_max_size(&instance->receive_buffer, msg->server_maximum_reply_size); send_buffer_list_set_max_buffer_size(&instance->send_buffer_list, msg->server_maximum_request_size); /* * Check if server supports decision algorithm we need */ res = 0; for (zi = 0; zi < msg->no_supported_decision_algorithms && !res; zi++) { if (msg->supported_decision_algorithms[zi] == instance->decision_algorithm) { res = 1; } } if (!res) { qdevice_log(LOG_ERR, "Server doesn't support required decision algorithm"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_DOESNT_SUPPORT_REQUIRED_ALGORITHM; return (-1); } /* * Finally fully connected so it's possible to remove connection timer */ if (instance->connect_timer != NULL) { timer_list_delete(&instance->main_timer_list, instance->connect_timer); instance->connect_timer = NULL; } /* * Server accepted heartbeat interval -> schedule regular sending of echo request */ qdevice_net_echo_request_timer_schedule(instance); send_config_node_list = 1; send_membership_node_list = 1; send_quorum_node_list = 1; vote = TLV_VOTE_WAIT_FOR_REPLY; if (qdevice_net_algorithm_connected(instance, &send_config_node_list, &send_membership_node_list, &send_quorum_node_list, &vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_CONNECTED_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s config node list, %s membership " "node list, %s quorum node list and result vote is %s", (send_config_node_list ? "send" : "not send"), (send_membership_node_list ? "send" : "not send"), (send_quorum_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } /* * Now we can finally really send node list, votequorum node list and update timer */ if (send_config_node_list) { if (qdevice_net_send_config_node_list(instance, &instance->qdevice_instance_ptr->config_node_list, instance->qdevice_instance_ptr->config_node_list_version_set, instance->qdevice_instance_ptr->config_node_list_version, 1) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } if (send_membership_node_list) { qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &instance->qdevice_instance_ptr->vq_node_list_ring_id); if (qdevice_net_send_membership_node_list(instance, &tlv_rid, instance->qdevice_instance_ptr->vq_node_list_entries, instance->qdevice_instance_ptr->vq_node_list) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } if (send_quorum_node_list) { quorate = (instance->qdevice_instance_ptr->vq_quorum_quorate ? TLV_QUORATE_QUORATE : TLV_QUORATE_INQUORATE); if (qdevice_net_send_quorum_node_list(instance, quorate, instance->qdevice_instance_ptr->vq_quorum_node_list_entries, instance->qdevice_instance_ptr->vq_quorum_node_list) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } if (qdevice_net_cast_vote_timer_update(instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_net_msg_received_set_option_reply fatal error. " " Can't update cast vote timer vote"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; } instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS; instance->connected_since_time = time(NULL); return (0); }
int qdevice_model_net_votequorum_node_list_notify(struct qdevice_instance *instance, votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[]) { struct qdevice_net_instance *net_instance; struct tlv_ring_id tlv_rid; enum tlv_vote vote; int pause_cast_vote_timer; net_instance = instance->model_data; /* * Stop regular heuristics till qdevice_model_net_votequorum_node_list_heuristics_notify * is called */ if (qdevice_net_heuristics_stop_timer(net_instance) != 0) { return (0); } pause_cast_vote_timer = 1; vote = TLV_VOTE_NO_CHANGE; if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS && net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { /* * Nodelist changed and vote timer still votes ACK. It's needed to start voting * NACK. */ if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } } qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id); if (qdevice_net_algorithm_votequorum_node_list_notify(net_instance, &tlv_rid, node_list_entries, node_list, &pause_cast_vote_timer, &vote) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting."); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_NOTIFY_ERR; net_instance->schedule_disconnect = 1; return (0); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s cast vote timer and result vote is %s ", (pause_cast_vote_timer ? "pause" : "not pause"), tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error " "Can't update cast vote timer"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; return (0); } qdevice_net_cast_vote_timer_set_paused(net_instance, pause_cast_vote_timer); return (0); }
int qdevice_model_net_votequorum_node_list_heuristics_notify(struct qdevice_instance *instance, votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[], enum qdevice_heuristics_exec_result heuristics_exec_result) { struct qdevice_net_instance *net_instance; struct tlv_ring_id tlv_rid; enum tlv_vote vote; enum tlv_heuristics heuristics; int send_node_list; net_instance = instance->model_data; qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id); heuristics = qdevice_net_heuristics_exec_result_to_tlv(heuristics_exec_result); if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { /* * Nodelist changed, but connection to qnetd not initiated yet. */ send_node_list = 0; if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } else { vote = TLV_VOTE_NO_CHANGE; } } else { send_node_list = 1; vote = TLV_VOTE_WAIT_FOR_REPLY; } if (qdevice_net_algorithm_votequorum_node_list_heuristics_notify(net_instance, &tlv_rid, node_list_entries, node_list, &send_node_list, &vote, &heuristics) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting."); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_HEURISTICS_NOTIFY_ERR; net_instance->schedule_disconnect = 1; return (0); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s list, result vote is %s and heuristics is %s", (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote), tlv_heuristics_to_str(heuristics)); } if (send_node_list) { if (qdevice_net_send_membership_node_list(net_instance, &tlv_rid, node_list_entries, node_list, heuristics) != 0) { /* * Fatal error -> schedule disconnect */ net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; net_instance->schedule_disconnect = 1; return (0); } } /* * Unpause cast vote timer */ qdevice_net_cast_vote_timer_set_paused(net_instance, 0); if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error " "Can't update cast vote timer"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; return (0); } net_instance->latest_vq_heuristics_result = heuristics; net_instance->latest_heuristics_result = heuristics; if (qdevice_net_heuristics_schedule_timer(net_instance) != 0) { return (0); } return (0); }
int qdevice_model_net_votequorum_quorum_notify(struct qdevice_instance *instance, uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[]) { struct qdevice_net_instance *net_instance; int send_node_list; enum tlv_vote vote; net_instance = instance->model_data; if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { /* * Nodelist changed, but connection to qnetd not initiated yet. */ send_node_list = 0; if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } else { vote = TLV_VOTE_NO_CHANGE; } } else { send_node_list = 1; vote = TLV_VOTE_NO_CHANGE; } if (qdevice_net_algorithm_votequorum_quorum_notify(net_instance, quorate, node_list_entries, node_list, &send_node_list, &vote) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting."); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_QUORUM_NOTIFY_ERR; net_instance->schedule_disconnect = 1; return (0); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s list and result vote is %s", (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_quorum_notify fatal error. " " Can't update cast vote timer vote"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; return (0); } if (send_node_list) { if (qdevice_net_send_quorum_node_list(net_instance, (quorate ? TLV_QUORATE_QUORATE : TLV_QUORATE_INQUORATE), node_list_entries, node_list) != 0) { /* * Fatal error -> schedule disconnect */ net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; net_instance->schedule_disconnect = 1; return (0); } } return (0); }
int qdevice_model_net_run(struct qdevice_instance *instance) { struct qdevice_net_instance *net_instance; int try_connect; int res; enum tlv_vote vote; int delay_before_reconnect; net_instance = instance->model_data; qdevice_log(LOG_DEBUG, "Executing qdevice-net"); try_connect = 1; while (try_connect) { net_instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT; net_instance->socket = NULL; net_instance->connect_timer = timer_list_add(&net_instance->main_timer_list, net_instance->connect_timeout, qdevice_model_net_timer_connect_timeout, (void *)net_instance, NULL); if (net_instance->connect_timer == NULL) { qdevice_log(LOG_CRIT, "Can't schedule connect timer"); try_connect = 0; break; } qdevice_log(LOG_DEBUG, "Trying connect to qnetd server %s:%u (timeout = %ums)", net_instance->host_addr, net_instance->host_port, net_instance->connect_timeout); res = nss_sock_non_blocking_client_init(net_instance->host_addr, net_instance->host_port, qdevice_model_net_get_af(net_instance), &net_instance->non_blocking_client); if (res == -1) { qdevice_log_nss(LOG_ERR, "Can't initialize non blocking client connection"); } res = nss_sock_non_blocking_client_try_next(&net_instance->non_blocking_client); if (res == -1) { qdevice_log_nss(LOG_ERR, "Can't connect to qnetd host"); nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client); } while (qdevice_net_poll(net_instance) == 0) { }; if (net_instance->connect_timer != NULL) { timer_list_delete(&net_instance->main_timer_list, net_instance->connect_timer); net_instance->connect_timer = NULL; } if (net_instance->echo_request_timer != NULL) { timer_list_delete(&net_instance->main_timer_list, net_instance->echo_request_timer); net_instance->echo_request_timer = NULL; } try_connect = qdevice_net_disconnect_reason_try_reconnect(net_instance->disconnect_reason); /* * Unpause cast vote timer, because if it is paused we cannot remove tracking */ qdevice_net_cast_vote_timer_set_paused(net_instance, 0); vote = TLV_VOTE_NO_CHANGE; if (qdevice_net_algorithm_disconnected(net_instance, net_instance->disconnect_reason, &try_connect, &vote) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error, force exit"); return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_ERR, "qdevice_model_net_run fatal error. " " Can't update cast vote timer vote"); } if (qdevice_net_disconnect_reason_force_disconnect(net_instance->disconnect_reason)) { try_connect = 0; } if (net_instance->socket != NULL) { if (PR_Close(net_instance->socket) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close connection"); } net_instance->socket = NULL; } if (!net_instance->non_blocking_client.destroyed) { nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client); } if (net_instance->non_blocking_client.socket != NULL) { if (PR_Close(net_instance->non_blocking_client.socket) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close non-blocking client connection"); } net_instance->non_blocking_client.socket = NULL; } if (try_connect && net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) { /* * Give qnetd server a little time before reconnect */ delay_before_reconnect = random() % (int)(net_instance->cast_vote_timer_interval * 0.9); qdevice_log(LOG_DEBUG, "Sleeping for %u ms before reconnect", delay_before_reconnect); (void)poll(NULL, 0, delay_before_reconnect); } qdevice_net_instance_clean(net_instance); } return (0); }