]> git.proxmox.com Git - mirror_corosync-qdevice.git/blame - qdevices/qdevice-cmap.c
qdevice-cmap: Load clear node high bit only once
[mirror_corosync-qdevice.git] / qdevices / qdevice-cmap.c
CommitLineData
9a1955a7 1/*
406b689d 2 * Copyright (c) 2015-2020 Red Hat, Inc.
9a1955a7
JF
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#include <sys/socket.h>
37
38#include <err.h>
39#include <poll.h>
40#include <stdio.h>
41#include <stdint.h>
42#include <netdb.h>
43
313d42d1 44#include "log.h"
9a1955a7
JF
45#include "qdevice-config.h"
46#include "qdevice-cmap.h"
47#include "qdevice-log.h"
313d42d1 48#include "log-common.h"
9a1955a7
JF
49#include "qdevice-model.h"
50#include "utils.h"
51
52static uint32_t
e4bdad3c 53qdevice_cmap_autogenerate_node_id(const char *addr, int clear_node_high_bit)
9a1955a7
JF
54{
55 struct addrinfo *ainfo;
56 struct addrinfo ahints;
57 int ret, i;
58
59 memset(&ahints, 0, sizeof(ahints));
60 ahints.ai_socktype = SOCK_DGRAM;
61 ahints.ai_protocol = IPPROTO_UDP;
62 /*
63 * Hardcoded AF_INET because autogenerated nodeid is valid only for ipv4
64 */
65 ahints.ai_family = AF_INET;
66
67 ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
68 if (ret != 0)
69 return (0);
70
71 if (ainfo->ai_family != AF_INET) {
72
73 freeaddrinfo(ainfo);
74
75 return (0);
76 }
77
37fda20a 78 memcpy(&i, &(((struct sockaddr_in *)((void *)ainfo->ai_addr))->sin_addr), sizeof(struct in_addr));
9a1955a7
JF
79 freeaddrinfo(ainfo);
80
81 ret = htonl(i);
82
e4bdad3c 83 if (clear_node_high_bit) {
9a1955a7
JF
84 ret &= 0x7FFFFFFF;
85 }
86
87 return (ret);
88}
89
90int
91qdevice_cmap_get_nodelist(cmap_handle_t cmap_handle, struct node_list *list)
92{
93 cs_error_t cs_err;
94 cmap_iter_handle_t iter_handle;
95 char key_name[CMAP_KEYNAME_MAXLEN + 1];
96 char tmp_key[CMAP_KEYNAME_MAXLEN + 1];
97 int res;
98 int ret_value;
99 unsigned int node_pos;
100 uint32_t node_id;
101 uint32_t data_center_id;
102 char *tmp_str;
103 char *addr0_str;
e4bdad3c 104 int clear_node_high_bit;
9a1955a7
JF
105
106 ret_value = 0;
107
108 node_list_init(list);
109
154ded5d
JF
110 /*
111 * Fill clear high node bit
112 */
113 clear_node_high_bit = 0;
114
115 if (cmap_get_string(cmap_handle, "totem.clear_node_high_bit", &tmp_str) == CS_OK) {
116 if (strcmp (tmp_str, "yes") == 0) {
117 clear_node_high_bit = 1;
118 }
119
120 free(tmp_str);
121 }
122
123 /*
124 * Iterate nodelist
125 */
9a1955a7
JF
126 cs_err = cmap_iter_init(cmap_handle, "nodelist.node.", &iter_handle);
127 if (cs_err != CS_OK) {
128 return (-1);
129 }
130
131 while ((cs_err = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL)) == CS_OK) {
132 res = sscanf(key_name, "nodelist.node.%u.%s", &node_pos, tmp_key);
133 if (res != 2) {
134 continue;
135 }
136
137 if (strcmp(tmp_key, "ring0_addr") != 0) {
138 continue;
139 }
140
141 snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
142 cs_err = cmap_get_uint32(cmap_handle, tmp_key, &node_id);
143
144 if (cs_err == CS_ERR_NOT_EXIST) {
145 /*
146 * Nodeid doesn't exists -> autogenerate node id
147 */
9a1955a7
JF
148 if (cmap_get_string(cmap_handle, key_name, &addr0_str) != CS_OK) {
149 return (-1);
150 }
151
152 node_id = qdevice_cmap_autogenerate_node_id(addr0_str,
e4bdad3c 153 clear_node_high_bit);
9a1955a7
JF
154
155 free(addr0_str);
156 } else if (cs_err != CS_OK) {
157 ret_value = -1;
158
159 goto iter_finalize;
160 }
161
162 snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.datacenterid", node_pos);
163 if (cmap_get_uint32(cmap_handle, tmp_key, &data_center_id) != CS_OK) {
164 data_center_id = 0;
165 }
166
167 if (node_list_add(list, node_id, data_center_id, TLV_NODE_STATE_NOT_SET) == NULL) {
168 ret_value = -1;
169
170 goto iter_finalize;
171 }
172 }
173
174iter_finalize:
175 cmap_iter_finalize(cmap_handle, iter_handle);
176
177 if (ret_value != 0) {
178 node_list_free(list);
179 }
180
181 return (ret_value);
182}
183
184int
185qdevice_cmap_get_config_version(cmap_handle_t cmap_handle, uint64_t *config_version)
186{
187 int res;
188
189 if (cmap_get_uint64(cmap_handle, "totem.config_version", config_version) == CS_OK) {
190 res = 0;
191 } else {
192 *config_version = 0;
193 res = -1;
194 }
195
196 return (res);
197}
198
199int
200qdevice_cmap_store_config_node_list(struct qdevice_instance *instance)
201{
202 int res;
203
204 node_list_free(&instance->config_node_list);
205
206 if (qdevice_cmap_get_nodelist(instance->cmap_handle, &instance->config_node_list) != 0) {
c8d19612 207 log(LOG_ERR, "Can't get configuration node list.");
9a1955a7
JF
208
209 return (-1);
210 }
211
212 res = qdevice_cmap_get_config_version(instance->cmap_handle, &instance->config_node_list_version);
213 instance->config_node_list_version_set = (res == 0);
214
215 return (0);
216}
217
218void
219qdevice_cmap_init(struct qdevice_instance *instance)
220{
221 cs_error_t res;
222 int no_retries;
223
224 no_retries = 0;
225
226 while ((res = cmap_initialize(&instance->cmap_handle)) == CS_ERR_TRY_AGAIN &&
227 no_retries++ < instance->advanced_settings->max_cs_try_again) {
228 (void)poll(NULL, 0, 1000);
229 }
230
231 if (res != CS_OK) {
406b689d 232 errx(EXIT_FAILURE, "Failed to initialize the cmap API. Error %s", cs_strerror(res));
9a1955a7
JF
233 }
234
235 if ((res = cmap_context_set(instance->cmap_handle, (void *)instance)) != CS_OK) {
406b689d 236 errx(EXIT_FAILURE, "Can't set cmap context. Error %s", cs_strerror(res));
9a1955a7
JF
237 }
238
239 cmap_fd_get(instance->cmap_handle, &instance->cmap_poll_fd);
240}
241
242static void
243qdevice_cmap_node_list_event(struct qdevice_instance *instance)
244{
245 struct node_list nlist;
246 int config_version_set;
247 uint64_t config_version;
248
c8d19612 249 log(LOG_DEBUG, "Node list configuration possibly changed");
9a1955a7 250 if (qdevice_cmap_get_nodelist(instance->cmap_handle, &nlist) != 0) {
c8d19612 251 log(LOG_ERR, "Can't get configuration node list.");
9a1955a7
JF
252
253 if (qdevice_model_get_config_node_list_failed(instance) != 0) {
c8d19612 254 log(LOG_DEBUG, "qdevice_model_get_config_node_list_failed returned error -> exit");
406b689d 255 exit(EXIT_FAILURE);
9a1955a7
JF
256 }
257
258 return ;
259 }
260
261 config_version_set = (qdevice_cmap_get_config_version(instance->cmap_handle,
262 &config_version) == 0);
263
264 if (node_list_eq(&instance->config_node_list, &nlist)) {
265 return ;
266 }
267
c8d19612 268 log(LOG_DEBUG, "Node list changed");
9a1955a7 269 if (config_version_set) {
c8d19612 270 log(LOG_DEBUG, " config_version = "UTILS_PRI_CONFIG_VERSION, config_version);
9a1955a7 271 }
313d42d1 272 log_common_debug_dump_node_list(&nlist);
9a1955a7
JF
273
274 if (qdevice_model_config_node_list_changed(instance, &nlist,
275 config_version_set, config_version) != 0) {
c8d19612 276 log(LOG_DEBUG, "qdevice_model_config_node_list_changed returned error -> exit");
406b689d 277 exit(EXIT_FAILURE);
9a1955a7
JF
278 }
279
280 node_list_free(&instance->config_node_list);
281 if (node_list_clone(&instance->config_node_list, &nlist) != 0) {
c8d19612 282 log(LOG_ERR, "Can't allocate instance->config_node_list clone");
9a1955a7
JF
283
284 node_list_free(&nlist);
285
286 if (qdevice_model_get_config_node_list_failed(instance) != 0) {
c8d19612 287 log(LOG_DEBUG, "qdevice_model_get_config_node_list_failed returned error -> exit");
406b689d 288 exit(EXIT_FAILURE);
9a1955a7
JF
289 }
290
291 return ;
292 }
293
294 instance->config_node_list_version_set = config_version_set;
295
296 if (config_version_set) {
297 instance->config_node_list_version = config_version;
298 }
299}
300
301static void
302qdevice_cmap_logging_event(struct qdevice_instance *instance)
303{
304
c8d19612 305 log(LOG_DEBUG, "Logging configuration possibly changed");
9a1955a7
JF
306 qdevice_log_configure(instance);
307}
308
309static void
310qdevice_cmap_heuristics_event(struct qdevice_instance *instance)
311{
312
c8d19612 313 log(LOG_DEBUG, "Heuristics configuration possibly changed");
9a1955a7 314 if (qdevice_instance_configure_from_cmap_heuristics(instance) != 0) {
c8d19612 315 log(LOG_DEBUG, "qdevice_instance_configure_from_cmap_heuristics returned error -> exit");
406b689d 316 exit(EXIT_FAILURE);
9a1955a7
JF
317 }
318}
319
320static void
321qdevice_cmap_reload_cb(cmap_handle_t cmap_handle, cmap_track_handle_t cmap_track_handle,
322 int32_t event, const char *key_name,
323 struct cmap_notify_value new_value, struct cmap_notify_value old_value,
324 void *user_data)
325{
326 cs_error_t cs_res;
327 uint8_t reload;
328 struct qdevice_instance *instance;
329 const char *node_list_prefix_str;
330 const char *logging_prefix_str;
331 const char *heuristics_prefix_str;
332 struct qdevice_cmap_change_events events;
333
334 memset(&events, 0, sizeof(events));
335 node_list_prefix_str = "nodelist.";
336 logging_prefix_str = "logging.";
337 heuristics_prefix_str = "quorum.device.heuristics.";
338
339 if (cmap_context_get(cmap_handle, (const void **)&instance) != CS_OK) {
c8d19612 340 log(LOG_ERR, "Fatal error. Can't get cmap context");
406b689d 341 exit(EXIT_FAILURE);
9a1955a7
JF
342 }
343
344 /*
345 * Wait for full reload
346 */
347 if (strcmp(key_name, "config.totemconfig_reload_in_progress") == 0 &&
348 new_value.type == CMAP_VALUETYPE_UINT8 && new_value.len == sizeof(reload)) {
349 reload = 1;
350 if (memcmp(new_value.data, &reload, sizeof(reload)) == 0) {
351 /*
352 * Ignore nodelist changes
353 */
354 instance->cmap_reload_in_progress = 1;
355 return ;
356 } else {
357 instance->cmap_reload_in_progress = 0;
358 events.node_list = 1;
359 events.logging = 1;
360 events.heuristics = 1;
361 }
362 }
363
364 if (instance->cmap_reload_in_progress) {
365 return ;
366 }
367
368 if (((cs_res = cmap_get_uint8(cmap_handle, "config.totemconfig_reload_in_progress",
369 &reload)) == CS_OK) && reload == 1) {
370 return ;
371 }
372
373 if (strncmp(key_name, node_list_prefix_str, strlen(node_list_prefix_str)) == 0) {
374 events.node_list = 1;
375 }
376
377 if (strncmp(key_name, logging_prefix_str, strlen(logging_prefix_str)) == 0) {
378 events.logging = 1;
379 }
380
381 if (strncmp(key_name, heuristics_prefix_str, strlen(heuristics_prefix_str)) == 0) {
382 events.heuristics = 1;
383 }
384
385 if (events.logging) {
386 qdevice_cmap_logging_event(instance);
387 }
388
389 if (events.node_list) {
390 qdevice_cmap_node_list_event(instance);
391 }
392
393 if (events.heuristics) {
394 qdevice_cmap_heuristics_event(instance);
395 }
396
397 /*
398 * Inform model about change
399 */
400 if (qdevice_model_cmap_changed(instance, &events) != 0) {
c8d19612 401 log(LOG_DEBUG, "qdevice_model_cmap_changed returned error -> exit");
406b689d 402 exit(EXIT_FAILURE);
9a1955a7
JF
403 }
404}
405
406int
407qdevice_cmap_add_track(struct qdevice_instance *instance)
408{
409 cs_error_t res;
410
411 res = cmap_track_add(instance->cmap_handle, "config.totemconfig_reload_in_progress",
412 CMAP_TRACK_ADD | CMAP_TRACK_MODIFY, qdevice_cmap_reload_cb,
413 NULL, &instance->cmap_reload_track_handle);
414
415 if (res != CS_OK) {
c8d19612 416 log(LOG_ERR, "Can't initialize cmap totemconfig_reload_in_progress tracking");
9a1955a7
JF
417 return (-1);
418 }
419
420 res = cmap_track_add(instance->cmap_handle, "nodelist.",
421 CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
422 qdevice_cmap_reload_cb,
423 NULL, &instance->cmap_nodelist_track_handle);
424
425 if (res != CS_OK) {
c8d19612 426 log(LOG_ERR, "Can't initialize cmap nodelist tracking");
9a1955a7
JF
427 return (-1);
428 }
429
430 res = cmap_track_add(instance->cmap_handle, "logging.",
431 CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
432 qdevice_cmap_reload_cb,
433 NULL, &instance->cmap_logging_track_handle);
434
435 if (res != CS_OK) {
c8d19612 436 log(LOG_ERR, "Can't initialize logging tracking");
9a1955a7
JF
437 return (-1);
438 }
439
440 res = cmap_track_add(instance->cmap_handle, "quorum.device.heuristics.",
441 CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
442 qdevice_cmap_reload_cb,
443 NULL, &instance->cmap_heuristics_track_handle);
444
445 if (res != CS_OK) {
c8d19612 446 log(LOG_ERR, "Can't initialize logging tracking");
9a1955a7
JF
447 return (-1);
448 }
449
450 return (0);
451}
452
453int
454qdevice_cmap_del_track(struct qdevice_instance *instance)
455{
456 cs_error_t res;
457
458 res = cmap_track_delete(instance->cmap_handle, instance->cmap_reload_track_handle);
459 if (res != CS_OK) {
c8d19612 460 log(LOG_WARNING, "Can't delete cmap totemconfig_reload_in_progress tracking");
9a1955a7
JF
461 }
462
463 res = cmap_track_delete(instance->cmap_handle, instance->cmap_nodelist_track_handle);
464 if (res != CS_OK) {
c8d19612 465 log(LOG_WARNING, "Can't delete cmap nodelist tracking");
9a1955a7
JF
466 }
467
468 res = cmap_track_delete(instance->cmap_handle, instance->cmap_logging_track_handle);
469 if (res != CS_OK) {
c8d19612 470 log(LOG_WARNING, "Can't delete cmap logging tracking");
9a1955a7
JF
471 }
472
473 res = cmap_track_delete(instance->cmap_handle, instance->cmap_heuristics_track_handle);
474 if (res != CS_OK) {
c8d19612 475 log(LOG_WARNING, "Can't delete cmap heuristics tracking");
9a1955a7
JF
476 }
477
478 return (0);
479}
480
481void
482qdevice_cmap_destroy(struct qdevice_instance *instance)
483{
484 cs_error_t res;
485
486 res = cmap_finalize(instance->cmap_handle);
487
488 if (res != CS_OK) {
c8d19612 489 log(LOG_WARNING, "Can't finalize cmap. Error %s", cs_strerror(res));
9a1955a7
JF
490 }
491}
492
493int
494qdevice_cmap_dispatch(struct qdevice_instance *instance)
495{
496 cs_error_t res;
497
498 /*
499 * dispatch can block if corosync is during sync phase
500 */
501 if (instance->sync_in_progress) {
502 return (0);
503 }
504
505 res = cmap_dispatch(instance->cmap_handle, CS_DISPATCH_ALL);
506
507 if (res != CS_OK && res != CS_ERR_TRY_AGAIN) {
c8d19612 508 log(LOG_ERR, "Can't dispatch cmap messages");
9a1955a7
JF
509
510 return (-1);
511 }
512
513 return (0);
514}