Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1842021
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
52 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/fence/agents/xvm/fence_xvmd.c b/fence/agents/xvm/fence_xvmd.c
index 888f24b5d..2746c2373 100644
--- a/fence/agents/xvm/fence_xvmd.c
+++ b/fence/agents/xvm/fence_xvmd.c
@@ -1,1053 +1,1053 @@
/*
* Author: Lon Hohberger <lhh at redhat.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <virterror.h>
#include <nss.h>
#include <libgen.h>
#include <ccs.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "virt.h"
#include "libcman.h"
#include "debug.h"
static int running = 1;
static int reload_key;
LOGSYS_DECLARE_SYSTEM (NULL,
LOG_MODE_OUTPUT_STDERR |
LOG_MODE_OUTPUT_SYSLOG_THREADED |
LOG_MODE_SHORT_FILELINE |
LOG_MODE_OUTPUT_FILE |
LOG_MODE_BUFFER_BEFORE_CONFIG,
LOGDIR "/fence_xvmd.log",
SYSLOGFACILITY);
LOGSYS_DECLARE_SUBSYS ("XVM", SYSLOGLEVEL);
int cleanup_xml(char *xmldesc, char **ret, size_t *retsz);
int
connect_tcp(fence_req_t *req, fence_auth_type_t auth,
void *key, size_t key_len)
{
int fd = -1;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
char buf[128];
switch(req->family) {
case PF_INET:
memset(&sin, 0, sizeof(sin));
memcpy(&sin.sin_addr, req->address,
sizeof(sin.sin_addr));
sin.sin_family = PF_INET;
fd = ipv4_connect(&sin.sin_addr, req->port,
5);
if (fd < 0) {
log_printf(LOG_ERR,
"Failed to connect to caller: %s\n",
strerror(errno));
return -1;
}
break;
case PF_INET6:
memset(&sin6, 0, sizeof(sin));
memcpy(&sin6.sin6_addr, req->address,
sizeof(sin6.sin6_addr));
sin.sin_family = PF_INET6;
fd = ipv6_connect(&sin6.sin6_addr, req->port,
5);
memset(buf,0,sizeof(buf));
inet_ntop(PF_INET6, &sin6.sin6_addr, buf, sizeof(buf));
if (fd < 0) {
log_printf(LOG_ERR, "Failed to call back %s\n", buf);
return -1;
}
break;
default:
dbg_printf(1, "Family = %d\n", req->family);
return -1;
}
/* Noops if auth == AUTH_NONE */
if (tcp_response(fd, auth, key, key_len, 10) <= 0) {
log_printf(LOG_ERR, "Failed to respond to challenge\n");
close(fd);
return -1;
}
if (tcp_challenge(fd, auth, key, key_len, 10) <= 0) {
log_printf(LOG_ERR, "Remote failed challenge\n");
close(fd);
return -1;
}
return fd;
}
int
do_notify_caller_tcp(fence_req_t *req, fence_auth_type_t auth,
void *key, size_t key_len, char response)
{
int fd;
fd = connect_tcp(req, auth, key, key_len);
if (fd < 0)
goto out;
if (write(fd, &response, 1) < 0) {
perror("write");
}
out:
if (fd != -1) {
close(fd);
return 0;
}
return -1;
}
void
raise_error(virConnectPtr vp)
{
virErrorPtr vep;
vep = virConnGetLastError(vp);
if (!vep) {
log_printf(LOG_ERR,
"Error: Unable to retrieve error from connection!\n");
return;
}
log_printf(LOG_ERR, "Error: libvirt #%d domain %d: %s\n", vep->code,
vep->domain, vep->message);
}
static inline virDomainPtr
get_domain(fence_req_t *req, virConnectPtr vp)
{
if (req->flags & RF_UUID) {
return virDomainLookupByUUIDString(vp,
(const char *)req->domain);
}
return virDomainLookupByName(vp, (const char *)req->domain);
}
static inline int
wait_domain(fence_req_t *req, virConnectPtr vp, int timeout)
{
int tries = 0;
int response = 1;
virDomainPtr vdp;
virDomainInfo di;
if (!(vdp = get_domain(req, vp)))
return 0;
/* Check domain liveliness. If the domain is still here,
we return failure, and the client must then retry */
/* XXX On the xen 3.0.4 API, we will be able to guarantee
synchronous virDomainDestroy, so this check will not
be necessary */
do {
sleep(1);
vdp = get_domain(req, vp);
if (!vdp) {
dbg_printf(2, "Domain no longer exists\n");
response = 0;
break;
}
memset(&di, 0, sizeof(di));
virDomainGetInfo(vdp, &di);
virDomainFree(vdp);
if (di.state == VIR_DOMAIN_SHUTOFF) {
dbg_printf(2, "Domain has been shut off\n");
response = 0;
break;
}
dbg_printf(4, "Domain still exists (state %d) after %d seconds\n",
di.state, tries);
if (++tries >= timeout)
break;
} while (1);
return response;
}
int
do_fence_request_tcp(fence_req_t *req, fence_auth_type_t auth,
void *key, size_t key_len, virConnectPtr vp,
int flags)
{
int fd = -1, ret = -1;
virDomainPtr vdp;
virDomainInfo vdi;
char response = 1;
char *domain_desc, *domain_desc_sanitized;
size_t sz;
if (!(vdp = get_domain(req, vp)) && (!(flags & F_NOCLUSTER))) {
dbg_printf(2, "Could not find domain: %s\n", req->domain);
goto out;
}
fd = connect_tcp(req, auth, key, key_len);
if (fd < 0) {
dbg_printf(2, "Could call back for fence request: %s\n",
strerror(errno));
goto out;
}
switch(req->request) {
case FENCE_NULL:
dbg_printf(1, "NULL operation: returning failure\n");
response = 1;
break;
case FENCE_OFF:
log_printf(LOG_NOTICE, "Destroying domain %s...\n",
(char *)req->domain);
if (flags & F_NOCLUSTER) {
if (!vdp ||
((virDomainGetInfo(vdp, &vdi) == 0) &&
(vdi.state == VIR_DOMAIN_SHUTOFF))) {
dbg_printf(2, "[NOCLUSTER] Nothing to "
"do - domain does not exist\n");
response = 0;
break;
}
}
dbg_printf(2, "[OFF] Calling virDomainDestroy\n");
ret = virDomainDestroy(vdp);
if (ret < 0) {
log_printf(LOG_ERR,
"virDomainDestroy() failed: %d\n",
ret);
break;
}
response = wait_domain(req, vp, 15);
if (response) {
log_printf(LOG_ERR,
"Domain %s still exists; fencing failed\n",
(char *)req->domain);
}
break;
case FENCE_REBOOT:
log_printf(LOG_NOTICE, "Rebooting domain %s...\n",
(char *)req->domain);
if (flags & F_NOCLUSTER) {
if (!vdp ||
((virDomainGetInfo(vdp, &vdi) == 0) &&
(vdi.state == VIR_DOMAIN_SHUTOFF))) {
dbg_printf(2, "[NOCLUSTER] Nothing to "
"do - domain does not exist\n");
response = 0;
break;
}
}
domain_desc = virDomainGetXMLDesc(vdp, 0);
if (domain_desc) {
dbg_printf(3, "[[ XML Domain Info ]]\n");
dbg_printf(3, "%s\n[[ XML END ]]\n", domain_desc);
sz = 0;
if (cleanup_xml(domain_desc,
&domain_desc_sanitized, &sz) == 0) {
free(domain_desc);
domain_desc = domain_desc_sanitized;
}
dbg_printf(3, "[[ XML Domain Info (modified) ]]\n");
dbg_printf(3, "%s\n[[ XML END ]]\n", domain_desc);
} else {
dbg_printf(1, "Failed getting domain description from "
"libvirt\n");
}
dbg_printf(2, "[REBOOT] Calling virDomainDestroy(%p)\n", vdp);
ret = virDomainDestroy(vdp);
if (ret < 0) {
log_printf(LOG_ERR,
"virDomainDestroy() failed: %d/%d\n",
ret, errno);
if (domain_desc)
free(domain_desc);
break;
}
response = wait_domain(req, vp, 15);
if (response) {
log_printf(LOG_ERR,
"Domain %s still exists; fencing failed\n",
(char *)req->domain);
} else if (domain_desc) {
/* Recreate the domain if possible */
/* Success */
dbg_printf(2, "Calling virDomainCreateLinux()...\n");
virDomainCreateLinux(vp, domain_desc, 0);
free(domain_desc);
}
break;
}
dbg_printf(3, "Sending response to caller...\n");
if (write(fd, &response, 1) < 0) {
log_printf(LOG_ERR, "Failed to send response to caller: %s\n",
strerror(errno));
}
out:
if (fd != -1)
close(fd);
return 1;
}
int
virt_list_update(virConnectPtr vp, virt_list_t **vl, int my_id)
{
virt_list_t *list = NULL;
list = vl_get(vp, my_id);
if (!list)
return -1;
if (*vl)
vl_free(*vl);
*vl = list;
return 0;
}
int
get_cman_ids(cman_handle_t ch, int *my_id, int *high_id)
{
int max_nodes;
int actual;
cman_node_t *nodes = NULL;
cman_node_t me;
int high = 0, ret = -1, x, _local = 0;
if (!my_id && !high_id)
return 0;
if (!ch) {
_local = 1;
ch = cman_init(NULL);
}
if (!ch)
return -1;
max_nodes = cman_get_node_count(ch);
if (max_nodes <= 0)
goto out;
if (my_id) {
memset(&me, 0, sizeof(me));
if (cman_get_node(ch, CMAN_NODEID_US, &me) < 0)
goto out;
*my_id = me.cn_nodeid;
}
if (!high_id) {
ret = 0;
goto out;
}
nodes = malloc(sizeof(cman_node_t) * max_nodes);
if (!nodes)
goto out;
memset(nodes, 0, sizeof(cman_node_t) * max_nodes);
if (cman_get_nodes(ch, max_nodes, &actual, nodes) < 0)
goto out;
for (x = 0; x < actual; x++)
if (nodes[x].cn_nodeid > high && nodes[x].cn_member)
high = nodes[x].cn_nodeid;
*high_id = high;
ret = 0;
out:
if (nodes)
free(nodes);
if (ch && _local)
cman_finish(ch);
return ret;
}
int
get_domain_state_ckpt(void *hp, unsigned char *domain, vm_state_t *state)
{
errno = EINVAL;
if (!hp || !domain || !state || !strlen((char *)domain))
return -1;
if (!strcmp(DOMAIN0NAME, (char *)domain))
return -1;
return ckpt_read(hp, (char *)domain, state, sizeof(*state));
}
void
store_domains_by_name(void *hp, virt_list_t *vl)
{
int x;
if (!vl)
return;
for (x = 0; x < vl->vm_count; x++) {
if (!strcmp(DOMAIN0NAME, vl->vm_states[x].v_name))
continue;
dbg_printf(2, "Storing %s\n", vl->vm_states[x].v_name);
ckpt_write(hp, vl->vm_states[x].v_name,
&vl->vm_states[x].v_state,
sizeof(vm_state_t));
}
}
void
store_domains_by_uuid(void *hp, virt_list_t *vl)
{
int x;
if (!vl)
return;
for (x = 0; x < vl->vm_count; x++) {
if (!strcmp(DOMAIN0UUID, vl->vm_states[x].v_uuid))
continue;
dbg_printf(2, "Storing %s\n", vl->vm_states[x].v_uuid);
ckpt_write(hp, vl->vm_states[x].v_uuid,
&vl->vm_states[x].v_state,
sizeof(vm_state_t));
}
}
static void
handle_remote_domain(cman_handle_t ch, void *h, fence_req_t *data,
fence_auth_type_t auth, void *key, size_t key_len,
int my_id)
{
vm_state_t vst;
int high_id;
int fenced;
uint64_t fence_time;
char ret = 1;
cman_node_t node;
if (get_domain_state_ckpt(h, data->domain, &vst) < 0) {
dbg_printf(1, "Evaluating Domain: %s Last Owner/State Unknown\n",
data->domain);
memset(&vst, 0, sizeof(vst));
} else {
dbg_printf(1, "Evaluating Domain: %s Last Owner: %d State %d\n",
data->domain, vst.s_owner, vst.s_state);
}
if (get_cman_ids(ch, NULL, &high_id) < 0) {
log_printf(LOG_ERR,
"Error: Could not determine high node ID; "
"unable to process fencing request\n");
return;
}
if (my_id == high_id && vst.s_owner == 0) {
dbg_printf(1, "There is no record of that domain; "
"returning success\n");
ret = 0;
} else if (my_id == high_id && vst.s_owner != my_id) {
memset(&node, 0, sizeof(node));
cman_get_node(ch, vst.s_owner, &node);
if (node.cn_nodeid == 0) {
dbg_printf(1, "Node %d does not exist\n",
vst.s_owner);
return;
}
if (node.cn_member) {
dbg_printf(1,
"Node %d is online - not taking action\n",
vst.s_owner);
return;
}
fenced = 0;
cman_get_fenceinfo(ch, vst.s_owner, &fence_time, &fenced, NULL);
if (fenced == 0) {
dbg_printf(1, "Node %d is dead but not fenced - not "
"taking action\n", vst.s_owner);
return;
}
dbg_printf(1, "Node %d is dead & fenced\n", vst.s_owner);
ret = 0;
} else if (vst.s_owner == my_id) {
dbg_printf(1, "I am the last owner of the domain\n");
ret = 0;
}
if (!ret) {
switch(auth) {
case AUTH_NONE:
case AUTH_SHA1:
case AUTH_SHA256:
case AUTH_SHA512:
dbg_printf(1, "Plain TCP request\n");
do_notify_caller_tcp(data, auth, key, key_len, ret);
break;
default:
dbg_printf(1, "XXX Unhandled authentication\n");
}
}
}
int
xvmd_loop(cman_handle_t ch, void *h, int fd, fence_xvm_args_t *args,
void *key, size_t key_len)
{
fd_set rfds;
struct timeval tv;
struct sockaddr_in sin;
int len;
int n;
int my_id = 1;
socklen_t slen;
fence_req_t data;
virConnectPtr vp = NULL;
virt_list_t *vl = NULL;
virt_state_t *dom = NULL;
vp = virConnectOpen(args->uri);
if (!vp)
log_printf(LOG_ERR, "virConnectOpen failed: %s",
strerror(errno));
if (!(args->flags & F_NOCLUSTER))
get_cman_ids(ch, &my_id, NULL);
dbg_printf(1, "My Node ID = %d\n", my_id);
if (vp) {
vl = vl_get(vp, my_id);
vl_print(vl);
virt_list_update(vp, &vl, my_id);
if (args->flags & F_USE_UUID)
store_domains_by_uuid(h, vl);
else
store_domains_by_name(h, vl);
}
while (running) {
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = 10;
tv.tv_usec = 0;
/* Close the connection */
if (vp) {
virConnectClose(vp);
vp = NULL;
}
if (reload_key) {
char temp_key[MAX_KEY_LEN];
int ret;
reload_key = 0;
ret = read_key_file(args->key_file, temp_key,
sizeof(temp_key));
if (ret < 0) {
log_printf(LOG_ERR, "Could not read %s; not updating key",
args->key_file);
} else {
memcpy(key, temp_key, MAX_KEY_LEN);
key_len = (size_t) ret;
if (args->auth == AUTH_NONE)
args->auth = AUTH_SHA256;
if (args->hash == HASH_NONE)
args->hash = HASH_SHA256;
}
}
n = select(fd+1, &rfds, NULL, NULL, &tv);
if (n < 0)
continue;
/* Request and/or timeout: open connection */
vp = virConnectOpen(args->uri);
if (!vp) {
log_printf(LOG_NOTICE, "NOTICE: virConnectOpen(): "
"%s; cannot fence!\n", strerror(errno));
continue;
}
/* Update list of VMs from libvirt. */
virt_list_update(vp, &vl, my_id);
vl_print(vl);
/* Store information here */
if (!(args->flags & F_NOCLUSTER)) {
if (args->flags & F_USE_UUID)
store_domains_by_uuid(h, vl);
else
store_domains_by_name(h, vl);
}
/*
* If no requests, we're done
*/
if (n == 0)
continue;
slen = sizeof(sin);
len = recvfrom(fd, &data, sizeof(data), 0,
(struct sockaddr *)&sin, &slen);
if (len <= 0) {
log_printf(LOG_ERR, "recvfrom: %s\n",
strerror(errno));
continue;
}
if (!verify_request(&data, args->hash, key, key_len)) {
dbg_printf(1, "Key mismatch; dropping packet\n");
continue;
}
if ((args->flags & F_USE_UUID) &&
!(data.flags & RF_UUID)) {
dbg_printf(1, "Dropping packet: Request to fence by "
"name while using UUIDs\n");
continue;
}
if (!(args->flags & F_USE_UUID) &&
(data.flags & RF_UUID)) {
dbg_printf(1, "Dropping packet: Request to fence by "
"UUID while using names\n");
continue;
}
dbg_printf(1, "Request to fence: %s\n", data.domain);
if (args->flags & F_USE_UUID)
dom = vl_find_uuid(vl, (char *)data.domain);
else
dom = vl_find_name(vl, (char *)data.domain);
if (!dom && !(args->flags & F_NOCLUSTER)) {
handle_remote_domain(ch, h, &data, args->auth,
key, key_len, my_id);
continue;
}
dbg_printf(1, "%s is running locally\n", (char *)data.domain);
switch(args->auth) {
case AUTH_NONE:
case AUTH_SHA1:
case AUTH_SHA256:
case AUTH_SHA512:
dbg_printf(1, "Plain TCP request\n");
do_fence_request_tcp(&data, args->auth, key,
key_len, vp, args->flags);
break;
default:
log_printf(LOG_ERR, "XXX Unhandled authentication\n");
}
}
cman_finish(ch);
if (vp) {
virConnectClose(vp);
vp = NULL;
}
return 0;
}
void
sigint_handler(int sig)
{
running = 0;
}
void
sighup_handler(int sig)
{
reload_key = 1;
}
void malloc_dump_table(void);
static void
log_config_done(int logmode)
{
if(logmode & LOG_MODE_BUFFER_BEFORE_CONFIG) {
log_printf(LOG_DEBUG, "logsys config enabled from get_logsys_config_data\n");
logmode &= ~LOG_MODE_BUFFER_BEFORE_CONFIG;
logmode |= LOG_MODE_FLUSH_AFTER_CONFIG;
logsys_config_mode_set (logmode);
}
}
/**
Grab logsys configuration data from libccs
*/
static int
get_logsys_config_data(int *debug)
{
int ccsfd = -1, loglevel = SYSLOGLEVEL, facility = SYSLOGFACILITY;
char *val = NULL, *error = NULL;
unsigned int logmode = 0;
int global_debug = 0;
log_printf(LOG_DEBUG, "Loading logsys configuration information\n");
ccsfd = ccs_connect();
if (ccsfd < 0) {
log_printf(LOG_CRIT, "Connection to CCSD failed; cannot start\n");
return -1;
}
logmode = logsys_config_mode_get();
if (!debug) {
if (ccs_get(ccsfd, "/cluster/logging/@debug", &val) == 0) {
if(!strcmp(val, "on")) {
global_debug = 1;
} else
if(!strcmp(val, "off")) {
global_debug = 0;
} else
log_printf(LOG_ERR, "global debug: unknown value\n");
free(val);
val = NULL;
}
if (ccs_get(ccsfd, "/cluster/logging/logger_subsys[@subsys=\"XVM\"]/@debug", &val) == 0) {
if(!strcmp(val, "on")) {
*debug = 1;
} else
if(!strcmp(val, "off")) { /* debug from cmdline/envvars override config */
*debug = 0;
} else
log_printf(LOG_ERR, "subsys debug: unknown value: %s\n", val);
free(val);
val = NULL;
} else
*debug = global_debug; /* global debug overrides subsystem only if latter is not specified */
if (ccs_get(ccsfd, "/cluster/logging/logger_subsys[@subsys=\"XVM\"]/@syslog_level", &val) == 0) {
loglevel = logsys_priority_id_get (val);
if (loglevel < 0)
loglevel = SYSLOGLEVEL;
if (!*debug) {
if (loglevel == LOG_LEVEL_DEBUG)
*debug = 1;
logsys_config_priority_set (loglevel);
}
free(val);
val = NULL;
} else
if (ccs_get(ccsfd, "/cluster/fence_xvmd/@log_level", &val) == 0) { /* check backward compat options */
loglevel = logsys_priority_id_get (val);
if (loglevel < 0)
loglevel = SYSLOGLEVEL;
log_printf(LOG_ERR, "<fence_xvmd log_level=\"%s\".. option is depracated\n", val);
if (!*debug) {
if (loglevel == LOG_LEVEL_DEBUG)
*debug = 1;
logsys_config_priority_set (loglevel);
}
free(val);
val = NULL;
}
} else
logsys_config_priority_set (LOG_LEVEL_DEBUG);
if (ccs_get(ccsfd, "/cluster/logging/@to_stderr", &val) == 0) {
if(!strcmp(val, "yes")) {
logmode |= LOG_MODE_OUTPUT_STDERR;
} else
if(!strcmp(val, "no")) {
logmode &= ~LOG_MODE_OUTPUT_STDERR;
} else
log_printf(LOG_ERR, "to_stderr: unknown value\n");
free(val);
val = NULL;
}
if (ccs_get(ccsfd, "/cluster/logging/@to_syslog", &val) == 0) {
if(!strcmp(val, "yes")) {
logmode |= LOG_MODE_OUTPUT_SYSLOG_THREADED;
} else
if(!strcmp(val, "no")) {
logmode &= ~LOG_MODE_OUTPUT_SYSLOG_THREADED;
} else
log_printf(LOG_ERR, "to_syslog: unknown value\n");
free(val);
val = NULL;
}
if (ccs_get(ccsfd, "/cluster/logging/@to_file", &val) == 0) {
if(!strcmp(val, "yes")) {
logmode |= LOG_MODE_OUTPUT_FILE;
} else
if(!strcmp(val, "no")) {
logmode &= ~LOG_MODE_OUTPUT_FILE;
} else
log_printf(LOG_ERR, "to_file: unknown value\n");
free(val);
val = NULL;
}
if (ccs_get(ccsfd, "/cluster/logging/@logfile", &val) == 0) {
if(logsys_config_file_set(&error, val))
log_printf(LOG_ERR, "logfile: unable to open %s for logging\n", val);
free(val);
val = NULL;
} else
log_printf(LOG_DEBUG, "logfile: use default built-in log file: %s\n", LOGDIR "/fence_xvmd.log");
if (ccs_get(ccsfd, "/cluster/logging/@syslog_facility", &val) == 0) {
facility = logsys_facility_id_get (val);
if (facility < 0) {
log_printf(LOG_ERR, "syslog_facility: unknown value\n");
facility = SYSLOGFACILITY;
}
logsys_config_facility_set ("XVM", facility);
free(val);
} else
if (ccs_get(ccsfd, "/cluster/fence_xvmd/@log_facility", &val) == 0) {
facility = logsys_facility_id_get (val);
if (facility < 0) {
log_printf(LOG_ERR, "syslog_facility: unknown value\n");
facility = SYSLOGFACILITY;
}
log_printf(LOG_ERR, "<fence_xvmd log_facility=\"%s\".. option is depracated\n", val);
logsys_config_facility_set ("XVM", facility);
free(val);
val = NULL;
}
log_config_done(logmode);
ccs_disconnect(ccsfd);
return 0;
}
int
main(int argc, char **argv)
{
fence_xvm_args_t args;
int mc_sock;
unsigned int logmode = 0;
char key[MAX_KEY_LEN];
int key_len = 0, x;
- char *my_options = "dfi:a:p:C:U:c:k:u?hLXV";
+ char *my_options = "dfi:a:p:I:C:U:c:k:u?hLXV";
cman_handle_t ch = NULL;
void *h = NULL;
args_init(&args);
args_get_getopt(argc, argv, my_options, &args);
if (args.flags & F_HELP) {
args_usage(argv[0], my_options, 0);
printf("Arguments may be specified as part of the\n");
printf("fence_xvmd tag in cluster.conf in the form of:\n");
printf(" <fence_xvmd argname=\"value\" ... />\n\n");
args_usage(argv[0], my_options, 1);
return 0;
}
if (args.flags & F_VERSION) {
printf("%s %s\n", basename(argv[0]), XVM_VERSION);
#ifdef RELEASE_VERSION
printf("fence release %s\n", RELEASE_VERSION);
#endif
exit(0);
}
if (!(args.flags & F_NOCCS)) {
args_get_ccs(my_options, &args);
get_logsys_config_data(&args.debug);
} else {
logmode = logsys_config_mode_get();
logmode &= ~LOG_MODE_DISPLAY_FILELINE;
log_config_done(logmode);
}
args_finalize(&args);
if (args.debug > 0) {
dset(args.debug);
logsys_config_priority_set (LOG_LEVEL_DEBUG);
args_print(&args);
}
if (args.flags & F_ERR) {
return 1;
}
if (args.auth != AUTH_NONE || args.hash != HASH_NONE) {
key_len = read_key_file(args.key_file, key, sizeof(key));
if (key_len < 0) {
log_printf(LOG_WARNING,
"Could not read %s; operating without "
"authentication\n", args.key_file);
args.auth = AUTH_NONE;
args.hash = HASH_NONE;
}
}
/* Fork in to background */
/* XXX need to wait for child to successfully start before
exiting... */
if (!(args.flags & F_FOREGROUND)) {
if(daemon(0,0)) {
log_printf(LOG_ERR, "Could not daemonize\n");
return 1;
}
}
if (virInitialize() != 0) {
log_printf(LOG_ERR, "Could not initialize libvirt\n");
return 1;
}
/* Initialize NSS; required to do hashing, as silly as that
sounds... */
if (NSS_NoDB_Init(NULL) != SECSuccess) {
log_printf(LOG_ERR, "Could not initialize NSS\n");
return 1;
}
if (!(args.flags & F_NOCLUSTER)) {
/* Wait for cman to start. */
x = 0;
while ((ch = cman_init(NULL)) == NULL) {
if (!x) {
dbg_printf(1,
"Could not connect to CMAN; retrying...\n");
x = 1;
}
sleep(3);
}
if (x)
dbg_printf(1, "Connected to CMAN\n");
/* Wait for quorum */
while (!cman_is_quorate(ch))
sleep(3);
/* Wait for openais checkpointing to become available */
x = 0;
while ((h = ckpt_init("vm_states", 262144, 4096, 64, 10)) == NULL) {
if (!x) {
dbg_printf(1, "Could not initialize saCkPt; retrying...\n");
x = 1;
}
sleep(3);
}
if (x)
dbg_printf(1, "Checkpoint initialized\n");
}
if (args.family == PF_INET)
- mc_sock = ipv4_recv_sk(args.addr, args.port);
+ mc_sock = ipv4_recv_sk(args.addr, args.port, args.ifindex);
else
- mc_sock = ipv6_recv_sk(args.addr, args.port);
+ mc_sock = ipv6_recv_sk(args.addr, args.port, args.ifindex);
if (mc_sock < 0) {
log_printf(LOG_ERR,
"Could not set up multicast listen socket\n");
return 1;
}
signal(SIGHUP, sighup_handler);
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
signal(SIGQUIT, sigint_handler);
xvmd_loop(ch, h, mc_sock, &args, key, key_len);
//malloc_dump_table();
return 0;
}
diff --git a/fence/agents/xvm/mcast.c b/fence/agents/xvm/mcast.c
index db46328af..9f20c8995 100644
--- a/fence/agents/xvm/mcast.c
+++ b/fence/agents/xvm/mcast.c
@@ -1,357 +1,358 @@
/*
* Author: Lon Hohberger <lhh at redhat.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
/* Local includes */
#include "mcast.h"
#include "debug.h"
LOGSYS_DECLARE_SUBSYS ("XVM", SYSLOGLEVEL);
/**
Sets up a multicast receive socket
*/
int
-ipv4_recv_sk(char *addr, int port)
+ipv4_recv_sk(char *addr, int port, unsigned int ifindex)
{
int sock;
- struct ip_mreq mreq;
+ struct ip_mreqn mreq;
struct sockaddr_in sin;
/* Store multicast address */
if (inet_pton(PF_INET, addr,
(void *)&mreq.imr_multiaddr.s_addr) < 0) {
printf("Invalid multicast address: %s\n", addr);
return -1;
}
/********************************
* SET UP MULTICAST RECV SOCKET *
********************************/
dbg_printf(4, "Setting up ipv4 multicast receive (%s:%d)\n", addr, port);
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
printf("socket: %s\n", strerror(errno));
close(sock);
sock = -1;
return 1;
}
/*
* When using Multicast, bind to the LOCAL address, not the MULTICAST
* address.
*/
sin.sin_family = PF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr *) &sin,
sizeof(struct sockaddr_in)) < 0) {
printf("bind failed: %s\n", strerror(errno));
close(sock);
return -1;
}
/*
* Join multicast group
*/
/* mreq.imr_multiaddr.s_addr is set above */
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ mreq.imr_ifindex = ifindex;
dbg_printf(4, "Joining multicast group\n");
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) == -1) {
printf("Failed to bind multicast receive socket to "
"%s: %s\n", addr, strerror(errno));
printf("Check network configuration.\n");
close(sock);
return -1;
}
dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
return sock;
}
/**
Set up multicast send socket
*/
int
ipv4_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt,
socklen_t tgt_len, int ttl)
{
int val;
struct ip_mreq mreq;
struct sockaddr_in mcast;
struct sockaddr_in src;
int sock;
if (tgt_len < sizeof(struct sockaddr_in)) {
errno = EINVAL;
return -1;
}
/* Store multicast address */
mcast.sin_family = PF_INET;
mcast.sin_port = htons(port);
if (inet_pton(PF_INET, addr,
(void *)&mcast.sin_addr.s_addr) < 0) {
printf("Invalid multicast address: %s\n", addr);
return -1;
}
mreq.imr_multiaddr.s_addr = mcast.sin_addr.s_addr;
/* Store sending address */
src.sin_family = PF_INET;
src.sin_port = htons(port);
if (inet_pton(PF_INET, send_addr,
(void *)&src.sin_addr.s_addr) < 0) {
printf("Invalid source address: %s\n", send_addr);
return -1;
}
mreq.imr_interface.s_addr = src.sin_addr.s_addr;
/*************************
* SET UP MULTICAST SEND *
*************************/
dbg_printf(4, "Setting up ipv4 multicast send (%s:%d)\n", addr, port);
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return -1;
}
/*
* Join Multicast group.
*/
dbg_printf(4, "Joining IP Multicast group (pass 1)\n");
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) == -1) {
printf("Failed to add multicast membership to transmit "
"socket %s: %s\n", addr, strerror(errno));
close(sock);
return -1;
}
/*
* Join Multicast group.
*/
dbg_printf(4, "Joining IP Multicast group (pass 2)\n");
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &src.sin_addr,
sizeof(src.sin_addr)) == -1) {
printf("Failed to bind multicast transmit socket to "
"%s: %s\n", addr, strerror(errno));
close(sock);
return -1;
}
/*
* set time to live to 2 hops.
*/
dbg_printf(4, "Setting TTL to %d for fd%d\n", ttl, sock);
val = ttl;
if (setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &val,
sizeof(val)))
printf("warning: setting TTL failed %s\n", strerror(errno));
memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in));
dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
return sock;
}
/**
Sets up a multicast receive (ipv6) socket
*/
int
-ipv6_recv_sk(char *addr, int port)
+ipv6_recv_sk(char *addr, int port, unsigned int ifindex)
{
int sock, val;
struct ipv6_mreq mreq;
struct sockaddr_in6 sin;
memset(&mreq, 0, sizeof(mreq));
memset(&sin, 0, sizeof(sin));
sin.sin6_family = PF_INET6;
sin.sin6_port = htons(port);
if (inet_pton(PF_INET6, addr,
(void *)&sin.sin6_addr) < 0) {
printf("Invalid multicast address: %s\n", addr);
return -1;
}
memcpy(&mreq.ipv6mr_multiaddr, &sin.sin6_addr,
sizeof(struct in6_addr));
+ mreq.ipv6mr_interface = ifindex;
/********************************
* SET UP MULTICAST RECV SOCKET *
********************************/
dbg_printf(4, "Setting up ipv6 multicast receive (%s:%d)\n", addr, port);
sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) {
printf("socket: %s\n", strerror(errno));
close(sock);
sock = -1;
return 1;
}
/*
* When using Multicast, bind to the LOCAL address, not the MULTICAST
* address.
*/
memset(&sin, 0, sizeof(sin));
sin.sin6_family = PF_INET6;
sin.sin6_port = htons(port);
sin.sin6_addr = in6addr_any;
if (bind(sock, (struct sockaddr *) &sin,
sizeof(struct sockaddr_in6)) < 0) {
printf("bind failed: %s\n", strerror(errno));
close(sock);
return -1;
}
dbg_printf(4, "Disabling IP Multicast loopback\n");
val = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
sizeof(val)) != 0) {
printf("Failed to disable multicast loopback\n");
close(sock);
return -1;
}
/*
* Join multicast group
*/
dbg_printf(4, "Joining IP Multicast group\n");
if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) == -1) {
printf("Failed to add multicast to socket %s: %s\n",
addr, strerror(errno));
close(sock);
return -1;
}
dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
return sock;
}
/**
Set up ipv6 multicast send socket
*/
int
ipv6_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt,
socklen_t tgt_len, int ttl)
{
int val;
struct ipv6_mreq mreq;
struct sockaddr_in6 mcast;
struct sockaddr_in6 src;
int sock;
if (tgt_len < sizeof(struct sockaddr_in6)) {
errno = EINVAL;
return -1;
}
memset(&mreq, 0, sizeof(mreq));
/* Store multicast address */
mcast.sin6_family = PF_INET6;
mcast.sin6_port = htons(port);
if (inet_pton(PF_INET6, addr,
(void *)&mcast.sin6_addr) < 0) {
printf("Invalid multicast address: %s\n", addr);
return -1;
}
memcpy(&mreq.ipv6mr_multiaddr, &mcast.sin6_addr,
sizeof(struct in6_addr));
/* Store sending address */
src.sin6_family = PF_INET6;
src.sin6_port = htons(port);
if (inet_pton(PF_INET6, send_addr,
(void *)&src.sin6_addr) < 0) {
printf("Invalid source address: %s\n", send_addr);
return -1;
}
/*************************
* SET UP MULTICAST SEND *
*************************/
dbg_printf(4, "Setting up ipv6 multicast send (%s:%d)\n", addr, port);
sock = socket(PF_INET6, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return -1;
}
dbg_printf(4, "Disabling IP Multicast loopback\n");
val = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
sizeof(val)) != 0) {
printf("Failed to disable multicast loopback\n");
close(sock);
return -1;
}
/*
* Join Multicast group.
*/
dbg_printf(4, "Joining IP Multicast group\n");
if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) == -1) {
printf("Failed to add multicast membership to transmit "
"socket %s: %s\n", addr, strerror(errno));
close(sock);
return -1;
}
/*
* Join Multicast group (part 2)
*/
/*
if (setsockopt(sock, IPPROTO_IPV6, IP_MULTICAST_IF, &src.sin6_addr,
sizeof(src.sin6_addr)) == -1) {
printf("Failed to bind multicast transmit socket to "
"%s: %s\n", addr, strerror(errno));
close(sock);
return -1;
}
*/
/*
* set time to live to 2 hops.
*/
val = ttl;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
sizeof(val)))
printf("warning: setting TTL failed %s\n", strerror(errno));
memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in6));
dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
return sock;
}
diff --git a/fence/agents/xvm/mcast.h b/fence/agents/xvm/mcast.h
index 5113f0400..08fd6deae 100644
--- a/fence/agents/xvm/mcast.h
+++ b/fence/agents/xvm/mcast.h
@@ -1,16 +1,16 @@
#ifndef _XVM_MCAST_H
#define _XVM_MCAST_H
#define IPV4_MCAST_DEFAULT "225.0.0.12"
#define IPV6_MCAST_DEFAULT "ff05::3:1"
-int ipv4_recv_sk(char *addr, int port);
+int ipv4_recv_sk(char *addr, int port, unsigned int ifindex);
int ipv4_send_sk(char *src_addr, char *addr, int port,
struct sockaddr *src, socklen_t slen,
int ttl);
-int ipv6_recv_sk(char *addr, int port);
+int ipv6_recv_sk(char *addr, int port, unsigned int ifindex);
int ipv6_send_sk(char *src_addr, char *addr, int port,
struct sockaddr *src, socklen_t slen,
int ttl);
#endif
diff --git a/fence/agents/xvm/options.c b/fence/agents/xvm/options.c
index 969ca8d5a..58b2aec0f 100644
--- a/fence/agents/xvm/options.c
+++ b/fence/agents/xvm/options.c
@@ -1,666 +1,679 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "mcast.h"
#include "options.h"
#include "debug.h"
LOGSYS_DECLARE_SUBSYS("XVM", SYSLOGLEVEL);
/* Assignment functions */
static inline void
assign_debug(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (!value) {
/* GNU getopt sets optarg to NULL for options w/o a param
We rely on this here... */
args->debug++;
return;
}
args->debug = atoi(value);
if (args->debug < 0) {
args->debug = 1;
}
}
static inline void
assign_foreground(fence_xvm_args_t *args, struct arg_info *arg,
char *value)
{
args->flags |= F_FOREGROUND;
}
static inline void
assign_family(fence_xvm_args_t *args, struct arg_info *arg,
char *value)
{
if (!strcasecmp(value, "ipv4")) {
args->family = PF_INET;
} else if (!strcasecmp(value, "ipv6")) {
args->family = PF_INET6;
} else if (!strcasecmp(value, "auto")) {
args->family = 0;
} else {
log_printf(LOG_ERR, "Unsupported family: '%s'\n", value);
args->flags |= F_ERR;
}
}
static inline void
assign_address(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (args->addr)
free(args->addr);
args->addr = strdup(value);
}
static inline void
assign_ttl(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
int ttl;
ttl = atoi(value);
if (ttl < 1 || ttl > 255)
ttl = DEFAULT_TTL;
args->ttl = ttl;
}
static inline void
assign_port(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->port = atoi(value);
if (args->port <= 0 || args->port >= 65500) {
log_printf(LOG_ERR, "Invalid port: '%s'\n", value);
args->flags |= F_ERR;
}
}
+static inline void
+assign_interface(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+ args->ifindex = if_nametoindex(value);
+}
+
+
static inline void
assign_retrans(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->retr_time = atoi(value);
if (args->retr_time <= 0) {
log_printf(LOG_ERR, "Invalid retransmit time: '%s'\n", value);
args->flags |= F_ERR;
}
}
static inline void
assign_hash(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (!strcasecmp(value, "none")) {
args->hash = HASH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = HASH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = HASH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = HASH_SHA512;
} else {
log_printf(LOG_ERR, "Unsupported hash: %s\n", value);
args->flags |= F_ERR;
}
}
static inline void
assign_auth(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (!strcasecmp(value, "none")) {
args->auth = AUTH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->auth = AUTH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->auth = AUTH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->auth = AUTH_SHA512;
} else {
log_printf(LOG_ERR, "Unsupported auth type: %s\n", value);
args->flags |= F_ERR;
}
}
static inline void
assign_key(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
struct stat st;
if (args->key_file)
free(args->key_file);
args->key_file = strdup(value);
if (stat(value, &st) == -1) {
log_printf(LOG_ERR, "Invalid key file: '%s' (%s)\n", value,
strerror(errno));
args->flags |= F_ERR;
}
}
static inline void
assign_op(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (!strcasecmp(value, "null")) {
args->op = FENCE_NULL;
} else if (!strcasecmp(value, "off")) {
args->op = FENCE_OFF;
} else if (!strcasecmp(value, "reboot")) {
args->op = FENCE_REBOOT;
} else {
log_printf(LOG_ERR, "Unsupported operation: %s\n", value);
args->flags |= F_ERR;
}
}
static inline void
assign_domain(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (args->domain) {
log_printf(LOG_ERR,
"Domain/UUID may not be specified more than once\n");
args->flags |= F_ERR;
return;
}
if (args->domain)
free(args->domain);
args->domain = strdup(value);
if (strlen(value) <= 0) {
log_printf(LOG_ERR, "Invalid domain name\n");
args->flags |= F_ERR;
}
if (strlen(value) >= MAX_DOMAINNAME_LENGTH) {
errno = ENAMETOOLONG;
log_printf(LOG_ERR, "Invalid domain name: '%s' (%s)\n",
value, strerror(errno));
args->flags |= F_ERR;
}
}
static inline void
assign_uuid_lookup(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (!value) {
/* GNU getopt sets optarg to NULL for options w/o a param
We rely on this here... */
args->flags |= F_USE_UUID;
return;
}
args->flags |= ( !!atoi(value) ? F_USE_UUID : 0);
}
static inline void
assign_timeout(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->timeout = atoi(value);
if (args->timeout <= 0) {
log_printf(LOG_ERR, "Invalid timeout: '%s'\n", value);
args->flags |= F_ERR;
}
}
static inline void
assign_help(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->flags |= F_HELP;
}
static inline void
assign_version(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->flags |= F_VERSION;
}
static inline void
assign_noccs(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->flags |= F_NOCCS;
}
static inline void
assign_nocluster(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
args->flags |= F_NOCLUSTER;
}
static inline void
assign_uri(fence_xvm_args_t *args, struct arg_info *arg, char *value)
{
if (args->uri)
free(args->uri);
/* XXX NO validation yet */
args->uri = strdup(value);
}
/** ALL valid command line and stdin arguments for this fencing agent */
static struct arg_info _arg_info[] = {
{ '\xff', NULL, "agent",
"Not user serviceable",
NULL },
{ '\xff', NULL, "self",
"Not user serviceable",
NULL },
{ 'd', "-d", "debug",
"Specify (CCS) / increment (command line) debug level",
assign_debug },
{ 'f', "-f", NULL,
"Foreground mode (do not fork)",
assign_foreground },
{ 'i', "-i <family>", "ip_family",
"IP Family ([auto], ipv4, ipv6)",
assign_family },
{ 'a', "-a <address>", "multicast_address",
"Multicast address (default=225.0.0.12 / ff02::3:1)",
assign_address },
{ 'T', "-T <ttl>", "multicast_ttl",
"Multicast time-to-live (in hops; default=2)",
assign_ttl },
{ 'p', "-p <port>", "port",
"IP port (default=1229)",
assign_port },
+ { 'I', "-I <interface>", "multicast_address",
+ "Network interface name to listen on",
+ assign_interface },
+
{ 'r', "-r <retrans>", "retrans",
"Multicast retransmit time (in 1/10sec; default=20)",
assign_retrans },
{ 'c', "-c <hash>", "hash",
"Packet hash strength (none, sha1, [sha256], sha512)",
assign_hash },
{ 'C', "-C <auth>", "auth",
"Authentication (none, sha1, [sha256], sha512)",
assign_auth },
{ 'k', "-k <file>", "key_file",
"Shared key file (default=" DEFAULT_KEY_FILE ")",
assign_key },
{ 'o', "-o <operation>", "option",
"Fencing operation (null, off, [reboot])",
assign_op },
{ 'H', "-H <domain>", "domain",
"Xen host (domain name) to fence",
assign_domain },
{ 'u', "-u", "use_uuid",
"Treat <domain> as UUID instead of domain name",
assign_uuid_lookup },
{ 't', "-t <timeout>", "timeout",
"Fencing timeout (in seconds; default=30)",
assign_timeout },
{ 'h', "-h", NULL,
"Help",
assign_help },
{ '?', "-?", NULL,
"Help (alternate)",
assign_help },
{ 'X', "-X", NULL,
"Do not connect to CCS for configuration",
assign_noccs },
{ 'L', "-L", NULL,
"Local mode only (no cluster)",
assign_nocluster },
{ 'U', "-U", "uri",
"URI for Hypervisor (default: " DEFAULT_HYPERVISOR_URI ")",
assign_uri },
{ 'V', "-V", NULL,
"Display version and exit",
assign_version },
/* Terminator */
{ 0, NULL, NULL, NULL, NULL }
};
struct arg_info *
find_arg_by_char(char arg)
{
int x = 0;
for (x = 0; _arg_info[x].opt != 0; x++) {
if (_arg_info[x].opt == arg)
return &_arg_info[x];
}
return NULL;
}
struct arg_info *
find_arg_by_string(char *arg)
{
int x = 0;
for (x = 0; _arg_info[x].opt != 0; x++) {
if (!_arg_info[x].stdin_opt)
continue;
if (!strcasecmp(_arg_info[x].stdin_opt, arg))
return &_arg_info[x];
}
return NULL;
}
/* ============================================================= */
/**
Initialize an args structure.
@param args Pointer to args structure to initialize.
*/
void
args_init(fence_xvm_args_t *args)
{
args->addr = NULL;
args->domain = NULL;
args->key_file = strdup(DEFAULT_KEY_FILE);
args->uri = strdup(DEFAULT_HYPERVISOR_URI);
args->op = FENCE_REBOOT;
args->hash = DEFAULT_HASH;
args->auth = DEFAULT_AUTH;
args->port = 1229;
+ args->ifindex = 0;
args->family = PF_INET;
args->timeout = 30;
args->retr_time = 20;
args->flags = 0;
args->debug = 0;
args->ttl = DEFAULT_TTL;
}
#define _pr_int(piece) dbg_printf(1, " %s = %d\n", #piece, piece)
#define _pr_str(piece) dbg_printf(1, " %s = %s\n", #piece, piece)
/**
Prints out the contents of an args structure for debugging.
@param args Pointer to args structure to print out.
*/
void
args_print(fence_xvm_args_t *args)
{
dbg_printf(1, "-- args @ %p --\n", args);
_pr_str(args->addr);
_pr_str(args->domain);
_pr_str(args->key_file);
_pr_int(args->op);
_pr_int(args->hash);
_pr_int(args->auth);
_pr_int(args->port);
+ _pr_int(args->ifindex);
_pr_int(args->family);
_pr_int(args->timeout);
_pr_int(args->retr_time);
_pr_int(args->flags);
_pr_int(args->debug);
dbg_printf(1, "-- end args --\n");
}
/**
Print out arguments and help information based on what is allowed in
the getopt string optstr.
TODO use log_printf instead of printf
@param progname Program name.
@param optstr Getopt(3) style options string
@param print_stdin 0 = print command line options + description,
1 = print fence-style stdin args + description
*/
void
args_usage(char *progname, char *optstr, int print_stdin)
{
int x;
struct arg_info *arg;
if (!print_stdin) {
if (progname) {
printf("usage: %s [args]\n", progname);
} else {
printf("usage: fence_xvm [args]\n");
}
}
for (x = 0; x < strlen(optstr); x++) {
arg = find_arg_by_char(optstr[x]);
if (!arg)
continue;
if (print_stdin) {
if (arg && arg->stdin_opt)
printf(" %-20.20s %-55.55s\n",
arg->stdin_opt, arg->desc);
} else {
printf(" %-20.20s %-55.55s\n", arg->opt_desc,
arg->desc);
}
}
printf("\n");
}
/**
Remove leading and trailing whitespace from a line of text.
@param line Line to clean up
@param linelen Max size of line
@return 0 on success, -1 on failure
*/
int
cleanup(char *line, size_t linelen)
{
char *p;
int x;
/* Remove leading whitespace. */
p = line;
for (x = 0; x <= linelen; x++) {
switch (line[x]) {
case '\t':
case ' ':
break;
case '\n':
case '\r':
return -1;
default:
goto eol;
}
}
eol:
/* Move the remainder down by as many whitespace chars as we
chewed up */
if (x)
memmove(p, &line[x], linelen-x);
/* Remove trailing whitespace. */
for (x=0; x <= linelen; x++) {
switch(line[x]) {
case '\t':
case ' ':
case '\r':
case '\n':
line[x] = 0;
case 0:
/* End of line */
return 0;
}
}
return -1;
}
/**
Parse args from stdin and assign to the specified args structure.
@param optstr Command line option string in getopt(3) format
@param args Args structure to fill in.
*/
void
args_get_stdin(char *optstr, fence_xvm_args_t *args)
{
char in[256];
int line = 0;
char *name, *val;
struct arg_info *arg;
while (fgets(in, sizeof(in), stdin)) {
++line;
if (in[0] == '#')
continue;
if (cleanup(in, sizeof(in)) == -1)
continue;
name = in;
if ((val = strchr(in, '='))) {
*val = 0;
++val;
}
arg = find_arg_by_string(name);
if (!arg || (arg->opt != '\xff' &&
!strchr(optstr, arg->opt))) {
fprintf(stderr,
"parse warning: "
"illegal variable '%s' on line %d\n", name,
line);
continue;
}
if (arg->assign)
arg->assign(args, arg, val);
}
}
/**
Parse args from stdin and assign to the specified args structure.
@param optstr Command line option string in getopt(3) format
@param args Args structure to fill in.
*/
void
args_get_getopt(int argc, char **argv, char *optstr, fence_xvm_args_t *args)
{
int opt;
struct arg_info *arg;
while ((opt = getopt(argc, argv, optstr)) != EOF) {
arg = find_arg_by_char(opt);
if (!arg) {
args->flags |= F_ERR;
continue;
}
if (arg->assign)
arg->assign(args, arg, optarg);
}
}
void
args_finalize(fence_xvm_args_t *args)
{
char *addr = NULL;
if (!args->addr) {
switch(args->family) {
case 0:
case PF_INET:
addr = IPV4_MCAST_DEFAULT;
break;
case PF_INET6:
addr = IPV6_MCAST_DEFAULT;
break;
default:
args->flags |= F_ERR;
break;
}
}
if (!args->addr)
args->addr = addr;
if (!args->addr) {
printf("No multicast address available\n");
args->flags |= F_ERR;
}
if (!args->addr)
return;
if (args->family)
return;
/* Set family */
if (strchr(args->addr, ':'))
args->family = PF_INET6;
if (strchr(args->addr, '.'))
args->family = PF_INET;
if (!args->family) {
printf("Could not determine address family\n");
args->flags |= F_ERR;
}
}
diff --git a/fence/agents/xvm/options.h b/fence/agents/xvm/options.h
index 7a2dccaba..07f99da92 100644
--- a/fence/agents/xvm/options.h
+++ b/fence/agents/xvm/options.h
@@ -1,55 +1,56 @@
#ifndef _XVM_OPTIONS_H
#define _XVM_OPTIONS_H
typedef enum {
F_FOREGROUND = 0x1,
F_NOCCS = 0x2,
F_ERR = 0x4,
F_HELP = 0x8,
F_USE_UUID = 0x10,
F_VERSION = 0x20,
F_CCSERR = 0x40,
F_CCSFAIL = 0x80,
F_NOCLUSTER = 0x100
} arg_flags_t;
typedef struct {
char *addr;
char *domain;
char *key_file;
char *uri;
fence_cmd_t op;
fence_hash_t hash;
fence_auth_type_t auth;
int port;
+ unsigned int ifindex;
int family;
int timeout;
int retr_time;
arg_flags_t flags;
int debug;
int ttl;
} fence_xvm_args_t;
/* Private structure for commandline / stdin fencing args */
struct arg_info {
char opt;
char *opt_desc;
char *stdin_opt;
char *desc;
void (*assign)(fence_xvm_args_t *, struct arg_info *, char *);
};
/* Get options */
void args_init(fence_xvm_args_t *args);
void args_finalize(fence_xvm_args_t *args);
void args_get_getopt(int argc, char **argv, char *optstr,
fence_xvm_args_t *args);
void args_get_stdin(char *optstr, fence_xvm_args_t *args);
void args_get_ccs(char *optstr, fence_xvm_args_t *args);
void args_usage(char *progname, char *optstr, int print_stdin);
void args_print(fence_xvm_args_t *args);
#endif
diff --git a/fence/man/fence_xvmd.8 b/fence/man/fence_xvmd.8
index 5a4721150..12af6073f 100644
--- a/fence/man/fence_xvmd.8
+++ b/fence/man/fence_xvmd.8
@@ -1,117 +1,120 @@
.TH fence_xvmd 8
.SH NAME
fence_xvmd - I/O Fencing agent host for Xen virtual machines.
.SH SYNOPSIS
.B
fence_xvmd
[\fIOPTION\fR]...
.SH DESCRIPTION
fence_xvmd is an I/O Fencing host which resides on dom0 and is used in
conjunction with the fence_xvm fencing agent. Together, these two programs
can be used to fence can be used to fence Xen virtual machines which are
part of a cluster. There is a requirement that the parent
dom0s are also a part of their own CMAN/OpenAIS based cluster, and that
the dom0 cluster does not share any members with the domU cluster.
Furthermore, the dom0 cluster is required to have fencing if domU recovery
is expected to be automatic.
fence_xvmd accepts options on the command line.
.SH OPTIONS
.TP
\fB-f\fP
Foreground mode (do not fork)
.TP
\fB-d\fP
Enable debugging output. The more times you specify this parameter,
the more debugging output you will receive.
.TP
\fB-i\fP \fIfamily\fP
IP family to use (auto, ipv4, or ipv6; default = auto)
.TP
\fB-a\fP \fIaddress\fP
Multicast address to listen on (default=225.0.0.12 for ipv4, ff02::3:1
for ipv6)
.TP
\fB-p\fP \fIport\fP
Port to use (default=1229)
.TP
+\fB-I\fP \fIinterface\fP
+Network interface to listen on, e.g. eth0.
+.TP
\fB-C\fP \fIauth\fP
Authentication type (none, sha1, sha256, sha512; default=sha256). This
controls the authentication mechanism used to authenticate clients. The
three SHA hashes use a key which must be shared between both the Xen virtual
machines and the host domain-0 cluster. The three SHA authentication
mechanisms use a simple bidirectional challenge-response based on pseudo-
random number generation and a shared private key.
.TP
\fB-c\fP \fIhash\fP
Packet hash type (none, sha1, sha256, sha512; default=sha256). This
controls the hashing mechanism used to authenticate fencing requests. The
three SHA hashes use a key which must be shared between both the Xen virtual
machines and the host domain-0 cluster.
.TP
\fB-k\fP \fIkey_file\fP
Use the specified key file for packet hashing / SHA authentication.
When both the hash type and the authentication type are set to "none",
this parameter is ignored.
.TP
\fB-u\fP
Fence by UUID instead of Xen Domain name.
.TP
\fB-?\fP
Print out a help message describing available options, then exit.
.TP
\fB-h\fP
Print out a help message describing available options, then exit.
.TP
\fB-X\fP
Do not connect to CCS for configuration; only use command line
parameters. CCS configuration parameters override command line
parameters (because they are cluster-wide), so if you need to
override a configuration option contained in CCS, you must specify
this parameter.
\fB-V\fP
.TP
\fB-L\fP
Local-only / non-cluster mode. When used with -X, this this option
prevents fence_xvmd from operating as a clustered service, obviating
the need to configure/run CMAN on the host domain.
.TP
\fB-V\fP
Print out a version message, then exit.
.SH CCS PARAMETERS
CCS options are simply attributes of the <fence_xvmd> tag, a
child of the <cluster> tag in /etc/cluster/cluster.conf.
.TP
\fIdebug="1"\fR
Same as the -d option. Specify numbers >1 for more debugging information.
.TP
\fIfamily="param"\fR
Same as the -i option.
.TP
\fImulticast_address="param"\fR
Same as the -a option.
.TP
\fIport="param"\fR
Same as the -p option.
.TP
\fIauth="param"\fR
Same as the -C option.
.TP
\fIhash="param"\fR
Same as the -c option.
.TP
\fIkey_file="param"\fR
Same as the -k option.
.TP
\fIuse_uuid="1"\fR
Same as the -u option.
.TP
.SH SEE ALSO
fence(8), fence_node(8), fence_xvm(8)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 11:07 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018643
Default Alt Text
(52 KB)
Attached To
Mode
rR Resource Agents
Attached
Detach File
Event Timeline
Log In to Comment