summaryrefslogtreecommitdiffstats
path: root/collectors/freeipmi.plugin/freeipmi_plugin.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:18 +0000
commit5da14042f70711ea5cf66e034699730335462f66 (patch)
tree0f6354ccac934ed87a2d555f45be4c831cf92f4a /collectors/freeipmi.plugin/freeipmi_plugin.c
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-5da14042f70711ea5cf66e034699730335462f66.tar.xz
netdata-5da14042f70711ea5cf66e034699730335462f66.zip
Merging upstream version 1.45.3+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'collectors/freeipmi.plugin/freeipmi_plugin.c')
-rw-r--r--collectors/freeipmi.plugin/freeipmi_plugin.c2094
1 files changed, 0 insertions, 2094 deletions
diff --git a/collectors/freeipmi.plugin/freeipmi_plugin.c b/collectors/freeipmi.plugin/freeipmi_plugin.c
deleted file mode 100644
index 6ec9b698b..000000000
--- a/collectors/freeipmi.plugin/freeipmi_plugin.c
+++ /dev/null
@@ -1,2094 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-/*
- * netdata freeipmi.plugin
- * Copyright (C) 2023 Netdata Inc.
- * GPL v3+
- *
- * Based on:
- * ipmimonitoring-sensors.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
- * ipmimonitoring-sel.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
- *
- * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
- * Copyright (C) 2006-2007 The Regents of the University of California.
- * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
- * Written by Albert Chu <chu11@llnl.gov>
- * UCRL-CODE-222073
- */
-
-// ----------------------------------------------------------------------------
-// BEGIN NETDATA CODE
-
-// #define NETDATA_TIMING_REPORT 1
-#include "libnetdata/libnetdata.h"
-#include "libnetdata/required_dummies.h"
-
-#define FREEIPMI_GLOBAL_FUNCTION_SENSORS() do { \
- fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"ipmi-sensors\" %d \"%s\"\n", 5, "Displays current sensor state and readings"); \
- } while(0)
-
-// component names, based on our patterns
-#define NETDATA_SENSOR_COMPONENT_MEMORY_MODULE "Memory Module"
-#define NETDATA_SENSOR_COMPONENT_MEMORY "Memory"
-#define NETDATA_SENSOR_COMPONENT_PROCESSOR "Processor"
-#define NETDATA_SENSOR_COMPONENT_IPU "Image Processor"
-#define NETDATA_SENSOR_COMPONENT_STORAGE "Storage"
-#define NETDATA_SENSOR_COMPONENT_MOTHERBOARD "Motherboard"
-#define NETDATA_SENSOR_COMPONENT_NETWORK "Network"
-#define NETDATA_SENSOR_COMPONENT_POWER_SUPPLY "Power Supply"
-#define NETDATA_SENSOR_COMPONENT_SYSTEM "System"
-#define NETDATA_SENSOR_COMPONENT_PERIPHERAL "Peripheral"
-
-// netdata plugin defaults
-#define SENSORS_DICT_KEY_SIZE 2048 // the max size of the key for the dictionary of sensors
-#define SPEED_TEST_ITERATIONS 5 // how many times to repeat data collection to decide latency
-#define IPMI_SENSORS_DASHBOARD_PRIORITY 90000 // the priority of the sensors charts on the dashboard
-#define IPMI_SEL_DASHBOARD_PRIORITY 99000 // the priority of the SEL events chart on the dashboard
-#define IPMI_SENSORS_MIN_UPDATE_EVERY 5 // the minimum data collection frequency for sensors
-#define IPMI_SEL_MIN_UPDATE_EVERY 30 // the minimum data collection frequency for SEL events
-#define IPMI_ENABLE_SEL_BY_DEFAULT true // true/false, to enable/disable SEL by default
-#define IPMI_RESTART_EVERY_SECONDS 14400 // restart the plugin every this many seconds
- // this is to prevent possible bugs/leaks in ipmi libraries
-#define IPMI_RESTART_IF_SENSORS_DONT_ITERATE_EVERY_SECONDS (10 * 60) // stale data collection detection time
-
-// forward definition of functions and structures
-struct netdata_ipmi_state;
-static void netdata_update_ipmi_sensor_reading(
- int record_id
- , int sensor_number
- , int sensor_type
- , int sensor_state
- , int sensor_units
- , int sensor_reading_type
- , char *sensor_name
- , void *sensor_reading
- , int event_reading_type_code
- , int sensor_bitmask_type
- , int sensor_bitmask
- , char **sensor_bitmask_strings
- , struct netdata_ipmi_state *state
-);
-static void netdata_update_ipmi_sel_events_count(struct netdata_ipmi_state *state, uint32_t events);
-
-// END NETDATA CODE
-// ----------------------------------------------------------------------------
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/time.h>
-
-#include <ipmi_monitoring.h>
-#include <ipmi_monitoring_bitmasks.h>
-#include <ipmi_monitoring_offsets.h>
-
-/* Communication Configuration - Initialize accordingly */
-
-static netdata_mutex_t stdout_mutex = NETDATA_MUTEX_INITIALIZER;
-static bool function_plugin_should_exit = false;
-
-int update_every = IPMI_SENSORS_MIN_UPDATE_EVERY; // this is the minimum update frequency
-int update_every_sel = IPMI_SEL_MIN_UPDATE_EVERY; // this is the minimum update frequency for SEL events
-
-/* Hostname, NULL for In-band communication, non-null for a hostname */
-char *hostname = NULL;
-
-/* In-band Communication Configuration */
-int driver_type = -1; // IPMI_MONITORING_DRIVER_TYPE_KCS, etc. or -1 for default
-int disable_auto_probe = 0; /* probe for in-band device */
-unsigned int driver_address = 0; /* not used if probing */
-unsigned int register_spacing = 0; /* not used if probing */
-char *driver_device = NULL; /* not used if probing */
-
-/* Out-of-band Communication Configuration */
-int protocol_version = -1; // IPMI_MONITORING_PROTOCOL_VERSION_1_5, etc. or -1 for default
-char *username = "";
-char *password = "";
-unsigned char *k_g = NULL;
-unsigned int k_g_len = 0;
-int privilege_level = -1; // IPMI_MONITORING_PRIVILEGE_LEVEL_USER, etc. or -1 for default
-int authentication_type = -1; // IPMI_MONITORING_AUTHENTICATION_TYPE_MD5, etc. or -1 for default
-int cipher_suite_id = -1; /* 0 or -1 for default */
-int session_timeout = 0; /* 0 for default */
-int retransmission_timeout = 0; /* 0 for default */
-
-/* Workarounds - specify workaround flags if necessary */
-unsigned int workaround_flags = 0;
-
-/* Set to an appropriate alternate if desired */
-char *sdr_cache_directory = "/tmp";
-char *sdr_sensors_cache_format = ".netdata-freeipmi-sensors-%H-on-%L.sdr";
-char *sdr_sel_cache_format = ".netdata-freeipmi-sel-%H-on-%L.sdr";
-char *sensor_config_file = NULL;
-char *sel_config_file = NULL;
-
-// controlled via command line options
-unsigned int global_sel_flags = IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
-unsigned int global_sensor_reading_flags = IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING|IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
-bool remove_reread_sdr_after_first_use = true;
-
-/* Initialization flags
- *
- * Most commonly bitwise OR IPMI_MONITORING_FLAGS_DEBUG and/or
- * IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS for extra debugging
- * information.
- */
-unsigned int ipmimonitoring_init_flags = 0;
-
-// ----------------------------------------------------------------------------
-// functions common to sensors and SEL
-
-static void initialize_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config) {
- fatal_assert(ipmi_config);
-
- ipmi_config->driver_type = driver_type;
- ipmi_config->disable_auto_probe = disable_auto_probe;
- ipmi_config->driver_address = driver_address;
- ipmi_config->register_spacing = register_spacing;
- ipmi_config->driver_device = driver_device;
-
- ipmi_config->protocol_version = protocol_version;
- ipmi_config->username = username;
- ipmi_config->password = password;
- ipmi_config->k_g = k_g;
- ipmi_config->k_g_len = k_g_len;
- ipmi_config->privilege_level = privilege_level;
- ipmi_config->authentication_type = authentication_type;
- ipmi_config->cipher_suite_id = cipher_suite_id;
- ipmi_config->session_timeout_len = session_timeout;
- ipmi_config->retransmission_timeout_len = retransmission_timeout;
-
- ipmi_config->workaround_flags = workaround_flags;
-}
-
-static const char *netdata_ipmi_get_sensor_type_string (int sensor_type, const char **component) {
- switch (sensor_type) {
- case IPMI_MONITORING_SENSOR_TYPE_RESERVED:
- return ("Reserved");
-
- case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
- return ("Temperature");
-
- case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
- return ("Voltage");
-
- case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
- return ("Current");
-
- case IPMI_MONITORING_SENSOR_TYPE_FAN:
- return ("Fan");
-
- case IPMI_MONITORING_SENSOR_TYPE_PHYSICAL_SECURITY:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Physical Security");
-
- case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_SECURITY_VIOLATION_ATTEMPT:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Platform Security Violation Attempt");
-
- case IPMI_MONITORING_SENSOR_TYPE_PROCESSOR:
- *component = NETDATA_SENSOR_COMPONENT_PROCESSOR;
- return ("Processor");
-
- case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
- *component = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY;
- return ("Power Supply");
-
- case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
- *component = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY;
- return ("Power Unit");
-
- case IPMI_MONITORING_SENSOR_TYPE_COOLING_DEVICE:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Cooling Device");
-
- case IPMI_MONITORING_SENSOR_TYPE_OTHER_UNITS_BASED_SENSOR:
- return ("Other Units Based Sensor");
-
- case IPMI_MONITORING_SENSOR_TYPE_MEMORY:
- *component = NETDATA_SENSOR_COMPONENT_MEMORY;
- return ("Memory");
-
- case IPMI_MONITORING_SENSOR_TYPE_DRIVE_SLOT:
- *component = NETDATA_SENSOR_COMPONENT_STORAGE;
- return ("Drive Slot");
-
- case IPMI_MONITORING_SENSOR_TYPE_POST_MEMORY_RESIZE:
- *component = NETDATA_SENSOR_COMPONENT_MEMORY;
- return ("POST Memory Resize");
-
- case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("System Firmware Progress");
-
- case IPMI_MONITORING_SENSOR_TYPE_EVENT_LOGGING_DISABLED:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Event Logging Disabled");
-
- case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG1:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Watchdog 1");
-
- case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_EVENT:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("System Event");
-
- case IPMI_MONITORING_SENSOR_TYPE_CRITICAL_INTERRUPT:
- return ("Critical Interrupt");
-
- case IPMI_MONITORING_SENSOR_TYPE_BUTTON_SWITCH:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Button/Switch");
-
- case IPMI_MONITORING_SENSOR_TYPE_MODULE_BOARD:
- return ("Module/Board");
-
- case IPMI_MONITORING_SENSOR_TYPE_MICROCONTROLLER_COPROCESSOR:
- *component = NETDATA_SENSOR_COMPONENT_PROCESSOR;
- return ("Microcontroller/Coprocessor");
-
- case IPMI_MONITORING_SENSOR_TYPE_ADD_IN_CARD:
- return ("Add In Card");
-
- case IPMI_MONITORING_SENSOR_TYPE_CHASSIS:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Chassis");
-
- case IPMI_MONITORING_SENSOR_TYPE_CHIP_SET:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Chip Set");
-
- case IPMI_MONITORING_SENSOR_TYPE_OTHER_FRU:
- return ("Other Fru");
-
- case IPMI_MONITORING_SENSOR_TYPE_CABLE_INTERCONNECT:
- return ("Cable/Interconnect");
-
- case IPMI_MONITORING_SENSOR_TYPE_TERMINATOR:
- return ("Terminator");
-
- case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_BOOT_INITIATED:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("System Boot Initiated");
-
- case IPMI_MONITORING_SENSOR_TYPE_BOOT_ERROR:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Boot Error");
-
- case IPMI_MONITORING_SENSOR_TYPE_OS_BOOT:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("OS Boot");
-
- case IPMI_MONITORING_SENSOR_TYPE_OS_CRITICAL_STOP:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("OS Critical Stop");
-
- case IPMI_MONITORING_SENSOR_TYPE_SLOT_CONNECTOR:
- return ("Slot/Connector");
-
- case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
- return ("System ACPI Power State");
-
- case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG2:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Watchdog 2");
-
- case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_ALERT:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Platform Alert");
-
- case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
- return ("Entity Presence");
-
- case IPMI_MONITORING_SENSOR_TYPE_MONITOR_ASIC_IC:
- return ("Monitor ASIC/IC");
-
- case IPMI_MONITORING_SENSOR_TYPE_LAN:
- *component = NETDATA_SENSOR_COMPONENT_NETWORK;
- return ("LAN");
-
- case IPMI_MONITORING_SENSOR_TYPE_MANAGEMENT_SUBSYSTEM_HEALTH:
- *component = NETDATA_SENSOR_COMPONENT_SYSTEM;
- return ("Management Subsystem Health");
-
- case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
- return ("Battery");
-
- case IPMI_MONITORING_SENSOR_TYPE_SESSION_AUDIT:
- return ("Session Audit");
-
- case IPMI_MONITORING_SENSOR_TYPE_VERSION_CHANGE:
- return ("Version Change");
-
- case IPMI_MONITORING_SENSOR_TYPE_FRU_STATE:
- return ("FRU State");
-
- case IPMI_MONITORING_SENSOR_TYPE_UNKNOWN:
- return ("Unknown");
-
- default:
- if(sensor_type >= IPMI_MONITORING_SENSOR_TYPE_OEM_MIN && sensor_type <= IPMI_MONITORING_SENSOR_TYPE_OEM_MAX)
- return ("OEM");
-
- return ("Unrecognized");
- }
-}
-
-#define netdata_ipmi_get_value_int(var, func, ctx) do { \
- (var) = func(ctx); \
- if( (var) < 0) { \
- collector_error("%s(): call to " #func " failed: %s", \
- __FUNCTION__, ipmi_monitoring_ctx_errormsg(ctx)); \
- goto cleanup; \
- } \
- timing_step(TIMING_STEP_FREEIPMI_READ_ ## var); \
-} while(0)
-
-#define netdata_ipmi_get_value_ptr(var, func, ctx) do { \
- (var) = func(ctx); \
- if(!(var)) { \
- collector_error("%s(): call to " #func " failed: %s", \
- __FUNCTION__, ipmi_monitoring_ctx_errormsg(ctx)); \
- goto cleanup; \
- } \
- timing_step(TIMING_STEP_FREEIPMI_READ_ ## var); \
-} while(0)
-
-#define netdata_ipmi_get_value_no_check(var, func, ctx) do { \
- (var) = func(ctx); \
- timing_step(TIMING_STEP_FREEIPMI_READ_ ## var); \
-} while(0)
-
-static int netdata_read_ipmi_sensors(struct ipmi_monitoring_ipmi_config *ipmi_config, struct netdata_ipmi_state *state) {
- timing_init();
-
- ipmi_monitoring_ctx_t ctx = NULL;
- unsigned int sensor_reading_flags = global_sensor_reading_flags;
- int i;
- int sensor_count;
- int rv = -1;
-
- if (!(ctx = ipmi_monitoring_ctx_create ())) {
- collector_error("ipmi_monitoring_ctx_create()");
- goto cleanup;
- }
-
- timing_step(TIMING_STEP_FREEIPMI_CTX_CREATE);
-
- if (sdr_cache_directory) {
- if (ipmi_monitoring_ctx_sdr_cache_directory (ctx, sdr_cache_directory) < 0) {
- collector_error("ipmi_monitoring_ctx_sdr_cache_directory(): %s\n", ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
- }
- if (sdr_sensors_cache_format) {
- if (ipmi_monitoring_ctx_sdr_cache_filenames(ctx, sdr_sensors_cache_format) < 0) {
- collector_error("ipmi_monitoring_ctx_sdr_cache_filenames(): %s\n", ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
- }
-
- timing_step(TIMING_STEP_FREEIPMI_DSR_CACHE_DIR);
-
- // Must call otherwise only default interpretations ever used
- // sensor_config_file can be NULL
- if (ipmi_monitoring_ctx_sensor_config_file (ctx, sensor_config_file) < 0) {
- collector_error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n", ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
-
- timing_step(TIMING_STEP_FREEIPMI_SENSOR_CONFIG_FILE);
-
- if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
- hostname,
- ipmi_config,
- sensor_reading_flags,
- NULL,
- 0,
- NULL,
- NULL)) < 0) {
- collector_error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
- ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
-
- timing_step(TIMING_STEP_FREEIPMI_SENSOR_READINGS_BY_X);
-
- for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (ctx)) {
- int record_id, sensor_number, sensor_type, sensor_state, sensor_units,
- sensor_bitmask_type, sensor_bitmask, event_reading_type_code, sensor_reading_type;
-
- char **sensor_bitmask_strings = NULL;
- char *sensor_name = NULL;
- void *sensor_reading;
-
- netdata_ipmi_get_value_int(record_id, ipmi_monitoring_sensor_read_record_id, ctx);
- netdata_ipmi_get_value_int(sensor_number, ipmi_monitoring_sensor_read_sensor_number, ctx);
- netdata_ipmi_get_value_int(sensor_type, ipmi_monitoring_sensor_read_sensor_type, ctx);
- netdata_ipmi_get_value_ptr(sensor_name, ipmi_monitoring_sensor_read_sensor_name, ctx);
- netdata_ipmi_get_value_int(sensor_state, ipmi_monitoring_sensor_read_sensor_state, ctx);
- netdata_ipmi_get_value_int(sensor_units, ipmi_monitoring_sensor_read_sensor_units, ctx);
- netdata_ipmi_get_value_int(sensor_bitmask_type, ipmi_monitoring_sensor_read_sensor_bitmask_type, ctx);
- netdata_ipmi_get_value_int(sensor_bitmask, ipmi_monitoring_sensor_read_sensor_bitmask, ctx);
- // it's ok for this to be NULL, i.e. sensor_bitmask == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN
- netdata_ipmi_get_value_no_check(sensor_bitmask_strings, ipmi_monitoring_sensor_read_sensor_bitmask_strings, ctx);
- netdata_ipmi_get_value_int(sensor_reading_type, ipmi_monitoring_sensor_read_sensor_reading_type, ctx);
- // whatever we read from the sensor, it is ok
- netdata_ipmi_get_value_no_check(sensor_reading, ipmi_monitoring_sensor_read_sensor_reading, ctx);
- netdata_ipmi_get_value_int(event_reading_type_code, ipmi_monitoring_sensor_read_event_reading_type_code, ctx);
-
- netdata_update_ipmi_sensor_reading(
- record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type, sensor_name,
- sensor_reading, event_reading_type_code, sensor_bitmask_type, sensor_bitmask, sensor_bitmask_strings,
- state
- );
-
-#ifdef NETDATA_COMMENTED
- /* It is possible you may want to monitor specific event
- * conditions that may occur. If that is the case, you may want
- * to check out what specific bitmask type and bitmask events
- * occurred. See ipmi_monitoring_bitmasks.h for a list of
- * bitmasks and types.
- */
-
- if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
- printf (", %Xh", sensor_bitmask);
- else
- printf (", N/A");
-
- if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN
- && sensor_bitmask_strings)
- {
- unsigned int i = 0;
-
- printf (",");
-
- while (sensor_bitmask_strings[i])
- {
- printf (" ");
-
- printf ("'%s'",
- sensor_bitmask_strings[i]);
-
- i++;
- }
- }
- else
- printf (", N/A");
-
- printf ("\n");
-#endif // NETDATA_COMMENTED
- }
-
- rv = 0;
-
-cleanup:
- if (ctx)
- ipmi_monitoring_ctx_destroy (ctx);
-
- timing_report();
-
- if(remove_reread_sdr_after_first_use)
- global_sensor_reading_flags &= ~(IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE);
-
- return (rv);
-}
-
-
-static int netdata_get_ipmi_sel_events_count(struct ipmi_monitoring_ipmi_config *ipmi_config, struct netdata_ipmi_state *state) {
- timing_init();
-
- ipmi_monitoring_ctx_t ctx = NULL;
- unsigned int sel_flags = global_sel_flags;
- int sel_count;
- int rv = -1;
-
- if (!(ctx = ipmi_monitoring_ctx_create ())) {
- collector_error("ipmi_monitoring_ctx_create()");
- goto cleanup;
- }
-
- if (sdr_cache_directory) {
- if (ipmi_monitoring_ctx_sdr_cache_directory (ctx, sdr_cache_directory) < 0) {
- collector_error( "ipmi_monitoring_ctx_sdr_cache_directory(): %s", ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
- }
- if (sdr_sel_cache_format) {
- if (ipmi_monitoring_ctx_sdr_cache_filenames(ctx, sdr_sel_cache_format) < 0) {
- collector_error("ipmi_monitoring_ctx_sdr_cache_filenames(): %s\n", ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
- }
-
- // Must call otherwise only default interpretations ever used
- // sel_config_file can be NULL
- if (ipmi_monitoring_ctx_sel_config_file (ctx, sel_config_file) < 0) {
- collector_error( "ipmi_monitoring_ctx_sel_config_file(): %s",
- ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
-
- if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
- hostname,
- ipmi_config,
- sel_flags,
- NULL,
- 0,
- NULL,
- NULL)) < 0) {
- collector_error( "ipmi_monitoring_sel_by_record_id(): %s",
- ipmi_monitoring_ctx_errormsg (ctx));
- goto cleanup;
- }
-
- netdata_update_ipmi_sel_events_count(state, sel_count);
-
- rv = 0;
-
-cleanup:
- if (ctx)
- ipmi_monitoring_ctx_destroy (ctx);
-
- timing_report();
-
- if(remove_reread_sdr_after_first_use)
- global_sel_flags &= ~(IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE);
-
- return (rv);
-}
-
-// ----------------------------------------------------------------------------
-// copied from freeipmi codebase commit 8dea6dec4012d0899901e595f2c868a05e1cefed
-// added netdata_ in-front to not overwrite library functions
-
-// FROM: common/miscutil/network.c
-static int netdata_host_is_localhost (const char *host) {
- /* Ordered by my assumption of most popular */
- if (!strcasecmp (host, "localhost")
- || !strcmp (host, "127.0.0.1")
- || !strcasecmp (host, "ipv6-localhost")
- || !strcmp (host, "::1")
- || !strcasecmp (host, "ip6-localhost")
- || !strcmp (host, "0:0:0:0:0:0:0:1"))
- return (1);
-
- return (0);
-}
-
-// FROM: common/parsecommon/parse-common.h
-#define IPMI_PARSE_DEVICE_LAN_STR "lan"
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR "lan_2_0"
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR2 "lan20"
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR3 "lan_20"
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR4 "lan2_0"
-#define IPMI_PARSE_DEVICE_LAN_2_0_STR5 "lanplus"
-#define IPMI_PARSE_DEVICE_KCS_STR "kcs"
-#define IPMI_PARSE_DEVICE_SSIF_STR "ssif"
-#define IPMI_PARSE_DEVICE_OPENIPMI_STR "openipmi"
-#define IPMI_PARSE_DEVICE_OPENIPMI_STR2 "open"
-#define IPMI_PARSE_DEVICE_SUNBMC_STR "sunbmc"
-#define IPMI_PARSE_DEVICE_SUNBMC_STR2 "bmc"
-#define IPMI_PARSE_DEVICE_INTELDCMI_STR "inteldcmi"
-
-// FROM: common/parsecommon/parse-common.c
-// changed the return values to match ipmi_monitoring.h
-static int netdata_parse_outofband_driver_type (const char *str) {
- if (strcasecmp (str, IPMI_PARSE_DEVICE_LAN_STR) == 0)
- return (IPMI_MONITORING_PROTOCOL_VERSION_1_5);
-
- /* support "lanplus" for those that might be used to ipmitool.
- * support typo variants to ease.
- */
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR) == 0
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR2) == 0
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR3) == 0
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR4) == 0
- || strcasecmp (str, IPMI_PARSE_DEVICE_LAN_2_0_STR5) == 0)
- return (IPMI_MONITORING_PROTOCOL_VERSION_2_0);
-
- return (-1);
-}
-
-// FROM: common/parsecommon/parse-common.c
-// changed the return values to match ipmi_monitoring.h
-static int netdata_parse_inband_driver_type (const char *str) {
- if (strcasecmp (str, IPMI_PARSE_DEVICE_KCS_STR) == 0)
- return (IPMI_MONITORING_DRIVER_TYPE_KCS);
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_SSIF_STR) == 0)
- return (IPMI_MONITORING_DRIVER_TYPE_SSIF);
- /* support "open" for those that might be used to
- * ipmitool.
- */
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_OPENIPMI_STR) == 0
- || strcasecmp (str, IPMI_PARSE_DEVICE_OPENIPMI_STR2) == 0)
- return (IPMI_MONITORING_DRIVER_TYPE_OPENIPMI);
- /* support "bmc" for those that might be used to
- * ipmitool.
- */
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_SUNBMC_STR) == 0
- || strcasecmp (str, IPMI_PARSE_DEVICE_SUNBMC_STR2) == 0)
- return (IPMI_MONITORING_DRIVER_TYPE_SUNBMC);
-
-#ifdef IPMI_MONITORING_DRIVER_TYPE_INTELDCMI
- else if (strcasecmp (str, IPMI_PARSE_DEVICE_INTELDCMI_STR) == 0)
- return (IPMI_MONITORING_DRIVER_TYPE_INTELDCMI);
-#endif // IPMI_MONITORING_DRIVER_TYPE_INTELDCMI
-
- return (-1);
-}
-
-// ----------------------------------------------------------------------------
-// BEGIN NETDATA CODE
-
-typedef enum __attribute__((packed)) {
- IPMI_COLLECT_TYPE_SENSORS = (1 << 0),
- IPMI_COLLECT_TYPE_SEL = (1 << 1),
-} IPMI_COLLECTION_TYPE;
-
-struct sensor {
- int sensor_type;
- int sensor_state;
- int sensor_units;
- char *sensor_name;
-
- int sensor_reading_type;
- union {
- uint8_t bool_value;
- uint32_t uint32_value;
- double double_value;
- } sensor_reading;
-
- // netdata provided
- const char *context;
- const char *title;
- const char *units;
- const char *family;
- const char *chart_type;
- const char *dimension;
- int priority;
-
- const char *type;
- const char *component;
-
- int multiplier;
- bool do_metric;
- bool do_state;
- bool metric_chart_sent;
- bool state_chart_sent;
- usec_t last_collected_metric_ut;
- usec_t last_collected_state_ut;
-};
-
-typedef enum __attribute__((packed)) {
- ICS_INIT,
- ICS_INIT_FAILED,
- ICS_RUNNING,
- ICS_FAILED,
-} IPMI_COLLECTOR_STATUS;
-
-struct netdata_ipmi_state {
- bool debug;
-
- struct {
- IPMI_COLLECTOR_STATUS status;
- usec_t last_iteration_ut;
- size_t collected;
- usec_t now_ut;
- usec_t freq_ut;
- int priority;
- DICTIONARY *dict;
- } sensors;
-
- struct {
- IPMI_COLLECTOR_STATUS status;
- usec_t last_iteration_ut;
- size_t events;
- usec_t now_ut;
- usec_t freq_ut;
- int priority;
- } sel;
-
- struct {
- usec_t now_ut;
- } updates;
-};
-
-struct netdata_ipmi_state state = {0};
-
-// ----------------------------------------------------------------------------
-// excluded record ids maintenance (both for sensor data and state)
-
-static int *excluded_record_ids = NULL;
-size_t excluded_record_ids_length = 0;
-
-static void excluded_record_ids_parse(const char *s, bool debug) {
- if(!s) return;
-
- while(*s) {
- while(*s && !isdigit(*s)) s++;
-
- if(isdigit(*s)) {
- char *e;
- unsigned long n = strtoul(s, &e, 10);
- s = e;
-
- if(n != 0) {
- excluded_record_ids = reallocz(excluded_record_ids, (excluded_record_ids_length + 1) * sizeof(int));
- excluded_record_ids[excluded_record_ids_length++] = (int)n;
- }
- }
- }
-
- if(debug) {
- fprintf(stderr, "%s: excluded record ids:", program_name);
- size_t i;
- for(i = 0; i < excluded_record_ids_length; i++) {
- fprintf(stderr, " %d", excluded_record_ids[i]);
- }
- fprintf(stderr, "\n");
- }
-}
-
-static int *excluded_status_record_ids = NULL;
-size_t excluded_status_record_ids_length = 0;
-
-static void excluded_status_record_ids_parse(const char *s, bool debug) {
- if(!s) return;
-
- while(*s) {
- while(*s && !isdigit(*s)) s++;
-
- if(isdigit(*s)) {
- char *e;
- unsigned long n = strtoul(s, &e, 10);
- s = e;
-
- if(n != 0) {
- excluded_status_record_ids = reallocz(excluded_status_record_ids, (excluded_status_record_ids_length + 1) * sizeof(int));
- excluded_status_record_ids[excluded_status_record_ids_length++] = (int)n;
- }
- }
- }
-
- if(debug) {
- fprintf(stderr, "%s: excluded status record ids:", program_name);
- size_t i;
- for(i = 0; i < excluded_status_record_ids_length; i++) {
- fprintf(stderr, " %d", excluded_status_record_ids[i]);
- }
- fprintf(stderr, "\n");
- }
-}
-
-
-static int excluded_record_ids_check(int record_id) {
- size_t i;
-
- for(i = 0; i < excluded_record_ids_length; i++) {
- if(excluded_record_ids[i] == record_id)
- return 1;
- }
-
- return 0;
-}
-
-static int excluded_status_record_ids_check(int record_id) {
- size_t i;
-
- for(i = 0; i < excluded_status_record_ids_length; i++) {
- if(excluded_status_record_ids[i] == record_id)
- return 1;
- }
-
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-// data collection functions
-
-struct {
- const char *search;
- SIMPLE_PATTERN *pattern;
- const char *label;
-} sensors_component_patterns[] = {
-
- // The order is important!
- // They are evaluated top to bottom
- // The first the matches is used
-
- {
- .search = "*DIMM*|*_DIM*|*VTT*|*VDDQ*|*ECC*|*MEM*CRC*|*MEM*BD*",
- .label = NETDATA_SENSOR_COMPONENT_MEMORY_MODULE,
- },
- {
- .search = "*CPU*|SOC_*|*VDDCR*|P*_VDD*|*_DTS|*VCORE*|*PROC*",
- .label = NETDATA_SENSOR_COMPONENT_PROCESSOR,
- },
- {
- .search = "IPU*",
- .label = NETDATA_SENSOR_COMPONENT_IPU,
- },
- {
- .search = "M2_*|*SSD*|*HSC*|*HDD*|*NVME*",
- .label = NETDATA_SENSOR_COMPONENT_STORAGE,
- },
- {
- .search = "MB_*|*PCH*|*VBAT*|*I/O*BD*|*IO*BD*",
- .label = NETDATA_SENSOR_COMPONENT_MOTHERBOARD,
- },
- {
- .search = "Watchdog|SEL|SYS_*|*CHASSIS*",
- .label = NETDATA_SENSOR_COMPONENT_SYSTEM,
- },
- {
- .search = "PS*|P_*|*PSU*|*PWR*|*TERMV*|*D2D*",
- .label = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY,
- },
-
- // fallback components
- {
- .search = "VR_P*|*VRMP*",
- .label = NETDATA_SENSOR_COMPONENT_PROCESSOR,
- },
- {
- .search = "*VSB*|*PS*",
- .label = NETDATA_SENSOR_COMPONENT_POWER_SUPPLY,
- },
- {
- .search = "*MEM*|*MEM*RAID*",
- .label = NETDATA_SENSOR_COMPONENT_MEMORY,
- },
- {
- .search = "*RAID*", // there is also "Memory RAID", so keep this after memory
- .label = NETDATA_SENSOR_COMPONENT_STORAGE,
- },
- {
- .search = "*PERIPHERAL*|*USB*",
- .label = NETDATA_SENSOR_COMPONENT_PERIPHERAL,
- },
- {
- .search = "*FAN*|*12V*|*VCC*|*PCI*|*CHIPSET*|*AMP*|*BD*",
- .label = NETDATA_SENSOR_COMPONENT_SYSTEM,
- },
-
- // terminator
- {
- .search = NULL,
- .label = NULL,
- }
-};
-
-static const char *netdata_sensor_name_to_component(const char *sensor_name) {
- for(int i = 0; sensors_component_patterns[i].search ;i++) {
- if(!sensors_component_patterns[i].pattern)
- sensors_component_patterns[i].pattern = simple_pattern_create(sensors_component_patterns[i].search, "|", SIMPLE_PATTERN_EXACT, false);
-
- if(simple_pattern_matches(sensors_component_patterns[i].pattern, sensor_name))
- return sensors_component_patterns[i].label;
- }
-
- return "Other";
-}
-
-const char *netdata_collect_type_to_string(IPMI_COLLECTION_TYPE type) {
- if((type & (IPMI_COLLECT_TYPE_SENSORS|IPMI_COLLECT_TYPE_SEL)) == (IPMI_COLLECT_TYPE_SENSORS|IPMI_COLLECT_TYPE_SEL))
- return "sensors,sel";
- if(type & IPMI_COLLECT_TYPE_SEL)
- return "sel";
- if(type & IPMI_COLLECT_TYPE_SENSORS)
- return "sensors";
-
- return "unknown";
-}
-
-static void netdata_sensor_set_value(struct sensor *sn, void *sensor_reading, struct netdata_ipmi_state *state __maybe_unused) {
- switch(sn->sensor_reading_type) {
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
- sn->sensor_reading.bool_value = *((uint8_t *)sensor_reading);
- break;
-
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
- sn->sensor_reading.uint32_value = *((uint32_t *)sensor_reading);
- break;
-
- case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
- sn->sensor_reading.double_value = *((double *)sensor_reading);
- break;
-
- default:
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNKNOWN:
- sn->do_metric = false;
- break;
- }
-}
-
-static void netdata_update_ipmi_sensor_reading(
- int record_id
- , int sensor_number
- , int sensor_type
- , int sensor_state
- , int sensor_units
- , int sensor_reading_type
- , char *sensor_name
- , void *sensor_reading
- , int event_reading_type_code __maybe_unused
- , int sensor_bitmask_type __maybe_unused
- , int sensor_bitmask __maybe_unused
- , char **sensor_bitmask_strings __maybe_unused
- , struct netdata_ipmi_state *state
-) {
- if(unlikely(sensor_state == IPMI_MONITORING_STATE_UNKNOWN &&
- sensor_type == IPMI_MONITORING_SENSOR_TYPE_UNKNOWN &&
- sensor_units == IPMI_MONITORING_SENSOR_UNITS_UNKNOWN &&
- sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNKNOWN &&
- (!sensor_name || !*sensor_name)))
- // we can't do anything about this sensor - everything is unknown
- return;
-
- if(unlikely(!sensor_name || !*sensor_name))
- sensor_name = "UNNAMED";
-
- state->sensors.collected++;
-
- char key[SENSORS_DICT_KEY_SIZE + 1];
- snprintfz(key, SENSORS_DICT_KEY_SIZE, "i%d_n%d_t%d_u%d_%s",
- record_id, sensor_number, sensor_reading_type, sensor_units, sensor_name);
-
- // find the sensor record
- const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(state->sensors.dict, key);
- if(likely(item)) {
- // recurring collection
-
- if(state->debug)
- fprintf(stderr, "%s: reusing sensor record for sensor '%s', id %d, number %d, type %d, state %d, units %d, reading_type %d\n",
- program_name, sensor_name, record_id, sensor_number, sensor_type, sensor_state, sensor_units, sensor_reading_type);
-
- struct sensor *sn = dictionary_acquired_item_value(item);
-
- if(sensor_reading) {
- netdata_sensor_set_value(sn, sensor_reading, state);
- sn->last_collected_metric_ut = state->sensors.now_ut;
- }
-
- sn->sensor_state = sensor_state;
-
- sn->last_collected_state_ut = state->sensors.now_ut;
-
- dictionary_acquired_item_release(state->sensors.dict, item);
-
- return;
- }
-
- if(state->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);
-
- // check if it is excluded
- bool excluded_metric = excluded_record_ids_check(record_id);
- bool excluded_state = excluded_status_record_ids_check(record_id);
-
- if(excluded_metric) {
- if(state->debug)
- fprintf(stderr, "Sensor '%s' is excluded by excluded_record_ids_check()\n", sensor_name);
- }
-
- if(excluded_state) {
- if(state->debug)
- fprintf(stderr, "Sensor '%s' is excluded for status check, by excluded_status_record_ids_check()\n", sensor_name);
- }
-
- struct sensor t = {
- .sensor_type = sensor_type,
- .sensor_state = sensor_state,
- .sensor_units = sensor_units,
- .sensor_reading_type = sensor_reading_type,
- .sensor_name = strdupz(sensor_name),
- .component = netdata_sensor_name_to_component(sensor_name),
- .do_state = !excluded_state,
- .do_metric = !excluded_metric,
- };
-
- t.type = netdata_ipmi_get_sensor_type_string(t.sensor_type, &t.component);
-
- switch(t.sensor_units) {
- case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
- t.dimension = "temperature";
- t.context = "ipmi.sensor_temperature_c";
- t.title = "IPMI Sensor Temperature Celsius";
- t.units = "Celsius";
- t.family = "temperatures";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 10;
- break;
-
- case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
- t.dimension = "temperature";
- t.context = "ipmi.sensor_temperature_f";
- t.title = "IPMI Sensor Temperature Fahrenheit";
- t.units = "Fahrenheit";
- t.family = "temperatures";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 20;
- break;
-
- case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
- t.dimension = "voltage";
- t.context = "ipmi.sensor_voltage";
- t.title = "IPMI Sensor Voltage";
- t.units = "Volts";
- t.family = "voltages";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 30;
- break;
-
- case IPMI_MONITORING_SENSOR_UNITS_AMPS:
- t.dimension = "ampere";
- t.context = "ipmi.sensor_ampere";
- t.title = "IPMI Sensor Current";
- t.units = "Amps";
- t.family = "current";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 40;
- break;
-
- case IPMI_MONITORING_SENSOR_UNITS_RPM:
- t.dimension = "rotations";
- t.context = "ipmi.sensor_fan_speed";
- t.title = "IPMI Sensor Fans Speed";
- t.units = "RPM";
- t.family = "fans";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 50;
- break;
-
- case IPMI_MONITORING_SENSOR_UNITS_WATTS:
- t.dimension = "power";
- t.context = "ipmi.sensor_power";
- t.title = "IPMI Sensor Power";
- t.units = "Watts";
- t.family = "power";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 60;
- break;
-
- case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
- t.dimension = "percentage";
- t.context = "ipmi.sensor_reading_percent";
- t.title = "IPMI Sensor Reading Percentage";
- t.units = "%%";
- t.family = "other";
- t.chart_type = "line";
- t.priority = state->sensors.priority + 70;
- break;
-
- default:
- t.priority = state->sensors.priority + 80;
- t.do_metric = false;
- break;
- }
-
- switch(sensor_reading_type) {
- case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
- t.multiplier = 1000;
- break;
-
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
- t.multiplier = 1;
- break;
-
- default:
- t.do_metric = false;
- break;
- }
-
- if(sensor_reading) {
- netdata_sensor_set_value(&t, sensor_reading, state);
- t.last_collected_metric_ut = state->sensors.now_ut;
- }
- t.last_collected_state_ut = state->sensors.now_ut;
-
- dictionary_set(state->sensors.dict, key, &t, sizeof(t));
-}
-
-static void netdata_update_ipmi_sel_events_count(struct netdata_ipmi_state *state, uint32_t events) {
- state->sel.events = events;
-}
-
-int netdata_ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config, IPMI_COLLECTION_TYPE type, struct netdata_ipmi_state *state) {
- errno = 0;
-
- if(type & IPMI_COLLECT_TYPE_SENSORS) {
- state->sensors.collected = 0;
- state->sensors.now_ut = now_monotonic_usec();
-
- if (netdata_read_ipmi_sensors(ipmi_config, state) < 0) return -1;
- }
-
- if(type & IPMI_COLLECT_TYPE_SEL) {
- state->sel.events = 0;
- state->sel.now_ut = now_monotonic_usec();
- if(netdata_get_ipmi_sel_events_count(ipmi_config, state) < 0) return -2;
- }
-
- return 0;
-}
-
-int netdata_ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config, IPMI_COLLECTION_TYPE type, struct netdata_ipmi_state *state) {
- int i, checks = SPEED_TEST_ITERATIONS, successful = 0;
- usec_t total = 0;
-
- for(i = 0 ; i < checks ; i++) {
- if(unlikely(state->debug))
- fprintf(stderr, "%s: checking %s data collection speed iteration %d of %d\n",
- program_name, netdata_collect_type_to_string(type), i + 1, checks);
-
- // measure the time a data collection needs
- usec_t start = now_realtime_usec();
-
- if(netdata_ipmi_collect_data(ipmi_config, type, state) < 0)
- continue;
-
- usec_t end = now_realtime_usec();
-
- successful++;
-
- if(unlikely(state->debug))
- fprintf(stderr, "%s: %s data collection speed was %"PRIu64" usec\n",
- program_name, netdata_collect_type_to_string(type), end - start);
-
- // add it to our total
- total += end - start;
-
- // wait the same time
- // to avoid flooding the IPMI processor with requests
- sleep_usec(end - start);
- }
-
- if(!successful)
- return 0;
-
- // so, we assume it needed 2x the time
- // we find the average in microseconds
- // and we round-up to the closest second
-
- return (int)(( total * 2 / successful / USEC_PER_SEC ) + 1);
-}
-
-// ----------------------------------------------------------------------------
-// data collection threads
-
-struct ipmi_collection_thread {
- struct ipmi_monitoring_ipmi_config ipmi_config;
- int freq_s;
- bool debug;
- IPMI_COLLECTION_TYPE type;
- SPINLOCK spinlock;
- struct netdata_ipmi_state state;
-};
-
-void *netdata_ipmi_collection_thread(void *ptr) {
- struct ipmi_collection_thread *t = ptr;
-
- if(t->debug) fprintf(stderr, "%s: calling initialize_ipmi_config() for %s\n",
- program_name, netdata_collect_type_to_string(t->type));
-
- initialize_ipmi_config(&t->ipmi_config);
-
- if(t->debug) fprintf(stderr, "%s: detecting IPMI minimum update frequency for %s...\n",
- program_name, netdata_collect_type_to_string(t->type));
-
- int freq_s = netdata_ipmi_detect_speed_secs(&t->ipmi_config, t->type, &t->state);
- if(!freq_s) {
- if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
- t->state.sensors.status = ICS_INIT_FAILED;
- t->state.sensors.last_iteration_ut = 0;
- }
-
- if(t->type & IPMI_COLLECT_TYPE_SEL) {
- t->state.sel.status = ICS_INIT_FAILED;
- t->state.sel.last_iteration_ut = 0;
- }
-
- return ptr;
- }
- else {
- if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
- t->state.sensors.status = ICS_RUNNING;
- }
-
- if(t->type & IPMI_COLLECT_TYPE_SEL) {
- t->state.sel.status = ICS_RUNNING;
- }
- }
-
- t->freq_s = freq_s = MAX(t->freq_s, freq_s);
-
- if(t->debug) {
- fprintf(stderr, "%s: IPMI minimum update frequency of %s was calculated to %d seconds.\n",
- program_name, netdata_collect_type_to_string(t->type), t->freq_s);
-
- fprintf(stderr, "%s: starting data collection of %s\n",
- program_name, netdata_collect_type_to_string(t->type));
- }
-
- size_t iteration = 0, failures = 0;
- usec_t step = t->freq_s * USEC_PER_SEC;
-
- heartbeat_t hb;
- heartbeat_init(&hb);
- while(++iteration) {
- heartbeat_next(&hb, step);
-
- if(t->debug)
- fprintf(stderr, "%s: calling netdata_ipmi_collect_data() for %s\n",
- program_name, netdata_collect_type_to_string(t->type));
-
- struct netdata_ipmi_state tmp_state = t->state;
-
- if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
- tmp_state.sensors.last_iteration_ut = now_monotonic_usec();
- tmp_state.sensors.freq_ut = t->freq_s * USEC_PER_SEC;
- }
-
- if(t->type & IPMI_COLLECT_TYPE_SEL) {
- tmp_state.sel.last_iteration_ut = now_monotonic_usec();
- tmp_state.sel.freq_ut = t->freq_s * USEC_PER_SEC;
- }
-
- if(netdata_ipmi_collect_data(&t->ipmi_config, t->type, &tmp_state) != 0)
- failures++;
- else
- failures = 0;
-
- if(failures > 10) {
- collector_error("%s() failed to collect %s data for %zu consecutive times, having made %zu iterations.",
- __FUNCTION__, netdata_collect_type_to_string(t->type), failures, iteration);
-
- if(t->type & IPMI_COLLECT_TYPE_SENSORS) {
- t->state.sensors.status = ICS_FAILED;
- t->state.sensors.last_iteration_ut = 0;
- }
-
- if(t->type & IPMI_COLLECT_TYPE_SEL) {
- t->state.sel.status = ICS_FAILED;
- t->state.sel.last_iteration_ut = 0;
- }
-
- break;
- }
-
- spinlock_lock(&t->spinlock);
- t->state = tmp_state;
- spinlock_unlock(&t->spinlock);
- }
-
- return ptr;
-}
-
-// ----------------------------------------------------------------------------
-// sending data to netdata
-
-static inline bool is_sensor_updated(usec_t last_collected_ut, usec_t now_ut, usec_t freq) {
- return (now_ut - last_collected_ut < freq * 2) ? true : false;
-}
-
-static size_t send_ipmi_sensor_metrics_to_netdata(struct netdata_ipmi_state *state) {
- if(state->sensors.status != ICS_RUNNING) {
- if(unlikely(state->debug))
- fprintf(stderr, "%s: %s() sensors state is not RUNNING\n",
- program_name, __FUNCTION__ );
- return 0;
- }
-
- size_t total_sensors_sent = 0;
- int update_every = (int)(state->sensors.freq_ut / USEC_PER_SEC);
- struct sensor *sn;
-
- netdata_mutex_lock(&stdout_mutex);
- // generate the CHART/DIMENSION lines, if we have to
- dfe_start_reentrant(state->sensors.dict, sn) {
- if(unlikely(!sn->do_metric && !sn->do_state))
- continue;
-
- bool did_metric = false, did_state = false;
-
- if(likely(sn->do_metric)) {
- if(unlikely(!is_sensor_updated(sn->last_collected_metric_ut, state->updates.now_ut, state->sensors.freq_ut))) {
- if(unlikely(state->debug))
- fprintf(stderr, "%s: %s() sensor '%s' metric is not UPDATED (last updated %"PRIu64", now %"PRIu64", freq %"PRIu64"\n",
- program_name, __FUNCTION__, sn->sensor_name, sn->last_collected_metric_ut, state->updates.now_ut, state->sensors.freq_ut);
- }
- else {
- if (unlikely(!sn->metric_chart_sent)) {
- sn->metric_chart_sent = true;
-
- printf("CHART '%s_%s' '' '%s' '%s' '%s' '%s' '%s' %d %d '' '%s' '%s'\n",
- sn->context, sn_dfe.name, sn->title, sn->units, sn->family, sn->context,
- sn->chart_type, sn->priority + 1, update_every, program_name, "sensors");
-
- printf("CLABEL 'sensor' '%s' 1\n", sn->sensor_name);
- printf("CLABEL 'type' '%s' 1\n", sn->type);
- printf("CLABEL 'component' '%s' 1\n", sn->component);
- printf("CLABEL_COMMIT\n");
-
- printf("DIMENSION '%s' '' absolute 1 %d\n", sn->dimension, sn->multiplier);
- }
-
- printf("BEGIN '%s_%s'\n", sn->context, sn_dfe.name);
-
- switch (sn->sensor_reading_type) {
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
- printf("SET '%s' = %u\n", sn->dimension, sn->sensor_reading.uint32_value
- );
- break;
-
- case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
- printf("SET '%s' = %lld\n", sn->dimension,
- (long long int) (sn->sensor_reading.double_value * sn->multiplier)
- );
- break;
-
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
- printf("SET '%s' = %u\n", sn->dimension, sn->sensor_reading.bool_value
- );
- break;
-
- default:
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNKNOWN:
- // this should never happen because we also do the same check at netdata_get_sensor()
- sn->do_metric = false;
- break;
- }
-
- printf("END\n");
- did_metric = true;
- }
- }
-
- if(likely(sn->do_state)) {
- if(unlikely(!is_sensor_updated(sn->last_collected_state_ut, state->updates.now_ut, state->sensors.freq_ut))) {
- if (unlikely(state->debug))
- fprintf(stderr, "%s: %s() sensor '%s' state is not UPDATED (last updated %"PRIu64", now %"PRIu64", freq %"PRIu64"\n",
- program_name, __FUNCTION__, sn->sensor_name, sn->last_collected_state_ut, state->updates.now_ut, state->sensors.freq_ut);
- }
- else {
- if (unlikely(!sn->state_chart_sent)) {
- sn->state_chart_sent = true;
-
- printf("CHART 'ipmi.sensor_state_%s' '' 'IPMI Sensor State' 'state' 'states' 'ipmi.sensor_state' 'line' %d %d '' '%s' '%s'\n",
- sn_dfe.name, sn->priority, update_every, program_name, "sensors");
-
- printf("CLABEL 'sensor' '%s' 1\n", sn->sensor_name);
- printf("CLABEL 'type' '%s' 1\n", sn->type);
- printf("CLABEL 'component' '%s' 1\n", sn->component);
- printf("CLABEL_COMMIT\n");
-
- printf("DIMENSION 'nominal' '' absolute 1 1\n");
- printf("DIMENSION 'warning' '' absolute 1 1\n");
- printf("DIMENSION 'critical' '' absolute 1 1\n");
- printf("DIMENSION 'unknown' '' absolute 1 1\n");
- }
-
- printf("BEGIN 'ipmi.sensor_state_%s'\n", sn_dfe.name);
- printf("SET 'nominal' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_NOMINAL ? 1LL : 0LL);
- printf("SET 'warning' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_WARNING ? 1LL : 0LL);
- printf("SET 'critical' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_CRITICAL ? 1LL : 0LL);
- printf("SET 'unknown' = %lld\n", sn->sensor_state == IPMI_MONITORING_STATE_UNKNOWN ? 1LL : 0LL);
- printf("END\n");
- did_state = true;
- }
- }
-
- if(likely(did_metric || did_state))
- total_sensors_sent++;
- }
- dfe_done(sn);
-
- netdata_mutex_unlock(&stdout_mutex);
-
- return total_sensors_sent;
-}
-
-static size_t send_ipmi_sel_metrics_to_netdata(struct netdata_ipmi_state *state) {
- static bool sel_chart_generated = false;
-
- netdata_mutex_lock(&stdout_mutex);
-
- if(likely(state->sel.status == ICS_RUNNING)) {
- if(unlikely(!sel_chart_generated)) {
- sel_chart_generated = true;
- printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' ipmi.sel area %d %d '' '%s' '%s'\n"
- , state->sel.priority + 2
- , (int)(state->sel.freq_ut / USEC_PER_SEC)
- , program_name
- , "sel"
- );
- printf("DIMENSION events '' absolute 1 1\n");
- }
-
- printf(
- "BEGIN ipmi.events\n"
- "SET events = %zu\n"
- "END\n"
- , state->sel.events
- );
- }
-
- netdata_mutex_unlock(&stdout_mutex);
-
- return state->sel.events;
-}
-
-// ----------------------------------------------------------------------------
-
-static const char *get_sensor_state_string(struct sensor *sn) {
- switch (sn->sensor_state) {
- case IPMI_MONITORING_STATE_NOMINAL:
- return "nominal";
- case IPMI_MONITORING_STATE_WARNING:
- return "warning";
- case IPMI_MONITORING_STATE_CRITICAL:
- return "critical";
- default:
- return "unknown";
- }
-}
-
-static const char *get_sensor_function_priority(struct sensor *sn) {
- switch (sn->sensor_state) {
- case IPMI_MONITORING_STATE_WARNING:
- return "warning";
- case IPMI_MONITORING_STATE_CRITICAL:
- return "critical";
- default:
- return "normal";
- }
-}
-
-static void freeimi_function_sensors(const char *transaction, char *function __maybe_unused, int timeout __maybe_unused, bool *cancelled __maybe_unused) {
- time_t expires = now_realtime_sec() + update_every;
-
- BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
- buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
- buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
- buffer_json_member_add_string(wb, "type", "table");
- buffer_json_member_add_time_t(wb, "update_every", update_every);
- buffer_json_member_add_string(wb, "help", "View IPMI sensor readings and its state");
- buffer_json_member_add_array(wb, "data");
-
- struct sensor *sn;
- dfe_start_reentrant(state.sensors.dict, sn) {
- if (unlikely(!sn->do_metric && !sn->do_state))
- continue;
-
- double reading = NAN;
- switch (sn->sensor_reading_type) {
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
- reading = (double)sn->sensor_reading.uint32_value;
- break;
- case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
- reading = (double)(sn->sensor_reading.double_value);
- break;
- case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
- reading = (double)sn->sensor_reading.bool_value;
- break;
- }
-
- buffer_json_add_array_item_array(wb);
-
- buffer_json_add_array_item_string(wb, sn->sensor_name);
- buffer_json_add_array_item_string(wb, sn->type);
- buffer_json_add_array_item_string(wb, sn->component);
- buffer_json_add_array_item_double(wb, reading);
- buffer_json_add_array_item_string(wb, sn->units);
- buffer_json_add_array_item_string(wb, get_sensor_state_string(sn));
-
- buffer_json_add_array_item_object(wb);
- buffer_json_member_add_string(wb, "severity", get_sensor_function_priority(sn));
- buffer_json_object_close(wb);
-
- buffer_json_array_close(wb);
- }
- dfe_done(sn);
-
- buffer_json_array_close(wb); // data
- buffer_json_member_add_object(wb, "columns");
- {
- size_t field_id = 0;
-
- buffer_rrdf_table_add_field(wb, field_id++, "Sensor", "Sensor Name",
- RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
- 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
- RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
- RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
- NULL);
- buffer_rrdf_table_add_field(wb, field_id++, "Type", "Sensor Type",
- RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
- 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
- RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
- RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
- NULL);
- buffer_rrdf_table_add_field(wb, field_id++, "Component", "Sensor Component",
- RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
- 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
- RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
- RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
- NULL);
- buffer_rrdf_table_add_field(wb, field_id++, "Reading", "Sensor Current Reading",
- RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
- 2, NULL, 0, RRDF_FIELD_SORT_DESCENDING, NULL,
- RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
- RRDF_FIELD_OPTS_VISIBLE,
- NULL);
- buffer_rrdf_table_add_field(wb, field_id++, "Units", "Sensor Reading Units",
- RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
- 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
- RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
- RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
- NULL);
- buffer_rrdf_table_add_field(wb, field_id++, "State", "Sensor State",
- RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
- 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
- RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
- RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
- NULL);
- buffer_rrdf_table_add_field(
- wb, field_id++,
- "rowOptions", "rowOptions",
- RRDF_FIELD_TYPE_NONE,
- RRDR_FIELD_VISUAL_ROW_OPTIONS,
- RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
- RRDF_FIELD_SORT_FIXED,
- NULL,
- RRDF_FIELD_SUMMARY_COUNT,
- RRDF_FIELD_FILTER_NONE,
- RRDF_FIELD_OPTS_DUMMY,
- NULL);
- }
-
- buffer_json_object_close(wb); // columns
- buffer_json_member_add_string(wb, "default_sort_column", "Type");
-
- buffer_json_member_add_object(wb, "charts");
- {
- buffer_json_member_add_object(wb, "Sensors");
- {
- buffer_json_member_add_string(wb, "name", "Sensors");
- buffer_json_member_add_string(wb, "type", "stacked-bar");
- buffer_json_member_add_array(wb, "columns");
- {
- buffer_json_add_array_item_string(wb, "Sensor");
- }
- buffer_json_array_close(wb);
- }
- buffer_json_object_close(wb);
- }
- buffer_json_object_close(wb); // charts
-
- buffer_json_member_add_array(wb, "default_charts");
- {
- buffer_json_add_array_item_array(wb);
- buffer_json_add_array_item_string(wb, "Sensors");
- buffer_json_add_array_item_string(wb, "Component");
- buffer_json_array_close(wb);
-
- buffer_json_add_array_item_array(wb);
- buffer_json_add_array_item_string(wb, "Sensors");
- buffer_json_add_array_item_string(wb, "State");
- buffer_json_array_close(wb);
- }
- buffer_json_array_close(wb);
-
- buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
- buffer_json_finalize(wb);
-
- pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires, wb);
-
- buffer_free(wb);
-}
-
-// ----------------------------------------------------------------------------
-// main, command line arguments parsing
-
-static void plugin_exit(int code) {
- fflush(stdout);
- function_plugin_should_exit = true;
- exit(code);
-}
-
-int main (int argc, char **argv) {
- clocks_init();
- nd_log_initialize_for_external_plugins("freeipmi.plugin");
- netdata_threads_init_for_external_plugins(0); // set the default threads stack size here
-
- bool netdata_do_sel = IPMI_ENABLE_SEL_BY_DEFAULT;
-
- bool debug = false;
-
- // ------------------------------------------------------------------------
- // parse command line parameters
-
- int i, freq_s = 0;
- for(i = 1; i < argc ; i++) {
- if(isdigit(*argv[i]) && !freq_s) {
- int n = str2i(argv[i]);
- if(n > 0 && n < 86400) {
- freq_s = n;
- continue;
- }
- }
- 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) {
- printf("%s %s\n", program_name, VERSION);
- exit(0);
- }
- else if(strcmp("debug", argv[i]) == 0) {
- debug = true;
- continue;
- }
- else if(strcmp("sel", argv[i]) == 0) {
- netdata_do_sel = true;
- continue;
- }
- else if(strcmp("no-sel", argv[i]) == 0) {
- netdata_do_sel = false;
- continue;
- }
- else if(strcmp("reread-sdr-cache", argv[i]) == 0) {
- global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
- remove_reread_sdr_after_first_use = false;
- if (debug) fprintf(stderr, "%s: reread-sdr-cache enabled for both sensors and SEL\n", program_name);
- }
- else if(strcmp("interpret-oem-data", argv[i]) == 0) {
- global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_INTERPRET_OEM_DATA;
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_INTERPRET_OEM_DATA;
- if (debug) fprintf(stderr, "%s: interpret-oem-data enabled for both sensors and SEL\n", program_name);
- }
- else if(strcmp("assume-system-event-record", argv[i]) == 0) {
- global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_ASSUME_SYSTEM_EVENT_RECORD;
- if (debug) fprintf(stderr, "%s: assume-system-event-record enabled\n", program_name);
- }
- else if(strcmp("ignore-non-interpretable-sensors", argv[i]) == 0) {
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
- if (debug) fprintf(stderr, "%s: ignore-non-interpretable-sensors enabled\n", program_name);
- }
- else if(strcmp("bridge-sensors", argv[i]) == 0) {
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_BRIDGE_SENSORS;
- if (debug) fprintf(stderr, "%s: bridge-sensors enabled\n", program_name);
- }
- else if(strcmp("shared-sensors", argv[i]) == 0) {
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_SHARED_SENSORS;
- if (debug) fprintf(stderr, "%s: shared-sensors enabled\n", program_name);
- }
- else if(strcmp("no-discrete-reading", argv[i]) == 0) {
- global_sensor_reading_flags &= ~(IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING);
- if (debug) fprintf(stderr, "%s: discrete-reading disabled\n", program_name);
- }
- else if(strcmp("ignore-scanning-disabled", argv[i]) == 0) {
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_SCANNING_DISABLED;
- if (debug) fprintf(stderr, "%s: ignore-scanning-disabled enabled\n", program_name);
- }
- else if(strcmp("assume-bmc-owner", argv[i]) == 0) {
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ASSUME_BMC_OWNER;
- if (debug) fprintf(stderr, "%s: assume-bmc-owner enabled\n", program_name);
- }
-#if defined(IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES) && defined(IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES)
- else if(strcmp("entity-sensor-names", argv[i]) == 0) {
- global_sel_flags |= IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES;
- global_sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES;
- if (debug) fprintf(stderr, "%s: entity-sensor-names enabled for both sensors and SEL\n", program_name);
- }
-#endif
- else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
- fprintf(stderr,
- "\n"
- " netdata %s %s\n"
- " Copyright (C) 2023 Netdata Inc.\n"
- " Released under GNU General Public License v3 or later.\n"
- " All rights reserved.\n"
- "\n"
- " This program is a data collector plugin for netdata.\n"
- "\n"
- " Available command line options:\n"
- "\n"
- " SECONDS data collection frequency\n"
- " minimum: %d\n"
- "\n"
- " debug enable verbose output\n"
- " default: disabled\n"
- "\n"
- " sel\n"
- " no-sel enable/disable SEL collection\n"
- " default: %s\n"
- "\n"
- " reread-sdr-cache re-read SDR cache on every iteration\n"
- " default: disabled\n"
- "\n"
- " interpret-oem-data attempt to parse OEM data\n"
- " default: disabled\n"
- "\n"
- " assume-system-event-record \n"
- " tread illegal SEL events records as normal\n"
- " default: disabled\n"
- "\n"
- " ignore-non-interpretable-sensors \n"
- " do not read sensors that cannot be interpreted\n"
- " default: disabled\n"
- "\n"
- " bridge-sensors bridge sensors not owned by the BMC\n"
- " default: disabled\n"
- "\n"
- " shared-sensors enable shared sensors, if found\n"
- " default: disabled\n"
- "\n"
- " no-discrete-reading do not read sensors that their event/reading type code is invalid\n"
- " default: enabled\n"
- "\n"
- " ignore-scanning-disabled \n"
- " Ignore the scanning bit and read sensors no matter what\n"
- " default: disabled\n"
- "\n"
- " assume-bmc-owner assume the BMC is the sensor owner no matter what\n"
- " (usually bridging is required too)\n"
- " default: disabled\n"
- "\n"
-#if defined(IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES) && defined(IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES)
- " entity-sensor-names sensor names prefixed with entity id and instance\n"
- " default: disabled\n"
- "\n"
-#endif
- " hostname HOST\n"
- " username USER\n"
- " password PASS connect to remote IPMI host\n"
- " default: local IPMI processor\n"
- "\n"
- " no-auth-code-check\n"
- " noauthcodecheck don't check the authentication codes returned\n"
- "\n"
- " driver-type IPMIDRIVER\n"
- " Specify the driver type to use instead of doing an auto selection. \n"
- " The currently available outofband drivers are LAN and LAN_2_0,\n"
- " which perform IPMI 1.5 and IPMI 2.0 respectively. \n"
- " The currently available inband drivers are KCS, SSIF, OPENIPMI and SUNBMC.\n"
- "\n"
- " sdr-cache-dir PATH directory for SDR cache files\n"
- " default: %s\n"
- "\n"
- " sensor-config-file FILE filename to read sensor configuration\n"
- " default: %s\n"
- "\n"
- " sel-config-file FILE filename to read sel configuration\n"
- " default: %s\n"
- "\n"
- " ignore N1,N2,N3,... sensor IDs to ignore\n"
- " default: none\n"
- "\n"
- " ignore-status N1,N2,N3,... sensor IDs to ignore status (nominal/warning/critical)\n"
- " default: none\n"
- "\n"
- " -v\n"
- " -V\n"
- " version print version and exit\n"
- "\n"
- " Linux kernel module for IPMI is CPU hungry.\n"
- " On Linux run this to lower kipmiN CPU utilization:\n"
- " # echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us\n"
- "\n"
- " or create: /etc/modprobe.d/ipmi.conf with these contents:\n"
- " options ipmi_si kipmid_max_busy_us=10\n"
- "\n"
- " For more information:\n"
- " https://github.com/netdata/netdata/tree/master/collectors/freeipmi.plugin\n"
- "\n"
- , program_name, VERSION
- , update_every
- , netdata_do_sel?"enabled":"disabled"
- , sdr_cache_directory?sdr_cache_directory:"system default"
- , sensor_config_file?sensor_config_file:"system default"
- , sel_config_file?sel_config_file:"system default"
- );
- exit(1);
- }
- else if(i < argc && strcmp("hostname", argv[i]) == 0) {
- hostname = strdupz(argv[++i]);
- char *s = argv[i];
- // mask it be hidden from the process tree
- while(*s) *s++ = 'x';
- if(debug) fprintf(stderr, "%s: hostname set to '%s'\n", program_name, hostname);
- continue;
- }
- else if(i < argc && strcmp("username", argv[i]) == 0) {
- username = strdupz(argv[++i]);
- char *s = argv[i];
- // mask it be hidden from the process tree
- while(*s) *s++ = 'x';
- if(debug) fprintf(stderr, "%s: username set to '%s'\n", program_name, username);
- continue;
- }
- else if(i < argc && strcmp("password", argv[i]) == 0) {
- password = strdupz(argv[++i]);
- char *s = argv[i];
- // mask it be hidden from the process tree
- while(*s) *s++ = 'x';
- if(debug) fprintf(stderr, "%s: password set to '%s'\n", program_name, password);
- continue;
- }
- else if(strcmp("driver-type", argv[i]) == 0) {
- if (hostname) {
- protocol_version = netdata_parse_outofband_driver_type(argv[++i]);
- if(debug) fprintf(stderr, "%s: outband protocol version set to '%d'\n",
- program_name, protocol_version);
- }
- else {
- driver_type = netdata_parse_inband_driver_type(argv[++i]);
- if(debug) fprintf(stderr, "%s: inband driver type set to '%d'\n",
- program_name, driver_type);
- }
- continue;
- } else if (i < argc && (strcmp("noauthcodecheck", argv[i]) == 0 || strcmp("no-auth-code-check", argv[i]) == 0)) {
- if (!hostname || netdata_host_is_localhost(hostname)) {
- if (debug)
- fprintf(stderr, "%s: noauthcodecheck workaround flag is ignored for inband configuration\n",
- program_name);
-
- }
- else if (protocol_version < 0 || protocol_version == IPMI_MONITORING_PROTOCOL_VERSION_1_5) {
- workaround_flags |= IPMI_MONITORING_WORKAROUND_FLAGS_PROTOCOL_VERSION_1_5_NO_AUTH_CODE_CHECK;
-
- if (debug)
- fprintf(stderr, "%s: noauthcodecheck workaround flag enabled\n", program_name);
- }
- else {
- if (debug)
- fprintf(stderr, "%s: noauthcodecheck workaround flag is ignored for protocol version 2.0\n",
- program_name);
- }
- continue;
- }
- else if(i < argc && strcmp("sdr-cache-dir", argv[i]) == 0) {
- sdr_cache_directory = argv[++i];
-
- if(debug)
- fprintf(stderr, "%s: SDR cache directory set to '%s'\n", program_name, sdr_cache_directory);
-
- continue;
- }
- else if(i < argc && strcmp("sensor-config-file", argv[i]) == 0) {
- sensor_config_file = argv[++i];
- if(debug) fprintf(stderr, "%s: sensor config file set to '%s'\n", program_name, sensor_config_file);
- continue;
- }
- else if(i < argc && strcmp("sel-config-file", argv[i]) == 0) {
- sel_config_file = argv[++i];
- if(debug) fprintf(stderr, "%s: sel config file set to '%s'\n", program_name, sel_config_file);
- continue;
- }
- else if(i < argc && strcmp("ignore", argv[i]) == 0) {
- excluded_record_ids_parse(argv[++i], debug);
- continue;
- }
- else if(i < argc && strcmp("ignore-status", argv[i]) == 0) {
- excluded_status_record_ids_parse(argv[++i], debug);
- continue;
- }
-
- collector_error("%s(): ignoring parameter '%s'", __FUNCTION__, argv[i]);
- }
-
- errno = 0;
-
- if(freq_s && freq_s < update_every)
- collector_info("%s(): update frequency %d seconds is too small for IPMI. Using %d.",
- __FUNCTION__, freq_s, update_every);
-
- update_every = freq_s = MAX(freq_s, update_every);
- update_every_sel = MAX(update_every, update_every_sel);
-
- // ------------------------------------------------------------------------
- // initialize IPMI
-
- if(debug) {
- fprintf(stderr, "%s: calling ipmi_monitoring_init()\n", program_name);
- ipmimonitoring_init_flags |= IPMI_MONITORING_FLAGS_DEBUG|IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS;
- }
-
- int rc;
- if(ipmi_monitoring_init(ipmimonitoring_init_flags, &rc) < 0)
- fatal("ipmi_monitoring_init: %s", ipmi_monitoring_ctx_strerror(rc));
-
- // ------------------------------------------------------------------------
- // create the data collection threads
-
- struct ipmi_collection_thread sensors_data = {
- .type = IPMI_COLLECT_TYPE_SENSORS,
- .freq_s = update_every,
- .spinlock = NETDATA_SPINLOCK_INITIALIZER,
- .debug = debug,
- .state = {
- .debug = debug,
- .sensors = {
- .status = ICS_INIT,
- .last_iteration_ut = now_monotonic_usec(),
- .freq_ut = update_every * USEC_PER_SEC,
- .priority = IPMI_SENSORS_DASHBOARD_PRIORITY,
- .dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE|DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct sensor)),
- },
- },
- }, sel_data = {
- .type = IPMI_COLLECT_TYPE_SEL,
- .freq_s = update_every_sel,
- .spinlock = NETDATA_SPINLOCK_INITIALIZER,
- .debug = debug,
- .state = {
- .debug = debug,
- .sel = {
- .status = ICS_INIT,
- .last_iteration_ut = now_monotonic_usec(),
- .freq_ut = update_every_sel * USEC_PER_SEC,
- .priority = IPMI_SEL_DASHBOARD_PRIORITY,
- },
- },
- };
-
- netdata_thread_t sensors_thread = 0, sel_thread = 0;
-
- netdata_thread_create(&sensors_thread, "IPMI[sensors]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sensors_data);
-
- if(netdata_do_sel)
- netdata_thread_create(&sel_thread, "IPMI[sel]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sel_data);
-
- // ------------------------------------------------------------------------
- // the main loop
-
- if(debug) fprintf(stderr, "%s: starting data collection\n", program_name);
-
- time_t started_t = now_monotonic_sec();
-
- size_t iteration = 0;
- usec_t step = 100 * USEC_PER_MS;
- bool global_chart_created = false;
- bool tty = isatty(fileno(stderr)) == 1;
-
- heartbeat_t hb;
- heartbeat_init(&hb);
-
- for(iteration = 0; 1 ; iteration++) {
- usec_t dt = heartbeat_next(&hb, step);
-
- if (!tty) {
- netdata_mutex_lock(&stdout_mutex);
- fprintf(stdout, "\n"); // keepalive to avoid parser read timeout (2 minutes) during ipmi_detect_speed_secs()
- fflush(stdout);
- netdata_mutex_unlock(&stdout_mutex);
- }
-
- spinlock_lock(&sensors_data.spinlock);
- state.sensors = sensors_data.state.sensors;
- spinlock_unlock(&sensors_data.spinlock);
-
- spinlock_lock(&sel_data.spinlock);
- state.sel = sel_data.state.sel;
- spinlock_unlock(&sel_data.spinlock);
-
- switch(state.sensors.status) {
- case ICS_RUNNING:
- step = update_every * USEC_PER_SEC;
- if(state.sensors.last_iteration_ut < now_monotonic_usec() - IPMI_RESTART_IF_SENSORS_DONT_ITERATE_EVERY_SECONDS * USEC_PER_SEC) {
- collector_error("%s(): sensors have not be collected for %zu seconds. Exiting to restart.",
- __FUNCTION__, (size_t)((now_monotonic_usec() - state.sensors.last_iteration_ut) / USEC_PER_SEC));
-
- fprintf(stdout, "EXIT\n");
- plugin_exit(0);
- }
- break;
-
- case ICS_INIT:
- continue;
-
- case ICS_INIT_FAILED:
- collector_error("%s(): sensors failed to initialize. Calling DISABLE.", __FUNCTION__);
- fprintf(stdout, "DISABLE\n");
- plugin_exit(0);
-
- case ICS_FAILED:
- collector_error("%s(): sensors fails repeatedly to collect metrics. Exiting to restart.", __FUNCTION__);
- fprintf(stdout, "EXIT\n");
- plugin_exit(0);
- }
-
- if(netdata_do_sel) {
- switch (state.sensors.status) {
- case ICS_RUNNING:
- case ICS_INIT:
- break;
-
- case ICS_INIT_FAILED:
- case ICS_FAILED:
- collector_error("%s(): SEL fails to collect events. Disabling SEL collection.", __FUNCTION__);
- netdata_do_sel = false;
- break;
- }
- }
-
- if(unlikely(debug))
- fprintf(stderr, "%s: calling send_ipmi_sensor_metrics_to_netdata()\n", program_name);
-
- static bool add_func_sensors = true;
- if (add_func_sensors) {
- add_func_sensors = false;
- struct functions_evloop_globals *wg =
- functions_evloop_init(1, "FREEIPMI", &stdout_mutex, &function_plugin_should_exit);
- functions_evloop_add_function(
- wg, "ipmi-sensors", freeimi_function_sensors, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT);
- FREEIPMI_GLOBAL_FUNCTION_SENSORS();
- }
-
- state.updates.now_ut = now_monotonic_usec();
- send_ipmi_sensor_metrics_to_netdata(&state);
-
- if(netdata_do_sel)
- send_ipmi_sel_metrics_to_netdata(&state);
-
- if(unlikely(debug))
- fprintf(stderr, "%s: iteration %zu, dt %"PRIu64" usec, sensors ever collected %zu, sensors last collected %zu \n"
- , program_name
- , iteration
- , dt
- , dictionary_entries(state.sensors.dict)
- , state.sensors.collected
- );
-
- netdata_mutex_lock(&stdout_mutex);
-
- if (!global_chart_created) {
- global_chart_created = true;
-
- fprintf(stdout,
- "CHART netdata.freeipmi_availability_status '' 'Plugin availability status' 'status' "
- "plugins netdata.plugin_availability_status line 146000 %d '' '%s' '%s'\n"
- "DIMENSION available '' absolute 1 1\n",
- update_every, program_name, "");
- }
-
- fprintf(stdout,
- "BEGIN netdata.freeipmi_availability_status\n"
- "SET available = 1\n"
- "END\n");
-
- // restart check (14400 seconds)
- if (now_monotonic_sec() - started_t > IPMI_RESTART_EVERY_SECONDS) {
- collector_info("%s(): reached my lifetime expectancy. Exiting to restart.", __FUNCTION__);
- fprintf(stdout, "EXIT\n");
- plugin_exit(0);
- }
-
- fflush(stdout);
-
- netdata_mutex_unlock(&stdout_mutex);
- }
-}