1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21
22 #ifdef HAVE_OPENIPMI
23
24 #include "dbcache.h"
25 #include "daemon.h"
26 #include "zbxself.h"
27 #include "log.h"
28 #include "zbxipcservice.h"
29 #include "zbxalgo.h"
30 #include "zbxserver.h"
31 #include "preproc.h"
32
33 #include "ipmi_manager.h"
34 #include "ipmi_protocol.h"
35 #include "checks_ipmi.h"
36 #include "ipmi.h"
37
38 #include "../poller/poller.h"
39
40 #define ZBX_IPMI_MANAGER_DELAY 1
41
42 extern unsigned char process_type, program_type;
43 extern int server_num, process_num;
44
45 extern int CONFIG_IPMIPOLLER_FORKS;
46
47 #define ZBX_IPMI_POLLER_INIT 0
48 #define ZBX_IPMI_POLLER_READY 1
49 #define ZBX_IPMI_POLLER_BUSY 2
50
51 #define ZBX_IPMI_MANAGER_CLEANUP_DELAY SEC_PER_HOUR
52 #define ZBX_IPMI_MANAGER_HOST_TTL SEC_PER_DAY
53
54 /* IPMI request queued by pollers */
55 typedef struct
56 {
57 /* internal requestid */
58 zbx_uint64_t requestid;
59
60 /* target host id */
61 zbx_uint64_t hostid;
62
63 /* itemid, set for value requests */
64 zbx_uint64_t itemid;
65
66 /* the current item state (supported/unsupported) */
67 unsigned char item_state;
68
69 /* the current item flags ( e.g. lld rule) */
70 unsigned char item_flags;
71
72 /* the request message */
73 zbx_ipc_message_t message;
74
75 /* the source client for external requests (command request) */
76 zbx_ipc_client_t *client;
77 }
78 zbx_ipmi_request_t;
79
80 /* IPMI poller data */
81 typedef struct
82 {
83 /* the connected IPMI poller client */
84 zbx_ipc_client_t *client;
85
86 /* the request queue */
87 zbx_binary_heap_t requests;
88
89 /* the currently processing request */
90 zbx_ipmi_request_t *request;
91
92 /* the number of hosts handled by the poller */
93 int hosts_num;
94 }
95 zbx_ipmi_poller_t;
96
97 /* cached host data */
98 typedef struct
99 {
100 zbx_uint64_t hostid;
101 int disable_until;
102 int lastcheck;
103 zbx_ipmi_poller_t *poller;
104 }
105 zbx_ipmi_manager_host_t;
106
107 /* IPMI manager data */
108 typedef struct
109 {
110 /* IPMI poller vector, created during manager initialization */
111 zbx_vector_ptr_t pollers;
112
113 /* IPMI pollers indexed by IPC service clients */
114 zbx_hashset_t pollers_client;
115
116 /* IPMI pollers sorted by number of hosts being monitored */
117 zbx_binary_heap_t pollers_load;
118
119 /* the next poller index to be assigned to new IPC service clients */
120 int next_poller_index;
121
122 /* monitored hosts cache */
123 zbx_hashset_t hosts;
124 }
125 zbx_ipmi_manager_t;
126
127 /* pollers_client hashset support */
128
poller_hash_func(const void * d)129 static zbx_hash_t poller_hash_func(const void *d)
130 {
131 const zbx_ipmi_poller_t *poller = *(const zbx_ipmi_poller_t **)d;
132
133 zbx_hash_t hash = ZBX_DEFAULT_PTR_HASH_FUNC(&poller->client);
134
135 return hash;
136 }
137
poller_compare_func(const void * d1,const void * d2)138 static int poller_compare_func(const void *d1, const void *d2)
139 {
140 const zbx_ipmi_poller_t *p1 = *(const zbx_ipmi_poller_t **)d1;
141 const zbx_ipmi_poller_t *p2 = *(const zbx_ipmi_poller_t **)d2;
142
143 ZBX_RETURN_IF_NOT_EQUAL(p1->client, p2->client);
144 return 0;
145 }
146
147 /* pollers_load binary heap support */
148
ipmi_poller_compare_load(const void * d1,const void * d2)149 static int ipmi_poller_compare_load(const void *d1, const void *d2)
150 {
151 const zbx_binary_heap_elem_t *e1 = (const zbx_binary_heap_elem_t *)d1;
152 const zbx_binary_heap_elem_t *e2 = (const zbx_binary_heap_elem_t *)d2;
153
154 const zbx_ipmi_poller_t *p1 = (const zbx_ipmi_poller_t *)e1->data;
155 const zbx_ipmi_poller_t *p2 = (const zbx_ipmi_poller_t *)e2->data;
156
157 return p1->hosts_num - p2->hosts_num;
158 }
159
160 /* pollers requests binary heap support */
161
ipmi_request_priority(const zbx_ipmi_request_t * request)162 static int ipmi_request_priority(const zbx_ipmi_request_t *request)
163 {
164 if (NULL != request->client)
165 return 0;
166
167 switch (request->message.code)
168 {
169 case ZBX_IPC_IPMI_VALUE_REQUEST:
170 return 1;
171 default:
172 return INT_MAX;
173 }
174 }
175
176 /* There can be two request types in the queue - ZBX_IPC_IPMI_VALUE_REQUEST and ZBX_IPC_IPMI_COMMAND_REQUEST. */
177 /* Prioritize command requests over value requests. */
ipmi_request_compare(const void * d1,const void * d2)178 static int ipmi_request_compare(const void *d1, const void *d2)
179 {
180 const zbx_binary_heap_elem_t *e1 = (const zbx_binary_heap_elem_t *)d1;
181 const zbx_binary_heap_elem_t *e2 = (const zbx_binary_heap_elem_t *)d2;
182
183 const zbx_ipmi_request_t *r1 = (const zbx_ipmi_request_t *)e1->data;
184 const zbx_ipmi_request_t *r2 = (const zbx_ipmi_request_t *)e2->data;
185
186 ZBX_RETURN_IF_NOT_EQUAL(ipmi_request_priority(r1), ipmi_request_priority(r2));
187 ZBX_RETURN_IF_NOT_EQUAL(r1->requestid, r2->requestid);
188
189 return 0;
190 }
191
192 /******************************************************************************
193 * *
194 * Function: ipmi_request_create *
195 * *
196 * Purpose: creates an IPMI request *
197 * *
198 * Parameters: hostid - [IN] the target hostid *
199 * *
200 ******************************************************************************/
ipmi_request_create(zbx_uint64_t hostid)201 static zbx_ipmi_request_t *ipmi_request_create(zbx_uint64_t hostid)
202 {
203 static zbx_uint64_t next_requestid = 1;
204 zbx_ipmi_request_t *request;
205
206 request = (zbx_ipmi_request_t *)zbx_malloc(NULL, sizeof(zbx_ipmi_request_t));
207 memset(request, 0, sizeof(zbx_ipmi_request_t));
208 request->requestid = next_requestid++;
209 request->hostid = hostid;
210
211 return request;
212 }
213
214 /******************************************************************************
215 * *
216 * Function: ipmi_request_free *
217 * *
218 * Purpose: frees IPMI request *
219 * *
220 ******************************************************************************/
ipmi_request_free(zbx_ipmi_request_t * request)221 static void ipmi_request_free(zbx_ipmi_request_t *request)
222 {
223 zbx_ipc_message_clean(&request->message);
224 zbx_free(request);
225 }
226
227 /******************************************************************************
228 * *
229 * Function: ipmi_poller_pop_request *
230 * *
231 * Purpose: pops the next queued request from IPMI poller request queue *
232 * *
233 * Parameters: poller - [IN] the IPMI poller *
234 * *
235 * Return value: The next request to process or NULL if the queue is empty. *
236 * *
237 ******************************************************************************/
ipmi_poller_pop_request(zbx_ipmi_poller_t * poller)238 static zbx_ipmi_request_t *ipmi_poller_pop_request(zbx_ipmi_poller_t *poller)
239 {
240 zbx_binary_heap_elem_t *el;
241 zbx_ipmi_request_t *request;
242
243 if (SUCCEED == zbx_binary_heap_empty(&poller->requests))
244 return NULL;
245
246 el = zbx_binary_heap_find_min(&poller->requests);
247 request = (zbx_ipmi_request_t *)el->data;
248 zbx_binary_heap_remove_min(&poller->requests);
249
250 return request;
251 }
252
253 /******************************************************************************
254 * *
255 * Function: ipmi_poller_push_request *
256 * *
257 * Purpose: pushes the requests into IPMI poller request queue *
258 * *
259 * Parameters: poller - [IN] the IPMI poller *
260 * request - [IN] the IPMI request to push *
261 * *
262 * *
263 ******************************************************************************/
ipmi_poller_push_request(zbx_ipmi_poller_t * poller,zbx_ipmi_request_t * request)264 static void ipmi_poller_push_request(zbx_ipmi_poller_t *poller, zbx_ipmi_request_t *request)
265 {
266 zbx_binary_heap_elem_t el = {0, (void *)request};
267
268 zbx_binary_heap_insert(&poller->requests, &el);
269 }
270
271 /******************************************************************************
272 * *
273 * Function: ipmi_poller_send_request *
274 * *
275 * Purpose: sends request to IPMI poller *
276 * *
277 * Parameters: poller - [IN] the IPMI poller *
278 * message - [IN] the message to send *
279 * *
280 ******************************************************************************/
ipmi_poller_send_request(zbx_ipmi_poller_t * poller,zbx_ipmi_request_t * request)281 static void ipmi_poller_send_request(zbx_ipmi_poller_t *poller, zbx_ipmi_request_t *request)
282 {
283 if (FAIL == zbx_ipc_client_send(poller->client, request->message.code, request->message.data,
284 request->message.size))
285 {
286 zabbix_log(LOG_LEVEL_CRIT, "cannot send data to IPMI poller");
287 exit(EXIT_FAILURE);
288 }
289
290 poller->request = request;
291 }
292
293 /******************************************************************************
294 * *
295 * Function: ipmi_poller_schedule_request *
296 * *
297 * Purpose: schedules request to IPMI poller *
298 * *
299 * Parameters: poller - [IN] the IPMI poller *
300 * request - [IN] the request to send *
301 * *
302 ******************************************************************************/
ipmi_poller_schedule_request(zbx_ipmi_poller_t * poller,zbx_ipmi_request_t * request)303 static void ipmi_poller_schedule_request(zbx_ipmi_poller_t *poller, zbx_ipmi_request_t *request)
304 {
305 if (NULL == poller->request && NULL != poller->client)
306 ipmi_poller_send_request(poller, request);
307 else
308 ipmi_poller_push_request(poller, request);
309 }
310
311 /******************************************************************************
312 * *
313 * Function: ipmi_poller_free_request *
314 * *
315 * Purpose: frees the current request processed by IPMI poller *
316 * *
317 * Parameters: poller - [IN] the IPMI poller *
318 * *
319 ******************************************************************************/
ipmi_poller_free_request(zbx_ipmi_poller_t * poller)320 static void ipmi_poller_free_request(zbx_ipmi_poller_t *poller)
321 {
322 ipmi_request_free(poller->request);
323 poller->request = NULL;
324 }
325
326 /******************************************************************************
327 * *
328 * Function: ipmi_poller_free *
329 * *
330 * Purpose: frees IPMI poller *
331 * *
332 ******************************************************************************/
ipmi_poller_free(zbx_ipmi_poller_t * poller)333 static void ipmi_poller_free(zbx_ipmi_poller_t *poller)
334 {
335 zbx_ipmi_request_t *request;
336
337 zbx_ipc_client_close(poller->client);
338
339 while (NULL != (request = ipmi_poller_pop_request(poller)))
340 ipmi_request_free(request);
341
342 zbx_binary_heap_destroy(&poller->requests);
343
344 zbx_free(poller);
345 }
346
347 /******************************************************************************
348 * *
349 * Function: ipmi_manager_init *
350 * *
351 * Purpose: initializes IPMI manager *
352 * *
353 * Parameters: manager - [IN] the manager to initialize *
354 * *
355 ******************************************************************************/
ipmi_manager_init(zbx_ipmi_manager_t * manager)356 static void ipmi_manager_init(zbx_ipmi_manager_t *manager)
357 {
358 int i;
359 zbx_ipmi_poller_t *poller;
360 zbx_binary_heap_elem_t elem = {0};
361
362 zabbix_log(LOG_LEVEL_DEBUG, "In %s() pollers:%d", __func__, CONFIG_IPMIPOLLER_FORKS);
363
364 zbx_vector_ptr_create(&manager->pollers);
365 zbx_hashset_create(&manager->pollers_client, 0, poller_hash_func, poller_compare_func);
366 zbx_binary_heap_create(&manager->pollers_load, ipmi_poller_compare_load, 0);
367
368 manager->next_poller_index = 0;
369
370 for (i = 0; i < CONFIG_IPMIPOLLER_FORKS; i++)
371 {
372 poller = (zbx_ipmi_poller_t *)zbx_malloc(NULL, sizeof(zbx_ipmi_poller_t));
373
374 poller->client = NULL;
375 poller->request = NULL;
376 poller->hosts_num = 0;
377
378 zbx_binary_heap_create(&poller->requests, ipmi_request_compare, 0);
379
380 zbx_vector_ptr_append(&manager->pollers, poller);
381
382 /* add poller to load balancing poller queue */
383 elem.data = (const void *)poller;
384 zbx_binary_heap_insert(&manager->pollers_load, &elem);
385 }
386
387 zbx_hashset_create(&manager->hosts, 0, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
388
389 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
390 }
391
392 /******************************************************************************
393 * *
394 * Function: ipmi_manager_destroy *
395 * *
396 * Purpose: destroys IPMI manager *
397 * *
398 * Parameters: manager - [IN] the manager to destroy *
399 * *
400 ******************************************************************************/
ipmi_manager_destroy(zbx_ipmi_manager_t * manager)401 static void ipmi_manager_destroy(zbx_ipmi_manager_t *manager)
402 {
403 zbx_hashset_destroy(&manager->hosts);
404 zbx_binary_heap_destroy(&manager->pollers_load);
405 zbx_hashset_destroy(&manager->pollers_client);
406 zbx_vector_ptr_clear_ext(&manager->pollers, (zbx_clean_func_t)ipmi_poller_free);
407 zbx_vector_ptr_destroy(&manager->pollers);
408 }
409
410 /******************************************************************************
411 * *
412 * Function: ipmi_manager_host_cleanup *
413 * *
414 * Purpose: performs cleanup of monitored hosts cache *
415 * *
416 * Parameters: manager - [IN] the manager *
417 * now - [IN] the current time *
418 * *
419 ******************************************************************************/
ipmi_manager_host_cleanup(zbx_ipmi_manager_t * manager,int now)420 static void ipmi_manager_host_cleanup(zbx_ipmi_manager_t *manager, int now)
421 {
422 zbx_hashset_iter_t iter;
423 zbx_ipmi_manager_host_t *host;
424 zbx_ipmi_poller_t *poller;
425 int i;
426
427 zabbix_log(LOG_LEVEL_DEBUG, "In %s() pollers:%d", __func__, CONFIG_IPMIPOLLER_FORKS);
428
429 zbx_hashset_iter_reset(&manager->hosts, &iter);
430 while (NULL != (host = (zbx_ipmi_manager_host_t *)zbx_hashset_iter_next(&iter)))
431 {
432 if (host->lastcheck + ZBX_IPMI_MANAGER_HOST_TTL <= now)
433 {
434 host->poller->hosts_num--;
435 zbx_hashset_iter_remove(&iter);
436 }
437 }
438
439 for (i = 0; i < manager->pollers.values_num; i++)
440 {
441 poller = (zbx_ipmi_poller_t *)manager->pollers.values[i];
442
443 if (NULL != poller->client)
444 zbx_ipc_client_send(poller->client, ZBX_IPC_IPMI_CLEANUP_REQUEST, NULL, 0);
445 }
446
447 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
448 }
449
450 /******************************************************************************
451 * *
452 * Function: ipmi_manager_register_poller *
453 * *
454 * Purpose: registers IPMI poller *
455 * *
456 * Parameters: manager - [IN] the manager *
457 * client - [IN] the connected IPMI poller *
458 * *
459 ******************************************************************************/
ipmi_manager_register_poller(zbx_ipmi_manager_t * manager,zbx_ipc_client_t * client,zbx_ipc_message_t * message)460 static zbx_ipmi_poller_t *ipmi_manager_register_poller(zbx_ipmi_manager_t *manager, zbx_ipc_client_t *client,
461 zbx_ipc_message_t *message)
462 {
463 zbx_ipmi_poller_t *poller = NULL;
464 pid_t ppid;
465
466 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
467
468 memcpy(&ppid, message->data, sizeof(ppid));
469
470 if (ppid != getppid())
471 {
472 zbx_ipc_client_close(client);
473 zabbix_log(LOG_LEVEL_DEBUG, "refusing connection from foreign process");
474 }
475 else
476 {
477 if (manager->next_poller_index == manager->pollers.values_num)
478 {
479 THIS_SHOULD_NEVER_HAPPEN;
480 exit(EXIT_FAILURE);
481 }
482
483 poller = (zbx_ipmi_poller_t *)manager->pollers.values[manager->next_poller_index++];
484 poller->client = client;
485
486 zbx_hashset_insert(&manager->pollers_client, &poller, sizeof(zbx_ipmi_poller_t *));
487 }
488
489 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
490
491 return poller;
492 }
493
494 /******************************************************************************
495 * *
496 * Function: ipmi_manager_get_poller_by_client *
497 * *
498 * Purpose: returns IPMI poller by connected client *
499 * *
500 * Parameters: manager - [IN] the manager *
501 * client - [IN] the connected IPMI poller *
502 * *
503 * Return value: The IPMI poller *
504 * *
505 ******************************************************************************/
ipmi_manager_get_poller_by_client(zbx_ipmi_manager_t * manager,zbx_ipc_client_t * client)506 static zbx_ipmi_poller_t *ipmi_manager_get_poller_by_client(zbx_ipmi_manager_t *manager,
507 zbx_ipc_client_t *client)
508 {
509 zbx_ipmi_poller_t **poller, poller_local, *plocal = &poller_local;
510
511 plocal->client = client;
512
513 poller = (zbx_ipmi_poller_t **)zbx_hashset_search(&manager->pollers_client, &plocal);
514
515 if (NULL == poller)
516 {
517 THIS_SHOULD_NEVER_HAPPEN;
518 exit(EXIT_FAILURE);
519 }
520
521 return *poller;
522 }
523
524 /******************************************************************************
525 * *
526 * Function: ipmi_manager_get_host_poller *
527 * *
528 * Purpose: returns IPMI poller to be assigned to a new host *
529 * *
530 * Parameters: manager - [IN] the manager *
531 * *
532 * Return value: The IPMI poller *
533 * *
534 * Comments: This function will return IPMI poller with least monitored hosts.*
535 * *
536 ******************************************************************************/
ipmi_manager_get_host_poller(zbx_ipmi_manager_t * manager)537 static zbx_ipmi_poller_t *ipmi_manager_get_host_poller(zbx_ipmi_manager_t *manager)
538 {
539 zbx_ipmi_poller_t *poller;
540 zbx_binary_heap_elem_t el;
541
542 el = *zbx_binary_heap_find_min(&manager->pollers_load);
543 zbx_binary_heap_remove_min(&manager->pollers_load);
544
545 poller = (zbx_ipmi_poller_t *)el.data;
546 poller->hosts_num++;
547
548 zbx_binary_heap_insert(&manager->pollers_load, &el);
549
550 return poller;
551 }
552
553 /******************************************************************************
554 * *
555 * Function: ipmi_manager_process_poller_queue *
556 * *
557 * Purpose: processes IPMI poller request queue *
558 * *
559 * Parameters: manager - [IN] the IPMI manager *
560 * poller - [IN] the IPMI poller *
561 * now - [IN] the current time *
562 * *
563 * Comments: This function will send the next request in queue to the poller, *
564 * skipping requests for unreachable hosts for unreachable period. *
565 * *
566 ******************************************************************************/
ipmi_manager_process_poller_queue(zbx_ipmi_manager_t * manager,zbx_ipmi_poller_t * poller,int now)567 static void ipmi_manager_process_poller_queue(zbx_ipmi_manager_t *manager, zbx_ipmi_poller_t *poller, int now)
568 {
569 zbx_ipmi_request_t *request;
570 zbx_ipmi_manager_host_t *host;
571
572 while (NULL != (request = ipmi_poller_pop_request(poller)))
573 {
574 switch (request->message.code)
575 {
576 case ZBX_IPC_IPMI_COMMAND_REQUEST:
577 case ZBX_IPC_IPMI_CLEANUP_REQUEST:
578 break;
579 case ZBX_IPC_IPMI_VALUE_REQUEST:
580 if (NULL != request->client)
581 break;
582
583 if (NULL == (host = (zbx_ipmi_manager_host_t *)zbx_hashset_search(&manager->hosts,
584 &request->hostid)))
585 {
586 THIS_SHOULD_NEVER_HAPPEN;
587 ipmi_request_free(request);
588 continue;
589 }
590 if (now < host->disable_until)
591 {
592 zbx_dc_requeue_unreachable_items(&request->itemid, 1);
593 ipmi_request_free(request);
594 continue;
595 }
596 break;
597 }
598
599 ipmi_poller_send_request(poller, request);
600 break;
601 }
602 }
603
604 /******************************************************************************
605 * *
606 * Function: ipmi_manager_cache_host *
607 * *
608 * Purpose: caches host to keep local copy of its availability data *
609 * *
610 * Parameters: manager - [IN] the IPMI manager *
611 * hostid - [IN] the host identifier *
612 * now - [IN] the current time *
613 * *
614 * Return value: The cached host. *
615 * *
616 ******************************************************************************/
ipmi_manager_cache_host(zbx_ipmi_manager_t * manager,zbx_uint64_t hostid,int now)617 static zbx_ipmi_manager_host_t *ipmi_manager_cache_host(zbx_ipmi_manager_t *manager, zbx_uint64_t hostid, int now)
618 {
619 zbx_ipmi_manager_host_t *host;
620
621 if (NULL == (host = (zbx_ipmi_manager_host_t *)zbx_hashset_search(&manager->hosts, &hostid)))
622 {
623 zbx_ipmi_manager_host_t host_local;
624
625 host_local.hostid = hostid;
626 host = (zbx_ipmi_manager_host_t *)zbx_hashset_insert(&manager->hosts, &host_local, sizeof(host_local));
627
628 host->disable_until = 0;
629 host->poller = ipmi_manager_get_host_poller(manager);
630 }
631
632 host->lastcheck = now;
633
634 return host;
635 }
636
637 /******************************************************************************
638 * *
639 * Function: ipmi_manager_update_host *
640 * *
641 * Purpose: updates cached host *
642 * *
643 * Parameters: manager - [IN] the IPMI manager *
644 * host - [IN] the host *
645 * *
646 ******************************************************************************/
ipmi_manager_update_host(zbx_ipmi_manager_t * manager,const DC_HOST * host)647 static void ipmi_manager_update_host(zbx_ipmi_manager_t *manager, const DC_HOST *host)
648 {
649 zbx_ipmi_manager_host_t *ipmi_host;
650
651 if (NULL == (ipmi_host = (zbx_ipmi_manager_host_t *)zbx_hashset_search(&manager->hosts, &host->hostid)))
652 {
653 THIS_SHOULD_NEVER_HAPPEN;
654 return;
655 }
656
657 ipmi_host->disable_until = host->ipmi_disable_until;
658 }
659
660 /******************************************************************************
661 * *
662 * Function: ipmi_manager_activate_host *
663 * *
664 * Purpose: tries to activate item's host after receiving response *
665 * *
666 * Parameters: manager - [IN] the IPMI manager *
667 * itemid - [IN] the item identifier *
668 * ts - [IN] the activation timestamp *
669 * *
670 ******************************************************************************/
ipmi_manager_activate_host(zbx_ipmi_manager_t * manager,zbx_uint64_t itemid,zbx_timespec_t * ts)671 static void ipmi_manager_activate_host(zbx_ipmi_manager_t *manager, zbx_uint64_t itemid, zbx_timespec_t *ts)
672 {
673 DC_ITEM item;
674 int errcode;
675
676 DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
677
678 zbx_activate_item_host(&item, ts);
679 ipmi_manager_update_host(manager, &item.host);
680
681 DCconfig_clean_items(&item, &errcode, 1);
682 }
683
684 /******************************************************************************
685 * *
686 * Function: ipmi_manager_deactivate_host *
687 * *
688 * Purpose: tries to deactivate item's host after receiving host level error *
689 * *
690 * Parameters: manager - [IN] the IPMI manager *
691 * itemid - [IN] the item identifier *
692 * ts - [IN] the deactivation timestamp *
693 * error - [IN] the error *
694 * *
695 ******************************************************************************/
ipmi_manager_deactivate_host(zbx_ipmi_manager_t * manager,zbx_uint64_t itemid,zbx_timespec_t * ts,const char * error)696 static void ipmi_manager_deactivate_host(zbx_ipmi_manager_t *manager, zbx_uint64_t itemid, zbx_timespec_t *ts,
697 const char *error)
698 {
699 DC_ITEM item;
700 int errcode;
701
702 DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
703
704 zbx_deactivate_item_host(&item, ts, error);
705 ipmi_manager_update_host(manager, &item.host);
706
707 DCconfig_clean_items(&item, &errcode, 1);
708 }
709
710 /******************************************************************************
711 * *
712 * Function: ipmi_manager_serialize_request *
713 * *
714 * Purpose: serializes IPMI poll and discovery requests *
715 * *
716 * Parameters: item - [IN] the item to poll *
717 * command - [IN] the command to execute *
718 * key - [IN] a valid item key *
719 * message - [OUT] the message *
720 * *
721 ******************************************************************************/
ipmi_manager_serialize_request(const DC_ITEM * item,zbx_ipc_message_t * message)722 static void ipmi_manager_serialize_request(const DC_ITEM *item, zbx_ipc_message_t *message)
723 {
724 zbx_uint32_t size;
725
726 size = zbx_ipmi_serialize_request(&message->data, item->host.hostid, item->itemid, item->interface.addr,
727 item->interface.port, item->host.ipmi_authtype, item->host.ipmi_privilege,
728 item->host.ipmi_username, item->host.ipmi_password, item->ipmi_sensor, 0, item->key_orig);
729
730 message->code = ZBX_IPC_IPMI_VALUE_REQUEST;
731
732 message->size = size;
733 }
734
735 /******************************************************************************
736 * *
737 * Function: ipmi_manager_schedule_request *
738 * *
739 * Purpose: schedules request to the host *
740 * *
741 * Parameters: manager - [IN] the IPMI manager *
742 * hostid - [IN] the target host id *
743 * request - [IN] the request to schedule *
744 * now - [IN] the current timestamp *
745 * *
746 ******************************************************************************/
ipmi_manager_schedule_request(zbx_ipmi_manager_t * manager,zbx_uint64_t hostid,zbx_ipmi_request_t * request,int now)747 static void ipmi_manager_schedule_request(zbx_ipmi_manager_t *manager, zbx_uint64_t hostid,
748 zbx_ipmi_request_t *request, int now)
749 {
750 zbx_ipmi_manager_host_t *host;
751
752 host = ipmi_manager_cache_host(manager, hostid, now);
753 ipmi_poller_schedule_request(host->poller, request);
754 }
755
756 /******************************************************************************
757 * *
758 * Function: ipmi_manager_schedule_requests *
759 * *
760 * Purpose: either sends or queues IPMI poll requests from configuration *
761 * cache IPMI poller queue *
762 * *
763 * Parameters: manager - [IN] the IPMI manager *
764 * now - [IN] current time *
765 * nextcheck - [OUT] time when the next IPMI check is scheduled *
766 * in configuration cache IPMI poller queue *
767 * *
768 * Return value: The number of requests scheduled. *
769 * *
770 ******************************************************************************/
ipmi_manager_schedule_requests(zbx_ipmi_manager_t * manager,int now,int * nextcheck)771 static int ipmi_manager_schedule_requests(zbx_ipmi_manager_t *manager, int now, int *nextcheck)
772 {
773 int i, num;
774 DC_ITEM items[MAX_POLLER_ITEMS];
775 zbx_ipmi_request_t *request;
776 char *error = NULL;
777
778 num = DCconfig_get_ipmi_poller_items(now, items, MAX_POLLER_ITEMS, nextcheck);
779
780 for (i = 0; i < num; i++)
781 {
782 zbx_timespec_t ts;
783 unsigned char state = ITEM_STATE_NOTSUPPORTED;
784 int errcode = CONFIG_ERROR;
785
786 if (FAIL == zbx_ipmi_port_expand_macros(items[i].host.hostid, items[i].interface.port_orig,
787 &items[i].interface.port, &error))
788 {
789
790 zbx_timespec(&ts);
791 zbx_preprocess_item_value(items[i].itemid, items[i].host.hostid, items[i].value_type,
792 items[i].flags, NULL, &ts, state, error);
793 DCrequeue_items(&items[i].itemid, &state, &ts.sec, &errcode, 1);
794 zbx_free(error);
795 continue;
796 }
797
798 request = ipmi_request_create(items[i].host.hostid);
799 request->itemid = items[i].itemid;
800 request->item_state = items[i].state;
801 request->item_flags = items[i].flags;
802 ipmi_manager_serialize_request(&items[i], &request->message);
803 ipmi_manager_schedule_request(manager, items[i].host.hostid, request, now);
804 }
805
806 zbx_preprocessor_flush();
807 DCconfig_clean_items(items, NULL, num);
808
809 return num;
810 }
811
812 /******************************************************************************
813 * *
814 * Function: ipmi_manager_process_client_request *
815 * *
816 * Purpose: forwards IPMI request to the poller managing the specified host *
817 * *
818 * Parameters: manager - [IN] the IPMI manager *
819 * client - [IN] the client asking to execute IPMI request *
820 * message - [IN] the request message *
821 * now - [IN] the current time *
822 * code - [IN] the request message code *
823 * *
824 ******************************************************************************/
ipmi_manager_process_client_request(zbx_ipmi_manager_t * manager,zbx_ipc_client_t * client,zbx_ipc_message_t * message,int now,int code)825 static void ipmi_manager_process_client_request(zbx_ipmi_manager_t *manager, zbx_ipc_client_t *client,
826 zbx_ipc_message_t *message, int now, int code)
827 {
828 zbx_ipmi_request_t *request;
829 zbx_uint64_t hostid;
830
831 zbx_ipmi_deserialize_request_objectid(message->data, &hostid);
832
833 zbx_ipc_client_addref(client);
834
835 request = ipmi_request_create(0);
836 request->client = client;
837 zbx_ipc_message_copy(&request->message, message);
838 request->message.code = code;
839
840 ipmi_manager_schedule_request(manager, hostid, request, now);
841 }
842
843 /******************************************************************************
844 * *
845 * Function: ipmi_manager_process_client_result *
846 * *
847 * Purpose: forwards result of request to the client *
848 * *
849 * Parameters: manager - [IN] the IPMI manager *
850 * client - [IN] the IPMI poller client *
851 * message - [IN] the command result message *
852 * now - [IN] the current time *
853 * code - [IN] the result message code *
854 * *
855 ******************************************************************************/
ipmi_manager_process_client_result(zbx_ipmi_manager_t * manager,zbx_ipc_client_t * client,zbx_ipc_message_t * message,int now,int code)856 static void ipmi_manager_process_client_result(zbx_ipmi_manager_t *manager, zbx_ipc_client_t *client,
857 zbx_ipc_message_t *message, int now, int code)
858 {
859 zbx_ipmi_poller_t *poller;
860
861 if (NULL == (poller = ipmi_manager_get_poller_by_client(manager, client)))
862 {
863 THIS_SHOULD_NEVER_HAPPEN;
864 return;
865 }
866
867 if (SUCCEED == zbx_ipc_client_connected(poller->request->client))
868 {
869 zbx_ipc_client_send(poller->request->client, code, message->data, message->size);
870 zbx_ipc_client_release(poller->request->client);
871 }
872
873 ipmi_poller_free_request(poller);
874 ipmi_manager_process_poller_queue(manager, poller, now);
875 }
876
877 /******************************************************************************
878 * *
879 * Function: ipmi_manager_process_value_result *
880 * *
881 * Purpose: processes IPMI check result received from IPMI poller *
882 * *
883 * Parameters: manager - [IN] the IPMI manager *
884 * client - [IN] the client (IPMI poller) *
885 * message - [IN] the received ZBX_IPC_IPMI_VALUE_RESULT message*
886 * now - [IN] the current time *
887 * *
888 ******************************************************************************/
ipmi_manager_process_value_result(zbx_ipmi_manager_t * manager,zbx_ipc_client_t * client,zbx_ipc_message_t * message,int now)889 static void ipmi_manager_process_value_result(zbx_ipmi_manager_t *manager, zbx_ipc_client_t *client,
890 zbx_ipc_message_t *message, int now)
891 {
892 char *value;
893 zbx_timespec_t ts;
894 unsigned char state;
895 int errcode;
896 AGENT_RESULT result;
897 zbx_ipmi_poller_t *poller;
898 zbx_uint64_t itemid;
899 unsigned char flags;
900
901 if (NULL == (poller = ipmi_manager_get_poller_by_client(manager, client)))
902 {
903 THIS_SHOULD_NEVER_HAPPEN;
904 return;
905 }
906
907 if (NULL != poller->request->client)
908 {
909 ipmi_manager_process_client_result(manager, client, message, now, ZBX_IPC_IPMI_VALUE_RESULT);
910 return;
911 }
912
913 itemid = poller->request->itemid;
914 flags = poller->request->item_flags;
915
916 zbx_ipmi_deserialize_result(message->data, &ts, &errcode, &value);
917
918 /* update host availability */
919 switch (errcode)
920 {
921 case SUCCEED:
922 case NOTSUPPORTED:
923 case AGENT_ERROR:
924 ipmi_manager_activate_host(manager, itemid, &ts);
925 break;
926 case NETWORK_ERROR:
927 case GATEWAY_ERROR:
928 case TIMEOUT_ERROR:
929 ipmi_manager_deactivate_host(manager, itemid, &ts, value);
930 break;
931 case CONFIG_ERROR:
932 /* nothing to do */
933 break;
934 }
935
936 /* add received data to history cache */
937 switch (errcode)
938 {
939 case SUCCEED:
940 state = ITEM_STATE_NORMAL;
941 if (NULL != value)
942 {
943 init_result(&result);
944 SET_TEXT_RESULT(&result, value);
945 value = NULL;
946 zbx_preprocess_item_value(itemid, poller->request->hostid, ITEM_VALUE_TYPE_TEXT, flags,
947 &result, &ts, state, NULL);
948 free_result(&result);
949 }
950 break;
951
952 case NOTSUPPORTED:
953 case AGENT_ERROR:
954 case CONFIG_ERROR:
955 state = ITEM_STATE_NOTSUPPORTED;
956 zbx_preprocess_item_value(itemid, poller->request->hostid, ITEM_VALUE_TYPE_TEXT, flags, NULL,
957 &ts, state, value);
958 break;
959 default:
960 /* don't change item's state when network related error occurs */
961 break;
962 }
963
964 zbx_free(value);
965
966 /* put back the item in configuration cache IPMI poller queue */
967 DCrequeue_items(&itemid, &state, &ts.sec, &errcode, 1);
968
969 ipmi_poller_free_request(poller);
970 ipmi_manager_process_poller_queue(manager, poller, now);
971 }
972
ZBX_THREAD_ENTRY(ipmi_manager_thread,args)973 ZBX_THREAD_ENTRY(ipmi_manager_thread, args)
974 {
975 zbx_ipc_service_t ipmi_service;
976 char *error = NULL;
977 zbx_ipc_client_t *client;
978 zbx_ipc_message_t *message;
979 zbx_ipmi_manager_t ipmi_manager;
980 zbx_ipmi_poller_t *poller;
981 int ret, nextcheck, timeout, nextcleanup, polled_num = 0, scheduled_num = 0, now;
982 double time_stat, time_idle = 0, time_now, sec;
983
984 #define STAT_INTERVAL 5 /* if a process is busy and does not sleep then update status not faster than */
985 /* once in STAT_INTERVAL seconds */
986
987 process_type = ((zbx_thread_args_t *)args)->process_type;
988 server_num = ((zbx_thread_args_t *)args)->server_num;
989 process_num = ((zbx_thread_args_t *)args)->process_num;
990
991 zbx_setproctitle("%s #%d starting", get_process_type_string(process_type), process_num);
992
993 zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
994 server_num, get_process_type_string(process_type), process_num);
995
996 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
997
998 if (FAIL == zbx_ipc_service_start(&ipmi_service, ZBX_IPC_SERVICE_IPMI, &error))
999 {
1000 zabbix_log(LOG_LEVEL_CRIT, "cannot start IPMI service: %s", error);
1001 zbx_free(error);
1002 exit(EXIT_FAILURE);
1003 }
1004
1005 ipmi_manager_init(&ipmi_manager);
1006
1007 DBconnect(ZBX_DB_CONNECT_NORMAL);
1008
1009 nextcleanup = time(NULL) + ZBX_IPMI_MANAGER_CLEANUP_DELAY;
1010
1011 time_stat = zbx_time();
1012
1013 zbx_setproctitle("%s #%d started", get_process_type_string(process_type), process_num);
1014
1015 while (ZBX_IS_RUNNING())
1016 {
1017 time_now = zbx_time();
1018 now = time_now;
1019
1020 if (STAT_INTERVAL < time_now - time_stat)
1021 {
1022 zbx_setproctitle("%s #%d [scheduled %d, polled %d values, idle " ZBX_FS_DBL " sec during "
1023 ZBX_FS_DBL " sec]", get_process_type_string(process_type), process_num,
1024 scheduled_num, polled_num, time_idle, time_now - time_stat);
1025
1026 time_stat = time_now;
1027 time_idle = 0;
1028 polled_num = 0;
1029 scheduled_num = 0;
1030 }
1031
1032 /* manager -> client */
1033 scheduled_num += ipmi_manager_schedule_requests(&ipmi_manager, now, &nextcheck);
1034
1035 if (FAIL != nextcheck)
1036 timeout = (nextcheck > now ? nextcheck - now : 0);
1037 else
1038 timeout = ZBX_IPMI_MANAGER_DELAY;
1039
1040 if (ZBX_IPMI_MANAGER_DELAY < timeout)
1041 timeout = ZBX_IPMI_MANAGER_DELAY;
1042
1043 update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
1044 ret = zbx_ipc_service_recv(&ipmi_service, timeout, &client, &message);
1045 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
1046 sec = zbx_time();
1047 zbx_update_env(sec);
1048
1049 if (ZBX_IPC_RECV_IMMEDIATE != ret)
1050 time_idle += sec - time_now;
1051
1052 if (NULL != message)
1053 {
1054 switch (message->code)
1055 {
1056 /* poller -> manager */
1057 case ZBX_IPC_IPMI_REGISTER:
1058 if (NULL != (poller = ipmi_manager_register_poller(&ipmi_manager, client,
1059 message)))
1060 {
1061 ipmi_manager_process_poller_queue(&ipmi_manager, poller, now);
1062 }
1063 break;
1064 /* client -> manager */
1065 case ZBX_IPC_IPMI_VALUE_REQUEST:
1066 ipmi_manager_process_client_request(&ipmi_manager, client, message, now,
1067 ZBX_IPC_IPMI_VALUE_REQUEST);
1068 break;
1069 /* poller -> manager or poller -> manager -> client if value request sent by client */
1070 case ZBX_IPC_IPMI_VALUE_RESULT:
1071 ipmi_manager_process_value_result(&ipmi_manager, client, message, now);
1072 polled_num++;
1073 break;
1074 /* client -> manager */
1075 case ZBX_IPC_IPMI_SCRIPT_REQUEST:
1076 ipmi_manager_process_client_request(&ipmi_manager, client, message, now,
1077 ZBX_IPC_IPMI_COMMAND_REQUEST);
1078 break;
1079 /* poller -> manager -> client */
1080 case ZBX_IPC_IPMI_COMMAND_RESULT:
1081 ipmi_manager_process_client_result(&ipmi_manager, client, message, now,
1082 ZBX_IPC_IPMI_SCRIPT_RESULT);
1083 }
1084
1085 zbx_ipc_message_free(message);
1086 }
1087
1088 if (NULL != client)
1089 zbx_ipc_client_release(client);
1090
1091 if (now >= nextcleanup)
1092 {
1093 ipmi_manager_host_cleanup(&ipmi_manager, now);
1094 nextcleanup = now + ZBX_IPMI_MANAGER_CLEANUP_DELAY;
1095 }
1096 }
1097
1098 zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
1099
1100 while (1)
1101 zbx_sleep(SEC_PER_MIN);
1102
1103 zbx_ipc_service_close(&ipmi_service);
1104 ipmi_manager_destroy(&ipmi_manager);
1105 #undef STAT_INTERVAL
1106 }
1107
1108 #endif
1109