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