@cryptotaxi247 / netdata-1 / commits / eb6f1de7c

multi-threaded version of freeipmi.plugin (#15327)

* multi-threaded version of freeipmi.plugin * fix type check * debug info * debug info * updated should be smaller, not bigger * ignore sensors without name * variable data collection frequencies for sensors and sel; also respect the min data collection frequency * reorg and code cleanup * collect states even for unknown units and empty names * render all sensors * reset unknown state sensors * ignore sensors without name * added component fan * Update ipmi.conf * added label type * remove global state counters and chart * updated copyright notice * remove unused struct members * remove unused variable * added a log line everytime the plugin decides to exit to show what was wrong * reworked freeipmi for optimal performance * disabled debugging and fixed bug * added debug * added debug * added debug * removed debugging info * cleanup and final touches * let fan metrics be categorized by the component they are cooling * added plugin and module to charts * more component matches * code cleanup, sel should now be a lot faster * make sel min collection time 30 secs * more component matches; refreshed functions copied from freeipmi codebase * add keepalive to avoid parser read timeout during ipmi_detect_speed_secs * ipmi.fan_speed => ipmi.sensor_fan_speed * update metrics csv and readme * ok newline --------- Co-authored-by: Ilya Mashchenko <ilya@netdata.cloud>

Costa Tsaousis committed Jul 10, 2023 at 14:11 UTC eb6f1de7c6f7b626cb2ec333697b63034115914b
5 files changed +1419 -1313
collectors/freeipmi.plugin/README.md
+111 -30
@@ -11,7 +11,10 @@ learn_rel_path: "Integrations/Monitor/Devices"
11
12 Netdata has a [freeipmi](https://www.gnu.org/software/freeipmi/) plugin.
13
14 -> FreeIPMI provides in-band and out-of-band IPMI software based on the IPMI v1.5/2.0 specification. The IPMI specification defines a set of interfaces for platform management and is implemented by a number vendors for system management. The features of IPMI that most users will be interested in are sensor monitoring, system event monitoring, power control, and serial-over-LAN (SOL).
14 +> FreeIPMI provides in-band and out-of-band IPMI software based on the IPMI v1.5/2.0 specification. The IPMI
15 +> specification defines a set of interfaces for platform management and is implemented by a number vendors for system
16 +> management. The features of IPMI that most users will be interested in are sensor monitoring, system event monitoring,
17 +> power control, and serial-over-LAN (SOL).
18
19 ## Installing the FreeIPMI plugin
20
@@ -22,7 +25,8 @@ installed automatically due to the large number of dependencies it requires.
25 When using a static build of Netdata, the FreeIPMI plugin will be included and installed automatically, though
26 you will still need to have FreeIPMI installed on your system to be able to use the plugin.
27
25 -When using a local build of Netdata, you need to ensure that the FreeIPMI development packages (typically called `libipmimonitoring-dev`, `libipmimonitoring-devel`, or `freeipmi-devel`) are installed when building Netdata.
28 +When using a local build of Netdata, you need to ensure that the FreeIPMI development packages (typically
29 +called `libipmimonitoring-dev`, `libipmimonitoring-devel`, or `freeipmi-devel`) are installed when building Netdata.
30
31 ### Special Considerations
32
@@ -30,7 +34,9 @@ Accessing IPMI requires root access, so the FreeIPMI plugin is automatically ins
34
35 FreeIPMI does not work correctly on IBM POWER systems, thus Netdata’s FreeIPMI plugin is not usable on such systems.
36
33 -If you have not previously used IPMI on your system, you will probably need to run the `ipmimonitoring` command as root to initiailze IPMI settings so that the Netdata plugin works correctly. It should return information about available seensors on the system.
37 +If you have not previously used IPMI on your system, you will probably need to run the `ipmimonitoring` command as root
38 +to initiailze IPMI settings so that the Netdata plugin works correctly. It should return information about available
39 +seensors on the system.
40
41 In some distributions `libipmimonitoring.pc` is located in a non-standard directory, which
42 can cause building the plugin to fail when building Netdata from source. In that case you
@@ -38,37 +44,68 @@ should find the file and link it to the standard pkg-config directory. Usually,
44 /usr/lib/$(uname -m)-linux-gnu/pkgconfig/libipmimonitoring.pc/libipmimonitoring.pc /usr/lib/pkgconfig/libipmimonitoring.pc`
45 resolves this issue.
46
41 -## Netdata use
47 +## Metrics
48
43 -The plugin creates (up to) 8 charts, based on the information collected from IPMI:
49 +The plugin does a speed test when it starts, to find out the duration needed by the IPMI processor to respond. Depending
50 +on the speed of your IPMI processor, charts may need several seconds to show up on the dashboard.
51
45 -1. number of sensors by state
46 -2. number of events in SEL
47 -3. Temperatures CELSIUS
48 -4. Temperatures FAHRENHEIT
49 -5. Voltages
50 -6. Currents
51 -7. Power
52 -8. Fans
52 +Metrics grouped by *scope*.
53
54 -It also adds 2 alarms:
54 +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
55
56 -1. Sensors in non-nominal state (i.e. warning and critical)
57 -2. SEL is non empty
56 +### global
57
59 -![image](https://cloud.githubusercontent.com/assets/2662304/23674138/88926a20-037d-11e7-89c0-20e74ee10cd1.png)
58 +These metrics refer to the monitored host.
59
61 -The plugin does a speed test when it starts, to find out the duration needed by the IPMI processor to respond. Depending on the speed of your IPMI processor, charts may need several seconds to show up on the dashboard.
60 +This scope has no labels.
61
63 -## `freeipmi.plugin` configuration
62 +Metrics:
63 +
64 +| Metric | Dimensions | Unit |
65 +|----------|:----------:|:------:|
66 +| ipmi.sel | events | events |
67 +
68 +### sensor
69 +
70 +These metrics refer to the VPN user.
71 +
72 +Labels:
73 +
74 +| Label | Description |
75 +|-----------|-----------------------------------------------------------------------------------------------------------------|
76 +| sensor | Sensor name. Same value as the "Name" column in the `ipmi-sensors` output. |
77 +| type | Sensor type. Same value as the "Type" column in the `ipmi-sensors` output. |
78 +| component | General sensor component. Identified by Netdata based on sensor name and type (e.g. System, Processor, Memory). |
79 +
80 +Metrics:
81 +
82 +| Metric | Dimensions | Unit |
83 +|-----------------------------|:-----------------------------------:|:----------:|
84 +| ipmi.sensor_state | nominal, critical, warning, unknown | state |
85 +| ipmi.sensor_temperature_c | temperature | Celsius |
86 +| ipmi.sensor_temperature_f | temperature | Fahrenheit |
87 +| ipmi.sensor_voltage | voltage | Volts |
88 +| ipmi.sensor_ampere | ampere | Amps |
89 +| ipmi.sensor_fan_speed | rotations | RPM |
90 +| ipmi.sensor_power | power | Watts |
91 +| ipmi.sensor_reading_percent | percentage | % |
92 +
93 +## Alarms
94 +
95 +There are 2 alarms:
96 +
97 +- The sensor is in a warning or critical state.
98 +- System Event Log (SEL) is non-empty.
99 +
100 +## Configuration
101
102 The plugin supports a few options. To see them, run:
103
104 ```text
68 -# /usr/libexec/netdata/plugins.d/freeipmi.plugin -h
105 +# ./freeipmi.plugin --help
106
70 - netdata freeipmi.plugin 1.8.0-546-g72ce5d6b_rolling
71 - Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>
107 + netdata freeipmi.plugin v1.40.0-137-gf162c25bd
108 + Copyright (C) 2023 Netdata Inc.
109 Released under GNU General Public License v3 or later.
110 All rights reserved.
111
@@ -86,17 +123,49 @@ The plugin supports a few options. To see them, run:
123 no-sel enable/disable SEL collection
124 default: enabled
125
126 + reread-sdr-cache re-read SDR cache on every iteration
127 + default: disabled
128 +
129 + interpret-oem-data attempt to parse OEM data
130 + default: disabled
131 +
132 + assume-system-event-record
133 + tread illegal SEL events records as normal
134 + default: disabled
135 +
136 + ignore-non-interpretable-sensors
137 + do not read sensors that cannot be interpreted
138 + default: disabled
139 +
140 + bridge-sensors bridge sensors not owned by the BMC
141 + default: disabled
142 +
143 + shared-sensors enable shared sensors, if found
144 + default: disabled
145 +
146 + no-discrete-reading do not read sensors that their event/reading type code is invalid
147 + default: enabled
148 +
149 + ignore-scanning-disabled
150 + Ignore the scanning bit and read sensors no matter what
151 + default: disabled
152 +
153 + assume-bmc-owner assume the BMC is the sensor owner no matter what
154 + (usually bridging is required too)
155 + default: disabled
156 +
157 hostname HOST
158 username USER
159 password PASS connect to remote IPMI host
160 default: local IPMI processor
161
162 + no-auth-code-check
163 noauthcodecheck don't check the authentication codes returned
164
96 - driver-type IPMIDRIVER
97 - Specify the driver type to use instead of doing an auto selection.
98 - The currently available outofband drivers are LAN and LAN_2_0,
99 - which perform IPMI 1.5 and IPMI 2.0 respectively.
165 + driver-type IPMIDRIVER
166 + Specify the driver type to use instead of doing an auto selection.
167 + The currently available outofband drivers are LAN and LAN_2_0,
168 + which perform IPMI 1.5 and IPMI 2.0 respectively.
169 The currently available inband drivers are KCS, SSIF, OPENIPMI and SUNBMC.
170
171 sdr-cache-dir PATH directory for SDR cache files
@@ -105,9 +174,15 @@ The plugin supports a few options. To see them, run:
174 sensor-config-file FILE filename to read sensor configuration
175 default: system default
176
177 + sel-config-file FILE filename to read sel configuration
178 + default: system default
179 +
180 ignore N1,N2,N3,... sensor IDs to ignore
181 default: none
182
183 + ignore-status N1,N2,N3,... sensor IDs to ignore status (nominal/warning/critical)
184 + default: none
185 +
186 -v
187 -V
188 version print version and exit
@@ -131,13 +206,17 @@ You can set these options in `/etc/netdata/netdata.conf` at this section:
206 command options =
207 ```
208
134 -Append to `command options =` the settings you need. The minimum `update every` is 5 (enforced internally by the plugin). IPMI is slow and CPU hungry. So, once every 5 seconds is pretty acceptable.
209 +Append to `command options =` the settings you need. The minimum `update every` is 5 (enforced internally by the
210 +plugin). IPMI is slow and CPU hungry. So, once every 5 seconds is pretty acceptable.
211
212 ## Ignoring specific sensors
213
138 -Specific sensor IDs can be excluded from freeipmi tools by editing `/etc/freeipmi/freeipmi.conf` and setting the IDs to be ignored at `ipmi-sensors-exclude-record-ids`. **However this file is not used by `libipmimonitoring`** (the library used by Netdata's `freeipmi.plugin`).
214 +Specific sensor IDs can be excluded from freeipmi tools by editing `/etc/freeipmi/freeipmi.conf` and setting the IDs to
215 +be ignored at `ipmi-sensors-exclude-record-ids`. **However this file is not used by `libipmimonitoring`** (the library
216 +used by Netdata's `freeipmi.plugin`).
217
140 -So, `freeipmi.plugin` supports the option `ignore` that accepts a comma separated list of sensor IDs to ignore. To configure it, edit `/etc/netdata/netdata.conf` and set:
218 +So, `freeipmi.plugin` supports the option `ignore` that accepts a comma separated list of sensor IDs to ignore. To
219 +configure it, edit `/etc/netdata/netdata.conf` and set:
220
221 ```
222 [plugin:freeipmi]
@@ -196,7 +275,9 @@ You can also permanently set the above setting by creating the file `/etc/modpro
275 options ipmi_si kipmid_max_busy_us=10
276 ```
277
199 -This instructs the kernel IPMI module to pause for a tick between checking IPMI. Querying IPMI will be a lot slower now (e.g. several seconds for IPMI to respond), but `kipmi` will not use any noticeable CPU. You can also use a higher number (this is the number of microseconds to poll IPMI for a response, before waiting for a tick).
278 +This instructs the kernel IPMI module to pause for a tick between checking IPMI. Querying IPMI will be a lot slower
279 +now (e.g. several seconds for IPMI to respond), but `kipmi` will not use any noticeable CPU. You can also use a higher
280 +number (this is the number of microseconds to poll IPMI for a response, before waiting for a tick).
281
282 If you need to disable IPMI for Netdata, edit `/etc/netdata/netdata.conf` and set:
283
collectors/freeipmi.plugin/freeipmi_plugin.c
+1268 -1269
@@ -1,7 +1,7 @@
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,9 +15,59 @@
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>
@@ -27,22 +77,9 @@
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
@@ -50,53 +87,35 @@
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 *
@@ -106,26 +125,10 @@ int entity_sensor_names = 0;
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;
@@ -137,8 +140,8 @@ _init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
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;
@@ -148,437 +151,568 @@ _init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
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]);
@@ -590,7 +724,7 @@ static void excluded_record_ids_parse(const char *s) {
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) {
@@ -602,18 +736,14 @@ static void excluded_status_record_ids_parse(const char *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]);
@@ -645,959 +775,647 @@ static int excluded_status_record_ids_check(int record_id) {
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, &timestamp) < 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
@@ -1610,40 +1428,84 @@ int main (int argc, char **argv) {
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"
@@ -1661,16 +1523,53 @@ int main (int argc, char **argv) {
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"
@@ -1680,6 +1579,9 @@ int main (int argc, char **argv) {
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"
@@ -1700,11 +1602,12 @@ int main (int argc, char **argv) {
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 }
@@ -1713,7 +1616,7 @@ int main (int argc, char **argv) {
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) {
@@ -1721,7 +1624,7 @@ int main (int argc, char **argv) {
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) {
@@ -1729,149 +1632,245 @@ int main (int argc, char **argv) {
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 -
collectors/freeipmi.plugin/metrics.csv
+9 -9
@@ -1,10 +1,10 @@
1 metric,scope,dimensions,unit,description,chart_type,labels,plugin,module
2 -ipmi.sel,,events,events,"IPMI Events",area,,freeipmi.plugin,
3 -ipmi.sensors_states,,"nominal, critical, warning",sensors,"IPMI Sensors State",line,,freeipmi.plugin,
4 -ipmi.temperatures_c,,a dimension per sensor,Celsius,"System Celsius Temperatures read by IPMI",line,,freeipmi.plugin,
5 -ipmi.temperatures_f,,a dimension per sensor,Fahrenheit,"System Celsius Temperatures read by IPMI",line,,freeipmi.plugin,
6 -ipmi.voltages,,a dimension per sensor,Volts,"System Voltages read by IPMI",line,,freeipmi.plugin,
7 -ipmi.amps,,a dimension per sensor,Amps,"System Current read by IPMI",line,,freeipmi.plugin,
8 -ipmi.rpm,,a dimension per sensor,RPM,"System Fans read by IPMI",line,,freeipmi.plugin,
9 -ipmi.watts,,a dimension per sensor,Watts,"System Power read by IPMI",line,,freeipmi.plugin,
10 -ipmi.percent,,a dimension per sensor,%,"System Metrics read by IPMI",line,,freeipmi.plugin,
\ No newline at end of file
2 +ipmi.sel,,events,events,"IPMI Events",area,,freeipmi.plugin,sel
3 +ipmi.sensor_state,sensor,"nominal, critical, warning, unknown",state,"IPMI Sensors State",line,,freeipmi.plugin,
4 +ipmi.sensor_temperature_c,sensor,temperature,Celsius,"IPMI Sensor Temperature Celsius",line,,freeipmi.plugin,sensors
5 +ipmi.sensor_temperature_f,sensor,temperature,Fahrenheit,"IPMI Sensor Temperature Fahrenheit",line,,freeipmi.plugin,sensors
6 +ipmi.sensor_voltage,sensor,voltage,Volts,"IPMI Sensor Voltage",line,,freeipmi.plugin,sensors
7 +ipmi.sensor_ampere,sensor,ampere,Amps,"IPMI Sensor Current",line,,freeipmi.plugin,sensors
8 +ipmi.sensor_fan_speed,sensor,rotations,RPM,"IPMI Sensor Fans Speed",line,,freeipmi.plugin,sensors
9 +ipmi.sensor_power,sensor,power,Watts,"IPMI Sensor Power",line,,freeipmi.plugin,sensors
10 +ipmi.sensor_reading_percent,sensor,percentage,%,"IPMI Sensor Reading Percentage",line,,freeipmi.plugin,sensors
health/health.d/ipmi.conf
+5 -5
@@ -1,15 +1,15 @@
1 - alarm: ipmi_sensors_states
2 - on: ipmi.sensors_states
1 + template: ipmi_sensor_state
2 + on: ipmi.sensor_state
3 class: Errors
4 type: System
5 component: IPMI
6 calc: $warning + $critical
7 - units: sensors
7 + units: state
8 every: 10s
9 - warn: $this > 0
9 + warn: $warning > 0
10 crit: $critical > 0
11 delay: up 5m down 15m multiplier 1.5 max 1h
12 - info: number of IPMI sensors in non-nominal state
12 + info: IPMI sensor ${label:sensor} (${label:component}) state
13 to: sysadmin
14
15 alarm: ipmi_events
libnetdata/libnetdata.h
+26
@@ -930,6 +930,32 @@ typedef enum {
930 TIMING_STEP_END2_PROPAGATE,
931 TIMING_STEP_END2_STORE,
932
933 + TIMING_STEP_FREEIPMI_CTX_CREATE,
934 + TIMING_STEP_FREEIPMI_DSR_CACHE_DIR,
935 + TIMING_STEP_FREEIPMI_SENSOR_CONFIG_FILE,
936 + TIMING_STEP_FREEIPMI_SENSOR_READINGS_BY_X,
937 + TIMING_STEP_FREEIPMI_READ_record_id,
938 + TIMING_STEP_FREEIPMI_READ_sensor_number,
939 + TIMING_STEP_FREEIPMI_READ_sensor_type,
940 + TIMING_STEP_FREEIPMI_READ_sensor_name,
941 + TIMING_STEP_FREEIPMI_READ_sensor_state,
942 + TIMING_STEP_FREEIPMI_READ_sensor_units,
943 + TIMING_STEP_FREEIPMI_READ_sensor_bitmask_type,
944 + TIMING_STEP_FREEIPMI_READ_sensor_bitmask,
945 + TIMING_STEP_FREEIPMI_READ_sensor_bitmask_strings,
946 + TIMING_STEP_FREEIPMI_READ_sensor_reading_type,
947 + TIMING_STEP_FREEIPMI_READ_sensor_reading,
948 + TIMING_STEP_FREEIPMI_READ_event_reading_type_code,
949 + TIMING_STEP_FREEIPMI_READ_record_type,
950 + TIMING_STEP_FREEIPMI_READ_record_type_class,
951 + TIMING_STEP_FREEIPMI_READ_sel_state,
952 + TIMING_STEP_FREEIPMI_READ_event_direction,
953 + TIMING_STEP_FREEIPMI_READ_event_type_code,
954 + TIMING_STEP_FREEIPMI_READ_event_offset_type,
955 + TIMING_STEP_FREEIPMI_READ_event_offset,
956 + TIMING_STEP_FREEIPMI_READ_event_offset_string,
957 + TIMING_STEP_FREEIPMI_READ_manufacturer_id,
958 +
959 // terminator
960 TIMING_STEP_MAX,
961 } TIMING_STEP;