1 /*
2  * Copyright (c) 2015-2017 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Jan Friesse (jfriesse@redhat.com)
7  *
8  * This software licensed under BSD license, the text of which follows:
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  * - Neither the name of the Red Hat, Inc. nor the names of its
19  *   contributors may be used to endorse or promote products derived from this
20  *   software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/types.h>
36 
37 #include "qnet-config.h"
38 #include "qdevice-net-algorithm.h"
39 #include "qdevice-log.h"
40 
41 #include "qdevice-net-algo-test.h"
42 #include "qdevice-net-algo-ffsplit.h"
43 #include "qdevice-net-algo-2nodelms.h"
44 #include "qdevice-net-algo-lms.h"
45 
46 static struct qdevice_net_algorithm *qdevice_net_algorithm_array[QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE];
47 
48 int
qdevice_net_algorithm_init(struct qdevice_net_instance * instance)49 qdevice_net_algorithm_init(struct qdevice_net_instance *instance)
50 {
51 
52 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
53 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
54 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_init unhandled decision algorithm");
55 		exit(1);
56 	}
57 
58 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->init(instance));
59 }
60 
61 int
qdevice_net_algorithm_connected(struct qdevice_net_instance * instance,enum tlv_heuristics * heuristics,int * send_config_node_list,int * send_membership_node_list,int * send_quorum_node_list,enum tlv_vote * vote)62 qdevice_net_algorithm_connected(struct qdevice_net_instance *instance, enum tlv_heuristics *heuristics,
63     int *send_config_node_list, int *send_membership_node_list, int *send_quorum_node_list, enum tlv_vote *vote)
64 {
65 
66 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
67 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
68 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_connected unhandled decision algorithm");
69 		exit(1);
70 	}
71 
72 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->connected(instance,
73 	    heuristics, send_config_node_list, send_membership_node_list, send_quorum_node_list, vote));
74 }
75 
76 int
qdevice_net_algorithm_config_node_list_changed(struct qdevice_net_instance * instance,const struct node_list * nlist,int config_version_set,uint64_t config_version,int * send_node_list,enum tlv_vote * vote)77 qdevice_net_algorithm_config_node_list_changed(struct qdevice_net_instance *instance,
78     const struct node_list *nlist, int config_version_set, uint64_t config_version,
79     int *send_node_list, enum tlv_vote *vote)
80 {
81 
82 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
83 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
84 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_connected unhandled decision algorithm");
85 		exit(1);
86 	}
87 
88 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
89 	    config_node_list_changed(instance, nlist, config_version_set, config_version,
90 	    send_node_list, vote));
91 }
92 
93 int
qdevice_net_algorithm_votequorum_node_list_notify(struct qdevice_net_instance * instance,const struct tlv_ring_id * ring_id,uint32_t node_list_entries,uint32_t node_list[],int * pause_cast_vote_timer,enum tlv_vote * vote)94 qdevice_net_algorithm_votequorum_node_list_notify(struct qdevice_net_instance *instance,
95     const struct tlv_ring_id *ring_id, uint32_t node_list_entries, uint32_t node_list[],
96     int *pause_cast_vote_timer, enum tlv_vote *vote)
97 {
98 
99 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
100 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
101 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_votequorum_node_list_notify "
102 		    "unhandled decision algorithm");
103 		exit(1);
104 	}
105 
106 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->votequorum_node_list_notify(
107 	    instance, ring_id, node_list_entries, node_list, pause_cast_vote_timer, vote));
108 }
109 
110 int
qdevice_net_algorithm_votequorum_node_list_heuristics_notify(struct qdevice_net_instance * instance,const struct tlv_ring_id * ring_id,uint32_t node_list_entries,uint32_t node_list[],int * send_node_list,enum tlv_vote * vote,enum tlv_heuristics * heuristics)111 qdevice_net_algorithm_votequorum_node_list_heuristics_notify(struct qdevice_net_instance *instance,
112     const struct tlv_ring_id *ring_id, uint32_t node_list_entries, uint32_t node_list[],
113     int *send_node_list, enum tlv_vote *vote, enum tlv_heuristics *heuristics)
114 {
115 
116 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
117 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
118 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_votequorum_node_list_heuristics_notify "
119 		    "unhandled decision algorithm");
120 		exit(1);
121 	}
122 
123 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
124 	    votequorum_node_list_heuristics_notify(
125 	    instance, ring_id, node_list_entries, node_list, send_node_list, vote, heuristics));
126 }
127 
128 int
qdevice_net_algorithm_votequorum_quorum_notify(struct qdevice_net_instance * instance,uint32_t quorate,uint32_t node_list_entries,votequorum_node_t node_list[],int * send_node_list,enum tlv_vote * vote)129 qdevice_net_algorithm_votequorum_quorum_notify(struct qdevice_net_instance *instance,
130     uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[], int *send_node_list,
131     enum tlv_vote *vote)
132 {
133 
134 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
135 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
136 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_votequorum_quorum_notify "
137 		    "unhandled decision algorithm");
138 		exit(1);
139 	}
140 
141 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
142 	    votequorum_quorum_notify(instance, quorate, node_list_entries, node_list,
143 	    send_node_list, vote));
144 }
145 
146 int
qdevice_net_algorithm_votequorum_expected_votes_notify(struct qdevice_net_instance * instance,uint32_t expected_votes,enum tlv_vote * vote)147 qdevice_net_algorithm_votequorum_expected_votes_notify(struct qdevice_net_instance *instance,
148     uint32_t expected_votes, enum tlv_vote *vote)
149 {
150 
151 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
152 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
153 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_votequorum_expected_votes_notify "
154 		    "unhandled decision algorithm");
155 		exit(1);
156 	}
157 
158 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
159 	    votequorum_expected_votes_notify(instance, expected_votes, vote));
160 }
161 
162 int
qdevice_net_algorithm_config_node_list_reply_received(struct qdevice_net_instance * instance,uint32_t seq_number,int initial,const struct tlv_ring_id * ring_id,int ring_id_is_valid,enum tlv_vote * vote)163 qdevice_net_algorithm_config_node_list_reply_received(struct qdevice_net_instance *instance,
164     uint32_t seq_number, int initial, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
165     enum tlv_vote *vote)
166 {
167 
168 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
169 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
170 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_config_node_list_reply_received "
171 		    "unhandled decision algorithm");
172 		exit(1);
173 	}
174 
175 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
176 	    config_node_list_reply_received(instance, seq_number, initial, ring_id,
177 	    ring_id_is_valid, vote));
178 }
179 
180 int
qdevice_net_algorithm_membership_node_list_reply_received(struct qdevice_net_instance * instance,uint32_t seq_number,const struct tlv_ring_id * ring_id,int ring_id_is_valid,enum tlv_vote * vote)181 qdevice_net_algorithm_membership_node_list_reply_received(struct qdevice_net_instance *instance,
182     uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid, enum tlv_vote *vote)
183 {
184 
185 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
186 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
187 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_membership_node_list_reply_received "
188 		    "unhandled decision algorithm");
189 		exit(1);
190 	}
191 
192 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
193 	    membership_node_list_reply_received(instance, seq_number, ring_id, ring_id_is_valid,
194 	    vote));
195 }
196 
197 int
qdevice_net_algorithm_quorum_node_list_reply_received(struct qdevice_net_instance * instance,uint32_t seq_number,const struct tlv_ring_id * ring_id,int ring_id_is_valid,enum tlv_vote * vote)198 qdevice_net_algorithm_quorum_node_list_reply_received(struct qdevice_net_instance *instance,
199     uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
200     enum tlv_vote *vote)
201 {
202 
203 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
204 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
205 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_quorum_node_list_reply_received "
206 		    "unhandled decision algorithm");
207 		exit(1);
208 	}
209 
210 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
211 	    quorum_node_list_reply_received(instance, seq_number, ring_id, ring_id_is_valid,
212 	    vote));
213 }
214 
215 int
qdevice_net_algorithm_ask_for_vote_reply_received(struct qdevice_net_instance * instance,uint32_t seq_number,const struct tlv_ring_id * ring_id,int ring_id_is_valid,enum tlv_vote * vote)216 qdevice_net_algorithm_ask_for_vote_reply_received(struct qdevice_net_instance *instance,
217     uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
218     enum tlv_vote *vote)
219 {
220 
221 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
222 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
223 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_ask_for_vote_reply_received "
224 		    "unhandled decision algorithm");
225 		exit(1);
226 	}
227 
228 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
229 	    ask_for_vote_reply_received(instance, seq_number, ring_id, ring_id_is_valid, vote));
230 }
231 
232 int
qdevice_net_algorithm_vote_info_received(struct qdevice_net_instance * instance,uint32_t seq_number,const struct tlv_ring_id * ring_id,int ring_id_is_valid,enum tlv_vote * vote)233 qdevice_net_algorithm_vote_info_received(struct qdevice_net_instance *instance,
234     uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
235     enum tlv_vote *vote)
236 {
237 
238 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
239 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
240 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_vote_info_received "
241 		    "unhandled decision algorithm");
242 		exit(1);
243 	}
244 
245 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
246 	    vote_info_received(instance, seq_number, ring_id, ring_id_is_valid, vote));
247 }
248 
249 int
qdevice_net_algorithm_echo_reply_received(struct qdevice_net_instance * instance,uint32_t seq_number,int is_expected_seq_number)250 qdevice_net_algorithm_echo_reply_received(struct qdevice_net_instance *instance,
251     uint32_t seq_number, int is_expected_seq_number)
252 {
253 
254 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
255 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
256 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_echo_reply_received "
257 		    "unhandled decision algorithm");
258 		exit(1);
259 	}
260 
261 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
262 	    echo_reply_received(instance, seq_number, is_expected_seq_number));
263 }
264 
265 int
qdevice_net_algorithm_echo_reply_not_received(struct qdevice_net_instance * instance)266 qdevice_net_algorithm_echo_reply_not_received(struct qdevice_net_instance *instance)
267 {
268 
269 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
270 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
271 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_echo_reply_not_received "
272 		    "unhandled decision algorithm");
273 		exit(1);
274 	}
275 
276 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
277 	    echo_reply_not_received(instance));
278 }
279 
280 int
qdevice_net_algorithm_heuristics_change(struct qdevice_net_instance * instance,enum tlv_heuristics * heuristics,int * send_msg,enum tlv_vote * vote)281 qdevice_net_algorithm_heuristics_change(struct qdevice_net_instance *instance,
282     enum tlv_heuristics *heuristics, int *send_msg, enum tlv_vote *vote)
283 {
284 
285 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
286 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
287 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_heuristics_change "
288 		    "unhandled decision algorithm");
289 		exit(1);
290 	}
291 
292 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
293 	    heuristics_change(instance, heuristics, send_msg, vote));
294 }
295 
296 int
qdevice_net_algorithm_heuristics_change_reply_received(struct qdevice_net_instance * instance,uint32_t seq_number,const struct tlv_ring_id * ring_id,int ring_id_is_valid,enum tlv_heuristics heuristics,enum tlv_vote * vote)297 qdevice_net_algorithm_heuristics_change_reply_received(struct qdevice_net_instance *instance,
298     uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
299     enum tlv_heuristics heuristics, enum tlv_vote *vote)
300 {
301 
302 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
303 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
304 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_heuristics_change_reply_received "
305 		    "unhandled decision algorithm");
306 		exit(1);
307 	}
308 
309 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
310 	    heuristics_change_reply_received(instance, seq_number, ring_id, ring_id_is_valid,
311 	    heuristics, vote));
312 }
313 
314 int
qdevice_net_algorithm_disconnected(struct qdevice_net_instance * instance,enum qdevice_net_disconnect_reason disconnect_reason,int * try_reconnect,enum tlv_vote * vote)315 qdevice_net_algorithm_disconnected(struct qdevice_net_instance *instance,
316     enum qdevice_net_disconnect_reason disconnect_reason, int *try_reconnect, enum tlv_vote *vote)
317 {
318 
319 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
320 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
321 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_disconnected "
322 		    "unhandled decision algorithm");
323 		exit(1);
324 	}
325 
326 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
327 	    disconnected(instance, disconnect_reason, try_reconnect, vote));
328 }
329 
330 void
qdevice_net_algorithm_destroy(struct qdevice_net_instance * instance)331 qdevice_net_algorithm_destroy(struct qdevice_net_instance *instance)
332 {
333 
334 	if (instance->decision_algorithm >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE ||
335 	    qdevice_net_algorithm_array[instance->decision_algorithm] == NULL) {
336 		qdevice_log(LOG_CRIT, "qdevice_net_algorithm_destroy "
337 		    "unhandled decision algorithm");
338 		exit(1);
339 	}
340 
341 	return (qdevice_net_algorithm_array[instance->decision_algorithm]->
342 	    destroy(instance));
343 }
344 
345 int
qdevice_net_algorithm_register(enum tlv_decision_algorithm_type algorithm_number,struct qdevice_net_algorithm * algorithm)346 qdevice_net_algorithm_register(enum tlv_decision_algorithm_type algorithm_number,
347     struct qdevice_net_algorithm *algorithm)
348 {
349 
350 	if (algorithm_number >= QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE) {
351 		return (-1);
352 	}
353 
354 	if (qdevice_net_algorithm_array[algorithm_number] != NULL) {
355 		return (-1);
356 	}
357 
358 	qdevice_net_algorithm_array[algorithm_number] = algorithm;
359 
360 	return (0);
361 }
362 
363 int
qdevice_net_algorithm_register_all(void)364 qdevice_net_algorithm_register_all(void)
365 {
366 
367 	if (qdevice_net_algo_test_register() != 0) {
368 		qdevice_log(LOG_CRIT, "Failed to register decision algorithm 'test' ");
369 		return (-1);
370 	}
371 
372 	if (qdevice_net_algo_ffsplit_register() != 0) {
373 		qdevice_log(LOG_CRIT, "Failed to register decision algorithm 'ffsplit' ");
374 		return (-1);
375 	}
376 
377 	if (qdevice_net_algo_2nodelms_register() != 0) {
378 		qdevice_log(LOG_CRIT, "Failed to register decision algorithm '2nodelms' ");
379 		return (-1);
380 	}
381 
382 	if (qdevice_net_algo_lms_register() != 0) {
383 		qdevice_log(LOG_CRIT, "Failed to register decision algorithm 'lms' ");
384 		return (-1);
385 	}
386 
387 	return (0);
388 }
389