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