2
* Stonith module for ipmi lan Stonith device
4
* Copyright (c) 2003 Intel Corp.
5
* Yixiong Zou <yixiong.zou@intel.com>
7
* Mangled by Sun Jiang Dong <sunjd@cn.ibm.com>, IBM, 2005.
8
* And passed the compiling with OpenIPMI-1.4.8.
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public
12
* License as published by the Free Software Foundation; either
13
* version 2.1 of the License, or (at your option) any later version.
15
* This library is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this library; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
* See README.ipmi for information regarding this plugin.
32
#define DEVICE "IPMI Over LAN"
34
#include "stonith_plugin_common.h"
36
#define PIL_PLUGIN ipmilan
37
#define PIL_PLUGIN_S "ipmilan"
38
#define PIL_PLUGINLICENSE LICENSE_LGPL
39
#define PIL_PLUGINLICENSEURL URL_LGPL
40
#include <pils/plugin.h>
42
#include <OpenIPMI/ipmi_types.h>
43
#include <OpenIPMI/ipmi_auth.h>
47
static StonithPlugin * ipmilan_new(const char *);
48
static void ipmilan_destroy(StonithPlugin *);
49
static const char ** ipmilan_get_confignames(StonithPlugin *);
50
static int ipmilan_set_config(StonithPlugin *, StonithNVpair *);
51
static const char * ipmilan_getinfo(StonithPlugin * s, int InfoType);
52
static int ipmilan_status(StonithPlugin * );
53
static int ipmilan_reset_req(StonithPlugin * s, int request, const char * host);
54
static char ** ipmilan_hostlist(StonithPlugin *);
56
static struct stonith_ops ipmilanOps ={
57
ipmilan_new, /* Create new STONITH object */
58
ipmilan_destroy, /* Destroy STONITH object */
59
ipmilan_getinfo, /* Return STONITH info string */
60
ipmilan_get_confignames,/* Get configuration parameter names */
61
ipmilan_set_config, /* Set configuration */
62
ipmilan_status, /* Return STONITH device status */
63
ipmilan_reset_req, /* Request a reset */
64
ipmilan_hostlist, /* Return list of supported hosts */
67
PIL_PLUGIN_BOILERPLATE2("1.0", Debug);
68
const PILPluginImports* PluginImports;
69
static PILPlugin* OurPlugin;
70
static PILInterface* OurInterface;
71
static StonithImports* OurImports;
72
static void* interfprivate;
75
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);
78
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
80
/* Force the compiler to do a little type checking */
81
(void)(PILPluginInitFun)PIL_PLUGIN_INIT;
83
PluginImports = imports;
86
/* Register ourself as a plugin */
87
imports->register_plugin(us, &OurPIExports);
89
/* Register our interface implementation */
90
return imports->register_interface(us, PIL_PLUGINTYPE_S
100
* ipmilan STONITH device.
102
* ipmilanHostInfo is a double linked list. Where the prev of the head always
103
* points to the tail. This is a little wierd. But it saves me from looping
104
* around to find the tail when destroying the list.
107
struct pluginDevice {
109
const char * pluginid;
112
struct ipmilanHostInfo * hostlist;
115
static const char * pluginid = "IPMI-LANDevice-Stonith";
116
static const char * NOTpluginid = "IPMI-LAN device has been destroyed";
118
#define ST_HOSTNAME "hostname"
119
#define ST_PORT "port"
120
#define ST_AUTH "auth"
121
#define ST_PRIV "priv"
122
#define ST_RESET_METHOD "reset_method"
124
#include "stonith_config_xml.h"
126
#define XML_HOSTNAME_SHORTDESC \
127
XML_PARM_SHORTDESC_BEGIN("en") \
129
XML_PARM_SHORTDESC_END
131
#define XML_HOSTNAME_LONGDESC \
132
XML_PARM_LONGDESC_BEGIN("en") \
133
"The hostname of the STONITH device" \
134
XML_PARM_LONGDESC_END
136
#define XML_HOSTNAME_PARM \
137
XML_PARAMETER_BEGIN(ST_HOSTNAME, "string", "1") \
138
XML_HOSTNAME_SHORTDESC \
139
XML_HOSTNAME_LONGDESC \
142
#define XML_PORT_SHORTDESC \
143
XML_PARM_SHORTDESC_BEGIN("en") \
145
XML_PARM_SHORTDESC_END
147
#define XML_PORT_LONGDESC \
148
XML_PARM_LONGDESC_BEGIN("en") \
149
"The port number to where the IPMI message is sent" \
150
XML_PARM_LONGDESC_END
152
#define XML_PORT_PARM \
153
XML_PARAMETER_BEGIN(ST_PORT, "string", "1") \
158
#define XML_AUTH_SHORTDESC \
159
XML_PARM_SHORTDESC_BEGIN("en") \
161
XML_PARM_SHORTDESC_END
163
#define XML_AUTH_LONGDESC \
164
XML_PARM_LONGDESC_BEGIN("en") \
165
"The authorization type of the IPMI session (\"none\", \"straight\", \"md2\", or \"md5\")" \
166
XML_PARM_LONGDESC_END
168
#define XML_AUTH_PARM \
169
XML_PARAMETER_BEGIN(ST_AUTH, "string", "1") \
174
#define XML_PRIV_SHORTDESC \
175
XML_PARM_SHORTDESC_BEGIN("en") \
177
XML_PARM_SHORTDESC_END
179
#define XML_PRIV_LONGDESC \
180
XML_PARM_LONGDESC_BEGIN("en") \
181
"The privilege level of the user (\"operator\" or \"admin\")" \
182
XML_PARM_LONGDESC_END
184
#define XML_PRIV_PARM \
185
XML_PARAMETER_BEGIN(ST_PRIV, "string", "1") \
190
#define XML_RESET_METHOD_SHORTDESC \
191
XML_PARM_SHORTDESC_BEGIN("en") \
193
XML_PARM_SHORTDESC_END
195
#define XML_RESET_METHOD_LONGDESC \
196
XML_PARM_LONGDESC_BEGIN("en") \
197
"How to reset the host (\"power_cycle\" or \"hard_reset\")" \
198
XML_PARM_LONGDESC_END
200
#define XML_RESET_METHOD_PARM \
201
XML_PARAMETER_BEGIN(ST_RESET_METHOD, "string", "0") \
202
XML_RESET_METHOD_SHORTDESC \
203
XML_RESET_METHOD_LONGDESC \
206
static const char *ipmilanXML =
218
* Check the status of the IPMI Lan STONITH device.
220
* NOTE: not sure what we should do here since each host is configured
224
* 1) always return S_OK.
225
* 2) using IPMI ping to confirm the status for every host that's
228
* For now I choose the option 1 hoping that I can get by. Maybe we should
229
* change it to option 2 later.
233
ipmilan_status(StonithPlugin *s)
235
struct pluginDevice * nd;
236
struct ipmilanHostInfo * node;
240
ERRIFWRONGDEV(s,S_OOPS);
244
nd = (struct pluginDevice *)s;
245
for( i=0, node = nd->hostlist;
246
i < nd->hostcount; i++, node = node->next ) {
247
rv = do_ipmi_cmd(node, ST_IPMI_STATUS);
249
LOG(PIL_INFO, "Host %s ipmilan status failure."
253
LOG(PIL_INFO, "Host %s ipmilan status OK."
263
* This function returns the list of hosts that's configured.
265
* The detailed configuration is disabled because the STONITH command can be
266
* run by anyone so there is a security risk if that to be exposed.
270
get_config_string(struct pluginDevice * nd, int index)
272
struct ipmilanHostInfo * host;
275
if (index >= nd->hostcount || index < 0) {
280
for (i = 0; i < index; i++) {
284
return STRDUP(host->hostname);
289
* Return the list of hosts configured for this ipmilan device
294
ipmilan_hostlist(StonithPlugin *s)
298
struct pluginDevice* nd;
301
ERRIFWRONGDEV(s,NULL);
303
nd = (struct pluginDevice*) s;
304
if (nd->hostcount < 0) {
306
, "unconfigured stonith object in ipmi_hostlist");
309
numnames = nd->hostcount;
311
ret = (char **)MALLOC((numnames + 1)*sizeof(char*));
313
LOG(PIL_CRIT, "out of memory");
317
memset(ret, 0, (numnames + 1)*sizeof(char*));
319
for (j = 0; j < numnames; ++j) {
320
ret[j] = get_config_string(nd, j);
322
stonith_free_hostlist(ret);
333
* Parse the config information, and stash it away...
335
* The buffer for each string is MAX_IPMI_STRING_LEN bytes long.
336
* Right now it is set to 64. Hope this is enough.
340
#define MAX_IPMI_STRING_LEN 64
343
* Reset the given host on this StonithPlugin device.
346
ipmilan_reset_req(StonithPlugin * s, int request, const char * host)
349
struct pluginDevice * nd;
350
struct ipmilanHostInfo * node;
353
ERRIFWRONGDEV(s,S_OOPS);
355
nd = (struct pluginDevice *)s;
356
for( i=0, node = nd->hostlist;
357
i < nd->hostcount; i++, node = node->next ) {
358
if (strcasecmp(node->hostname, host) == 0) {
363
if (i >= nd->hostcount) {
364
LOG(PIL_CRIT, "Host %s is not configured in this STONITH "
365
" module. Please check your configuration file.", host);
369
rc = do_ipmi_cmd(node, request);
371
LOG(PIL_INFO, "Host %s ipmilan-reset.", host);
373
LOG(PIL_INFO, "Host %s ipmilan-reset error. Error = %d."
380
* Get configuration parameter names
383
ipmilan_get_confignames(StonithPlugin * s)
385
static const char * ret[] =
386
{ ST_HOSTNAME, ST_IPADDR, ST_PORT, ST_AUTH,
387
ST_PRIV, ST_LOGIN, ST_PASSWD, ST_RESET_METHOD, NULL};
392
* Set the configuration parameters
395
ipmilan_set_config(StonithPlugin* s, StonithNVpair * list)
397
struct pluginDevice* nd;
399
struct ipmilanHostInfo * tmp;
400
const char *reset_opt;
402
StonithNamesToGet namestocopy [] =
403
{ {ST_HOSTNAME, NULL}
413
ERRIFWRONGDEV(s,S_OOPS);
414
nd = (struct pluginDevice *)s;
416
ERRIFWRONGDEV(s, S_OOPS);
417
if (nd->sp.isconfigured) {
421
if ((rc=OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
425
tmp = ST_MALLOCT(struct ipmilanHostInfo);
426
tmp->hostname = namestocopy[0].s_value;
427
tmp->ipaddr = namestocopy[1].s_value;
428
tmp->portnumber = atoi(namestocopy[2].s_value);
429
FREE(namestocopy[2].s_value);
430
if (namestocopy[3].s_value == NULL) {
431
LOG(PIL_CRIT, "ipmilan auth type is NULL. See "
432
"README.ipmilan for allowed values");
434
} else if (strcmp(namestocopy[3].s_value, "none") == 0) {
436
} else if (strcmp(namestocopy[3].s_value, "md2") == 0) {
438
} else if (strcmp(namestocopy[3].s_value, "md5") == 0) {
440
} else if (strcmp(namestocopy[3].s_value, "key") == 0 ||
441
strcmp(namestocopy[3].s_value, "password") == 0 ||
442
strcmp(namestocopy[3].s_value, "straight") == 0) {
445
LOG(PIL_CRIT, "ipmilan auth type '%s' invalid. See "
446
"README.ipmilan for allowed values", namestocopy[3].s_value);
449
FREE(namestocopy[3].s_value);
450
if (namestocopy[4].s_value == NULL) {
451
LOG(PIL_CRIT, "ipmilan priv value is NULL. See "
452
"README.ipmilan for allowed values");
454
} else if (strcmp(namestocopy[4].s_value, "operator") == 0) {
456
} else if (strcmp(namestocopy[4].s_value, "admin") == 0) {
459
LOG(PIL_CRIT, "ipmilan priv value '%s' invalid. See "
460
"README.ipmilan for allowed values", namestocopy[4].s_value);
463
FREE(namestocopy[4].s_value);
464
tmp->username = namestocopy[5].s_value;
465
tmp->password = namestocopy[6].s_value;
466
reset_opt = OurImports->GetValue(list, ST_RESET_METHOD);
467
if (!reset_opt || !strcmp(reset_opt, "power_cycle")) {
468
tmp->reset_method = 0;
469
} else if (!strcmp(reset_opt, "hard_reset")) {
470
tmp->reset_method = 1;
472
LOG(PIL_CRIT, "ipmilan reset_method '%s' invalid", reset_opt);
476
if (nd->hostlist == NULL ) {
478
nd->hostlist->prev = tmp;
479
nd->hostlist->next = tmp;
481
tmp->prev = nd->hostlist->prev;
482
tmp->next = nd->hostlist;
483
nd->hostlist->prev->next = tmp;
484
nd->hostlist->prev = tmp;
492
ipmilan_getinfo(StonithPlugin * s, int reqtype)
494
struct pluginDevice * nd;
497
ERRIFWRONGDEV(s,NULL);
499
* We look in the ST_TEXTDOMAIN catalog for our messages
501
nd = (struct pluginDevice *)s;
509
ret = nd->hostlist ? nd->hostlist->hostname : NULL;
513
ret = "IPMI LAN STONITH device\n";
517
ret = "http://www.intel.com/design/servers/ipmi/";
520
case ST_CONF_XML: /* XML metadata */
532
* ipmilan StonithPlugin destructor...
534
* The hostlist is a link list. So have to iterate through.
537
ipmilan_destroy(StonithPlugin *s)
539
struct pluginDevice* nd;
540
struct ipmilanHostInfo * host;
543
VOIDERRIFWRONGDEV(s);
545
nd = (struct pluginDevice *)s;
547
nd->pluginid = NOTpluginid;
550
host = nd->hostlist->prev;
551
for (i = 0; i < nd->hostcount; i++) {
552
struct ipmilanHostInfo * host_prev = host->prev;
554
FREE(host->hostname);
556
FREE(host->username);
557
FREE(host->password);
569
/* Create a new ipmilan StonithPlugin device. Too bad this function can't be static */
570
static StonithPlugin *
571
ipmilan_new(const char *subplugin)
573
struct pluginDevice* nd = ST_MALLOCT(struct pluginDevice);
576
LOG(PIL_CRIT, "out of memory");
579
memset(nd, 0, sizeof(*nd));
580
nd->pluginid = pluginid;
584
nd->sp.s_ops = &ipmilanOps;