X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvirt.c;h=93f9cebfc94e85820bddb40f94903d183cfd3c2e;hb=ce2eb567629eb21d650d5c27fefe607837c061fd;hp=7896b2e571f2ca58665a160623c4a1b303a231aa;hpb=7325774e210ab695351723e56a32dd3679af2032;p=collectd.git diff --git a/src/virt.c b/src/virt.c index 7896b2e5..93f9cebf 100644 --- a/src/virt.c +++ b/src/virt.c @@ -34,10 +34,19 @@ #include #include #include +#include /* Plugin name */ #define PLUGIN_NAME "virt" +/* Secure strcat macro assuring null termination. Parameter (n) is the size of + buffer (d), allowing this macro to be safe for static and dynamic buffers */ +#define SSTRNCAT(d, s, n) \ + do { \ + size_t _l = strlen(d); \ + sstrncpy((d) + _l, (s), (n)-_l); \ + } while (0) + #ifdef LIBVIR_CHECK_VERSION #if LIBVIR_CHECK_VERSION(0, 9, 2) @@ -65,11 +74,9 @@ in some systems which actually have virConnectListAllDomains() we can't detect this. */ -#ifdef LIBVIR_CHECK_VERSION #if LIBVIR_CHECK_VERSION(0, 10, 2) #define HAVE_LIST_ALL_DOMAINS 1 #endif -#endif #if LIBVIR_CHECK_VERSION(1, 0, 1) #define HAVE_DOM_REASON_PAUSED_SNAPSHOT 1 @@ -102,6 +109,14 @@ #endif /* LIBVIR_CHECK_VERSION */ +/* structure used for aggregating notification-thread data*/ +typedef struct virt_notif_thread_s { + pthread_t event_loop_tid; + int domain_event_cb_id; + pthread_mutex_t active_mutex; /* protects 'is_active' member access*/ + bool is_active; +} virt_notif_thread_t; + static const char *config_keys[] = {"Connection", "RefreshInterval", @@ -114,6 +129,8 @@ static const char *config_keys[] = {"Connection", "IgnoreSelected", "HostnameFormat", + "HostnameMetadataNS", + "HostnameMetadataXPath", "InterfaceFormat", "PluginInstanceFormat", @@ -121,15 +138,19 @@ static const char *config_keys[] = {"Connection", "Instances", "ExtraStats", "PersistentNotification", + + "ReportBlockDevices", + "ReportNetworkInterfaces", NULL}; /* PersistentNotification is false by default */ -static _Bool persistent_notification = 0; +static bool persistent_notification = false; -/* libvirt event loop */ -static pthread_t event_loop_tid; +static bool report_block_devices = true; +static bool report_network_interfaces = true; -static int domain_event_cb_id; +/* Thread used for handling libvirt notifications events */ +static virt_notif_thread_t notif_thread; const char *domain_states[] = { [VIR_DOMAIN_NOSTATE] = "no state", @@ -163,18 +184,23 @@ static int map_domain_event_to_state(int event) { case VIR_DOMAIN_EVENT_SHUTDOWN: ret = VIR_DOMAIN_SHUTDOWN; break; +#ifdef HAVE_DOM_STATE_PMSUSPENDED case VIR_DOMAIN_EVENT_PMSUSPENDED: ret = VIR_DOMAIN_PMSUSPENDED; break; +#endif +#ifdef HAVE_DOM_REASON_CRASHED case VIR_DOMAIN_EVENT_CRASHED: ret = VIR_DOMAIN_CRASHED; break; +#endif default: ret = VIR_DOMAIN_NOSTATE; } return ret; } +#ifdef HAVE_DOM_REASON static int map_domain_event_detail_to_reason(int event, int detail) { int ret; switch (event) { @@ -183,7 +209,8 @@ static int map_domain_event_detail_to_reason(int event, int detail) { case VIR_DOMAIN_EVENT_STARTED_BOOTED: /* Normal startup from boot */ ret = VIR_DOMAIN_RUNNING_BOOTED; break; - case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another host */ + case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another + host */ ret = VIR_DOMAIN_RUNNING_MIGRATED; break; case VIR_DOMAIN_EVENT_STARTED_RESTORED: /* Restored from a state file */ @@ -192,60 +219,78 @@ static int map_domain_event_detail_to_reason(int event, int detail) { case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: /* Restored from snapshot */ ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT; break; +#ifdef HAVE_DOM_REASON_RUNNING_WAKEUP case VIR_DOMAIN_EVENT_STARTED_WAKEUP: /* Started due to wakeup event */ ret = VIR_DOMAIN_RUNNING_WAKEUP; break; +#endif default: ret = VIR_DOMAIN_RUNNING_UNKNOWN; } break; case VIR_DOMAIN_EVENT_SUSPENDED: switch (detail) { - case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin pause */ + case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin + pause */ ret = VIR_DOMAIN_PAUSED_USER; break; - case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline migration */ + case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline + migration */ ret = VIR_DOMAIN_PAUSED_MIGRATION; break; - case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O error */ + case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O + error */ ret = VIR_DOMAIN_PAUSED_IOERROR; break; - case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog firing */ + case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog + firing */ ret = VIR_DOMAIN_PAUSED_WATCHDOG; break; - case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state file */ + case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state + file */ ret = VIR_DOMAIN_PAUSED_UNKNOWN; break; - case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused snapshot */ + case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused + snapshot */ ret = VIR_DOMAIN_PAUSED_FROM_SNAPSHOT; break; - case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during libvirt API call */ + case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during + libvirt API call */ ret = VIR_DOMAIN_PAUSED_UNKNOWN; break; - case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy migration */ +#ifdef HAVE_DOM_REASON_POSTCOPY + case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy + migration */ ret = VIR_DOMAIN_PAUSED_POSTCOPY; break; - case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed post-copy */ + case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed + post-copy */ ret = VIR_DOMAIN_PAUSED_POSTCOPY_FAILED; break; +#endif default: ret = VIR_DOMAIN_PAUSED_UNKNOWN; } break; case VIR_DOMAIN_EVENT_RESUMED: switch (detail) { - case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin unpause */ + case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin + unpause */ ret = VIR_DOMAIN_RUNNING_UNPAUSED; break; - case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of migration */ + case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of + migration */ ret = VIR_DOMAIN_RUNNING_MIGRATED; break; case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: /* Resumed from snapshot */ ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT; break; - case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still running in post-copy mode */ +#ifdef HAVE_DOM_REASON_POSTCOPY + case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still + running in post-copy mode */ ret = VIR_DOMAIN_RUNNING_POSTCOPY; break; +#endif default: ret = VIR_DOMAIN_RUNNING_UNKNOWN; } @@ -279,16 +324,19 @@ static int map_domain_event_detail_to_reason(int event, int detail) { break; case VIR_DOMAIN_EVENT_SHUTDOWN: switch (detail) { - case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown sequence */ + case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown + sequence */ ret = VIR_DOMAIN_SHUTDOWN_USER; break; default: ret = VIR_DOMAIN_SHUTDOWN_UNKNOWN; } break; +#ifdef HAVE_DOM_STATE_PMSUSPENDED case VIR_DOMAIN_EVENT_PMSUSPENDED: switch (detail) { - case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to memory */ + case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to + memory */ ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN; break; case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK: /* Guest was PM suspended to disk */ @@ -298,6 +346,7 @@ static int map_domain_event_detail_to_reason(int event, int detail) { ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN; } break; +#endif case VIR_DOMAIN_EVENT_CRASHED: switch (detail) { case VIR_DOMAIN_EVENT_CRASHED_PANICKED: /* Guest was panicked */ @@ -313,7 +362,6 @@ static int map_domain_event_detail_to_reason(int event, int detail) { return ret; } -#ifdef HAVE_DOM_REASON #define DOMAIN_STATE_REASON_MAX_SIZE 20 const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { [VIR_DOMAIN_NOSTATE][VIR_DOMAIN_NOSTATE_UNKNOWN] = @@ -347,7 +395,6 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_POSTCOPY] = "running in post-copy migration mode", #endif - [VIR_DOMAIN_BLOCKED][VIR_DOMAIN_BLOCKED_UNKNOWN] = "the reason is unknown", @@ -387,7 +434,6 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY_FAILED] = "paused after failed post-copy", #endif - [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_UNKNOWN] = "the reason is unknown", [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_USER] = @@ -426,12 +472,12 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { do { \ status = _f(__VA_ARGS__); \ if (status != 0) \ - ERROR(PLUGIN_NAME ": Failed to get " _name); \ + ERROR(PLUGIN_NAME " plugin: Failed to get " _name); \ } while (0) /* Connection. */ -static virConnectPtr conn = 0; -static char *conn_string = NULL; +static virConnectPtr conn; +static char *conn_string; static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC; /* Node information required for %CPU */ @@ -441,11 +487,11 @@ static virNodeInfo nodeinfo; static int interval = 60; /* List of domains, if specified. */ -static ignorelist_t *il_domains = NULL; +static ignorelist_t *il_domains; /* List of block devices, if specified. */ -static ignorelist_t *il_block_devices = NULL; +static ignorelist_t *il_block_devices; /* List of network interface devices, if specified. */ -static ignorelist_t *il_interface_devices = NULL; +static ignorelist_t *il_interface_devices; static int ignore_device_match(ignorelist_t *, const char *domname, const char *devpath); @@ -454,6 +500,7 @@ static int ignore_device_match(ignorelist_t *, const char *domname, struct block_device { virDomainPtr dom; /* domain */ char *path; /* name of block device */ + bool has_source; /* information whether source is defined or not */ }; /* Actual list of network interfaces found on last refresh. */ @@ -467,7 +514,7 @@ struct interface_device { typedef struct domain_s { virDomainPtr ptr; virDomainInfo info; - _Bool active; + bool active; } domain_t; struct lv_read_state { @@ -484,11 +531,11 @@ struct lv_read_state { static void free_domains(struct lv_read_state *state); static int add_domain(struct lv_read_state *state, virDomainPtr dom, - _Bool active); + bool active); static void free_block_devices(struct lv_read_state *state); static int add_block_device(struct lv_read_state *state, virDomainPtr dom, - const char *path); + const char *path, bool has_source); static void free_interface_devices(struct lv_read_state *state); static int add_interface_device(struct lv_read_state *state, virDomainPtr dom, @@ -519,20 +566,29 @@ static int nr_instances = NR_INSTANCES_DEFAULT; static struct lv_user_data lv_read_user_data[NR_INSTANCES_MAX]; /* HostnameFormat. */ -#define HF_MAX_FIELDS 3 +#define HF_MAX_FIELDS 4 -enum hf_field { hf_none = 0, hf_hostname, hf_name, hf_uuid }; +enum hf_field { hf_none = 0, hf_hostname, hf_name, hf_uuid, hf_metadata }; static enum hf_field hostname_format[HF_MAX_FIELDS] = {hf_name}; /* PluginInstanceFormat */ -#define PLGINST_MAX_FIELDS 2 +#define PLGINST_MAX_FIELDS 3 -enum plginst_field { plginst_none = 0, plginst_name, plginst_uuid }; +enum plginst_field { + plginst_none = 0, + plginst_name, + plginst_uuid, + plginst_metadata +}; static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] = { plginst_none}; +/* HostnameMetadataNS && HostnameMetadataXPath */ +static char *hm_xpath; +static char *hm_ns; + /* BlockDeviceFormat */ enum bd_field { target, source }; @@ -561,6 +617,9 @@ enum ex_stats { ex_stats_job_stats_completed = 1 << 8, ex_stats_job_stats_background = 1 << 9, #endif + ex_stats_disk_allocation = 1 << 10, + ex_stats_disk_capacity = 1 << 11, + ex_stats_disk_physical = 1 << 12 }; static unsigned int extra_stats = ex_stats_none; @@ -588,11 +647,14 @@ static const struct ex_stats_item ex_stats_table[] = { {"job_stats_completed", ex_stats_job_stats_completed}, {"job_stats_background", ex_stats_job_stats_background}, #endif + {"disk_allocation", ex_stats_disk_allocation}, + {"disk_capacity", ex_stats_disk_capacity}, + {"disk_physical", ex_stats_disk_physical}, {NULL, ex_stats_none}, }; /* BlockDeviceFormatBasename */ -_Bool blockdevice_format_basename = 0; +static bool blockdevice_format_basename; static enum bd_field blockdevice_format = target; static enum if_field interface_format = if_name; @@ -601,13 +663,7 @@ static time_t last_refresh = (time_t)0; static int refresh_lists(struct lv_read_instance *inst); -struct lv_info { - virDomainInfo di; - unsigned long long total_user_cpu_time; - unsigned long long total_syst_cpu_time; -}; - -struct lv_block_info { +struct lv_block_stats { virDomainBlockStatsStruct bi; long long rd_total_times; @@ -617,50 +673,56 @@ struct lv_block_info { long long fl_total_times; }; -static void init_block_info(struct lv_block_info *binfo) { - if (binfo == NULL) +static void init_block_stats(struct lv_block_stats *bstats) { + if (bstats == NULL) return; - binfo->bi.rd_req = -1; - binfo->bi.wr_req = -1; - binfo->bi.rd_bytes = -1; - binfo->bi.wr_bytes = -1; + bstats->bi.rd_req = -1; + bstats->bi.wr_req = -1; + bstats->bi.rd_bytes = -1; + bstats->bi.wr_bytes = -1; - binfo->rd_total_times = -1; - binfo->wr_total_times = -1; - binfo->fl_req = -1; - binfo->fl_total_times = -1; + bstats->rd_total_times = -1; + bstats->wr_total_times = -1; + bstats->fl_req = -1; + bstats->fl_total_times = -1; +} + +static void init_block_info(virDomainBlockInfoPtr binfo) { + binfo->allocation = -1; + binfo->capacity = -1; + binfo->physical = -1; } #ifdef HAVE_BLOCK_STATS_FLAGS -#define GET_BLOCK_INFO_VALUE(NAME, FIELD) \ +#define GET_BLOCK_STATS_VALUE(NAME, FIELD) \ if (!strcmp(param[i].field, NAME)) { \ - binfo->FIELD = param[i].value.l; \ + bstats->FIELD = param[i].value.l; \ continue; \ } -static int get_block_info(struct lv_block_info *binfo, - virTypedParameterPtr param, int nparams) { - if (binfo == NULL || param == NULL) +static int get_block_stats(struct lv_block_stats *bstats, + virTypedParameterPtr param, int nparams) { + if (bstats == NULL || param == NULL) return -1; for (int i = 0; i < nparams; ++i) { /* ignore type. Everything must be LLONG anyway. */ - GET_BLOCK_INFO_VALUE("rd_operations", bi.rd_req); - GET_BLOCK_INFO_VALUE("wr_operations", bi.wr_req); - GET_BLOCK_INFO_VALUE("rd_bytes", bi.rd_bytes); - GET_BLOCK_INFO_VALUE("wr_bytes", bi.wr_bytes); - GET_BLOCK_INFO_VALUE("rd_total_times", rd_total_times); - GET_BLOCK_INFO_VALUE("wr_total_times", wr_total_times); - GET_BLOCK_INFO_VALUE("flush_operations", fl_req); - GET_BLOCK_INFO_VALUE("flush_total_times", fl_total_times); + GET_BLOCK_STATS_VALUE("rd_operations", bi.rd_req); + GET_BLOCK_STATS_VALUE("wr_operations", bi.wr_req); + GET_BLOCK_STATS_VALUE("rd_bytes", bi.rd_bytes); + GET_BLOCK_STATS_VALUE("wr_bytes", bi.wr_bytes); + GET_BLOCK_STATS_VALUE("rd_total_times", rd_total_times); + GET_BLOCK_STATS_VALUE("wr_total_times", wr_total_times); + GET_BLOCK_STATS_VALUE("flush_operations", fl_req); + GET_BLOCK_STATS_VALUE("flush_total_times", fl_total_times); } return 0; } -#undef GET_BLOCK_INFO_VALUE +#undef GET_BLOCK_STATS_VALUE #endif /* HAVE_BLOCK_STATS_FLAGS */ @@ -670,61 +732,99 @@ static int get_block_info(struct lv_block_info *binfo, virErrorPtr err; \ err = (conn) ? virConnGetLastError((conn)) : virGetLastError(); \ if (err) \ - ERROR("%s: %s", (s), err->message); \ + ERROR(PLUGIN_NAME " plugin: %s failed: %s", (s), err->message); \ } while (0) -static void init_lv_info(struct lv_info *info) { - if (info != NULL) - memset(info, 0, sizeof(*info)); -} +char *metadata_get_hostname(virDomainPtr dom) { + const char *xpath_str = NULL; + if (hm_xpath == NULL) + xpath_str = "/instance/name/text()"; + else + xpath_str = hm_xpath; -static int lv_domain_info(virDomainPtr dom, struct lv_info *info) { -#ifdef HAVE_CPU_STATS - virTypedParameterPtr param = NULL; - int nparams = 0; -#endif /* HAVE_CPU_STATS */ - int ret = virDomainGetInfo(dom, &(info->di)); - if (ret != 0) { - return ret; + const char *namespace = NULL; + if (hm_ns == NULL) { + namespace = "http://openstack.org/xmlns/libvirt/nova/1.0"; + } else { + namespace = hm_ns; } -#ifdef HAVE_CPU_STATS - nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0); - if (nparams < 0) { - VIRT_ERROR(conn, "getting the CPU params count"); - return -1; + char *metadata_str = virDomainGetMetadata( + dom, VIR_DOMAIN_METADATA_ELEMENT, namespace, VIR_DOMAIN_AFFECT_CURRENT); + if (metadata_str == NULL) { + return NULL; } - param = calloc(nparams, sizeof(virTypedParameter)); - if (param == NULL) { - ERROR("virt plugin: alloc(%i) for cpu parameters failed.", nparams); - return -1; + char *hostname = NULL; + xmlXPathContextPtr xpath_ctx = NULL; + xmlXPathObjectPtr xpath_obj = NULL; + xmlNodePtr xml_node = NULL; + + xmlDocPtr xml_doc = + xmlReadDoc((xmlChar *)metadata_str, NULL, NULL, XML_PARSE_NONET); + if (xml_doc == NULL) { + ERROR(PLUGIN_NAME " plugin: xmlReadDoc failed to read metadata"); + goto metadata_end; } - ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats. - if (ret < 0) { - virTypedParamsClear(param, nparams); - sfree(param); - VIRT_ERROR(conn, "getting the disk params values"); - return -1; + xpath_ctx = xmlXPathNewContext(xml_doc); + if (xpath_ctx == NULL) { + ERROR(PLUGIN_NAME " plugin: xmlXPathNewContext(%s) failed for metadata", + metadata_str); + goto metadata_end; + } + xpath_obj = xmlXPathEval((xmlChar *)xpath_str, xpath_ctx); + if (xpath_obj == NULL) { + ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) failed for metadata", + xpath_str); + goto metadata_end; } - for (int i = 0; i < nparams; ++i) { - if (!strcmp(param[i].field, "user_time")) - info->total_user_cpu_time = param[i].value.ul; - else if (!strcmp(param[i].field, "system_time")) - info->total_syst_cpu_time = param[i].value.ul; + if (xpath_obj->type != XPATH_NODESET) { + ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) unexpected return type %d " + "(wanted %d) for metadata", + xpath_str, xpath_obj->type, XPATH_NODESET); + goto metadata_end; } - virTypedParamsClear(param, nparams); - sfree(param); -#endif /* HAVE_CPU_STATS */ + // TODO(sileht): We can support || operator by looping on nodes here + if (xpath_obj->nodesetval == NULL || xpath_obj->nodesetval->nodeNr != 1) { + WARNING(PLUGIN_NAME " plugin: xmlXPathEval(%s) return nodeset size=%i " + "expected=1 for metadata", + xpath_str, + (xpath_obj->nodesetval == NULL) ? 0 + : xpath_obj->nodesetval->nodeNr); + goto metadata_end; + } + + xml_node = xpath_obj->nodesetval->nodeTab[0]; + if (xml_node->type == XML_TEXT_NODE) { + hostname = strdup((const char *)xml_node->content); + } else if (xml_node->type == XML_ATTRIBUTE_NODE) { + hostname = strdup((const char *)xml_node->children->content); + } else { + ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) unsupported node type %d", + xpath_str, xml_node->type); + goto metadata_end; + } - return 0; + if (hostname == NULL) { + ERROR(PLUGIN_NAME " plugin: strdup(%s) hostname failed", xpath_str); + goto metadata_end; + } + +metadata_end: + if (xpath_obj) + xmlXPathFreeObject(xpath_obj); + if (xpath_ctx) + xmlXPathFreeContext(xpath_ctx); + if (xml_doc) + xmlFreeDoc(xml_doc); + sfree(metadata_str); + return hostname; } static void init_value_list(value_list_t *vl, virDomainPtr dom) { - int n; const char *name; char uuid[VIR_UUID_STRING_BUFLEN]; @@ -737,44 +837,39 @@ static void init_value_list(value_list_t *vl, virDomainPtr dom) { if (hostname_format[i] == hf_none) continue; - n = DATA_MAX_NAME_LEN - strlen(vl->host) - 2; - - if (i > 0 && n >= 1) { - strncat(vl->host, ":", 1); - n--; - } + if (i > 0) + SSTRNCAT(vl->host, ":", sizeof(vl->host)); switch (hostname_format[i]) { case hf_none: break; case hf_hostname: - strncat(vl->host, hostname_g, n); + SSTRNCAT(vl->host, hostname_g, sizeof(vl->host)); break; case hf_name: name = virDomainGetName(dom); if (name) - strncat(vl->host, name, n); + SSTRNCAT(vl->host, name, sizeof(vl->host)); break; case hf_uuid: if (virDomainGetUUIDString(dom, uuid) == 0) - strncat(vl->host, uuid, n); + SSTRNCAT(vl->host, uuid, sizeof(vl->host)); + break; + case hf_metadata: + name = metadata_get_hostname(dom); + if (name) + SSTRNCAT(vl->host, name, sizeof(vl->host)); break; } } - vl->host[sizeof(vl->host) - 1] = '\0'; - /* Construct the plugin instance field according to PluginInstanceFormat. */ for (int i = 0; i < PLGINST_MAX_FIELDS; ++i) { if (plugin_instance_format[i] == plginst_none) continue; - n = sizeof(vl->plugin_instance) - strlen(vl->plugin_instance) - 2; - - if (i > 0 && n >= 1) { - strncat(vl->plugin_instance, ":", 1); - n--; - } + if (i > 0) + SSTRNCAT(vl->plugin_instance, ":", sizeof(vl->plugin_instance)); switch (plugin_instance_format[i]) { case plginst_none: @@ -782,17 +877,20 @@ static void init_value_list(value_list_t *vl, virDomainPtr dom) { case plginst_name: name = virDomainGetName(dom); if (name) - strncat(vl->plugin_instance, name, n); + SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance)); break; case plginst_uuid: if (virDomainGetUUIDString(dom, uuid) == 0) - strncat(vl->plugin_instance, uuid, n); + SSTRNCAT(vl->plugin_instance, uuid, sizeof(vl->plugin_instance)); + break; + case plginst_metadata: + name = metadata_get_hostname(dom); + if (name) + SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance)); break; } } - vl->plugin_instance[sizeof(vl->plugin_instance) - 1] = '\0'; - } /* void init_value_list */ static int init_notif(notification_t *notif, const virDomainPtr domain, @@ -801,7 +899,7 @@ static int init_notif(notification_t *notif, const virDomainPtr domain, value_list_t vl = VALUE_LIST_INIT; if (!notif) { - ERROR(PLUGIN_NAME ": init_notif: NULL pointer"); + ERROR(PLUGIN_NAME " plugin: init_notif: NULL pointer"); return -1; } @@ -867,14 +965,6 @@ static void submit_derive2(const char *type, derive_t v0, derive_t v1, submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values)); } /* void submit_derive2 */ -static void pcpu_submit(virDomainPtr dom, struct lv_info *info) { -#ifdef HAVE_CPU_STATS - if (extra_stats & ex_stats_pcpu) - submit_derive2("ps_cputime", info->total_user_cpu_time, - info->total_syst_cpu_time, dom, NULL); -#endif /* HAVE_CPU_STATS */ -} - static double cpu_ns_to_percent(unsigned int node_cpus, unsigned long long cpu_time_old, unsigned long long cpu_time_new) { @@ -888,7 +978,7 @@ static double cpu_ns_to_percent(unsigned int node_cpus, (time_diff_sec * node_cpus * NANOSEC_IN_SEC); } - DEBUG(PLUGIN_NAME ": node_cpus=%u cpu_time_old=%" PRIu64 + DEBUG(PLUGIN_NAME " plugin: node_cpus=%u cpu_time_old=%" PRIu64 " cpu_time_new=%" PRIu64 "cpu_time_diff=%" PRIu64 " time_diff_sec=%f percent=%f", node_cpus, (uint64_t)cpu_time_old, (uint64_t)cpu_time_new, @@ -925,8 +1015,9 @@ static void vcpu_submit(derive_t value, virDomainPtr dom, int vcpu_nr, submit(dom, type, type_instance, &(value_t){.derive = value}, 1); } -static void disk_submit(struct lv_block_info *binfo, virDomainPtr dom, - const char *dev) { +static void disk_block_stats_submit(struct lv_block_stats *bstats, + virDomainPtr dom, const char *dev, + virDomainBlockInfoPtr binfo) { char *dev_copy = strdup(dev); const char *type_instance = dev_copy; @@ -945,29 +1036,43 @@ static void disk_submit(struct lv_block_info *binfo, virDomainPtr dom, snprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s", type_instance); - if ((binfo->bi.rd_req != -1) && (binfo->bi.wr_req != -1)) - submit_derive2("disk_ops", (derive_t)binfo->bi.rd_req, - (derive_t)binfo->bi.wr_req, dom, type_instance); + if ((bstats->bi.rd_req != -1) && (bstats->bi.wr_req != -1)) + submit_derive2("disk_ops", (derive_t)bstats->bi.rd_req, + (derive_t)bstats->bi.wr_req, dom, type_instance); - if ((binfo->bi.rd_bytes != -1) && (binfo->bi.wr_bytes != -1)) - submit_derive2("disk_octets", (derive_t)binfo->bi.rd_bytes, - (derive_t)binfo->bi.wr_bytes, dom, type_instance); + if ((bstats->bi.rd_bytes != -1) && (bstats->bi.wr_bytes != -1)) + submit_derive2("disk_octets", (derive_t)bstats->bi.rd_bytes, + (derive_t)bstats->bi.wr_bytes, dom, type_instance); if (extra_stats & ex_stats_disk) { - if ((binfo->rd_total_times != -1) && (binfo->wr_total_times != -1)) - submit_derive2("disk_time", (derive_t)binfo->rd_total_times, - (derive_t)binfo->wr_total_times, dom, type_instance); + if ((bstats->rd_total_times != -1) && (bstats->wr_total_times != -1)) + submit_derive2("disk_time", (derive_t)bstats->rd_total_times, + (derive_t)bstats->wr_total_times, dom, type_instance); - if (binfo->fl_req != -1) + if (bstats->fl_req != -1) submit(dom, "total_requests", flush_type_instance, - &(value_t){.derive = (derive_t)binfo->fl_req}, 1); - if (binfo->fl_total_times != -1) { - derive_t value = binfo->fl_total_times / 1000; // ns -> ms + &(value_t){.derive = (derive_t)bstats->fl_req}, 1); + if (bstats->fl_total_times != -1) { + derive_t value = bstats->fl_total_times / 1000; // ns -> ms submit(dom, "total_time_in_ms", flush_type_instance, &(value_t){.derive = value}, 1); } } + /* disk_allocation, disk_capacity and disk_physical are stored only + * if corresponding extrastats are set in collectd configuration file */ + if ((extra_stats & ex_stats_disk_allocation) && binfo->allocation != -1) + submit(dom, "disk_allocation", type_instance, + &(value_t){.gauge = (gauge_t)binfo->allocation}, 1); + + if ((extra_stats & ex_stats_disk_capacity) && binfo->capacity != -1) + submit(dom, "disk_capacity", type_instance, + &(value_t){.gauge = (gauge_t)binfo->capacity}, 1); + + if ((extra_stats & ex_stats_disk_physical) && binfo->physical != -1) + submit(dom, "disk_physical", type_instance, + &(value_t){.gauge = (gauge_t)binfo->physical}, 1); + sfree(dev_copy); } @@ -983,7 +1088,8 @@ static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) { } if (ex_stats_table[j + 1].name == NULL) { - ERROR(PLUGIN_NAME ": Unmatched ExtraStats option: %s", exstats[i]); + ERROR(PLUGIN_NAME " plugin: Unmatched ExtraStats option: %s", + exstats[i]); } } } @@ -991,16 +1097,17 @@ static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) { } static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { - if ((state < 0) || (state >= STATIC_ARRAY_SIZE(domain_states))) { - ERROR(PLUGIN_NAME ": Array index out of bounds: state=%d", state); + if ((state < 0) || ((size_t)state >= STATIC_ARRAY_SIZE(domain_states))) { + ERROR(PLUGIN_NAME " plugin: Array index out of bounds: state=%d", state); return; } char msg[DATA_MAX_NAME_LEN]; const char *state_str = domain_states[state]; #ifdef HAVE_DOM_REASON - if ((reason < 0) || (reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) { - ERROR(PLUGIN_NAME ": Array index out of bounds: reason=%d", reason); + if ((reason < 0) || + ((size_t)reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) { + ERROR(PLUGIN_NAME " plugin: Array index out of bounds: reason=%d", reason); return; } @@ -1009,8 +1116,8 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { * have different number of reasons. We need to check if reason was * successfully parsed */ if (!reason_str) { - ERROR(PLUGIN_NAME ": Invalid reason (%d) for domain state: %s", reason, - state_str); + ERROR(PLUGIN_NAME " plugin: Invalid reason (%d) for domain state: %s", + reason, state_str); return; } #else @@ -1039,16 +1146,13 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { severity = NOTIF_FAILURE; break; default: - ERROR(PLUGIN_NAME ": Unrecognized domain state (%d)", state); + ERROR(PLUGIN_NAME " plugin: Unrecognized domain state (%d)", state); return; } submit_notif(dom, severity, msg, "domain_state", NULL); } -static int lv_config(const char *key, const char *value) { - if (virInitialize() != 0) - return 1; - +static int lv_init_ignorelists() { if (il_domains == NULL) il_domains = ignorelist_create(1); if (il_block_devices == NULL) @@ -1056,6 +1160,19 @@ static int lv_config(const char *key, const char *value) { if (il_interface_devices == NULL) il_interface_devices = ignorelist_create(1); + if (!il_domains || !il_block_devices || !il_interface_devices) + return 1; + + return 0; +} + +static int lv_config(const char *key, const char *value) { + if (virInitialize() != 0) + return 1; + + if (lv_init_ignorelists() != 0) + return 1; + if (strcasecmp(key, "Connection") == 0) { char *tmp = strdup(value); if (tmp == NULL) { @@ -1098,7 +1215,7 @@ static int lv_config(const char *key, const char *value) { return 0; } if (strcasecmp(key, "BlockDeviceFormatBasename") == 0) { - blockdevice_format_basename = IS_TRUE(value); + blockdevice_format_basename = IS_TRUE(value) ? true : false; return 0; } if (strcasecmp(key, "InterfaceDevice") == 0) { @@ -1120,18 +1237,37 @@ static int lv_config(const char *key, const char *value) { return 0; } - if (strcasecmp(key, "HostnameFormat") == 0) { - char *value_copy; - char *fields[HF_MAX_FIELDS]; - int n; + if (strcasecmp(key, "HostnameMetadataNS") == 0) { + char *tmp = strdup(value); + if (tmp == NULL) { + ERROR(PLUGIN_NAME " plugin: HostnameMetadataNS strdup failed."); + return 1; + } + sfree(hm_ns); + hm_ns = tmp; + return 0; + } + + if (strcasecmp(key, "HostnameMetadataXPath") == 0) { + char *tmp = strdup(value); + if (tmp == NULL) { + ERROR(PLUGIN_NAME " plugin: HostnameMetadataXPath strdup failed."); + return 1; + } + sfree(hm_xpath); + hm_xpath = tmp; + return 0; + } - value_copy = strdup(value); + if (strcasecmp(key, "HostnameFormat") == 0) { + char *value_copy = strdup(value); if (value_copy == NULL) { ERROR(PLUGIN_NAME " plugin: strdup failed."); return -1; } - n = strsplit(value_copy, fields, HF_MAX_FIELDS); + char *fields[HF_MAX_FIELDS]; + int n = strsplit(value_copy, fields, HF_MAX_FIELDS); if (n < 1) { sfree(value_copy); ERROR(PLUGIN_NAME " plugin: HostnameFormat: no fields"); @@ -1145,6 +1281,8 @@ static int lv_config(const char *key, const char *value) { hostname_format[i] = hf_name; else if (strcasecmp(fields[i], "uuid") == 0) hostname_format[i] = hf_uuid; + else if (strcasecmp(fields[i], "metadata") == 0) + hostname_format[i] = hf_metadata; else { ERROR(PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]); @@ -1161,17 +1299,14 @@ static int lv_config(const char *key, const char *value) { } if (strcasecmp(key, "PluginInstanceFormat") == 0) { - char *value_copy; - char *fields[PLGINST_MAX_FIELDS]; - int n; - - value_copy = strdup(value); + char *value_copy = strdup(value); if (value_copy == NULL) { ERROR(PLUGIN_NAME " plugin: strdup failed."); return -1; } - n = strsplit(value_copy, fields, PLGINST_MAX_FIELDS); + char *fields[PLGINST_MAX_FIELDS]; + int n = strsplit(value_copy, fields, PLGINST_MAX_FIELDS); if (n < 1) { sfree(value_copy); ERROR(PLUGIN_NAME " plugin: PluginInstanceFormat: no fields"); @@ -1186,6 +1321,8 @@ static int lv_config(const char *key, const char *value) { plugin_instance_format[i] = plginst_name; else if (strcasecmp(fields[i], "uuid") == 0) plugin_instance_format[i] = plginst_uuid; + else if (strcasecmp(fields[i], "metadata") == 0) + plugin_instance_format[i] = plginst_metadata; else { ERROR(PLUGIN_NAME " plugin: unknown PluginInstanceFormat field: %s", fields[i]); @@ -1265,6 +1402,16 @@ static int lv_config(const char *key, const char *value) { return 0; } + if (strcasecmp(key, "ReportBlockDevices") == 0) { + report_block_devices = IS_TRUE(value); + return 0; + } + + if (strcasecmp(key, "ReportNetworkInterfaces") == 0) { + report_network_interfaces = IS_TRUE(value); + return 0; + } + /* Unrecognised option. */ return -1; } @@ -1287,7 +1434,7 @@ static int lv_connect(void) { } int status = virNodeGetInfo(conn, &nodeinfo); if (status != 0) { - ERROR(PLUGIN_NAME ": virNodeGetInfo failed"); + ERROR(PLUGIN_NAME " plugin: virNodeGetInfo failed"); return -1; } } @@ -1303,8 +1450,8 @@ static void lv_disconnect(void) { WARNING(PLUGIN_NAME " plugin: closed connection to libvirt"); } -static int lv_domain_block_info(virDomainPtr dom, const char *path, - struct lv_block_info *binfo) { +static int lv_domain_block_stats(virDomainPtr dom, const char *path, + struct lv_block_stats *bstats) { #ifdef HAVE_BLOCK_STATS_FLAGS int nparams = 0; if (virDomainBlockStatsFlags(dom, path, NULL, &nparams, 0) < 0 || @@ -1313,7 +1460,7 @@ static int lv_domain_block_info(virDomainPtr dom, const char *path, return -1; } - virTypedParameterPtr params = calloc((size_t)nparams, sizeof(*params)); + virTypedParameterPtr params = calloc(nparams, sizeof(*params)); if (params == NULL) { ERROR("virt plugin: alloc(%i) for block=%s parameters failed.", nparams, path); @@ -1324,14 +1471,14 @@ static int lv_domain_block_info(virDomainPtr dom, const char *path, if (virDomainBlockStatsFlags(dom, path, params, &nparams, 0) < 0) { VIRT_ERROR(conn, "getting the disk params values"); } else { - rc = get_block_info(binfo, params, nparams); + rc = get_block_stats(bstats, params, nparams); } virTypedParamsClear(params, nparams); sfree(params); return rc; #else - return virDomainBlockStats(dom, path, &(binfo->bi), sizeof(binfo->bi)); + return virDomainBlockStats(dom, path, &(bstats->bi), sizeof(bstats->bi)); #endif /* HAVE_BLOCK_STATS_FLAGS */ } @@ -1372,7 +1519,7 @@ static void vcpu_pin_submit(virDomainPtr dom, int max_cpus, int vcpu, unsigned char *cpu_maps, int cpu_map_len) { for (int cpu = 0; cpu < max_cpus; ++cpu) { char type_instance[DATA_MAX_NAME_LEN]; - _Bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu) ? 1 : 0; + bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu); snprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, cpu); submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1); @@ -1383,15 +1530,15 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) { int max_cpus = VIR_NODEINFO_MAXCPUS(nodeinfo); int cpu_map_len = VIR_CPU_MAPLEN(max_cpus); - virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(vinfo[0])); + virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(*vinfo)); if (vinfo == NULL) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); + ERROR(PLUGIN_NAME " plugin: calloc failed."); return -1; } unsigned char *cpumaps = calloc(nr_virt_cpu, cpu_map_len); if (cpumaps == NULL) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); + ERROR(PLUGIN_NAME " plugin: calloc failed."); sfree(vinfo); return -1; } @@ -1417,6 +1564,49 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) { return 0; } +#ifdef HAVE_CPU_STATS +static int get_pcpu_stats(virDomainPtr dom) { + int nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0); + if (nparams < 0) { + VIRT_ERROR(conn, "getting the CPU params count"); + return -1; + } + + virTypedParameterPtr param = calloc(nparams, sizeof(*param)); + if (param == NULL) { + ERROR(PLUGIN_NAME " plugin: alloc(%i) for cpu parameters failed.", nparams); + return -1; + } + + int ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats. + if (ret < 0) { + virTypedParamsClear(param, nparams); + sfree(param); + VIRT_ERROR(conn, "getting the CPU params values"); + return -1; + } + + unsigned long long total_user_cpu_time = 0; + unsigned long long total_syst_cpu_time = 0; + + for (int i = 0; i < nparams; ++i) { + if (!strcmp(param[i].field, "user_time")) + total_user_cpu_time = param[i].value.ul; + else if (!strcmp(param[i].field, "system_time")) + total_syst_cpu_time = param[i].value.ul; + } + + if (total_user_cpu_time > 0 || total_syst_cpu_time > 0) + submit_derive2("ps_cputime", total_user_cpu_time, total_syst_cpu_time, dom, + NULL); + + virTypedParamsClear(param, nparams); + sfree(param); + + return 0; +} +#endif /* HAVE_CPU_STATS */ + #ifdef HAVE_DOM_REASON static void domain_state_submit(virDomainPtr dom, int state, int reason) { @@ -1465,9 +1655,9 @@ static int get_domain_state_notify(virDomainPtr domain) { static int get_memory_stats(virDomainPtr domain) { virDomainMemoryStatPtr minfo = - calloc(VIR_DOMAIN_MEMORY_STAT_NR, sizeof(virDomainMemoryStatStruct)); + calloc(VIR_DOMAIN_MEMORY_STAT_NR, sizeof(*minfo)); if (minfo == NULL) { - ERROR("virt plugin: malloc failed."); + ERROR("virt plugin: calloc failed."); return -1; } @@ -1527,22 +1717,39 @@ static int get_disk_err(virDomainPtr domain) { } #endif /* HAVE_DISK_ERR */ -static int get_block_stats(struct block_device *block_dev) { - +static int get_block_device_stats(struct block_device *block_dev) { if (!block_dev) { ERROR(PLUGIN_NAME " plugin: get_block_stats NULL pointer"); return -1; } - struct lv_block_info binfo; + virDomainBlockInfo binfo; init_block_info(&binfo); - if (lv_domain_block_info(block_dev->dom, block_dev->path, &binfo) < 0) { - ERROR(PLUGIN_NAME " plugin: lv_domain_block_info failed"); + /* Fetching block info stats only if needed*/ + if (extra_stats & (ex_stats_disk_allocation | ex_stats_disk_capacity | + ex_stats_disk_physical)) { + /* Block info statistics can be only fetched from devices with 'source' + * defined */ + if (block_dev->has_source) { + if (virDomainGetBlockInfo(block_dev->dom, block_dev->path, &binfo, 0) < + 0) { + ERROR(PLUGIN_NAME " plugin: virDomainGetBlockInfo failed for path: %s", + block_dev->path); + return -1; + } + } + } + + struct lv_block_stats bstats; + init_block_stats(&bstats); + + if (lv_domain_block_stats(block_dev->dom, block_dev->path, &bstats) < 0) { + ERROR(PLUGIN_NAME " plugin: lv_domain_block_stats failed"); return -1; } - disk_submit(&binfo, block_dev->dom, block_dev->path); + disk_block_stats_submit(&bstats, block_dev->dom, block_dev->path, &binfo); return 0; } @@ -1559,7 +1766,7 @@ static int get_block_stats(struct block_device *block_dev) { #define NM_ADD_STR_ITEMS(_items, _size) \ do { \ - for (int _i = 0; _i < _size; ++_i) { \ + for (size_t _i = 0; _i < _size; ++_i) { \ DEBUG(PLUGIN_NAME \ " plugin: Adding notification metadata name=%s value=%s", \ _items[_i].name, _items[_i].value); \ @@ -1584,7 +1791,7 @@ static int fs_info_notify(virDomainPtr domain, virDomainFSInfoPtr fs_info) { {.name = "name", .value = fs_info->name}, {.name = "fstype", .value = fs_info->fstype}}; - for (int i = 0; i < fs_info->ndevAlias; ++i) { + for (size_t i = 0; i < fs_info->ndevAlias; ++i) { fs_dev_alias[i].name = "devAlias"; fs_dev_alias[i].value = fs_info->devAlias[i]; } @@ -1690,15 +1897,13 @@ static int get_job_stats(virDomainPtr domain) { #endif /* HAVE_JOB_STATS */ static int get_domain_metrics(domain_t *domain) { - struct lv_info info; - if (!domain || !domain->ptr) { - ERROR(PLUGIN_NAME ": get_domain_metrics: NULL pointer"); + ERROR(PLUGIN_NAME " plugin: get_domain_metrics: NULL pointer"); return -1; } - init_lv_info(&info); - int status = lv_domain_info(domain->ptr, &info); + virDomainInfo info; + int status = virDomainGetInfo(domain->ptr, &info); if (status != 0) { ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", status); @@ -1716,15 +1921,19 @@ static int get_domain_metrics(domain_t *domain) { } /* Gather remaining stats only for running domains */ - if (info.di.state != VIR_DOMAIN_RUNNING) + if (info.state != VIR_DOMAIN_RUNNING) return 0; - pcpu_submit(domain->ptr, &info); - cpu_submit(domain, info.di.cpuTime); +#ifdef HAVE_CPU_STATS + if (extra_stats & ex_stats_pcpu) + get_pcpu_stats(domain->ptr); +#endif - memory_submit(domain->ptr, (gauge_t)info.di.memory * 1024); + cpu_submit(domain, info.cpuTime); - GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.di.nrVirtCpu); + memory_submit(domain->ptr, (gauge_t)info.memory * 1024); + + GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu); GET_STATS(get_memory_stats, "memory stats", domain->ptr); #ifdef HAVE_PERF_STATS @@ -1749,7 +1958,7 @@ static int get_domain_metrics(domain_t *domain) { #endif /* Update cached virDomainInfo. It has to be done after cpu_submit */ - memcpy(&domain->info, &info.di, sizeof(domain->info)); + memcpy(&domain->info, &info, sizeof(domain->info)); return 0; } @@ -1799,11 +2008,14 @@ static int get_if_dev_stats(struct interface_device *if_dev) { return 0; } -static int domain_lifecycle_event_cb(__attribute__((unused)) virConnectPtr conn, +static int domain_lifecycle_event_cb(__attribute__((unused)) virConnectPtr con_, virDomainPtr dom, int event, int detail, __attribute__((unused)) void *opaque) { int domain_state = map_domain_event_to_state(event); - int domain_reason = map_domain_event_detail_to_reason(event, detail); + int domain_reason = 0; /* 0 means UNKNOWN reason for any state */ +#ifdef HAVE_DOM_REASON + domain_reason = map_domain_event_detail_to_reason(event, detail); +#endif domain_state_submit_notif(dom, domain_state, domain_reason); return 0; @@ -1821,9 +2033,30 @@ static int register_event_impl(void) { return 0; } +static void virt_notif_thread_set_active(virt_notif_thread_t *thread_data, + const bool active) { + assert(thread_data != NULL); + pthread_mutex_lock(&thread_data->active_mutex); + thread_data->is_active = active; + pthread_mutex_unlock(&thread_data->active_mutex); +} + +static bool virt_notif_thread_is_active(virt_notif_thread_t *thread_data) { + bool active = false; + + assert(thread_data != NULL); + pthread_mutex_lock(&thread_data->active_mutex); + active = thread_data->is_active; + pthread_mutex_unlock(&thread_data->active_mutex); + + return active; +} + /* worker function running default event implementation */ -static void *event_loop_worker(__attribute__((unused)) void *arg) { - while (1) { +static void *event_loop_worker(void *arg) { + virt_notif_thread_t *thread_data = (virt_notif_thread_t *)arg; + + while (virt_notif_thread_is_active(thread_data)) { if (virEventRunDefaultImpl() < 0) { virErrorPtr err = virGetLastError(); ERROR(PLUGIN_NAME " plugin: failed to run event loop: %s\n", @@ -1834,19 +2067,44 @@ static void *event_loop_worker(__attribute__((unused)) void *arg) { return NULL; } +static int virt_notif_thread_init(virt_notif_thread_t *thread_data) { + int ret; + + assert(thread_data != NULL); + ret = pthread_mutex_init(&thread_data->active_mutex, NULL); + if (ret != 0) { + ERROR(PLUGIN_NAME " plugin: Failed to initialize mutex, err %u", ret); + return ret; + } + + /** + * '0' and positive integers are meaningful ID's, therefore setting + * domain_event_cb_id to '-1' + */ + thread_data->domain_event_cb_id = -1; + pthread_mutex_lock(&thread_data->active_mutex); + thread_data->is_active = false; + pthread_mutex_unlock(&thread_data->active_mutex); + + return 0; +} + /* register domain event callback and start event loop thread */ -static int start_event_loop(void) { - domain_event_cb_id = virConnectDomainEventRegisterAny( +static int start_event_loop(virt_notif_thread_t *thread_data) { + assert(thread_data != NULL); + thread_data->domain_event_cb_id = virConnectDomainEventRegisterAny( conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(domain_lifecycle_event_cb), NULL, NULL); - if (domain_event_cb_id == -1) { + if (thread_data->domain_event_cb_id == -1) { ERROR(PLUGIN_NAME " plugin: error while callback registering"); return -1; } - if (pthread_create(&event_loop_tid, NULL, event_loop_worker, NULL)) { + virt_notif_thread_set_active(thread_data, 1); + if (pthread_create(&thread_data->event_loop_tid, NULL, event_loop_worker, + thread_data)) { ERROR(PLUGIN_NAME " plugin: failed event loop thread creation"); - virConnectDomainEventDeregisterAny(conn, domain_event_cb_id); + virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id); return -1; } @@ -1854,31 +2112,27 @@ static int start_event_loop(void) { } /* stop event loop thread and deregister callback */ -static void stop_event_loop(void) { - if (pthread_cancel(event_loop_tid) != 0) - ERROR(PLUGIN_NAME " plugin: cancelling thread %lu failed", - event_loop_tid); - - if (pthread_join(event_loop_tid, NULL) != 0) - ERROR(PLUGIN_NAME " plugin: stopping thread %lu failed", - event_loop_tid); - - if (conn != NULL && domain_event_cb_id != -1) - virConnectDomainEventDeregisterAny(conn, domain_event_cb_id); +static void stop_event_loop(virt_notif_thread_t *thread_data) { + /* stopping loop and de-registering event handler*/ + virt_notif_thread_set_active(thread_data, 0); + if (conn != NULL && thread_data->domain_event_cb_id != -1) + virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id); + + if (pthread_join(notif_thread.event_loop_tid, NULL) != 0) + ERROR(PLUGIN_NAME " plugin: stopping notification thread failed"); } static int persistent_domains_state_notification(void) { int status = 0; int n; #ifdef HAVE_LIST_ALL_DOMAINS - virDomainPtr *domains; + virDomainPtr *domains = NULL; n = virConnectListAllDomains(conn, &domains, - VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT); + VIR_CONNECT_LIST_DOMAINS_PERSISTENT); if (n < 0) { VIRT_ERROR(conn, "reading list of persistent domains"); status = -1; - } - else { + } else { DEBUG(PLUGIN_NAME " plugin: getting state of %i persistent domains", n); /* Fetch each persistent domain's state and notify it */ int n_notified = n; @@ -1889,6 +2143,7 @@ static int persistent_domains_state_notification(void) { ERROR(PLUGIN_NAME " plugin: could not notify state of domain %s", virDomainGetName(domains[i])); } + virDomainFree(domains[i]); } sfree(domains); @@ -1900,9 +2155,9 @@ static int persistent_domains_state_notification(void) { if (n > 0) { int *domids; /* Get list of domains. */ - domids = malloc(sizeof(*domids) * n); + domids = calloc(n, sizeof(*domids)); if (domids == NULL) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); + ERROR(PLUGIN_NAME " plugin: calloc failed."); return -1; } n = virConnectListDomains(conn, domids, n); @@ -1922,14 +2177,15 @@ static int persistent_domains_state_notification(void) { continue; } status = virDomainGetInfo(dom, &info); - if (status != 0) { + if (status == 0) + /* virDomainGetState is not available. Submit 0, which corresponds to + * unknown reason. */ + domain_state_submit_notif(dom, info.state, 0); + else ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", status); - continue; - } - /* virDomainGetState is not available. Submit 0, which corresponds to - * unknown reason. */ - domain_state_submit_notif(dom, info.state, 0); + + virDomainFree(dom); } sfree(domids); } @@ -1951,7 +2207,7 @@ static int lv_read(user_data_t *ud) { inst = ud->data; state = &inst->read_state; - _Bool reconnect = conn == NULL ? 1 : 0; + bool reconnect = conn == NULL ? true : false; /* event implementation must be registered before connection is opened */ if (inst->id == 0) { if (!persistent_notification && reconnect) @@ -1962,7 +2218,7 @@ static int lv_read(user_data_t *ud) { return -1; if (!persistent_notification && reconnect && conn != NULL) - if (start_event_loop() != 0) + if (start_event_loop(¬if_thread) != 0) return -1; } @@ -1971,16 +2227,10 @@ static int lv_read(user_data_t *ud) { /* Need to refresh domain or device lists? */ if ((last_refresh == (time_t)0) || ((interval > 0) && ((last_refresh + interval) <= t))) { - if (inst->id == 0 && persistent_notification) { - int status = persistent_domains_state_notification(); - if (status != 0) - DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications " \ - "returned with status %i", status); - } if (refresh_lists(inst) != 0) { if (inst->id == 0) { if (!persistent_notification) - stop_event_loop(); + stop_event_loop(¬if_thread); lv_disconnect(); } return -1; @@ -1988,52 +2238,64 @@ static int lv_read(user_data_t *ud) { last_refresh = t; } - #if COLLECT_DEBUG - for (int i = 0; i < state->nr_domains; ++i) - DEBUG(PLUGIN_NAME " plugin: domain %s", - virDomainGetName(state->domains[i].ptr)); - for (int i = 0; i < state->nr_block_devices; ++i) - DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s", - i, virDomainGetName(state->block_devices[i].dom), - state->block_devices[i].path); - for (int i = 0; i < state->nr_interface_devices; ++i) - DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s", - i, virDomainGetName(state->interface_devices[i].dom), - state->interface_devices[i].path); - #endif + /* persistent domains state notifications are handled by instance 0 */ + if (inst->id == 0 && persistent_notification) { + int status = persistent_domains_state_notification(); + if (status != 0) + DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications " + "returned with status %i", + status); + } + +#if COLLECT_DEBUG + for (int i = 0; i < state->nr_domains; ++i) + DEBUG(PLUGIN_NAME " plugin: domain %s", + virDomainGetName(state->domains[i].ptr)); + for (int i = 0; i < state->nr_block_devices; ++i) + DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s", i, + virDomainGetName(state->block_devices[i].dom), + state->block_devices[i].path); + for (int i = 0; i < state->nr_interface_devices; ++i) + DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s", i, + virDomainGetName(state->interface_devices[i].dom), + state->interface_devices[i].path); +#endif /* Get domains' metrics */ for (int i = 0; i < state->nr_domains; ++i) { domain_t *dom = &state->domains[i]; - int status; + int status = 0; if (dom->active) status = get_domain_metrics(dom); +#ifdef HAVE_DOM_REASON else status = get_domain_state(dom->ptr); +#endif if (status != 0) - ERROR(PLUGIN_NAME " failed to get metrics for domain=%s", + ERROR(PLUGIN_NAME " plugin: failed to get metrics for domain=%s", virDomainGetName(dom->ptr)); } /* Get block device stats for each domain. */ for (int i = 0; i < state->nr_block_devices; ++i) { - int status = get_block_stats(&state->block_devices[i]); + int status = get_block_device_stats(&state->block_devices[i]); if (status != 0) ERROR(PLUGIN_NAME - " failed to get stats for block device (%s) in domain %s", + " plugin: failed to get stats for block device (%s) in domain %s", state->block_devices[i].path, - virDomainGetName(state->domains[i].ptr)); + virDomainGetName(state->block_devices[i].dom)); } /* Get interface stats for each domain. */ for (int i = 0; i < state->nr_interface_devices; ++i) { int status = get_if_dev_stats(&state->interface_devices[i]); if (status != 0) - ERROR(PLUGIN_NAME - " failed to get interface stats for device (%s) in domain %s", - state->interface_devices[i].path, - virDomainGetName(state->interface_devices[i].dom)); + ERROR( + PLUGIN_NAME + " plugin: failed to get interface stats for device (%s) in domain %s", + state->interface_devices[i].path, + virDomainGetName(state->interface_devices[i].dom)); } return 0; @@ -2076,6 +2338,10 @@ static int lv_init(void) { if (virInitialize() != 0) return -1; + /* Init ignorelists if there was no explicit configuration */ + if (lv_init_ignorelists() != 0) + return -1; + /* event implementation must be registered before connection is opened */ if (!persistent_notification) if (register_event_impl() != 0) @@ -2086,9 +2352,11 @@ static int lv_init(void) { DEBUG(PLUGIN_NAME " plugin: starting event loop"); - if (!persistent_notification) - if (start_event_loop() != 0) + if (!persistent_notification) { + virt_notif_thread_init(¬if_thread); + if (start_event_loop(¬if_thread) != 0) return -1; + } DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances); @@ -2193,6 +2461,135 @@ static int lv_instance_include_domain(struct lv_read_instance *inst, return 0; } +static void lv_add_block_devices(struct lv_read_state *state, virDomainPtr dom, + const char *domname, + xmlXPathContextPtr xpath_ctx) { + xmlXPathObjectPtr xpath_obj = + xmlXPathEval((const xmlChar *)"/domain/devices/disk", xpath_ctx); + + if (xpath_obj == NULL) { + DEBUG(PLUGIN_NAME " plugin: no disk xpath-object found for domain %s", + domname); + return; + } + + if (xpath_obj->type != XPATH_NODESET || xpath_obj->nodesetval == NULL) { + DEBUG(PLUGIN_NAME " plugin: no disk node found for domain %s", domname); + goto cleanup; + } + + xmlNodeSetPtr xml_block_devices = xpath_obj->nodesetval; + for (int i = 0; i < xml_block_devices->nodeNr; ++i) { + xmlNodePtr xml_device = xpath_obj->nodesetval->nodeTab[i]; + char *path_str = NULL; + char *source_str = NULL; + + if (!xml_device) + continue; + + /* Fetching path and source for block device */ + for (xmlNodePtr child = xml_device->children; child; child = child->next) { + if (child->type != XML_ELEMENT_NODE) + continue; + + /* we are interested only in either "target" or "source" elements */ + if (xmlStrEqual(child->name, (const xmlChar *)"target")) + path_str = (char *)xmlGetProp(child, (const xmlChar *)"dev"); + else if (xmlStrEqual(child->name, (const xmlChar *)"source")) { + /* name of the source is located in "dev" or "file" element (it depends + * on type of source). Trying "dev" at first*/ + source_str = (char *)xmlGetProp(child, (const xmlChar *)"dev"); + if (!source_str) + source_str = (char *)xmlGetProp(child, (const xmlChar *)"file"); + } + /* ignoring any other element*/ + } + + /* source_str will be interpreted as a device path if blockdevice_format + * param is set to 'source'. */ + const char *device_path = + (blockdevice_format == source) ? source_str : path_str; + + if (!device_path) { + /* no path found and we can't add block_device without it */ + WARNING(PLUGIN_NAME " plugin: could not generate device path for disk in " + "domain %s - disk device will be ignored in reports", + domname); + goto cont; + } + + if (ignore_device_match(il_block_devices, domname, device_path) == 0) { + /* we only have to store information whether 'source' exists or not */ + bool has_source = (source_str != NULL) ? true : false; + + add_block_device(state, dom, device_path, has_source); + } + + cont: + if (path_str) + xmlFree(path_str); + + if (source_str) + xmlFree(source_str); + } + +cleanup: + xmlXPathFreeObject(xpath_obj); +} + +static void lv_add_network_interfaces(struct lv_read_state *state, + virDomainPtr dom, const char *domname, + xmlXPathContextPtr xpath_ctx) { + xmlXPathObjectPtr xpath_obj = xmlXPathEval( + (xmlChar *)"/domain/devices/interface[target[@dev]]", xpath_ctx); + + if (xpath_obj == NULL) + return; + + if (xpath_obj->type != XPATH_NODESET || xpath_obj->nodesetval == NULL) { + xmlXPathFreeObject(xpath_obj); + return; + } + + xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval; + + for (int j = 0; j < xml_interfaces->nodeNr; ++j) { + char *path = NULL; + char *address = NULL; + + xmlNodePtr xml_interface = xml_interfaces->nodeTab[j]; + if (!xml_interface) + continue; + + for (xmlNodePtr 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 ((ignore_device_match(il_interface_devices, domname, path) == 0 && + ignore_device_match(il_interface_devices, domname, address) == 0)) { + add_interface_device(state, dom, path, address, j + 1); + } + + if (path) + xmlFree(path); + if (address) + xmlFree(address); + } + xmlXPathFreeObject(xpath_obj); +} + static int refresh_lists(struct lv_read_instance *inst) { struct lv_read_state *state = &inst->read_state; int n; @@ -2216,15 +2613,12 @@ static int refresh_lists(struct lv_read_instance *inst) { virDomainPtr *domains, *domains_inactive; int m = virConnectListAllDomains(conn, &domains_inactive, VIR_CONNECT_LIST_DOMAINS_INACTIVE); - n = virConnectListAllDomains(conn, &domains, - VIR_CONNECT_LIST_DOMAINS_ACTIVE); + n = virConnectListAllDomains(conn, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE); #else - int *domids; - /* Get list of domains. */ - domids = malloc(sizeof(*domids) * n); + int *domids = calloc(n, sizeof(*domids)); if (domids == NULL) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); + ERROR(PLUGIN_NAME " plugin: calloc failed."); return -1; } @@ -2236,6 +2630,8 @@ static int refresh_lists(struct lv_read_instance *inst) { #ifndef HAVE_LIST_ALL_DOMAINS sfree(domids); #else + for (int i = 0; i < m; ++i) + virDomainFree(domains_inactive[i]); sfree(domains_inactive); #endif return -1; @@ -2245,26 +2641,19 @@ static int refresh_lists(struct lv_read_instance *inst) { for (int i = 0; i < m; ++i) if (add_domain(state, domains_inactive[i], 0) < 0) { ERROR(PLUGIN_NAME " plugin: malloc failed."); + virDomainFree(domains_inactive[i]); + domains_inactive[i] = NULL; continue; } #endif /* Fetch each domain and add it to the list, unless ignore. */ for (int i = 0; i < n; ++i) { - const char *name; - char *xml = NULL; - xmlDocPtr xml_doc = NULL; - xmlXPathContextPtr xpath_ctx = NULL; - xmlXPathObjectPtr xpath_obj = NULL; - char tag[PARTITION_TAG_MAX_LEN] = {'\0'}; - virDomainInfo info; - int status; #ifdef HAVE_LIST_ALL_DOMAINS virDomainPtr dom = domains[i]; #else - virDomainPtr dom = NULL; - dom = virDomainLookupByID(conn, domids[i]); + virDomainPtr dom = virDomainLookupByID(conn, domids[i]); if (dom == NULL) { VIRT_ERROR(conn, "virDomainLookupByID"); /* Could be that the domain went away -- ignore it anyway. */ @@ -2272,13 +2661,28 @@ static int refresh_lists(struct lv_read_instance *inst) { } #endif - name = virDomainGetName(dom); - if (name == NULL) { + if (add_domain(state, dom, 1) < 0) { + /* + * When domain is already tracked, then there is + * no problem with memory handling (will be freed + * with the rest of domains cached data) + * But in case of error like this (error occurred + * before adding domain to track) we have to take + * care it ourselves and call virDomainFree + */ + ERROR(PLUGIN_NAME " plugin: malloc failed."); + virDomainFree(dom); + continue; + } + + const char *domname = virDomainGetName(dom); + if (domname == NULL) { VIRT_ERROR(conn, "virDomainGetName"); - goto cont; + continue; } - status = virDomainGetInfo(dom, &info); + virDomainInfo info; + int status = virDomainGetInfo(dom, &info); if (status != 0) { ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", status); @@ -2286,15 +2690,18 @@ static int refresh_lists(struct lv_read_instance *inst) { } if (info.state != VIR_DOMAIN_RUNNING) { - DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", name); + DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", domname); continue; } - if (il_domains && ignorelist_match(il_domains, name) != 0) - goto cont; + if (ignorelist_match(il_domains, domname) != 0) + continue; /* Get a list of devices for this domain. */ - xml = virDomainGetXMLDesc(dom, 0); + xmlDocPtr xml_doc = NULL; + xmlXPathContextPtr xpath_ctx = NULL; + + char *xml = virDomainGetXMLDesc(dom, 0); if (!xml) { VIRT_ERROR(conn, "virDomainGetXMLDesc"); goto cont; @@ -2309,101 +2716,24 @@ static int refresh_lists(struct lv_read_instance *inst) { xpath_ctx = xmlXPathNewContext(xml_doc); - if (lv_domain_get_tag(xpath_ctx, name, tag) < 0) { + char tag[PARTITION_TAG_MAX_LEN] = {'\0'}; + if (lv_domain_get_tag(xpath_ctx, domname, tag) < 0) { ERROR(PLUGIN_NAME " plugin: lv_domain_get_tag failed."); goto cont; } - if (!lv_instance_include_domain(inst, name, tag)) + if (!lv_instance_include_domain(inst, domname, tag)) goto cont; - if (add_domain(state, dom, 1) < 0) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); - goto cont; - } - /* Block devices. */ - const char *bd_xmlpath = "/domain/devices/disk/target[@dev]"; - if (blockdevice_format == source) - bd_xmlpath = "/domain/devices/disk/source[@dev]"; - xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx); - - if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET || - xpath_obj->nodesetval == NULL) - goto cont; - - for (int j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) { - xmlNodePtr node; - char *path = NULL; - - node = xpath_obj->nodesetval->nodeTab[j]; - if (!node) - continue; - path = (char *)xmlGetProp(node, (xmlChar *)"dev"); - if (!path) - continue; - - if (il_block_devices && - ignore_device_match(il_block_devices, name, path) != 0) - goto cont2; - - add_block_device(state, dom, path); - cont2: - if (path) - xmlFree(path); - } - xmlXPathFreeObject(xpath_obj); + if (report_block_devices) + lv_add_block_devices(state, dom, domname, xpath_ctx); /* Network interfaces. */ - xpath_obj = xmlXPathEval( - (xmlChar *)"/domain/devices/interface[target[@dev]]", xpath_ctx); - if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET || - xpath_obj->nodesetval == NULL) - goto cont; - - xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval; - - for (int j = 0; j < xml_interfaces->nodeNr; ++j) { - char *path = NULL; - char *address = NULL; - xmlNodePtr xml_interface; - - xml_interface = xml_interfaces->nodeTab[j]; - if (!xml_interface) - continue; - - for (xmlNodePtr 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, address) != 0)) - goto cont3; - - add_interface_device(state, dom, path, address, j + 1); - cont3: - if (path) - xmlFree(path); - if (address) - xmlFree(address); - } + if (report_network_interfaces) + lv_add_network_interfaces(state, dom, domname, xpath_ctx); cont: - if (xpath_obj) - xmlXPathFreeObject(xpath_obj); if (xpath_ctx) xmlXPathFreeContext(xpath_ctx); if (xml_doc) @@ -2412,6 +2742,9 @@ static int refresh_lists(struct lv_read_instance *inst) { } #ifdef HAVE_LIST_ALL_DOMAINS + /* NOTE: domains_active and domains_inactive data will be cleared during + refresh of all domains (inside lv_clean_read_state function) so we need + to free here only allocated arrays */ sfree(domains); sfree(domains_inactive); #else @@ -2439,15 +2772,11 @@ static void free_domains(struct lv_read_state *state) { } static int add_domain(struct lv_read_state *state, virDomainPtr dom, - _Bool active) { - domain_t *new_ptr; - int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1); + bool active) { - if (state->domains) - new_ptr = realloc(state->domains, new_size); - else - new_ptr = malloc(new_size); + int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1); + domain_t *new_ptr = realloc(state->domains, new_size); if (new_ptr == NULL) return -1; @@ -2471,21 +2800,16 @@ static void free_block_devices(struct lv_read_state *state) { } static int add_block_device(struct lv_read_state *state, virDomainPtr dom, - const char *path) { - struct block_device *new_ptr; - int new_size = - sizeof(state->block_devices[0]) * (state->nr_block_devices + 1); - char *path_copy; + const char *path, bool has_source) { - path_copy = strdup(path); + char *path_copy = strdup(path); if (!path_copy) return -1; - if (state->block_devices) - new_ptr = realloc(state->block_devices, new_size); - else - new_ptr = malloc(new_size); + int new_size = + sizeof(state->block_devices[0]) * (state->nr_block_devices + 1); + struct block_device *new_ptr = realloc(state->block_devices, new_size); if (new_ptr == NULL) { sfree(path_copy); return -1; @@ -2493,6 +2817,7 @@ static int add_block_device(struct lv_read_state *state, virDomainPtr dom, state->block_devices = new_ptr; state->block_devices[state->nr_block_devices].dom = dom; state->block_devices[state->nr_block_devices].path = path_copy; + state->block_devices[state->nr_block_devices].has_source = has_source; return state->nr_block_devices++; } @@ -2512,61 +2837,62 @@ static void free_interface_devices(struct lv_read_state *state) { static int add_interface_device(struct lv_read_state *state, virDomainPtr dom, const char *path, const char *address, unsigned int number) { - struct interface_device *new_ptr; - int new_size = - sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1); - char *path_copy, *address_copy, number_string[15]; if ((path == NULL) || (address == NULL)) return EINVAL; - path_copy = strdup(path); + char *path_copy = strdup(path); if (!path_copy) return -1; - address_copy = strdup(address); + char *address_copy = strdup(address); if (!address_copy) { sfree(path_copy); return -1; } + char number_string[21]; snprintf(number_string, sizeof(number_string), "interface-%u", number); + char *number_copy = strdup(number_string); + if (!number_copy) { + sfree(path_copy); + sfree(address_copy); + return -1; + } - if (state->interface_devices) - new_ptr = realloc(state->interface_devices, new_size); - else - new_ptr = malloc(new_size); + int new_size = + sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1); + struct interface_device *new_ptr = + realloc(state->interface_devices, new_size); if (new_ptr == NULL) { sfree(path_copy); sfree(address_copy); + sfree(number_copy); return -1; } + state->interface_devices = new_ptr; state->interface_devices[state->nr_interface_devices].dom = dom; state->interface_devices[state->nr_interface_devices].path = path_copy; state->interface_devices[state->nr_interface_devices].address = address_copy; - state->interface_devices[state->nr_interface_devices].number = - strdup(number_string); + state->interface_devices[state->nr_interface_devices].number = number_copy; return state->nr_interface_devices++; } static int ignore_device_match(ignorelist_t *il, const char *domname, const char *devpath) { - char *name; - int n, r; - if ((domname == NULL) || (devpath == NULL)) return 0; - n = strlen(domname) + strlen(devpath) + 2; - name = malloc(n); + size_t n = strlen(domname) + strlen(devpath) + 2; + char *name = malloc(n); if (name == NULL) { ERROR(PLUGIN_NAME " plugin: malloc failed."); return 0; } snprintf(name, n, "%s:%s", domname, devpath); - r = ignorelist_match(il, name); + int r = ignorelist_match(il, name); sfree(name); return r; } @@ -2579,7 +2905,7 @@ static int lv_shutdown(void) { DEBUG(PLUGIN_NAME " plugin: stopping event loop"); if (!persistent_notification) - stop_event_loop(); + stop_event_loop(¬if_thread); lv_disconnect();