diff --git a/ChangeLog b/ChangeLog index 415c9601ef..2473f4dd06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Tue Aug 21 10:58:00 BST 2007 Richard W.M. Jones + + * src/libvirt.c (virDomainBlockStats, virDomainInterfaceStats): + Added block device and network interface statistics. + * src/xen_internal.c: Support for stats from Xen domains. + * qemud/remote.c, qemud/remote_protocol.x, qemud/remote_internal.c: + Support for fetching device and network interface stats + across remote connections. + * src/virsh.c: Added 'virsh domblkstat' and 'virsh domifstat' + commands to display stats. + * docs/libvir.html, docs/hvsupport.html: Updated hvsupport + documentation. + Tue Aug 21 10:36:00 BST 2007 Richard W.M. Jones * tests/xencapsdata/*.xml: Fixed tests to include new diff --git a/docs/hvsupport.html b/docs/hvsupport.html index fe7f30faf3..b6244e088e 100644 --- a/docs/hvsupport.html +++ b/docs/hvsupport.html @@ -96,6 +96,12 @@ updated on 2007-08-20. x x ≥ 0.3.0 + virDomainBlockStats + 0.3.2 + ≥ 0.3.2 + x + x + ≥ 0.3.2 virDomainCoreDump 0.1.9 ≥ 0.1.9 @@ -213,6 +219,12 @@ updated on 2007-08-20. x x ≥ 0.3.0 + virDomainInterfaceStats + 0.3.2 + ≥ 0.3.2 + x + x + ≥ 0.3.2 virDomainGetXMLDesc All All diff --git a/docs/libvir.html b/docs/libvir.html index 0e7539d8db..2365653c88 100644 --- a/docs/libvir.html +++ b/docs/libvir.html @@ -2799,6 +2799,14 @@ updated on 2007-08-20. x ≥ 0.3.0 + + virDomainBlockStats + 0.3.2 + ≥ 0.3.2 + x + x + ≥ 0.3.2 + virDomainCoreDump 0.1.9 @@ -2956,6 +2964,14 @@ updated on 2007-08-20. x ≥ 0.3.0 + + virDomainInterfaceStats + 0.3.2 + ≥ 0.3.2 + x + x + ≥ 0.3.2 + virDomainGetXMLDesc All diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 0ef4e27080..3a22f9a09a 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -14,6 +14,8 @@ #ifndef __VIR_VIRLIB_H__ #define __VIR_VIRLIB_H__ +#include + #ifdef __cplusplus extern "C" { #endif @@ -197,6 +199,41 @@ int virDomainSetSchedulerParameters (virDomainPtr domain, virSchedParameterPtr params, int nparams); +/* Block device stats for virDomainBlockStats. + * + * Hypervisors may return a field set to ((long long)-1) which indicates + * that the hypervisor does not support that statistic. + * + * NB. Here 'long long' means 64 bit integer. + */ +struct _virDomainBlockStats { + long long rd_req; + long long rd_bytes; + long long wr_req; + long long wr_bytes; + long long errs; // In Xen this returns the mysterious 'oo_req'. +}; +typedef struct _virDomainBlockStats *virDomainBlockStatsPtr; + +/* Network interface stats for virDomainInterfaceStats. + * + * Hypervisors may return a field set to ((long long)-1) which indicates + * that the hypervisor does not support that statistic. + * + * NB. Here 'long long' means 64 bit integer. + */ +struct _virDomainInterfaceStats { + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_drop; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_drop; +}; +typedef struct _virDomainInterfaceStats *virDomainInterfaceStatsPtr; + /* Domain migration flags. */ typedef enum { VIR_MIGRATE_LIVE = 1, /* live migration */ @@ -379,6 +416,16 @@ int virDomainGetMaxVcpus (virDomainPtr domain); char * virDomainGetXMLDesc (virDomainPtr domain, int flags); +int virDomainBlockStats (virDomainPtr dom, + const char *path, + virDomainBlockStatsPtr stats, + size_t size); +int virDomainInterfaceStats (virDomainPtr dom, + const char *path, + virDomainInterfaceStatsPtr stats, + size_t size); + + /* * defined but not running domains */ diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 255d11e2d0..7a0df52d11 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -14,6 +14,8 @@ #ifndef __VIR_VIRLIB_H__ #define __VIR_VIRLIB_H__ +#include + #ifdef __cplusplus extern "C" { #endif @@ -197,6 +199,41 @@ int virDomainSetSchedulerParameters (virDomainPtr domain, virSchedParameterPtr params, int nparams); +/* Block device stats for virDomainBlockStats. + * + * Hypervisors may return a field set to ((long long)-1) which indicates + * that the hypervisor does not support that statistic. + * + * NB. Here 'long long' means 64 bit integer. + */ +struct _virDomainBlockStats { + long long rd_req; + long long rd_bytes; + long long wr_req; + long long wr_bytes; + long long errs; // In Xen this returns the mysterious 'oo_req'. +}; +typedef struct _virDomainBlockStats *virDomainBlockStatsPtr; + +/* Network interface stats for virDomainInterfaceStats. + * + * Hypervisors may return a field set to ((long long)-1) which indicates + * that the hypervisor does not support that statistic. + * + * NB. Here 'long long' means 64 bit integer. + */ +struct _virDomainInterfaceStats { + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_drop; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_drop; +}; +typedef struct _virDomainInterfaceStats *virDomainInterfaceStatsPtr; + /* Domain migration flags. */ typedef enum { VIR_MIGRATE_LIVE = 1, /* live migration */ @@ -379,6 +416,16 @@ int virDomainGetMaxVcpus (virDomainPtr domain); char * virDomainGetXMLDesc (virDomainPtr domain, int flags); +int virDomainBlockStats (virDomainPtr dom, + const char *path, + virDomainBlockStatsPtr stats, + size_t size); +int virDomainInterfaceStats (virDomainPtr dom, + const char *path, + virDomainInterfaceStatsPtr stats, + size_t size); + + /* * defined but not running domains */ diff --git a/qemud/remote.c b/qemud/remote.c index 90ee1529d7..7bbe51024e 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -714,6 +714,69 @@ remoteDispatchDomainSetSchedulerParameters (struct qemud_client *client, return 0; } +static int +remoteDispatchDomainBlockStats (struct qemud_client *client, + remote_message_header *req, + remote_domain_block_stats_args *args, + remote_domain_block_stats_ret *ret) +{ + virDomainPtr dom; + char *path; + struct _virDomainBlockStats stats; + CHECK_CONN (client); + + dom = get_nonnull_domain (client->conn, args->dom); + if (dom == NULL) { + remoteDispatchError (client, req, "domain not found"); + return -2; + } + path = args->path; + + if (virDomainBlockStats (dom, path, &stats, sizeof stats) == -1) + return -1; + + ret->rd_req = stats.rd_req; + ret->rd_bytes = stats.rd_bytes; + ret->wr_req = stats.wr_req; + ret->wr_bytes = stats.wr_bytes; + ret->errs = stats.errs; + + return 0; +} + +static int +remoteDispatchDomainInterfaceStats (struct qemud_client *client, + remote_message_header *req, + remote_domain_interface_stats_args *args, + remote_domain_interface_stats_ret *ret) +{ + virDomainPtr dom; + char *path; + struct _virDomainInterfaceStats stats; + CHECK_CONN (client); + + dom = get_nonnull_domain (client->conn, args->dom); + if (dom == NULL) { + remoteDispatchError (client, req, "domain not found"); + return -2; + } + path = args->path; + + if (virDomainInterfaceStats (dom, path, &stats, sizeof stats) == -1) + return -1; + + ret->rx_bytes = stats.rx_bytes; + ret->rx_packets = stats.rx_packets; + ret->rx_errs = stats.rx_errs; + ret->rx_drop = stats.rx_drop; + ret->tx_bytes = stats.tx_bytes; + ret->tx_packets = stats.tx_packets; + ret->tx_errs = stats.tx_errs; + ret->tx_drop = stats.tx_drop; + + return 0; +} + static int remoteDispatchDomainAttachDevice (struct qemud_client *client, remote_message_header *req, diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h index 07795d7c9e..92ec482f85 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -2,94 +2,98 @@ * Do not edit this file. Any changes you make will be lost. */ -remote_network_lookup_by_name_args lv_remote_network_lookup_by_name_args; -remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret; remote_domain_lookup_by_uuid_args lv_remote_domain_lookup_by_uuid_args; remote_domain_lookup_by_uuid_ret lv_remote_domain_lookup_by_uuid_ret; -remote_num_of_defined_domains_ret lv_remote_num_of_defined_domains_ret; -remote_domain_detach_device_args lv_remote_domain_detach_device_args; -remote_domain_save_args lv_remote_domain_save_args; remote_domain_shutdown_args lv_remote_domain_shutdown_args; remote_list_defined_domains_args lv_remote_list_defined_domains_args; remote_list_defined_domains_ret lv_remote_list_defined_domains_ret; -remote_domain_migrate_prepare_args lv_remote_domain_migrate_prepare_args; -remote_domain_migrate_prepare_ret lv_remote_domain_migrate_prepare_ret; remote_get_capabilities_ret lv_remote_get_capabilities_ret; remote_domain_set_max_memory_args lv_remote_domain_set_max_memory_args; -remote_domain_undefine_args lv_remote_domain_undefine_args; remote_domain_get_os_type_args lv_remote_domain_get_os_type_args; remote_domain_get_os_type_ret lv_remote_domain_get_os_type_ret; remote_domain_get_autostart_args lv_remote_domain_get_autostart_args; remote_domain_get_autostart_ret lv_remote_domain_get_autostart_ret; remote_domain_set_vcpus_args lv_remote_domain_set_vcpus_args; -remote_domain_get_scheduler_type_args lv_remote_domain_get_scheduler_type_args; -remote_domain_get_scheduler_type_ret lv_remote_domain_get_scheduler_type_ret; remote_get_hostname_ret lv_remote_get_hostname_ret; remote_network_undefine_args lv_remote_network_undefine_args; remote_domain_create_args lv_remote_domain_create_args; -remote_domain_suspend_args lv_remote_domain_suspend_args; -remote_get_version_ret lv_remote_get_version_ret; remote_network_destroy_args lv_remote_network_destroy_args; -remote_network_set_autostart_args lv_remote_network_set_autostart_args; -remote_network_get_autostart_args lv_remote_network_get_autostart_args; -remote_network_get_autostart_ret lv_remote_network_get_autostart_ret; remote_domain_pin_vcpu_args lv_remote_domain_pin_vcpu_args; remote_list_defined_networks_args lv_remote_list_defined_networks_args; remote_list_defined_networks_ret lv_remote_list_defined_networks_ret; remote_network_create_xml_args lv_remote_network_create_xml_args; remote_network_create_xml_ret lv_remote_network_create_xml_ret; -remote_domain_core_dump_args lv_remote_domain_core_dump_args; remote_open_args lv_remote_open_args; remote_list_domains_args lv_remote_list_domains_args; remote_list_domains_ret lv_remote_list_domains_ret; remote_network_define_xml_args lv_remote_network_define_xml_args; remote_network_define_xml_ret lv_remote_network_define_xml_ret; -remote_domain_get_max_memory_args lv_remote_domain_get_max_memory_args; -remote_domain_get_max_memory_ret lv_remote_domain_get_max_memory_ret; remote_get_type_ret lv_remote_get_type_ret; -remote_num_of_domains_ret lv_remote_num_of_domains_ret; -remote_list_networks_args lv_remote_list_networks_args; -remote_list_networks_ret lv_remote_list_networks_ret; remote_network_dump_xml_args lv_remote_network_dump_xml_args; remote_network_dump_xml_ret lv_remote_network_dump_xml_ret; -remote_domain_set_autostart_args lv_remote_domain_set_autostart_args; remote_domain_reboot_args lv_remote_domain_reboot_args; remote_domain_set_memory_args lv_remote_domain_set_memory_args; remote_domain_create_linux_args lv_remote_domain_create_linux_args; remote_domain_create_linux_ret lv_remote_domain_create_linux_ret; remote_domain_set_scheduler_parameters_args lv_remote_domain_set_scheduler_parameters_args; -remote_domain_attach_device_args lv_remote_domain_attach_device_args; -remote_domain_lookup_by_id_args lv_remote_domain_lookup_by_id_args; -remote_domain_lookup_by_id_ret lv_remote_domain_lookup_by_id_ret; -remote_num_of_networks_ret lv_remote_num_of_networks_ret; -remote_domain_restore_args lv_remote_domain_restore_args; +remote_domain_interface_stats_args lv_remote_domain_interface_stats_args; +remote_domain_interface_stats_ret lv_remote_domain_interface_stats_ret; remote_domain_get_max_vcpus_args lv_remote_domain_get_max_vcpus_args; remote_domain_get_max_vcpus_ret lv_remote_domain_get_max_vcpus_ret; remote_domain_get_info_args lv_remote_domain_get_info_args; remote_domain_get_info_ret lv_remote_domain_get_info_ret; -remote_network_create_args lv_remote_network_create_args; -remote_num_of_defined_networks_ret lv_remote_num_of_defined_networks_ret; remote_supports_feature_args lv_remote_supports_feature_args; remote_supports_feature_ret lv_remote_supports_feature_ret; remote_domain_lookup_by_name_args lv_remote_domain_lookup_by_name_args; remote_domain_lookup_by_name_ret lv_remote_domain_lookup_by_name_ret; -remote_network_lookup_by_uuid_args lv_remote_network_lookup_by_uuid_args; -remote_network_lookup_by_uuid_ret lv_remote_network_lookup_by_uuid_ret; remote_domain_resume_args lv_remote_domain_resume_args; remote_network_get_bridge_name_args lv_remote_network_get_bridge_name_args; remote_network_get_bridge_name_ret lv_remote_network_get_bridge_name_ret; remote_domain_destroy_args lv_remote_domain_destroy_args; -remote_domain_define_xml_args lv_remote_domain_define_xml_args; -remote_domain_define_xml_ret lv_remote_domain_define_xml_ret; remote_domain_migrate_finish_args lv_remote_domain_migrate_finish_args; remote_domain_migrate_finish_ret lv_remote_domain_migrate_finish_ret; remote_domain_get_vcpus_args lv_remote_domain_get_vcpus_args; remote_domain_get_vcpus_ret lv_remote_domain_get_vcpus_ret; remote_domain_get_scheduler_parameters_args lv_remote_domain_get_scheduler_parameters_args; remote_domain_get_scheduler_parameters_ret lv_remote_domain_get_scheduler_parameters_ret; +remote_node_get_info_ret lv_remote_node_get_info_ret; +remote_network_lookup_by_name_args lv_remote_network_lookup_by_name_args; +remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret; +remote_num_of_defined_domains_ret lv_remote_num_of_defined_domains_ret; +remote_domain_block_stats_args lv_remote_domain_block_stats_args; +remote_domain_block_stats_ret lv_remote_domain_block_stats_ret; +remote_domain_detach_device_args lv_remote_domain_detach_device_args; +remote_domain_save_args lv_remote_domain_save_args; +remote_domain_migrate_prepare_args lv_remote_domain_migrate_prepare_args; +remote_domain_migrate_prepare_ret lv_remote_domain_migrate_prepare_ret; +remote_domain_undefine_args lv_remote_domain_undefine_args; +remote_domain_get_scheduler_type_args lv_remote_domain_get_scheduler_type_args; +remote_domain_get_scheduler_type_ret lv_remote_domain_get_scheduler_type_ret; +remote_get_version_ret lv_remote_get_version_ret; +remote_domain_suspend_args lv_remote_domain_suspend_args; +remote_network_set_autostart_args lv_remote_network_set_autostart_args; +remote_network_get_autostart_args lv_remote_network_get_autostart_args; +remote_network_get_autostart_ret lv_remote_network_get_autostart_ret; +remote_domain_core_dump_args lv_remote_domain_core_dump_args; +remote_domain_get_max_memory_args lv_remote_domain_get_max_memory_args; +remote_domain_get_max_memory_ret lv_remote_domain_get_max_memory_ret; +remote_num_of_domains_ret lv_remote_num_of_domains_ret; +remote_list_networks_args lv_remote_list_networks_args; +remote_list_networks_ret lv_remote_list_networks_ret; +remote_domain_set_autostart_args lv_remote_domain_set_autostart_args; +remote_domain_lookup_by_id_args lv_remote_domain_lookup_by_id_args; +remote_domain_lookup_by_id_ret lv_remote_domain_lookup_by_id_ret; +remote_domain_attach_device_args lv_remote_domain_attach_device_args; +remote_num_of_networks_ret lv_remote_num_of_networks_ret; +remote_domain_restore_args lv_remote_domain_restore_args; +remote_network_create_args lv_remote_network_create_args; +remote_num_of_defined_networks_ret lv_remote_num_of_defined_networks_ret; +remote_network_lookup_by_uuid_args lv_remote_network_lookup_by_uuid_args; +remote_network_lookup_by_uuid_ret lv_remote_network_lookup_by_uuid_ret; +remote_domain_define_xml_args lv_remote_domain_define_xml_args; +remote_domain_define_xml_ret lv_remote_domain_define_xml_ret; remote_domain_dump_xml_args lv_remote_domain_dump_xml_args; remote_domain_dump_xml_ret lv_remote_domain_dump_xml_ret; remote_get_max_vcpus_args lv_remote_get_max_vcpus_args; remote_get_max_vcpus_ret lv_remote_get_max_vcpus_ret; -remote_node_get_info_ret lv_remote_node_get_info_ret; remote_domain_migrate_perform_args lv_remote_domain_migrate_perform_args; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index e58d8e97fd..ba000f1f11 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -11,6 +11,15 @@ case REMOTE_PROC_DOMAIN_ATTACH_DEVICE: args = (char *) &lv_remote_domain_attach_device_args; memset (&lv_remote_domain_attach_device_args, 0, sizeof lv_remote_domain_attach_device_args); break; +case REMOTE_PROC_DOMAIN_BLOCK_STATS: + fn = (dispatch_fn) remoteDispatchDomainBlockStats; + args_filter = (xdrproc_t) xdr_remote_domain_block_stats_args; + args = (char *) &lv_remote_domain_block_stats_args; + memset (&lv_remote_domain_block_stats_args, 0, sizeof lv_remote_domain_block_stats_args); + ret_filter = (xdrproc_t) xdr_remote_domain_block_stats_ret; + ret = (char *) &lv_remote_domain_block_stats_ret; + memset (&lv_remote_domain_block_stats_ret, 0, sizeof lv_remote_domain_block_stats_ret); + break; case REMOTE_PROC_DOMAIN_CORE_DUMP: fn = (dispatch_fn) remoteDispatchDomainCoreDump; args_filter = (xdrproc_t) xdr_remote_domain_core_dump_args; @@ -134,6 +143,15 @@ case REMOTE_PROC_DOMAIN_GET_VCPUS: ret = (char *) &lv_remote_domain_get_vcpus_ret; memset (&lv_remote_domain_get_vcpus_ret, 0, sizeof lv_remote_domain_get_vcpus_ret); break; +case REMOTE_PROC_DOMAIN_INTERFACE_STATS: + fn = (dispatch_fn) remoteDispatchDomainInterfaceStats; + args_filter = (xdrproc_t) xdr_remote_domain_interface_stats_args; + args = (char *) &lv_remote_domain_interface_stats_args; + memset (&lv_remote_domain_interface_stats_args, 0, sizeof lv_remote_domain_interface_stats_args); + ret_filter = (xdrproc_t) xdr_remote_domain_interface_stats_ret; + ret = (char *) &lv_remote_domain_interface_stats_ret; + memset (&lv_remote_domain_interface_stats_ret, 0, sizeof lv_remote_domain_interface_stats_ret); + break; case REMOTE_PROC_DOMAIN_LOOKUP_BY_ID: fn = (dispatch_fn) remoteDispatchDomainLookupById; args_filter = (xdrproc_t) xdr_remote_domain_lookup_by_id_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 9ad9fb9b32..c1925fcc7a 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -4,6 +4,7 @@ static int remoteDispatchClose (struct qemud_client *client, remote_message_header *req, void *args, void *ret); static int remoteDispatchDomainAttachDevice (struct qemud_client *client, remote_message_header *req, remote_domain_attach_device_args *args, void *ret); +static int remoteDispatchDomainBlockStats (struct qemud_client *client, remote_message_header *req, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret); static int remoteDispatchDomainCoreDump (struct qemud_client *client, remote_message_header *req, remote_domain_core_dump_args *args, void *ret); static int remoteDispatchDomainCreate (struct qemud_client *client, remote_message_header *req, remote_domain_create_args *args, void *ret); static int remoteDispatchDomainCreateLinux (struct qemud_client *client, remote_message_header *req, remote_domain_create_linux_args *args, remote_domain_create_linux_ret *ret); @@ -19,6 +20,7 @@ static int remoteDispatchDomainGetOsType (struct qemud_client *client, remote_me static int remoteDispatchDomainGetSchedulerParameters (struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_parameters_args *args, remote_domain_get_scheduler_parameters_ret *ret); static int remoteDispatchDomainGetSchedulerType (struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_type_args *args, remote_domain_get_scheduler_type_ret *ret); static int remoteDispatchDomainGetVcpus (struct qemud_client *client, remote_message_header *req, remote_domain_get_vcpus_args *args, remote_domain_get_vcpus_ret *ret); +static int remoteDispatchDomainInterfaceStats (struct qemud_client *client, remote_message_header *req, remote_domain_interface_stats_args *args, remote_domain_interface_stats_ret *ret); static int remoteDispatchDomainLookupById (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret); static int remoteDispatchDomainLookupByName (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret); static int remoteDispatchDomainLookupByUuid (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index e5dfb1c2cb..b0f7c7c996 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -390,6 +390,68 @@ xdr_remote_domain_set_scheduler_parameters_args (XDR *xdrs, remote_domain_set_sc return TRUE; } +bool_t +xdr_remote_domain_block_stats_args (XDR *xdrs, remote_domain_block_stats_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->path)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_block_stats_ret (XDR *xdrs, remote_domain_block_stats_ret *objp) +{ + + if (!xdr_quad_t (xdrs, &objp->rd_req)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->rd_bytes)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->wr_req)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->wr_bytes)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->errs)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_interface_stats_args (XDR *xdrs, remote_domain_interface_stats_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->path)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_interface_stats_ret (XDR *xdrs, remote_domain_interface_stats_ret *objp) +{ + + if (!xdr_quad_t (xdrs, &objp->rx_bytes)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->rx_packets)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->rx_errs)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->rx_drop)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->tx_bytes)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->tx_packets)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->tx_errs)) + return FALSE; + if (!xdr_quad_t (xdrs, &objp->tx_drop)) + return FALSE; + return TRUE; +} + bool_t xdr_remote_list_domains_args (XDR *xdrs, remote_list_domains_args *objp) { diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h index 5a0310b561..a17a0d733f 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -182,6 +182,39 @@ struct remote_domain_set_scheduler_parameters_args { }; typedef struct remote_domain_set_scheduler_parameters_args remote_domain_set_scheduler_parameters_args; +struct remote_domain_block_stats_args { + remote_nonnull_domain dom; + remote_nonnull_string path; +}; +typedef struct remote_domain_block_stats_args remote_domain_block_stats_args; + +struct remote_domain_block_stats_ret { + quad_t rd_req; + quad_t rd_bytes; + quad_t wr_req; + quad_t wr_bytes; + quad_t errs; +}; +typedef struct remote_domain_block_stats_ret remote_domain_block_stats_ret; + +struct remote_domain_interface_stats_args { + remote_nonnull_domain dom; + remote_nonnull_string path; +}; +typedef struct remote_domain_interface_stats_args remote_domain_interface_stats_args; + +struct remote_domain_interface_stats_ret { + quad_t rx_bytes; + quad_t rx_packets; + quad_t rx_errs; + quad_t rx_drop; + quad_t tx_bytes; + quad_t tx_packets; + quad_t tx_errs; + quad_t tx_drop; +}; +typedef struct remote_domain_interface_stats_ret remote_domain_interface_stats_ret; + struct remote_list_domains_args { int maxids; }; @@ -693,6 +726,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61, REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62, REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63, + REMOTE_PROC_DOMAIN_BLOCK_STATS = 64, + REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65, }; typedef enum remote_procedure remote_procedure; @@ -748,6 +783,10 @@ extern bool_t xdr_remote_domain_get_scheduler_type_ret (XDR *, remote_domain_ge extern bool_t xdr_remote_domain_get_scheduler_parameters_args (XDR *, remote_domain_get_scheduler_parameters_args*); extern bool_t xdr_remote_domain_get_scheduler_parameters_ret (XDR *, remote_domain_get_scheduler_parameters_ret*); extern bool_t xdr_remote_domain_set_scheduler_parameters_args (XDR *, remote_domain_set_scheduler_parameters_args*); +extern bool_t xdr_remote_domain_block_stats_args (XDR *, remote_domain_block_stats_args*); +extern bool_t xdr_remote_domain_block_stats_ret (XDR *, remote_domain_block_stats_ret*); +extern bool_t xdr_remote_domain_interface_stats_args (XDR *, remote_domain_interface_stats_args*); +extern bool_t xdr_remote_domain_interface_stats_ret (XDR *, remote_domain_interface_stats_ret*); extern bool_t xdr_remote_list_domains_args (XDR *, remote_list_domains_args*); extern bool_t xdr_remote_list_domains_ret (XDR *, remote_list_domains_ret*); extern bool_t xdr_remote_num_of_domains_ret (XDR *, remote_num_of_domains_ret*); @@ -856,6 +895,10 @@ extern bool_t xdr_remote_domain_get_scheduler_type_ret (); extern bool_t xdr_remote_domain_get_scheduler_parameters_args (); extern bool_t xdr_remote_domain_get_scheduler_parameters_ret (); extern bool_t xdr_remote_domain_set_scheduler_parameters_args (); +extern bool_t xdr_remote_domain_block_stats_args (); +extern bool_t xdr_remote_domain_block_stats_ret (); +extern bool_t xdr_remote_domain_interface_stats_args (); +extern bool_t xdr_remote_domain_interface_stats_ret (); extern bool_t xdr_remote_list_domains_args (); extern bool_t xdr_remote_list_domains_ret (); extern bool_t xdr_remote_num_of_domains_ret (); diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x index c9012ad8f3..3120d0be1c 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -242,6 +242,35 @@ struct remote_domain_set_scheduler_parameters_args { remote_sched_param params; }; +struct remote_domain_block_stats_args { + remote_nonnull_domain dom; + remote_nonnull_string path; +}; + +struct remote_domain_block_stats_ret { + hyper rd_req; + hyper rd_bytes; + hyper wr_req; + hyper wr_bytes; + hyper errs; +}; + +struct remote_domain_interface_stats_args { + remote_nonnull_domain dom; + remote_nonnull_string path; +}; + +struct remote_domain_interface_stats_ret { + hyper rx_bytes; + hyper rx_packets; + hyper rx_errs; + hyper rx_drop; + hyper tx_bytes; + hyper tx_packets; + hyper tx_errs; + hyper tx_drop; +}; + struct remote_list_domains_args { int maxids; }; @@ -652,7 +681,9 @@ enum remote_procedure { REMOTE_PROC_SUPPORTS_FEATURE = 60, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61, REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62, - REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63 + REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63, + REMOTE_PROC_DOMAIN_BLOCK_STATS = 64, + REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65 }; /* Custom RPC structure. */ diff --git a/src/driver.h b/src/driver.h index d73a940c7a..7d6a2d808f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -211,6 +211,17 @@ typedef int virSchedParameterPtr params, int nparams); +typedef int + (*virDrvDomainBlockStats) + (virDomainPtr domain, + const char *path, + struct _virDomainBlockStats *stats); +typedef int + (*virDrvDomainInterfaceStats) + (virDomainPtr domain, + const char *path, + struct _virDomainInterfaceStats *stats); + typedef int (*virDrvDomainMigratePrepare) (virConnectPtr dconn, @@ -309,6 +320,8 @@ struct _virDriver { virDrvDomainMigratePrepare domainMigratePrepare; virDrvDomainMigratePerform domainMigratePerform; virDrvDomainMigrateFinish domainMigrateFinish; + virDrvDomainBlockStats domainBlockStats; + virDrvDomainInterfaceStats domainInterfaceStats; }; typedef int diff --git a/src/libvirt.c b/src/libvirt.c index fa81ea868c..4ed40b914a 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -2063,6 +2063,113 @@ virDomainSetSchedulerParameters(virDomainPtr domain, } +/** + * virDomainBlockStats + * @dom: pointer to the domain object + * @path: path to the block device + * @stats: block device stats (returned) + * @size: size of stats structure + * + * This function returns block device (disk) stats for block + * devices attached to the domain. + * + * The path parameter is the name of the block device. Get this + * by calling virDomainGetXMLDesc and finding the + * attribute within //domain/devices/disk. (For example, "xvda"). + * + * Domains may have more than one block device. To get stats for + * each you should make multiple calls to this function. + * + * Individual fields within the stats structure may be returned + * as -1, which indicates that the hypervisor does not support + * that particular statistic. + * + * Returns: 0 in case of success or -1 in case of failure. + */ +int +virDomainBlockStats (virDomainPtr dom, const char *path, + virDomainBlockStatsPtr stats, size_t size) +{ + virConnectPtr conn; + struct _virDomainBlockStats stats2 = { -1, -1, -1, -1, -1 }; + DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size); + + if (!stats || size > sizeof stats2) { + virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__); + return -1; + } + if (!VIR_IS_CONNECTED_DOMAIN (dom)) { + virLibDomainError (dom, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return -1; + } + conn = dom->conn; + + if (conn->driver->domainBlockStats) { + if (conn->driver->domainBlockStats (dom, path, &stats2) == -1) + return -1; + + memcpy (stats, &stats2, size); + return 0; + } + + virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virDomainInterfaceStats + * @dom: pointer to the domain object + * @path: path to the interface + * @stats: network interface stats (returned) + * @size: size of stats structure + * + * This function returns network interface stats for interfaces + * attached to the domain. + * + * The path parameter is the name of the network interface. + * + * Domains may have more than network interface. To get stats for + * each you should make multiple calls to this function. + * + * Individual fields within the stats structure may be returned + * as -1, which indicates that the hypervisor does not support + * that particular statistic. + * + * Returns: 0 in case of success or -1 in case of failure. + */ +int +virDomainInterfaceStats (virDomainPtr dom, const char *path, + virDomainInterfaceStatsPtr stats, size_t size) +{ + virConnectPtr conn; + struct _virDomainInterfaceStats stats2 = { -1, -1, -1, -1, + -1, -1, -1, -1 }; + DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size); + + if (!stats || size > sizeof stats2) { + virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__); + return -1; + } + if (!VIR_IS_CONNECTED_DOMAIN (dom)) { + virLibDomainError (dom, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return -1; + } + conn = dom->conn; + + if (conn->driver->domainInterfaceStats) { + if (conn->driver->domainInterfaceStats (dom, path, &stats2) == -1) + return -1; + + memcpy (stats, &stats2, size); + return 0; + } + + virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + + /************************************************************************ * * diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index b218ec0837..d04a6cd545 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -65,7 +65,8 @@ virDomainGetSchedulerType; virDomainGetSchedulerParameters; virDomainSetSchedulerParameters; - + virDomainBlockStats; + virDomainInterfaceStats; virDomainAttachDevice; virDomainDetachDevice; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index e00d449df4..f912c86bc4 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2665,6 +2665,8 @@ static virDriver qemuDriver = { NULL, /* domainMigratePrepare */ NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ }; static virNetworkDriver qemuNetworkDriver = { diff --git a/src/remote_internal.c b/src/remote_internal.c index d952374a5a..7ac70b9ee1 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -2263,6 +2263,64 @@ remoteDomainSetSchedulerParameters (virDomainPtr domain, return 0; } +static int +remoteDomainBlockStats (virDomainPtr domain, const char *path, + struct _virDomainBlockStats *stats) +{ + remote_domain_block_stats_args args; + remote_domain_block_stats_ret ret; + GET_PRIVATE (domain->conn, -1); + + make_nonnull_domain (&args.dom, domain); + args.path = (char *) path; + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_BLOCK_STATS, + (xdrproc_t) xdr_remote_domain_block_stats_args, (char *) &args, + (xdrproc_t) xdr_remote_domain_block_stats_ret, (char *) &ret) + == -1) + return -1; + + stats->rd_req = ret.rd_req; + stats->rd_bytes = ret.rd_bytes; + stats->wr_req = ret.wr_req; + stats->wr_bytes = ret.wr_bytes; + stats->errs = ret.errs; + + return 0; +} + +static int +remoteDomainInterfaceStats (virDomainPtr domain, const char *path, + struct _virDomainInterfaceStats *stats) +{ + remote_domain_interface_stats_args args; + remote_domain_interface_stats_ret ret; + GET_PRIVATE (domain->conn, -1); + + make_nonnull_domain (&args.dom, domain); + args.path = (char *) path; + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_INTERFACE_STATS, + (xdrproc_t) xdr_remote_domain_interface_stats_args, + (char *) &args, + (xdrproc_t) xdr_remote_domain_interface_stats_ret, + (char *) &ret) == -1) + return -1; + + stats->rx_bytes = ret.rx_bytes; + stats->rx_packets = ret.rx_packets; + stats->rx_errs = ret.rx_errs; + stats->rx_drop = ret.rx_drop; + stats->tx_bytes = ret.tx_bytes; + stats->tx_packets = ret.tx_packets; + stats->tx_errs = ret.tx_errs; + stats->tx_drop = ret.tx_drop; + + return 0; +} + /*----------------------------------------------------------------------*/ static int @@ -3057,6 +3115,8 @@ static virDriver driver = { .domainMigratePrepare = remoteDomainMigratePrepare, .domainMigratePerform = remoteDomainMigratePerform, .domainMigrateFinish = remoteDomainMigrateFinish, + .domainBlockStats = remoteDomainBlockStats, + .domainInterfaceStats = remoteDomainInterfaceStats, }; static virNetworkDriver network_driver = { diff --git a/src/test.c b/src/test.c index 8252241069..59e1d4b958 100644 --- a/src/test.c +++ b/src/test.c @@ -1967,6 +1967,8 @@ static virDriver testDriver = { NULL, /* domainMigratePrepare */ NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/virsh.c b/src/virsh.c index dc68a719ff..ec9146aa61 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -659,6 +660,129 @@ cmdDomstate(vshControl * ctl, vshCmd * cmd) return ret; } +/* "domblkstat" command + */ +static vshCmdInfo info_domblkstat[] = { + {"syntax", "domblkstat "}, + {"help", gettext_noop("get device block stats for a domain")}, + {"desc", gettext_noop("Get device block stats for a running domain.")}, + {NULL,NULL} +}; + +static vshCmdOptDef opts_domblkstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("block device")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdDomblkstat (vshControl *ctl, vshCmd *cmd) +{ + virDomainPtr dom; + char *name, *device; + struct _virDomainBlockStats stats; + + if (!vshConnectionUsability (ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain (ctl, cmd, "domain", &name))) + return FALSE; + + if (!(device = vshCommandOptString (cmd, "device", NULL))) + return FALSE; + + if (virDomainBlockStats (dom, device, &stats, sizeof stats) == -1) { + vshError (ctl, FALSE, _("Failed to get block stats %s %s"), + name, device); + virDomainFree(dom); + return FALSE; + } + + if (stats.rd_req >= 0) + vshPrint (ctl, "%s rd_req %lld\n", device, stats.rd_req); + + if (stats.rd_bytes >= 0) + vshPrint (ctl, "%s rd_bytes %lld\n", device, stats.rd_bytes); + + if (stats.wr_req >= 0) + vshPrint (ctl, "%s wr_req %lld\n", device, stats.wr_req); + + if (stats.wr_bytes >= 0) + vshPrint (ctl, "%s wr_bytes %lld\n", device, stats.wr_bytes); + + if (stats.errs >= 0) + vshPrint (ctl, "%s errs %lld\n", device, stats.errs); + + virDomainFree(dom); + return TRUE; +} + +/* "domifstat" command + */ +static vshCmdInfo info_domifstat[] = { + {"syntax", "domifstat "}, + {"help", gettext_noop("get network interface stats for a domain")}, + {"desc", gettext_noop("Get network interface stats for a running domain.")}, + {NULL,NULL} +}; + +static vshCmdOptDef opts_domifstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface device")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdDomIfstat (vshControl *ctl, vshCmd *cmd) +{ + virDomainPtr dom; + char *name, *device; + struct _virDomainInterfaceStats stats; + + if (!vshConnectionUsability (ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain (ctl, cmd, "domain", &name))) + return FALSE; + + if (!(device = vshCommandOptString (cmd, "interface", NULL))) + return FALSE; + + if (virDomainInterfaceStats (dom, device, &stats, sizeof stats) == -1) { + vshError (ctl, FALSE, _("Failed to get interface stats %s %s"), + name, device); + virDomainFree(dom); + return FALSE; + } + + if (stats.rx_bytes >= 0) + vshPrint (ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes); + + if (stats.rx_packets >= 0) + vshPrint (ctl, "%s rx_packets %lld\n", device, stats.rx_packets); + + if (stats.rx_errs >= 0) + vshPrint (ctl, "%s rx_errs %lld\n", device, stats.rx_errs); + + if (stats.rx_drop >= 0) + vshPrint (ctl, "%s rx_drop %lld\n", device, stats.rx_drop); + + if (stats.tx_bytes >= 0) + vshPrint (ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes); + + if (stats.tx_packets >= 0) + vshPrint (ctl, "%s tx_packets %lld\n", device, stats.tx_packets); + + if (stats.tx_errs >= 0) + vshPrint (ctl, "%s tx_errs %lld\n", device, stats.tx_errs); + + if (stats.tx_drop >= 0) + vshPrint (ctl, "%s tx_drop %lld\n", device, stats.tx_drop); + + virDomainFree(dom); + return TRUE; +} + /* * "suspend" command */ @@ -3529,6 +3653,8 @@ static vshCmdDef commands[] = { {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, {"domname", cmdDomname, opts_domname, info_domname}, {"domstate", cmdDomstate, opts_domstate, info_domstate}, + {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, + {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat}, {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml}, {"hostname", cmdHostname, NULL, info_hostname}, {"list", cmdList, opts_list, info_list}, diff --git a/src/xen_internal.c b/src/xen_internal.c index de7021b55d..ebba04de25 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -1306,6 +1306,152 @@ xenHypervisorSetSchedulerParameters(virDomainPtr domain, return 0; } +static int64_t +read_stat (const char *path) +{ + char str[64]; + int64_t r; + int i; + FILE *fp; + + fp = fopen (path, "r"); + if (!fp) return -1; + /* stupid GCC warning */ i = fread (str, sizeof str, 1, fp); + r = strtoll (str, NULL, 10); + fclose (fp); + return r; +} + +static int64_t +read_bd_stat (int device, int domid, const char *str) +{ + char path[PATH_MAX]; + int64_t r; + + snprintf (path, sizeof path, + "/sys/devices/xen-backend/vbd-%d-%d/statistics/%s_req", + domid, device, str); + r = read_stat (path); + if (r >= 0) return r; + + snprintf (path, sizeof path, + "/sys/devices/xen-backend/tap-%d-%d/statistics/%s_req", + domid, device, str); + r = read_stat (path); + return r; +} + +/* Paths have the form "xvd[a-]" and map to paths /sys/devices/xen-backend/ + * (vbd|tap)-domid-major:minor/statistics/(rd|wr|oo)_req. The major:minor + * is in this case fixed as 202*256 + 16*minor where minor is 0 for xvda, + * 1 for xvdb and so on. + */ +int +xenHypervisorDomainBlockStats (virDomainPtr dom, + const char *path, + struct _virDomainBlockStats *stats) +{ + int minor, device; + + if (strlen (path) != 4 || + STRNEQLEN (path, "xvd", 3) || + (minor = path[3] - 'a') < 0 || + minor > 26) { + virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__, + "invalid path, should be xvda, xvdb, etc.", 0); + return -1; + } + device = 202 * 256 + minor; + + stats->rd_req = read_bd_stat (device, dom->id, "rd"); + stats->wr_req = read_bd_stat (device, dom->id, "wr"); + stats->errs = read_bd_stat (device, dom->id, "oo"); + + if (stats->rd_req == -1 && stats->wr_req == -1 && stats->errs == -1) { + virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__, + "Failed to read any block statistics", dom->id); + return -1; + } + + return 0; +} + +/* Paths have the form vif. (this interface checks that + * is the real domain ID and returns an error if not). + * + * In future we may allow you to query bridge stats (virbrX or + * xenbrX), but that will probably be through a separate + * virNetwork interface, as yet not decided. + * + * On Linux we open /proc/net/dev and look for the device + * called vif.. + */ +int +xenHypervisorDomainInterfaceStats (virDomainPtr dom, + const char *path, + struct _virDomainInterfaceStats *stats) +{ + int rqdomid, device; + FILE *fp; + char line[256]; + + if (sscanf (path, "vif%d.%d", &rqdomid, &device) != 2) { + virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__, + "invalid path, should be vif..", 0); + return -1; + } + if (rqdomid != dom->id) { + virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__, + "invalid path, vif should match this domain ID", 0); + return -1; + } + + fp = fopen ("/proc/net/dev", "r"); + if (!fp) { + virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__, + "/proc/net/dev", errno); + return -1; + } + while (fgets (line, sizeof line, fp)) { + int domid, port; + long long dummy; + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_drop; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_drop; + + if (sscanf (line, "vif%d.%d: %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld", + &domid, &port, + &rx_bytes, &rx_packets, &rx_errs, &rx_drop, + &dummy, &dummy, &dummy, &dummy, + &tx_bytes, &tx_packets, &tx_errs, &tx_drop, + &dummy, &dummy, &dummy, &dummy) != 18) + continue; + + if (domid == dom->id && port == device) { + stats->rx_bytes = rx_bytes; + stats->rx_packets = rx_packets; + stats->rx_errs = rx_errs; + stats->rx_drop = rx_drop; + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + stats->tx_errs = tx_errs; + stats->tx_drop = tx_drop; + fclose (fp); + return 0; + } + } + fclose (fp); + + virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__, + "/proc/net/dev: Interface not found", 0); + return -1; +} + /** * virXen_pausedomain: * @handle: the hypervisor handle diff --git a/src/xen_internal.h b/src/xen_internal.h index 6d5c1cbce4..be4d79e834 100644 --- a/src/xen_internal.h +++ b/src/xen_internal.h @@ -86,6 +86,13 @@ int xenHypervisorSetSchedulerParameters (virDomainPtr domain, virSchedParameterPtr params, int nparams); +int xenHypervisorDomainBlockStats (virDomainPtr domain, + const char *path, + struct _virDomainBlockStats *stats); +int xenHypervisorDomainInterfaceStats (virDomainPtr domain, + const char *path, + struct _virDomainInterfaceStats *stats); + #ifdef __cplusplus } #endif diff --git a/src/xen_unified.c b/src/xen_unified.c index fafc24ca58..dcf8927872 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -1023,6 +1023,32 @@ xenUnifiedDomainSetSchedulerParameters (virDomainPtr dom, return(-1); } +static int +xenUnifiedDomainBlockStats (virDomainPtr dom, const char *path, + struct _virDomainBlockStats *stats) +{ + GET_PRIVATE (dom->conn); + + if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) + return xenHypervisorDomainBlockStats (dom, path, stats); + + xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +static int +xenUnifiedDomainInterfaceStats (virDomainPtr dom, const char *path, + struct _virDomainInterfaceStats *stats) +{ + GET_PRIVATE (dom->conn); + + if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) + return xenHypervisorDomainInterfaceStats (dom, path, stats); + + xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + /*----- Register with libvirt.c, and initialise Xen drivers. -----*/ #define VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 + \ @@ -1081,6 +1107,8 @@ static virDriver xenUnifiedDriver = { .domainMigratePrepare = xenUnifiedDomainMigratePrepare, .domainMigratePerform = xenUnifiedDomainMigratePerform, .domainMigrateFinish = xenUnifiedDomainMigrateFinish, + .domainBlockStats = xenUnifiedDomainBlockStats, + .domainInterfaceStats = xenUnifiedDomainInterfaceStats, }; /**