コード例 #1
0
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);
}
コード例 #2
0
ファイル: qdevice-model-net.c プロジェクト: wferi/corosync
/*
 * 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);
}
コード例 #3
0
ファイル: qdevice-model-net.c プロジェクト: wferi/corosync
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);
}
コード例 #4
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);
}
コード例 #5
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);
}
コード例 #6
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);
}
コード例 #7
0
ファイル: qdevice-model-net.c プロジェクト: wferi/corosync
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);
}
コード例 #8
0
ファイル: qdevice-model-net.c プロジェクト: wferi/corosync
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);
}
コード例 #9
0
ファイル: qdevice-model-net.c プロジェクト: wferi/corosync
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);
}
コード例 #10
0
ファイル: qdevice-model-net.c プロジェクト: wferi/corosync
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);
}