]> git.proxmox.com Git - mirror_corosync-qdevice.git/blob - qdevices/qdevice-model-net.c
qdevice: Propagate error to exit code
[mirror_corosync-qdevice.git] / qdevices / qdevice-model-net.c
1 /*
2 * Copyright (c) 2015-2018 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 <poll.h>
36
37 #include "qdevice-model.h"
38 #include "qdevice-model-net.h"
39 #include "qdevice-log.h"
40 #include "qdevice-net-cast-vote-timer.h"
41 #include "qdevice-net-instance.h"
42 #include "qdevice-net-ipc-cmd.h"
43 #include "qdevice-net-algorithm.h"
44 #include "qdevice-net-heuristics.h"
45 #include "qdevice-net-poll.h"
46 #include "qdevice-net-send.h"
47 #include "qdevice-net-votequorum.h"
48 #include "qnet-config.h"
49 #include "nss-sock.h"
50
51 int
52 qdevice_model_net_init(struct qdevice_instance *instance)
53 {
54
55 struct qdevice_net_instance *net_instance;
56
57 qdevice_log(LOG_DEBUG, "Initializing qdevice_net_instance");
58 if (qdevice_net_instance_init_from_cmap(instance) != 0) {
59 return (-1);
60 }
61
62 net_instance = instance->model_data;
63
64 qdevice_log(LOG_DEBUG, "Registering algorithms");
65 if (qdevice_net_algorithm_register_all() != 0) {
66 return (-1);
67 }
68
69 qdevice_log(LOG_DEBUG, "Initializing NSS");
70 if (nss_sock_init_nss((net_instance->tls_supported != TLV_TLS_UNSUPPORTED ?
71 instance->advanced_settings->net_nss_db_dir : NULL)) != 0) {
72 qdevice_log_nss(LOG_ERR, "Can't init nss");
73 return (-1);
74 }
75
76 if (qdevice_net_cast_vote_timer_update(net_instance, TLV_VOTE_ASK_LATER) != 0) {
77 qdevice_log(LOG_ERR, "Can't update cast vote timer");
78 return (-1);
79 }
80
81 if (qdevice_net_algorithm_init(net_instance) != 0) {
82 qdevice_log(LOG_ERR, "Algorithm init failed");
83 return (-1);
84 }
85
86 if (qdevice_net_heuristics_init(net_instance) != 0) {
87 qdevice_log(LOG_ERR, "Can't initialize net heuristics");
88 return (-1);
89 }
90
91 return (0);
92 }
93
94 int
95 qdevice_model_net_destroy(struct qdevice_instance *instance)
96 {
97 struct qdevice_net_instance *net_instance;
98
99 net_instance = instance->model_data;
100
101 qdevice_log(LOG_DEBUG, "Destroying algorithm");
102 qdevice_net_algorithm_destroy(net_instance);
103
104 qdevice_log(LOG_DEBUG, "Destroying qdevice_net_instance");
105 qdevice_net_instance_destroy(net_instance);
106
107 qdevice_log(LOG_DEBUG, "Shutting down NSS");
108 SSL_ClearSessionCache();
109
110 if (NSS_Shutdown() != SECSuccess) {
111 qdevice_log_nss(LOG_WARNING, "Can't shutdown NSS");
112 }
113
114 if (PR_Cleanup() != PR_SUCCESS) {
115 qdevice_log_nss(LOG_WARNING, "Can't shutdown NSPR");
116 }
117
118 free(net_instance);
119
120 return (0);
121 }
122
123 static int
124 qdevice_model_net_timer_connect_timeout(void *data1, void *data2)
125 {
126 struct qdevice_net_instance *instance;
127
128 instance = (struct qdevice_net_instance *)data1;
129
130 qdevice_log(LOG_ERR, "Connect timeout");
131
132 instance->schedule_disconnect = 1;
133
134 instance->connect_timer = NULL;
135 instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_CONNECT_TO_THE_SERVER;
136
137 return (0);
138 }
139
140 static PRIntn
141 qdevice_model_net_get_af(const struct qdevice_net_instance *instance)
142 {
143 PRIntn af;
144
145 af = PR_AF_UNSPEC;
146 if (instance->force_ip_version == 4) {
147 af = PR_AF_INET;
148 }
149
150 if (instance->force_ip_version == 6) {
151 af = PR_AF_INET6;
152 }
153
154 return (af);
155 }
156
157 int
158 qdevice_model_net_run(struct qdevice_instance *instance)
159 {
160 struct qdevice_net_instance *net_instance;
161 int try_connect;
162 int res;
163 enum tlv_vote vote;
164 int delay_before_reconnect;
165 int ret_val;
166
167 net_instance = instance->model_data;
168
169 qdevice_log(LOG_DEBUG, "Executing qdevice-net");
170
171 ret_val = -1;
172
173 try_connect = 1;
174 while (try_connect) {
175 net_instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT;
176 net_instance->socket = NULL;
177
178 net_instance->connect_timer = timer_list_add(&net_instance->main_timer_list,
179 net_instance->connect_timeout, qdevice_model_net_timer_connect_timeout,
180 (void *)net_instance, NULL);
181
182 if (net_instance->connect_timer == NULL) {
183 qdevice_log(LOG_CRIT, "Can't schedule connect timer");
184
185 try_connect = 0;
186 break;
187 }
188
189 qdevice_log(LOG_DEBUG, "Trying connect to qnetd server %s:%u (timeout = %ums)",
190 net_instance->host_addr, net_instance->host_port, net_instance->connect_timeout);
191
192 res = nss_sock_non_blocking_client_init(net_instance->host_addr,
193 net_instance->host_port, qdevice_model_net_get_af(net_instance),
194 &net_instance->non_blocking_client);
195 if (res == -1) {
196 qdevice_log_nss(LOG_ERR, "Can't initialize non blocking client connection");
197 }
198
199 res = nss_sock_non_blocking_client_try_next(&net_instance->non_blocking_client);
200 if (res == -1) {
201 qdevice_log_nss(LOG_ERR, "Can't connect to qnetd host");
202 nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client);
203 }
204
205 while (qdevice_net_poll(net_instance) == 0) {
206 };
207
208 if (net_instance->connect_timer != NULL) {
209 timer_list_delete(&net_instance->main_timer_list, net_instance->connect_timer);
210 net_instance->connect_timer = NULL;
211 }
212
213 if (net_instance->echo_request_timer != NULL) {
214 timer_list_delete(&net_instance->main_timer_list, net_instance->echo_request_timer);
215 net_instance->echo_request_timer = NULL;
216 }
217
218 try_connect = qdevice_net_disconnect_reason_try_reconnect(net_instance->disconnect_reason);
219
220 /*
221 * Unpause cast vote timer, because if it is paused we cannot remove tracking
222 */
223 qdevice_net_cast_vote_timer_set_paused(net_instance, 0);
224
225 vote = TLV_VOTE_NO_CHANGE;
226
227 if (qdevice_net_algorithm_disconnected(net_instance,
228 net_instance->disconnect_reason, &try_connect, &vote) != 0) {
229 qdevice_log(LOG_ERR, "Algorithm returned error, force exit");
230 return (-1);
231 } else {
232 qdevice_log(LOG_DEBUG, "Algorithm result vote is %s",
233 tlv_vote_to_str(vote));
234 }
235
236 if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
237 qdevice_log(LOG_ERR, "qdevice_model_net_run fatal error. "
238 " Can't update cast vote timer vote");
239 }
240
241 if (qdevice_net_disconnect_reason_force_disconnect(net_instance->disconnect_reason)) {
242 try_connect = 0;
243 }
244
245 /*
246 * Return 0 only when local socket was closed -> regular exit
247 */
248 if (net_instance->disconnect_reason == QDEVICE_NET_DISCONNECT_REASON_LOCAL_SOCKET_CLOSED) {
249 ret_val = 0;
250 }
251
252 if (net_instance->socket != NULL) {
253 if (PR_Close(net_instance->socket) != PR_SUCCESS) {
254 qdevice_log_nss(LOG_WARNING, "Unable to close connection");
255 }
256 net_instance->socket = NULL;
257 }
258
259 if (!net_instance->non_blocking_client.destroyed) {
260 nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client);
261 }
262
263 if (net_instance->non_blocking_client.socket != NULL) {
264 if (PR_Close(net_instance->non_blocking_client.socket) != PR_SUCCESS) {
265 qdevice_log_nss(LOG_WARNING, "Unable to close non-blocking client connection");
266 }
267 net_instance->non_blocking_client.socket = NULL;
268 }
269
270 if (try_connect &&
271 net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
272 /*
273 * Give qnetd server a little time before reconnect
274 */
275 delay_before_reconnect = random() %
276 (int)(net_instance->cast_vote_timer_interval * 0.9);
277
278 qdevice_log(LOG_DEBUG, "Sleeping for %u ms before reconnect",
279 delay_before_reconnect);
280 (void)poll(NULL, 0, delay_before_reconnect);
281 }
282
283
284 qdevice_net_instance_clean(net_instance);
285 }
286
287 return (ret_val);
288 }
289
290 /*
291 * Called when cmap reload (or nodelist) was requested.
292 *
293 * nlist is node list
294 * config_version is valid only if config_version_set != 0
295 *
296 * Should return 0 if processing should continue or -1 to call exit
297 */
298 int
299 qdevice_model_net_config_node_list_changed(struct qdevice_instance *instance,
300 const struct node_list *nlist, int config_version_set, uint64_t config_version)
301 {
302 struct qdevice_net_instance *net_instance;
303 int send_node_list;
304 enum tlv_vote vote;
305
306 net_instance = instance->model_data;
307
308 if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
309 /*
310 * Nodelist changed, but connection to qnetd not initiated yet.
311 */
312 send_node_list = 0;
313
314 if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
315 vote = TLV_VOTE_NACK;
316 } else {
317 vote = TLV_VOTE_NO_CHANGE;
318 }
319 } else {
320 send_node_list = 1;
321 vote = TLV_VOTE_NO_CHANGE;
322 }
323
324 if (qdevice_net_algorithm_config_node_list_changed(net_instance, nlist, config_version_set,
325 config_version, &send_node_list, &vote) != 0) {
326 qdevice_log(LOG_ERR, "Algorithm returned error, Disconnecting");
327
328 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_CONFIG_NODE_LIST_CHANGED_ERR;
329 net_instance->schedule_disconnect = 1;
330
331 return (0);
332 } else {
333 qdevice_log(LOG_DEBUG, "Algorithm decided to %s node list and result vote is %s",
334 (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote));
335 }
336
337 if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
338 qdevice_log(LOG_CRIT, "qdevice_model_net_config_node_list_changed fatal error. "
339 " Can't update cast vote timer vote");
340 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
341 net_instance->schedule_disconnect = 1;
342
343 return (0);
344 }
345
346 if (send_node_list) {
347 if (qdevice_net_send_config_node_list(net_instance, nlist, config_version_set,
348 config_version, 0) != 0) {
349 net_instance->schedule_disconnect = 1;
350 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
351
352 return (0);
353 }
354 }
355
356 return (0);
357 }
358
359 /*
360 * Called when cmap reload (or nodelist) was requested, but it was not possible to
361 * get node list.
362 *
363 * Should return 0 if processing should continue or -1 to call exit
364 */
365 int
366 qdevice_model_net_get_config_node_list_failed(struct qdevice_instance *instance)
367 {
368 struct qdevice_net_instance *net_instance;
369
370 net_instance = instance->model_data;
371
372 net_instance->schedule_disconnect = 1;
373 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
374
375 return (0);
376 }
377
378 int
379 qdevice_model_net_votequorum_quorum_notify(struct qdevice_instance *instance,
380 uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[])
381 {
382 struct qdevice_net_instance *net_instance;
383 int send_node_list;
384 enum tlv_vote vote;
385
386 net_instance = instance->model_data;
387
388 if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
389 /*
390 * Nodelist changed, but connection to qnetd not initiated yet.
391 */
392 send_node_list = 0;
393
394 if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
395 vote = TLV_VOTE_NACK;
396 } else {
397 vote = TLV_VOTE_NO_CHANGE;
398 }
399 } else {
400 send_node_list = 1;
401 vote = TLV_VOTE_NO_CHANGE;
402 }
403
404 if (qdevice_net_algorithm_votequorum_quorum_notify(net_instance, quorate,
405 node_list_entries, node_list, &send_node_list, &vote) != 0) {
406 qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting.");
407
408 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_QUORUM_NOTIFY_ERR;
409 net_instance->schedule_disconnect = 1;
410
411 return (0);
412 } else {
413 qdevice_log(LOG_DEBUG, "Algorithm decided to %s list and result vote is %s",
414 (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote));
415 }
416
417 if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
418 qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_quorum_notify fatal error. "
419 " Can't update cast vote timer vote");
420 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
421 net_instance->schedule_disconnect = 1;
422
423 return (0);
424 }
425
426 if (send_node_list) {
427 if (qdevice_net_send_quorum_node_list(net_instance,
428 (quorate ? TLV_QUORATE_QUORATE : TLV_QUORATE_INQUORATE),
429 node_list_entries, node_list) != 0) {
430 /*
431 * Fatal error -> schedule disconnect
432 */
433 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
434 net_instance->schedule_disconnect = 1;
435
436 return (0);
437 }
438 }
439
440 return (0);
441 }
442
443 int
444 qdevice_model_net_votequorum_node_list_heuristics_notify(struct qdevice_instance *instance,
445 votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[],
446 enum qdevice_heuristics_exec_result heuristics_exec_result)
447 {
448 struct qdevice_net_instance *net_instance;
449 struct tlv_ring_id tlv_rid;
450 enum tlv_vote vote;
451 enum tlv_heuristics heuristics;
452 int send_node_list;
453
454 net_instance = instance->model_data;
455
456 qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id);
457 heuristics = qdevice_net_heuristics_exec_result_to_tlv(heuristics_exec_result);
458
459 if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
460 /*
461 * Nodelist changed, but connection to qnetd not initiated yet.
462 */
463 send_node_list = 0;
464
465 if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
466 vote = TLV_VOTE_NACK;
467 } else {
468 vote = TLV_VOTE_NO_CHANGE;
469 }
470 } else {
471 send_node_list = 1;
472 vote = TLV_VOTE_WAIT_FOR_REPLY;
473 }
474
475 if (qdevice_net_algorithm_votequorum_node_list_heuristics_notify(net_instance, &tlv_rid,
476 node_list_entries, node_list, &send_node_list, &vote, &heuristics) != 0) {
477 qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting.");
478
479 net_instance->disconnect_reason =
480 QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_HEURISTICS_NOTIFY_ERR;
481 net_instance->schedule_disconnect = 1;
482
483 return (0);
484 } else {
485 qdevice_log(LOG_DEBUG, "Algorithm decided to %s list, result vote is %s and heuristics is %s",
486 (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote),
487 tlv_heuristics_to_str(heuristics));
488 }
489
490 if (send_node_list) {
491 if (qdevice_net_send_membership_node_list(net_instance, &tlv_rid,
492 node_list_entries, node_list, heuristics) != 0) {
493 /*
494 * Fatal error -> schedule disconnect
495 */
496 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
497 net_instance->schedule_disconnect = 1;
498
499 return (0);
500 }
501 }
502
503 /*
504 * Unpause cast vote timer
505 */
506 qdevice_net_cast_vote_timer_set_paused(net_instance, 0);
507
508 if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
509 qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error "
510 "Can't update cast vote timer");
511 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
512 net_instance->schedule_disconnect = 1;
513
514 return (0);
515 }
516
517 net_instance->latest_vq_heuristics_result = heuristics;
518 net_instance->latest_heuristics_result = heuristics;
519
520 if (qdevice_net_heuristics_schedule_timer(net_instance) != 0) {
521 return (0);
522 }
523
524 return (0);
525 }
526
527 int
528 qdevice_model_net_votequorum_node_list_notify(struct qdevice_instance *instance,
529 votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[])
530 {
531 struct qdevice_net_instance *net_instance;
532 struct tlv_ring_id tlv_rid;
533 enum tlv_vote vote;
534 int pause_cast_vote_timer;
535
536 net_instance = instance->model_data;
537
538 /*
539 * Stop regular heuristics till qdevice_model_net_votequorum_node_list_heuristics_notify
540 * is called
541 */
542 if (qdevice_net_heuristics_stop_timer(net_instance) != 0) {
543 return (0);
544 }
545
546 pause_cast_vote_timer = 1;
547 vote = TLV_VOTE_NO_CHANGE;
548
549 if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS &&
550 net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
551 /*
552 * Nodelist changed and vote timer still votes ACK. It's needed to start voting
553 * NACK.
554 */
555 if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
556 vote = TLV_VOTE_NACK;
557 }
558 }
559
560 qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id);
561
562 if (qdevice_net_algorithm_votequorum_node_list_notify(net_instance, &tlv_rid,
563 node_list_entries, node_list, &pause_cast_vote_timer, &vote) != 0) {
564 qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting.");
565
566 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_NOTIFY_ERR;
567 net_instance->schedule_disconnect = 1;
568
569 return (0);
570 } else {
571 qdevice_log(LOG_DEBUG, "Algorithm decided to %s cast vote timer and result vote is %s ",
572 (pause_cast_vote_timer ? "pause" : "not pause"), tlv_vote_to_str(vote));
573 }
574
575 if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
576 qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error "
577 "Can't update cast vote timer");
578 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
579 net_instance->schedule_disconnect = 1;
580
581 return (0);
582 }
583
584 qdevice_net_cast_vote_timer_set_paused(net_instance, pause_cast_vote_timer);
585
586 return (0);
587 }
588
589 int
590 qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance,
591 uint32_t expected_votes)
592 {
593 struct qdevice_net_instance *net_instance;
594 enum tlv_vote vote;
595
596 net_instance = instance->model_data;
597
598 qdevice_log(LOG_DEBUG, "qdevice_model_net_votequorum_expected_votes_notify"
599 " (expected votes old=%"PRIu32" / new=%"PRIu32")",
600 net_instance->qdevice_instance_ptr->vq_expected_votes, expected_votes);
601
602 vote = TLV_VOTE_NO_CHANGE;
603
604 if (qdevice_net_algorithm_votequorum_expected_votes_notify(net_instance, expected_votes,
605 &vote) != 0) {
606 qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting.");
607
608 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_EXPECTED_VOTES_NOTIFY_ERR;
609 net_instance->schedule_disconnect = 1;
610
611 return (0);
612 } else {
613 qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(vote));
614 }
615
616 if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
617 qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_expected_votes_notify fatal error. "
618 " Can't update cast vote timer vote");
619 net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
620 net_instance->schedule_disconnect = 1;
621
622 return (0);
623 }
624
625 return (0);
626 }
627
628 int
629 qdevice_model_net_cmap_changed(struct qdevice_instance *instance,
630 const struct qdevice_cmap_change_events *events)
631 {
632 struct qdevice_net_instance *net_instance;
633 enum qdevice_heuristics_mode active_heuristics_mode;
634 int heuristics_enabled;
635
636 net_instance = instance->model_data;
637
638 if (events->heuristics) {
639 active_heuristics_mode = instance->heuristics_instance.mode;
640 heuristics_enabled = (active_heuristics_mode == QDEVICE_HEURISTICS_MODE_ENABLED ||
641 active_heuristics_mode == QDEVICE_HEURISTICS_MODE_SYNC);
642
643 if (net_instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS &&
644 !net_instance->server_supports_heuristics && heuristics_enabled) {
645 qdevice_log(LOG_ERR, "Heuristics are enabled but not supported by the server");
646
647 net_instance->disconnect_reason =
648 QDEVICE_NET_DISCONNECT_REASON_SERVER_DOESNT_SUPPORT_REQUIRED_OPT;
649
650 net_instance->schedule_disconnect = 1;
651
652 return (0);
653 }
654
655 if (qdevice_net_heuristics_schedule_timer(net_instance) != 0) {
656 return (0);
657 }
658 }
659
660 return (0);
661 }
662
663 int
664 qdevice_model_net_ipc_cmd_status(struct qdevice_instance *instance,
665 struct dynar *outbuf, int verbose)
666 {
667 struct qdevice_net_instance *net_instance;
668
669 net_instance = instance->model_data;
670
671 if (!qdevice_net_ipc_cmd_status(net_instance, outbuf, verbose)) {
672 return (-1);
673 }
674
675 return (0);
676 }
677
678 static struct qdevice_model qdevice_model_net = {
679 .name = "net",
680 .init = qdevice_model_net_init,
681 .destroy = qdevice_model_net_destroy,
682 .run = qdevice_model_net_run,
683 .get_config_node_list_failed = qdevice_model_net_get_config_node_list_failed,
684 .config_node_list_changed = qdevice_model_net_config_node_list_changed,
685 .votequorum_quorum_notify = qdevice_model_net_votequorum_quorum_notify,
686 .votequorum_node_list_notify = qdevice_model_net_votequorum_node_list_notify,
687 .votequorum_node_list_heuristics_notify = qdevice_model_net_votequorum_node_list_heuristics_notify,
688 .votequorum_expected_votes_notify = qdevice_model_net_votequorum_expected_votes_notify,
689 .cmap_changed = qdevice_model_net_cmap_changed,
690 .ipc_cmd_status = qdevice_model_net_ipc_cmd_status,
691 };
692
693 int
694 qdevice_model_net_register(void)
695 {
696 return (qdevice_model_register(QDEVICE_MODEL_TYPE_NET, &qdevice_model_net));
697 }