#include "plugin.h"
#include "configfile.h"
#include "utils_ignorelist.h"
+#include "utils_complain.h"
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
"IgnoreSelected",
"HostnameFormat",
+ "InterfaceFormat",
NULL
};
/* Connection. */
static virConnectPtr conn = 0;
+static char *conn_string = NULL;
+static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
/* Seconds between list refreshes, 0 disables completely. */
static int interval = 60;
struct interface_device {
virDomainPtr dom; /* domain */
char *path; /* name of interface device */
+ char *address; /* mac address of interface device */
};
static struct interface_device *interface_devices = NULL;
static int nr_interface_devices = 0;
static void free_interface_devices (void);
-static int add_interface_device (virDomainPtr dom, const char *path);
+static int add_interface_device (virDomainPtr dom, const char *path, const char *address);
/* HostnameFormat. */
#define HF_MAX_FIELDS 3
static enum hf_field hostname_format[HF_MAX_FIELDS] =
{ hf_name };
+/* InterfaceFormat. */
+enum if_field {
+ if_address,
+ if_name
+};
+
+static enum if_field interface_format = if_name;
+
/* Time that we last refreshed. */
static time_t last_refresh = (time_t) 0;
il_interface_devices = ignorelist_create (1);
if (strcasecmp (key, "Connection") == 0) {
- if (conn != 0) {
- ERROR ("Connection may only be given once in config file");
- return 1;
- }
- conn = virConnectOpenReadOnly (value);
- if (!conn) {
- VIRT_ERROR (NULL, "connection failed");
+ char *tmp = strdup (value);
+ if (tmp == NULL) {
+ ERROR ("libvirt plugin: Connection strdup failed.");
return 1;
}
+ sfree (conn_string);
+ conn_string = tmp;
return 0;
}
}
if (strcasecmp (key, "IgnoreSelected") == 0) {
- if (strcasecmp (value, "True") == 0 ||
- strcasecmp (value, "Yes") == 0 ||
- strcasecmp (value, "On") == 0)
+ if (IS_TRUE (value))
{
ignorelist_set_invert (il_domains, 0);
ignorelist_set_invert (il_block_devices, 0);
n = strsplit (value_copy, fields, HF_MAX_FIELDS);
if (n < 1) {
- free (value_copy);
+ sfree (value_copy);
ERROR ("HostnameFormat: no fields");
return -1;
}
else if (strcasecmp (fields[i], "uuid") == 0)
hostname_format[i] = hf_uuid;
else {
- free (value_copy);
+ sfree (value_copy);
ERROR ("unknown HostnameFormat field: %s", fields[i]);
return -1;
}
}
- free (value_copy);
+ sfree (value_copy);
for (i = n; i < HF_MAX_FIELDS; ++i)
hostname_format[i] = hf_none;
return 0;
}
+ if (strcasecmp (key, "InterfaceFormat") == 0) {
+ if (strcasecmp (value, "name") == 0)
+ interface_format = if_name;
+ else if (strcasecmp (value, "address") == 0)
+ interface_format = if_address;
+ else {
+ ERROR ("unknown InterfaceFormat: %s", value);
+ return -1;
+ }
+ return 0;
+ }
+
/* Unrecognised option. */
return -1;
}
int i;
if (conn == NULL) {
- ERROR ("libvirt plugin: Not connected. Use Connection in "
- "config file to supply connection URI. For more information "
- "see <http://libvirt.org/uri.html>");
- return -1;
+ /* `conn_string == NULL' is acceptable. */
+ conn = virConnectOpenReadOnly (conn_string);
+ if (conn == NULL) {
+ c_complain (LOG_ERR, &conn_complain,
+ "libvirt plugin: Unable to connect: "
+ "virConnectOpenReadOnly failed.");
+ return -1;
+ }
}
+ c_release (LOG_NOTICE, &conn_complain,
+ "libvirt plugin: Connection established.");
time (&t);
/* Need to refresh domain or device lists? */
if ((last_refresh == (time_t) 0) ||
((interval > 0) && ((last_refresh + interval) <= t))) {
- if (refresh_lists () != 0)
+ if (refresh_lists () != 0) {
+ if (conn != NULL)
+ virConnectClose (conn);
+ conn = NULL;
return -1;
+ }
last_refresh = t;
}
if (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
NULL, 0) != 0) {
- free (vinfo);
+ sfree (vinfo);
continue;
}
vcpu_submit (vinfo[j].cpuTime,
t, domains[i], vinfo[j].number, "virt_vcpu");
- free (vinfo);
+ sfree (vinfo);
}
/* Get block device stats for each domain. */
/* Get interface stats for each domain. */
for (i = 0; i < nr_interface_devices; ++i) {
struct _virDomainInterfaceStats stats;
+ char *display_name = interface_devices[i].path;
+
+ if (interface_format == if_address)
+ display_name = interface_devices[i].address;
if (virDomainInterfaceStats (interface_devices[i].dom,
interface_devices[i].path,
if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
submit_counter2 ("if_octets",
(counter_t) stats.rx_bytes, (counter_t) stats.tx_bytes,
- t, interface_devices[i].dom, interface_devices[i].path);
+ t, interface_devices[i].dom, display_name);
if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
submit_counter2 ("if_packets",
(counter_t) stats.rx_packets, (counter_t) stats.tx_packets,
- t, interface_devices[i].dom, interface_devices[i].path);
+ t, interface_devices[i].dom, display_name);
if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
submit_counter2 ("if_errors",
(counter_t) stats.rx_errs, (counter_t) stats.tx_errs,
- t, interface_devices[i].dom, interface_devices[i].path);
+ t, interface_devices[i].dom, display_name);
if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
submit_counter2 ("if_dropped",
(counter_t) stats.rx_drop, (counter_t) stats.tx_drop,
- t, interface_devices[i].dom, interface_devices[i].path);
+ t, interface_devices[i].dom, display_name);
} /* for (nr_interface_devices) */
return 0;
n = virConnectListDomains (conn, domids, n);
if (n < 0) {
VIRT_ERROR (conn, "reading list of domains");
- free (domids);
+ sfree (domids);
return -1;
}
/* Network interfaces. */
xpath_obj = xmlXPathEval
- ((xmlChar *) "/domain/devices/interface/target[@dev]",
+ ((xmlChar *) "/domain/devices/interface[target[@dev]]",
xpath_ctx);
if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
xpath_obj->nodesetval == NULL)
goto cont;
- for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
- xmlNodePtr node;
+ xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
+
+ for (j = 0; j < xml_interfaces->nodeNr; ++j) {
char *path = NULL;
+ char *address = NULL;
+ xmlNodePtr xml_interface;
- node = xpath_obj->nodesetval->nodeTab[j];
- if (!node) continue;
- path = (char *) xmlGetProp (node, (xmlChar *) "dev");
- if (!path) continue;
+ xml_interface = xml_interfaces->nodeTab[j];
+ if (!xml_interface) continue;
+ xmlNodePtr child = NULL;
+
+ for (child = xml_interface->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE) continue;
+
+ if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
+ path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
+ if (!path) continue;
+ } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
+ address = (char *) xmlGetProp (child, (const xmlChar *) "address");
+ if (!address) continue;
+ }
+ }
if (il_interface_devices &&
- ignore_device_match (il_interface_devices, name, path) != 0)
+ (ignore_device_match (il_interface_devices, name, path) != 0 ||
+ ignore_device_match (il_interface_devices, name, address) != 0))
goto cont3;
- add_interface_device (dom, path);
- cont3:
- if (path) xmlFree (path);
+ add_interface_device (dom, path, address);
+ cont3:
+ if (path) xmlFree (path);
+ if (address) xmlFree (address);
}
cont:
if (xpath_obj) xmlXPathFreeObject (xpath_obj);
if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
if (xml_doc) xmlFreeDoc (xml_doc);
- if (xml) free (xml);
+ sfree (xml);
}
- free (domids);
+ sfree (domids);
}
return 0;
if (domains) {
for (i = 0; i < nr_domains; ++i)
virDomainFree (domains[i]);
- free (domains);
+ sfree (domains);
}
domains = NULL;
nr_domains = 0;
if (block_devices) {
for (i = 0; i < nr_block_devices; ++i)
- free (block_devices[i].path);
- free (block_devices);
+ sfree (block_devices[i].path);
+ sfree (block_devices);
}
block_devices = NULL;
nr_block_devices = 0;
new_ptr = malloc (new_size);
if (new_ptr == NULL) {
- free (path_copy);
+ sfree (path_copy);
return -1;
}
block_devices = new_ptr;
int i;
if (interface_devices) {
- for (i = 0; i < nr_interface_devices; ++i)
- free (interface_devices[i].path);
- free (interface_devices);
+ for (i = 0; i < nr_interface_devices; ++i) {
+ sfree (interface_devices[i].path);
+ sfree (interface_devices[i].address);
+ }
+ sfree (interface_devices);
}
interface_devices = NULL;
nr_interface_devices = 0;
}
static int
-add_interface_device (virDomainPtr dom, const char *path)
+add_interface_device (virDomainPtr dom, const char *path, const char *address)
{
struct interface_device *new_ptr;
int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
- char *path_copy;
+ char *path_copy, *address_copy;
path_copy = strdup (path);
if (!path_copy) return -1;
+ address_copy = strdup (address);
+ if (!address_copy) return -1;
+
if (interface_devices)
new_ptr = realloc (interface_devices, new_size);
else
new_ptr = malloc (new_size);
if (new_ptr == NULL) {
- free (path_copy);
+ sfree (path_copy);
+ sfree (address_copy);
return -1;
}
interface_devices = new_ptr;
interface_devices[nr_interface_devices].dom = dom;
interface_devices[nr_interface_devices].path = path_copy;
+ interface_devices[nr_interface_devices].address = address_copy;
return nr_interface_devices++;
}
}
ssnprintf (name, n, "%s:%s", domname, devpath);
r = ignorelist_match (il, name);
- free (name);
+ sfree (name);
return r;
}
n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
if (i > 0 && n >= 1) {
- strcat (vl->host, ":");
+ strncat (vl->host, ":", 1);
n--;
}