1
// SPDX-License-Identifier: GPL-3.0-or-later
2
/*
3
* netdata freeipmi.plugin
4
- * Copyright (C) 2017 Costa Tsaousis
4
+ * Copyright (C) 2023 Netdata Inc.
5
* GPL v3+
6
*
7
* Based on:
15
* UCRL-CODE-222073
16
*/
17
18
+// ----------------------------------------------------------------------------
19
+// BEGIN NETDATA CODE
20
+
21
+// #define NETDATA_TIMING_REPORT 1
22
#include "libnetdata/libnetdata.h"
23
#include "libnetdata/required_dummies.h"
24
25
+// component names, based on our patterns
26
+#define NETDATA_SENSOR_COMPONENT_MEMORY_MODULE "Memory Module"
27
+#define NETDATA_SENSOR_COMPONENT_MEMORY "Memory"
28
+#define NETDATA_SENSOR_COMPONENT_PROCESSOR "Processor"
29
+#define NETDATA_SENSOR_COMPONENT_IPU "Image Processor"
30
+#define NETDATA_SENSOR_COMPONENT_STORAGE "Storage"
31
+#define NETDATA_SENSOR_COMPONENT_MOTHERBOARD "Motherboard"
32
+#define NETDATA_SENSOR_COMPONENT_NETWORK "Network"
33
+#define NETDATA_SENSOR_COMPONENT_POWER_SUPPLY "Power Supply"
34
+#define NETDATA_SENSOR_COMPONENT_SYSTEM "System"
35
+#define NETDATA_SENSOR_COMPONENT_PERIPHERAL "Peripheral"
36
+
37
+// netdata plugin defaults
38
+#define SENSORS_DICT_KEY_SIZE 2048 // the max size of the key for the dictionary of sensors
39
+#define SPEED_TEST_ITERATIONS 5 // how many times to repeat data collection to decide latency
40
+#define IPMI_SENSORS_DASHBOARD_PRIORITY 90000 // the priority of the sensors charts on the dashboard
41
+#define IPMI_SEL_DASHBOARD_PRIORITY 99000 // the priority of the SEL events chart on the dashboard
42
+#define IPMI_SENSORS_MIN_UPDATE_EVERY 5 // the minimum data collection frequency for sensors
43
+#define IPMI_SEL_MIN_UPDATE_EVERY 30 // the minimum data collection frequency for SEL events
44
+#define IPMI_ENABLE_SEL_BY_DEFAULT true // true/false, to enable/disable SEL by default
45
+#define IPMI_RESTART_EVERY_SECONDS 14400 // restart the plugin every this many seconds
46
+ // this is to prevent possible bugs/leaks in ipmi libraries
47
+#define IPMI_RESTART_IF_SENSORS_DONT_ITERATE_EVERY_SECONDS (10 * 60) // stale data collection detection time
48
+
49
+// forward definition of functions and structures
50
+struct netdata_ipmi_state;
51
+static void netdata_update_ipmi_sensor_reading(
52
+ int record_id
53
+ , int sensor_number
54
+ , int sensor_type
55
+ , int sensor_state
56
+ , int sensor_units
57
+ , int sensor_reading_type
58
+ , char *sensor_name
59
+ , void *sensor_reading
60
+ , int event_reading_type_code
61
+ , int sensor_bitmask_type
62
+ , int sensor_bitmask
63
+ , char **sensor_bitmask_strings
64
+ , struct netdata_ipmi_state *state
65
+);
66
+static void netdata_update_ipmi_sel_events_count(struct netdata_ipmi_state *state, uint32_t events);
67
+
68
+// END NETDATA CODE
69
+// ----------------------------------------------------------------------------
70
+
71
#include <stdio.h>
72
#include <stdlib.h>
73
#include <stdint.h>
77
#include <unistd.h>
78
#include <sys/time.h>
79
30
-#define IPMI_PARSE_DEVICE_LAN_STR "lan"
31
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR "lan_2_0"
32
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR2 "lan20"
33
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR3 "lan_20"
34
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR4 "lan2_0"
35
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR5 "lanplus"
36
-#define IPMI_PARSE_DEVICE_KCS_STR "kcs"
37
-#define IPMI_PARSE_DEVICE_SSIF_STR "ssif"
38
-#define IPMI_PARSE_DEVICE_OPENIPMI_STR "openipmi"
39
-#define IPMI_PARSE_DEVICE_OPENIPMI_STR2 "open"
40
-#define IPMI_PARSE_DEVICE_SUNBMC_STR "sunbmc"
41
-#define IPMI_PARSE_DEVICE_SUNBMC_STR2 "bmc"
42
-#define IPMI_PARSE_DEVICE_INTELDCMI_STR "inteldcmi"
43
-
80
#include <ipmi_monitoring.h>
81
#include <ipmi_monitoring_bitmasks.h>
82
+#include <ipmi_monitoring_offsets.h>
83
84
/* Communication Configuration - Initialize accordingly */
85
87
char *hostname = NULL;
88
89
/* In-band Communication Configuration */
53
-int driver_type = -1; // IPMI_MONITORING_DRIVER_TYPE_KCS; /* or -1 for default */
54
-int disable_auto_probe = 0; /* probe for in-band device */
55
-unsigned int driver_address = 0; /* not used if probing */
56
-unsigned int register_spacing = 0; /* not used if probing */
57
-char *driver_device = NULL; /* not used if probing */
90
+int driver_type = -1; // IPMI_MONITORING_DRIVER_TYPE_KCS, etc. or -1 for default
91
+int disable_auto_probe = 0; /* probe for in-band device */
92
+unsigned int driver_address = 0; /* not used if probing */
93
+unsigned int register_spacing = 0; /* not used if probing */
94
+char *driver_device = NULL; /* not used if probing */
95
96
/* Out-of-band Communication Configuration */
60
-int protocol_version = -1; //IPMI_MONITORING_PROTOCOL_VERSION_1_5; /* or -1 for default */
61
-char *username = "foousername";
62
-char *password = "foopassword";
63
-unsigned char *ipmi_k_g = NULL;
64
-unsigned int ipmi_k_g_len = 0;
65
-int privilege_level = -1; // IPMI_MONITORING_PRIVILEGE_LEVEL_USER; /* or -1 for default */
66
-int authentication_type = -1; // IPMI_MONITORING_AUTHENTICATION_TYPE_MD5; /* or -1 for default */
67
-int cipher_suite_id = 0; /* or -1 for default */
97
+int protocol_version = -1; // IPMI_MONITORING_PROTOCOL_VERSION_1_5, etc. or -1 for default
98
+char *username = "";
99
+char *password = "";
100
+unsigned char *k_g = NULL;
101
+unsigned int k_g_len = 0;
102
+int privilege_level = -1; // IPMI_MONITORING_PRIVILEGE_LEVEL_USER, etc. or -1 for default
103
+int authentication_type = -1; // IPMI_MONITORING_AUTHENTICATION_TYPE_MD5, etc. or -1 for default
104
+int cipher_suite_id = -1; /* 0 or -1 for default */
105
int session_timeout = 0; /* 0 for default */
106
int retransmission_timeout = 0; /* 0 for default */
107
108
/* Workarounds - specify workaround flags if necessary */
109
unsigned int workaround_flags = 0;
110
74
-/* Initialize w/ record id numbers to only monitor specific record ids */
75
-unsigned int record_ids[] = {0};
76
-unsigned int record_ids_length = 0;
77
-
78
-/* Initialize w/ sensor types to only monitor specific sensor types
79
- * see ipmi_monitoring.h sensor types list.
80
- */
81
-unsigned int sensor_types[] = {0};
82
-unsigned int sensor_types_length = 0;
83
-
111
/* Set to an appropriate alternate if desired */
112
char *sdr_cache_directory = "/tmp";
113
char *sensor_config_file = NULL;
114
+char *sel_config_file = NULL;
115
88
-/* Set to 1 or 0 to enable these sensor reading flags
89
- * - See ipmi_monitoring.h for descriptions of these flags.
90
- */
91
-int reread_sdr_cache = 0;
92
-int ignore_non_interpretable_sensors = 0;
93
-int bridge_sensors = 0;
94
-int interpret_oem_data = 0;
95
-int shared_sensors = 0;
96
-int discrete_reading = 1;
97
-int ignore_scanning_disabled = 0;
98
-int assume_bmc_owner = 0;
99
-int entity_sensor_names = 0;
116
+// controlled via command line options
117
+unsigned int global_sel_flags = 0;
118
+unsigned int global_sensor_reading_flags = IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING;
119
120
/* Initialization flags
121
*
125
*/
126
unsigned int ipmimonitoring_init_flags = 0;
127
109
-int errnum;
110
-
111
-// ----------------------------------------------------------------------------
112
-// SEL only variables
113
-
114
-/* Initialize w/ date range to only monitoring specific date range */
115
-char *date_begin = NULL; /* use MM/DD/YYYY format */
116
-char *date_end = NULL; /* use MM/DD/YYYY format */
117
-
118
-int assume_system_event_record = 0;
119
-
120
-char *sel_config_file = NULL;
121
-
122
-
128
// ----------------------------------------------------------------------------
129
// functions common to sensors and SEL
130
126
-static void
127
-_init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
128
-{
131
+static void initialize_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config) {
132
fatal_assert(ipmi_config);
133
134
ipmi_config->driver_type = driver_type;
140
ipmi_config->protocol_version = protocol_version;
141
ipmi_config->username = username;
142
ipmi_config->password = password;
140
- ipmi_config->k_g = ipmi_k_g;
141
- ipmi_config->k_g_len = ipmi_k_g_len;
143
+ ipmi_config->k_g = k_g;
144
+ ipmi_config->k_g_len = k_g_len;
145
ipmi_config->privilege_level = privilege_level;
146
ipmi_config->authentication_type = authentication_type;
147
ipmi_config->cipher_suite_id = cipher_suite_id;
151
ipmi_config->workaround_flags = workaround_flags;
152
}
153
151
-#ifdef NETDATA_COMMENTED
152
-static const char *
153
-_get_sensor_type_string (int sensor_type)
154
-{
155
- switch (sensor_type)
156
- {
154
+static const char *netdata_ipmi_get_sensor_type_string (int sensor_type, const char **component) {
155
+ switch (sensor_type) {
156
case IPMI_MONITORING_SENSOR_TYPE_RESERVED:
157
return ("Reserved");
158
+
159
case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
160
return ("Temperature");
161
+
162
case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
163
return ("Voltage");
164
+
165
case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
166
return ("Current");
167
+
168
case IPMI_MONITORING_SENSOR_TYPE_FAN:
169
return ("Fan");
170
+
171
case IPMI_MONITORING_SENSOR_TYPE_PHYSICAL_SECURITY:
172
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
173
return ("Physical Security");
174
+
175
case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_SECURITY_VIOLATION_ATTEMPT:
176
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
177
return ("Platform Security Violation Attempt");
178
+
179
case IPMI_MONITORING_SENSOR_TYPE_PROCESSOR:
180
+ *component = NETDATA_SENSOR_COMPONENT_PROCESSOR;
181
return ("Processor");
182
+
183
case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
184
+ *component = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY;
185
return ("Power Supply");
186
+
187
case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
188
+ *component = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY;
189
return ("Power Unit");
190
+
191
case IPMI_MONITORING_SENSOR_TYPE_COOLING_DEVICE:
192
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
193
return ("Cooling Device");
194
+
195
case IPMI_MONITORING_SENSOR_TYPE_OTHER_UNITS_BASED_SENSOR:
196
return ("Other Units Based Sensor");
197
+
198
case IPMI_MONITORING_SENSOR_TYPE_MEMORY:
199
+ *component = NETDATA_SENSOR_COMPONENT_MEMORY;
200
return ("Memory");
201
+
202
case IPMI_MONITORING_SENSOR_TYPE_DRIVE_SLOT:
203
+ *component = NETDATA_SENSOR_COMPONENT_STORAGE;
204
return ("Drive Slot");
205
+
206
case IPMI_MONITORING_SENSOR_TYPE_POST_MEMORY_RESIZE:
207
+ *component = NETDATA_SENSOR_COMPONENT_MEMORY;
208
return ("POST Memory Resize");
209
+
210
case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS:
211
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
212
return ("System Firmware Progress");
213
+
214
case IPMI_MONITORING_SENSOR_TYPE_EVENT_LOGGING_DISABLED:
215
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
216
return ("Event Logging Disabled");
217
+
218
case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG1:
219
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
220
return ("Watchdog 1");
221
+
222
case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_EVENT:
223
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
224
return ("System Event");
225
+
226
case IPMI_MONITORING_SENSOR_TYPE_CRITICAL_INTERRUPT:
227
return ("Critical Interrupt");
228
+
229
case IPMI_MONITORING_SENSOR_TYPE_BUTTON_SWITCH:
230
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
231
return ("Button/Switch");
232
+
233
case IPMI_MONITORING_SENSOR_TYPE_MODULE_BOARD:
234
return ("Module/Board");
235
+
236
case IPMI_MONITORING_SENSOR_TYPE_MICROCONTROLLER_COPROCESSOR:
237
+ *component = NETDATA_SENSOR_COMPONENT_PROCESSOR;
238
return ("Microcontroller/Coprocessor");
239
+
240
case IPMI_MONITORING_SENSOR_TYPE_ADD_IN_CARD:
241
return ("Add In Card");
242
+
243
case IPMI_MONITORING_SENSOR_TYPE_CHASSIS:
244
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
245
return ("Chassis");
246
+
247
case IPMI_MONITORING_SENSOR_TYPE_CHIP_SET:
248
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
249
return ("Chip Set");
250
+
251
case IPMI_MONITORING_SENSOR_TYPE_OTHER_FRU:
252
return ("Other Fru");
253
+
254
case IPMI_MONITORING_SENSOR_TYPE_CABLE_INTERCONNECT:
255
return ("Cable/Interconnect");
256
+
257
case IPMI_MONITORING_SENSOR_TYPE_TERMINATOR:
258
return ("Terminator");
259
+
260
case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_BOOT_INITIATED:
261
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
262
return ("System Boot Initiated");
263
+
264
case IPMI_MONITORING_SENSOR_TYPE_BOOT_ERROR:
265
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
266
return ("Boot Error");
267
+
268
case IPMI_MONITORING_SENSOR_TYPE_OS_BOOT:
269
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
270
return ("OS Boot");
271
+
272
case IPMI_MONITORING_SENSOR_TYPE_OS_CRITICAL_STOP:
273
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
274
return ("OS Critical Stop");
275
+
276
case IPMI_MONITORING_SENSOR_TYPE_SLOT_CONNECTOR:
277
return ("Slot/Connector");
278
+
279
case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
280
return ("System ACPI Power State");
281
+
282
case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG2:
283
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
284
return ("Watchdog 2");
285
+
286
case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_ALERT:
287
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
288
return ("Platform Alert");
289
+
290
case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
291
return ("Entity Presence");
292
+
293
case IPMI_MONITORING_SENSOR_TYPE_MONITOR_ASIC_IC:
294
return ("Monitor ASIC/IC");
295
+
296
case IPMI_MONITORING_SENSOR_TYPE_LAN:
297
+ *component = NETDATA_SENSOR_COMPONENT_NETWORK;
298
return ("LAN");
299
+
300
case IPMI_MONITORING_SENSOR_TYPE_MANAGEMENT_SUBSYSTEM_HEALTH:
301
+ *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
302
return ("Management Subsystem Health");
303
+
304
case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
305
return ("Battery");
306
+
307
case IPMI_MONITORING_SENSOR_TYPE_SESSION_AUDIT:
308
return ("Session Audit");
309
+
310
case IPMI_MONITORING_SENSOR_TYPE_VERSION_CHANGE:
311
return ("Version Change");
312
+
313
case IPMI_MONITORING_SENSOR_TYPE_FRU_STATE:
314
return ("FRU State");
247
- }
248
-
249
- return ("Unrecognized");
250
-}
251
-#endif // NETDATA_COMMENTED
315
316
+ case IPMI_MONITORING_SENSOR_TYPE_UNKNOWN:
317
+ return ("Unknown");
318
254
-// ----------------------------------------------------------------------------
255
-// BEGIN NETDATA CODE
319
+ default:
320
+ if(sensor_type >= IPMI_MONITORING_SENSOR_TYPE_OEM_MIN && sensor_type <= IPMI_MONITORING_SENSOR_TYPE_OEM_MAX)
321
+ return ("OEM");
322
257
-static int debug = 0;
323
+ return ("Unrecognized");
324
+ }
325
+}
326
259
-static int netdata_update_every = 5; // this is the minimum update frequency
260
-static int netdata_priority = 90000;
261
-static int netdata_do_sel = 1;
327
+#define netdata_ipmi_get_value_int(var, func, ctx) do { \
328
+ (var) = func(ctx); \
329
+ if( (var) < 0) { \
330
+ collector_error("%s(): call to " #func " failed: %s", \
331
+ __FUNCTION__, ipmi_monitoring_ctx_errormsg(ctx)); \
332
+ goto cleanup; \
333
+ } \
334
+ timing_step(TIMING_STEP_FREEIPMI_READ_ ## var); \
335
+} while(0)
336
+
337
+#define netdata_ipmi_get_value_ptr(var, func, ctx) do { \
338
+ (var) = func(ctx); \
339
+ if(!(var)) { \
340
+ collector_error("%s(): call to " #func " failed: %s", \
341
+ __FUNCTION__, ipmi_monitoring_ctx_errormsg(ctx)); \
342
+ goto cleanup; \
343
+ } \
344
+ timing_step(TIMING_STEP_FREEIPMI_READ_ ## var); \
345
+} while(0)
346
+
347
+#define netdata_ipmi_get_value_no_check(var, func, ctx) do { \
348
+ (var) = func(ctx); \
349
+ timing_step(TIMING_STEP_FREEIPMI_READ_ ## var); \
350
+} while(0)
351
+
352
+static int netdata_read_ipmi_sensors(struct ipmi_monitoring_ipmi_config *ipmi_config, struct netdata_ipmi_state *state) {
353
+ timing_init();
354
263
-static size_t netdata_sensors_updated = 0;
264
-static size_t netdata_sensors_collected = 0;
265
-static size_t netdata_sel_events = 0;
266
-static size_t netdata_sensors_states_nominal = 0;
267
-static size_t netdata_sensors_states_warning = 0;
268
-static size_t netdata_sensors_states_critical = 0;
355
+ ipmi_monitoring_ctx_t ctx = NULL;
356
+ unsigned int sensor_reading_flags = global_sensor_reading_flags;
357
+ int i;
358
+ int sensor_count;
359
+ int rv = -1;
360
270
-struct sensor {
271
- int record_id;
272
- int sensor_number;
273
- int sensor_type;
274
- int sensor_state;
275
- int sensor_units;
276
- char *sensor_name;
361
+ if (!(ctx = ipmi_monitoring_ctx_create ())) {
362
+ collector_error("ipmi_monitoring_ctx_create()");
363
+ goto cleanup;
364
+ }
365
278
- int sensor_reading_type;
279
- union {
280
- uint8_t bool_value;
281
- uint32_t uint32_value;
282
- double double_value;
283
- } sensor_reading;
366
+ timing_step(TIMING_STEP_FREEIPMI_CTX_CREATE);
367
285
- int sent;
286
- int ignore;
287
- int exposed;
288
- int updated;
289
- struct sensor *next;
290
-} *sensors_root = NULL;
368
+ if (sdr_cache_directory) {
369
+ if (ipmi_monitoring_ctx_sdr_cache_directory (ctx, sdr_cache_directory) < 0) {
370
+ collector_error("ipmi_monitoring_ctx_sdr_cache_directory(): %s\n", ipmi_monitoring_ctx_errormsg (ctx));
371
+ goto cleanup;
372
+ }
373
+ }
374
292
-static void netdata_mark_as_not_updated() {
293
- struct sensor *sn;
294
- for(sn = sensors_root; sn ;sn = sn->next)
295
- sn->updated = sn->sent = 0;
375
+ timing_step(TIMING_STEP_FREEIPMI_DSR_CACHE_DIR);
376
297
- netdata_sensors_updated = 0;
298
- netdata_sensors_collected = 0;
299
- netdata_sel_events = 0;
377
+ // Must call otherwise only default interpretations ever used
378
+ // sensor_config_file can be NULL
379
+ if (ipmi_monitoring_ctx_sensor_config_file (ctx, sensor_config_file) < 0) {
380
+ collector_error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n", ipmi_monitoring_ctx_errormsg (ctx));
381
+ goto cleanup;
382
+ }
383
301
- netdata_sensors_states_nominal = 0;
302
- netdata_sensors_states_warning = 0;
303
- netdata_sensors_states_critical = 0;
304
-}
384
+ timing_step(TIMING_STEP_FREEIPMI_SENSOR_CONFIG_FILE);
385
+
386
+ if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
387
+ hostname,
388
+ ipmi_config,
389
+ sensor_reading_flags,
390
+ NULL,
391
+ 0,
392
+ NULL,
393
+ NULL)) < 0) {
394
+ collector_error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
395
+ ipmi_monitoring_ctx_errormsg (ctx));
396
+ goto cleanup;
397
+ }
398
306
-static void send_chart_to_netdata_for_units(int units) {
307
- struct sensor *sn, *sn_stored;
308
- int dupfound, multiplier;
399
+ timing_step(TIMING_STEP_FREEIPMI_SENSOR_READINGS_BY_X);
400
310
- switch(units) {
311
- case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
312
- printf("CHART ipmi.temperatures_c '' 'System Celsius Temperatures read by IPMI' 'Celsius' 'temperatures' 'ipmi.temperatures_c' 'line' %d %d\n"
313
- , netdata_priority + 10
314
- , netdata_update_every
315
- );
316
- break;
401
+ for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (ctx)) {
402
+ int record_id, sensor_number, sensor_type, sensor_state, sensor_units,
403
+ sensor_bitmask_type, sensor_bitmask, event_reading_type_code, sensor_reading_type;
404
318
- case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
319
- printf("CHART ipmi.temperatures_f '' 'System Fahrenheit Temperatures read by IPMI' 'Fahrenheit' 'temperatures' 'ipmi.temperatures_f' 'line' %d %d\n"
320
- , netdata_priority + 11
321
- , netdata_update_every
322
- );
323
- break;
405
+ char **sensor_bitmask_strings = NULL;
406
+ char *sensor_name = NULL;
407
+ void *sensor_reading;
408
325
- case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
326
- printf("CHART ipmi.volts '' 'System Voltages read by IPMI' 'Volts' 'voltages' 'ipmi.voltages' 'line' %d %d\n"
327
- , netdata_priority + 12
328
- , netdata_update_every
329
- );
330
- break;
409
+ netdata_ipmi_get_value_int(record_id, ipmi_monitoring_sensor_read_record_id, ctx);
410
+ netdata_ipmi_get_value_int(sensor_number, ipmi_monitoring_sensor_read_sensor_number, ctx);
411
+ netdata_ipmi_get_value_int(sensor_type, ipmi_monitoring_sensor_read_sensor_type, ctx);
412
+ netdata_ipmi_get_value_ptr(sensor_name, ipmi_monitoring_sensor_read_sensor_name, ctx);
413
+ netdata_ipmi_get_value_int(sensor_state, ipmi_monitoring_sensor_read_sensor_state, ctx);
414
+ netdata_ipmi_get_value_int(sensor_units, ipmi_monitoring_sensor_read_sensor_units, ctx);
415
+ netdata_ipmi_get_value_int(sensor_bitmask_type, ipmi_monitoring_sensor_read_sensor_bitmask_type, ctx);
416
+ netdata_ipmi_get_value_int(sensor_bitmask, ipmi_monitoring_sensor_read_sensor_bitmask, ctx);
417
+ // it's ok for this to be NULL, i.e. sensor_bitmask == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN
418
+ netdata_ipmi_get_value_no_check(sensor_bitmask_strings, ipmi_monitoring_sensor_read_sensor_bitmask_strings, ctx);
419
+ netdata_ipmi_get_value_int(sensor_reading_type, ipmi_monitoring_sensor_read_sensor_reading_type, ctx);
420
+ // whatever we read from the sensor, it is ok
421
+ netdata_ipmi_get_value_no_check(sensor_reading, ipmi_monitoring_sensor_read_sensor_reading, ctx);
422
+ netdata_ipmi_get_value_int(event_reading_type_code, ipmi_monitoring_sensor_read_event_reading_type_code, ctx);
423
+
424
+ netdata_update_ipmi_sensor_reading(
425
+ record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type, sensor_name,
426
+ sensor_reading, event_reading_type_code, sensor_bitmask_type, sensor_bitmask, sensor_bitmask_strings,
427
+ state
428
+ );
429
332
- case IPMI_MONITORING_SENSOR_UNITS_AMPS:
333
- printf("CHART ipmi.amps '' 'System Current read by IPMI' 'Amps' 'current' 'ipmi.amps' 'line' %d %d\n"
334
- , netdata_priority + 13
335
- , netdata_update_every
336
- );
337
- break;
430
+#ifdef NETDATA_COMMENTED
431
+ /* It is possible you may want to monitor specific event
432
+ * conditions that may occur. If that is the case, you may want
433
+ * to check out what specific bitmask type and bitmask events
434
+ * occurred. See ipmi_monitoring_bitmasks.h for a list of
435
+ * bitmasks and types.
436
+ */
437
339
- case IPMI_MONITORING_SENSOR_UNITS_RPM:
340
- printf("CHART ipmi.rpm '' 'System Fans read by IPMI' 'RPM' 'fans' 'ipmi.rpm' 'line' %d %d\n"
341
- , netdata_priority + 14
342
- , netdata_update_every
343
- );
344
- break;
438
+ if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
439
+ printf (", %Xh", sensor_bitmask);
440
+ else
441
+ printf (", N/A");
442
346
- case IPMI_MONITORING_SENSOR_UNITS_WATTS:
347
- printf("CHART ipmi.watts '' 'System Power read by IPMI' 'Watts' 'power' 'ipmi.watts' 'line' %d %d\n"
348
- , netdata_priority + 5
349
- , netdata_update_every
350
- );
351
- break;
443
+ if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN
444
+ && sensor_bitmask_strings)
445
+ {
446
+ unsigned int i = 0;
447
353
- case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
354
- printf("CHART ipmi.percent '' 'System Metrics read by IPMI' '%%' 'other' 'ipmi.percent' 'line' %d %d\n"
355
- , netdata_priority + 15
356
- , netdata_update_every
357
- );
358
- break;
448
+ printf (",");
449
360
- default:
361
- for(sn = sensors_root; sn; sn = sn->next)
362
- if(sn->sensor_units == units)
363
- sn->ignore = 1;
364
- return;
365
- }
450
+ while (sensor_bitmask_strings[i])
451
+ {
452
+ printf (" ");
453
367
- for(sn = sensors_root; sn; sn = sn->next) {
368
- dupfound = 0;
369
- if(sn->sensor_units == units && sn->updated && !sn->ignore) {
370
- sn->exposed = 1;
371
- multiplier = 1;
372
-
373
- switch(sn->sensor_reading_type) {
374
- case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
375
- multiplier = 1000;
376
- // fallthrough
377
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
378
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
379
- for (sn_stored = sensors_root; sn_stored; sn_stored = sn_stored->next) {
380
- if (sn_stored == sn) continue;
381
- // If the name is a duplicate, append the sensor number
382
- if ( !strcmp(sn_stored->sensor_name, sn->sensor_name) ) {
383
- dupfound = 1;
384
- printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 %d\n"
385
- , sn->sensor_number
386
- , sn->record_id
387
- , sn->sensor_reading_type
388
- , sn->sensor_name
389
- , sn->sensor_number
390
- , multiplier
391
- );
392
- break;
393
- }
394
- }
395
- // No duplicate name was found, display it just with Name
396
- if (!dupfound) {
397
- // display without ID
398
- printf("DIMENSION i%d_n%d_r%d '%s' absolute 1 %d\n"
399
- , sn->sensor_number
400
- , sn->record_id
401
- , sn->sensor_reading_type
402
- , sn->sensor_name
403
- , multiplier
404
- );
405
- }
406
- break;
454
+ printf ("'%s'",
455
+ sensor_bitmask_strings[i]);
456
408
- default:
409
- sn->ignore = 1;
410
- break;
457
+ i++;
458
}
459
}
413
- }
414
-}
460
+ else
461
+ printf (", N/A");
462
416
-static void send_metrics_to_netdata_for_units(int units) {
417
- struct sensor *sn;
463
+ printf ("\n");
464
+#endif // NETDATA_COMMENTED
465
+ }
466
419
- switch(units) {
420
- case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
421
- printf("BEGIN ipmi.temperatures_c\n");
422
- break;
467
+ rv = 0;
468
424
- case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
425
- printf("BEGIN ipmi.temperatures_f\n");
426
- break;
469
+cleanup:
470
+ if (ctx)
471
+ ipmi_monitoring_ctx_destroy (ctx);
472
428
- case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
429
- printf("BEGIN ipmi.volts\n");
430
- break;
473
+ timing_report();
474
432
- case IPMI_MONITORING_SENSOR_UNITS_AMPS:
433
- printf("BEGIN ipmi.amps\n");
434
- break;
475
+ return (rv);
476
+}
477
436
- case IPMI_MONITORING_SENSOR_UNITS_RPM:
437
- printf("BEGIN ipmi.rpm\n");
438
- break;
478
440
- case IPMI_MONITORING_SENSOR_UNITS_WATTS:
441
- printf("BEGIN ipmi.watts\n");
442
- break;
479
+static int netdata_get_ipmi_sel_events_count(struct ipmi_monitoring_ipmi_config *ipmi_config, struct netdata_ipmi_state *state) {
480
+ timing_init();
481
444
- case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
445
- printf("BEGIN ipmi.percent\n");
446
- break;
482
+ ipmi_monitoring_ctx_t ctx = NULL;
483
+ unsigned int sel_flags = global_sel_flags;
484
+ int sel_count;
485
+ int rv = -1;
486
448
- default:
449
- for(sn = sensors_root; sn; sn = sn->next)
450
- if(sn->sensor_units == units)
451
- sn->ignore = 1;
452
- return;
487
+ if (!(ctx = ipmi_monitoring_ctx_create ())) {
488
+ collector_error("ipmi_monitoring_ctx_create()");
489
+ goto cleanup;
490
}
491
455
- for(sn = sensors_root; sn; sn = sn->next) {
456
- if(sn->sensor_units == units && sn->updated && !sn->sent && !sn->ignore) {
457
- netdata_sensors_updated++;
458
-
459
- sn->sent = 1;
460
-
461
- switch(sn->sensor_reading_type) {
462
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
463
- printf("SET i%d_n%d_r%d = %u\n"
464
- , sn->sensor_number
465
- , sn->record_id
466
- , sn->sensor_reading_type
467
- , sn->sensor_reading.bool_value
468
- );
469
- break;
470
-
471
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
472
- printf("SET i%d_n%d_r%d = %u\n"
473
- , sn->sensor_number
474
- , sn->record_id
475
- , sn->sensor_reading_type
476
- , sn->sensor_reading.uint32_value
477
- );
478
- break;
479
-
480
- case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
481
- printf("SET i%d_n%d_r%d = %lld\n"
482
- , sn->sensor_number
483
- , sn->record_id
484
- , sn->sensor_reading_type
485
- , (long long int)(sn->sensor_reading.double_value * 1000)
486
- );
487
- break;
488
-
489
- default:
490
- sn->ignore = 1;
491
- break;
492
- }
492
+ if (sdr_cache_directory) {
493
+ if (ipmi_monitoring_ctx_sdr_cache_directory (ctx, sdr_cache_directory) < 0) {
494
+ collector_error( "ipmi_monitoring_ctx_sdr_cache_directory(): %s",
495
+ ipmi_monitoring_ctx_errormsg (ctx));
496
+ goto cleanup;
497
}
498
}
499
496
- printf("END\n");
497
-}
498
-
499
-static void send_metrics_to_netdata() {
500
- static int sel_chart_generated = 0, sensors_states_chart_generated = 0;
501
- struct sensor *sn;
502
-
503
- if(netdata_do_sel && !sel_chart_generated) {
504
- sel_chart_generated = 1;
505
- printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' ipmi.sel area %d %d\n"
506
- , netdata_priority + 2
507
- , netdata_update_every
508
- );
509
- printf("DIMENSION events '' absolute 1 1\n");
500
+ // Must call otherwise only default interpretations ever used
501
+ // sel_config_file can be NULL
502
+ if (ipmi_monitoring_ctx_sel_config_file (ctx, sel_config_file) < 0) {
503
+ collector_error( "ipmi_monitoring_ctx_sel_config_file(): %s",
504
+ ipmi_monitoring_ctx_errormsg (ctx));
505
+ goto cleanup;
506
}
507
512
- if(!sensors_states_chart_generated) {
513
- sensors_states_chart_generated = 1;
514
- printf("CHART ipmi.sensors_states '' 'IPMI Sensors State' 'sensors' 'states' ipmi.sensors_states line %d %d\n"
515
- , netdata_priority + 1
516
- , netdata_update_every
517
- );
518
- printf("DIMENSION nominal '' absolute 1 1\n");
519
- printf("DIMENSION critical '' absolute 1 1\n");
520
- printf("DIMENSION warning '' absolute 1 1\n");
508
+ if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
509
+ hostname,
510
+ ipmi_config,
511
+ sel_flags,
512
+ NULL,
513
+ 0,
514
+ NULL,
515
+ NULL)) < 0) {
516
+ collector_error( "ipmi_monitoring_sel_by_record_id(): %s",
517
+ ipmi_monitoring_ctx_errormsg (ctx));
518
+ goto cleanup;
519
}
520
523
- // generate the CHART/DIMENSION lines, if we have to
524
- for(sn = sensors_root; sn; sn = sn->next)
525
- if(sn->updated && !sn->exposed && !sn->ignore)
526
- send_chart_to_netdata_for_units(sn->sensor_units);
521
+ netdata_update_ipmi_sel_events_count(state, sel_count >= 0 ? sel_count : 0);
522
528
- if(netdata_do_sel) {
529
- printf(
530
- "BEGIN ipmi.events\n"
531
- "SET events = %zu\n"
532
- "END\n"
533
- , netdata_sel_events
534
- );
535
- }
523
+ rv = 0;
524
537
- printf(
538
- "BEGIN ipmi.sensors_states\n"
539
- "SET nominal = %zu\n"
540
- "SET warning = %zu\n"
541
- "SET critical = %zu\n"
542
- "END\n"
543
- , netdata_sensors_states_nominal
544
- , netdata_sensors_states_warning
545
- , netdata_sensors_states_critical
546
- );
547
-
548
- // send metrics to netdata
549
- for(sn = sensors_root; sn; sn = sn->next)
550
- if(sn->updated && sn->exposed && !sn->sent && !sn->ignore)
551
- send_metrics_to_netdata_for_units(sn->sensor_units);
525
+cleanup:
526
+ if (ctx)
527
+ ipmi_monitoring_ctx_destroy (ctx);
528
553
-}
529
+ timing_report();
530
555
-static int *excluded_record_ids = NULL;
556
-size_t excluded_record_ids_length = 0;
531
+ return (rv);
532
+}
533
558
-static void excluded_record_ids_parse(const char *s) {
559
- if(!s) return;
534
+// ----------------------------------------------------------------------------
535
+// copied from freeipmi codebase commit 8dea6dec4012d0899901e595f2c868a05e1cefed
536
+// added netdata_ in-front to not overwrite library functions
537
+
538
+// FROM: common/miscutil/network.c
539
+static int netdata_host_is_localhost (const char *host) {
540
+ /* Ordered by my assumption of most popular */
541
+ if (!strcasecmp (host, "localhost")
542
+ || !strcmp (host, "127.0.0.1")
543
+ || !strcasecmp (host, "ipv6-localhost")
544
+ || !strcmp (host, "::1")
545
+ || !strcasecmp (host, "ip6-localhost")
546
+ || !strcmp (host, "0:0:0:0:0:0:0:1"))
547
+ return (1);
548
561
- while(*s) {
562
- while(*s && !isdigit(*s)) s++;
549
+ return (0);
550
+}
551
564
- if(isdigit(*s)) {
552
+// FROM: common/parsecommon/parse-common.h
553
+#define IPMI_PARSE_DEVICE_LAN_STR "lan"
554
+#define IPMI_PARSE_DEVICE_LAN_2_0_STR "lan_2_0"
555
+#define IPMI_PARSE_DEVICE_LAN_2_0_STR2 "lan20"
556
+#define IPMI_PARSE_DEVICE_LAN_2_0_STR3 "lan_20"
557
+#define IPMI_PARSE_DEVICE_LAN_2_0_STR4 "lan2_0"
558
+#define IPMI_PARSE_DEVICE_LAN_2_0_STR5 "lanplus"
559
+#define IPMI_PARSE_DEVICE_KCS_STR "kcs"
560
+#define IPMI_PARSE_DEVICE_SSIF_STR "ssif"
561
+#define IPMI_PARSE_DEVICE_OPENIPMI_STR "openipmi"
562
+#define IPMI_PARSE_DEVICE_OPENIPMI_STR2 "open"
563
+#define IPMI_PARSE_DEVICE_SUNBMC_STR "sunbmc"
564
+#define IPMI_PARSE_DEVICE_SUNBMC_STR2 "bmc"
565
+#define IPMI_PARSE_DEVICE_INTELDCMI_STR "inteldcmi"
566
+
567
+// FROM: common/parsecommon/parse-common.c
568
+// changed the return values to match ipmi_monitoring.h
569
+static int netdata_parse_outofband_driver_type (const char *str) {
570
+ if (strcasecmp (str, IPMI_PARSE_DEVICE_LAN_STR) == 0)
571
+ return (IPMI_MONITORING_PROTOCOL_VERSION_1_5);
572
+
573
+ /* support "lanplus" for those that might be used to ipmitool.
574
+ * support typo variants to ease.
575
+ */
576
+ else if (strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR) == 0
577
+ || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR2) == 0
578
+ || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR3) == 0
579
+ || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR4) == 0
580
+ || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR5) == 0)
581
+ return (IPMI_MONITORING_PROTOCOL_VERSION_2_0);
582
+
583
+ return (-1);
584
+}
585
+
586
+// FROM: common/parsecommon/parse-common.c
587
+// changed the return values to match ipmi_monitoring.h
588
+static int netdata_parse_inband_driver_type (const char *str) {
589
+ if (strcasecmp (str, IPMI_PARSE_DEVICE_KCS_STR) == 0)
590
+ return (IPMI_MONITORING_DRIVER_TYPE_KCS);
591
+ else if (strcasecmp (str, IPMI_PARSE_DEVICE_SSIF_STR) == 0)
592
+ return (IPMI_MONITORING_DRIVER_TYPE_SSIF);
593
+ /* support "open" for those that might be used to
594
+ * ipmitool.
595
+ */
596
+ else if (strcasecmp (str, IPMI_PARSE_DEVICE_OPENIPMI_STR) == 0
597
+ || strcasecmp (str, IPMI_PARSE_DEVICE_OPENIPMI_STR2) == 0)
598
+ return (IPMI_MONITORING_DRIVER_TYPE_OPENIPMI);
599
+ /* support "bmc" for those that might be used to
600
+ * ipmitool.
601
+ */
602
+ else if (strcasecmp (str, IPMI_PARSE_DEVICE_SUNBMC_STR) == 0
603
+ || strcasecmp (str, IPMI_PARSE_DEVICE_SUNBMC_STR2) == 0)
604
+ return (IPMI_MONITORING_DRIVER_TYPE_SUNBMC);
605
+
606
+#ifdef IPMI_MONITORING_DRIVER_TYPE_INTELDCMI
607
+ else if (strcasecmp (str, IPMI_PARSE_DEVICE_INTELDCMI_STR) == 0)
608
+ return (IPMI_MONITORING_DRIVER_TYPE_INTELDCMI);
609
+#endif // IPMI_MONITORING_DRIVER_TYPE_INTELDCMI
610
+
611
+ return (-1);
612
+}
613
+
614
+// ----------------------------------------------------------------------------
615
+// BEGIN NETDATA CODE
616
+
617
+typedef enum __attribute__((packed)) {
618
+ IPMI_COLLECT_TYPE_SENSORS = (1 << 0),
619
+ IPMI_COLLECT_TYPE_SEL = (1 << 1),
620
+} IPMI_COLLECTION_TYPE;
621
+
622
+struct sensor {
623
+ int sensor_type;
624
+ int sensor_state;
625
+ int sensor_units;
626
+ char *sensor_name;
627
+
628
+ int sensor_reading_type;
629
+ union {
630
+ uint8_t bool_value;
631
+ uint32_t uint32_value;
632
+ double double_value;
633
+ } sensor_reading;
634
+
635
+ // netdata provided
636
+ const char *context;
637
+ const char *title;
638
+ const char *units;
639
+ const char *family;
640
+ const char *chart_type;
641
+ const char *dimension;
642
+ int priority;
643
+
644
+ const char *type;
645
+ const char *component;
646
+
647
+ int multiplier;
648
+ bool do_metric;
649
+ bool do_state;
650
+ bool metric_chart_sent;
651
+ bool state_chart_sent;
652
+ usec_t last_collected_metric_ut;
653
+ usec_t last_collected_state_ut;
654
+};
655
+
656
+typedef enum __attribute__((packed)) {
657
+ ICS_INIT,
658
+ ICS_INIT_FAILED,
659
+ ICS_RUNNING,
660
+ ICS_FAILED,
661
+} IPMI_COLLECTOR_STATUS;
662
+
663
+struct netdata_ipmi_state {
664
+ bool debug;
665
+
666
+ struct {
667
+ IPMI_COLLECTOR_STATUS status;
668
+ usec_t last_iteration_ut;
669
+ size_t collected;
670
+ usec_t now_ut;
671
+ usec_t freq_ut;
672
+ int priority;
673
+ DICTIONARY *dict;
674
+ } sensors;
675
+
676
+ struct {
677
+ IPMI_COLLECTOR_STATUS status;
678
+ usec_t last_iteration_ut;
679
+ size_t events;
680
+ usec_t now_ut;
681
+ usec_t freq_ut;
682
+ int priority;
683
+ } sel;
684
+
685
+ struct {
686
+ usec_t now_ut;
687
+ } updates;
688
+};
689
+
690
+// ----------------------------------------------------------------------------
691
+// excluded record ids maintenance (both for sensor data and state)
692
+
693
+static int *excluded_record_ids = NULL;
694
+size_t excluded_record_ids_length = 0;
695
+
696
+static void excluded_record_ids_parse(const char *s, bool debug) {
697
+ if(!s) return;
698
+
699
+ while(*s) {
700
+ while(*s && !isdigit(*s)) s++;
701
+
702
+ if(isdigit(*s)) {
703
char *e;
704
unsigned long n = strtoul(s, &e, 10);
705
s = e;
706
707
if(n != 0) {
570
- excluded_record_ids = realloc(excluded_record_ids, (excluded_record_ids_length + 1) * sizeof(int));
571
- if(!excluded_record_ids) {
572
- fprintf(stderr, "freeipmi.plugin: failed to allocate memory. Exiting.");
573
- exit(1);
574
- }
708
+ excluded_record_ids = reallocz(excluded_record_ids, (excluded_record_ids_length + 1) * sizeof(int));
709
excluded_record_ids[excluded_record_ids_length++] = (int)n;
710
}
711
}
712
}
713
714
if(debug) {
581
- fprintf(stderr, "freeipmi.plugin: excluded record ids:");
715
+ fprintf(stderr, "%s: excluded record ids:", program_name);
716
size_t i;
717
for(i = 0; i < excluded_record_ids_length; i++) {
718
fprintf(stderr, " %d", excluded_record_ids[i]);
724
static int *excluded_status_record_ids = NULL;
725
size_t excluded_status_record_ids_length = 0;
726
593
-static void excluded_status_record_ids_parse(const char *s) {
727
+static void excluded_status_record_ids_parse(const char *s, bool debug) {
728
if(!s) return;
729
730
while(*s) {
736
s = e;
737
738
if(n != 0) {
605
- excluded_status_record_ids = realloc(excluded_status_record_ids, (excluded_status_record_ids_length + 1) * sizeof(int));
606
- if(!excluded_status_record_ids) {
607
- fprintf(stderr, "freeipmi.plugin: failed to allocate memory. Exiting.");
608
- exit(1);
609
- }
739
+ excluded_status_record_ids = reallocz(excluded_status_record_ids, (excluded_status_record_ids_length + 1) * sizeof(int));
740
excluded_status_record_ids[excluded_status_record_ids_length++] = (int)n;
741
}
742
}
743
}
744
745
if(debug) {
616
- fprintf(stderr, "freeipmi.plugin: excluded status record ids:");
746
+ fprintf(stderr, "%s: excluded status record ids:", program_name);
747
size_t i;
748
for(i = 0; i < excluded_status_record_ids_length; i++) {
749
fprintf(stderr, " %d", excluded_status_record_ids[i]);
775
return 0;
776
}
777
648
-static void netdata_get_sensor(
649
- int record_id
650
- , int sensor_number
651
- , int sensor_type
652
- , int sensor_state
653
- , int sensor_units
654
- , int sensor_reading_type
655
- , char *sensor_name
656
- , void *sensor_reading
657
-) {
658
- // find the sensor record
659
- struct sensor *sn;
660
- for(sn = sensors_root; sn ;sn = sn->next)
661
- if( sn->record_id == record_id &&
662
- sn->sensor_number == sensor_number &&
663
- sn->sensor_reading_type == sensor_reading_type &&
664
- sn->sensor_units == sensor_units &&
665
- !strcmp(sn->sensor_name, sensor_name)
666
- )
667
- break;
778
+// ----------------------------------------------------------------------------
779
+// data collection functions
780
669
- if(!sn) {
670
- // not found, create it
671
- // check if it is excluded
672
- if(excluded_record_ids_check(record_id)) {
673
- if(debug) fprintf(stderr, "Sensor '%s' is excluded by excluded_record_ids_check()\n", sensor_name);
674
- return;
675
- }
781
+struct {
782
+ const char *search;
783
+ SIMPLE_PATTERN *pattern;
784
+ const char *label;
785
+} sensors_component_patterns[] = {
786
677
- if(debug) fprintf(stderr, "Allocating new sensor data record for sensor '%s', id %d, number %d, type %d, state %d, units %d, reading_type %d\n", sensor_name, record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type);
787
+ // The order is important!
788
+ // They are evaluated top to bottom
789
+ // The first the matches is used
790
679
- sn = calloc(1, sizeof(struct sensor));
680
- if(!sn) {
681
- fatal("cannot allocate %zu bytes of memory.", sizeof(struct sensor));
682
- }
791
+ {
792
+ .search = "*DIMM*|*_DIM*|*VTT*|*VDDQ*|*ECC*|*MEM*CRC*|*MEM*BD*",
793
+ .label = NETDATA_SENSOR_COMPONENT_MEMORY_MODULE,
794
+ },
795
+ {
796
+ .search = "*CPU*|SOC_*|*VDDCR*|P*_VDD*|*_DTS|*VCORE*|*PROC*",
797
+ .label = NETDATA_SENSOR_COMPONENT_PROCESSOR,
798
+ },
799
+ {
800
+ .search = "IPU*",
801
+ .label = NETDATA_SENSOR_COMPONENT_IPU,
802
+ },
803
+ {
804
+ .search = "M2_*|*SSD*|*HSC*|*HDD*|*NVME*",
805
+ .label = NETDATA_SENSOR_COMPONENT_STORAGE,
806
+ },
807
+ {
808
+ .search = "MB_*|*PCH*|*VBAT*|*I/O*BD*|*IO*BD*",
809
+ .label = NETDATA_SENSOR_COMPONENT_MOTHERBOARD,
810
+ },
811
+ {
812
+ .search = "Watchdog|SEL|SYS_*|*CHASSIS*",
813
+ .label = NETDATA_SENSOR_COMPONENT_SYSTEM,
814
+ },
815
+ {
816
+ .search = "PS*|P_*|*PSU*|*PWR*|*TERMV*|*D2D*",
817
+ .label = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY,
818
+ },
819
684
- sn->record_id = record_id;
685
- sn->sensor_number = sensor_number;
686
- sn->sensor_type = sensor_type;
687
- sn->sensor_state = sensor_state;
688
- sn->sensor_units = sensor_units;
689
- sn->sensor_reading_type = sensor_reading_type;
690
- sn->sensor_name = strdup(sensor_name);
691
- if(!sn->sensor_name) {
692
- fatal("cannot allocate %zu bytes of memory.", strlen(sensor_name));
820
+ // fallback components
821
+ {
822
+ .search = "VR_P*|*VRMP*",
823
+ .label = NETDATA_SENSOR_COMPONENT_PROCESSOR,
824
+ },
825
+ {
826
+ .search = "*VSB*|*PS*",
827
+ .label = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY,
828
+ },
829
+ {
830
+ .search = "*MEM*|*MEM*RAID*",
831
+ .label = NETDATA_SENSOR_COMPONENT_MEMORY,
832
+ },
833
+ {
834
+ .search = "*RAID*", // there is also "Memory RAID", so keep this after memory
835
+ .label = NETDATA_SENSOR_COMPONENT_STORAGE,
836
+ },
837
+ {
838
+ .search = "*PERIPHERAL*|*USB*",
839
+ .label = NETDATA_SENSOR_COMPONENT_PERIPHERAL,
840
+ },
841
+ {
842
+ .search = "*FAN*|*12V*|*VCC*|*PCI*|*CHIPSET*|*AMP*|*BD*",
843
+ .label = NETDATA_SENSOR_COMPONENT_SYSTEM,
844
+ },
845
+
846
+ // terminator
847
+ {
848
+ .search = NULL,
849
+ .label = NULL,
850
}
851
+};
852
695
- sn->next = sensors_root;
696
- sensors_root = sn;
697
- }
698
- else {
699
- if(debug) fprintf(stderr, "Reusing sensor record for sensor '%s', id %d, number %d, type %d, state %d, units %d, reading_type %d\n", sensor_name, record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type);
853
+static const char *netdata_sensor_name_to_component(const char *sensor_name) {
854
+ for(int i = 0; sensors_component_patterns[i].search ;i++) {
855
+ if(!sensors_component_patterns[i].pattern)
856
+ sensors_component_patterns[i].pattern = simple_pattern_create(sensors_component_patterns[i].search, "|", SIMPLE_PATTERN_EXACT, false);
857
+
858
+ if(simple_pattern_matches(sensors_component_patterns[i].pattern, sensor_name))
859
+ return sensors_component_patterns[i].label;
860
}
861
702
- switch(sensor_reading_type) {
862
+ return "Other";
863
+}
864
+
865
+const char *netdata_collect_type_to_string(IPMI_COLLECTION_TYPE type) {
866
+ if((type & (IPMI_COLLECT_TYPE_SENSORS|IPMI_COLLECT_TYPE_SEL)) == (IPMI_COLLECT_TYPE_SENSORS|IPMI_COLLECT_TYPE_SEL))
867
+ return "sensors,sel";
868
+ if(type & IPMI_COLLECT_TYPE_SEL)
869
+ return "sel";
870
+ if(type & IPMI_COLLECT_TYPE_SENSORS)
871
+ return "sensors";
872
+
873
+ return "unknown";
874
+}
875
+
876
+static void netdata_sensor_set_value(struct sensor *sn, void *sensor_reading, struct netdata_ipmi_state *state __maybe_unused) {
877
+ switch(sn->sensor_reading_type) {
878
case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
879
sn->sensor_reading.bool_value = *((uint8_t *)sensor_reading);
705
- sn->updated = 1;
706
- netdata_sensors_collected++;
880
break;
881
882
case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
883
sn->sensor_reading.uint32_value = *((uint32_t *)sensor_reading);
711
- sn->updated = 1;
712
- netdata_sensors_collected++;
884
break;
885
886
case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
887
sn->sensor_reading.double_value = *((double *)sensor_reading);
717
- sn->updated = 1;
718
- netdata_sensors_collected++;
719
- break;
720
-
721
- default:
722
- if(debug) fprintf(stderr, "Unknown reading type - Ignoring sensor record for sensor '%s', id %d, number %d, type %d, state %d, units %d, reading_type %d\n", sensor_name, record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type);
723
- sn->ignore = 1;
724
- break;
725
- }
726
-
727
- // check if it is excluded
728
- if(excluded_status_record_ids_check(record_id)) {
729
- if(debug) fprintf(stderr, "Sensor '%s' is excluded for status check, by excluded_status_record_ids_check()\n", sensor_name);
730
- return;
731
- }
732
-
733
- switch(sensor_state) {
734
- case IPMI_MONITORING_STATE_NOMINAL:
735
- netdata_sensors_states_nominal++;
736
- break;
737
-
738
- case IPMI_MONITORING_STATE_WARNING:
739
- netdata_sensors_states_warning++;
740
- break;
741
-
742
- case IPMI_MONITORING_STATE_CRITICAL:
743
- netdata_sensors_states_critical++;
888
break;
889
890
default:
891
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNKNOWN:
892
+ sn->do_metric = false;
893
break;
894
}
895
}
896
751
-static void netdata_get_sel(
752
- int record_id
753
- , int record_type_class
754
- , int sel_state
897
+static void netdata_update_ipmi_sensor_reading(
898
+ int record_id
899
+ , int sensor_number
900
+ , int sensor_type
901
+ , int sensor_state
902
+ , int sensor_units
903
+ , int sensor_reading_type
904
+ , char *sensor_name
905
+ , void *sensor_reading
906
+ , int event_reading_type_code __maybe_unused
907
+ , int sensor_bitmask_type __maybe_unused
908
+ , int sensor_bitmask __maybe_unused
909
+ , char **sensor_bitmask_strings __maybe_unused
910
+ , struct netdata_ipmi_state *state
911
) {
756
- (void)record_id;
757
- (void)record_type_class;
758
- (void)sel_state;
759
-
760
- netdata_sel_events++;
761
-}
912
+ if(unlikely(sensor_state == IPMI_MONITORING_STATE_UNKNOWN &&
913
+ sensor_type == IPMI_MONITORING_SENSOR_TYPE_UNKNOWN &&
914
+ sensor_units == IPMI_MONITORING_SENSOR_UNITS_UNKNOWN &&
915
+ sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNKNOWN &&
916
+ (!sensor_name || !*sensor_name)))
917
+ // we can't do anything about this sensor - everything is unknown
918
+ return;
919
920
+ if(unlikely(!sensor_name || !*sensor_name))
921
+ sensor_name = "UNNAMED";
922
764
-// END NETDATA CODE
765
-// ----------------------------------------------------------------------------
923
+ state->sensors.collected++;
924
925
+ char key[SENSORS_DICT_KEY_SIZE + 1];
926
+ snprintfz(key, SENSORS_DICT_KEY_SIZE, "i%d_n%d_t%d_u%d_%s",
927
+ record_id, sensor_number, sensor_reading_type, sensor_units, sensor_name);
928
768
-static int
769
-_ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
770
-{
771
- ipmi_monitoring_ctx_t ctx = NULL;
772
- unsigned int sensor_reading_flags = 0;
773
- int i;
774
- int sensor_count;
775
- int rv = -1;
929
+ // find the sensor record
930
+ const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(state->sensors.dict, key);
931
+ if(likely(item)) {
932
+ // recurring collection
933
777
- if (!(ctx = ipmi_monitoring_ctx_create ())) {
778
- collector_error("ipmi_monitoring_ctx_create()");
779
- goto cleanup;
780
- }
934
+ if(state->debug)
935
+ fprintf(stderr, "%s: reusing sensor record for sensor '%s', id %d, number %d, type %d, state %d, units %d, reading_type %d\n",
936
+ program_name, sensor_name, record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type);
937
782
- if (sdr_cache_directory)
783
- {
784
- if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
785
- sdr_cache_directory) < 0)
786
- {
787
- collector_error("ipmi_monitoring_ctx_sdr_cache_directory(): %s\n",
788
- ipmi_monitoring_ctx_errormsg (ctx));
789
- goto cleanup;
790
- }
791
- }
938
+ struct sensor *sn = dictionary_acquired_item_value(item);
939
793
- /* Must call otherwise only default interpretations ever used */
794
- if (sensor_config_file)
795
- {
796
- if (ipmi_monitoring_ctx_sensor_config_file (ctx,
797
- sensor_config_file) < 0)
798
- {
799
- collector_error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
800
- ipmi_monitoring_ctx_errormsg (ctx));
801
- goto cleanup;
940
+ if(sensor_reading) {
941
+ netdata_sensor_set_value(sn, sensor_reading, state);
942
+ sn->last_collected_metric_ut = state->sensors.now_ut;
943
}
803
- }
804
- else
805
- {
806
- if (ipmi_monitoring_ctx_sensor_config_file (ctx, NULL) < 0)
807
- {
808
- collector_error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
809
- ipmi_monitoring_ctx_errormsg (ctx));
810
- goto cleanup;
811
- }
812
- }
944
814
- if (reread_sdr_cache)
815
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
945
+ sn->last_collected_state_ut = state->sensors.now_ut;
946
817
- if (ignore_non_interpretable_sensors)
818
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
947
+ dictionary_acquired_item_release(state->sensors.dict, item);
948
820
- if (bridge_sensors)
821
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_BRIDGE_SENSORS;
822
-
823
- if (interpret_oem_data)
824
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_INTERPRET_OEM_DATA;
825
-
826
- if (shared_sensors)
827
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_SHARED_SENSORS;
828
-
829
- if (discrete_reading)
830
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING;
831
-
832
- if (ignore_scanning_disabled)
833
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_SCANNING_DISABLED;
834
-
835
- if (assume_bmc_owner)
836
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ASSUME_BMC_OWNER;
837
-
838
-#ifdef IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
839
- if (entity_sensor_names)
840
- sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES;
841
-#endif // IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
842
-
843
- if (!record_ids_length && !sensor_types_length)
844
- {
845
- if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
846
- hostname,
847
- ipmi_config,
848
- sensor_reading_flags,
849
- NULL,
850
- 0,
851
- NULL,
852
- NULL)) < 0)
853
- {
854
- collector_error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
855
- ipmi_monitoring_ctx_errormsg (ctx));
856
- goto cleanup;
857
- }
858
- }
859
- else if (record_ids_length)
860
- {
861
- if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
862
- hostname,
863
- ipmi_config,
864
- sensor_reading_flags,
865
- record_ids,
866
- record_ids_length,
867
- NULL,
868
- NULL)) < 0)
869
- {
870
- collector_error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
871
- ipmi_monitoring_ctx_errormsg (ctx));
872
- goto cleanup;
873
- }
874
- }
875
- else
876
- {
877
- if ((sensor_count = ipmi_monitoring_sensor_readings_by_sensor_type (ctx,
878
- hostname,
879
- ipmi_config,
880
- sensor_reading_flags,
881
- sensor_types,
882
- sensor_types_length,
883
- NULL,
884
- NULL)) < 0)
885
- {
886
- collector_error( "ipmi_monitoring_sensor_readings_by_sensor_type(): %s",
887
- ipmi_monitoring_ctx_errormsg (ctx));
888
- goto cleanup;
889
- }
949
+ return;
950
}
951
892
-#ifdef NETDATA_COMMENTED
893
- printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
894
- "Record ID",
895
- "Sensor Name",
896
- "Sensor Number",
897
- "Sensor Type",
898
- "Sensor State",
899
- "Sensor Reading",
900
- "Sensor Units",
901
- "Sensor Event/Reading Type Code",
902
- "Sensor Event Bitmask",
903
- "Sensor Event String");
904
-#endif // NETDATA_COMMENTED
905
-
906
- for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (ctx))
907
- {
908
- int record_id, sensor_number, sensor_type, sensor_state, sensor_units,
909
- sensor_reading_type;
910
-
911
-#ifdef NETDATA_COMMENTED
912
- int sensor_bitmask_type, sensor_bitmask, event_reading_type_code;
913
- char **sensor_bitmask_strings = NULL;
914
- const char *sensor_type_str;
915
- const char *sensor_state_str;
916
-#endif // NETDATA_COMMENTED
917
-
918
- char *sensor_name = NULL;
919
- void *sensor_reading;
920
-
921
- if ((record_id = ipmi_monitoring_sensor_read_record_id (ctx)) < 0)
922
- {
923
- collector_error( "ipmi_monitoring_sensor_read_record_id(): %s",
924
- ipmi_monitoring_ctx_errormsg (ctx));
925
- goto cleanup;
926
- }
927
-
928
- if ((sensor_number = ipmi_monitoring_sensor_read_sensor_number (ctx)) < 0)
929
- {
930
- collector_error( "ipmi_monitoring_sensor_read_sensor_number(): %s",
931
- ipmi_monitoring_ctx_errormsg (ctx));
932
- goto cleanup;
933
- }
934
-
935
- if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (ctx)) < 0)
936
- {
937
- collector_error( "ipmi_monitoring_sensor_read_sensor_type(): %s",
938
- ipmi_monitoring_ctx_errormsg (ctx));
939
- goto cleanup;
940
- }
941
-
942
- if (!(sensor_name = ipmi_monitoring_sensor_read_sensor_name (ctx)))
943
- {
944
- collector_error( "ipmi_monitoring_sensor_read_sensor_name(): %s",
945
- ipmi_monitoring_ctx_errormsg (ctx));
946
- goto cleanup;
947
- }
948
-
949
- if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (ctx)) < 0)
950
- {
951
- collector_error( "ipmi_monitoring_sensor_read_sensor_state(): %s",
952
- ipmi_monitoring_ctx_errormsg (ctx));
953
- goto cleanup;
954
- }
955
-
956
- if ((sensor_units = ipmi_monitoring_sensor_read_sensor_units (ctx)) < 0)
957
- {
958
- collector_error( "ipmi_monitoring_sensor_read_sensor_units(): %s",
959
- ipmi_monitoring_ctx_errormsg (ctx));
960
- goto cleanup;
961
- }
962
-
963
-#ifdef NETDATA_COMMENTED
964
- if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (ctx)) < 0)
965
- {
966
- collector_error( "ipmi_monitoring_sensor_read_sensor_bitmask_type(): %s",
967
- ipmi_monitoring_ctx_errormsg (ctx));
968
- goto cleanup;
969
- }
970
- if ((sensor_bitmask = ipmi_monitoring_sensor_read_sensor_bitmask (ctx)) < 0)
971
- {
972
- collector_error("ipmi_monitoring_sensor_read_sensor_bitmask(): %s",
973
- ipmi_monitoring_ctx_errormsg (ctx));
974
- goto cleanup;
975
- }
952
+ if(state->debug)
953
+ fprintf(stderr, "Allocating new sensor data record for sensor '%s', id %d, number %d, type %d, state %d, units %d, reading_type %d\n",
954
+ sensor_name, record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type);
955
977
- /* it's ok for this to be NULL, i.e. sensor_bitmask ==
978
- * IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN
979
- */
980
- sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (ctx);
981
-
982
-
983
-
984
-#endif // NETDATA_COMMENTED
956
+ // check if it is excluded
957
+ bool excluded_metric = excluded_record_ids_check(record_id);
958
+ bool excluded_state = excluded_status_record_ids_check(record_id);
959
986
- if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
987
- {
988
- collector_error( "ipmi_monitoring_sensor_read_sensor_reading_type(): %s",
989
- ipmi_monitoring_ctx_errormsg (ctx));
990
- goto cleanup;
991
- }
960
+ if(excluded_metric) {
961
+ if(state->debug)
962
+ fprintf(stderr, "Sensor '%s' is excluded by excluded_record_ids_check()\n", sensor_name);
963
+ }
964
993
- sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (ctx);
965
+ if(excluded_state) {
966
+ if(state->debug)
967
+ fprintf(stderr, "Sensor '%s' is excluded for status check, by excluded_status_record_ids_check()\n", sensor_name);
968
+ }
969
995
-#ifdef NETDATA_COMMENTED
996
- if ((event_reading_type_code = ipmi_monitoring_sensor_read_event_reading_type_code (ctx)) < 0)
997
- {
998
- collector_error( "ipmi_monitoring_sensor_read_event_reading_type_code(): %s",
999
- ipmi_monitoring_ctx_errormsg (ctx));
1000
- goto cleanup;
1001
- }
1002
-#endif // NETDATA_COMMENTED
970
+ struct sensor t = {
971
+ .sensor_type = sensor_type,
972
+ .sensor_state = sensor_state,
973
+ .sensor_units = sensor_units,
974
+ .sensor_reading_type = sensor_reading_type,
975
+ .sensor_name = strdupz(sensor_name ? sensor_name : ""),
976
+ .component = netdata_sensor_name_to_component(sensor_name),
977
+ .do_state = !excluded_state,
978
+ .do_metric = !excluded_metric,
979
+ };
980
1004
- netdata_get_sensor(
1005
- record_id
1006
- , sensor_number
1007
- , sensor_type
1008
- , sensor_state
1009
- , sensor_units
1010
- , sensor_reading_type
1011
- , sensor_name
1012
- , sensor_reading
1013
- );
981
+ t.type = netdata_ipmi_get_sensor_type_string(t.sensor_type, &t.component);
982
1015
-#ifdef NETDATA_COMMENTED
1016
- if (!strlen (sensor_name))
1017
- sensor_name = "N/A";
1018
-
1019
- sensor_type_str = _get_sensor_type_string (sensor_type);
1020
-
1021
- printf ("%d, %s, %d, %s",
1022
- record_id,
1023
- sensor_name,
1024
- sensor_number,
1025
- sensor_type_str);
1026
-
1027
- if (sensor_state == IPMI_MONITORING_STATE_NOMINAL)
1028
- sensor_state_str = "Nominal";
1029
- else if (sensor_state == IPMI_MONITORING_STATE_WARNING)
1030
- sensor_state_str = "Warning";
1031
- else if (sensor_state == IPMI_MONITORING_STATE_CRITICAL)
1032
- sensor_state_str = "Critical";
1033
- else
1034
- sensor_state_str = "N/A";
983
+ switch(t.sensor_units) {
984
+ case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
985
+ t.dimension = "temperature";
986
+ t.context = "ipmi.sensor_temperature_c";
987
+ t.title = "IPMI Sensor Temperature Celsius";
988
+ t.units = "Celsius";
989
+ t.family = "temperatures";
990
+ t.chart_type = "line";
991
+ t.priority = state->sensors.priority + 10;
992
+ break;
993
1036
- printf (", %s", sensor_state_str);
994
+ case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
995
+ t.dimension = "temperature";
996
+ t.context = "ipmi.sensor_temperature_f";
997
+ t.title = "IPMI Sensor Temperature Fahrenheit";
998
+ t.units = "Fahrenheit";
999
+ t.family = "temperatures";
1000
+ t.chart_type = "line";
1001
+ t.priority = state->sensors.priority + 20;
1002
+ break;
1003
1038
- if (sensor_reading)
1039
- {
1040
- const char *sensor_units_str;
1041
-
1042
- if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL)
1043
- printf (", %s",
1044
- (*((uint8_t *)sensor_reading) ? "true" : "false"));
1045
- else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32)
1046
- printf (", %u",
1047
- *((uint32_t *)sensor_reading));
1048
- else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE)
1049
- printf (", %.2f",
1050
- *((double *)sensor_reading));
1051
- else
1052
- printf (", N/A");
1053
-
1054
- if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_CELSIUS)
1055
- sensor_units_str = "C";
1056
- else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT)
1057
- sensor_units_str = "F";
1058
- else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_VOLTS)
1059
- sensor_units_str = "V";
1060
- else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_AMPS)
1061
- sensor_units_str = "A";
1062
- else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_RPM)
1063
- sensor_units_str = "RPM";
1064
- else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_WATTS)
1065
- sensor_units_str = "W";
1066
- else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_PERCENT)
1067
- sensor_units_str = "%";
1068
- else
1069
- sensor_units_str = "N/A";
1070
-
1071
- printf (", %s", sensor_units_str);
1072
- }
1073
- else
1074
- printf (", N/A, N/A");
1004
+ case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
1005
+ t.dimension = "voltage";
1006
+ t.context = "ipmi.sensor_voltage";
1007
+ t.title = "IPMI Sensor Voltage";
1008
+ t.units = "Volts";
1009
+ t.family = "voltages";
1010
+ t.chart_type = "line";
1011
+ t.priority = state->sensors.priority + 30;
1012
+ break;
1013
1076
- printf (", %Xh", event_reading_type_code);
1014
+ case IPMI_MONITORING_SENSOR_UNITS_AMPS:
1015
+ t.dimension = "ampere";
1016
+ t.context = "ipmi.sensor_ampere";
1017
+ t.title = "IPMI Sensor Current";
1018
+ t.units = "Amps";
1019
+ t.family = "current";
1020
+ t.chart_type = "line";
1021
+ t.priority = state->sensors.priority + 40;
1022
+ break;
1023
1078
- /* It is possible you may want to monitor specific event
1079
- * conditions that may occur. If that is the case, you may want
1080
- * to check out what specific bitmask type and bitmask events
1081
- * occurred. See ipmi_monitoring_bitmasks.h for a list of
1082
- * bitmasks and types.
1083
- */
1024
+ case IPMI_MONITORING_SENSOR_UNITS_RPM:
1025
+ t.dimension = "rotations";
1026
+ t.context = "ipmi.sensor_fan_speed";
1027
+ t.title = "IPMI Sensor Fans Speed";
1028
+ t.units = "RPM";
1029
+ t.family = "fans";
1030
+ t.chart_type = "line";
1031
+ t.priority = state->sensors.priority + 50;
1032
+ break;
1033
1085
- if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
1086
- printf (", %Xh", sensor_bitmask);
1087
- else
1088
- printf (", N/A");
1034
+ case IPMI_MONITORING_SENSOR_UNITS_WATTS:
1035
+ t.dimension = "power";
1036
+ t.context = "ipmi.sensor_power";
1037
+ t.title = "IPMI Sensor Power";
1038
+ t.units = "Watts";
1039
+ t.family = "power";
1040
+ t.chart_type = "line";
1041
+ t.priority = state->sensors.priority + 60;
1042
+ break;
1043
1090
- if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN
1091
- && sensor_bitmask_strings)
1092
- {
1093
- unsigned int i = 0;
1044
+ case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
1045
+ t.dimension = "percentage";
1046
+ t.context = "ipmi.sensor_reading_percent";
1047
+ t.title = "IPMI Sensor Reading Percentage";
1048
+ t.units = "%%";
1049
+ t.family = "other";
1050
+ t.chart_type = "line";
1051
+ t.priority = state->sensors.priority + 70;
1052
+ break;
1053
1095
- printf (",");
1054
+ default:
1055
+ t.priority = state->sensors.priority + 80;
1056
+ t.do_metric = false;
1057
+ break;
1058
+ }
1059
1097
- while (sensor_bitmask_strings[i])
1098
- {
1099
- printf (" ");
1060
+ switch(sensor_reading_type) {
1061
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
1062
+ t.multiplier = 1000;
1063
+ break;
1064
1101
- printf ("'%s'",
1102
- sensor_bitmask_strings[i]);
1065
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
1066
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
1067
+ t.multiplier = 1;
1068
+ break;
1069
1104
- i++;
1105
- }
1106
- }
1107
- else
1108
- printf (", N/A");
1070
+ default:
1071
+ t.do_metric = false;
1072
+ break;
1073
+ }
1074
1110
- printf ("\n");
1111
-#endif // NETDATA_COMMENTED
1075
+ if(sensor_reading) {
1076
+ netdata_sensor_set_value(&t, sensor_reading, state);
1077
+ t.last_collected_metric_ut = state->sensors.now_ut;
1078
}
1079
+ t.last_collected_state_ut = state->sensors.now_ut;
1080
1114
- rv = 0;
1115
- cleanup:
1116
- if (ctx)
1117
- ipmi_monitoring_ctx_destroy (ctx);
1118
- return (rv);
1081
+ dictionary_set(state->sensors.dict, key, &t, sizeof(t));
1082
}
1083
1084
+static void netdata_update_ipmi_sel_events_count(struct netdata_ipmi_state *state, uint32_t events) {
1085
+ state->sel.events = events;
1086
+}
1087
1122
-static int
1123
-_ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
1124
-{
1125
- ipmi_monitoring_ctx_t ctx = NULL;
1126
- unsigned int sel_flags = 0;
1127
- int i;
1128
- int sel_count;
1129
- int rv = -1;
1130
-
1131
- if (!(ctx = ipmi_monitoring_ctx_create ()))
1132
- {
1133
- collector_error("ipmi_monitoring_ctx_create()");
1134
- goto cleanup;
1135
- }
1136
-
1137
- if (sdr_cache_directory)
1138
- {
1139
- if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
1140
- sdr_cache_directory) < 0)
1141
- {
1142
- collector_error( "ipmi_monitoring_ctx_sdr_cache_directory(): %s",
1143
- ipmi_monitoring_ctx_errormsg (ctx));
1144
- goto cleanup;
1145
- }
1146
- }
1147
-
1148
- /* Must call otherwise only default interpretations ever used */
1149
- if (sel_config_file)
1150
- {
1151
- if (ipmi_monitoring_ctx_sel_config_file (ctx,
1152
- sel_config_file) < 0)
1153
- {
1154
- collector_error( "ipmi_monitoring_ctx_sel_config_file(): %s",
1155
- ipmi_monitoring_ctx_errormsg (ctx));
1156
- goto cleanup;
1157
- }
1158
- }
1159
- else
1160
- {
1161
- if (ipmi_monitoring_ctx_sel_config_file (ctx, NULL) < 0)
1162
- {
1163
- collector_error( "ipmi_monitoring_ctx_sel_config_file(): %s",
1164
- ipmi_monitoring_ctx_errormsg (ctx));
1165
- goto cleanup;
1166
- }
1167
- }
1088
+int netdata_ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config, IPMI_COLLECTION_TYPE type, struct netdata_ipmi_state *state) {
1089
+ errno = 0;
1090
1169
- if (reread_sdr_cache)
1170
- sel_flags |= IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
1171
-
1172
- if (interpret_oem_data)
1173
- sel_flags |= IPMI_MONITORING_SEL_FLAGS_INTERPRET_OEM_DATA;
1174
-
1175
- if (assume_system_event_record)
1176
- sel_flags |= IPMI_MONITORING_SEL_FLAGS_ASSUME_SYSTEM_EVENT_RECORD;
1177
-
1178
-#ifdef IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
1179
- if (entity_sensor_names)
1180
- sel_flags |= IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES;
1181
-#endif // IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
1182
-
1183
- if (record_ids_length)
1184
- {
1185
- if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
1186
- hostname,
1187
- ipmi_config,
1188
- sel_flags,
1189
- record_ids,
1190
- record_ids_length,
1191
- NULL,
1192
- NULL)) < 0)
1193
- {
1194
- collector_error( "ipmi_monitoring_sel_by_record_id(): %s",
1195
- ipmi_monitoring_ctx_errormsg (ctx));
1196
- goto cleanup;
1197
- }
1198
- }
1199
- else if (sensor_types_length)
1200
- {
1201
- if ((sel_count = ipmi_monitoring_sel_by_sensor_type (ctx,
1202
- hostname,
1203
- ipmi_config,
1204
- sel_flags,
1205
- sensor_types,
1206
- sensor_types_length,
1207
- NULL,
1208
- NULL)) < 0)
1209
- {
1210
- collector_error( "ipmi_monitoring_sel_by_sensor_type(): %s",
1211
- ipmi_monitoring_ctx_errormsg (ctx));
1212
- goto cleanup;
1213
- }
1091
+ if(type & IPMI_COLLECT_TYPE_SENSORS) {
1092
+ state->sensors.collected = 0;
1093
+ state->sensors.now_ut = now_monotonic_usec();
1094
+
1095
+ if (netdata_read_ipmi_sensors(ipmi_config, state) < 0) return -1;
1096
}
1215
- else if (date_begin
1216
- || date_end)
1217
- {
1218
- if ((sel_count = ipmi_monitoring_sel_by_date_range (ctx,
1219
- hostname,
1220
- ipmi_config,
1221
- sel_flags,
1222
- date_begin,
1223
- date_end,
1224
- NULL,
1225
- NULL)) < 0)
1226
- {
1227
- collector_error( "ipmi_monitoring_sel_by_sensor_type(): %s",
1228
- ipmi_monitoring_ctx_errormsg (ctx));
1229
- goto cleanup;
1230
- }
1097
+
1098
+ if(type & IPMI_COLLECT_TYPE_SEL) {
1099
+ state->sel.events = 0;
1100
+ state->sel.now_ut = now_monotonic_usec();
1101
+ if(netdata_get_ipmi_sel_events_count(ipmi_config, state) < 0) return -2;
1102
}
1232
- else
1233
- {
1234
- if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
1235
- hostname,
1236
- ipmi_config,
1237
- sel_flags,
1238
- NULL,
1239
- 0,
1240
- NULL,
1241
- NULL)) < 0)
1242
- {
1243
- collector_error( "ipmi_monitoring_sel_by_record_id(): %s",
1244
- ipmi_monitoring_ctx_errormsg (ctx));
1245
- goto cleanup;
1246
- }
1103
+
1104
+ return 0;
1105
+}
1106
+
1107
+int netdata_ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config, IPMI_COLLECTION_TYPE type, struct netdata_ipmi_state *state) {
1108
+ int i, checks = SPEED_TEST_ITERATIONS, successful = 0;
1109
+ usec_t total = 0;
1110
+
1111
+ for(i = 0 ; i < checks ; i++) {
1112
+ if(unlikely(state->debug))
1113
+ fprintf(stderr, "%s: checking %s data collection speed iteration %d of %d\n",
1114
+ program_name, netdata_collect_type_to_string(type), i + 1, checks);
1115
+
1116
+ // measure the time a data collection needs
1117
+ usec_t start = now_realtime_usec();
1118
+
1119
+ if(netdata_ipmi_collect_data(ipmi_config, type, state) < 0)
1120
+ continue;
1121
+
1122
+ usec_t end = now_realtime_usec();
1123
+
1124
+ successful++;
1125
+
1126
+ if(unlikely(state->debug))
1127
+ fprintf(stderr, "%s: %s data collection speed was %llu usec\n",
1128
+ program_name, netdata_collect_type_to_string(type), end - start);
1129
+
1130
+ // add it to our total
1131
+ total += end - start;
1132
+
1133
+ // wait the same time
1134
+ // to avoid flooding the IPMI processor with requests
1135
+ sleep_usec(end - start);
1136
}
1137
1249
-#ifdef NETDATA_COMMENTED
1250
- printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
1251
- "Record ID",
1252
- "Record Type",
1253
- "SEL State",
1254
- "Timestamp",
1255
- "Sensor Name",
1256
- "Sensor Type",
1257
- "Event Direction",
1258
- "Event Type Code",
1259
- "Event Data",
1260
- "Event Offset",
1261
- "Event Offset String");
1262
-#endif // NETDATA_COMMENTED
1138
+ if(!successful)
1139
+ return 0;
1140
1264
- for (i = 0; i < sel_count; i++, ipmi_monitoring_sel_iterator_next (ctx))
1265
- {
1266
- int record_id, record_type, sel_state, record_type_class;
1267
-#ifdef NETDATA_COMMENTED
1268
- int sensor_type, sensor_number, event_direction,
1269
- event_offset_type, event_offset, event_type_code, manufacturer_id;
1270
- unsigned int timestamp, event_data1, event_data2, event_data3;
1271
- char *event_offset_string = NULL;
1272
- const char *sensor_type_str;
1273
- const char *event_direction_str;
1274
- const char *sel_state_str;
1275
- char *sensor_name = NULL;
1276
- unsigned char oem_data[64];
1277
- int oem_data_len;
1278
- unsigned int j;
1279
-#endif // NETDATA_COMMENTED
1141
+ // so, we assume it needed 2x the time
1142
+ // we find the average in microseconds
1143
+ // and we round-up to the closest second
1144
1281
- if ((record_id = ipmi_monitoring_sel_read_record_id (ctx)) < 0)
1282
- {
1283
- collector_error( "ipmi_monitoring_sel_read_record_id(): %s",
1284
- ipmi_monitoring_ctx_errormsg (ctx));
1285
- goto cleanup;
1286
- }
1145
+ return (int)(( total * 2 / successful / USEC_PER_SEC ) + 1);
1146
+}
1147
1288
- if ((record_type = ipmi_monitoring_sel_read_record_type (ctx)) < 0)
1289
- {
1290
- collector_error( "ipmi_monitoring_sel_read_record_type(): %s",
1291
- ipmi_monitoring_ctx_errormsg (ctx));
1292
- goto cleanup;
1293
- }
1148
+// ----------------------------------------------------------------------------
1149
+// data collection threads
1150
1295
- if ((record_type_class = ipmi_monitoring_sel_read_record_type_class (ctx)) < 0)
1296
- {
1297
- collector_error( "ipmi_monitoring_sel_read_record_type_class(): %s",
1298
- ipmi_monitoring_ctx_errormsg (ctx));
1299
- goto cleanup;
1300
- }
1151
+struct ipmi_collection_thread {
1152
+ struct ipmi_monitoring_ipmi_config ipmi_config;
1153
+ int freq_s;
1154
+ bool debug;
1155
+ IPMI_COLLECTION_TYPE type;
1156
+ SPINLOCK spinlock;
1157
+ struct netdata_ipmi_state state;
1158
+};
1159
1302
- if ((sel_state = ipmi_monitoring_sel_read_sel_state (ctx)) < 0)
1303
- {
1304
- collector_error( "ipmi_monitoring_sel_read_sel_state(): %s",
1305
- ipmi_monitoring_ctx_errormsg (ctx));
1306
- goto cleanup;
1307
- }
1160
+void *netdata_ipmi_collection_thread(void *ptr) {
1161
+ struct ipmi_collection_thread *t = ptr;
1162
1309
- netdata_get_sel(
1310
- record_id
1311
- , record_type_class
1312
- , sel_state
1313
- );
1163
+ if(t->debug) fprintf(stderr, "%s: calling initialize_ipmi_config() for %s\n",
1164
+ program_name, netdata_collect_type_to_string(t->type));
1165
1315
-#ifdef NETDATA_COMMENTED
1316
- if (sel_state == IPMI_MONITORING_STATE_NOMINAL)
1317
- sel_state_str = "Nominal";
1318
- else if (sel_state == IPMI_MONITORING_STATE_WARNING)
1319
- sel_state_str = "Warning";
1320
- else if (sel_state == IPMI_MONITORING_STATE_CRITICAL)
1321
- sel_state_str = "Critical";
1322
- else
1323
- sel_state_str = "N/A";
1166
+ initialize_ipmi_config(&t->ipmi_config);
1167
1325
- printf ("%d, %d, %s",
1326
- record_id,
1327
- record_type,
1328
- sel_state_str);
1168
+ if(t->debug) fprintf(stderr, "%s: detecting IPMI minimum update frequency for %s...\n",
1169
+ program_name, netdata_collect_type_to_string(t->type));
1170
1330
- if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD
1331
- || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
1332
- {
1171
+ int freq_s = netdata_ipmi_detect_speed_secs(&t->ipmi_config, t->type, &t->state);
1172
+ if(!freq_s) {
1173
+ if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
1174
+ t->state.sensors.status = ICS_INIT_FAILED;
1175
+ t->state.sensors.last_iteration_ut = 0;
1176
+ }
1177
1334
- if (ipmi_monitoring_sel_read_timestamp (ctx, ×tamp) < 0)
1335
- {
1336
- collector_error( "ipmi_monitoring_sel_read_timestamp(): %s",
1337
- ipmi_monitoring_ctx_errormsg (ctx));
1338
- goto cleanup;
1339
- }
1178
+ if(t->type & IPMI_COLLECT_TYPE_SEL) {
1179
+ t->state.sel.status = ICS_INIT_FAILED;
1180
+ t->state.sel.last_iteration_ut = 0;
1181
+ }
1182
1341
- /* XXX: This should be converted to a nice date output using
1342
- * your favorite timestamp -> string conversion functions.
1343
- */
1344
- printf (", %u", timestamp);
1183
+ return ptr;
1184
+ }
1185
+ else {
1186
+ if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
1187
+ t->state.sensors.status = ICS_RUNNING;
1188
}
1346
- else
1347
- printf (", N/A");
1189
1349
- if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD)
1350
- {
1351
- /* If you are integrating ipmimonitoring SEL into a monitoring application,
1352
- * you may wish to count the number of times a specific error occurred
1353
- * and report that to the monitoring application.
1354
- *
1355
- * In this particular case, you'll probably want to check out
1356
- * what sensor type each SEL event is reporting, the
1357
- * event offset type, and the specific event offset that occurred.
1358
- *
1359
- * See ipmi_monitoring_offsets.h for a list of event offsets
1360
- * and types.
1361
- */
1362
-
1363
- if (!(sensor_name = ipmi_monitoring_sel_read_sensor_name (ctx)))
1364
- {
1365
- collector_error( "ipmi_monitoring_sel_read_sensor_name(): %s",
1366
- ipmi_monitoring_ctx_errormsg (ctx));
1367
- goto cleanup;
1368
- }
1190
+ if(t->type & IPMI_COLLECT_TYPE_SEL) {
1191
+ t->state.sel.status = ICS_RUNNING;
1192
+ }
1193
+ }
1194
1370
- if ((sensor_type = ipmi_monitoring_sel_read_sensor_type (ctx)) < 0)
1371
- {
1372
- collector_error( "ipmi_monitoring_sel_read_sensor_type(): %s",
1373
- ipmi_monitoring_ctx_errormsg (ctx));
1374
- goto cleanup;
1375
- }
1195
+ t->freq_s = freq_s = MAX(t->freq_s, freq_s);
1196
1377
- if ((sensor_number = ipmi_monitoring_sel_read_sensor_number (ctx)) < 0)
1378
- {
1379
- collector_error( "ipmi_monitoring_sel_read_sensor_number(): %s",
1380
- ipmi_monitoring_ctx_errormsg (ctx));
1381
- goto cleanup;
1382
- }
1197
+ if(t->debug) {
1198
+ fprintf(stderr, "%s: IPMI minimum update frequency of %s was calculated to %d seconds.\n",
1199
+ program_name, netdata_collect_type_to_string(t->type), t->freq_s);
1200
1384
- if ((event_direction = ipmi_monitoring_sel_read_event_direction (ctx)) < 0)
1385
- {
1386
- collector_error( "ipmi_monitoring_sel_read_event_direction(): %s",
1387
- ipmi_monitoring_ctx_errormsg (ctx));
1388
- goto cleanup;
1389
- }
1201
+ fprintf(stderr, "%s: starting data collection of %s\n",
1202
+ program_name, netdata_collect_type_to_string(t->type));
1203
+ }
1204
1391
- if ((event_type_code = ipmi_monitoring_sel_read_event_type_code (ctx)) < 0)
1392
- {
1393
- collector_error( "ipmi_monitoring_sel_read_event_type_code(): %s",
1394
- ipmi_monitoring_ctx_errormsg (ctx));
1395
- goto cleanup;
1396
- }
1205
+ size_t iteration = 0, failures = 0;
1206
+ usec_t step = t->freq_s * USEC_PER_SEC;
1207
1398
- if (ipmi_monitoring_sel_read_event_data (ctx,
1399
- &event_data1,
1400
- &event_data2,
1401
- &event_data3) < 0)
1402
- {
1403
- collector_error( "ipmi_monitoring_sel_read_event_data(): %s",
1404
- ipmi_monitoring_ctx_errormsg (ctx));
1405
- goto cleanup;
1406
- }
1208
+ heartbeat_t hb;
1209
+ heartbeat_init(&hb);
1210
+ while(++iteration) {
1211
+ heartbeat_next(&hb, step);
1212
1408
- if ((event_offset_type = ipmi_monitoring_sel_read_event_offset_type (ctx)) < 0)
1409
- {
1410
- collector_error( "ipmi_monitoring_sel_read_event_offset_type(): %s",
1411
- ipmi_monitoring_ctx_errormsg (ctx));
1412
- goto cleanup;
1413
- }
1213
+ if(t->debug)
1214
+ fprintf(stderr, "%s: calling netdata_ipmi_collect_data() for %s\n",
1215
+ program_name, netdata_collect_type_to_string(t->type));
1216
1415
- if ((event_offset = ipmi_monitoring_sel_read_event_offset (ctx)) < 0)
1416
- {
1417
- collector_error( "ipmi_monitoring_sel_read_event_offset(): %s",
1418
- ipmi_monitoring_ctx_errormsg (ctx));
1419
- goto cleanup;
1420
- }
1217
+ struct netdata_ipmi_state tmp_state = t->state;
1218
1422
- if (!(event_offset_string = ipmi_monitoring_sel_read_event_offset_string (ctx)))
1423
- {
1424
- collector_error( "ipmi_monitoring_sel_read_event_offset_string(): %s",
1425
- ipmi_monitoring_ctx_errormsg (ctx));
1426
- goto cleanup;
1427
- }
1219
+ if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
1220
+ tmp_state.sensors.last_iteration_ut = now_monotonic_usec();
1221
+ tmp_state.sensors.freq_ut = t->freq_s * USEC_PER_SEC;
1222
+ }
1223
1429
- if (!strlen (sensor_name))
1430
- sensor_name = "N/A";
1431
-
1432
- sensor_type_str = _get_sensor_type_string (sensor_type);
1433
-
1434
- if (event_direction == IPMI_MONITORING_SEL_EVENT_DIRECTION_ASSERTION)
1435
- event_direction_str = "Assertion";
1436
- else
1437
- event_direction_str = "Deassertion";
1438
-
1439
- printf (", %s, %s, %d, %s, %Xh, %Xh-%Xh-%Xh",
1440
- sensor_name,
1441
- sensor_type_str,
1442
- sensor_number,
1443
- event_direction_str,
1444
- event_type_code,
1445
- event_data1,
1446
- event_data2,
1447
- event_data3);
1448
-
1449
- if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
1450
- printf (", %Xh", event_offset);
1451
- else
1452
- printf (", N/A");
1453
-
1454
- if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
1455
- printf (", %s", event_offset_string);
1456
- else
1457
- printf (", N/A");
1224
+ if(t->type & IPMI_COLLECT_TYPE_SEL) {
1225
+ tmp_state.sel.last_iteration_ut = now_monotonic_usec();
1226
+ tmp_state.sel.freq_ut = t->freq_s * USEC_PER_SEC;
1227
}
1459
- else if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD
1460
- || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_NON_TIMESTAMPED_OEM_RECORD)
1461
- {
1462
- if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
1463
- {
1464
- if ((manufacturer_id = ipmi_monitoring_sel_read_manufacturer_id (ctx)) < 0)
1465
- {
1466
- collector_error( "ipmi_monitoring_sel_read_manufacturer_id(): %s",
1467
- ipmi_monitoring_ctx_errormsg (ctx));
1468
- goto cleanup;
1469
- }
1228
1471
- printf (", Manufacturer ID = %Xh", manufacturer_id);
1472
- }
1229
+ if(netdata_ipmi_collect_data(&t->ipmi_config, t->type, &tmp_state) != 0)
1230
+ failures++;
1231
+ else
1232
+ failures = 0;
1233
1474
- if ((oem_data_len = ipmi_monitoring_sel_read_oem_data (ctx, oem_data, 1024)) < 0)
1475
- {
1476
- collector_error( "ipmi_monitoring_sel_read_oem_data(): %s",
1477
- ipmi_monitoring_ctx_errormsg (ctx));
1478
- goto cleanup;
1234
+ if(failures > 10) {
1235
+ collector_error("%s() failed to collect %s data for %zu consecutive times, having made %zu iterations.",
1236
+ __FUNCTION__, netdata_collect_type_to_string(t->type), failures, iteration);
1237
+
1238
+ if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
1239
+ t->state.sensors.status = ICS_FAILED;
1240
+ t->state.sensors.last_iteration_ut = 0;
1241
}
1242
1481
- printf (", OEM Data = ");
1243
+ if(t->type & IPMI_COLLECT_TYPE_SEL) {
1244
+ t->state.sel.status = ICS_FAILED;
1245
+ t->state.sel.last_iteration_ut = 0;
1246
+ }
1247
1483
- for (j = 0; j < oem_data_len; j++)
1484
- printf ("%02Xh ", oem_data[j]);
1248
+ return ptr;
1249
}
1486
- else
1487
- printf (", N/A, N/A, N/A, N/A, N/A, N/A, N/A");
1250
1489
- printf ("\n");
1490
-#endif // NETDATA_COMMENTED
1251
+ spinlock_lock(&t->spinlock);
1252
+ t->state = tmp_state;
1253
+ spinlock_unlock(&t->spinlock);
1254
}
1255
1493
- rv = 0;
1494
- cleanup:
1495
- if (ctx)
1496
- ipmi_monitoring_ctx_destroy (ctx);
1497
- return (rv);
1256
+ return ptr;
1257
}
1258
1259
// ----------------------------------------------------------------------------
1501
-// MAIN PROGRAM FOR NETDATA PLUGIN
1502
-
1503
-int ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config) {
1504
- errno = 0;
1260
+// sending data to netdata
1261
1506
- if (_ipmimonitoring_sensors(ipmi_config) < 0) return -1;
1262
+static inline bool is_sensor_updated(usec_t last_collected_ut, usec_t now_ut, usec_t freq) {
1263
+ return (now_ut - last_collected_ut < freq * 2) ? true : false;
1264
+}
1265
1508
- if(netdata_do_sel) {
1509
- if(_ipmimonitoring_sel(ipmi_config) < 0) return -2;
1266
+static size_t send_ipmi_sensor_metrics_to_netdata(struct netdata_ipmi_state *state) {
1267
+ if(state->sensors.status != ICS_RUNNING) {
1268
+ if(unlikely(state->debug))
1269
+ fprintf(stderr, "%s: %s() sensors state is not RUNNING\n",
1270
+ program_name, __FUNCTION__ );
1271
+ return 0;
1272
}
1273
1512
- return 0;
1513
-}
1274
+ size_t total_sensors_sent = 0;
1275
+ int update_every = (int)(state->sensors.freq_ut / USEC_PER_SEC);
1276
+ struct sensor *sn;
1277
1515
-int ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config) {
1516
- int i, checks = 10;
1517
- unsigned long long total = 0;
1278
+ // generate the CHART/DIMENSION lines, if we have to
1279
+ dfe_start_reentrant(state->sensors.dict, sn) {
1280
+ if(unlikely(!sn->do_metric && !sn->do_state))
1281
+ continue;
1282
1519
- for(i = 0 ; i < checks ; i++) {
1520
- if(debug) fprintf(stderr, "freeipmi.plugin: checking data collection speed iteration %d of %d\n", i+1, checks);
1283
+ bool did_metric = false, did_state = false;
1284
1522
- // measure the time a data collection needs
1523
- unsigned long long start = now_realtime_usec();
1524
- if(ipmi_collect_data(ipmi_config) < 0)
1525
- fatal("freeipmi.plugin: data collection failed.");
1285
+ if(likely(sn->do_metric)) {
1286
+ if(unlikely(!is_sensor_updated(sn->last_collected_metric_ut, state->updates.now_ut, state->sensors.freq_ut))) {
1287
+ if(unlikely(state->debug))
1288
+ fprintf(stderr, "%s: %s() sensor '%s' metric is not UPDATED (last updated %llu, now %llu, freq %llu\n",
1289
+ program_name, __FUNCTION__, sn->sensor_name, sn->last_collected_metric_ut, state->updates.now_ut, state->sensors.freq_ut);
1290
+ }
1291
+ else {
1292
+ if (unlikely(!sn->metric_chart_sent)) {
1293
+ sn->metric_chart_sent = true;
1294
1527
- unsigned long long end = now_realtime_usec();
1295
+ printf("CHART '%s_%s' '' '%s' '%s' '%s' '%s' '%s' %d %d '' '%s' '%s'\n",
1296
+ sn->context, sn_dfe.name, sn->title, sn->units, sn->family, sn->context,
1297
+ sn->chart_type, sn->priority + 1, update_every, program_name, "sensors");
1298
1529
- if(debug) fprintf(stderr, "freeipmi.plugin: data collection speed was %llu usec\n", end - start);
1299
+ printf("CLABEL 'sensor' '%s' 1\n", sn->sensor_name);
1300
+ printf("CLABEL 'type' '%s' 1\n", sn->type);
1301
+ printf("CLABEL 'component' '%s' 1\n", sn->component);
1302
+ printf("CLABEL_COMMIT\n");
1303
1531
- // add it to our total
1532
- total += end - start;
1304
+ printf("DIMENSION '%s' '' absolute 1 %d\n", sn->dimension, sn->multiplier);
1305
+ }
1306
1534
- // wait the same time
1535
- // to avoid flooding the IPMI processor with requests
1536
- sleep_usec(end - start);
1537
- }
1307
+ printf("BEGIN '%s_%s'\n", sn->context, sn_dfe.name);
1308
+
1309
+ switch (sn->sensor_reading_type) {
1310
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
1311
+ printf("SET '%s' = %u\n", sn->dimension, sn->sensor_reading.uint32_value
1312
+ );
1313
+ break;
1314
+
1315
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
1316
+ printf("SET '%s' = %lld\n", sn->dimension,
1317
+ (long long int) (sn->sensor_reading.double_value * sn->multiplier)
1318
+ );
1319
+ break;
1320
+
1321
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
1322
+ printf("SET '%s' = %u\n", sn->dimension, sn->sensor_reading.bool_value
1323
+ );
1324
+ break;
1325
+
1326
+ default:
1327
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNKNOWN:
1328
+ // this should never happen because we also do the same check at netdata_get_sensor()
1329
+ sn->do_metric = false;
1330
+ break;
1331
+ }
1332
1539
- // so, we assume it needed 2x the time
1540
- // we find the average in microseconds
1541
- // and we round-up to the closest second
1333
+ printf("END\n");
1334
+ did_metric = true;
1335
+ }
1336
+ }
1337
1543
- return (int)(( total * 2 / checks / 1000000 ) + 1);
1544
-}
1338
+ if(likely(sn->do_state)) {
1339
+ if(unlikely(!is_sensor_updated(sn->last_collected_state_ut, state->updates.now_ut, state->sensors.freq_ut))) {
1340
+ if (unlikely(state->debug))
1341
+ fprintf(stderr, "%s: %s() sensor '%s' state is not UPDATED (last updated %llu, now %llu, freq %llu\n",
1342
+ program_name, __FUNCTION__, sn->sensor_name, sn->last_collected_state_ut, state->updates.now_ut, state->sensors.freq_ut);
1343
+ }
1344
+ else {
1345
+ if (unlikely(!sn->state_chart_sent)) {
1346
+ sn->state_chart_sent = true;
1347
+
1348
+ printf("CHART 'ipmi.sensor_state_%s' '' 'IPMI Sensor State' 'state' 'states' 'ipmi.sensor_state' 'line' %d %d '' '%s' '%s'\n",
1349
+ sn_dfe.name, sn->priority, update_every, program_name, "sensors");
1350
+
1351
+ printf("CLABEL 'sensor' '%s' 1\n", sn->sensor_name);
1352
+ printf("CLABEL 'type' '%s' 1\n", sn->type);
1353
+ printf("CLABEL 'component' '%s' 1\n", sn->component);
1354
+ printf("CLABEL_COMMIT\n");
1355
+
1356
+ printf("DIMENSION 'nominal' '' absolute 1 1\n");
1357
+ printf("DIMENSION 'warning' '' absolute 1 1\n");
1358
+ printf("DIMENSION 'critical' '' absolute 1 1\n");
1359
+ printf("DIMENSION 'unknown' '' absolute 1 1\n");
1360
+ }
1361
1546
-int parse_inband_driver_type (const char *str)
1547
-{
1548
- fatal_assert(str);
1362
+ printf("BEGIN 'ipmi.sensor_state_%s'\n", sn_dfe.name);
1363
+ printf("SET 'nominal' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_NOMINAL ? 1LL : 0LL);
1364
+ printf("SET 'warning' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_WARNING ? 1LL : 0LL);
1365
+ printf("SET 'critical' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_CRITICAL ? 1LL : 0LL);
1366
+ printf("SET 'unknown' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_UNKNOWN ? 1LL : 0LL);
1367
+ printf("END\n");
1368
+ did_state = true;
1369
+ }
1370
+ }
1371
1550
- if (strcasecmp (str, IPMI_PARSE_DEVICE_KCS_STR) == 0)
1551
- return (IPMI_MONITORING_DRIVER_TYPE_KCS);
1552
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_SSIF_STR) == 0)
1553
- return (IPMI_MONITORING_DRIVER_TYPE_SSIF);
1554
- /* support "open" for those that might be used to
1555
- * ipmitool.
1556
- */
1557
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_OPENIPMI_STR) == 0
1558
- || strcasecmp (str, IPMI_PARSE_DEVICE_OPENIPMI_STR2) == 0)
1559
- return (IPMI_MONITORING_DRIVER_TYPE_OPENIPMI);
1560
- /* support "bmc" for those that might be used to
1561
- * ipmitool.
1562
- */
1563
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_SUNBMC_STR) == 0
1564
- || strcasecmp (str, IPMI_PARSE_DEVICE_SUNBMC_STR2) == 0)
1565
- return (IPMI_MONITORING_DRIVER_TYPE_SUNBMC);
1372
+ if(likely(did_metric || did_state))
1373
+ total_sensors_sent++;
1374
+ }
1375
+ dfe_done(sn);
1376
1567
- return (-1);
1377
+ return total_sensors_sent;
1378
}
1379
1570
-int parse_outofband_driver_type (const char *str)
1571
-{
1572
- fatal_assert(str);
1380
+static size_t send_ipmi_sel_metrics_to_netdata(struct netdata_ipmi_state *state) {
1381
+ static bool sel_chart_generated = false;
1382
+
1383
+ if(likely(state->sel.status == ICS_RUNNING)) {
1384
+ if(unlikely(!sel_chart_generated)) {
1385
+ sel_chart_generated = true;
1386
+ printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' ipmi.sel area %d %d '' '%s' '%s'\n"
1387
+ , state->sel.priority + 2
1388
+ , (int)(state->sel.freq_ut / USEC_PER_SEC)
1389
+ , program_name
1390
+ , "sel"
1391
+ );
1392
+ printf("DIMENSION events '' absolute 1 1\n");
1393
+ }
1394
1574
- if (strcasecmp (str, IPMI_PARSE_DEVICE_LAN_STR) == 0)
1575
- return (IPMI_MONITORING_PROTOCOL_VERSION_1_5);
1576
- /* support "lanplus" for those that might be used to ipmitool.
1577
- * support typo variants to ease.
1578
- */
1579
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR) == 0
1580
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR2) == 0
1581
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR3) == 0
1582
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR4) == 0
1583
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR5) == 0)
1584
- return (IPMI_MONITORING_PROTOCOL_VERSION_2_0);
1395
+ printf(
1396
+ "BEGIN ipmi.events\n"
1397
+ "SET events = %zu\n"
1398
+ "END\n"
1399
+ , state->sel.events
1400
+ );
1401
+ }
1402
1586
- return (-1);
1403
+ return state->sel.events;
1404
}
1405
1589
-int host_is_local(const char *host)
1590
-{
1591
- if (host && (!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1") || !strcmp(host, "::1")))
1592
- return (1);
1593
-
1594
- return (0);
1595
-}
1406
+// ----------------------------------------------------------------------------
1407
+// main, command line arguments parsing
1408
1409
int main (int argc, char **argv) {
1410
+ bool netdata_do_sel = IPMI_ENABLE_SEL_BY_DEFAULT;
1411
+
1412
stderror = stderr;
1413
clocks_init();
1414
1415
+ int update_every = IPMI_SENSORS_MIN_UPDATE_EVERY; // this is the minimum update frequency
1416
+ int update_every_sel = IPMI_SEL_MIN_UPDATE_EVERY; // this is the minimum update frequency for SEL events
1417
+ bool debug = false;
1418
+
1419
// ------------------------------------------------------------------------
1420
// initialization of netdata plugin
1421
1428
error_log_errors_per_period = 100;
1429
error_log_throttle_period = 3600;
1430
1613
-
1431
// ------------------------------------------------------------------------
1432
// parse command line parameters
1433
1617
- int i, freq = 0;
1434
+ int i, freq_s = 0;
1435
for(i = 1; i < argc ; i++) {
1619
- if(isdigit(*argv[i]) && !freq) {
1436
+ if(isdigit(*argv[i]) && !freq_s) {
1437
int n = str2i(argv[i]);
1438
if(n > 0 && n < 86400) {
1622
- freq = n;
1439
+ freq_s = n;
1440
continue;
1441
}
1442
}
1443
else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
1627
- printf("freeipmi.plugin %s\n", VERSION);
1444
+ printf("%s %s\n", program_name, VERSION);
1445
exit(0);
1446
}
1447
else if(strcmp("debug", argv[i]) == 0) {
1631
- debug = 1;
1448
+ debug = true;
1449
continue;
1450
}
1451
else if(strcmp("sel", argv[i]) == 0) {
1635
- netdata_do_sel = 1;
1452
+ netdata_do_sel = true;
1453
continue;
1454
}
1455
else if(strcmp("no-sel", argv[i]) == 0) {
1639
- netdata_do_sel = 0;
1456
+ netdata_do_sel = false;
1457
continue;
1458
}
1459
+ else if(strcmp("reread-sdr-cache", argv[i]) == 0) {
1460
+ global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
1461
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
1462
+ if (debug) fprintf(stderr, "%s: reread-sdr-cache enabled for both sensors and SEL\n", program_name);
1463
+ }
1464
+ else if(strcmp("interpret-oem-data", argv[i]) == 0) {
1465
+ global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_INTERPRET_OEM_DATA;
1466
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_INTERPRET_OEM_DATA;
1467
+ if (debug) fprintf(stderr, "%s: interpret-oem-data enabled for both sensors and SEL\n", program_name);
1468
+ }
1469
+ else if(strcmp("assume-system-event-record", argv[i]) == 0) {
1470
+ global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_ASSUME_SYSTEM_EVENT_RECORD;
1471
+ if (debug) fprintf(stderr, "%s: assume-system-event-record enabled\n", program_name);
1472
+ }
1473
+ else if(strcmp("ignore-non-interpretable-sensors", argv[i]) == 0) {
1474
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
1475
+ if (debug) fprintf(stderr, "%s: ignore-non-interpretable-sensors enabled\n", program_name);
1476
+ }
1477
+ else if(strcmp("bridge-sensors", argv[i]) == 0) {
1478
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_BRIDGE_SENSORS;
1479
+ if (debug) fprintf(stderr, "%s: bridge-sensors enabled\n", program_name);
1480
+ }
1481
+ else if(strcmp("shared-sensors", argv[i]) == 0) {
1482
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_SHARED_SENSORS;
1483
+ if (debug) fprintf(stderr, "%s: shared-sensors enabled\n", program_name);
1484
+ }
1485
+ else if(strcmp("no-discrete-reading", argv[i]) == 0) {
1486
+ global_sensor_reading_flags &= ~(IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING);
1487
+ if (debug) fprintf(stderr, "%s: discrete-reading disabled\n", program_name);
1488
+ }
1489
+ else if(strcmp("ignore-scanning-disabled", argv[i]) == 0) {
1490
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_SCANNING_DISABLED;
1491
+ if (debug) fprintf(stderr, "%s: ignore-scanning-disabled enabled\n", program_name);
1492
+ }
1493
+ else if(strcmp("assume-bmc-owner", argv[i]) == 0) {
1494
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ASSUME_BMC_OWNER;
1495
+ if (debug) fprintf(stderr, "%s: assume-bmc-owner enabled\n", program_name);
1496
+ }
1497
+#if defined(IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES) && defined(IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES)
1498
+ else if(strcmp("entity-sensor-names", argv[i]) == 0) {
1499
+ global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES;
1500
+ global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES;
1501
+ if (debug) fprintf(stderr, "%s: entity-sensor-names enabled for both sensors and SEL\n", program_name);
1502
+ }
1503
+#endif
1504
else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
1505
fprintf(stderr,
1506
"\n"
1645
- " netdata freeipmi.plugin %s\n"
1646
- " Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
1507
+ " netdata %s %s\n"
1508
+ " Copyright (C) 2023 Netdata Inc.\n"
1509
" Released under GNU General Public License v3 or later.\n"
1510
" All rights reserved.\n"
1511
"\n"
1523
" no-sel enable/disable SEL collection\n"
1524
" default: %s\n"
1525
"\n"
1526
+ " reread-sdr-cache re-read SDR cache on every iteration\n"
1527
+ " default: disabled\n"
1528
+ "\n"
1529
+ " interpret-oem-data attempt to parse OEM data\n"
1530
+ " default: disabled\n"
1531
+ "\n"
1532
+ " assume-system-event-record \n"
1533
+ " tread illegal SEL events records as normal\n"
1534
+ " default: disabled\n"
1535
+ "\n"
1536
+ " ignore-non-interpretable-sensors \n"
1537
+ " do not read sensors that cannot be interpreted\n"
1538
+ " default: disabled\n"
1539
+ "\n"
1540
+ " bridge-sensors bridge sensors not owned by the BMC\n"
1541
+ " default: disabled\n"
1542
+ "\n"
1543
+ " shared-sensors enable shared sensors, if found\n"
1544
+ " default: disabled\n"
1545
+ "\n"
1546
+ " no-discrete-reading do not read sensors that their event/reading type code is invalid\n"
1547
+ " default: enabled\n"
1548
+ "\n"
1549
+ " ignore-scanning-disabled \n"
1550
+ " Ignore the scanning bit and read sensors no matter what\n"
1551
+ " default: disabled\n"
1552
+ "\n"
1553
+ " assume-bmc-owner assume the BMC is the sensor owner no matter what\n"
1554
+ " (usually bridging is required too)\n"
1555
+ " default: disabled\n"
1556
+ "\n"
1557
+#if defined(IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES) && defined(IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES)
1558
+ " entity-sensor-names sensor names prefixed with entity id and instance\n"
1559
+ " default: disabled\n"
1560
+ "\n"
1561
+#endif
1562
" hostname HOST\n"
1563
" username USER\n"
1564
" password PASS connect to remote IPMI host\n"
1565
" default: local IPMI processor\n"
1566
"\n"
1567
+ " no-auth-code-check\n"
1568
" noauthcodecheck don't check the authentication codes returned\n"
1569
"\n"
1570
" driver-type IPMIDRIVER\n"
1571
" Specify the driver type to use instead of doing an auto selection. \n"
1673
- " The currently available outofband drivers are LAN and LAN_2_0,\n"
1572
+ " The currently available outofband drivers are LAN and LAN_2_0,\n"
1573
" which perform IPMI 1.5 and IPMI 2.0 respectively. \n"
1574
" The currently available inband drivers are KCS, SSIF, OPENIPMI and SUNBMC.\n"
1575
"\n"
1579
" sensor-config-file FILE filename to read sensor configuration\n"
1580
" default: %s\n"
1581
"\n"
1582
+ " sel-config-file FILE filename to read sel configuration\n"
1583
+ " default: %s\n"
1584
+ "\n"
1585
" ignore N1,N2,N3,... sensor IDs to ignore\n"
1586
" default: none\n"
1587
"\n"
1602
" For more information:\n"
1603
" https://github.com/netdata/netdata/tree/master/collectors/freeipmi.plugin\n"
1604
"\n"
1703
- , VERSION
1704
- , netdata_update_every
1605
+ , program_name, VERSION
1606
+ , update_every
1607
, netdata_do_sel?"enabled":"disabled"
1608
, sdr_cache_directory?sdr_cache_directory:"system default"
1609
, sensor_config_file?sensor_config_file:"system default"
1610
+ , sel_config_file?sel_config_file:"system default"
1611
);
1612
exit(1);
1613
}
1616
char *s = argv[i];
1617
// mask it be hidden from the process tree
1618
while(*s) *s++ = 'x';
1716
- if(debug) fprintf(stderr, "freeipmi.plugin: hostname set to '%s'\n", hostname);
1619
+ if(debug) fprintf(stderr, "%s: hostname set to '%s'\n", program_name, hostname);
1620
continue;
1621
}
1622
else if(i < argc && strcmp("username", argv[i]) == 0) {
1624
char *s = argv[i];
1625
// mask it be hidden from the process tree
1626
while(*s) *s++ = 'x';
1724
- if(debug) fprintf(stderr, "freeipmi.plugin: username set to '%s'\n", username);
1627
+ if(debug) fprintf(stderr, "%s: username set to '%s'\n", program_name, username);
1628
continue;
1629
}
1630
else if(i < argc && strcmp("password", argv[i]) == 0) {
1632
char *s = argv[i];
1633
// mask it be hidden from the process tree
1634
while(*s) *s++ = 'x';
1732
- if(debug) fprintf(stderr, "freeipmi.plugin: password set to '%s'\n", password);
1635
+ if(debug) fprintf(stderr, "%s: password set to '%s'\n", program_name, password);
1636
continue;
1637
}
1638
else if(strcmp("driver-type", argv[i]) == 0) {
1639
if (hostname) {
1737
- protocol_version=parse_outofband_driver_type(argv[++i]);
1738
- if(debug) fprintf(stderr, "freeipmi.plugin: outband protocol version set to '%d'\n", protocol_version);
1640
+ protocol_version = netdata_parse_outofband_driver_type(argv[++i]);
1641
+ if(debug) fprintf(stderr, "%s: outband protocol version set to '%d'\n",
1642
+ program_name, protocol_version);
1643
}
1644
else {
1741
- driver_type=parse_inband_driver_type(argv[++i]);
1742
- if(debug) fprintf(stderr, "freeipmi.plugin: inband driver type set to '%d'\n", driver_type);
1645
+ driver_type = netdata_parse_inband_driver_type(argv[++i]);
1646
+ if(debug) fprintf(stderr, "%s: inband driver type set to '%d'\n",
1647
+ program_name, driver_type);
1648
}
1649
continue;
1745
- } else if (i < argc && strcmp("noauthcodecheck", argv[i]) == 0) {
1746
- if (!hostname || host_is_local(hostname)) {
1650
+ } else if (i < argc && (strcmp("noauthcodecheck", argv[i]) == 0 || strcmp("no-auth-code-check", argv[i]) == 0)) {
1651
+ if (!hostname || netdata_host_is_localhost(hostname)) {
1652
if (debug)
1748
- fprintf(
1749
- stderr,
1750
- "freeipmi.plugin: noauthcodecheck workaround flag is ignored for inband configuration\n");
1751
- } else if (protocol_version < 0 || protocol_version == IPMI_MONITORING_PROTOCOL_VERSION_1_5) {
1653
+ fprintf(stderr, "%s: noauthcodecheck workaround flag is ignored for inband configuration\n",
1654
+ program_name);
1655
+
1656
+ }
1657
+ else if (protocol_version < 0 || protocol_version == IPMI_MONITORING_PROTOCOL_VERSION_1_5) {
1658
workaround_flags |= IPMI_MONITORING_WORKAROUND_FLAGS_PROTOCOL_VERSION_1_5_NO_AUTH_CODE_CHECK;
1659
+
1660
if (debug)
1754
- fprintf(stderr, "freeipmi.plugin: noauthcodecheck workaround flag enabled\n");
1755
- } else {
1661
+ fprintf(stderr, "%s: noauthcodecheck workaround flag enabled\n", program_name);
1662
+ }
1663
+ else {
1664
if (debug)
1757
- fprintf(
1758
- stderr,
1759
- "freeipmi.plugin: noauthcodecheck workaround flag is ignored for protocol version 2.0\n");
1665
+ fprintf(stderr, "%s: noauthcodecheck workaround flag is ignored for protocol version 2.0\n",
1666
+ program_name);
1667
}
1668
continue;
1669
}
1670
else if(i < argc && strcmp("sdr-cache-dir", argv[i]) == 0) {
1671
sdr_cache_directory = argv[++i];
1765
- if(debug) fprintf(stderr, "freeipmi.plugin: SDR cache directory set to '%s'\n", sdr_cache_directory);
1672
+
1673
+ if(debug)
1674
+ fprintf(stderr, "%s: SDR cache directory set to '%s'\n", program_name, sdr_cache_directory);
1675
+
1676
continue;
1677
}
1678
else if(i < argc && strcmp("sensor-config-file", argv[i]) == 0) {
1679
sensor_config_file = argv[++i];
1770
- if(debug) fprintf(stderr, "freeipmi.plugin: sensor config file set to '%s'\n", sensor_config_file);
1680
+ if(debug) fprintf(stderr, "%s: sensor config file set to '%s'\n", program_name, sensor_config_file);
1681
+ continue;
1682
+ }
1683
+ else if(i < argc && strcmp("sel-config-file", argv[i]) == 0) {
1684
+ sel_config_file = argv[++i];
1685
+ if(debug) fprintf(stderr, "%s: sel config file set to '%s'\n", program_name, sel_config_file);
1686
continue;
1687
}
1688
else if(i < argc && strcmp("ignore", argv[i]) == 0) {
1774
- excluded_record_ids_parse(argv[++i]);
1689
+ excluded_record_ids_parse(argv[++i], debug);
1690
continue;
1691
}
1692
else if(i < argc && strcmp("ignore-status", argv[i]) == 0) {
1778
- excluded_status_record_ids_parse(argv[++i]);
1693
+ excluded_status_record_ids_parse(argv[++i], debug);
1694
continue;
1695
}
1696
1782
- collector_error("freeipmi.plugin: ignoring parameter '%s'", argv[i]);
1697
+ collector_error("%s(): ignoring parameter '%s'", __FUNCTION__, argv[i]);
1698
}
1699
1700
errno = 0;
1701
1787
- if(freq >= netdata_update_every)
1788
- netdata_update_every = freq;
1789
-
1790
- else if(freq)
1791
- collector_error("update frequency %d seconds is too small for IPMI. Using %d.", freq, netdata_update_every);
1702
+ if(freq_s && freq_s < update_every)
1703
+ collector_error("%s(): update frequency %d seconds is too small for IPMI. Using %d.",
1704
+ __FUNCTION__, freq_s, update_every);
1705
1706
+ update_every = freq_s = MAX(freq_s, update_every);
1707
+ update_every_sel = MAX(update_every, update_every_sel);
1708
1709
// ------------------------------------------------------------------------
1710
// initialize IPMI
1711
1797
- struct ipmi_monitoring_ipmi_config ipmi_config;
1798
-
1799
- if(debug) fprintf(stderr, "freeipmi.plugin: calling _init_ipmi_config()\n");
1800
-
1801
- _init_ipmi_config(&ipmi_config);
1802
-
1712
if(debug) {
1804
- fprintf(stderr, "freeipmi.plugin: calling ipmi_monitoring_init()\n");
1805
- ipmimonitoring_init_flags|=IPMI_MONITORING_FLAGS_DEBUG|IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS;
1713
+ fprintf(stderr, "%s: calling ipmi_monitoring_init()\n", program_name);
1714
+ ipmimonitoring_init_flags |= IPMI_MONITORING_FLAGS_DEBUG|IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS;
1715
}
1716
1808
- if(ipmi_monitoring_init(ipmimonitoring_init_flags, &errnum) < 0)
1809
- fatal("ipmi_monitoring_init: %s", ipmi_monitoring_ctx_strerror(errnum));
1810
-
1811
- if(debug) fprintf(stderr, "freeipmi.plugin: detecting IPMI minimum update frequency...\n");
1812
- freq = ipmi_detect_speed_secs(&ipmi_config);
1813
- if(debug) fprintf(stderr, "freeipmi.plugin: IPMI minimum update frequency was calculated to %d seconds.\n", freq);
1814
-
1815
- if(freq > netdata_update_every) {
1816
- collector_info("enforcing minimum data collection frequency, calculated to %d seconds.", freq);
1817
- netdata_update_every = freq;
1818
- }
1717
+ int rc;
1718
+ if(ipmi_monitoring_init(ipmimonitoring_init_flags, &rc) < 0)
1719
+ fatal("ipmi_monitoring_init: %s", ipmi_monitoring_ctx_strerror(rc));
1720
1721
+ // ------------------------------------------------------------------------
1722
+ // create the data collection threads
1723
+
1724
+ struct ipmi_collection_thread sensors_data = {
1725
+ .type = IPMI_COLLECT_TYPE_SENSORS,
1726
+ .freq_s = update_every,
1727
+ .spinlock = NETDATA_SPINLOCK_INITIALIZER,
1728
+ .debug = debug,
1729
+ .state = {
1730
+ .debug = debug,
1731
+ .sensors = {
1732
+ .status = ICS_INIT,
1733
+ .last_iteration_ut = now_monotonic_usec(),
1734
+ .freq_ut = update_every * USEC_PER_SEC,
1735
+ .priority = IPMI_SENSORS_DASHBOARD_PRIORITY,
1736
+ .dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE|DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct sensor)),
1737
+ },
1738
+ },
1739
+ }, sel_data = {
1740
+ .type = IPMI_COLLECT_TYPE_SEL,
1741
+ .freq_s = update_every_sel,
1742
+ .spinlock = NETDATA_SPINLOCK_INITIALIZER,
1743
+ .debug = debug,
1744
+ .state = {
1745
+ .debug = debug,
1746
+ .sel = {
1747
+ .status = ICS_INIT,
1748
+ .last_iteration_ut = now_monotonic_usec(),
1749
+ .freq_ut = update_every_sel * USEC_PER_SEC,
1750
+ .priority = IPMI_SEL_DASHBOARD_PRIORITY,
1751
+ },
1752
+ },
1753
+ };
1754
+
1755
+ netdata_thread_t sensors_thread = 0, sel_thread = 0;
1756
+
1757
+ netdata_thread_create(&sensors_thread, "IPMI[sensors]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sensors_data);
1758
+
1759
+ if(netdata_do_sel)
1760
+ netdata_thread_create(&sel_thread, "IPMI[sel]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sel_data);
1761
1762
// ------------------------------------------------------------------------
1763
// the main loop
1764
1824
- if(debug) fprintf(stderr, "freeipmi.plugin: starting data collection\n");
1765
+ if(debug) fprintf(stderr, "%s: starting data collection\n", program_name);
1766
1767
time_t started_t = now_monotonic_sec();
1768
1769
size_t iteration = 0;
1829
- usec_t step = netdata_update_every * USEC_PER_SEC;
1770
+ usec_t step = 100 * USEC_PER_MS;
1771
+ bool global_chart_created = false;
1772
1773
heartbeat_t hb;
1774
heartbeat_init(&hb);
1775
for(iteration = 0; 1 ; iteration++) {
1776
usec_t dt = heartbeat_next(&hb, step);
1777
1836
- if (iteration) {
1837
- if (iteration == 1) {
1838
- fprintf(
1839
- stdout,
1840
- "CHART netdata.freeipmi_availability_status '' 'Plugin availability status' 'status' plugins netdata.plugin_availability_status line 146000 %d\n"
1841
- "DIMENSION available '' absolute 1 1\n",
1842
- netdata_update_every);
1778
+ fprintf(stdout, "\n"); // keepalive to avoid parser read timeout (2 minutes) during ipmi_detect_speed_secs()
1779
+
1780
+ struct netdata_ipmi_state state = {0 };
1781
+
1782
+ spinlock_lock(&sensors_data.spinlock);
1783
+ state.sensors = sensors_data.state.sensors;
1784
+ spinlock_unlock(&sensors_data.spinlock);
1785
+
1786
+ spinlock_lock(&sel_data.spinlock);
1787
+ state.sel = sel_data.state.sel;
1788
+ spinlock_unlock(&sel_data.spinlock);
1789
+
1790
+ switch(state.sensors.status) {
1791
+ case ICS_RUNNING:
1792
+ step = update_every * USEC_PER_SEC;
1793
+ if(state.sensors.last_iteration_ut < now_monotonic_usec() - IPMI_RESTART_IF_SENSORS_DONT_ITERATE_EVERY_SECONDS * USEC_PER_SEC) {
1794
+ collector_error("%s(): sensors have not be collected for %zu seconds. Exiting to restart.",
1795
+ __FUNCTION__, (size_t)((now_monotonic_usec() - state.sensors.last_iteration_ut) / USEC_PER_SEC));
1796
+
1797
+ fprintf(stdout, "EXIT\n");
1798
+ fflush(stdout);
1799
+ exit(0);
1800
+ }
1801
+ break;
1802
+
1803
+ case ICS_INIT:
1804
+ continue;
1805
+
1806
+ case ICS_INIT_FAILED:
1807
+ collector_error("%s(): sensors failed to initialize. Calling DISABLE.", __FUNCTION__);
1808
+ fprintf(stdout, "DISABLE\n");
1809
+ fflush(stdout);
1810
+ exit(0);
1811
+
1812
+ case ICS_FAILED:
1813
+ collector_error("%s(): sensors fails repeatedly to collect metrics. Exiting to restart.", __FUNCTION__);
1814
+ fprintf(stdout, "EXIT\n");
1815
+ fflush(stdout);
1816
+ exit(0);
1817
+ }
1818
+
1819
+ if(netdata_do_sel) {
1820
+ switch (state.sensors.status) {
1821
+ case ICS_RUNNING:
1822
+ case ICS_INIT:
1823
+ break;
1824
+
1825
+ case ICS_INIT_FAILED:
1826
+ case ICS_FAILED:
1827
+ collector_error("%s(): SEL fails to collect events. Disabling SEL collection.", __FUNCTION__);
1828
+ netdata_do_sel = false;
1829
+ break;
1830
}
1844
- fprintf(
1845
- stdout,
1846
- "BEGIN netdata.freeipmi_availability_status\n"
1847
- "SET available = 1\n"
1848
- "END\n");
1831
}
1832
1851
- if(debug && iteration)
1852
- fprintf(stderr, "freeipmi.plugin: iteration %zu, dt %llu usec, sensors collected %zu, sensors sent to netdata %zu \n"
1833
+ if(unlikely(debug))
1834
+ fprintf(stderr, "%s: calling send_ipmi_sensor_metrics_to_netdata()\n", program_name);
1835
+
1836
+ state.updates.now_ut = now_monotonic_usec();
1837
+ send_ipmi_sensor_metrics_to_netdata(&state);
1838
+
1839
+ if(netdata_do_sel)
1840
+ send_ipmi_sel_metrics_to_netdata(&state);
1841
+
1842
+ if(unlikely(debug))
1843
+ fprintf(stderr, "%s: iteration %zu, dt %llu usec, sensors ever collected %zu, sensors last collected %zu \n"
1844
+ , program_name
1845
, iteration
1846
, dt
1855
- , netdata_sensors_collected
1856
- , netdata_sensors_updated
1847
+ , dictionary_entries(state.sensors.dict)
1848
+ , state.sensors.collected
1849
);
1850
1859
- netdata_mark_as_not_updated();
1851
+ if (!global_chart_created) {
1852
+ global_chart_created = true;
1853
1861
- if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_collect_data()\n");
1862
- if(ipmi_collect_data(&ipmi_config) < 0)
1863
- fatal("data collection failed.");
1854
+ fprintf(stdout,
1855
+ "CHART netdata.freeipmi_availability_status '' 'Plugin availability status' 'status' "
1856
+ "plugins netdata.plugin_availability_status line 146000 %d '' '%s' '%s'\n"
1857
+ "DIMENSION available '' absolute 1 1\n",
1858
+ update_every, program_name, "");
1859
+ }
1860
1865
- if(debug) fprintf(stderr, "freeipmi.plugin: calling send_metrics_to_netdata()\n");
1866
- send_metrics_to_netdata();
1867
- fflush(stdout);
1861
+ fprintf(stdout,
1862
+ "BEGIN netdata.freeipmi_availability_status\n"
1863
+ "SET available = 1\n"
1864
+ "END\n");
1865
1866
// restart check (14400 seconds)
1870
- if (now_monotonic_sec() - started_t > 14400) {
1867
+ if (now_monotonic_sec() - started_t > IPMI_RESTART_EVERY_SECONDS) {
1868
+ collector_error("%s(): reached my lifetime expectancy. Exiting to restart.", __FUNCTION__);
1869
fprintf(stdout, "EXIT\n");
1870
fflush(stdout);
1871
exit(0);
1872
}
1873
+
1874
+ fflush(stdout);
1875
}
1876
}
1877
-