Enable VM Channel support in serial plugin

- Add cmdline processing for channel_ip
- Allow 'port' to be used in fence_virt mode
- Allow configuration of vmchannel mode for fence_virtd
  serial plugin
- Remove serial port default from fence_virt.
  It must now be specified or else VM Channel mode
  is used.  Note that to use VM Channel mode, you need:
    qemu 0.12.1 or later
    libvirt 0.7.3 or later
- Update man pages

Signed-off-by: Lon Hohberger <lon@users.sourceforge.net>
This commit is contained in:
Lon Hohberger 2010-01-13 23:34:35 -05:00
parent 4602faeaf2
commit f665796f26
10 changed files with 232 additions and 82 deletions

View File

@ -59,7 +59,7 @@ main(int argc, char **argv)
my_options = "di:a:p:r:C:c:k:M:H:uo:t:?hV";
args.mode = MODE_MULTICAST;
} else {
my_options = "dD:P:M:H:o:t:?hV";
my_options = "dD:P:A:p:M:H:o:t:?hV";
args.mode = MODE_SERIAL;
}

View File

@ -97,6 +97,15 @@ assign_address(fence_virt_args_t *args, struct arg_info *arg, char *value)
}
static inline void
assign_channel_address(fence_virt_args_t *args, struct arg_info *arg, char *value)
{
if (args->serial.address)
free(args->serial.address);
args->serial.address = strdup(value);
}
static inline void
assign_port(fence_virt_args_t *args, struct arg_info *arg, char *value)
{
@ -319,8 +328,12 @@ static struct arg_info _arg_info[] = {
"Multicast address (default=" IPV4_MCAST_DEFAULT " / " IPV6_MCAST_DEFAULT ")",
assign_address },
{ 'A', "-A <address>", "channel_address",
"VM Channel IP address (default=" DEFAULT_CHANNEL_IP ")",
assign_channel_address },
{ 'p', "-p <port>", "port",
"IP port (default=1229)",
"Multicast or VMChannel IP port (default=1229)",
assign_port },
{ 'I', "-I <interface>", "interface",
@ -443,8 +456,9 @@ args_init(fence_virt_args_t *args)
args->net.port = DEFAULT_MCAST_PORT;
args->net.ifindex = 0;
args->net.family = PF_INET;
args->serial.device = strdup(DEFAULT_SERIAL_DEVICE);
args->serial.device = NULL;
args->serial.speed = strdup(DEFAULT_SERIAL_SPEED);
args->serial.address = strdup(DEFAULT_CHANNEL_IP);
args->timeout = 30;
args->retr_time = 20;
args->flags = 0;

View File

@ -25,6 +25,8 @@
#include <xvm.h>
#include <options.h>
#include <client.h>
#include <arpa/inet.h>
#include <tcp.h>
static int
@ -212,28 +214,46 @@ wait_for(int fd, const char *pattern, size_t size, struct timeval *tout)
int
serial_fence_virt(fence_virt_args_t *args)
{
struct in_addr ina;
struct in6_addr in6a;
serial_req_t req;
int fd, ret;
char speed[32], *flags = NULL;
struct timeval tv;
serial_resp_t resp;
strncpy(speed, args->serial.speed, sizeof(speed));
if (args->serial.device) {
strncpy(speed, args->serial.speed, sizeof(speed));
//printf("Port: %s Speed: %s\n", args->serial.device, speed);
//printf("Port: %s Speed: %s\n", args->serial.device, speed);
if ((flags = strchr(speed, ','))) {
*flags = 0;
flags++;
if ((flags = strchr(speed, ','))) {
*flags = 0;
flags++;
}
fd = open_port(args->serial.device, speed, flags);
if (fd == -1) {
perror("open_port");
return -1;
}
hangup(fd, 300000);
} else {
fd = -1;
if (inet_pton(PF_INET, args->serial.address, &ina)) {
fd = ipv4_connect(&ina, args->net.port, 3);
} else if (inet_pton(PF_INET6, args->serial.address, &in6a)) {
fd = ipv6_connect(&in6a, args->net.port, 3);
}
if (fd < 0) {
perror("vmchannel connect");
printf("Failed to connect to %s:%d\n", args->serial.address,
args->net.port);
}
}
fd = open_port(args->serial.device, speed, flags);
if (fd == -1) {
perror("open_port");
return -1;
}
hangup(fd, 300000);
memset(&req, 0, sizeof(req));
req.magic = SERIAL_MAGIC;
@ -241,8 +261,6 @@ serial_fence_virt(fence_virt_args_t *args)
gettimeofday(&tv, NULL);
req.seqno = (int)tv.tv_usec;
if (args->flags & RF_UUID)
req.flags |= RF_UUID;
if (args->domain)
strncpy((char *)req.domain, args->domain, sizeof(req.domain));

View File

@ -60,6 +60,7 @@ typedef struct {
struct serial_args {
char *device; /* Serial device */
char *speed;
char *address; /* vmchannel IP */
} serial;
} fence_virt_args_t;

View File

@ -96,6 +96,7 @@ typedef struct __attribute__ ((packed)) _host_info {
#define DEFAULT_SERIAL_DEVICE "/dev/ttyS1"
#define DEFAULT_SERIAL_SPEED "115200,8N1"
#define DEFAULT_CHANNEL_IP "10.0.2.179"
#define SERIAL_MAGIC 0x61626261 /* endian doesn't matter */
typedef struct __attribute__((packed)) _serial_fence_req {

View File

@ -27,7 +27,7 @@ machines from scripts.
.TP
.B -d
.
Specify (CCS) / increment (command line) debug level
Increment (command line) debug level
.TP
.B -H
@ -37,12 +37,12 @@ Virtual machine (domain name) to fence
.TP
.B -o
.
Fencing action (null, off, on, [reboot], status, devstatus, or hostlist) (Default Value: reboot)
Fencing action (null, off, on, reboot, status, devstatus, or hostlist) (Default Value: reboot)
.TP
.B -t
.
Fencing timeout (in seconds; default=30) (Default Value: 30)
Fencing timeout (in seconds) (Default Value: 30)
.SH MULTICAST PARAMETERS
These parameters are used only when using fence_virt in multicast mode
@ -51,37 +51,37 @@ These parameters are used only when using fence_virt in multicast mode
.TP
.B -i
.
IP Family ([auto], ipv4, ipv6) (Default Value: auto)
IP Family (auto, ipv4, ipv6) (Default Value: auto)
.TP
.B -a
.
Multicast address (default=225.0.0.12 / ff02::3:1)
Multicast address (Default Values: 225.0.0.12 / ff02::3:1)
.TP
.B -p
.
IP port (default=1229) (Default Value: 1229)
IP port (Default Value: 1229)
.TP
.B -T
.
Multicast time-to-live (in hops; default=2) (Default Value: 2)
Multicast time-to-live (in hops) (Default Value: 2)
.TP
.B -r
.
Multicast retransmit time (in 1/10sec; default=20) (Default Value: 20)
Multicast retransmit time (in 1/10sec) (Default Value: 20)
.TP
.B -C
.
Authentication (none, sha1, [sha256], sha512) (Default Value: sha256)
Authentication (none, sha1, sha256, sha512) (Default Value: sha256)
.TP
.B -c
.
Packet hash strength (none, sha1, [sha256], sha512) (Default Value: sha256)
Packet hash strength (none, sha1, sha256, sha512) (Default Value: sha256)
.TP
.B -k
@ -93,21 +93,31 @@ Shared key file (Default Value: /etc/cluster/fence_xvm.key)
.
Treat 'domain' as UUID instead of domain name.
.SH MULTICAST PARAMETERS
.SH SERIAL/VMCHANNEL PARAMETERS
These parameters are used only when using fence_virt in multicast mode
(e.g. by running fence_xvm).
.TP
.B -D
.
Serial device (fence_virt mode). Default=/dev/ttyS1. On the host, the
serial device must be mapped in each domain's configuration file. See
fence_virt.conf(5) for more information.
Serial device (fence_virt mode). On the host, the serial device must
be mapped in each domain's configuration file. See fence_virt.conf(5)
for more information. Specifying a serial device causes fence_virt
to use serial mode (as opposed to VMChannel mode).
.TP
.B -P
.
Serial parameters. Default=115200,8N1
Serial parameters. (Default Value: 115200,8N1)
.TP
.B -A
VMChannel IP address (Default Value: 10.0.2.179)
.TP
.B -p
.
VMChannel IP port (Default Value: 1229)
.SH GENERAL STDIN PARAMETERS
These parameters are passed to fence_virt via standard input if
@ -134,7 +144,7 @@ Fencing action to perform (See FENCING ACTIONS section)
.TP
.B timeout
.
Fencing timeout (in seconds; default=30) (Default Value: 30)
Fencing timeout (in seconds) (Default Value: 30)
.SH MULTICAST STDIN PARAMETERS
.TP
@ -145,56 +155,69 @@ IP Family ([auto], ipv4, ipv6) (Default Value: auto)
.TP
.B multicast_address
.
Multicast address (default=225.0.0.12 / ff02::3:1)
Multicast address (Defaults: 225.0.0.12 / ff02::3:1)
.TP
.B port
.
IP port (default=1229) (Default Value: 1229)
IP port (Default Value: 1229)
.TP
.B multicast_ttl
.
Multicast time-to-live (in hops; default=2) (Default Value: 2)
Multicast time-to-live (in hops) (Default Value: 2)
.TP
.B retrans
.
Multicast retransmit time (in 1/10sec; default=20) (Default Value: 20)
Multicast retransmit time (in 1/10sec) (Default Value: 20)
.TP
.B auth
.
Authentication (none, sha1, [sha256], sha512) (Default Value: sha256)
Authentication (none, sha1, sha256, sha512) (Default Value: sha256)
.TP
.B hash
.
Packet hash strength (none, sha1, [sha256], sha512) (Default Value: sha256)
Packet hash strength (none, sha1, sha256, sha512) (Default Value: sha256)
.TP
.B key_file
.
Shared key file (default=/etc/cluster/fence_xvm.key) (Default Value: /etc/cluster/fence_xvm.key)
Shared key file (Default Value: /etc/cluster/fence_xvm.key)
.TP
.B use_uuid
.
Treat 'domain' as UUID instead of domain name
.SH SERIAL STDIN PARAMETERS
.SH SERIAL/VMCHANNEL STDIN PARAMETERS
.TP
.B serial_device
.
Serial device. Default=/dev/ttyS1. On the host, the serial device must
be mapped in each domain's configuration file. See fence_virt.conf(5)
for more information.
Serial device. On the host, the serial device must be mapped in
each domain's configuration file. See fence_virt.conf(5)
for more information. If specified, causes fence_virt to operate
in serial mode (not specifying causes fence_virt to operate in
VM Channel mode).
.TP
.B serial_params
.
Serial parameters. Default=115200,8N1.
.TP
.B channel_ip
.
Channel IP. Default=10.0.2.179
.TP
.B port
.
Channel port. Default=1229
.SH FENCING ACTIONS
.TP

View File

@ -73,10 +73,6 @@ There are various listeners available for fence_virtd, each one handles
decoding and authentication of a given fencing request. The following
configuration blocks belong in the \fBlisteners\fP section of fence_virtd.conf
.SS vmchannel
To be done. This listener utilizes serial vmchannel tied to Unix domain
sockets on the host in order to receive and route fencing requests.
.SS multicast
.TP
.B key_file
@ -119,23 +115,25 @@ is used as a gateway.
.SS serial
The serial listener plugin utilizes libvirt's serial mapping to listen
for requests. When using the serial listener, it is necessary to add
a serial port (preferably pointing to /dev/ttyS1) in the libvirt domain
description. Note that only serial type
The serial listener plugin utilizes libvirt's serial (or VMChannel)
mapping to listen for requests. When using the serial listener, it is
necessary to add a serial port (preferably pointing to /dev/ttyS1) or
a channel (preferrably pointing to 10.0.2.179:1229) to the
libvirt domain description. Note that only type
.B unix
, mode
.B bind
is supported. The socket path does not matter, and currently, fence_virt
will only use the
.B first specified
virtual serial port of this type. Example libvirt XML:
serial ports and channels are supported. Example libvirt XML:
.in 8
<serial type='unix'>
<\fBserial\fP type='unix'>
<source mode='bind' path='/sandbox/guests/fence_socket_molly'/>
<target port='1'/>
</serial>
<\fBchannel\fP type='unix'>
<source mode='bind' path='/sandbox/guests/fence_molly_vmchannel'/>
<target type='guestfwd' address='10.0.2.179' port='1229'/>
</serial>
.in 0
.TP
@ -143,6 +141,19 @@ virtual serial port of this type. Example libvirt XML:
.
the URI to use when connecting to libvirt by the serial plugin.
.TP
.B path
.
Sockets must reside in this directory in order to be considered
valid. This can be used to prevent fence_virtd from using the wrong
sockets.
.TP
.B mode
.
This selects the type of sockets to register. Valid values are "serial"
(default) and "vmchannel".
.SH BACKENDS

View File

@ -71,8 +71,10 @@ typedef struct _serial_info {
const fence_callbacks_t *cb;
void *priv;
char *uri;
char *path;
history_info_t *history;
void *maps;
int mode;
} serial_info;
@ -260,12 +262,16 @@ serial_dispatch(listener_context_t c, struct timeval *timeout)
if (n == 0)
return 0;
printf("max = %d\n", max);
/* find & read request */
for (x = 0; x <= max; x++) {
if (FD_ISSET(x, &rfds)) {
tv.tv_sec = 1;
tv.tv_usec = 0;
printf("Reading from %d\n", x);
ret = _read_retry(x, &data, sizeof(data), &tv);
if (ret != sizeof(data)) {
@ -314,6 +320,29 @@ serial_config(config_object_t *config, serial_info *args)
args->uri = strdup(value);
}
if (sc_get(config, "listeners/serial/@path",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for uri\n", value);
args->path = strdup(value);
}
if (sc_get(config, "listeners/serial/@mode",
value, sizeof(value)-1) == 0) {
if (!strcasecmp(value, "vmchannel")) {
args->mode = 1;
} else if (!strcasecmp(value, "serial")) {
args->mode = 0;
} else {
args->mode = atoi(value);
if (args->mode < 0)
args->mode = 0;
}
dbg_printf(1, "Got %s for mode\n",
args->mode?"VMChannel":"serial");
}
return errors;
}
@ -347,7 +376,7 @@ serial_init(listener_context_t *c, const fence_callbacks_t *cb,
info->magic = SERIAL_PLUG_MAGIC;
info->history = history_init(check_history, 10, sizeof(fence_req_t));
*c = (listener_context_t)info;
start_event_listener(info->uri);
start_event_listener(info->uri, info->path, info->mode);
sleep(1);
return 0;
@ -366,6 +395,7 @@ serial_shutdown(listener_context_t c)
stop_event_listener();
domain_sock_cleanup();
free(info->uri);
free(info->path);
free(info);
return 0;

View File

@ -18,7 +18,7 @@ int static_map_check(void *info, const char *value1, const char *value2);
int static_map_init(config_object_t *config, void **perm_info);
/* virt-serial.c - event thread control functions */
int start_event_listener(const char *uri);
int start_event_listener(const char *uri, const char *path, int mode);
int stop_event_listener(void);

View File

@ -185,13 +185,14 @@ myEventRemoveTimeoutFunc(int timer)
static int
domainStarted(virDomainPtr mojaDomain)
domainStarted(virDomainPtr mojaDomain, const char *path, int mode)
{
char dom_uuid[42];
char *xml;
xmlDocPtr doc;
xmlNodePtr cur, devices, child, serial;
xmlAttrPtr attr, attr_mode, attr_path;
size_t path_len = 0;
if (!mojaDomain)
return -1;
@ -200,6 +201,8 @@ domainStarted(virDomainPtr mojaDomain)
xml = virDomainGetXMLDesc(mojaDomain, 0);
// printf("%s\n", xml);
if (path)
path_len = strlen(path);
// @todo: free mojaDomain
@ -229,7 +232,9 @@ domainStarted(virDomainPtr mojaDomain)
for (child = devices->xmlChildrenNode; child != NULL;
child = child->next) {
if (xmlStrcmp(child->name, (const xmlChar *) "serial")) {
if ((!mode && xmlStrcmp(child->name, (const xmlChar *) "serial")) ||
(mode && xmlStrcmp(child->name, (const xmlChar *) "channel"))) {
continue;
}
@ -252,13 +257,25 @@ domainStarted(virDomainPtr mojaDomain)
attr_mode = xmlHasProp(serial, (const xmlChar *)"mode");
attr_path = xmlHasProp(serial, (const xmlChar *)"path");
if ((attr_path != NULL) &&
(attr_mode != NULL) &&
(!xmlStrcmp(attr_mode->children->content,
(const xmlChar *) "bind"))) {
domain_sock_setup(dom_uuid, (const char *)
attr_path->children->content);
if (!attr_path || !attr_mode)
continue;
if (xmlStrcmp(attr_mode->children->content,
(const xmlChar *) "bind"))
continue;
if (path) {
if (xmlStrlen(attr_path->children->content) <
path_len)
continue;
if (strncmp(attr_path->children->content,
path, path_len))
continue;
}
domain_sock_setup(dom_uuid, (const char *)
attr_path->children->content);
}
}
}
@ -268,7 +285,7 @@ domainStarted(virDomainPtr mojaDomain)
}
static int
registerExisting(virConnectPtr vp)
registerExisting(virConnectPtr vp, const char *path, int mode)
{
int *d_ids = NULL;
int d_count, x;
@ -312,7 +329,7 @@ registerExisting(virConnectPtr vp)
if (d_info.state != VIR_DOMAIN_SHUTOFF &&
d_info.state != VIR_DOMAIN_CRASHED)
domainStarted(dom);
domainStarted(dom, path, mode);
virDomainFree(dom);
}
@ -337,15 +354,28 @@ domainStopped(virDomainPtr mojaDomain)
}
struct event_args {
char *uri;
char *path;
int mode;
};
static void *
event_thread(void *arg)
{
struct event_args *args = (struct event_args *)arg;
virConnectPtr dconn = NULL;
struct domain_info dinfo;
int sts;
int callback1ret = -1;
int sts;
dbg_printf(3,"Event listener starting \n");
dbg_printf(3, "Libvirt event listener starting\n");
if (args->uri)
dbg_printf(3," * URI: %s\n", args->uri);
if (args->path)
dbg_printf(3," * Socket path: %s\n", args->path);
dbg_printf(3," * Mode: %s\n", args->mode?"VMChannel":"Serial");
virEventRegisterImpl(myEventAddHandleFunc,
myEventUpdateHandleFunc,
@ -354,15 +384,15 @@ event_thread(void *arg)
myEventUpdateTimeoutFunc,
myEventRemoveTimeoutFunc);
dconn = virConnectOpen((char *)arg);
dconn = virConnectOpen(args->uri);
if (!dconn) {
dbg_printf(1, "Error connecting to libvirt\n");
return NULL;
goto out;
}
DEBUG0("Registering domain event cbs");
registerExisting(dconn);
registerExisting(dconn, args->path, args->mode);
/* Add 2 callbacks to prove this works with more than just one */
memset(&dinfo, 0, sizeof (dinfo));
@ -385,7 +415,7 @@ event_thread(void *arg)
}
if (dinfo.event == VIR_DOMAIN_EVENT_STARTED) {
domainStarted(dinfo.dom);
domainStarted(dinfo.dom, args->path, args->mode);
virDomainFree(dinfo.dom);
dinfo.dom = NULL;
dinfo.event = VIR_DOMAIN_EVENT_UNDEFINED;
@ -408,7 +438,7 @@ event_thread(void *arg)
if (pfd.revents & POLLHUP) {
DEBUG0("Reset by peer");
return NULL;
goto out;
}
if (h_cb) {
@ -428,26 +458,48 @@ event_thread(void *arg)
dbg_printf(1, "error closing libvirt connection\n");
}
out:
free(args->uri);
free(args->path);
free(args);
return NULL;
}
int
start_event_listener(const char *uri)
start_event_listener(const char *uri, const char *path, int mode)
{
char *arg = NULL;
struct event_args *args = NULL;
virInitialize();
args = malloc(sizeof(*args));
if (!args)
return -1;
memset(args, 0, sizeof(*args));
if (uri) {
arg = strdup(uri);
if (uri == NULL)
return -1;
args->uri = strdup(uri);
if (args->uri == NULL)
goto out_fail;
}
if (path) {
args->path = strdup(path);
if (args->path == NULL)
goto out_fail;
}
args->mode = mode;
run = 1;
return pthread_create(&event_tid, NULL, event_thread, arg);
return pthread_create(&event_tid, NULL, event_thread, args);
out_fail:
free(args->uri);
free(args->path);
free(args);
return -1;
}