corosync-notifyd.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395
  1. /*
  2. * Copyright (c) 2011-2017 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Angus Salkeld <asalkeld@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 MontaVista Software, 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. #include <config.h>
  35. #include <sys/select.h>
  36. #include <sys/socket.h>
  37. #include <sys/un.h>
  38. #include <sys/types.h>
  39. #include <netdb.h>
  40. #include <arpa/inet.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <errno.h>
  44. #include <unistd.h>
  45. #include <string.h>
  46. #include <ctype.h>
  47. #include <poll.h>
  48. #include <signal.h>
  49. #include <qb/qbdefs.h>
  50. #include <qb/qbloop.h>
  51. #include <qb/qbmap.h>
  52. #include <qb/qblog.h>
  53. #include <corosync/corotypes.h>
  54. #include <corosync/cfg.h>
  55. #include <corosync/quorum.h>
  56. #include <corosync/cmap.h>
  57. #ifdef HAVE_LIBSYSTEMD
  58. #include <systemd/sd-daemon.h>
  59. #endif
  60. /*
  61. * generic declarations
  62. */
  63. enum {
  64. CS_NTF_LOG,
  65. CS_NTF_STDOUT,
  66. CS_NTF_SNMP,
  67. CS_NTF_DBUS,
  68. CS_NTF_FG,
  69. CS_NTF_MAX,
  70. };
  71. static int conf[CS_NTF_MAX];
  72. static int exit_code = 0;
  73. static int32_t _cs_is_quorate = 0;
  74. typedef void (*node_membership_fn_t)(char *nodename, uint32_t nodeid, char *state, char* ip);
  75. typedef void (*node_quorum_fn_t)(char *nodename, uint32_t nodeid, const char *state);
  76. typedef void (*application_connection_fn_t)(char *nodename, uint32_t nodeid, char *app_name, const char *state);
  77. typedef void (*link_faulty_fn_t)(char *nodename, uint32_t local_nodeid, uint32_t nodeid, uint32_t iface_no, const char *state);
  78. struct notify_callbacks {
  79. node_membership_fn_t node_membership_fn;
  80. node_quorum_fn_t node_quorum_fn;
  81. application_connection_fn_t application_connection_fn;
  82. link_faulty_fn_t link_faulty_fn;
  83. };
  84. struct track_item {
  85. char key_name[CMAP_KEYNAME_MAXLEN + 1];
  86. cmap_track_handle_t track_handle;
  87. };
  88. #define MAX_NOTIFIERS 5
  89. static int num_notifiers = 0;
  90. static struct notify_callbacks notifiers[MAX_NOTIFIERS];
  91. /*
  92. * Global variable with local nodeid
  93. */
  94. static uint32_t g_local_nodeid = 0;
  95. static char local_nodename[CS_MAX_NAME_LENGTH];
  96. static qb_loop_t *main_loop;
  97. static quorum_handle_t quorum_handle;
  98. static qb_map_t *tracker_map;
  99. static void _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip);
  100. static void _cs_node_quorum_event(const char *state);
  101. static void _cs_application_connection_event(char *app_name, const char *state);
  102. static void _cs_link_faulty_event(uint32_t nodeid, uint32_t iface_no, const char *state);
  103. #ifdef HAVE_DBUS
  104. #include <dbus/dbus.h>
  105. /*
  106. * dbus
  107. */
  108. #define DBUS_CS_NAME "org.corosync"
  109. #define DBUS_CS_IFACE "org.corosync"
  110. #define DBUS_CS_PATH "/org/corosync"
  111. static DBusConnection *db = NULL;
  112. static char _err[512];
  113. static int err_set = 0;
  114. static void _cs_dbus_init(void);
  115. #endif /* HAVE_DBUS */
  116. #ifdef ENABLE_SNMP
  117. #include <net-snmp/net-snmp-config.h>
  118. #include <net-snmp/snmpv3_api.h>
  119. #include <net-snmp/agent/agent_trap.h>
  120. #include <net-snmp/library/mib.h>
  121. #include <net-snmp/library/snmp_api.h>
  122. #include <net-snmp/library/snmp_client.h>
  123. #include <net-snmp/library/snmp_debug.h>
  124. enum snmp_node_status {
  125. SNMP_NODE_STATUS_UNKNOWN = 0,
  126. SNMP_NODE_STATUS_JOINED = 1,
  127. SNMP_NODE_STATUS_LEFT = 2
  128. };
  129. #define SNMP_OID_COROSYNC "1.3.6.1.4.1.35488"
  130. #define SNMP_OID_OBJECT_ROOT SNMP_OID_COROSYNC ".1"
  131. #define SNMP_OID_OBJECT_NODE_NAME SNMP_OID_OBJECT_ROOT ".1"
  132. #define SNMP_OID_OBJECT_NODE_ID SNMP_OID_OBJECT_ROOT ".2"
  133. #define SNMP_OID_OBJECT_NODE_STATUS SNMP_OID_OBJECT_ROOT ".3"
  134. #define SNMP_OID_OBJECT_NODE_ADDR SNMP_OID_OBJECT_ROOT ".4"
  135. #define SNMP_OID_OBJECT_LOCAL_NODE_ID SNMP_OID_OBJECT_ROOT ".5"
  136. #define SNMP_OID_OBJECT_RINGSEQ SNMP_OID_OBJECT_ROOT ".20"
  137. #define SNMP_OID_OBJECT_QUORUM SNMP_OID_OBJECT_ROOT ".21"
  138. #define SNMP_OID_OBJECT_APP_NAME SNMP_OID_OBJECT_ROOT ".40"
  139. #define SNMP_OID_OBJECT_APP_STATUS SNMP_OID_OBJECT_ROOT ".41"
  140. #define SNMP_OID_OBJECT_LINK_IFACE_NO SNMP_OID_OBJECT_ROOT ".60"
  141. #define SNMP_OID_OBJECT_LINK_STATUS SNMP_OID_OBJECT_ROOT ".61"
  142. #define SNMP_OID_TRAPS_ROOT SNMP_OID_COROSYNC ".0"
  143. #define SNMP_OID_TRAPS_NODE SNMP_OID_TRAPS_ROOT ".1"
  144. #define SNMP_OID_TRAPS_QUORUM SNMP_OID_TRAPS_ROOT ".2"
  145. #define SNMP_OID_TRAPS_APP SNMP_OID_TRAPS_ROOT ".3"
  146. #define SNMP_OID_TRAPS_LINK SNMP_OID_TRAPS_ROOT ".4"
  147. #define CS_TIMESTAMP_STR_LEN 20
  148. static const char *local_host = "localhost";
  149. #endif /* ENABLE_SNMP */
  150. static char snmp_manager_buf[CS_MAX_NAME_LENGTH];
  151. static char *snmp_manager = NULL;
  152. static char snmp_community_buf[CS_MAX_NAME_LENGTH];
  153. static char *snmp_community = NULL;
  154. #define CMAP_MAX_RETRIES 10
  155. /*
  156. * cmap
  157. */
  158. static cmap_handle_t cmap_handle;
  159. static cmap_handle_t stats_handle;
  160. static cmap_track_handle_t cmap_track_handle_runtime_members_key_changed;
  161. static cmap_track_handle_t cmap_track_handle_stats_ipcs_key_changed;
  162. static cmap_track_handle_t cmap_track_handle_stats_knet_key_changed;
  163. static int32_t _cs_ip_to_hostname(char* ip, char* name_out)
  164. {
  165. struct sockaddr_in sa;
  166. int rc;
  167. if (strchr(ip, ':') == NULL) {
  168. sa.sin_family = AF_INET;
  169. } else {
  170. sa.sin_family = AF_INET6;
  171. }
  172. rc = inet_pton(sa.sin_family, ip, &sa.sin_addr);
  173. if (rc == 0) {
  174. return -EINVAL;
  175. }
  176. rc = getnameinfo((struct sockaddr*)&sa, sizeof(sa),
  177. name_out, CS_MAX_NAME_LENGTH, NULL, 0, 0);
  178. if (rc != 0) {
  179. qb_log(LOG_ERR, "error looking up %s : %s", ip, gai_strerror(rc));
  180. return -EINVAL;
  181. }
  182. return 0;
  183. }
  184. static void _cs_cmap_members_key_changed (
  185. cmap_handle_t cmap_handle_c,
  186. cmap_track_handle_t cmap_track_handle,
  187. int32_t event,
  188. const char *key_name,
  189. struct cmap_notify_value new_value,
  190. struct cmap_notify_value old_value,
  191. void *user_data)
  192. {
  193. char nodename[CS_MAX_NAME_LENGTH];
  194. char* open_bracket = NULL;
  195. char* close_bracket = NULL;
  196. int res;
  197. uint32_t nodeid;
  198. char *ip_str;
  199. char tmp_key[CMAP_KEYNAME_MAXLEN];
  200. cs_error_t err;
  201. int no_retries;
  202. if (event != CMAP_TRACK_ADD && event != CMAP_TRACK_MODIFY) {
  203. return ;
  204. }
  205. if (NULL == key_name) {
  206. qb_log(LOG_ERR, "key_name: nil");
  207. }
  208. res = sscanf(key_name, "runtime.members.%u.%s", &nodeid, tmp_key);
  209. if (res != 2)
  210. return ;
  211. if (strcmp(tmp_key, "status") != 0) {
  212. return ;
  213. }
  214. res = snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "runtime.members.%u.ip", nodeid);
  215. if (res <= 0 || res >= CMAP_KEYNAME_MAXLEN) {
  216. qb_log(LOG_ERR, "temp_key: failed, res: %d, nodeid: %u", res, nodeid);
  217. return ;
  218. }
  219. no_retries = 0;
  220. while ((err = cmap_get_string(cmap_handle, tmp_key, &ip_str)) == CS_ERR_TRY_AGAIN &&
  221. no_retries++ < CMAP_MAX_RETRIES) {
  222. sleep(1);
  223. }
  224. if (err != CS_OK) {
  225. return ;
  226. }
  227. /*
  228. * We want the ip out of: "r(0) ip(192.168.100.92)"
  229. */
  230. open_bracket = strrchr(ip_str, '(');
  231. if (NULL == open_bracket) {
  232. qb_log(LOG_ERR, "ip_str: %s", ip_str);
  233. free(ip_str);
  234. return ;
  235. }
  236. open_bracket++;
  237. close_bracket = strchr(open_bracket, ')');
  238. if (NULL == close_bracket) {
  239. qb_log(LOG_ERR, "open_bracket: %s", open_bracket);
  240. free(ip_str);
  241. return ;
  242. }
  243. *close_bracket = '\0';
  244. res = _cs_ip_to_hostname(open_bracket, nodename);
  245. if (res) {
  246. strncpy(nodename, open_bracket, CS_MAX_NAME_LENGTH-1);
  247. }
  248. _cs_node_membership_event(nodename, nodeid, (char *)new_value.data, open_bracket);
  249. free(ip_str);
  250. }
  251. static void _cs_cmap_connections_key_changed (
  252. cmap_handle_t cmap_handle_c,
  253. cmap_track_handle_t cmap_track_handle,
  254. int32_t event,
  255. const char *key_name,
  256. struct cmap_notify_value new_value,
  257. struct cmap_notify_value old_value,
  258. void *user_data)
  259. {
  260. char obj_name[CS_MAX_NAME_LENGTH];
  261. char conn_str[CMAP_KEYNAME_MAXLEN];
  262. char tmp_key[CMAP_KEYNAME_MAXLEN];
  263. int service, pid;
  264. int res;
  265. res = sscanf(key_name, "stats.ipcs.service%d.%d.%[^.].%s", &service,&pid, conn_str, tmp_key);
  266. if (res != 4) {
  267. return ;
  268. }
  269. if (strcmp(tmp_key, "procname") != 0) {
  270. return ;
  271. }
  272. if (snprintf(obj_name, CS_MAX_NAME_LENGTH, "%s.%d.%s", conn_str, pid,
  273. (char*)new_value.data) >= CS_MAX_NAME_LENGTH) {
  274. /*
  275. * This should never happen
  276. */
  277. qb_log(LOG_ERR, "Can't snprintf obj_name");
  278. return ;
  279. }
  280. if (event == CMAP_TRACK_ADD) {
  281. _cs_application_connection_event(obj_name, "connected");
  282. }
  283. if (event == CMAP_TRACK_DELETE) {
  284. _cs_application_connection_event(obj_name, "disconnected");
  285. }
  286. }
  287. static void _cs_cmap_link_faulty_key_changed (
  288. cmap_handle_t cmap_handle_c,
  289. cmap_track_handle_t cmap_track_handle,
  290. int32_t event,
  291. const char *key_name,
  292. struct cmap_notify_value new_value,
  293. struct cmap_notify_value old_value,
  294. void *user_data)
  295. {
  296. uint32_t iface_no;
  297. uint32_t nodeid;
  298. int res;
  299. int no_retries;
  300. uint8_t connected;
  301. cs_error_t err;
  302. res = sscanf(key_name, "stats.knet.node%u.link%u.connected", &nodeid, &iface_no);
  303. if (res != 2) {
  304. return ;
  305. }
  306. no_retries = 0;
  307. while ((err = cmap_get_uint8(stats_handle, key_name, &connected)) == CS_ERR_TRY_AGAIN &&
  308. no_retries++ < CMAP_MAX_RETRIES) {
  309. sleep(1);
  310. }
  311. if (err != CS_OK) {
  312. return ;
  313. }
  314. if (connected) {
  315. _cs_link_faulty_event(nodeid, iface_no, "operational");
  316. } else {
  317. _cs_link_faulty_event(nodeid, iface_no, "disconnected");
  318. }
  319. }
  320. static void _cs_cmap_link_added_removed (
  321. cmap_handle_t cmap_handle_c,
  322. cmap_track_handle_t track_handle,
  323. int32_t event,
  324. const char *key_name,
  325. struct cmap_notify_value new_value,
  326. struct cmap_notify_value old_value,
  327. void *user_data)
  328. {
  329. struct track_item *track_item;
  330. /* Add/remove a tracker for a new/removed knet link */
  331. if (strstr(key_name, ".connected")) {
  332. if (event == CMAP_TRACK_ADD) {
  333. track_item = malloc(sizeof(struct track_item));
  334. if (!track_item) {
  335. return;
  336. }
  337. cmap_track_add(stats_handle, key_name, CMAP_TRACK_MODIFY, _cs_cmap_link_faulty_key_changed, NULL, &track_handle);
  338. strcpy(track_item->key_name, key_name);
  339. track_item->track_handle = track_handle;
  340. qb_map_put(tracker_map, track_item->key_name, track_item);
  341. } else {
  342. track_item = qb_map_get(tracker_map, key_name);
  343. if (track_item) {
  344. cmap_track_delete(stats_handle, track_item->track_handle);
  345. qb_map_rm(tracker_map, track_item->key_name);
  346. free(track_item);
  347. }
  348. }
  349. }
  350. }
  351. static int
  352. _cs_cmap_dispatch(int fd, int revents, void *data)
  353. {
  354. cs_error_t err;
  355. err = cmap_dispatch(*(cmap_handle_t *)data, CS_DISPATCH_ONE);
  356. if (err != CS_OK && err != CS_ERR_TRY_AGAIN && err != CS_ERR_TIMEOUT &&
  357. err != CS_ERR_QUEUE_FULL) {
  358. qb_log(LOG_ERR, "Could not dispatch cmap events. Error %u", err);
  359. qb_loop_stop(main_loop);
  360. exit_code = 1;
  361. return -1;
  362. }
  363. return 0;
  364. }
  365. static void _cs_quorum_notification(quorum_handle_t handle,
  366. uint32_t quorate, uint64_t ring_seq,
  367. uint32_t view_list_entries, uint32_t *view_list)
  368. {
  369. if (_cs_is_quorate == quorate) {
  370. return;
  371. }
  372. _cs_is_quorate = quorate;
  373. if (quorate) {
  374. _cs_node_quorum_event("quorate");
  375. } else {
  376. _cs_node_quorum_event("not quorate");
  377. }
  378. }
  379. static int
  380. _cs_quorum_dispatch(int fd, int revents, void *data)
  381. {
  382. cs_error_t err;
  383. err = quorum_dispatch(quorum_handle, CS_DISPATCH_ONE);
  384. if (err != CS_OK && err != CS_ERR_TRY_AGAIN && err != CS_ERR_TIMEOUT &&
  385. err != CS_ERR_QUEUE_FULL) {
  386. qb_log(LOG_ERR, "Could not dispatch quorum events. Error %u", err);
  387. qb_loop_stop(main_loop);
  388. exit_code = 1;
  389. return -1;
  390. }
  391. return 0;
  392. }
  393. static void
  394. _cs_quorum_init(void)
  395. {
  396. cs_error_t rc;
  397. uint32_t quorum_type;
  398. int fd;
  399. quorum_callbacks_t quorum_callbacks = {
  400. .quorum_notify_fn = _cs_quorum_notification,
  401. };
  402. rc = quorum_initialize (&quorum_handle, &quorum_callbacks,
  403. &quorum_type);
  404. if (rc != CS_OK) {
  405. qb_log(LOG_ERR, "Could not connect to corosync(quorum)");
  406. return;
  407. }
  408. quorum_fd_get(quorum_handle, &fd);
  409. qb_loop_poll_add(main_loop, QB_LOOP_MED, fd, POLLIN|POLLNVAL, NULL,
  410. _cs_quorum_dispatch);
  411. rc = quorum_trackstart(quorum_handle, CS_TRACK_CHANGES);
  412. if (rc != CS_OK) {
  413. qb_log(LOG_ERR, "Could not start tracking");
  414. return;
  415. }
  416. }
  417. static void
  418. _cs_quorum_finalize(void)
  419. {
  420. quorum_finalize (quorum_handle);
  421. }
  422. #ifdef HAVE_DBUS
  423. /*
  424. * dbus notifications
  425. */
  426. static void
  427. _cs_dbus_auto_flush(void)
  428. {
  429. dbus_connection_ref(db);
  430. while (dbus_connection_get_dispatch_status(db) == DBUS_DISPATCH_DATA_REMAINS) {
  431. dbus_connection_dispatch(db);
  432. }
  433. while (dbus_connection_has_messages_to_send(db)) {
  434. dbus_connection_flush(db);
  435. }
  436. dbus_connection_unref(db);
  437. }
  438. static void
  439. _cs_dbus_release(void)
  440. {
  441. DBusError err;
  442. if (!db)
  443. return;
  444. dbus_error_init(&err);
  445. dbus_bus_release_name(db, DBUS_CS_NAME, &err);
  446. dbus_error_free(&err);
  447. dbus_connection_unref(db);
  448. db = NULL;
  449. }
  450. static void
  451. _cs_dbus_node_quorum_event(char *nodename, uint32_t nodeid, const char *state)
  452. {
  453. DBusMessage *msg = NULL;
  454. if (err_set) {
  455. qb_log(LOG_ERR, "%s", _err);
  456. err_set = 0;
  457. }
  458. if (!db) {
  459. goto out_free;
  460. }
  461. if (dbus_connection_get_is_connected(db) != TRUE) {
  462. err_set = 1;
  463. snprintf(_err, sizeof(_err), "DBus connection lost");
  464. _cs_dbus_release();
  465. goto out_unlock;
  466. }
  467. _cs_dbus_auto_flush();
  468. if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
  469. DBUS_CS_IFACE,
  470. "QuorumStateChange"))) {
  471. qb_log(LOG_ERR, "error creating dbus signal");
  472. goto out_unlock;
  473. }
  474. if (!dbus_message_append_args(msg,
  475. DBUS_TYPE_STRING, &nodename,
  476. DBUS_TYPE_UINT32, &nodeid,
  477. DBUS_TYPE_STRING, &state,
  478. DBUS_TYPE_INVALID)) {
  479. qb_log(LOG_ERR, "error adding args to quorum signal");
  480. goto out_unlock;
  481. }
  482. dbus_connection_send(db, msg, NULL);
  483. out_unlock:
  484. if (msg) {
  485. dbus_message_unref(msg);
  486. }
  487. out_free:
  488. return;
  489. }
  490. static void
  491. _cs_dbus_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
  492. {
  493. DBusMessage *msg = NULL;
  494. if (err_set) {
  495. qb_log(LOG_ERR, "%s", _err);
  496. err_set = 0;
  497. }
  498. if (!db) {
  499. goto out_free;
  500. }
  501. if (dbus_connection_get_is_connected(db) != TRUE) {
  502. err_set = 1;
  503. snprintf(_err, sizeof(_err), "DBus connection lost");
  504. _cs_dbus_release();
  505. goto out_unlock;
  506. }
  507. _cs_dbus_auto_flush();
  508. if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
  509. DBUS_CS_IFACE,
  510. "NodeStateChange"))) {
  511. qb_log(LOG_ERR, "error creating NodeStateChange signal");
  512. goto out_unlock;
  513. }
  514. if (!dbus_message_append_args(msg,
  515. DBUS_TYPE_STRING, &nodename,
  516. DBUS_TYPE_UINT32, &nodeid,
  517. DBUS_TYPE_STRING, &ip,
  518. DBUS_TYPE_STRING, &state,
  519. DBUS_TYPE_INVALID)) {
  520. qb_log(LOG_ERR, "error adding args to NodeStateChange signal");
  521. goto out_unlock;
  522. }
  523. dbus_connection_send(db, msg, NULL);
  524. out_unlock:
  525. if (msg) {
  526. dbus_message_unref(msg);
  527. }
  528. out_free:
  529. return;
  530. }
  531. static void
  532. _cs_dbus_application_connection_event(char *nodename, uint32_t nodeid, char *app_name, const char *state)
  533. {
  534. DBusMessage *msg = NULL;
  535. if (err_set) {
  536. qb_log(LOG_ERR, "%s", _err);
  537. err_set = 0;
  538. }
  539. if (!db) {
  540. goto out_free;
  541. }
  542. if (dbus_connection_get_is_connected(db) != TRUE) {
  543. err_set = 1;
  544. snprintf(_err, sizeof(_err), "DBus connection lost");
  545. _cs_dbus_release();
  546. goto out_unlock;
  547. }
  548. _cs_dbus_auto_flush();
  549. if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
  550. DBUS_CS_IFACE,
  551. "ConnectionStateChange"))) {
  552. qb_log(LOG_ERR, "error creating ConnectionStateChange signal");
  553. goto out_unlock;
  554. }
  555. if (!dbus_message_append_args(msg,
  556. DBUS_TYPE_STRING, &nodename,
  557. DBUS_TYPE_UINT32, &nodeid,
  558. DBUS_TYPE_STRING, &app_name,
  559. DBUS_TYPE_STRING, &state,
  560. DBUS_TYPE_INVALID)) {
  561. qb_log(LOG_ERR, "error adding args to ConnectionStateChange signal");
  562. goto out_unlock;
  563. }
  564. dbus_connection_send(db, msg, NULL);
  565. out_unlock:
  566. if (msg) {
  567. dbus_message_unref(msg);
  568. }
  569. out_free:
  570. return;
  571. }
  572. static void
  573. _cs_dbus_link_faulty_event(char *nodename, uint32_t local_nodeid, uint32_t nodeid, uint32_t iface_no, const char *state)
  574. {
  575. DBusMessage *msg = NULL;
  576. if (err_set) {
  577. qb_log(LOG_ERR, "%s", _err);
  578. err_set = 0;
  579. }
  580. if (!db) {
  581. goto out_free;
  582. }
  583. if (dbus_connection_get_is_connected(db) != TRUE) {
  584. err_set = 1;
  585. snprintf(_err, sizeof(_err), "DBus connection lost");
  586. _cs_dbus_release();
  587. goto out_unlock;
  588. }
  589. _cs_dbus_auto_flush();
  590. if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
  591. DBUS_CS_IFACE,
  592. "QuorumStateChange"))) {
  593. qb_log(LOG_ERR, "error creating dbus signal");
  594. goto out_unlock;
  595. }
  596. if (!dbus_message_append_args(msg,
  597. DBUS_TYPE_STRING, &nodename,
  598. DBUS_TYPE_UINT32, &local_nodeid,
  599. DBUS_TYPE_UINT32, &nodeid,
  600. DBUS_TYPE_UINT32, &iface_no,
  601. DBUS_TYPE_STRING, &state,
  602. DBUS_TYPE_INVALID)) {
  603. qb_log(LOG_ERR, "error adding args to link signal");
  604. goto out_unlock;
  605. }
  606. dbus_connection_send(db, msg, NULL);
  607. out_unlock:
  608. if (msg) {
  609. dbus_message_unref(msg);
  610. }
  611. out_free:
  612. return;
  613. }
  614. static void
  615. _cs_dbus_init(void)
  616. {
  617. DBusConnection *dbc = NULL;
  618. DBusError err;
  619. dbus_error_init(&err);
  620. dbc = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
  621. if (!dbc) {
  622. snprintf(_err, sizeof(_err),
  623. "dbus_bus_get: %s", err.message);
  624. err_set = 1;
  625. dbus_error_free(&err);
  626. return;
  627. }
  628. dbus_connection_set_exit_on_disconnect(dbc, FALSE);
  629. db = dbc;
  630. notifiers[num_notifiers].node_membership_fn =
  631. _cs_dbus_node_membership_event;
  632. notifiers[num_notifiers].node_quorum_fn =
  633. _cs_dbus_node_quorum_event;
  634. notifiers[num_notifiers].application_connection_fn =
  635. _cs_dbus_application_connection_event;
  636. notifiers[num_notifiers].link_faulty_fn =
  637. _cs_dbus_link_faulty_event;
  638. num_notifiers++;
  639. }
  640. #endif /* HAVE_DBUS */
  641. #ifdef ENABLE_SNMP
  642. static netsnmp_session *snmp_init (const char *target)
  643. {
  644. static netsnmp_session *session = NULL;
  645. #ifndef NETSNMPV54
  646. char default_port[128];
  647. snprintf (default_port, sizeof (default_port), "%s:162", target);
  648. #endif
  649. if (session) {
  650. return (session);
  651. }
  652. if (target == NULL) {
  653. return NULL;
  654. }
  655. session = malloc (sizeof (netsnmp_session));
  656. snmp_sess_init (session);
  657. session->version = SNMP_VERSION_2c;
  658. session->callback = NULL;
  659. session->callback_magic = NULL;
  660. if (snmp_community) {
  661. session->community = (u_char *)snmp_community;
  662. session->community_len = strlen(snmp_community_buf);
  663. }
  664. session = snmp_add(session,
  665. #ifdef NETSNMPV54
  666. netsnmp_transport_open_client ("snmptrap", target),
  667. #else
  668. netsnmp_tdomain_transport (default_port, 0, "udp"),
  669. #endif
  670. NULL, NULL);
  671. if (session == NULL) {
  672. qb_log(LOG_ERR, 0, "Could not create snmp transport");
  673. }
  674. return (session);
  675. }
  676. static inline void add_field (
  677. netsnmp_pdu *trap_pdu,
  678. u_char asn_type,
  679. const char *prefix,
  680. void *value,
  681. size_t value_size)
  682. {
  683. oid _oid[MAX_OID_LEN];
  684. size_t _oid_len = MAX_OID_LEN;
  685. if (snmp_parse_oid(prefix, _oid, &_oid_len)) {
  686. snmp_pdu_add_variable (trap_pdu, _oid, _oid_len, asn_type, (u_char *) value, value_size);
  687. }
  688. }
  689. static void
  690. _cs_snmp_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
  691. {
  692. int ret;
  693. char csysuptime[CS_TIMESTAMP_STR_LEN];
  694. static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
  695. static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
  696. time_t now = time (NULL);
  697. netsnmp_pdu *trap_pdu;
  698. netsnmp_session *session = snmp_init (snmp_manager);
  699. if (session == NULL) {
  700. qb_log(LOG_NOTICE, "Failed to init SNMP session.");
  701. return ;
  702. }
  703. trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
  704. if (!trap_pdu) {
  705. qb_log(LOG_NOTICE, "Failed to create SNMP notification.");
  706. return ;
  707. }
  708. /* send uptime */
  709. snprintf (csysuptime, CS_TIMESTAMP_STR_LEN, "%ld", now);
  710. snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
  711. snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_NODE);
  712. /* Add extries to the trap */
  713. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename));
  714. add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid));
  715. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_ADDR, (void*)ip, strlen (ip));
  716. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_STATUS, (void*)state, strlen (state));
  717. /* Send and cleanup */
  718. ret = snmp_send (session, trap_pdu);
  719. if (ret == 0) {
  720. /* error */
  721. qb_log(LOG_ERR, "Could not send SNMP trap");
  722. snmp_free_pdu (trap_pdu);
  723. }
  724. }
  725. static void
  726. _cs_snmp_node_quorum_event(char *nodename, uint32_t nodeid,
  727. const char *state)
  728. {
  729. int ret;
  730. char csysuptime[20];
  731. static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
  732. static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
  733. time_t now = time (NULL);
  734. netsnmp_pdu *trap_pdu;
  735. netsnmp_session *session = snmp_init (snmp_manager);
  736. if (session == NULL) {
  737. qb_log(LOG_NOTICE, "Failed to init SNMP session.");
  738. return ;
  739. }
  740. trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
  741. if (!trap_pdu) {
  742. qb_log(LOG_NOTICE, "Failed to create SNMP notification.");
  743. return ;
  744. }
  745. /* send uptime */
  746. sprintf (csysuptime, "%ld", now);
  747. snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
  748. snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_QUORUM);
  749. /* Add extries to the trap */
  750. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename));
  751. add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid));
  752. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_QUORUM, (void*)state, strlen (state));
  753. /* Send and cleanup */
  754. ret = snmp_send (session, trap_pdu);
  755. if (ret == 0) {
  756. /* error */
  757. qb_log(LOG_ERR, "Could not send SNMP trap");
  758. snmp_free_pdu (trap_pdu);
  759. }
  760. }
  761. static void
  762. _cs_snmp_link_faulty_event(char *nodename, uint32_t local_nodeid, uint32_t nodeid,
  763. uint32_t iface_no, const char *state)
  764. {
  765. int ret;
  766. char csysuptime[20];
  767. static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
  768. static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
  769. time_t now = time (NULL);
  770. netsnmp_pdu *trap_pdu;
  771. netsnmp_session *session = snmp_init (snmp_manager);
  772. if (session == NULL) {
  773. qb_log(LOG_NOTICE, "Failed to init SNMP session.");
  774. return ;
  775. }
  776. trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
  777. if (!trap_pdu) {
  778. qb_log(LOG_NOTICE, "Failed to create SNMP notification.");
  779. return ;
  780. }
  781. /* send uptime */
  782. sprintf (csysuptime, "%ld", now);
  783. snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
  784. snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_LINK);
  785. /* Add extries to the trap */
  786. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename));
  787. add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_LOCAL_NODE_ID, (void*)&local_nodeid, sizeof (local_nodeid));
  788. add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid));
  789. add_field (trap_pdu, ASN_INTEGER, SNMP_OID_OBJECT_LINK_IFACE_NO, (void*)&iface_no, sizeof (iface_no));
  790. add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_LINK_STATUS, (void*)state, strlen (state));
  791. /* Send and cleanup */
  792. ret = snmp_send (session, trap_pdu);
  793. if (ret == 0) {
  794. /* error */
  795. qb_log(LOG_ERR, "Could not send SNMP trap");
  796. snmp_free_pdu (trap_pdu);
  797. }
  798. }
  799. static void
  800. _cs_snmp_init(void)
  801. {
  802. if (snmp_manager == NULL) {
  803. snmp_manager = (char*)local_host;
  804. }
  805. notifiers[num_notifiers].node_membership_fn =
  806. _cs_snmp_node_membership_event;
  807. notifiers[num_notifiers].node_quorum_fn =
  808. _cs_snmp_node_quorum_event;
  809. notifiers[num_notifiers].application_connection_fn = NULL;
  810. notifiers[num_notifiers].link_faulty_fn =
  811. _cs_snmp_link_faulty_event;
  812. num_notifiers++;
  813. }
  814. #endif /* ENABLE_SNMP */
  815. static void
  816. _cs_syslog_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
  817. {
  818. qb_log(LOG_NOTICE, "%s[%d] ip:%s %s", nodename, nodeid, ip, state);
  819. }
  820. static void
  821. _cs_syslog_node_quorum_event(char *nodename, uint32_t nodeid, const char *state)
  822. {
  823. if (strcmp(state, "quorate") == 0) {
  824. qb_log(LOG_NOTICE, "%s[%d] is now %s", nodename, nodeid, state);
  825. } else {
  826. qb_log(LOG_NOTICE, "%s[%d] has lost quorum", nodename, nodeid);
  827. }
  828. }
  829. static void
  830. _cs_syslog_application_connection_event(char *nodename, uint32_t nodeid, char* app_name, const char *state)
  831. {
  832. if (strcmp(state, "connected") == 0) {
  833. qb_log(LOG_NOTICE, "%s[%d] %s is now %s to corosync", nodename, nodeid, app_name, state);
  834. } else {
  835. qb_log(LOG_NOTICE, "%s[%d] %s is now %s from corosync", nodename, nodeid, app_name, state);
  836. }
  837. }
  838. static void
  839. _cs_syslog_link_faulty_event(char *nodename, uint32_t our_nodeid, uint32_t nodeid, uint32_t iface_no, const char *state)
  840. {
  841. qb_log(LOG_NOTICE, "%s[%d] link %u to node %u is now %s", nodename, our_nodeid, iface_no, nodeid, state);
  842. }
  843. static void
  844. _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
  845. {
  846. int i;
  847. for (i = 0; i < num_notifiers; i++) {
  848. if (notifiers[i].node_membership_fn) {
  849. notifiers[i].node_membership_fn(nodename, nodeid, state, ip);
  850. }
  851. }
  852. }
  853. static void
  854. _cs_local_node_info_get(char **nodename, uint32_t *nodeid)
  855. {
  856. cs_error_t rc;
  857. corosync_cfg_handle_t cfg_handle;
  858. if (g_local_nodeid == 0) {
  859. rc = corosync_cfg_initialize(&cfg_handle, NULL);
  860. if (rc != CS_OK) {
  861. syslog (LOG_ERR, "Failed to initialize the cfg API. Error %d\n", rc);
  862. exit (EXIT_FAILURE);
  863. }
  864. rc = corosync_cfg_local_get (cfg_handle, &g_local_nodeid);
  865. corosync_cfg_finalize(cfg_handle);
  866. if (rc != CS_OK) {
  867. g_local_nodeid = 0;
  868. strncpy(local_nodename, "localhost", sizeof (local_nodename));
  869. local_nodename[sizeof (local_nodename) - 1] = '\0';
  870. } else {
  871. gethostname(local_nodename, CS_MAX_NAME_LENGTH);
  872. }
  873. }
  874. *nodeid = g_local_nodeid;
  875. *nodename = local_nodename;
  876. }
  877. static void
  878. _cs_node_quorum_event(const char *state)
  879. {
  880. int i;
  881. char *nodename;
  882. uint32_t nodeid;
  883. _cs_local_node_info_get(&nodename, &nodeid);
  884. for (i = 0; i < num_notifiers; i++) {
  885. if (notifiers[i].node_quorum_fn) {
  886. notifiers[i].node_quorum_fn(nodename, nodeid, state);
  887. }
  888. }
  889. }
  890. static void
  891. _cs_application_connection_event(char *app_name, const char *state)
  892. {
  893. int i;
  894. char *nodename;
  895. uint32_t nodeid;
  896. _cs_local_node_info_get(&nodename, &nodeid);
  897. for (i = 0; i < num_notifiers; i++) {
  898. if (notifiers[i].application_connection_fn) {
  899. notifiers[i].application_connection_fn(nodename, nodeid, app_name, state);
  900. }
  901. }
  902. }
  903. static void
  904. _cs_link_faulty_event(uint32_t nodeid, uint32_t iface_no, const char *state)
  905. {
  906. int i;
  907. char *nodename;
  908. uint32_t our_nodeid;
  909. _cs_local_node_info_get(&nodename, &our_nodeid);
  910. for (i = 0; i < num_notifiers; i++) {
  911. if (notifiers[i].link_faulty_fn) {
  912. notifiers[i].link_faulty_fn(nodename, our_nodeid, nodeid, iface_no, state);
  913. }
  914. }
  915. }
  916. static int32_t
  917. sig_exit_handler(int32_t num, void *data)
  918. {
  919. qb_loop_stop(main_loop);
  920. return 0;
  921. }
  922. static void track_link_updown_events(void)
  923. {
  924. cmap_iter_handle_t iter_handle;
  925. cmap_track_handle_t track_handle;
  926. char key_name[CMAP_KEYNAME_MAXLEN + 1];
  927. size_t value_len;
  928. cmap_value_types_t type;
  929. cs_error_t err;
  930. struct track_item *track_item;
  931. err = cmap_iter_init(stats_handle, "stats.knet.", &iter_handle);
  932. if (err != CS_OK) {
  933. fprintf (stderr, "Failed to initialize knet stats iterator. Error %s\n", cs_strerror(err));
  934. exit (EXIT_FAILURE);
  935. }
  936. while ((err = cmap_iter_next(stats_handle, iter_handle, key_name, &value_len, &type)) == CS_OK) {
  937. if (strstr(key_name, ".connected")) {
  938. track_item = malloc(sizeof(struct track_item));
  939. if (!track_item) {
  940. return;
  941. }
  942. if ((err = cmap_track_add(stats_handle, key_name, CMAP_TRACK_MODIFY, _cs_cmap_link_faulty_key_changed, NULL, &track_handle)) != CS_OK) {
  943. fprintf (stderr, "Failed to add tracker for %s. Error %s\n", key_name, cs_strerror(err));
  944. exit (EXIT_FAILURE);
  945. }
  946. strcpy(track_item->key_name, key_name);
  947. track_item->track_handle = track_handle;
  948. qb_map_put(tracker_map, track_item->key_name, track_item);
  949. }
  950. }
  951. cmap_iter_finalize(stats_handle, iter_handle);
  952. }
  953. static void
  954. _cs_cmap_init(void)
  955. {
  956. cs_error_t rc = CS_OK;
  957. int cmap_fd = 0;
  958. int stats_fd = 0;
  959. tracker_map = qb_trie_create();
  960. if (!tracker_map) {
  961. qb_log(LOG_ERR, "Failed to initialize the track map. Error %d", rc);
  962. exit (EXIT_FAILURE);
  963. }
  964. rc = cmap_initialize_map (&cmap_handle, CMAP_MAP_ICMAP);
  965. if (rc != CS_OK) {
  966. qb_log(LOG_ERR, "Failed to initialize the cmap API. Error %d", rc);
  967. exit (EXIT_FAILURE);
  968. }
  969. cmap_fd_get(cmap_handle, &cmap_fd);
  970. qb_loop_poll_add(main_loop, QB_LOOP_MED, cmap_fd, POLLIN|POLLNVAL, (void*)&cmap_handle,
  971. _cs_cmap_dispatch);
  972. rc = cmap_initialize_map (&stats_handle, CMAP_MAP_STATS);
  973. if (rc != CS_OK) {
  974. qb_log(LOG_ERR, "Failed to initialize the cmap stats API. Error %d", rc);
  975. exit (EXIT_FAILURE);
  976. }
  977. cmap_fd_get(stats_handle, &stats_fd);
  978. qb_loop_poll_add(main_loop, QB_LOOP_MED, stats_fd, POLLIN|POLLNVAL, (void*)&stats_handle,
  979. _cs_cmap_dispatch);
  980. rc = cmap_track_add(cmap_handle, "runtime.members.",
  981. CMAP_TRACK_ADD | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
  982. _cs_cmap_members_key_changed,
  983. NULL,
  984. &cmap_track_handle_runtime_members_key_changed);
  985. if (rc != CS_OK) {
  986. qb_log(LOG_ERR,
  987. "Failed to track the members key. Error %d", rc);
  988. exit (EXIT_FAILURE);
  989. }
  990. rc = cmap_track_add(stats_handle, "stats.ipcs.",
  991. CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_PREFIX,
  992. _cs_cmap_connections_key_changed,
  993. NULL,
  994. &cmap_track_handle_stats_ipcs_key_changed);
  995. if (rc != CS_OK) {
  996. qb_log(LOG_ERR,
  997. "Failed to track the connections key. Error %d", rc);
  998. exit (EXIT_FAILURE);
  999. }
  1000. rc = cmap_track_add(stats_handle, "stats.knet.",
  1001. CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_PREFIX,
  1002. _cs_cmap_link_added_removed,
  1003. NULL,
  1004. &cmap_track_handle_stats_knet_key_changed);
  1005. if (rc != CS_OK) {
  1006. qb_log(LOG_ERR,
  1007. "Failed to track the knet link status key. Error %d", rc);
  1008. exit (EXIT_FAILURE);
  1009. }
  1010. track_link_updown_events();
  1011. }
  1012. static void
  1013. _cs_cmap_finalize(void)
  1014. {
  1015. struct qb_map_iter *map_iter;
  1016. struct track_item *track_item;
  1017. map_iter = qb_map_iter_create(tracker_map);
  1018. while (qb_map_iter_next(map_iter, (void **)&track_item) != NULL) {
  1019. cmap_track_delete(stats_handle, track_item->track_handle);
  1020. free(track_item);
  1021. }
  1022. qb_map_iter_free(map_iter);
  1023. cmap_track_delete(cmap_handle, cmap_track_handle_runtime_members_key_changed);
  1024. cmap_track_delete(stats_handle, cmap_track_handle_stats_ipcs_key_changed);
  1025. cmap_track_delete(stats_handle, cmap_track_handle_stats_knet_key_changed);
  1026. cmap_finalize (cmap_handle);
  1027. cmap_finalize (stats_handle);
  1028. }
  1029. static void
  1030. _cs_check_config(void)
  1031. {
  1032. if (conf[CS_NTF_LOG] == QB_FALSE &&
  1033. conf[CS_NTF_STDOUT] == QB_FALSE &&
  1034. conf[CS_NTF_SNMP] == QB_FALSE &&
  1035. conf[CS_NTF_DBUS] == QB_FALSE) {
  1036. qb_log(LOG_ERR, "no event type enabled, see corosync-notifyd -h, exiting.");
  1037. exit(EXIT_FAILURE);
  1038. }
  1039. #ifndef ENABLE_SNMP
  1040. if (conf[CS_NTF_SNMP]) {
  1041. qb_log(LOG_ERR, "Not compiled with SNMP support enabled, exiting.");
  1042. exit(EXIT_FAILURE);
  1043. }
  1044. #endif
  1045. #ifndef HAVE_DBUS
  1046. if (conf[CS_NTF_DBUS]) {
  1047. qb_log(LOG_ERR, "Not compiled with DBus support enabled, exiting.");
  1048. exit(EXIT_FAILURE);
  1049. }
  1050. #endif
  1051. if (conf[CS_NTF_STDOUT] && !conf[CS_NTF_FG]) {
  1052. qb_log(LOG_ERR, "configured to print to stdout and run in the background, exiting");
  1053. exit(EXIT_FAILURE);
  1054. }
  1055. if (conf[CS_NTF_SNMP] && conf[CS_NTF_DBUS]) {
  1056. qb_log(LOG_ERR, "configured to send snmp traps and dbus signals - are you sure?.");
  1057. }
  1058. }
  1059. static void
  1060. _cs_usage(void)
  1061. {
  1062. fprintf(stderr, "usage:\n"\
  1063. " -c : SNMP Community name.\n"\
  1064. " -f : Start application in foreground.\n"\
  1065. " -l : Log all events.\n"\
  1066. " -o : Print events to stdout (turns on -l).\n"\
  1067. " -s : Send SNMP traps on all events.\n"\
  1068. " -m : Set the SNMP Manager IP address (defaults to localhost).\n"\
  1069. " -d : Send DBUS signals on all events.\n"\
  1070. " -h : Print this help.\n\n");
  1071. }
  1072. int
  1073. main(int argc, char *argv[])
  1074. {
  1075. int ch;
  1076. conf[CS_NTF_FG] = QB_FALSE;
  1077. conf[CS_NTF_LOG] = QB_FALSE;
  1078. conf[CS_NTF_STDOUT] = QB_FALSE;
  1079. conf[CS_NTF_SNMP] = QB_FALSE;
  1080. conf[CS_NTF_DBUS] = QB_FALSE;
  1081. while ((ch = getopt (argc, argv, "c:floshdm:")) != EOF) {
  1082. switch (ch) {
  1083. case 'c':
  1084. strncpy(snmp_community_buf, optarg, sizeof (snmp_community_buf));
  1085. snmp_community_buf[sizeof (snmp_community_buf) - 1] = '\0';
  1086. snmp_community = snmp_community_buf;
  1087. break;
  1088. case 'f':
  1089. conf[CS_NTF_FG] = QB_TRUE;
  1090. break;
  1091. case 'l':
  1092. conf[CS_NTF_LOG] = QB_TRUE;
  1093. break;
  1094. case 'm':
  1095. conf[CS_NTF_SNMP] = QB_TRUE;
  1096. strncpy(snmp_manager_buf, optarg, sizeof (snmp_manager_buf));
  1097. snmp_manager_buf[sizeof (snmp_manager_buf) - 1] = '\0';
  1098. snmp_manager = snmp_manager_buf;
  1099. break;
  1100. case 'o':
  1101. conf[CS_NTF_LOG] = QB_TRUE;
  1102. conf[CS_NTF_STDOUT] = QB_TRUE;
  1103. break;
  1104. case 's':
  1105. conf[CS_NTF_SNMP] = QB_TRUE;
  1106. break;
  1107. case 'd':
  1108. conf[CS_NTF_DBUS] = QB_TRUE;
  1109. break;
  1110. case 'h':
  1111. default:
  1112. _cs_usage();
  1113. return EXIT_FAILURE;
  1114. }
  1115. }
  1116. qb_log_init("notifyd", LOG_DAEMON, LOG_INFO);
  1117. if (conf[CS_NTF_STDOUT]) {
  1118. qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
  1119. QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
  1120. qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, conf[CS_NTF_STDOUT]);
  1121. }
  1122. _cs_check_config();
  1123. if (!conf[CS_NTF_FG]) {
  1124. if (daemon(0, 0) < 0)
  1125. {
  1126. perror("daemon() failed");
  1127. return EXIT_FAILURE;
  1128. }
  1129. }
  1130. num_notifiers = 0;
  1131. if (conf[CS_NTF_LOG]) {
  1132. notifiers[num_notifiers].node_membership_fn =
  1133. _cs_syslog_node_membership_event;
  1134. notifiers[num_notifiers].node_quorum_fn =
  1135. _cs_syslog_node_quorum_event;
  1136. notifiers[num_notifiers].application_connection_fn =
  1137. _cs_syslog_application_connection_event;
  1138. notifiers[num_notifiers].link_faulty_fn =
  1139. _cs_syslog_link_faulty_event;
  1140. num_notifiers++;
  1141. }
  1142. main_loop = qb_loop_create();
  1143. _cs_cmap_init();
  1144. _cs_quorum_init();
  1145. #ifdef HAVE_DBUS
  1146. if (conf[CS_NTF_DBUS]) {
  1147. _cs_dbus_init();
  1148. }
  1149. #endif /* HAVE_DBUS */
  1150. #ifdef ENABLE_SNMP
  1151. if (conf[CS_NTF_SNMP]) {
  1152. _cs_snmp_init();
  1153. }
  1154. #endif /* ENABLE_SNMP */
  1155. qb_loop_signal_add(main_loop,
  1156. QB_LOOP_HIGH,
  1157. SIGINT,
  1158. NULL,
  1159. sig_exit_handler,
  1160. NULL);
  1161. qb_loop_signal_add(main_loop,
  1162. QB_LOOP_HIGH,
  1163. SIGQUIT,
  1164. NULL,
  1165. sig_exit_handler,
  1166. NULL);
  1167. qb_loop_signal_add(main_loop,
  1168. QB_LOOP_HIGH,
  1169. SIGTERM,
  1170. NULL,
  1171. sig_exit_handler,
  1172. NULL);
  1173. #ifdef HAVE_LIBSYSTEMD
  1174. sd_notify (0, "READY=1");
  1175. #endif
  1176. qb_loop_run(main_loop);
  1177. #ifdef HAVE_DBUS
  1178. if (conf[CS_NTF_DBUS]) {
  1179. _cs_dbus_release();
  1180. }
  1181. #endif /* HAVE_DBUS */
  1182. _cs_quorum_finalize();
  1183. _cs_cmap_finalize();
  1184. return (exit_code);
  1185. }