diff --git a/client/main.c b/client/main.c
index 956020a..5b65c39 100644
--- a/client/main.c
+++ b/client/main.c
@@ -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;
}
diff --git a/client/options.c b/client/options.c
index 6816ec2..528bc74 100644
--- a/client/options.c
+++ b/client/options.c
@@ -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
", "channel_address",
+ "VM Channel IP address (default=" DEFAULT_CHANNEL_IP ")",
+ assign_channel_address },
+
{ 'p', "-p ", "port",
- "IP port (default=1229)",
+ "Multicast or VMChannel IP port (default=1229)",
assign_port },
{ 'I', "-I ", "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;
diff --git a/client/serial.c b/client/serial.c
index 3ce872d..390f4d7 100644
--- a/client/serial.c
+++ b/client/serial.c
@@ -25,6 +25,8 @@
#include
#include
#include
+#include
+#include
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));
diff --git a/include/options.h b/include/options.h
index ffacfea..5253ba9 100644
--- a/include/options.h
+++ b/include/options.h
@@ -60,6 +60,7 @@ typedef struct {
struct serial_args {
char *device; /* Serial device */
char *speed;
+ char *address; /* vmchannel IP */
} serial;
} fence_virt_args_t;
diff --git a/include/xvm.h b/include/xvm.h
index 835f961..b08d0bb 100644
--- a/include/xvm.h
+++ b/include/xvm.h
@@ -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 {
diff --git a/man/fence_virt.8 b/man/fence_virt.8
index eecb26b..862aa9a 100644
--- a/man/fence_virt.8
+++ b/man/fence_virt.8
@@ -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
diff --git a/man/fence_virt.conf.5 b/man/fence_virt.conf.5
index 6303184..1f6937d 100644
--- a/man/fence_virt.conf.5
+++ b/man/fence_virt.conf.5
@@ -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
-
+ <\fBserial\fP type='unix'>
+ <\fBchannel\fP type='unix'>
+
+
+
.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
diff --git a/server/serial.c b/server/serial.c
index b249e63..67241f7 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -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;
diff --git a/server/serial.h b/server/serial.h
index 39c9540..ef11dd1 100644
--- a/server/serial.h
+++ b/server/serial.h
@@ -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);
diff --git a/server/virt-serial.c b/server/virt-serial.c
index 681bba8..a135f12 100644
--- a/server/virt-serial.c
+++ b/server/virt-serial.c
@@ -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;
}