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 "checks_ipmi.h"
21
22 #ifdef HAVE_OPENIPMI
23
24 /* Theoretically it should be enough max 16 bytes for sensor ID and terminating '\0' (see SDR record format in IPMI */
25 /* v2 spec). OpenIPMI author Corey Minyard explained at */
26 /* www.mail-archive.com/openipmi-developer@lists.sourceforge.net/msg02013.html: */
27 /* "...Since you can use BCD and the field is 16 bytes max, you can get up to 32 bytes in the ID string. Adding the */
28 /* sensor sharing and that's another three bytes (I believe 142 is the maximum number you can get), so 35 bytes is */
29 /* the maximum, I believe." */
30 #define IPMI_SENSOR_ID_SZ 36
31
32 /* delete inactive hosts after this period */
33 #define INACTIVE_HOST_LIMIT 3 * SEC_PER_HOUR
34
35 #define IPMI_THRESHOLDS_NUM 6
36 #define MAX_DISCRETE_STATES 15
37
38 #define ZBX_IPMI_TAG_ID "id"
39 #define ZBX_IPMI_TAG_NAME "name"
40 #define ZBX_IPMI_TAG_SENSOR "sensor"
41 #define ZBX_IPMI_TAG_READING "reading"
42 #define ZBX_IPMI_TAG_STATE "state"
43 #define ZBX_IPMI_TAG_TYPE "type"
44 #define ZBX_IPMI_TAG_TEXT "text"
45
46 #define ZBX_IPMI_TAG_UNITS "units"
47 #define ZBX_IPMI_TAG_VALUE "value"
48 #define ZBX_IPMI_TAG_THRESHOLD "threshold"
49 #define ZBX_IPMI_TAG_LOWER "lower"
50 #define ZBX_IPMI_TAG_UPPER "upper"
51 #define ZBX_IPMI_TAG_NON_CRIT "non_crit"
52 #define ZBX_IPMI_TAG_CRIT "crit"
53 #define ZBX_IPMI_TAG_NON_RECOVER "non_recover"
54
55 #define ZBX_IPMI_THRESHOLD_STATUS_DISABLED 0
56 #define ZBX_IPMI_THRESHOLD_STATUS_ENABLED 1
57
58 #include "log.h"
59
60 #include <OpenIPMI/ipmiif.h>
61 #include <OpenIPMI/ipmi_posix.h>
62 #include <OpenIPMI/ipmi_lan.h>
63 #include <OpenIPMI/ipmi_auth.h>
64
65 #define RETURN_IF_CB_DATA_NULL(x, y) \
66 if (NULL == (x)) \
67 { \
68 zabbix_log(LOG_LEVEL_WARNING, "%s() called with cb_data:NULL", (y)); \
69 return; \
70 }
71
72 typedef union
73 {
74 double threshold;
75 zbx_uint64_t discrete;
76 }
77 zbx_ipmi_sensor_value_t;
78
79 typedef struct
80 {
81 int status; /* Is this threshold enabled? */
82 double val;
83 }
84 zbx_ipmi_sensor_threshold_t;
85
86 typedef struct
87 {
88 ipmi_sensor_t *sensor;
89 char id[IPMI_SENSOR_ID_SZ];
90 enum ipmi_str_type_e id_type; /* For sensors IPMI specifications mention Unicode, BCD plus, */
91 /* 6-bit ASCII packed, 8-bit ASCII+Latin1. */
92 int id_sz; /* "id" value length in bytes */
93 zbx_ipmi_sensor_value_t value;
94 int reading_type; /* "Event/Reading Type Code", e.g. Threshold, */
95 /* Discrete, 'digital' Discrete. */
96 int type; /* "Sensor Type Code", e.g. Temperature, Voltage, */
97 /* Current, Fan, Physical Security (Chassis Intrusion), etc. */
98 char *full_name;
99 int state;
100 zbx_ipmi_sensor_threshold_t thresholds[IPMI_THRESHOLDS_NUM];
101 }
102 zbx_ipmi_sensor_t;
103
104 typedef struct
105 {
106 ipmi_control_t *control;
107 char *c_name;
108 int num_values;
109 int *val;
110 char *full_name;
111 }
112 zbx_ipmi_control_t;
113
114 typedef struct zbx_ipmi_host
115 {
116 char *ip;
117 int port;
118 int authtype;
119 int privilege;
120 int ret;
121 char *username;
122 char *password;
123 zbx_ipmi_sensor_t *sensors;
124 zbx_ipmi_control_t *controls;
125 int sensor_count;
126 int control_count;
127 ipmi_con_t *con;
128 int domain_up;
129 int done;
130 time_t lastaccess; /* Time of last access attempt. Used to detect and delete inactive */
131 /* (disabled) IPMI hosts from OpenIPMI to stop polling them. */
132 unsigned int domain_nr; /* Domain number. It is converted to text string and used as */
133 /* domain name. */
134 char *err;
135 struct zbx_ipmi_host *next;
136 }
137 zbx_ipmi_host_t;
138
139 static unsigned int domain_nr = 0; /* for making a sequence of domain names "0", "1", "2", ... */
140 static zbx_ipmi_host_t *hosts = NULL; /* head of single-linked list of monitored hosts */
141 static os_handler_t *os_hnd;
142
zbx_sensor_id_to_str(char * str,size_t str_sz,const char * id,enum ipmi_str_type_e id_type,int id_sz)143 static char *zbx_sensor_id_to_str(char *str, size_t str_sz, const char *id, enum ipmi_str_type_e id_type, int id_sz)
144 {
145 /* minimum size of 'str' buffer, str_sz, is 35 bytes to avoid truncation */
146 int i;
147 char *p = str;
148 size_t id_len;
149
150 if (0 == id_sz) /* id is meaningful only if length > 0 (see SDR record format in IPMI v2 spec) */
151 {
152 *str = '\0';
153 return str;
154 }
155
156 if (IPMI_SENSOR_ID_SZ < id_sz)
157 {
158 zbx_strlcpy(str, "ILLEGAL-SENSOR-ID-SIZE", str_sz);
159 THIS_SHOULD_NEVER_HAPPEN;
160 return str;
161 }
162
163 switch (id_type)
164 {
165 case IPMI_ASCII_STR:
166 case IPMI_UNICODE_STR:
167 id_len = str_sz > (size_t)id_sz ? (size_t)id_sz : str_sz - 1;
168 memcpy(str, id, id_len);
169 *(str + id_len) = '\0';
170 break;
171 case IPMI_BINARY_STR:
172 /* "BCD Plus" or "6-bit ASCII packed" encoding - print it as a hex string. */
173
174 *p++ = '0'; /* prefix to distinguish from ASCII/Unicode strings */
175 *p++ = 'x';
176 for (i = 0; i < id_sz; i++, p += 2)
177 {
178 zbx_snprintf(p, str_sz - (size_t)(2 + i + i), "%02x",
179 (unsigned int)(unsigned char)*(id + i));
180 }
181 *p = '\0';
182 break;
183 default:
184 zbx_strlcpy(str, "ILLEGAL-SENSOR-ID-TYPE", str_sz);
185 THIS_SHOULD_NEVER_HAPPEN;
186 }
187 return str;
188 }
189
190 /******************************************************************************
191 * *
192 * Function: zbx_get_ipmi_host *
193 * *
194 * Purpose: Find element in the global list 'hosts' using parameters as *
195 * search criteria *
196 * *
197 * Return value: pointer to list element with host data *
198 * NULL if not found *
199 * *
200 ******************************************************************************/
zbx_get_ipmi_host(const char * ip,const int port,int authtype,int privilege,const char * username,const char * password)201 static zbx_ipmi_host_t *zbx_get_ipmi_host(const char *ip, const int port, int authtype, int privilege,
202 const char *username, const char *password)
203 {
204 zbx_ipmi_host_t *h;
205
206 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __func__, ip, port);
207
208 h = hosts;
209 while (NULL != h)
210 {
211 if (0 == strcmp(ip, h->ip) && port == h->port && authtype == h->authtype &&
212 privilege == h->privilege && 0 == strcmp(username, h->username) &&
213 0 == strcmp(password, h->password))
214 {
215 break;
216 }
217
218 h = h->next;
219 }
220
221 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)h);
222
223 return h;
224 }
225
226 /******************************************************************************
227 * *
228 * Function: zbx_allocate_ipmi_host *
229 * *
230 * Purpose: create a new element in the global list 'hosts' *
231 * *
232 * Return value: pointer to the new list element with host data *
233 * *
234 ******************************************************************************/
zbx_allocate_ipmi_host(const char * ip,int port,int authtype,int privilege,const char * username,const char * password)235 static zbx_ipmi_host_t *zbx_allocate_ipmi_host(const char *ip, int port, int authtype, int privilege,
236 const char *username, const char *password)
237 {
238 zbx_ipmi_host_t *h;
239
240 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __func__, ip, port);
241
242 h = (zbx_ipmi_host_t *)zbx_malloc(NULL, sizeof(zbx_ipmi_host_t));
243
244 memset(h, 0, sizeof(zbx_ipmi_host_t));
245
246 h->ip = strdup(ip);
247 h->port = port;
248 h->authtype = authtype;
249 h->privilege = privilege;
250 h->username = strdup(username);
251 h->password = strdup(password);
252 h->domain_nr = domain_nr++;
253
254 h->next = hosts;
255 hosts = h;
256
257 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)h);
258
259 return h;
260 }
261
zbx_get_ipmi_sensor(const zbx_ipmi_host_t * h,const ipmi_sensor_t * sensor)262 static zbx_ipmi_sensor_t *zbx_get_ipmi_sensor(const zbx_ipmi_host_t *h, const ipmi_sensor_t *sensor)
263 {
264 int i;
265 zbx_ipmi_sensor_t *s = NULL;
266
267 zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p psensor:%p", __func__, (const void *)h,
268 (const void *)sensor);
269
270 for (i = 0; i < h->sensor_count; i++)
271 {
272 if (h->sensors[i].sensor == sensor)
273 {
274 s = &h->sensors[i];
275 break;
276 }
277 }
278
279 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
280
281 return s;
282 }
283
zbx_get_ipmi_sensor_by_id(const zbx_ipmi_host_t * h,const char * id)284 static zbx_ipmi_sensor_t *zbx_get_ipmi_sensor_by_id(const zbx_ipmi_host_t *h, const char *id)
285 {
286 int i;
287 zbx_ipmi_sensor_t *s = NULL;
288
289 zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id, h->ip, h->port);
290
291 for (i = 0; i < h->sensor_count; i++)
292 {
293 if (0 == strcmp(h->sensors[i].id, id))
294 {
295 /* Some devices present a sensor as both a threshold sensor and a discrete sensor. We work */
296 /* around this by preferring the threshold sensor in such case, as it is most widely used. */
297
298 s = &h->sensors[i];
299
300 if (IPMI_EVENT_READING_TYPE_THRESHOLD == s->reading_type)
301 break;
302 }
303 }
304
305 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
306
307 return s;
308 }
309
zbx_get_ipmi_sensor_by_full_name(const zbx_ipmi_host_t * h,const char * full_name)310 static zbx_ipmi_sensor_t *zbx_get_ipmi_sensor_by_full_name(const zbx_ipmi_host_t *h, const char *full_name)
311 {
312 int i;
313 zbx_ipmi_sensor_t *s = NULL;
314
315 zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d", __func__, full_name, h->ip, h->port);
316
317 for (i = 0; i < h->sensor_count; i++)
318 {
319 if (0 == strcmp(h->sensors[i].full_name, full_name))
320 {
321 s = &h->sensors[i];
322 break;
323 }
324 }
325
326 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
327
328 return s;
329 }
330
331 /******************************************************************************
332 * *
333 * Function: get_domain_offset *
334 * *
335 * Purpose: Check if an item name starts from domain name and find the domain *
336 * name length *
337 * *
338 * Parameters: h - [IN] ipmi host *
339 * full_name - [IN] item name *
340 * *
341 * Return value: 0 or offset for skipping the domain name *
342 * *
343 ******************************************************************************/
get_domain_offset(const zbx_ipmi_host_t * h,const char * full_name)344 static size_t get_domain_offset(const zbx_ipmi_host_t *h, const char *full_name)
345 {
346 char domain_name[IPMI_DOMAIN_NAME_LEN];
347 size_t offset;
348
349 zbx_snprintf(domain_name, sizeof(domain_name), "%u", h->domain_nr);
350 offset = strlen(domain_name);
351
352 if (offset >= strlen(full_name) || 0 != strncmp(domain_name, full_name, offset))
353 offset = 0;
354
355 return offset;
356 }
357 /******************************************************************************
358 * *
359 * Function: zbx_get_sensor_id *
360 * *
361 * Purpose: Converts sensor id to printable string and return id_type *
362 * *
363 * Parameters: sensor - [IN] ipmi sensor *
364 * id - [OUT] sensor id *
365 * sz - [IN] sensor id buffer length *
366 * id_sz - [OUT] sensor id length *
367 * id_type - [OUT] type of sensor id *
368 * id_str - [OUT] sensor id string *
369 * id_str_sz - [IN] sensor id string buffer length *
370 * *
371 * Return value: pointer to sensor id string *
372 * *
373 ******************************************************************************/
zbx_get_sensor_id(ipmi_sensor_t * sensor,char * id,int sz,int * id_sz,enum ipmi_str_type_e * id_type,char * id_str,int id_str_sz)374 static char *zbx_get_sensor_id(ipmi_sensor_t *sensor, char *id, int sz, int *id_sz, enum ipmi_str_type_e *id_type,
375 char *id_str, int id_str_sz )
376 {
377 *id_sz = ipmi_sensor_get_id_length(sensor);
378 memset(id, 0, (size_t)sz);
379 ipmi_sensor_get_id(sensor, id, sz);
380 *id_type = ipmi_sensor_get_id_type(sensor);
381 return zbx_sensor_id_to_str(id_str, (size_t)id_str_sz, id, *id_type, *id_sz);
382 }
383
zbx_allocate_ipmi_sensor(zbx_ipmi_host_t * h,ipmi_sensor_t * sensor)384 static zbx_ipmi_sensor_t *zbx_allocate_ipmi_sensor(zbx_ipmi_host_t *h, ipmi_sensor_t *sensor)
385 {
386 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
387 zbx_ipmi_sensor_t *s;
388 char id[IPMI_SENSOR_ID_SZ];
389 enum ipmi_str_type_e id_type;
390 int id_sz;
391 size_t sz;
392 char full_name[IPMI_SENSOR_NAME_LEN];
393 int i;
394
395 zbx_get_sensor_id(sensor, id, sizeof(id), &id_sz, &id_type, id_str, sizeof(id_str));
396 zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id_str, h->ip, h->port);
397
398 h->sensor_count++;
399 sz = (size_t)h->sensor_count * sizeof(zbx_ipmi_sensor_t);
400
401 if (NULL == h->sensors)
402 h->sensors = (zbx_ipmi_sensor_t *)zbx_malloc(h->sensors, sz);
403 else
404 h->sensors = (zbx_ipmi_sensor_t *)zbx_realloc(h->sensors, sz);
405
406 s = &h->sensors[h->sensor_count - 1];
407 s->sensor = sensor;
408 memcpy(s->id, id, sizeof(id));
409 s->id_type = id_type;
410 s->id_sz = id_sz;
411 memset(&s->value, 0, sizeof(s->value));
412 s->reading_type = ipmi_sensor_get_event_reading_type(sensor);
413 s->type = ipmi_sensor_get_sensor_type(sensor);
414
415 ipmi_sensor_get_name(s->sensor, full_name, sizeof(full_name));
416 s->full_name = zbx_strdup(NULL, full_name + get_domain_offset(h, full_name));
417 for (i = IPMI_LOWER_NON_CRITICAL; i <= IPMI_UPPER_NON_RECOVERABLE; i++)
418 s->thresholds[i].status = ZBX_IPMI_THRESHOLD_STATUS_DISABLED;
419
420 zabbix_log(LOG_LEVEL_DEBUG, "Added sensor: host:'%s:%d' id_type:%d id_sz:%d id:'%s' reading_type:0x%x "
421 "('%s') type:0x%x ('%s') domain:'%u' name:'%s'", h->ip, h->port, (int)s->id_type, s->id_sz,
422 zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz),
423 (unsigned int)s->reading_type, ipmi_sensor_get_event_reading_type_string(s->sensor),
424 (unsigned int)s->type, ipmi_sensor_get_sensor_type_string(s->sensor), h->domain_nr,
425 s->full_name);
426
427 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)s);
428
429 return s;
430 }
431
zbx_delete_ipmi_sensor(zbx_ipmi_host_t * h,const ipmi_sensor_t * sensor)432 static void zbx_delete_ipmi_sensor(zbx_ipmi_host_t *h, const ipmi_sensor_t *sensor)
433 {
434 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
435 int i;
436 size_t sz;
437
438 zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p psensor:%p", __func__, (void *)h, (const void *)sensor);
439
440 for (i = 0; i < h->sensor_count; i++)
441 {
442 if (h->sensors[i].sensor != sensor)
443 continue;
444
445 sz = sizeof(zbx_ipmi_sensor_t);
446
447 zabbix_log(LOG_LEVEL_DEBUG, "sensor '%s@[%s]:%d' deleted",
448 zbx_sensor_id_to_str(id_str, sizeof(id_str), h->sensors[i].id, h->sensors[i].id_type,
449 h->sensors[i].id_sz), h->ip, h->port);
450
451 zbx_free(h->sensors[i].full_name);
452
453 h->sensor_count--;
454 if (h->sensor_count != i)
455 memmove(&h->sensors[i], &h->sensors[i + 1], sz * (size_t)(h->sensor_count - i));
456 h->sensors = (zbx_ipmi_sensor_t *)zbx_realloc(h->sensors, sz * (size_t)h->sensor_count);
457
458 break;
459 }
460
461 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
462 }
463
zbx_get_ipmi_control(const zbx_ipmi_host_t * h,const ipmi_control_t * control)464 static zbx_ipmi_control_t *zbx_get_ipmi_control(const zbx_ipmi_host_t *h, const ipmi_control_t *control)
465 {
466 int i;
467 zbx_ipmi_control_t *c = NULL;
468
469 zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p pcontrol:%p", __func__, (const void *)h, (const void *)control);
470
471 for (i = 0; i < h->control_count; i++)
472 {
473 if (h->controls[i].control == control)
474 {
475 c = &h->controls[i];
476 break;
477 }
478 }
479
480 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
481
482 return c;
483 }
484
zbx_get_ipmi_control_by_name(const zbx_ipmi_host_t * h,const char * c_name)485 static zbx_ipmi_control_t *zbx_get_ipmi_control_by_name(const zbx_ipmi_host_t *h, const char *c_name)
486 {
487 int i;
488 zbx_ipmi_control_t *c = NULL;
489
490 zabbix_log(LOG_LEVEL_DEBUG, "In %s() control: %s@[%s]:%d", __func__, c_name, h->ip, h->port);
491
492 for (i = 0; i < h->control_count; i++)
493 {
494 if (0 == strcmp(h->controls[i].c_name, c_name))
495 {
496 c = &h->controls[i];
497 break;
498 }
499 }
500
501 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
502
503 return c;
504 }
505
zbx_get_ipmi_control_by_full_name(const zbx_ipmi_host_t * h,const char * full_name)506 static zbx_ipmi_control_t *zbx_get_ipmi_control_by_full_name(const zbx_ipmi_host_t *h, const char *full_name)
507 {
508 int i;
509 zbx_ipmi_control_t *c = NULL;
510
511 zabbix_log(LOG_LEVEL_DEBUG, "In %s() control:'%s@[%s]:%d", __func__, full_name, h->ip, h->port);
512
513 for (i = 0; i < h->control_count; i++)
514 {
515 if (0 == strcmp(h->controls[i].full_name, full_name))
516 {
517 c = &h->controls[i];
518 break;
519 }
520 }
521
522 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
523
524 return c;
525 }
526
zbx_allocate_ipmi_control(zbx_ipmi_host_t * h,ipmi_control_t * control)527 static zbx_ipmi_control_t *zbx_allocate_ipmi_control(zbx_ipmi_host_t *h, ipmi_control_t *control)
528 {
529 size_t sz, dm_sz;
530 zbx_ipmi_control_t *c;
531 char *c_name = NULL;
532 char full_name[IPMI_SENSOR_NAME_LEN];
533
534 sz = (size_t)ipmi_control_get_id_length(control);
535 c_name = (char *)zbx_malloc(c_name, sz + 1);
536 ipmi_control_get_id(control, c_name, sz);
537
538 ipmi_control_get_name(control, full_name, sizeof(full_name));
539 dm_sz = get_domain_offset(h, full_name);
540
541 zabbix_log(LOG_LEVEL_DEBUG, "In %s() Added control: host'%s:%d' id:'%s' domain:'%u' name:'%s'",
542 __func__, h->ip, h->port, c_name, h->domain_nr, full_name + dm_sz);
543
544 h->control_count++;
545 sz = (size_t)h->control_count * sizeof(zbx_ipmi_control_t);
546
547 if (NULL == h->controls)
548 h->controls = (zbx_ipmi_control_t *)zbx_malloc(h->controls, sz);
549 else
550 h->controls = (zbx_ipmi_control_t *)zbx_realloc(h->controls, sz);
551
552 c = &h->controls[h->control_count - 1];
553
554 memset(c, 0, sizeof(zbx_ipmi_control_t));
555
556 c->control = control;
557 c->c_name = c_name;
558 c->num_values = ipmi_control_get_num_vals(control);
559 sz = sizeof(int) * (size_t)c->num_values;
560 c->val = (int *)zbx_malloc(c->val, sz);
561 memset(c->val, 0, sz);
562 c->full_name = zbx_strdup(NULL, full_name + dm_sz);
563
564 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)c);
565
566 return c;
567 }
568
zbx_delete_ipmi_control(zbx_ipmi_host_t * h,const ipmi_control_t * control)569 static void zbx_delete_ipmi_control(zbx_ipmi_host_t *h, const ipmi_control_t *control)
570 {
571 int i;
572 size_t sz;
573
574 zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p pcontrol:%p", __func__, (void *)h, (const void *)control);
575
576 for (i = 0; i < h->control_count; i++)
577 {
578 if (h->controls[i].control != control)
579 continue;
580
581 sz = sizeof(zbx_ipmi_control_t);
582
583 zabbix_log(LOG_LEVEL_DEBUG, "control '%s@[%s]:%d' deleted", h->controls[i].c_name, h->ip, h->port);
584
585 zbx_free(h->controls[i].c_name);
586 zbx_free(h->controls[i].val);
587 zbx_free(h->controls[i].full_name);
588
589 h->control_count--;
590 if (h->control_count != i)
591 memmove(&h->controls[i], &h->controls[i + 1], sz * (size_t)(h->control_count - i));
592 h->controls = (zbx_ipmi_control_t *)zbx_realloc(h->controls, sz * (size_t)h->control_count);
593
594 break;
595 }
596
597 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
598 }
599
600 /* callback function invoked from OpenIPMI */
zbx_got_thresholds_cb(ipmi_sensor_t * sensor,int err,ipmi_thresholds_t * th,void * cb_data)601 static void zbx_got_thresholds_cb(ipmi_sensor_t *sensor, int err, ipmi_thresholds_t *th, void *cb_data)
602 {
603 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
604 zbx_ipmi_sensor_t *s;
605 enum ipmi_thresh_e i;
606 int val, ret;
607
608 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
609
610 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' err:%d th:%p", __func__, h->ip, h->port, err, (void *)th);
611
612 if (0 != err)
613 {
614 zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
615
616 h->err = zbx_dsprintf(h->err, "error 0x%x while getting thresholds for sensor", (unsigned int)err);
617 h->ret = NOTSUPPORTED;
618 goto out;
619 }
620
621 if (NULL == (s = zbx_get_ipmi_sensor(h, sensor)))
622 {
623 char id[IPMI_SENSOR_ID_SZ];
624 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
625 int id_sz;
626 enum ipmi_str_type_e id_type;
627
628 THIS_SHOULD_NEVER_HAPPEN;
629 h->err = zbx_dsprintf(h->err, "fatal error: host:'[%s]:%d' sensor %s", h->ip, h->port,
630 zbx_get_sensor_id(sensor, id, sizeof(id), &id_sz, &id_type, id_str, sizeof(id_str)));
631
632 h->ret = NOTSUPPORTED;
633 goto out;
634 }
635
636 for (i = IPMI_LOWER_NON_CRITICAL; i <= IPMI_UPPER_NON_RECOVERABLE; i++)
637 {
638 double thr;
639
640 s->thresholds[i].status = ZBX_IPMI_THRESHOLD_STATUS_DISABLED;
641 ret = ipmi_sensor_threshold_readable(sensor, i, &val);
642 if (0 != ret || 0 == val)
643 continue;
644
645 if (0 == ipmi_threshold_get(th, i, &thr))
646 {
647 s->thresholds[i].status = ZBX_IPMI_THRESHOLD_STATUS_ENABLED;
648 s->thresholds[i].val = thr;
649 }
650 else
651 zabbix_log(LOG_LEVEL_DEBUG, "Threshold %s could not be fetched", ipmi_get_threshold_string(i));
652 }
653 out:
654 h->done = 1;
655
656 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
657 }
658
659 /*get sensor units full string*/
zbx_get_ipmi_units(ipmi_sensor_t * sensor)660 static char *zbx_get_ipmi_units(ipmi_sensor_t *sensor)
661 {
662 const char *base, *mod_use = "", *modifier = "", *rate;
663
664 if (0 != ipmi_sensor_get_percentage(sensor))
665 return zbx_dsprintf(NULL, "%%");
666
667 base = ipmi_sensor_get_base_unit_string(sensor);
668
669 switch (ipmi_sensor_get_modifier_unit_use(sensor))
670 {
671 case IPMI_MODIFIER_UNIT_NONE:
672 break;
673 case IPMI_MODIFIER_UNIT_BASE_DIV_MOD:
674 mod_use = "/";
675 modifier = ipmi_sensor_get_modifier_unit_string(sensor);
676 break;
677 case IPMI_MODIFIER_UNIT_BASE_MULT_MOD:
678 mod_use = "*";
679 modifier = ipmi_sensor_get_modifier_unit_string(sensor);
680 break;
681 default:
682 THIS_SHOULD_NEVER_HAPPEN;
683 }
684 rate = ipmi_sensor_get_rate_unit_string(sensor);
685
686 return zbx_dsprintf(NULL, "%s%s%s%s", base, mod_use, modifier, rate);
687 }
688
689 /* callback function invoked from OpenIPMI */
zbx_got_thresh_reading_cb(ipmi_sensor_t * sensor,int err,enum ipmi_value_present_e value_present,unsigned int raw_value,double val,ipmi_states_t * states,void * cb_data)690 static void zbx_got_thresh_reading_cb(ipmi_sensor_t *sensor, int err, enum ipmi_value_present_e value_present,
691 unsigned int raw_value, double val, ipmi_states_t *states, void *cb_data)
692 {
693 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
694 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
695 zbx_ipmi_sensor_t *s;
696
697 ZBX_UNUSED(raw_value);
698
699 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
700
701 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
702
703 if (0 != err)
704 {
705 zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
706
707 h->err = zbx_dsprintf(h->err, "error 0x%x while reading threshold sensor", (unsigned int)err);
708 h->ret = NOTSUPPORTED;
709 goto out;
710 }
711
712 if (0 == ipmi_is_sensor_scanning_enabled(states) || 0 != ipmi_is_initial_update_in_progress(states))
713 {
714 h->err = zbx_strdup(h->err, "sensor data is not available");
715 h->ret = NOTSUPPORTED;
716 goto out;
717 }
718
719 s = zbx_get_ipmi_sensor(h, sensor);
720
721 if (NULL == s)
722 {
723 THIS_SHOULD_NEVER_HAPPEN;
724 h->err = zbx_strdup(h->err, "fatal error");
725 h->ret = NOTSUPPORTED;
726 goto out;
727 }
728
729 switch (value_present)
730 {
731 case IPMI_NO_VALUES_PRESENT:
732 case IPMI_RAW_VALUE_PRESENT:
733 h->err = zbx_strdup(h->err, "no value present for threshold sensor");
734 h->ret = NOTSUPPORTED;
735 break;
736 case IPMI_BOTH_VALUES_PRESENT:
737 s->value.threshold = val;
738
739 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
740 {
741 char *units;
742 const char *e_string, *s_type_string, *s_reading_type_string;
743
744 e_string = ipmi_entity_get_entity_id_string(ipmi_sensor_get_entity(sensor));
745 s_type_string = ipmi_sensor_get_sensor_type_string(sensor);
746 s_reading_type_string = ipmi_sensor_get_event_reading_type_string(sensor);
747
748 units = zbx_get_ipmi_units(sensor);
749
750 zabbix_log(LOG_LEVEL_DEBUG, "Value [%s | %s | %s | %s | " ZBX_FS_DBL " %s]",
751 zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type,
752 s->id_sz), e_string, s_type_string, s_reading_type_string, val, units);
753
754 zbx_free(units);
755 }
756
757 s->state = 0;
758 if (IPMI_THRESHOLD_ACCESS_SUPPORT_NONE != ipmi_sensor_get_threshold_access(sensor))
759 {
760 int value, ret;
761 int i;
762
763 for (i = IPMI_LOWER_NON_CRITICAL; i <= IPMI_UPPER_NON_RECOVERABLE; i++)
764 {
765 ret = ipmi_sensor_threshold_reading_supported(sensor, i, &value);
766 if (0 != ret || 0 == value)
767 continue;
768 if (0 != ipmi_is_threshold_out_of_range(states, i))
769 s->state |= 1 << i;
770 }
771 }
772
773 break;
774 default:
775 THIS_SHOULD_NEVER_HAPPEN;
776 }
777 out:
778 h->done = 1;
779
780 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
781 }
782
783 /* callback function invoked from OpenIPMI */
zbx_got_discrete_states_cb(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)784 static void zbx_got_discrete_states_cb(ipmi_sensor_t *sensor, int err, ipmi_states_t *states, void *cb_data)
785 {
786 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
787 int id, i, val, ret, is_state_set;
788 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
789 zbx_ipmi_sensor_t *s;
790
791 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
792
793 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
794
795 if (0 == ipmi_is_sensor_scanning_enabled(states) || 0 != ipmi_is_initial_update_in_progress(states))
796 {
797 h->err = zbx_strdup(h->err, "sensor data is not available");
798 h->ret = NOTSUPPORTED;
799 goto out;
800 }
801
802 s = zbx_get_ipmi_sensor(h, sensor);
803
804 if (NULL == s)
805 {
806 THIS_SHOULD_NEVER_HAPPEN;
807 h->err = zbx_strdup(h->err, "fatal error");
808 h->ret = NOTSUPPORTED;
809 goto out;
810 }
811
812 if (0 != err)
813 {
814 h->err = zbx_dsprintf(h->err, "error 0x%x while reading a discrete sensor %s@[%s]:%d",
815 (unsigned int)err,
816 zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz), h->ip,
817 h->port);
818 h->ret = NOTSUPPORTED;
819 goto out;
820 }
821
822 id = ipmi_entity_get_entity_id(ipmi_sensor_get_entity(sensor));
823
824 /* Discrete values are 16-bit. We're storing them into a 64-bit uint. */
825
826 s->value.discrete = 0;
827 for (i = 0; i < MAX_DISCRETE_STATES; i++)
828 {
829 ret = ipmi_sensor_discrete_event_readable(sensor, i, &val);
830 if (0 != ret || 0 == val)
831 continue;
832
833 is_state_set = ipmi_is_state_set(states, i);
834
835 zabbix_log(LOG_LEVEL_DEBUG, "State [%s | %s | %s | %s | state %d value is %d]",
836 zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz),
837 ipmi_get_entity_id_string(id), ipmi_sensor_get_sensor_type_string(sensor),
838 ipmi_sensor_get_event_reading_type_string(sensor), i, is_state_set);
839
840 if (0 != is_state_set)
841 s->value.discrete |= 1 << i;
842 }
843 out:
844 h->done = 1;
845
846 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
847 }
848
849 /******************************************************************************
850 * *
851 * Function: zbx_perform_openipmi_ops *
852 * *
853 * Purpose: Pass control to OpenIPMI library to process events *
854 * *
855 * Return value: SUCCEED - no errors *
856 * FAIL - an error occurred while processing events *
857 * *
858 ******************************************************************************/
zbx_perform_openipmi_ops(zbx_ipmi_host_t * h,const char * func_name)859 static int zbx_perform_openipmi_ops(zbx_ipmi_host_t *h, const char *func_name)
860 {
861 struct timeval tv;
862
863 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p from %s()", __func__, h->ip, h->port,
864 (void *)h, func_name);
865
866 tv.tv_sec = 10; /* set timeout for one operation */
867 tv.tv_usec = 0;
868
869 while (0 == h->done)
870 {
871 int res;
872
873 if (0 == (res = os_hnd->perform_one_op(os_hnd, &tv)))
874 continue;
875
876 zabbix_log(LOG_LEVEL_DEBUG, "End %s() from %s(): error: %s", __func__, func_name, zbx_strerror(res));
877
878 return FAIL;
879 }
880
881 zabbix_log(LOG_LEVEL_DEBUG, "End %s() from %s()", __func__, func_name);
882
883 return SUCCEED;
884 }
885
886 /******************************************************************************
887 * *
888 * Function: zbx_perform_all_openipmi_ops *
889 * *
890 * Purpose: Pass control to OpenIPMI library to process all internal events *
891 * *
892 * Parameters: timeout - [IN] timeout (in seconds) for processing single *
893 * operation; processing multiple operations may *
894 * take more time *
895 * *
896 *****************************************************************************/
zbx_perform_all_openipmi_ops(int timeout)897 void zbx_perform_all_openipmi_ops(int timeout)
898 {
899 /* Before OpenIPMI v2.0.26, perform_one_op() did not modify timeout argument. */
900 /* Starting with OpenIPMI v2.0.26, perform_one_op() updates timeout argument. */
901 /* To make sure that the loop works consistently with all versions of OpenIPMI, */
902 /* initialize timeout argument for perform_one_op() inside the loop. */
903
904 for (;;)
905 {
906 struct timeval tv;
907 double start_time;
908 int res;
909
910 tv.tv_sec = timeout;
911 tv.tv_usec = 0;
912
913 start_time = zbx_time();
914
915 /* perform_one_op() returns 0 on success, errno on failure (timeout means success) */
916 if (0 != (res = os_hnd->perform_one_op(os_hnd, &tv)))
917 {
918 zabbix_log(LOG_LEVEL_DEBUG, "IPMI error: %s", zbx_strerror(res));
919 break;
920 }
921
922 /* If execution of perform_one_op() took more time than specified in timeout argument, assume that */
923 /* perform_one_op() timed out and break the loop. */
924 /* If it took less than specified in timeout argument, assume that some operation was performed and */
925 /* there may be more operations to be performed. */
926 if (zbx_time() - start_time >= timeout)
927 {
928 break;
929 }
930 }
931 }
932
zbx_read_ipmi_sensor(zbx_ipmi_host_t * h,const zbx_ipmi_sensor_t * s)933 static void zbx_read_ipmi_sensor(zbx_ipmi_host_t *h, const zbx_ipmi_sensor_t *s)
934 {
935 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
936 int ret;
937 const char *s_reading_type_string;
938
939 /* copy sensor details at start - it can go away and we won't be able to make an error message */
940 zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz);
941
942 zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id_str, h->ip, h->port);
943
944 h->ret = SUCCEED;
945 h->done = 0;
946
947 switch (s->reading_type)
948 {
949 case IPMI_EVENT_READING_TYPE_THRESHOLD:
950 if (0 != (ret = ipmi_sensor_get_reading(s->sensor, zbx_got_thresh_reading_cb, h)))
951 {
952 /* do not use pointer to sensor here - the sensor may have disappeared during */
953 /* ipmi_sensor_get_reading(), as domain might be closed due to communication failure */
954 h->err = zbx_dsprintf(h->err, "Cannot read sensor \"%s\"."
955 " ipmi_sensor_get_reading() return error: 0x%x", id_str,
956 (unsigned int)ret);
957 h->ret = NOTSUPPORTED;
958 goto out;
959 }
960 break;
961 case IPMI_EVENT_READING_TYPE_DISCRETE_USAGE:
962 case IPMI_EVENT_READING_TYPE_DISCRETE_STATE:
963 case IPMI_EVENT_READING_TYPE_DISCRETE_PREDICTIVE_FAILURE:
964 case IPMI_EVENT_READING_TYPE_DISCRETE_LIMIT_EXCEEDED:
965 case IPMI_EVENT_READING_TYPE_DISCRETE_PERFORMANCE_MET:
966 case IPMI_EVENT_READING_TYPE_DISCRETE_SEVERITY:
967 case IPMI_EVENT_READING_TYPE_DISCRETE_DEVICE_PRESENCE:
968 case IPMI_EVENT_READING_TYPE_DISCRETE_DEVICE_ENABLE:
969 case IPMI_EVENT_READING_TYPE_DISCRETE_AVAILABILITY:
970 case IPMI_EVENT_READING_TYPE_DISCRETE_REDUNDANCY:
971 case IPMI_EVENT_READING_TYPE_DISCRETE_ACPI_POWER:
972 case IPMI_EVENT_READING_TYPE_SENSOR_SPECIFIC:
973 case 0x70: /* reading types 70h-7Fh are for OEM discrete sensors */
974 case 0x71:
975 case 0x72:
976 case 0x73:
977 case 0x74:
978 case 0x75:
979 case 0x76:
980 case 0x77:
981 case 0x78:
982 case 0x79:
983 case 0x7a:
984 case 0x7b:
985 case 0x7c:
986 case 0x7d:
987 case 0x7e:
988 case 0x7f:
989 if (0 != (ret = ipmi_sensor_get_states(s->sensor, zbx_got_discrete_states_cb, h)))
990 {
991 /* do not use pointer to sensor here - the sensor may have disappeared during */
992 /* ipmi_sensor_get_states(), as domain might be closed due to communication failure */
993 h->err = zbx_dsprintf(h->err, "Cannot read sensor \"%s\"."
994 " ipmi_sensor_get_states() return error: 0x%x", id_str,
995 (unsigned int)ret);
996 h->ret = NOTSUPPORTED;
997 goto out;
998 }
999 break;
1000 default:
1001 s_reading_type_string = ipmi_sensor_get_event_reading_type_string(s->sensor);
1002
1003 h->err = zbx_dsprintf(h->err, "Cannot read sensor \"%s\"."
1004 " IPMI reading type \"%s\" is not supported", id_str, s_reading_type_string);
1005 h->ret = NOTSUPPORTED;
1006 goto out;
1007 }
1008
1009 zbx_perform_openipmi_ops(h, __func__); /* ignore returned result */
1010 out:
1011 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1012 }
1013
zbx_read_ipmi_thresholds(zbx_ipmi_host_t * h,const zbx_ipmi_sensor_t * s)1014 static void zbx_read_ipmi_thresholds(zbx_ipmi_host_t *h, const zbx_ipmi_sensor_t *s)
1015 {
1016 char id_str[2 * IPMI_SENSOR_ID_SZ + 1];
1017 int ret;
1018 int thr_access;
1019
1020 /* copy sensor details at start - it can go away and we won't be able to make an error message */
1021 zbx_sensor_id_to_str(id_str, sizeof(id_str), s->id, s->id_type, s->id_sz);
1022
1023 zabbix_log(LOG_LEVEL_DEBUG, "In %s() sensor:'%s@[%s]:%d'", __func__, id_str, h->ip, h->port);
1024
1025 h->done = 0;
1026
1027 thr_access = ipmi_sensor_get_threshold_access(s->sensor);
1028 if (thr_access == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE || thr_access == IPMI_THRESHOLD_ACCESS_SUPPORT_FIXED)
1029 {
1030 zabbix_log(LOG_LEVEL_DEBUG, "Cannot access thresholds");
1031 goto out;
1032 }
1033
1034 if (0 != (ret = ipmi_sensor_get_thresholds(s->sensor, zbx_got_thresholds_cb, h)))
1035 {
1036 zabbix_log(LOG_LEVEL_DEBUG, "Cannot read thresholds for sensor \"%s\". ipmi_sensor_get_thresholds()"
1037 " return error: 0x%x", id_str, (unsigned int)ret);
1038 goto out;
1039 }
1040
1041 zbx_perform_openipmi_ops(h, __func__); /* ignore returned result */
1042 out:
1043 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1044 }
1045 /* callback function invoked from OpenIPMI */
zbx_got_control_reading_cb(ipmi_control_t * control,int err,int * val,void * cb_data)1046 static void zbx_got_control_reading_cb(ipmi_control_t *control, int err, int *val, void *cb_data)
1047 {
1048 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1049 int n;
1050 zbx_ipmi_control_t *c;
1051 const char *e_string;
1052 size_t sz;
1053
1054 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1055
1056 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1057
1058 if (0 != err)
1059 {
1060 zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
1061
1062 h->err = zbx_dsprintf(h->err, "error 0x%x while reading control", (unsigned int)err);
1063 h->ret = NOTSUPPORTED;
1064 goto out;
1065 }
1066
1067 c = zbx_get_ipmi_control(h, control);
1068
1069 if (NULL == c)
1070 {
1071 THIS_SHOULD_NEVER_HAPPEN;
1072 h->err = zbx_strdup(h->err, "fatal error");
1073 h->ret = NOTSUPPORTED;
1074 goto out;
1075 }
1076
1077 if (c->num_values == 0)
1078 {
1079 THIS_SHOULD_NEVER_HAPPEN;
1080 h->err = zbx_strdup(h->err, "no value present for control");
1081 h->ret = NOTSUPPORTED;
1082 goto out;
1083 }
1084
1085 e_string = ipmi_entity_get_entity_id_string(ipmi_control_get_entity(control));
1086
1087 for (n = 0; n < c->num_values; n++)
1088 {
1089 zabbix_log(LOG_LEVEL_DEBUG, "control values [%s | %s | %d:%d]",
1090 c->c_name, e_string, n + 1, val[n]);
1091 }
1092
1093 sz = sizeof(int) * (size_t)c->num_values;
1094 memcpy(c->val, val, sz);
1095 out:
1096 h->done = 1;
1097
1098 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1099 }
1100
1101 /* callback function invoked from OpenIPMI */
zbx_got_control_setting_cb(ipmi_control_t * control,int err,void * cb_data)1102 static void zbx_got_control_setting_cb(ipmi_control_t *control, int err, void *cb_data)
1103 {
1104 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1105 zbx_ipmi_control_t *c;
1106
1107 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1108
1109 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1110
1111 if (0 != err)
1112 {
1113 zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
1114
1115 h->err = zbx_dsprintf(h->err, "error 0x%x while set control", (unsigned int)err);
1116 h->ret = NOTSUPPORTED;
1117 h->done = 1;
1118 return;
1119 }
1120
1121 c = zbx_get_ipmi_control(h, control);
1122
1123 if (NULL == c)
1124 {
1125 THIS_SHOULD_NEVER_HAPPEN;
1126 h->err = zbx_strdup(h->err, "fatal error");
1127 h->ret = NOTSUPPORTED;
1128 h->done = 1;
1129 return;
1130 }
1131
1132 zabbix_log(LOG_LEVEL_DEBUG, "set value completed for control %s@[%s]:%d", c->c_name, h->ip, h->port);
1133
1134 h->done = 1;
1135
1136 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1137 }
1138
zbx_read_ipmi_control(zbx_ipmi_host_t * h,const zbx_ipmi_control_t * c)1139 static void zbx_read_ipmi_control(zbx_ipmi_host_t *h, const zbx_ipmi_control_t *c)
1140 {
1141 int ret;
1142 char control_name[128]; /* internally defined CONTROL_ID_LEN is 32 in OpenIPMI 2.0.22 */
1143
1144 zabbix_log(LOG_LEVEL_DEBUG, "In %s() control:'%s@[%s]:%d'", __func__, c->c_name, h->ip, h->port);
1145
1146 if (0 == ipmi_control_is_readable(c->control))
1147 {
1148 h->err = zbx_strdup(h->err, "control is not readable");
1149 h->ret = NOTSUPPORTED;
1150 goto out;
1151 }
1152
1153 /* copy control name - it can go away and we won't be able to make an error message */
1154 zbx_strlcpy(control_name, c->c_name, sizeof(control_name));
1155
1156 h->ret = SUCCEED;
1157 h->done = 0;
1158
1159 if (0 != (ret = ipmi_control_get_val(c->control, zbx_got_control_reading_cb, h)))
1160 {
1161 /* do not use pointer to control here - the control may have disappeared during */
1162 /* ipmi_control_get_val(), as domain might be closed due to communication failure */
1163 h->err = zbx_dsprintf(h->err, "Cannot read control %s. ipmi_control_get_val() return error: 0x%x",
1164 control_name, (unsigned int)ret);
1165 h->ret = NOTSUPPORTED;
1166 goto out;
1167 }
1168
1169 zbx_perform_openipmi_ops(h, __func__); /* ignore returned result */
1170 out:
1171 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1172 }
1173
zbx_set_ipmi_control(zbx_ipmi_host_t * h,zbx_ipmi_control_t * c,int value)1174 static void zbx_set_ipmi_control(zbx_ipmi_host_t *h, zbx_ipmi_control_t *c, int value)
1175 {
1176 int ret;
1177 char control_name[128]; /* internally defined CONTROL_ID_LEN is 32 in OpenIPMI 2.0.22 */
1178
1179 zabbix_log(LOG_LEVEL_DEBUG, "In %s() control:'%s@[%s]:%d' value:%d",
1180 __func__, c->c_name, h->ip, h->port, value);
1181
1182 if (c->num_values == 0)
1183 {
1184 THIS_SHOULD_NEVER_HAPPEN;
1185 h->err = zbx_strdup(h->err, "no value present for control");
1186 h->ret = NOTSUPPORTED;
1187 h->done = 1;
1188 goto out;
1189 }
1190
1191 if (0 == ipmi_control_is_settable(c->control))
1192 {
1193 h->err = zbx_strdup(h->err, "control is not settable");
1194 h->ret = NOTSUPPORTED;
1195 goto out;
1196 }
1197
1198 /* copy control name - it can go away and we won't be able to make an error message */
1199 zbx_strlcpy(control_name, c->c_name, sizeof(control_name));
1200
1201 c->val[0] = value;
1202 h->ret = SUCCEED;
1203 h->done = 0;
1204
1205 if (0 != (ret = ipmi_control_set_val(c->control, c->val, zbx_got_control_setting_cb, h)))
1206 {
1207 /* do not use pointer to control here - the control may have disappeared during */
1208 /* ipmi_control_set_val(), as domain might be closed due to communication failure */
1209 h->err = zbx_dsprintf(h->err, "Cannot set control %s. ipmi_control_set_val() return error: 0x%x",
1210 control_name, (unsigned int)ret);
1211 h->ret = NOTSUPPORTED;
1212 goto out;
1213 }
1214
1215 zbx_perform_openipmi_ops(h, __func__); /* ignore returned result */
1216 out:
1217 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1218 }
1219
1220 /* callback function invoked from OpenIPMI */
zbx_sensor_change_cb(enum ipmi_update_e op,ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)1221 static void zbx_sensor_change_cb(enum ipmi_update_e op, ipmi_entity_t *ent, ipmi_sensor_t *sensor, void *cb_data)
1222 {
1223 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1224
1225 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1226
1227 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p ent:%p sensor:%p op:%d",
1228 __func__, h->ip, h->port, (void *)h, (void *)ent, (void *)sensor, (int)op);
1229
1230 /* ignore non-readable sensors (e.g. Event-only) */
1231 if (0 != ipmi_sensor_get_is_readable(sensor))
1232 {
1233 switch (op)
1234 {
1235 case IPMI_ADDED:
1236 if (NULL == zbx_get_ipmi_sensor(h, sensor))
1237 zbx_allocate_ipmi_sensor(h, sensor);
1238 break;
1239 case IPMI_DELETED:
1240 zbx_delete_ipmi_sensor(h, sensor);
1241 break;
1242 case IPMI_CHANGED:
1243 break;
1244 default:
1245 THIS_SHOULD_NEVER_HAPPEN;
1246 }
1247 }
1248
1249 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1250 }
1251
1252 /* callback function invoked from OpenIPMI */
zbx_control_change_cb(enum ipmi_update_e op,ipmi_entity_t * ent,ipmi_control_t * control,void * cb_data)1253 static void zbx_control_change_cb(enum ipmi_update_e op, ipmi_entity_t *ent, ipmi_control_t *control, void *cb_data)
1254 {
1255 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1256
1257 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1258
1259 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p ent:%p control:%p op:%d",
1260 __func__, h->ip, h->port, (void *)h, (void *)ent, (void *)control, (int)op);
1261
1262 switch (op)
1263 {
1264 case IPMI_ADDED:
1265 if (NULL == zbx_get_ipmi_control(h, control))
1266 zbx_allocate_ipmi_control(h, control);
1267 break;
1268 case IPMI_DELETED:
1269 zbx_delete_ipmi_control(h, control);
1270 break;
1271 case IPMI_CHANGED:
1272 break;
1273 default:
1274 THIS_SHOULD_NEVER_HAPPEN;
1275 }
1276
1277 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1278 }
1279
1280 /* callback function invoked from OpenIPMI */
zbx_entity_change_cb(enum ipmi_update_e op,ipmi_domain_t * domain,ipmi_entity_t * entity,void * cb_data)1281 static void zbx_entity_change_cb(enum ipmi_update_e op, ipmi_domain_t *domain, ipmi_entity_t *entity, void *cb_data)
1282 {
1283 int ret;
1284 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1285
1286 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1287
1288 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
1289 {
1290 char entity_name[IPMI_ENTITY_NAME_LEN];
1291
1292 ipmi_entity_get_name(entity, entity_name, sizeof(entity_name));
1293
1294 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p domain:%p entity:%p:'%s' op:%d",
1295 __func__, h->ip, h->port, (void *)h, (void *)domain, (void *)entity, entity_name,
1296 (int)op);
1297 }
1298
1299 if (op == IPMI_ADDED)
1300 {
1301 if (0 != (ret = ipmi_entity_add_sensor_update_handler(entity, zbx_sensor_change_cb, h)))
1302 {
1303 zabbix_log(LOG_LEVEL_DEBUG, "ipmi_entity_set_sensor_update_handler() return error: 0x%x",
1304 (unsigned int)ret);
1305 }
1306
1307 if (0 != (ret = ipmi_entity_add_control_update_handler(entity, zbx_control_change_cb, h)))
1308 {
1309 zabbix_log(LOG_LEVEL_DEBUG, "ipmi_entity_add_control_update_handler() return error: 0x%x",
1310 (unsigned int)ret);
1311 }
1312 }
1313
1314 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1315 }
1316
1317 /* callback function invoked from OpenIPMI */
zbx_domain_closed_cb(void * cb_data)1318 static void zbx_domain_closed_cb(void *cb_data)
1319 {
1320 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1321
1322 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1323
1324 zabbix_log(LOG_LEVEL_DEBUG, "In %s() phost:%p host:'[%s]:%d'", __func__, (void *)h, h->ip, h->port);
1325
1326 h->domain_up = 0;
1327 h->done = 1;
1328
1329 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1330 }
1331
1332 /* callback function invoked from OpenIPMI */
zbx_connection_change_cb(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected,void * cb_data)1333 static void zbx_connection_change_cb(ipmi_domain_t *domain, int err, unsigned int conn_num, unsigned int port_num,
1334 int still_connected, void *cb_data)
1335 {
1336 /* this function is called when a connection comes up or goes down */
1337
1338 int ret;
1339 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1340
1341 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1342
1343 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' phost:%p domain:%p err:%d conn_num:%u port_num:%u"
1344 " still_connected:%d cb_data:%p", __func__, h->ip, h->port, (void *)h, (void *)domain,
1345 err, conn_num, port_num, still_connected, cb_data);
1346
1347 if (0 != err)
1348 {
1349 zabbix_log(LOG_LEVEL_DEBUG, "%s() fail: %s", __func__, zbx_strerror(err));
1350
1351 h->err = zbx_dsprintf(h->err, "cannot connect to IPMI host: %s", zbx_strerror(err));
1352 h->ret = NETWORK_ERROR;
1353
1354 if (0 != (ret = ipmi_domain_close(domain, zbx_domain_closed_cb, h)))
1355 zabbix_log(LOG_LEVEL_DEBUG, "cannot close IPMI domain: [0x%x]", (unsigned int)ret);
1356
1357 goto out;
1358 }
1359
1360 if (0 != (ret = ipmi_domain_add_entity_update_handler(domain, zbx_entity_change_cb, h)))
1361 {
1362 zabbix_log(LOG_LEVEL_DEBUG, "ipmi_domain_add_entity_update_handler() return error: [0x%x]",
1363 (unsigned int)ret);
1364 }
1365 out:
1366 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(h->ret));
1367 }
1368
1369 /* callback function invoked from OpenIPMI */
zbx_domain_up_cb(ipmi_domain_t * domain,void * cb_data)1370 static void zbx_domain_up_cb(ipmi_domain_t *domain, void *cb_data)
1371 {
1372 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1373
1374 RETURN_IF_CB_DATA_NULL(cb_data, __func__);
1375
1376 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' domain:%p cb_data:%p", __func__, h->ip,
1377 h->port, (void *)domain, cb_data);
1378
1379 h->domain_up = 1;
1380 h->done = 1;
1381
1382 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1383 }
1384
zbx_vlog(os_handler_t * handler,const char * format,enum ipmi_log_type_e log_type,va_list ap)1385 static void zbx_vlog(os_handler_t *handler, const char *format, enum ipmi_log_type_e log_type, va_list ap)
1386 {
1387 char type[8], str[MAX_STRING_LEN];
1388
1389 ZBX_UNUSED(handler);
1390
1391 switch (log_type)
1392 {
1393 case IPMI_LOG_INFO : zbx_strlcpy(type, "INFO: ", sizeof(type)); break;
1394 case IPMI_LOG_WARNING : zbx_strlcpy(type, "WARN: ", sizeof(type)); break;
1395 case IPMI_LOG_SEVERE : zbx_strlcpy(type, "SEVR: ", sizeof(type)); break;
1396 case IPMI_LOG_FATAL : zbx_strlcpy(type, "FATL: ", sizeof(type)); break;
1397 case IPMI_LOG_ERR_INFO : zbx_strlcpy(type, "EINF: ", sizeof(type)); break;
1398 case IPMI_LOG_DEBUG_START :
1399 case IPMI_LOG_DEBUG : zbx_strlcpy(type, "DEBG: ", sizeof(type)); break;
1400 case IPMI_LOG_DEBUG_CONT :
1401 case IPMI_LOG_DEBUG_END : *type = '\0'; break;
1402 default : THIS_SHOULD_NEVER_HAPPEN;
1403 }
1404
1405 zbx_vsnprintf(str, sizeof(str), format, ap);
1406
1407 zabbix_log(LOG_LEVEL_DEBUG, "%s%s", type, str);
1408 }
1409
zbx_init_ipmi_handler(void)1410 int zbx_init_ipmi_handler(void)
1411 {
1412 int res, ret = FAIL;
1413
1414 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1415
1416 if (NULL == (os_hnd = ipmi_posix_setup_os_handler()))
1417 {
1418 zabbix_log(LOG_LEVEL_WARNING, "unable to allocate IPMI handler");
1419 goto out;
1420 }
1421
1422 os_hnd->set_log_handler(os_hnd, zbx_vlog);
1423
1424 if (0 != (res = ipmi_init(os_hnd)))
1425 {
1426 zabbix_log(LOG_LEVEL_WARNING, "unable to initialize the OpenIPMI library."
1427 " ipmi_init() return error: 0x%x", (unsigned int)res);
1428 goto out;
1429 }
1430
1431 ret = SUCCEED;
1432 out:
1433 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1434
1435 return ret;
1436 }
1437
zbx_free_ipmi_host(zbx_ipmi_host_t * h)1438 static void zbx_free_ipmi_host(zbx_ipmi_host_t *h)
1439 {
1440 int i;
1441
1442 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d' h:%p", __func__, h->ip, h->port, (void *)h);
1443
1444 for (i = 0; i < h->control_count; i++)
1445 {
1446 zbx_free(h->controls[i].c_name);
1447 zbx_free(h->controls[i].val);
1448 }
1449
1450 zbx_free(h->sensors);
1451 zbx_free(h->controls);
1452 zbx_free(h->ip);
1453 zbx_free(h->username);
1454 zbx_free(h->password);
1455 zbx_free(h->err);
1456
1457 zbx_free(h);
1458
1459 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1460 }
1461
zbx_free_ipmi_handler(void)1462 void zbx_free_ipmi_handler(void)
1463 {
1464 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1465
1466 while (NULL != hosts)
1467 {
1468 zbx_ipmi_host_t *h;
1469
1470 h = hosts;
1471 hosts = hosts->next;
1472
1473 zbx_free_ipmi_host(h);
1474 }
1475
1476 os_hnd->free_os_handler(os_hnd);
1477
1478 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1479 }
1480
zbx_init_ipmi_host(const char * ip,int port,int authtype,int privilege,const char * username,const char * password)1481 static zbx_ipmi_host_t *zbx_init_ipmi_host(const char *ip, int port, int authtype, int privilege, const char *username,
1482 const char *password)
1483 {
1484 zbx_ipmi_host_t *h;
1485 ipmi_open_option_t options[4];
1486
1487 /* Although we use only one address and port we pass them in 2-element arrays. The reason is */
1488 /* OpenIPMI v.2.0.16 - 2.0.24 file lib/ipmi_lan.c, function ipmi_lanp_setup_con() ending with loop */
1489 /* in OpenIPMI file lib/ipmi_lan.c, function ipmi_lanp_setup_con() ending with */
1490 /* for (i=0; i<MAX_IP_ADDR; i++) { */
1491 /* if (!ports[i]) */
1492 /* ports[i] = IPMI_LAN_STD_PORT_STR; */
1493 /* } */
1494 /* MAX_IP_ADDR is '#define MAX_IP_ADDR 2' in OpenIPMI and not available to library users. */
1495 /* The loop is running two times regardless of number of addresses supplied by the caller, so we use */
1496 /* 2-element arrays to match OpenIPMI internals. */
1497 char *addrs[2] = {NULL}, *ports[2] = {NULL};
1498
1499 char domain_name[11]; /* max int length */
1500 int ret;
1501
1502 zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __func__, ip, port);
1503
1504 /* Host already in the list? */
1505
1506 if (NULL != (h = zbx_get_ipmi_host(ip, port, authtype, privilege, username, password)))
1507 {
1508 if (1 == h->domain_up)
1509 goto out;
1510 }
1511 else
1512 h = zbx_allocate_ipmi_host(ip, port, authtype, privilege, username, password);
1513
1514 h->ret = SUCCEED;
1515 h->done = 0;
1516
1517 addrs[0] = strdup(h->ip);
1518 ports[0] = zbx_dsprintf(NULL, "%d", h->port);
1519
1520 if (0 != (ret = ipmi_ip_setup_con(addrs, ports, 1,
1521 h->authtype == -1 ? (unsigned int)IPMI_AUTHTYPE_DEFAULT : (unsigned int)h->authtype,
1522 (unsigned int)h->privilege, h->username, strlen(h->username),
1523 h->password, strlen(h->password), os_hnd, NULL, &h->con)))
1524 {
1525 h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d."
1526 " ipmi_ip_setup_con() returned error 0x%x",
1527 h->ip, h->port, (unsigned int)ret);
1528 h->ret = NETWORK_ERROR;
1529 goto out;
1530 }
1531
1532 if (0 != (ret = h->con->start_con(h->con)))
1533 {
1534 h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d."
1535 " start_con() returned error 0x%x",
1536 h->ip, h->port, (unsigned int)ret);
1537 h->ret = NETWORK_ERROR;
1538 goto out;
1539 }
1540
1541 options[0].option = IPMI_OPEN_OPTION_ALL;
1542 options[0].ival = 0;
1543 options[1].option = IPMI_OPEN_OPTION_SDRS; /* scan SDRs */
1544 options[1].ival = 1;
1545 options[2].option = IPMI_OPEN_OPTION_IPMB_SCAN; /* scan IPMB bus to find out as much as possible */
1546 options[2].ival = 1;
1547 options[3].option = IPMI_OPEN_OPTION_LOCAL_ONLY; /* scan only local resources */
1548 options[3].ival = 1;
1549
1550 zbx_snprintf(domain_name, sizeof(domain_name), "%u", h->domain_nr);
1551
1552 if (0 != (ret = ipmi_open_domain(domain_name, &h->con, 1, zbx_connection_change_cb, h, zbx_domain_up_cb, h,
1553 options, ARRSIZE(options), NULL)))
1554 {
1555 h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d. ipmi_open_domain() failed: %s",
1556 h->ip, h->port, zbx_strerror(ret));
1557 h->ret = NETWORK_ERROR;
1558 goto out;
1559 }
1560
1561 zbx_perform_openipmi_ops(h, __func__); /* ignore returned result */
1562 out:
1563 zbx_free(addrs[0]);
1564 zbx_free(ports[0]);
1565
1566 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p domain_nr:%u", __func__, (void *)h, h->domain_nr);
1567
1568 return h;
1569 }
1570
1571 static ipmi_domain_id_t domain_id; /* global variable for passing OpenIPMI domain ID between callbacks */
1572 static int domain_id_found; /* A flag to indicate whether the 'domain_id' carries a valid value. */
1573 /* Values: 0 - not found, 1 - found. The flag is used because we */
1574 /* cannot set 'domain_id' to NULL. */
1575 static int domain_close_ok;
1576
1577 /* callback function invoked from OpenIPMI */
zbx_get_domain_id_by_name_cb(ipmi_domain_t * domain,void * cb_data)1578 static void zbx_get_domain_id_by_name_cb(ipmi_domain_t *domain, void *cb_data)
1579 {
1580 char name[IPMI_DOMAIN_NAME_LEN], *domain_name = (char *)cb_data;
1581
1582 RETURN_IF_CB_DATA_NULL(cb_data, "zbx_get_domain_id_by_name_cb");
1583
1584 /* from 'domain' pointer find the domain name */
1585 ipmi_domain_get_name(domain, name, sizeof(name));
1586
1587 /* if the domain name matches the name we are searching for then store the domain ID into global variable */
1588 if (0 == strcmp(domain_name, name))
1589 {
1590 domain_id = ipmi_domain_convert_to_id(domain);
1591 domain_id_found = 1;
1592 }
1593 }
1594
1595 /* callback function invoked from OpenIPMI */
zbx_domain_close_cb(ipmi_domain_t * domain,void * cb_data)1596 static void zbx_domain_close_cb(ipmi_domain_t *domain, void *cb_data)
1597 {
1598 zbx_ipmi_host_t *h = (zbx_ipmi_host_t *)cb_data;
1599 int ret;
1600
1601 RETURN_IF_CB_DATA_NULL(cb_data, "zbx_domain_close_cb");
1602
1603 if (0 != (ret = ipmi_domain_close(domain, zbx_domain_closed_cb, h)))
1604 zabbix_log(LOG_LEVEL_DEBUG, "cannot close IPMI domain: [0x%x]", (unsigned int)ret);
1605 else
1606 domain_close_ok = 1;
1607 }
1608
zbx_close_inactive_host(zbx_ipmi_host_t * h)1609 static int zbx_close_inactive_host(zbx_ipmi_host_t *h)
1610 {
1611 char domain_name[11]; /* max int length */
1612 int ret = FAIL;
1613
1614 zabbix_log(LOG_LEVEL_DEBUG, "In %s(): %s", __func__, h->ip);
1615
1616 zbx_snprintf(domain_name, sizeof(domain_name), "%u", h->domain_nr);
1617
1618 /* Search the list of domains in OpenIPMI library and find which one to close. It could happen that */
1619 /* the domain is not found (e.g. if Zabbix allocated an IPMI host during network problem and the domain was */
1620 /* closed by OpenIPMI library but the host is still in our 'hosts' list). */
1621
1622 domain_id_found = 0;
1623 ipmi_domain_iterate_domains(zbx_get_domain_id_by_name_cb, domain_name);
1624
1625 h->done = 0;
1626 domain_close_ok = 0;
1627
1628 if (1 == domain_id_found)
1629 {
1630 int res;
1631
1632 if (0 != (res = ipmi_domain_pointer_cb(domain_id, zbx_domain_close_cb, h)))
1633 {
1634 zabbix_log(LOG_LEVEL_DEBUG, "%s(): ipmi_domain_pointer_cb() return error: %s", __func__,
1635 zbx_strerror(res));
1636 goto out;
1637 }
1638
1639 if (1 != domain_close_ok || SUCCEED != zbx_perform_openipmi_ops(h, __func__))
1640 goto out;
1641 }
1642
1643 /* The domain was either successfully closed or not found. */
1644 zbx_free_ipmi_host(h);
1645 ret = SUCCEED;
1646 out:
1647 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1648
1649 return ret;
1650 }
1651
zbx_delete_inactive_ipmi_hosts(time_t last_check)1652 void zbx_delete_inactive_ipmi_hosts(time_t last_check)
1653 {
1654 zbx_ipmi_host_t *h = hosts, *prev = NULL, *next;
1655
1656 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1657
1658 while (NULL != h)
1659 {
1660 if (last_check - h->lastaccess > INACTIVE_HOST_LIMIT)
1661 {
1662 next = h->next;
1663
1664 if (SUCCEED == zbx_close_inactive_host(h))
1665 {
1666 if (NULL == prev)
1667 hosts = next;
1668 else
1669 prev->next = next;
1670
1671 h = next;
1672
1673 continue;
1674 }
1675 }
1676
1677 prev = h;
1678 h = h->next;
1679 }
1680
1681 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1682 }
1683
1684 /******************************************************************************
1685 * *
1686 * Function: has_name_prefix *
1687 * *
1688 * Purpose: Check if a string starts with one of predefined prefixes and *
1689 * set prefix length *
1690 * *
1691 * Parameters: str - [IN] string to examine *
1692 * prefix_len - [OUT] length of the prefix *
1693 * *
1694 * Return value: 1 - the string starts with the name prefix, *
1695 * 0 - otherwise (no prefix or other prefix was found) *
1696 * *
1697 ******************************************************************************/
has_name_prefix(const char * str,size_t * prefix_len)1698 static int has_name_prefix(const char *str, size_t *prefix_len)
1699 {
1700 #define ZBX_ID_PREFIX "id:"
1701 #define ZBX_NAME_PREFIX "name:"
1702
1703 const size_t id_len = sizeof(ZBX_ID_PREFIX) - 1, name_len = sizeof(ZBX_NAME_PREFIX) - 1;
1704
1705 if (0 == strncmp(str, ZBX_NAME_PREFIX, name_len))
1706 {
1707 *prefix_len = name_len;
1708 return 1;
1709 }
1710
1711 if (0 == strncmp(str, ZBX_ID_PREFIX, id_len))
1712 *prefix_len = id_len;
1713 else
1714 *prefix_len = 0;
1715
1716 return 0;
1717
1718 #undef ZBX_ID_PREFIX
1719 #undef ZBX_NAME_PREFIX
1720 }
1721
get_value_ipmi(zbx_uint64_t itemid,const char * addr,unsigned short port,signed char authtype,unsigned char privilege,const char * username,const char * password,const char * sensor,char ** value)1722 int get_value_ipmi(zbx_uint64_t itemid, const char *addr, unsigned short port, signed char authtype,
1723 unsigned char privilege, const char *username, const char *password, const char *sensor, char **value)
1724 {
1725 zbx_ipmi_host_t *h;
1726 zbx_ipmi_sensor_t *s;
1727 zbx_ipmi_control_t *c = NULL;
1728 size_t offset;
1729
1730 zabbix_log(LOG_LEVEL_DEBUG, "In %s() itemid:" ZBX_FS_UI64, __func__, itemid);
1731
1732 if (NULL == os_hnd)
1733 {
1734 *value = zbx_strdup(*value, "IPMI handler is not initialised.");
1735 return CONFIG_ERROR;
1736 }
1737
1738 h = zbx_init_ipmi_host(addr, port, authtype, privilege, username, password);
1739
1740 h->lastaccess = time(NULL);
1741
1742 if (0 == h->domain_up)
1743 {
1744 if (NULL != h->err)
1745 *value = zbx_strdup(*value, h->err);
1746
1747 return h->ret;
1748 }
1749
1750 if (0 == has_name_prefix(sensor, &offset))
1751 {
1752 if (NULL == (s = zbx_get_ipmi_sensor_by_id(h, sensor + offset)))
1753 c = zbx_get_ipmi_control_by_name(h, sensor + offset);
1754 }
1755 else
1756 {
1757 if (NULL == (s = zbx_get_ipmi_sensor_by_full_name(h, sensor + offset)))
1758 c = zbx_get_ipmi_control_by_full_name(h, sensor + offset);
1759 }
1760
1761 if (NULL == s && NULL == c)
1762 {
1763 *value = zbx_dsprintf(*value, "sensor or control %s@[%s]:%d does not exist", sensor, h->ip, h->port);
1764 return NOTSUPPORTED;
1765 }
1766
1767 if (NULL != s)
1768 zbx_read_ipmi_sensor(h, s);
1769 else
1770 zbx_read_ipmi_control(h, c);
1771
1772 if (h->ret != SUCCEED)
1773 {
1774 if (NULL != h->err)
1775 *value = zbx_strdup(*value, h->err);
1776
1777 return h->ret;
1778 }
1779
1780 if (NULL != s)
1781 {
1782 if (IPMI_EVENT_READING_TYPE_THRESHOLD == s->reading_type)
1783 *value = zbx_dsprintf(*value, ZBX_FS_DBL, s->value.threshold);
1784 else
1785 *value = zbx_dsprintf(*value, ZBX_FS_UI64, s->value.discrete);
1786 }
1787
1788 if (NULL != c)
1789 *value = zbx_dsprintf(*value, "%d", c->val[0]);
1790
1791 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:%s", __func__, zbx_result_string(h->ret),
1792 ZBX_NULL2EMPTY_STR(*value));
1793
1794 return h->ret;
1795 }
1796
add_threshold_ipmi(struct zbx_json * json,const char * tag,zbx_ipmi_sensor_threshold_t * threshold)1797 static void add_threshold_ipmi(struct zbx_json *json, const char *tag, zbx_ipmi_sensor_threshold_t *threshold)
1798 {
1799 if (ZBX_IPMI_THRESHOLD_STATUS_ENABLED == threshold->status)
1800 zbx_json_addfloat(json, tag, threshold->val);
1801 }
1802
get_discovery_ipmi(zbx_uint64_t itemid,const char * addr,unsigned short port,signed char authtype,unsigned char privilege,const char * username,const char * password,char ** value)1803 int get_discovery_ipmi(zbx_uint64_t itemid, const char *addr, unsigned short port, signed char authtype,
1804 unsigned char privilege, const char *username, const char *password, char **value)
1805 {
1806 zbx_ipmi_host_t *h;
1807 int i, j;
1808 struct zbx_json json;
1809
1810 zabbix_log(LOG_LEVEL_DEBUG, "In %s() itemid:" ZBX_FS_UI64, __func__, itemid);
1811
1812 if (NULL == os_hnd)
1813 {
1814 *value = zbx_strdup(*value, "IPMI handler is not initialised.");
1815 return CONFIG_ERROR;
1816 }
1817
1818 h = zbx_init_ipmi_host(addr, port, authtype, privilege, username, password);
1819
1820 h->lastaccess = time(NULL);
1821
1822 if (0 == h->domain_up)
1823 {
1824 if (NULL != h->err)
1825 *value = zbx_strdup(*value, h->err);
1826
1827 return h->ret;
1828 }
1829
1830 zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
1831
1832 for (i = 0; i < h->sensor_count; i++)
1833 {
1834 const char *p;
1835 char state_name[MAX_STRING_LEN];
1836 size_t offset = 0;
1837 zbx_uint64_t state;
1838
1839 zbx_read_ipmi_sensor(h, &h->sensors[i]);
1840 if (SUCCEED != h->ret)
1841 {
1842 zabbix_log(LOG_LEVEL_DEBUG,"Sensor '%s' cannot be discovered. Error: %s",h->sensors[i].id,
1843 ZBX_NULL2EMPTY_STR(h->err));
1844
1845 continue;
1846 }
1847
1848 if (IPMI_EVENT_READING_TYPE_THRESHOLD == h->sensors[i].reading_type)
1849 {
1850 zbx_read_ipmi_thresholds(h, &h->sensors[i]);
1851 if (SUCCEED != h->ret)
1852 {
1853 zabbix_log(LOG_LEVEL_DEBUG,"Sensor '%s' cannot be discovered. Error: %s",
1854 h->sensors[i].id, ZBX_NULL2EMPTY_STR(h->err));
1855
1856 continue;
1857 }
1858 }
1859
1860 zbx_json_addobject(&json, NULL);
1861
1862 zbx_json_addstring(&json, ZBX_IPMI_TAG_ID, h->sensors[i].id, ZBX_JSON_TYPE_STRING);
1863 zbx_json_addstring(&json, ZBX_IPMI_TAG_NAME, h->sensors[i].full_name, ZBX_JSON_TYPE_STRING);
1864
1865 zbx_json_addobject(&json, ZBX_IPMI_TAG_SENSOR);
1866 zbx_json_adduint64(&json, ZBX_IPMI_TAG_TYPE, (zbx_uint64_t)h->sensors[i].type);
1867 p = ipmi_sensor_get_sensor_type_string(h->sensors[i].sensor);
1868 zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, p, ZBX_JSON_TYPE_STRING);
1869 zbx_json_close(&json);
1870
1871 zbx_json_addobject(&json, ZBX_IPMI_TAG_READING);
1872 zbx_json_adduint64(&json, ZBX_IPMI_TAG_TYPE, (zbx_uint64_t)h->sensors[i].reading_type);
1873 p = ipmi_sensor_get_event_reading_type_string(h->sensors[i].sensor);
1874 zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, p, ZBX_JSON_TYPE_STRING);
1875 zbx_json_close(&json);
1876
1877 if (IPMI_EVENT_READING_TYPE_THRESHOLD != h->sensors[i].reading_type) /* discrete */
1878 {
1879 state = h->sensors[i].value.discrete;
1880 zbx_json_addobject(&json, ZBX_IPMI_TAG_STATE);
1881 zbx_json_adduint64(&json, ZBX_IPMI_TAG_STATE, state);
1882
1883 state_name[0] = '\0';
1884 for (j = 0; j < MAX_DISCRETE_STATES; j++)
1885 {
1886 if (0 != (state & (1u << j)))
1887 {
1888 if (NULL != (p = ipmi_sensor_reading_name_string(h->sensors[i].sensor, j)))
1889 {
1890 if (0 < offset)
1891 offset += zbx_snprintf(state_name + offset,
1892 sizeof(state_name) - offset,", ");
1893 offset += zbx_snprintf(state_name + offset, sizeof(state_name) - offset,
1894 "%s", p);
1895 }
1896 }
1897 }
1898
1899 zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, state_name, ZBX_JSON_TYPE_STRING);
1900 zbx_json_close(&json);
1901 }
1902 else /* threshold */
1903 {
1904 char *units;
1905
1906 state = (zbx_uint64_t)h->sensors[i].state;
1907 zbx_json_addobject(&json, ZBX_IPMI_TAG_STATE);
1908 zbx_json_adduint64(&json, ZBX_IPMI_TAG_STATE, state);
1909
1910 state_name[0] = '\0';
1911 for (j = IPMI_LOWER_NON_CRITICAL; j <= IPMI_UPPER_NON_RECOVERABLE; j++)
1912 {
1913 if (0 != (state & (1u << j)))
1914 {
1915 if (0 < offset)
1916 offset += zbx_snprintf(state_name + offset,
1917 sizeof(state_name) - offset,", ");
1918 offset += zbx_snprintf(state_name + offset, sizeof(state_name) - offset,
1919 "%s - out of range", ipmi_get_threshold_string(j));
1920 }
1921 }
1922
1923 zbx_json_addstring(&json, ZBX_IPMI_TAG_TEXT, state_name, ZBX_JSON_TYPE_STRING);
1924 zbx_json_close(&json);
1925
1926 zbx_json_addfloat(&json, ZBX_IPMI_TAG_VALUE, h->sensors[i].value.threshold);
1927
1928 units = zbx_get_ipmi_units(h->sensors[i].sensor);
1929 zbx_json_addstring(&json, ZBX_IPMI_TAG_UNITS, units, ZBX_JSON_TYPE_STRING);
1930 zbx_free(units);
1931
1932 zbx_read_ipmi_thresholds(h, &h->sensors[i]);
1933
1934 zbx_json_addobject(&json, ZBX_IPMI_TAG_THRESHOLD);
1935 zbx_json_addobject(&json, ZBX_IPMI_TAG_LOWER);
1936
1937 add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_CRIT,
1938 &h->sensors[i].thresholds[IPMI_LOWER_NON_CRITICAL]);
1939 add_threshold_ipmi(&json,ZBX_IPMI_TAG_CRIT,
1940 &h->sensors[i].thresholds[IPMI_LOWER_CRITICAL]);
1941 add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_RECOVER,
1942 &h->sensors[i].thresholds[IPMI_LOWER_NON_RECOVERABLE]);
1943
1944 zbx_json_close(&json);
1945
1946 zbx_json_addobject(&json, ZBX_IPMI_TAG_UPPER);
1947
1948 add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_CRIT,
1949 &h->sensors[i].thresholds[IPMI_UPPER_NON_CRITICAL]);
1950 add_threshold_ipmi(&json,ZBX_IPMI_TAG_CRIT,
1951 &h->sensors[i].thresholds[IPMI_UPPER_CRITICAL]);
1952 add_threshold_ipmi(&json,ZBX_IPMI_TAG_NON_RECOVER,
1953 &h->sensors[i].thresholds[IPMI_UPPER_NON_RECOVERABLE]);
1954
1955 zbx_json_close(&json);
1956 zbx_json_close(&json);
1957 }
1958 zbx_json_close(&json);
1959
1960 }
1961 zbx_json_close(&json);
1962
1963 *value = zbx_strdup(*value, json.buffer);
1964
1965 zbx_json_free(&json);
1966
1967 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:%s", __func__, ZBX_NULL2EMPTY_STR(*value));
1968
1969 return SUCCEED;
1970 }
1971
1972 /* function 'zbx_parse_ipmi_command' requires 'c_name' with size 'ITEM_IPMI_SENSOR_LEN_MAX' */
zbx_parse_ipmi_command(const char * command,char * c_name,int * val,char * error,size_t max_error_len)1973 int zbx_parse_ipmi_command(const char *command, char *c_name, int *val, char *error, size_t max_error_len)
1974 {
1975 const char *p;
1976 size_t sz_c_name;
1977 int ret = FAIL;
1978
1979 zabbix_log(LOG_LEVEL_DEBUG, "In %s() command:'%s'", __func__, command);
1980
1981 while ('\0' != *command && NULL != strchr(" \t", *command))
1982 command++;
1983
1984 for (p = command; '\0' != *p && NULL == strchr(" \t", *p); p++)
1985 ;
1986
1987 if (0 == (sz_c_name = p - command))
1988 {
1989 zbx_strlcpy(error, "IPMI command is empty", max_error_len);
1990 goto fail;
1991 }
1992
1993 if (ITEM_IPMI_SENSOR_LEN_MAX <= sz_c_name)
1994 {
1995 zbx_snprintf(error, max_error_len, "IPMI command is too long [%.*s]", (int)sz_c_name, command);
1996 goto fail;
1997 }
1998
1999 memcpy(c_name, command, sz_c_name);
2000 c_name[sz_c_name] = '\0';
2001
2002 while ('\0' != *p && NULL != strchr(" \t", *p))
2003 p++;
2004
2005 if ('\0' == *p || 0 == strcasecmp(p, "on"))
2006 *val = 1;
2007 else if (0 == strcasecmp(p, "off"))
2008 *val = 0;
2009 else if (SUCCEED != is_uint31(p, val))
2010 {
2011 zbx_snprintf(error, max_error_len, "IPMI command value is not supported [%s]", p);
2012 goto fail;
2013 }
2014
2015 ret = SUCCEED;
2016 fail:
2017 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2018
2019 return ret;
2020 }
2021
zbx_set_ipmi_control_value(zbx_uint64_t hostid,const char * addr,unsigned short port,signed char authtype,unsigned char privilege,const char * username,const char * password,const char * sensor,int value,char ** error)2022 int zbx_set_ipmi_control_value(zbx_uint64_t hostid, const char *addr, unsigned short port, signed char authtype,
2023 unsigned char privilege, const char *username, const char *password, const char *sensor,
2024 int value, char **error)
2025 {
2026 zbx_ipmi_host_t *h;
2027 zbx_ipmi_control_t *c;
2028 size_t offset;
2029
2030 zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostid:" ZBX_FS_UI64 "control:%s value:%d",
2031 __func__, hostid, sensor, value);
2032
2033 if (NULL == os_hnd)
2034 {
2035 *error = zbx_strdup(*error, "IPMI handler is not initialized.");
2036 zabbix_log(LOG_LEVEL_DEBUG, "%s", *error);
2037 return NOTSUPPORTED;
2038 }
2039
2040 h = zbx_init_ipmi_host(addr, port, authtype, privilege, username, password);
2041
2042 if (0 == h->domain_up)
2043 {
2044 if (NULL != h->err)
2045 {
2046 *error = zbx_strdup(*error, h->err);
2047 zabbix_log(LOG_LEVEL_DEBUG, "%s", h->err);
2048 }
2049 return h->ret;
2050 }
2051
2052 if (0 == has_name_prefix(sensor, &offset))
2053 c = zbx_get_ipmi_control_by_name(h, sensor + offset);
2054 else
2055 c = zbx_get_ipmi_control_by_full_name(h, sensor + offset);
2056
2057 if (NULL == c)
2058 {
2059 *error = zbx_dsprintf(*error, "Control \"%s\" at address \"%s:%d\" does not exist.", sensor, h->ip, h->port);
2060 zabbix_log(LOG_LEVEL_DEBUG, "%s", *error);
2061 return NOTSUPPORTED;
2062 }
2063
2064 zbx_set_ipmi_control(h, c, value);
2065
2066 if (h->ret != SUCCEED)
2067 {
2068 if (NULL != h->err)
2069 {
2070 *error = zbx_strdup(*error, h->err);
2071 zabbix_log(LOG_LEVEL_DEBUG, "%s", h->err);
2072 }
2073 }
2074
2075 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);\
2076
2077 return h->ret;
2078 }
2079
2080 #endif /* HAVE_OPENIPMI */
2081