1 /*****************************************************************************\
2 * acct_gather_energy_xcc.c - slurm energy accounting plugin for xcc.
3 *****************************************************************************
4 * Copyright (C) 2018
5 * Written by SchedMD - Felip Moll
6 * Based on IPMI plugin by Thomas Cadeau/Yoann Blein @ Bull
7 *
8 * This file is part of Slurm, a resource management program.
9 * For details, see <https://slurm.schedmd.com/>.
10 * Please also read the included file: DISCLAIMER.
11 *
12 * Slurm is free software; you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 *
17 * In addition, as a special exception, the copyright holders give permission
18 * to link the code of portions of this program with the OpenSSL library under
19 * certain conditions as described in each individual source file, and
20 * distribute linked combinations including the two. You must obey the GNU
21 * General Public License in all respects for all of the code used other than
22 * OpenSSL. If you modify file(s) with this exception, you may extend this
23 * exception to your version of the file(s), but you are not obligated to do
24 * so. If you do not wish to do so, delete this exception statement from your
25 * version. If you delete this exception statement from all source files in
26 * the program, then also delete it here.
27 *
28 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
29 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
31 * details.
32 *
33 * You should have received a copy of the GNU General Public License along
34 * with Slurm; if not, write to the Free Software Foundation, Inc.,
35 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 *
37 * This file is patterned after jobcomp_linux.c, written by Morris Jette and
38 * Copyright (C) 2002 The Regents of the University of California.
39 \*****************************************************************************/
40
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <fcntl.h>
44 #include <sys/stat.h>
45 #include <signal.h>
46 #include <math.h>
47
48 #include "src/common/slurm_xlator.h"
49 #include "src/common/slurm_acct_gather_energy.h"
50 #include "src/common/slurm_protocol_defs.h"
51 #include "src/common/fd.h"
52
53 #include "src/slurmd/common/proctrack.h"
54
55 #include "src/slurmd/slurmd/slurmd.h"
56
57 /*
58 * freeipmi includes for the lib
59 */
60 #include <freeipmi/freeipmi.h>
61
62 /* These are defined here so when we link with something other than
63 * the slurmctld we will have these symbols defined. They will get
64 * overwritten when linking with the slurmctld.
65 */
66 #if defined (__APPLE__)
67 extern slurmd_conf_t *conf __attribute__((weak_import));
68 #else
69 slurmd_conf_t *conf = NULL;
70 #endif
71
72 #define DEFAULT_IPMI_FREQ 30
73 #define DEFAULT_IPMI_USER "USERID"
74 #define DEFAULT_IPMI_PASS "PASSW0RD"
75 #define DEFAULT_IPMI_TIMEOUT 10
76
77 #define IPMI_VERSION 2 /* Data structure version number */
78 #define MAX_LOG_ERRORS 5 /* Max sensor reading errors log messages */
79 #define XCC_MIN_RES 50 /* Minimum resolution for XCC readings, in ms */
80 #define IPMI_RAW_MAX_ARGS 256 /* Max XCC response length in bytes*/
81 /*FIXME: Investigate which is the OVERFLOW limit for XCC*/
82 #define IPMI_XCC_OVERFLOW INFINITE /* XCC overflows at X */
83
84 #define XCC_FLAG_NONE 0x00000000
85 #define XCC_FLAG_FAKE 0x00000001
86 #define XCC_EXPECTED_RSPLEN 16 /* Must match cmd_rq[] response expectations */
87
88 /*
89 * These variables are required by the generic plugin interface. If they
90 * are not found in the plugin, the plugin loader will ignore it.
91 *
92 * plugin_name - a string giving a human-readable description of the
93 * plugin. There is no maximum length, but the symbol must refer to
94 * a valid string.
95 *
96 * plugin_type - a string suggesting the type of the plugin or its
97 * applicability to a particular form of data or method of data handling.
98 * If the low-level plugin API is used, the contents of this string are
99 * unimportant and may be anything. Slurm uses the higher-level plugin
100 * interface which requires this string to be of the form
101 *
102 * <application>/<method>
103 *
104 * where <application> is a description of the intended application of
105 * the plugin (e.g., "jobacct" for Slurm job completion logging) and <method>
106 * is a description of how this plugin satisfies that application. Slurm will
107 * only load job completion logging plugins if the plugin_type string has a
108 * prefix of "jobacct/".
109 *
110 * plugin_version - an unsigned 32-bit integer containing the Slurm version
111 * (major.minor.micro combined into a single number).
112 */
113
114 const char plugin_name[] = "AcctGatherEnergy XCC plugin";
115 const char plugin_type[] = "acct_gather_energy/xcc";
116 const uint32_t plugin_version = SLURM_VERSION_NUMBER;
117
118 typedef struct slurm_ipmi_conf {
119 /* Adjust/approach the consumption
120 * in function of time between ipmi update and read call */
121 bool adjustment;
122 /* authentication type to use
123 * IPMI_MONITORING_AUTHENTICATION_TYPE_NONE = 0x00,
124 * IPMI_MONITORING_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY = 0x01,
125 * IPMI_MONITORING_AUTHENTICATION_TYPE_MD2 = 0x02,
126 * IPMI_MONITORING_AUTHENTICATION_TYPE_MD5 = 0x03,
127 * Pass < 0 for default of IPMI_MONITORING_AUTHENTICATION_TYPE_MD5*/
128 uint32_t authentication_type;
129 /* Cipher suite identifier to determine authentication, integrity,
130 * and confidentiality algorithms to use.
131 * Supported Cipher Suite IDs
132 * (Key: A - Authentication Algorithm
133 * I - Integrity Algorithm
134 * C - Confidentiality Algorithm)
135 * 0 - A = None; I = None; C = None
136 * 1 - A = HMAC-SHA1; I = None; C = None
137 * 2 - A = HMAC-SHA1; I = HMAC-SHA1-96; C = None
138 * 3 - A = HMAC-SHA1; I = HMAC-SHA1-96; C = AES-CBC-128
139 * 6 - A = HMAC-MD5; I = None; C = None
140 * 7 - A = HMAC-MD5; I = HMAC-MD5-128; C = None
141 * 8 - A = HMAC-MD5; I = HMAC-MD5-128; C = AES-CBC-128
142 * 11 - A = HMAC-MD5; I = MD5-128; C = None
143 * 12 - A = HMAC-MD5; I = MD5-128; C = AES-CBC-128
144 * 15 - A = HMAC-SHA256; I = None; C = None
145 * 16 - A = HMAC-SHA256; I = HMAC-SHA256-128; C = None
146 * 17 - A = HMAC-SHA256; I = HMAC-SHA256-128; C = AES-CBC-128
147 * Pass < 0 for default.of 3.*/
148 uint32_t cipher_suite_id;
149 /* Flag informs the library if in-band driver information should be
150 * probed or not.*/
151 uint32_t disable_auto_probe;
152 /* Use this specified driver address instead of a probed one.*/
153 uint32_t driver_address;
154 /* Use this driver device for the IPMI driver.*/
155 char *driver_device;
156 /* Options for IPMI configuration*/
157 /* Use a specific in-band driver.
158 * IPMI_MONITORING_DRIVER_TYPE_KCS = 0x00,
159 * IPMI_MONITORING_DRIVER_TYPE_SSIF = 0x01,
160 * IPMI_MONITORING_DRIVER_TYPE_OPENIPMI = 0x02,
161 * IPMI_MONITORING_DRIVER_TYPE_SUNBMC = 0x03,
162 * Pass < 0 for default of IPMI_MONITORING_DRIVER_TYPE_KCS.*/
163 uint32_t driver_type;
164 uint32_t flags;
165 /* frequency for ipmi call*/
166 uint32_t freq;
167 uint32_t ipmi_flags;
168 /* BMC password. Pass NULL ptr for default password. Standard
169 * default is the null (e.g. empty) password. Maximum length of 20
170 * bytes.*/
171 char *password;
172 /* privilege level to authenticate with.
173 * Supported privilege levels:
174 * 0 = IPMICONSOLE_PRIVILEGE_USER
175 * 1 = IPMICONSOLE_PRIVILEGE_OPERATOR
176 * 2 = IPMICONSOLE_PRIVILEGE_ADMIN
177 * Pass < 0 for default of IPMICONSOLE_PRIVILEGE_ADMIN.*/
178 uint32_t privilege_level;
179 /* Flag informs the library if in-band driver information should be
180 * probed or not.*/
181 /* Indicate the IPMI protocol version to use
182 * IPMI_MONITORING_PROTOCOL_VERSION_1_5 = 0x00,
183 * IPMI_MONITORING_PROTOCOL_VERSION_2_0 = 0x01,
184 * Pass < 0 for default of IPMI_MONITORING_VERSION_1_5.*/
185 uint32_t protocol_version;
186 /* Use this register space instead of the probed one.*/
187 uint32_t register_spacing;
188 /* Specifies the packet retransmission timeout length in
189 * milliseconds. Pass <= 0 to default 500 (0.5 seconds).*/
190 uint32_t retransmission_timeout;
191 /* Specifies the session timeout length in milliseconds. Pass <= 0
192 * to default 60000 (60 seconds).*/
193 uint32_t session_timeout;
194 uint8_t target_channel_number;
195 bool target_channel_number_is_set;
196 uint8_t target_slave_address;
197 bool target_slave_address_is_set;
198 /* Timeout for the ipmi thread */
199 uint32_t timeout;
200 /* BMC username. Pass NULL ptr for default username. Standard
201 * default is the null (e.g. empty) username. Maximum length of 16
202 * bytes.*/
203 char *username;
204 /* Bitwise OR of flags indicating IPMI implementation changes. Some
205 * BMCs which are non-compliant and may require a workaround flag
206 * for correct operation. Pass IPMICONSOLE_WORKAROUND_DEFAULT for
207 * default. Standard default is 0, no modifications to the IPMI
208 * protocol.*/
209 uint32_t workaround_flags;
210 } slurm_ipmi_conf_t;
211
212 /* Struct to store the raw single data command reading */
213 typedef struct xcc_raw_single_data {
214 uint16_t fifo_inx;
215 uint32_t j;
216 uint16_t mj;
217 uint16_t ms;
218 uint32_t s;
219 } xcc_raw_single_data_t;
220
221 static acct_gather_energy_t xcc_energy;
222
223 /* LUN, NetFN, CMD, Data[n]*/
224 static uint8_t cmd_rq[8] = { 0x00, 0x3A, 0x32, 4, 2, 0, 0, 0 };
225 static unsigned int cmd_rq_len = 8;
226
227
228 static int dataset_id = -1; /* id of the dataset for profile data */
229
230 static slurm_ipmi_conf_t slurm_ipmi_conf;
231 static uint64_t debug_flags = 0;
232 static bool flag_energy_accounting_shutdown = false;
233 static bool flag_thread_started = false;
234 static bool flag_init = false;
235
236 static pthread_mutex_t ipmi_mutex = PTHREAD_MUTEX_INITIALIZER;
237 static pthread_cond_t ipmi_cond = PTHREAD_COND_INITIALIZER;
238 static pthread_mutex_t launch_mutex = PTHREAD_MUTEX_INITIALIZER;
239 static pthread_cond_t launch_cond = PTHREAD_COND_INITIALIZER;
240 static pthread_t thread_ipmi_id_launcher = 0;
241 static pthread_t thread_ipmi_id_run = 0;
242 static stepd_step_rec_t *job = NULL;
243 static int context_id = -1;
244
245 /* Thread scope global vars */
246 __thread ipmi_ctx_t ipmi_ctx = NULL;
247
_reset_slurm_ipmi_conf(slurm_ipmi_conf_t * slurm_ipmi_conf)248 static void _reset_slurm_ipmi_conf(slurm_ipmi_conf_t *slurm_ipmi_conf)
249 {
250 if (slurm_ipmi_conf) {
251 slurm_ipmi_conf->adjustment = false;
252 slurm_ipmi_conf->authentication_type = 0;
253 slurm_ipmi_conf->cipher_suite_id = 0;
254 slurm_ipmi_conf->disable_auto_probe = 0;
255 slurm_ipmi_conf->driver_address = 0;
256 xfree(slurm_ipmi_conf->driver_device);
257 slurm_ipmi_conf->driver_type = NO_VAL;
258 slurm_ipmi_conf->flags = XCC_FLAG_NONE;
259 slurm_ipmi_conf->freq = DEFAULT_IPMI_FREQ;
260 slurm_ipmi_conf->ipmi_flags = IPMI_FLAGS_DEFAULT;
261 xfree(slurm_ipmi_conf->password);
262 slurm_ipmi_conf->password = xstrdup(DEFAULT_IPMI_PASS);
263 slurm_ipmi_conf->privilege_level = 0;
264 slurm_ipmi_conf->protocol_version = 0;
265 slurm_ipmi_conf->register_spacing = 0;
266 slurm_ipmi_conf->retransmission_timeout = 0;
267 slurm_ipmi_conf->session_timeout = 0;
268 slurm_ipmi_conf->target_channel_number = 0x00;
269 slurm_ipmi_conf->target_channel_number_is_set = false;
270 slurm_ipmi_conf->target_slave_address = 0x20;
271 slurm_ipmi_conf->target_slave_address_is_set = false;
272 slurm_ipmi_conf->timeout = DEFAULT_IPMI_TIMEOUT;
273 xfree(slurm_ipmi_conf->username);
274 slurm_ipmi_conf->username = xstrdup(DEFAULT_IPMI_USER);
275 slurm_ipmi_conf->workaround_flags = 0; // See man 8 ipmi-raw
276 }
277 }
278
_running_profile(void)279 static int _running_profile(void)
280 {
281 static bool run = false;
282 static uint32_t profile_opt = ACCT_GATHER_PROFILE_NOT_SET;
283
284 if (profile_opt == ACCT_GATHER_PROFILE_NOT_SET) {
285 acct_gather_profile_g_get(ACCT_GATHER_PROFILE_RUNNING,
286 &profile_opt);
287 if (profile_opt & ACCT_GATHER_PROFILE_ENERGY)
288 run = true;
289 }
290
291 return run;
292 }
293
294 /*
295 * _init_ipmi_config initializes parameters for freeipmi library
296 */
_init_ipmi_config(void)297 static int _init_ipmi_config (void)
298 {
299 int ret = 0;
300 unsigned int workaround_flags_mask =
301 (IPMI_WORKAROUND_FLAGS_INBAND_ASSUME_IO_BASE_ADDRESS
302 | IPMI_WORKAROUND_FLAGS_INBAND_SPIN_POLL);
303
304 if (ipmi_ctx) {
305 debug("ipmi_ctx already initialized\n");
306 return SLURM_SUCCESS;
307 }
308
309 if (!(ipmi_ctx = ipmi_ctx_create())) {
310 error("ipmi_ctx_create: %s\n", strerror(errno));
311 goto cleanup;
312 }
313
314 if (getuid() != 0) {
315 error ("%s: error : must be root to open ipmi devices\n",
316 __func__);
317 goto cleanup;
318 }
319
320 /* XCC OEM commands always require to use in-band communication */
321 if (((slurm_ipmi_conf.driver_type > 0) &&
322 (slurm_ipmi_conf.driver_type != NO_VAL) &&
323 (slurm_ipmi_conf.driver_type != IPMI_DEVICE_KCS) &&
324 (slurm_ipmi_conf.driver_type != IPMI_DEVICE_SSIF) &&
325 (slurm_ipmi_conf.driver_type != IPMI_DEVICE_OPENIPMI) &&
326 (slurm_ipmi_conf.driver_type != IPMI_DEVICE_SUNBMC))
327 || (slurm_ipmi_conf.workaround_flags & ~workaround_flags_mask)) {
328 /* IPMI ERROR PARAMETERS */
329 error ("%s: error: XCC Lenovo plugin only supports in-band communication, incorrect driver type or workaround flags",
330 __func__);
331
332 debug("slurm_ipmi_conf.driver_type=%u slurm_ipmi_conf.workaround_flags=%u",
333 slurm_ipmi_conf.driver_type,
334 slurm_ipmi_conf.workaround_flags);
335
336 goto cleanup;
337 }
338
339 if (slurm_ipmi_conf.driver_type == NO_VAL) {
340 if ((ret = ipmi_ctx_find_inband(
341 ipmi_ctx,
342 NULL,
343 slurm_ipmi_conf.disable_auto_probe,
344 slurm_ipmi_conf.driver_address,
345 slurm_ipmi_conf.register_spacing,
346 slurm_ipmi_conf.driver_device,
347 slurm_ipmi_conf.workaround_flags,
348 slurm_ipmi_conf.ipmi_flags)) <= 0) {
349 error("%s: error on ipmi_ctx_find_inband: %s",
350 __func__, ipmi_ctx_errormsg(ipmi_ctx));
351
352 debug("slurm_ipmi_conf.driver_type=%u\n"
353 "slurm_ipmi_conf.disable_auto_probe=%u\n"
354 "slurm_ipmi_conf.driver_address=%u\n"
355 "slurm_ipmi_conf.register_spacing=%u\n"
356 "slurm_ipmi_conf.driver_device=%s\n"
357 "slurm_ipmi_conf.workaround_flags=%u\n"
358 "slurm_ipmi_conf.ipmi_flags=%u",
359 slurm_ipmi_conf.driver_type,
360 slurm_ipmi_conf.disable_auto_probe,
361 slurm_ipmi_conf.driver_address,
362 slurm_ipmi_conf.register_spacing,
363 slurm_ipmi_conf.driver_device,
364 slurm_ipmi_conf.workaround_flags,
365 slurm_ipmi_conf.ipmi_flags);
366
367 goto cleanup;
368 }
369 } else {
370 if ((ipmi_ctx_open_inband(ipmi_ctx,
371 slurm_ipmi_conf.driver_type,
372 slurm_ipmi_conf.disable_auto_probe,
373 slurm_ipmi_conf.driver_address,
374 slurm_ipmi_conf.register_spacing,
375 slurm_ipmi_conf.driver_device,
376 slurm_ipmi_conf.workaround_flags,
377 slurm_ipmi_conf.ipmi_flags) < 0)) {
378 error ("%s: error on ipmi_ctx_open_inband: %s",
379 __func__, ipmi_ctx_errormsg (ipmi_ctx));
380
381 debug("slurm_ipmi_conf.driver_type=%u\n"
382 "slurm_ipmi_conf.disable_auto_probe=%u\n"
383 "slurm_ipmi_conf.driver_address=%u\n"
384 "slurm_ipmi_conf.register_spacing=%u\n"
385 "slurm_ipmi_conf.driver_device=%s\n"
386 "slurm_ipmi_conf.workaround_flags=%u\n"
387 "slurm_ipmi_conf.ipmi_flags=%u",
388 slurm_ipmi_conf.driver_type,
389 slurm_ipmi_conf.disable_auto_probe,
390 slurm_ipmi_conf.driver_address,
391 slurm_ipmi_conf.register_spacing,
392 slurm_ipmi_conf.driver_device,
393 slurm_ipmi_conf.workaround_flags,
394 slurm_ipmi_conf.ipmi_flags);
395 goto cleanup;
396 }
397 }
398
399 if (slurm_ipmi_conf.target_channel_number_is_set
400 || slurm_ipmi_conf.target_slave_address_is_set) {
401 if (ipmi_ctx_set_target(
402 ipmi_ctx,
403 slurm_ipmi_conf.target_channel_number_is_set ?
404 &slurm_ipmi_conf.target_channel_number : NULL,
405 slurm_ipmi_conf.target_slave_address_is_set ?
406 &slurm_ipmi_conf.target_slave_address : NULL) < 0) {
407 error ("%s: error on ipmi_ctx_set_target: %s",
408 __func__, ipmi_ctx_errormsg (ipmi_ctx));
409 goto cleanup;
410 }
411 }
412
413 return SLURM_SUCCESS;
414
415 cleanup:
416 ipmi_ctx_close(ipmi_ctx);
417 ipmi_ctx_destroy(ipmi_ctx);
418 return SLURM_ERROR;
419 }
420
421 /*
422 * _read_ipmi_values read the Power sensor and update last_update_watt and times
423 */
_read_ipmi_values(void)424 static xcc_raw_single_data_t *_read_ipmi_values(void)
425 {
426 xcc_raw_single_data_t *xcc_reading;
427 uint8_t buf_rs[IPMI_RAW_MAX_ARGS];
428 int rs_len = 0;
429
430 if (!IPMI_NET_FN_RQ_VALID(cmd_rq[1])) {
431 error("Invalid netfn value\n");
432 return NULL;
433 }
434
435 rs_len = ipmi_cmd_raw(ipmi_ctx,
436 cmd_rq[0], // Lun (logical unit number)
437 cmd_rq[1], // Net Function
438 &cmd_rq[2], // Command number + request data
439 cmd_rq_len - 2, // Length (in bytes)
440 &buf_rs, // response buffer
441 IPMI_RAW_MAX_ARGS // max response length
442 );
443
444 debug3("ipmi_cmd_raw: %s", ipmi_ctx_errormsg(ipmi_ctx));
445
446 if (rs_len != XCC_EXPECTED_RSPLEN) {
447 error("Invalid ipmi response length for XCC raw command: "
448 "%d bytes, expected %d", rs_len, XCC_EXPECTED_RSPLEN);
449 return NULL;
450 }
451
452 /* Due to memory alineation we must copy the data from the buffer */
453 xcc_reading = xmalloc(sizeof(xcc_raw_single_data_t));
454 if (slurm_ipmi_conf.flags & XCC_FLAG_FAKE) {
455 static uint32_t fake_past_read = 10774496;
456 static bool fake_inited = false;
457
458 if (!fake_inited) {
459 srand((unsigned) time(NULL));
460 fake_inited = true;
461 }
462
463 xcc_reading->fifo_inx = 0;
464 // Fake metric j
465 xcc_reading->j = fake_past_read + 550 + rand() % 200;
466 fake_past_read = xcc_reading->j;
467 xcc_reading->mj = 0;
468 xcc_reading->s = time(NULL); //Fake metric timestamp
469 xcc_reading->ms = 0;
470 } else {
471 memcpy(&xcc_reading->fifo_inx, buf_rs+2, 2);
472 memcpy(&xcc_reading->j, buf_rs+4, 4);
473 memcpy(&xcc_reading->mj, buf_rs+8, 2);
474 memcpy(&xcc_reading->s, buf_rs+10, 4);
475 memcpy(&xcc_reading->ms, buf_rs+14, 2);
476 }
477
478 return xcc_reading;
479 }
480
481 /*
482 * _thread_update_node_energy calls _read_ipmi_values and updates all values
483 * for node consumption
484 */
_thread_update_node_energy(void)485 static int _thread_update_node_energy(void)
486 {
487 xcc_raw_single_data_t *xcc_raw;
488 static uint16_t overflows = 0; /* Number of overflows of the counter */
489 int elapsed = 0;
490 static uint64_t first_consumed_energy = 0;
491
492 xcc_raw = _read_ipmi_values();
493
494 if (!xcc_raw) {
495 error("%s could not read XCC ipmi values", __func__);
496 return SLURM_ERROR;
497 }
498
499 if (!xcc_energy.poll_time) {
500 /*
501 * First number from the slurmd. We will figure out the usage
502 * by subtracting this each time.
503 */
504 first_consumed_energy = xcc_raw->j;
505 xcc_energy.consumed_energy = 0;
506 xcc_energy.base_consumed_energy = 0;
507 xcc_energy.previous_consumed_energy = 0;
508 xcc_energy.ave_watts = 0;
509 } else {
510 xcc_energy.previous_consumed_energy =
511 xcc_energy.consumed_energy;
512
513 /* Detect first overflow */
514 if (!overflows && xcc_raw->j < xcc_energy.consumed_energy) {
515 xcc_energy.consumed_energy = IPMI_XCC_OVERFLOW -
516 first_consumed_energy +
517 xcc_raw->j;
518 overflows++;
519 } else if (!overflows &&
520 (xcc_raw->j >= xcc_energy.consumed_energy)) {
521 xcc_energy.consumed_energy = xcc_raw->j;
522 xcc_energy.consumed_energy -= first_consumed_energy;
523 } else if (overflows) {
524 /*
525 * Offset = First overflow + consecutive overflows
526 * If it happens that the offset + xcc_raw->j is less
527 * than the past consumed energy, it means that we
528 * overflowed and must add a new overflow to the count
529 */
530 uint64_t offset = IPMI_XCC_OVERFLOW -
531 first_consumed_energy +
532 (IPMI_XCC_OVERFLOW * (overflows-1));
533
534 if ((offset + xcc_raw->j) <
535 xcc_energy.consumed_energy) {
536 overflows++;
537 xcc_energy.consumed_energy = offset +
538 IPMI_XCC_OVERFLOW + xcc_raw->j;
539 } else {
540 xcc_energy.consumed_energy += offset +
541 xcc_raw->j;
542 }
543 }
544
545 xcc_energy.base_consumed_energy =
546 xcc_energy.consumed_energy -
547 xcc_energy.previous_consumed_energy;
548
549 elapsed = xcc_raw->s - xcc_energy.poll_time;
550 }
551
552 xcc_energy.poll_time = xcc_raw->s;
553
554 xfree(xcc_raw);
555
556 if (elapsed && xcc_energy.base_consumed_energy) {
557 static uint64_t readings = 0;
558 xcc_energy.current_watts =
559 round((double)xcc_energy.base_consumed_energy /
560 (double)elapsed);
561
562 /* ave_watts is used as TresUsageOutAve (AvePower) */
563 xcc_energy.ave_watts = ((xcc_energy.ave_watts * readings) +
564 xcc_energy.current_watts) /
565 (readings + 1);
566 readings++;
567 }
568
569 if (debug_flags & DEBUG_FLAG_ENERGY) {
570 info("%s: XCC current_watts: %u consumed energy last interval: %"PRIu64"(current reading %"PRIu64") Joules, elapsed time: %u Seconds, first read energy counter val: %"PRIu64" ave watts: %u",
571 __func__,
572 xcc_energy.current_watts,
573 xcc_energy.base_consumed_energy,
574 xcc_energy.consumed_energy,
575 elapsed,
576 first_consumed_energy,
577 xcc_energy.ave_watts);
578 }
579 return SLURM_SUCCESS;
580 }
581
582 /*
583 * _thread_init initializes values and conf for the ipmi thread
584 */
_thread_init(void)585 static int _thread_init(void)
586 {
587 static bool first = true;
588 static int first_init = SLURM_ERROR;
589
590 /*
591 * If we are here we are a new slurmd thread serving
592 * a request. In that case we must init a new ipmi_ctx,
593 * update the sensor and return because the freeipmi lib
594 * context cannot be shared among threads.
595 */
596 if (_init_ipmi_config() != SLURM_SUCCESS)
597 if (debug_flags & DEBUG_FLAG_ENERGY) {
598 info("%s thread init error on _init_ipmi_config()",
599 plugin_name);
600 goto cleanup;
601 }
602
603 if (!first)
604 return first_init;
605
606 first = false;
607
608 if (debug_flags & DEBUG_FLAG_ENERGY)
609 info("%s thread init success", plugin_name);
610
611 first_init = SLURM_SUCCESS;
612 return SLURM_SUCCESS;
613 cleanup:
614 info("%s thread init error", plugin_name);
615 first_init = SLURM_ERROR;
616
617 return SLURM_ERROR;
618 }
619
_ipmi_send_profile(void)620 static int _ipmi_send_profile(void)
621 {
622 /*
623 * This enum is directly related to the xcc_labels below. If this is
624 * changed it should be altered as well.
625 */
626 enum {
627 XCC_ENERGY = 0,
628 XCC_CURR_POWER,
629 XCC_LABEL_CNT
630 };
631
632 static char *xcc_labels[] = { "Energy",
633 "CurrPower",
634 NULL };
635
636 uint16_t i;
637 uint64_t data[XCC_LABEL_CNT];
638
639 if (!_running_profile())
640 return SLURM_SUCCESS;
641
642 if (dataset_id < 0) {
643 acct_gather_profile_dataset_t dataset[XCC_LABEL_CNT + 1];
644 for (i = 0; i < XCC_LABEL_CNT; i++) {
645 dataset[i].name = xcc_labels[i];
646 dataset[i].type = PROFILE_FIELD_UINT64;
647 }
648 dataset[i].name = NULL;
649 dataset[i].type = PROFILE_FIELD_NOT_SET;
650
651 dataset_id = acct_gather_profile_g_create_dataset(
652 "Energy", NO_PARENT, dataset);
653
654 if (debug_flags & DEBUG_FLAG_ENERGY)
655 debug("Energy: dataset created (id = %d)", dataset_id);
656 if (dataset_id == SLURM_ERROR) {
657 error("Energy: Failed to create the dataset for IPMI");
658 return SLURM_ERROR;
659 }
660 }
661
662 /* pack an array of uint64_t with current power of sensors */
663 memset(data, 0, sizeof(data));
664 data[XCC_ENERGY] = xcc_energy.base_consumed_energy;
665 data[XCC_CURR_POWER] = xcc_energy.current_watts;
666 if (debug_flags & DEBUG_FLAG_PROFILE)
667 for (i = 0; i < XCC_LABEL_CNT; i++)
668 info("PROFILE-Energy: %s=%"PRIu64,
669 xcc_labels[i], data[i]);
670
671 return acct_gather_profile_g_add_sample_data(
672 dataset_id, (void *)data, xcc_energy.poll_time);
673 }
674
675
676 /*
677 * _thread_ipmi_run is the thread calling ipmi and launching _thread_ipmi_write
678 */
_thread_ipmi_run(void * no_data)679 static void *_thread_ipmi_run(void *no_data)
680 {
681 // need input (attr)
682 struct timeval tvnow;
683 struct timespec abs;
684
685 flag_energy_accounting_shutdown = false;
686 if (debug_flags & DEBUG_FLAG_ENERGY)
687 info("ipmi-thread: launched");
688
689 (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
690 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
691
692 slurm_mutex_lock(&ipmi_mutex);
693 if (_thread_init() != SLURM_SUCCESS) {
694 if (debug_flags & DEBUG_FLAG_ENERGY)
695 info("ipmi-thread: aborted");
696 slurm_mutex_unlock(&ipmi_mutex);
697
698 slurm_cond_signal(&launch_cond);
699
700 return NULL;
701 }
702
703 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
704
705 slurm_mutex_unlock(&ipmi_mutex);
706 flag_thread_started = true;
707
708 slurm_cond_signal(&launch_cond);
709
710 /* setup timer */
711 gettimeofday(&tvnow, NULL);
712 abs.tv_sec = tvnow.tv_sec;
713 abs.tv_nsec = tvnow.tv_usec * 1000;
714
715 //loop until slurm stop
716 while (!flag_energy_accounting_shutdown) {
717 slurm_mutex_lock(&ipmi_mutex);
718
719 _thread_update_node_energy();
720
721 /* Sleep until the next time. */
722 abs.tv_sec += slurm_ipmi_conf.freq;
723 slurm_cond_timedwait(&ipmi_cond, &ipmi_mutex, &abs);
724
725 slurm_mutex_unlock(&ipmi_mutex);
726 }
727
728 if (debug_flags & DEBUG_FLAG_ENERGY)
729 info("ipmi-thread: ended");
730
731 return NULL;
732 }
733
_thread_launcher(void * no_data)734 static void *_thread_launcher(void *no_data)
735 {
736 //what arg would countain? frequency, socket?
737 struct timeval tvnow;
738 struct timespec abs;
739
740 slurm_thread_create(&thread_ipmi_id_run, _thread_ipmi_run, NULL);
741
742 /* setup timer */
743 gettimeofday(&tvnow, NULL);
744 abs.tv_sec = tvnow.tv_sec + slurm_ipmi_conf.timeout;
745 abs.tv_nsec = tvnow.tv_usec * 1000;
746
747 slurm_mutex_lock(&launch_mutex);
748 slurm_cond_timedwait(&launch_cond, &launch_mutex, &abs);
749 slurm_mutex_unlock(&launch_mutex);
750
751 if (!flag_thread_started) {
752 error("%s threads failed to start in a timely manner",
753 plugin_name);
754
755 flag_energy_accounting_shutdown = true;
756
757 /*
758 * It is a known thing we can hang up on IPMI calls cancel if
759 * we must.
760 */
761 pthread_cancel(thread_ipmi_id_run);
762
763 /*
764 * Unlock just to make sure since we could have canceled the
765 * thread while in the lock.
766 */
767 slurm_mutex_unlock(&ipmi_mutex);
768 }
769
770 return NULL;
771 }
772
_get_joules_task(uint16_t delta)773 static int _get_joules_task(uint16_t delta)
774 {
775 acct_gather_energy_t *new = NULL;
776 uint16_t sensor_cnt = 0;
777 static bool first = true;
778 static uint64_t first_consumed_energy = 0;
779
780 xassert(context_id != -1);
781
782 /*
783 * 'delta' parameter means "use cache" if data is newer than delta
784 * seconds ago, otherwise just inquiry ipmi again.
785 */
786 if (slurm_get_node_energy(NULL, context_id, delta, &sensor_cnt, &new)) {
787 error("%s: can't get info from slurmd", __func__);
788 return SLURM_ERROR;
789 }
790
791 if (sensor_cnt != 1) {
792 error("%s: received %u xcc sensors expected 1",
793 __func__, sensor_cnt);
794 acct_gather_energy_destroy(new);
795 return SLURM_ERROR;
796 }
797
798 if (first) {
799 if (!new->consumed_energy) {
800 info("we got a blank");
801 goto end_it;
802 }
803
804 /*
805 * First number from the slurmd. We will figure out the usage
806 * by subtracting this each time.
807 */
808 first_consumed_energy = new->consumed_energy;
809 first = false;
810 }
811
812 new->consumed_energy -= first_consumed_energy;
813 new->previous_consumed_energy = xcc_energy.consumed_energy;
814 new->base_consumed_energy =
815 new->consumed_energy - new->previous_consumed_energy;
816
817 memcpy(&xcc_energy, new, sizeof(acct_gather_energy_t));
818
819 if (debug_flags & DEBUG_FLAG_ENERGY)
820 info("%s: consumed %"PRIu64" Joules "
821 "(received %"PRIu64"(%u watts) from slurmd)",
822 __func__,
823 xcc_energy.consumed_energy,
824 xcc_energy.base_consumed_energy,
825 xcc_energy.current_watts);
826
827 // new->previous_consumed_energy = xcc_energy.consumed_energy;
828 end_it:
829 acct_gather_energy_destroy(new);
830
831 return SLURM_SUCCESS;
832 }
833
834 /*
835 * init() is called when the plugin is loaded, before any other functions
836 * are called. Put global initialization here.
837 */
init(void)838 extern int init(void)
839 {
840 debug_flags = slurm_get_debug_flags();
841
842 memset(&xcc_energy, 0, sizeof(acct_gather_energy_t));
843
844 return SLURM_SUCCESS;
845 }
846
fini(void)847 extern int fini(void)
848 {
849 if (!running_in_slurmdstepd())
850 return SLURM_SUCCESS;
851
852 flag_energy_accounting_shutdown = true;
853
854 /* clean up the launch thread */
855 slurm_cond_signal(&launch_cond);
856
857 if (thread_ipmi_id_launcher)
858 pthread_join(thread_ipmi_id_launcher, NULL);
859
860 /* clean up the run thread */
861 slurm_cond_signal(&ipmi_cond);
862
863 slurm_mutex_lock(&ipmi_mutex);
864
865 if (ipmi_ctx)
866 ipmi_ctx_destroy(ipmi_ctx);
867 _reset_slurm_ipmi_conf(&slurm_ipmi_conf);
868
869 slurm_mutex_unlock(&ipmi_mutex);
870
871 if (thread_ipmi_id_run)
872 pthread_join(thread_ipmi_id_run, NULL);
873
874 return SLURM_SUCCESS;
875 }
876
acct_gather_energy_p_update_node_energy(void)877 extern int acct_gather_energy_p_update_node_energy(void)
878 {
879 int rc = SLURM_SUCCESS;
880 xassert(running_in_slurmdstepd());
881
882 return rc;
883 }
884
acct_gather_energy_p_get_data(enum acct_energy_type data_type,void * data)885 extern int acct_gather_energy_p_get_data(enum acct_energy_type data_type,
886 void *data)
887 {
888 int rc = SLURM_SUCCESS;
889 acct_gather_energy_t *energy = (acct_gather_energy_t *)data;
890 time_t *last_poll = (time_t *)data;
891 uint16_t *sensor_cnt = (uint16_t *)data;
892
893 xassert(running_in_slurmdstepd());
894
895 switch (data_type) {
896 case ENERGY_DATA_NODE_ENERGY_UP:
897 case ENERGY_DATA_JOULES_TASK:
898 slurm_mutex_lock(&ipmi_mutex);
899 if (running_in_slurmd()) {
900 if (_thread_init() == SLURM_SUCCESS)
901 _thread_update_node_energy();
902 } else {
903 _get_joules_task(10);
904 }
905 memcpy(energy, &xcc_energy, sizeof(acct_gather_energy_t));
906 slurm_mutex_unlock(&ipmi_mutex);
907 break;
908 case ENERGY_DATA_NODE_ENERGY:
909 case ENERGY_DATA_STRUCT:
910 slurm_mutex_lock(&ipmi_mutex);
911 memcpy(energy, &xcc_energy, sizeof(acct_gather_energy_t));
912 slurm_mutex_unlock(&ipmi_mutex);
913 break;
914 case ENERGY_DATA_LAST_POLL:
915 slurm_mutex_lock(&ipmi_mutex);
916 *last_poll = xcc_energy.poll_time;
917 slurm_mutex_unlock(&ipmi_mutex);
918 break;
919 case ENERGY_DATA_SENSOR_CNT:
920 *sensor_cnt = 1;
921 break;
922 default:
923 error("acct_gather_energy_p_get_data: unknown enum %d",
924 data_type);
925 rc = SLURM_ERROR;
926 break;
927 }
928 return rc;
929 }
930
acct_gather_energy_p_set_data(enum acct_energy_type data_type,void * data)931 extern int acct_gather_energy_p_set_data(enum acct_energy_type data_type,
932 void *data)
933 {
934 int rc = SLURM_SUCCESS;
935 int *delta = (int *)data;
936
937 xassert(running_in_slurmdstepd());
938
939 switch (data_type) {
940 case ENERGY_DATA_RECONFIG:
941 debug_flags = slurm_get_debug_flags();
942 break;
943 case ENERGY_DATA_PROFILE:
944 slurm_mutex_lock(&ipmi_mutex);
945 _get_joules_task(*delta);
946 _ipmi_send_profile();
947 slurm_mutex_unlock(&ipmi_mutex);
948 break;
949 case ENERGY_DATA_STEP_PTR:
950 /* set global job if needed later */
951 job = (stepd_step_rec_t *)data;
952 break;
953 default:
954 error("acct_gather_energy_p_set_data: unknown enum %d",
955 data_type);
956 rc = SLURM_ERROR;
957 break;
958 }
959 return rc;
960 }
961
acct_gather_energy_p_conf_options(s_p_options_t ** full_options,int * full_options_cnt)962 extern void acct_gather_energy_p_conf_options(s_p_options_t **full_options,
963 int *full_options_cnt)
964 {
965 // s_p_options_t *full_options_ptr;
966 s_p_options_t options[] = {
967 {"EnergyIPMIAuthenticationType", S_P_UINT32},
968 {"EnergyIPMICalcAdjustment", S_P_BOOLEAN},
969 {"EnergyIPMICipherSuiteId", S_P_UINT32},
970 {"EnergyIPMIDisableAutoProbe", S_P_UINT32},
971 {"EnergyIPMIDriverAddress", S_P_UINT32},
972 {"EnergyIPMIDriverDevice", S_P_STRING},
973 {"EnergyIPMIDriverType", S_P_UINT32},
974 {"EnergyIPMIFrequency", S_P_UINT32},
975 {"EnergyIPMIPassword", S_P_STRING},
976 {"EnergyIPMIPrivilegeLevel", S_P_UINT32},
977 {"EnergyIPMIProtocolVersion", S_P_UINT32},
978 {"EnergyIPMIRegisterSpacing", S_P_UINT32},
979 {"EnergyIPMIRetransmissionTimeout", S_P_UINT32},
980 {"EnergyIPMISessionTimeout", S_P_UINT32},
981 {"EnergyIPMITimeout", S_P_UINT32},
982 {"EnergyIPMIUsername", S_P_STRING},
983 {"EnergyIPMIWorkaroundFlags", S_P_UINT32},
984 {"EnergyXCCFake", S_P_BOOLEAN},
985 {NULL} };
986
987 transfer_s_p_options(full_options, options, full_options_cnt);
988 }
989
acct_gather_energy_p_conf_set(int context_id_in,s_p_hashtbl_t * tbl)990 extern void acct_gather_energy_p_conf_set(int context_id_in,
991 s_p_hashtbl_t *tbl)
992 {
993 bool tmp_bool;
994
995 /* Set initial values */
996 _reset_slurm_ipmi_conf(&slurm_ipmi_conf);
997
998 if (tbl) {
999 /* ipmi initialization parameters */
1000 s_p_get_uint32(&slurm_ipmi_conf.authentication_type,
1001 "EnergyIPMIAuthenticationType", tbl);
1002 (void) s_p_get_boolean(&(slurm_ipmi_conf.adjustment),
1003 "EnergyIPMICalcAdjustment", tbl);
1004 s_p_get_uint32(&slurm_ipmi_conf.cipher_suite_id,
1005 "EnergyIPMICipherSuiteId", tbl);
1006 s_p_get_uint32(&slurm_ipmi_conf.disable_auto_probe,
1007 "EnergyIPMIDisableAutoProbe", tbl);
1008 s_p_get_uint32(&slurm_ipmi_conf.driver_address,
1009 "EnergyIPMIDriverAddress", tbl);
1010 s_p_get_string(&slurm_ipmi_conf.driver_device,
1011 "EnergyIPMIDriverDevice", tbl);
1012 s_p_get_uint32(&slurm_ipmi_conf.driver_type,
1013 "EnergyIPMIDriverType", tbl);
1014 s_p_get_uint32(&slurm_ipmi_conf.freq,
1015 "EnergyIPMIFrequency", tbl);
1016 if ((int)slurm_ipmi_conf.freq <= 0)
1017 fatal("EnergyIPMIFrequency must be a positive integer in acct_gather.conf.");
1018 s_p_get_string(&slurm_ipmi_conf.password,
1019 "EnergyIPMIPassword", tbl);
1020 s_p_get_uint32(&slurm_ipmi_conf.privilege_level,
1021 "EnergyIPMIPrivilegeLevel", tbl);
1022 s_p_get_uint32(&slurm_ipmi_conf.protocol_version,
1023 "EnergyIPMIProtocolVersion", tbl);
1024 s_p_get_uint32(&slurm_ipmi_conf.register_spacing,
1025 "EnergyIPMIRegisterSpacing", tbl);
1026 s_p_get_uint32(&slurm_ipmi_conf.retransmission_timeout,
1027 "EnergyIPMIRetransmissionTimeout", tbl);
1028 s_p_get_uint32(&slurm_ipmi_conf.session_timeout,
1029 "EnergyIPMISessionTimeout", tbl);
1030 s_p_get_uint32(&slurm_ipmi_conf.timeout,
1031 "EnergyIPMITimeout", tbl);
1032 s_p_get_string(&slurm_ipmi_conf.username,
1033 "EnergyIPMIUsername", tbl);
1034 s_p_get_uint32(&slurm_ipmi_conf.workaround_flags,
1035 "EnergyIPMIWorkaroundFlags", tbl);
1036 (void) s_p_get_boolean(&tmp_bool, "EnergyXCCFake", tbl);
1037 if (tmp_bool) {
1038 slurm_ipmi_conf.flags |= XCC_FLAG_FAKE;
1039 /*
1040 * This is just to do a random query and get error if
1041 * ipmi is not initialized
1042 */
1043 cmd_rq[0] = 0x00;
1044 cmd_rq[1] = 0x04;
1045 cmd_rq[2] = 0x2d;
1046 cmd_rq[3] = 0x36;
1047 cmd_rq_len = 4;
1048 }
1049 }
1050
1051 context_id = context_id_in;
1052
1053 if (!running_in_slurmdstepd())
1054 return;
1055
1056 if (!flag_init) {
1057 flag_init = true;
1058 if (running_in_slurmd()) {
1059 slurm_thread_create(&thread_ipmi_id_launcher,
1060 _thread_launcher, NULL);
1061 if (debug_flags & DEBUG_FLAG_ENERGY)
1062 info("%s thread launched", plugin_name);
1063 } else
1064 _get_joules_task(0);
1065 }
1066
1067 verbose("%s loaded", plugin_name);
1068 }
1069
acct_gather_energy_p_conf_values(List * data)1070 extern void acct_gather_energy_p_conf_values(List *data)
1071 {
1072 config_key_pair_t *key_pair;
1073
1074 xassert(*data);
1075
1076 key_pair = xmalloc(sizeof(config_key_pair_t));
1077 key_pair->name = xstrdup("EnergyIPMIAuthenticationType");
1078 key_pair->value = xstrdup_printf("%u",
1079 slurm_ipmi_conf.authentication_type);
1080 list_append(*data, key_pair);
1081
1082 key_pair = xmalloc(sizeof(config_key_pair_t));
1083 key_pair->name = xstrdup("EnergyIPMICalcAdjustment");
1084 key_pair->value = xstrdup(slurm_ipmi_conf.adjustment
1085 ? "Yes" : "No");
1086 list_append(*data, key_pair);
1087
1088 key_pair = xmalloc(sizeof(config_key_pair_t));
1089 key_pair->name = xstrdup("EnergyIPMICipherSuiteId");
1090 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.cipher_suite_id);
1091 list_append(*data, key_pair);
1092
1093 key_pair = xmalloc(sizeof(config_key_pair_t));
1094 key_pair->name = xstrdup("EnergyIPMIDisableAutoProbe");
1095 key_pair->value = xstrdup_printf("%u",
1096 slurm_ipmi_conf.disable_auto_probe);
1097 list_append(*data, key_pair);
1098
1099 key_pair = xmalloc(sizeof(config_key_pair_t));
1100 key_pair->name = xstrdup("EnergyIPMIDriverAddress");
1101 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.driver_address);
1102 list_append(*data, key_pair);
1103
1104 key_pair = xmalloc(sizeof(config_key_pair_t));
1105 key_pair->name = xstrdup("EnergyIPMIDriverDevice");
1106 key_pair->value = xstrdup(slurm_ipmi_conf.driver_device);
1107 list_append(*data, key_pair);
1108
1109 key_pair = xmalloc(sizeof(config_key_pair_t));
1110 key_pair->name = xstrdup("EnergyIPMIDriverType");
1111 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.driver_type);
1112 list_append(*data, key_pair);
1113
1114 key_pair = xmalloc(sizeof(config_key_pair_t));
1115 key_pair->name = xstrdup("EnergyIPMIFrequency");
1116 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.freq);
1117 list_append(*data, key_pair);
1118
1119 /*
1120 * Don't give out the password
1121 * key_pair = xmalloc(sizeof(config_key_pair_t));
1122 * key_pair->name = xstrdup("EnergyIPMIPassword");
1123 * key_pair->value = xstrdup(slurm_ipmi_conf.password);
1124 * list_append(*data, key_pair);
1125 */
1126
1127 key_pair = xmalloc(sizeof(config_key_pair_t));
1128 key_pair->name = xstrdup("EnergyIPMIPrivilegeLevel");
1129 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.privilege_level);
1130 list_append(*data, key_pair);
1131
1132 key_pair = xmalloc(sizeof(config_key_pair_t));
1133 key_pair->name = xstrdup("EnergyIPMIProtocolVersion");
1134 key_pair->value = xstrdup_printf("%u",
1135 slurm_ipmi_conf.protocol_version);
1136 list_append(*data, key_pair);
1137
1138 key_pair = xmalloc(sizeof(config_key_pair_t));
1139 key_pair->name = xstrdup("EnergyIPMIRegisterSpacing");
1140 key_pair->value = xstrdup_printf("%u",
1141 slurm_ipmi_conf.register_spacing);
1142 list_append(*data, key_pair);
1143
1144 key_pair = xmalloc(sizeof(config_key_pair_t));
1145 key_pair->name = xstrdup("EnergyIPMIRetransmissionTimeout");
1146 key_pair->value = xstrdup_printf(
1147 "%u", slurm_ipmi_conf.retransmission_timeout);
1148 list_append(*data, key_pair);
1149
1150 key_pair = xmalloc(sizeof(config_key_pair_t));
1151 key_pair->name = xstrdup("EnergyIPMISessionTimeout");
1152 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.session_timeout);
1153 list_append(*data, key_pair);
1154
1155 key_pair = xmalloc(sizeof(config_key_pair_t));
1156 key_pair->name = xstrdup("EnergyIPMITimeout");
1157 key_pair->value = xstrdup_printf("%u", slurm_ipmi_conf.timeout);
1158 list_append(*data, key_pair);
1159
1160 key_pair = xmalloc(sizeof(config_key_pair_t));
1161 key_pair->name = xstrdup("EnergyIPMIUsername");
1162 key_pair->value = xstrdup(slurm_ipmi_conf.username);
1163 list_append(*data, key_pair);
1164
1165 key_pair = xmalloc(sizeof(config_key_pair_t));
1166 key_pair->name = xstrdup("EnergyIPMIWorkaroundFlags");
1167 key_pair->value = xstrdup_printf(
1168 "%u", slurm_ipmi_conf.workaround_flags);
1169 list_append(*data, key_pair);
1170
1171 return;
1172
1173 }
1174