Show a patch.

GET /api/patches/439/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 439,
    "url": "https://patches.dpdk.org/api/patches/439/?format=api",
    "web_url": "https://patches.dpdk.org/patch/439/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk"
    },
    "msgid": "<1411410879-28872-2-git-send-email-alan.carew@intel.com>",
    "date": "2014-09-22T18:34:30",
    "name": "[dpdk-dev,01/10] Channel Manager and Monitor for VM Power Management(Host).",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "23ccef72c0ff339ed11648cbcf45f844d2554039",
    "submitter": {
        "id": 72,
        "url": "https://patches.dpdk.org/api/people/72/?format=api",
        "name": "Alan Carew",
        "email": "alan.carew@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/patch/439/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/439/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/439/checks/",
    "tags": {},
    "headers": {
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Message-Id": "<1411410879-28872-2-git-send-email-alan.carew@intel.com>",
        "X-Mailer": "git-send-email 1.9.3",
        "To": "dev@dpdk.org",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 3A6D42E8B;\n\tMon, 22 Sep 2014 20:29:38 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 33D03333\n\tfor <dev@dpdk.org>; Mon, 22 Sep 2014 20:29:35 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga101.jf.intel.com with ESMTP; 22 Sep 2014 11:35:16 -0700",
            "from sie-lab-212-143.ir.intel.com (HELO\n\tsilpixa00385294.ir.intel.com) ([10.237.212.143])\n\tby orsmga002.jf.intel.com with ESMTP; 22 Sep 2014 11:35:11 -0700"
        ],
        "X-BeenThere": "dev@dpdk.org",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Subject": "[dpdk-dev] [PATCH 01/10] Channel Manager and Monitor for VM Power\n\tManagement(Host).",
        "In-Reply-To": "<1411410879-28872-1-git-send-email-alan.carew@intel.com>",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "Date": "Mon, 22 Sep 2014 19:34:30 +0100",
        "X-ExtLoop1": "1",
        "Precedence": "list",
        "From": "Alan Carew <alan.carew@intel.com>",
        "X-IronPort-AV": "E=Sophos;i=\"5.04,573,1406617200\"; d=\"scan'208\";a=\"606714317\"",
        "References": "<1411410879-28872-1-git-send-email-alan.carew@intel.com>",
        "X-Original-To": "patchwork@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "Errors-To": "dev-bounces@dpdk.org",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "Delivered-To": "patchwork@dpdk.org",
        "X-Mailman-Version": "2.1.15"
    },
    "content": "The manager is responsible for adding communications channels to the Monitor\nthread, tracking and reporting VM state and employs the libvirt API for\nsynchronization with the KVM Hypervisor. The manager interacts with the\nHypervisor to discover the mapping of virtual CPUS(vCPUs) to the host\nphysical CPUS(pCPUs) and to inspect the VM running state.\n\nThe manager provides the following functionality to the CLI:\n1) Connect to a libvirtd instance, default: qemu:///system\n2) Add a VM to an internal list, each VM is identified by a \"name\" which must\n   correspond a valid libvirt Domain Name.\n3) Add communication channels associated with a VM to the epoll based Monitor\n   thread.\n   The channels must exist and be in the form of:\n   /tmp/powermonitor/<vm_name>.<channel_number>. Each channel is a\n   Virtio-Serial endpoint configured as an AF_UNIX file socket and opened in\n   non-blocking mode.\n   Each VM can have a maximum of 64 channels associated with it.\n4) Disable or re-enable VM communication channels, channels once added to the\n   Monitor thread remain in that threads control, however acting on channel\n   requests can be disabled and renabled via CLI.\n\nThe monitor is an epoll based infinite loop running in a separate thread that\nwaits on channel events from VMs and calls the corresponding functions. Channel\ndefinitions from the manager are registered via the epoll event opaque pointer\nwhen calling epoll_ctl(EPOLL_CTL_ADD), this allows for obtaining the channels\nfile descriptor for reading EPOLLIN events and mapping the vCPU to pCPU(s)\nassociated with a request from a particular VM.\n\nSigned-off-by: Alan Carew <alan.carew@intel.com>\n---\n examples/vm_power_manager/channel_manager.c | 643 ++++++++++++++++++++++++++++\n examples/vm_power_manager/channel_manager.h | 273 ++++++++++++\n examples/vm_power_manager/channel_monitor.c | 228 ++++++++++\n examples/vm_power_manager/channel_monitor.h | 102 +++++\n 4 files changed, 1246 insertions(+)\n create mode 100644 examples/vm_power_manager/channel_manager.c\n create mode 100644 examples/vm_power_manager/channel_manager.h\n create mode 100644 examples/vm_power_manager/channel_monitor.c\n create mode 100644 examples/vm_power_manager/channel_monitor.h",
    "diff": "diff --git a/examples/vm_power_manager/channel_manager.c b/examples/vm_power_manager/channel_manager.c\nnew file mode 100644\nindex 0000000..7ec798f\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_manager.c\n@@ -0,0 +1,643 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <sys/un.h>\n+#include <fcntl.h>\n+#include <unistd.h>\n+#include <inttypes.h>\n+#include <dirent.h>\n+#include <errno.h>\n+\n+#include <sys/queue.h>\n+#include <sys/types.h>\n+#include <sys/socket.h>\n+#include <sys/select.h>\n+\n+#include <rte_config.h>\n+#include <rte_malloc.h>\n+#include <rte_memory.h>\n+#include <rte_log.h>\n+#include <rte_atomic.h>\n+#include <rte_spinlock.h>\n+\n+#include <libvirt/libvirt.h>\n+\n+#include \"channel_manager.h\"\n+#include \"channel_commands.h\"\n+#include \"channel_monitor.h\"\n+\n+\n+#define SOCKET_PATH \"/tmp/powermonitor/\"\n+\n+#define RTE_LOGTYPE_CHANNEL_MANAGER RTE_LOGTYPE_USER1\n+\n+#define ITERATIVE_BITMASK_CHECK_64(mask_u64b, i) \\\n+\t\tfor (i = 0; mask_u64b; mask_u64b &= ~(1ULL << i++)) \\\n+\t\t\tif ((mask_u64b >> i) & 1) \\\n+\n+/* Global pointer to libvirt connection */\n+static virConnectPtr global_vir_conn_ptr;\n+\n+/*\n+ * Represents a single Virtual Machine\n+ */\n+struct virtual_machine_info {\n+\tchar name[MAX_NAME_LEN];\n+\tuint64_t pcpu_mask[MAX_VCPU];\n+\tstruct channel_info *channels[MAX_VM_CHANNELS];\n+\tuint64_t channel_mask;\n+\tuint8_t num_channels;\n+\tenum vm_status status;\n+\tvirDomainPtr domainPtr;\n+\tvirDomainInfo info;\n+\trte_spinlock_t config_spinlock;\n+\tLIST_ENTRY(virtual_machine_info) vms_info;\n+};\n+\n+LIST_HEAD(, virtual_machine_info) vm_list_head;\n+\n+static struct virtual_machine_info *\n+find_domain_by_name(const char *name)\n+{\n+\tstruct virtual_machine_info *info;\n+\tLIST_FOREACH(info, &vm_list_head, vms_info) {\n+\t\tif (!strncmp(info->name, name, MAX_NAME_LEN-1))\n+\t\t\treturn info;\n+\t}\n+\treturn NULL;\n+}\n+\n+static void\n+disconnect_hypervisor(void)\n+{\n+\tif (global_vir_conn_ptr != NULL) {\n+\t\tvirConnectClose(global_vir_conn_ptr);\n+\t\tglobal_vir_conn_ptr = NULL;\n+\t}\n+}\n+\n+static int\n+connect_hypervisor(const char *path)\n+{\n+\tif (global_vir_conn_ptr != NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error connecting to %s, connection\"\n+\t\t\t\t\"already established\\n\", path);\n+\t\treturn -1;\n+\t}\n+\tglobal_vir_conn_ptr = virConnectOpen(path);\n+\tif (global_vir_conn_ptr == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error failed to open connection to \"\n+\t\t\t\t\"Hypervisor '%s'\\n\", path);\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+update_pcpus_mask(struct virtual_machine_info *vm_info)\n+{\n+\tsize_t maplen = VIR_CPU_MAPLEN(RTE_MAX_LCORE);\n+\tunsigned char cpumap[RTE_MAX_LCORE*maplen];\n+\tunsigned int i, j;\n+\n+\tif (virDomainGetVcpuPinInfo(vm_info->domainPtr,\n+\t\t\tvm_info->info.nrVirtCpu,\n+\t\t\tcpumap,\n+\t\t\tmaplen,\n+\t\t\tVIR_DOMAIN_DEVICE_MODIFY_CURRENT) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error getting Vcpu Pin Info\\n\");\n+\t\treturn -1;\n+\t}\n+\tfor (i = 0; i < vm_info->info.nrVirtCpu; i++) {\n+\t\tvm_info->pcpu_mask[i] = 0;\n+\t\tfor (j = 0; j < maplen; j++)\n+\t\t\tvm_info->pcpu_mask[i] += VIR_CPU_USABLE(cpumap, maplen, i, j);\n+\t}\n+\treturn 0;\n+}\n+\n+uint64_t\n+get_pcpus_mask(struct channel_info *chan_info, unsigned vcpu)\n+{\n+\tstruct virtual_machine_info *vm_info =\n+\t\t\t(struct virtual_machine_info *)chan_info->priv_info;\n+\treturn vm_info->pcpu_mask[vcpu];\n+}\n+\n+static inline int\n+channel_exists(struct virtual_machine_info *vm_info, unsigned int channel_num)\n+{\n+\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\tif (vm_info->channel_mask & (1ULL << channel_num)) {\n+\t\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\t\treturn 1;\n+\t}\n+\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\treturn 0;\n+}\n+\n+int\n+add_vm(const char *vm_name)\n+{\n+\tstruct virtual_machine_info *new_domain;\n+\tvirDomainPtr dom_ptr;\n+\n+\tif (find_domain_by_name(vm_name) != NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to add VM: VM '%s' \"\n+\t\t\t\t\t\t\"already exists\\n\", vm_name);\n+\t\treturn -1;\n+\t}\n+\n+\tif (global_vir_conn_ptr == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"No connection to hypervisor exists\\n\");\n+\t\treturn -1;\n+\t}\n+\tdom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name);\n+\tif (dom_ptr == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error on VM lookup with libvirt: \"\n+\t\t\t\t\"VM '%s' not found\\n\", vm_name);\n+\t\treturn -1;\n+\t}\n+\n+\tnew_domain = rte_malloc(\"virtual_machine_info\", sizeof(*new_domain),\n+\t\t\tCACHE_LINE_SIZE);\n+\tif (new_domain == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to allocate memory for VM \"\n+\t\t\t\t\"info\\n\");\n+\t\treturn -1;\n+\t}\n+\tnew_domain->domainPtr = dom_ptr;\n+\tif (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to get libvirt VM info\\n\");\n+\t\trte_free(new_domain);\n+\t\treturn -1;\n+\t}\n+\tif (new_domain->info.nrVirtCpu > MAX_VCPU) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error the number of virtual CPUs(%u) is \"\n+\t\t\t\t\"greater than allowable(%d)\\n\", new_domain->info.nrVirtCpu,\n+\t\t\t\tMAX_VCPU);\n+\t\trte_free(new_domain);\n+\t\treturn -1;\n+\t}\n+\tif (update_pcpus_mask(new_domain) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error getting physical CPU pinning\\n\");\n+\t\trte_free(new_domain);\n+\t\treturn -1;\n+\t}\n+\tstrncpy(new_domain->name, vm_name, sizeof(new_domain->name));\n+\tnew_domain->channel_mask = 0;\n+\tnew_domain->num_channels = 0;\n+\n+\tif (!virDomainIsActive(dom_ptr))\n+\t\tnew_domain->status = VM_INACTIVE;\n+\telse\n+\t\tnew_domain->status = VM_ACTIVE;\n+\n+\trte_spinlock_init(&(new_domain->config_spinlock));\n+\tLIST_INSERT_HEAD(&vm_list_head, new_domain, vms_info);\n+\treturn 0;\n+}\n+\n+static int\n+open_non_blocking_channel(struct channel_info *info)\n+{\n+\tint ret, flags;\n+\tstruct sockaddr_un sock_addr;\n+\tfd_set soc_fd_set;\n+\tstruct timeval tv;\n+\n+\tinfo->fd = socket(AF_UNIX, SOCK_STREAM, 0);\n+\tif (info->fd == -1) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error(%s) creating socket for '%s'\\n\",\n+\t\t\t\tstrerror(errno),\n+\t\t\t\tinfo->channel_path);\n+\t\treturn -1;\n+\t}\n+\tsock_addr.sun_family = AF_UNIX;\n+\tmemcpy(&sock_addr.sun_path, info->channel_path,\n+\t\t\tstrlen(info->channel_path)+1);\n+\n+\t/* Get current flags */\n+\tflags = fcntl(info->fd, F_GETFL, 0);\n+\tif (flags < 0) {\n+\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"Error(%s) fcntl get flags socket for\"\n+\t\t\t\t\"'%s'\\n\", strerror(errno), info->channel_path);\n+\t\treturn 1;\n+\t}\n+\t/* Set to Non Blocking */\n+\tflags |= O_NONBLOCK;\n+\tif (fcntl(info->fd, F_SETFL, flags) < 0) {\n+\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"Error(%s) setting non-blocking \"\n+\t\t\t\t\"socket for '%s'\\n\", strerror(errno), info->channel_path);\n+\t\treturn -1;\n+\t}\n+\tret = connect(info->fd, (struct sockaddr *)&sock_addr,\n+\t\t\tsizeof(sock_addr));\n+\tif (ret < 0) {\n+\t\t/* ECONNREFUSED error is given when VM is not active */\n+\t\tif (errno == ECONNREFUSED) {\n+\t\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"VM is not active or has not \"\n+\t\t\t\t\t\"activated its endpoint to channel %s\\n\",\n+\t\t\t\t\tinfo->channel_path);\n+\t\t\treturn -1;\n+\t\t}\n+\t\t/* Wait for tv_sec if in progress */\n+\t\telse if (errno == EINPROGRESS) {\n+\t\t\ttv.tv_sec = 2;\n+\t\t\ttv.tv_usec = 0;\n+\t\t\tFD_ZERO(&soc_fd_set);\n+\t\t\tFD_SET(info->fd, &soc_fd_set);\n+\t\t\tif (select(info->fd+1, NULL, &soc_fd_set, NULL, &tv) > 0) {\n+\t\t\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"Timeout or error on channel \"\n+\t\t\t\t\t\t\"'%s'\\n\", info->channel_path);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t} else {\n+\t\t\t/* Any other error */\n+\t\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"Error(%s) connecting socket\"\n+\t\t\t\t\t\" for '%s'\\n\", strerror(errno), info->channel_path);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+setup_channel_info(struct virtual_machine_info **vm_info_dptr,\n+\t\tstruct channel_info **chan_info_dptr, unsigned channel_num)\n+{\n+\tstruct channel_info *chan_info = *chan_info_dptr;\n+\tstruct virtual_machine_info *vm_info = *vm_info_dptr;\n+\n+\tchan_info->channel_num = channel_num;\n+\tchan_info->priv_info = (void *)vm_info;\n+\tchan_info->status = CHANNEL_DISCONNECTED;\n+\tif (open_non_blocking_channel(chan_info) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Could not open channel: \"\n+\t\t\t\t\"'%s' for VM '%s'\\n\",\n+\t\t\t\tchan_info->channel_path, vm_info->name);\n+\t\treturn -1;\n+\t}\n+\tif (add_channel_to_monitor(&chan_info) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Could add channel: \"\n+\t\t\t\t\"'%s' to epoll ctl for VM '%s'\\n\",\n+\t\t\t\tchan_info->channel_path, vm_info->name);\n+\t\treturn -1;\n+\n+\t}\n+\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\tvm_info->num_channels++;\n+\tvm_info->channel_mask |= 1ULL << channel_num;\n+\tvm_info->channels[channel_num] = chan_info;\n+\tchan_info->status = CHANNEL_CONNECTED;\n+\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\treturn 0;\n+}\n+\n+int\n+add_all_channels(const char *vm_name)\n+{\n+\tDIR *d;\n+\tstruct dirent *dir;\n+\tstruct virtual_machine_info *vm_info;\n+\tstruct channel_info *chan_info;\n+\tchar *token, *remaining, *tail_ptr;\n+\tchar socket_name[PATH_MAX];\n+\tunsigned channel_num;\n+\tint num_channels_enabled = 0;\n+\n+\t/* verify VM exists */\n+\tvm_info = find_domain_by_name(vm_name);\n+\tif (vm_info == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"VM: '%s' not found\"\n+\t\t\t\t\" during channel discovery\\n\", vm_name);\n+\t\treturn 0;\n+\t}\n+\tif (!virDomainIsActive(vm_info->domainPtr)) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"VM: '%s' is not active\\n\", vm_name);\n+\t\tvm_info->status = VM_INACTIVE;\n+\t\treturn 0;\n+\t}\n+\td = opendir(SOCKET_PATH);\n+\tif (d == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error opening directory '%s': %s\\n\",\n+\t\t\t\tSOCKET_PATH, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\twhile ((dir = readdir(d)) != NULL) {\n+\t\tif (!strncmp(dir->d_name, \".\", 1) ||\n+\t\t\t\t!strncmp(dir->d_name, \"..\", 2))\n+\t\t\tcontinue;\n+\n+\t\tsnprintf(socket_name, sizeof(socket_name), \"%s\", dir->d_name);\n+\t\tremaining = socket_name;\n+\t\t/* Extract vm_name from \"<vm_name>.<channel_num>\" */\n+\t\ttoken = strsep(&remaining, \".\");\n+\t\tif (remaining == NULL)\n+\t\t\tcontinue;\n+\t\tif (strncmp(vm_name, token, MAX_NAME_LEN))\n+\t\t\tcontinue;\n+\n+\t\t/* remaining should contain only <channel_num> */\n+\t\terrno = 0;\n+\t\tchannel_num = (unsigned int)strtol(remaining, &tail_ptr, 0);\n+\t\tif ((errno != 0) || (remaining[0] == '\\0') ||\n+\t\t\t\t(*tail_ptr != '\\0') || tail_ptr == NULL) {\n+\t\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"Malformed channel name\"\n+\t\t\t\t\t\"'%s' found it should be in the form of \"\n+\t\t\t\t\t\"'<guest_name>.<channel_num>(decimal)'\\n\",\n+\t\t\t\t\tdir->d_name);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (channel_num >= MAX_VM_CHANNELS) {\n+\t\t\tRTE_LOG(WARNING, CHANNEL_MANAGER, \"Channel number(%u) is \"\n+\t\t\t\t\t\"greater than max allowable: %d, skipping '%s%s'\\n\",\n+\t\t\t\t\tchannel_num, MAX_VM_CHANNELS-1, SOCKET_PATH,\n+\t\t\t\t\tdir->d_name);\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* if channel has not been added previously */\n+\t\tif (channel_exists(vm_info, channel_num))\n+\t\t\tcontinue;\n+\n+\t\tchan_info = rte_malloc(NULL, sizeof(*chan_info),\n+\t\t\t\tCACHE_LINE_SIZE);\n+\t\tif (chan_info == NULL) {\n+\t\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error allocating memory for \"\n+\t\t\t\t\t\"channel '%s%s'\\n\", SOCKET_PATH, dir->d_name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tsnprintf(chan_info->channel_path,\n+\t\t\t\tsizeof(chan_info->channel_path), \"%s%s\", SOCKET_PATH,\n+\t\t\t\tdir->d_name);\n+\n+\t\tif (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) {\n+\t\t\trte_free(chan_info);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tnum_channels_enabled++;\n+\t}\n+\tclosedir(d);\n+\treturn num_channels_enabled;\n+}\n+\n+int\n+add_channels(const char *vm_name, unsigned *channel_list,\n+\t\tunsigned len_channel_list)\n+{\n+\tstruct virtual_machine_info *vm_info;\n+\tstruct channel_info *chan_info;\n+\tchar socket_path[PATH_MAX];\n+\tunsigned i;\n+\tint num_channels_enabled = 0;\n+\n+\tvm_info = find_domain_by_name(vm_name);\n+\tif (vm_info == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to add channels: VM '%s' \"\n+\t\t\t\t\"not found\\n\", vm_name);\n+\t\treturn 0;\n+\t}\n+\tif (!virDomainIsActive(vm_info->domainPtr)) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"VM: '%s' is not active\\n\", vm_name);\n+\t\tvm_info->status = VM_INACTIVE;\n+\t\treturn 0;\n+\t}\n+\tfor (i = 0; i < len_channel_list; i++) {\n+\t\tif (i == MAX_VM_CHANNELS)\n+\t\t\tcontinue;\n+\t\tif (channel_exists(vm_info, channel_list[i])) {\n+\t\t\tRTE_LOG(INFO, CHANNEL_MANAGER,  \"Channel already exists, skipping  \"\n+\t\t\t\t\t\"'%s.%u'\\n\", vm_name, i);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tsnprintf(socket_path, sizeof(socket_path), \"%s%s.%u\", SOCKET_PATH,\n+\t\t\t\tvm_name, channel_list[i]);\n+\t\terrno = 0;\n+\t\tif (access(socket_path, F_OK) < 0) {\n+\t\t\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Channel path '%s' error: \"\n+\t\t\t\t\t\t\"%s\\n\", socket_path, strerror(errno));\n+\t\t\tcontinue;\n+\t\t}\n+\t\tchan_info = rte_malloc(NULL, sizeof(*chan_info),\n+\t\t\t\tCACHE_LINE_SIZE);\n+\t\tif (chan_info == NULL) {\n+\t\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error allocating memory for \"\n+\t\t\t\t\t\"channel '%s'\\n\", socket_path);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tsnprintf(chan_info->channel_path,\n+\t\t\t\t\t\t\tsizeof(chan_info->channel_path), \"%s%s.%u\",\n+\t\t\t\t\t\t\tSOCKET_PATH, vm_name, channel_list[i]);\n+\t\tif (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) {\n+\t\t\trte_free(chan_info);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tnum_channels_enabled++;\n+\n+\t}\n+\treturn num_channels_enabled;\n+}\n+\n+int\n+remove_channel(struct channel_info *chan_info)\n+{\n+\tstruct virtual_machine_info *vm_info;\n+\tclose(chan_info->fd);\n+\tvm_info = (struct virtual_machine_info *)chan_info->priv_info;\n+\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\tvm_info->channel_mask &= ~(1ULL << chan_info->channel_num);\n+\tvm_info->num_channels--;\n+\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\trte_free(chan_info);\n+\treturn 0;\n+}\n+\n+int\n+remove_vm(const char *vm_name)\n+{\n+\tstruct virtual_machine_info *vm_info = find_domain_by_name(vm_name);\n+\tif (vm_info == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to remove VM: VM '%s' \"\n+\t\t\t\t\t\t\"not found\\n\", vm_name);\n+\t\treturn -1;\n+\t}\n+\trte_spinlock_lock(&vm_info->config_spinlock);\n+\tif (vm_info->num_channels != 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to remove VM '%s', there are \"\n+\t\t\t\t\"%\"PRId8\" channels still active\\n\",\n+\t\t\t\tvm_name, vm_info->num_channels);\n+\t\trte_spinlock_unlock(&vm_info->config_spinlock);\n+\t\treturn -1;\n+\t}\n+\tLIST_REMOVE(vm_info, vms_info);\n+\trte_spinlock_unlock(&vm_info->config_spinlock);\n+\trte_free(vm_info);\n+\treturn 0;\n+}\n+\n+int\n+set_channel_status_all(const char *vm_name, enum channel_status status)\n+{\n+\tstruct virtual_machine_info *vm_info;\n+\tunsigned int i;\n+\tuint64_t mask;\n+\tint num_channels_changed = 0;\n+\n+\tif (!(status == CHANNEL_CONNECTED || status == CHANNEL_DISABLED)) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Channels can only be enabled or \"\n+\t\t\t\t\"disabled: Unable to change status for VM '%s'\\n\", vm_name);\n+\t}\n+\tvm_info = find_domain_by_name(vm_name);\n+\tif (vm_info == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to disable channels: VM '%s' \"\n+\t\t\t\t\"not found\\n\", vm_name);\n+\t\treturn 0;\n+\t}\n+\n+\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\tmask = vm_info->channel_mask;\n+\tITERATIVE_BITMASK_CHECK_64(mask, i) {\n+\t\t\tvm_info->channels[i]->status = status;\n+\t\t\tnum_channels_changed++;\n+\t}\n+\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\treturn num_channels_changed;\n+\n+}\n+\n+int\n+set_channel_status(const char *vm_name, unsigned *channel_list,\n+\t\tunsigned len_channel_list, enum channel_status status)\n+{\n+\tstruct virtual_machine_info *vm_info;\n+\tunsigned i;\n+\tint num_channels_changed = 0;\n+\n+\tif (!(status == CHANNEL_CONNECTED || status == CHANNEL_DISABLED)) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Channels can only be enabled or \"\n+\t\t\t\t\"disabled: Unable to change status for VM '%s'\\n\", vm_name);\n+\t}\n+\tvm_info = find_domain_by_name(vm_name);\n+\tif (vm_info == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to add channels: VM '%s' \"\n+\t\t\t\t\"not found\\n\", vm_name);\n+\t\treturn 0;\n+\t}\n+\tfor (i = 0; i < len_channel_list; i++) {\n+\t\tif (channel_exists(vm_info, channel_list[i])) {\n+\t\t\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\t\t\tvm_info->channels[channel_list[i]]->status = status;\n+\t\t\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\t\t\tnum_channels_changed++;\n+\t\t}\n+\t}\n+\treturn num_channels_changed;\n+}\n+\n+int\n+get_info_vm(const char *vm_name, struct vm_info *info)\n+{\n+\tstruct virtual_machine_info *vm_info;\n+\tunsigned i, channel_num = 0;\n+\tuint64_t mask;\n+\tvm_info = find_domain_by_name(vm_name);\n+\tif (vm_info == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"VM '%s' not found\\n\", vm_name);\n+\t\treturn -1;\n+\t}\n+\tinfo->status = VM_ACTIVE;\n+\tif (!virDomainIsActive(vm_info->domainPtr))\n+\t\tinfo->status = VM_INACTIVE;\n+\n+\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\tmask = vm_info->channel_mask;\n+\tITERATIVE_BITMASK_CHECK_64(mask, i) {\n+\t\t\tinfo->channels[channel_num].channel_num = i;\n+\t\t\tmemcpy(info->channels[channel_num].channel_path,\n+\t\t\t\t\tvm_info->channels[i]->channel_path, PATH_MAX);\n+\t\t\tinfo->channels[channel_num].status = vm_info->channels[i]->status;\n+\t\t\tinfo->channels[channel_num].fd = vm_info->channels[i]->fd;\n+\t\t\tchannel_num++;\n+\t}\n+\tinfo->num_channels = channel_num;\n+\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\tinfo->num_vcpus = vm_info->info.nrVirtCpu;\n+\n+\tmemcpy(info->name, vm_info->name, sizeof(vm_info->name));\n+\n+\tif (update_pcpus_mask(vm_info) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"VM '%s' unable to update vCPU Pinning\\n\",\n+\t\t\t\tvm_name);\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+channel_manager_init(const char *path)\n+{\n+\tLIST_INIT(&vm_list_head);\n+\tif (connect_hypervisor(path) < 0)\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to initialize channel manager\\n\");\n+\treturn 0;\n+}\n+\n+void\n+channel_manager_exit(void)\n+{\n+\tunsigned int i;\n+\tuint64_t mask;\n+\tstruct virtual_machine_info *vm_info;\n+\n+\tLIST_FOREACH(vm_info, &vm_list_head, vms_info) {\n+\n+\t\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\t\tmask = vm_info->channel_mask;\n+\t\tITERATIVE_BITMASK_CHECK_64(mask, i) {\n+\t\t\t\tremove_channel_from_monitor(vm_info->channels[i]);\n+\t\t\t\tclose(vm_info->channels[i]->fd);\n+\t\t\t\trte_free(vm_info->channels[i]);\n+\t\t}\n+\t\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\n+\t\tLIST_REMOVE(vm_info, vms_info);\n+\t\trte_free(vm_info);\n+\t}\n+\tdisconnect_hypervisor();\n+}\n+\ndiff --git a/examples/vm_power_manager/channel_manager.h b/examples/vm_power_manager/channel_manager.h\nnew file mode 100644\nindex 0000000..d114201\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_manager.h\n@@ -0,0 +1,273 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef CHANNEL_MANAGER_H_\n+#define CHANNEL_MANAGER_H_\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <linux/limits.h>\n+#include <rte_atomic.h>\n+\n+/* Maximum number of channels per VM */\n+#define MAX_VM_CHANNELS 64\n+\n+/* Maximum name length including '\\0' terminator */\n+#define MAX_NAME_LEN    64\n+\n+/* Maximum number of virtual CPUs that can be assigned to a VM */\n+#define MAX_VCPU        64\n+\n+/* Default Hypervisor Path for libvirt(qemu/KVM) */\n+#define DEFAULT_HV_PATH \"qemu:///system\"\n+\n+/* Communication Channel Status */\n+enum channel_status { CHANNEL_DISCONNECTED = 0, CHANNEL_CONNECTED,\n+\tCHANNEL_DISABLED, CHANNEL_PROCESSING};\n+\n+/* VM libvirt(qemu/KVM) connection status */\n+enum vm_status { VM_INACTIVE = 0, VM_ACTIVE};\n+\n+/*\n+ *  Represents a single and exclusive VM channel that exists between a guest and\n+ *  the host.\n+ */\n+struct channel_info {\n+\tchar channel_path[PATH_MAX]; /**< Path to host socket */\n+\tvolatile uint32_t status;    /**< Connection status(enum channel_status) */\n+\tint fd;                      /**< AF_UNIX socket fd */\n+\tunsigned int channel_num;    /**< /tmp/powermonitor/<vm_name>.channel_num */\n+\tvoid *priv_info;             /**< Pointer to private info, do not modify */\n+};\n+\n+/* Represents a single VM instance used to return internal information about\n+ * a VM */\n+struct vm_info {\n+\tchar name[MAX_NAME_LEN];                      /**< VM name */\n+\tenum vm_status status;                        /**< libvirt status */\n+\tuint64_t pcpu_mask[MAX_VCPU];                 /**< pCPU mask for each vCPU */\n+\tunsigned num_vcpus;                           /**< number of vCPUS */\n+\tstruct channel_info channels[MAX_VM_CHANNELS];/**< Array of channel_info */\n+\tunsigned num_channels;                        /**< Number of channels */\n+};\n+\n+/**\n+ * Initialize the Channel Manager resources and connect to the Hypervisor\n+ * specified in path.\n+ * This must be successfully called first before calling any other functions.\n+ * It must only be call once;\n+ *\n+ * @param path\n+ *  Must be a local path, e.g. qemu:///system.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int channel_manager_init(const char *path);\n+\n+/**\n+ * Free resources associated with the Channel Manager.\n+ *\n+ * @param path\n+ *  Must be a local path, e.g. qemu:///system.\n+ *\n+ * @return\n+ *  None\n+ */\n+void channel_manager_exit(void);\n+\n+/**\n+ * Get the Physical CPU mask for VM lcore channel(vcpu), result is assigned to\n+ * core_mask.\n+ * It is not thread-safe.\n+ *\n+ * @param chan_info\n+ *  Pointer to struct channel_info\n+ *\n+ * @param vcpu\n+ *  The virtual CPU to query.\n+ *\n+ *\n+ * @return\n+ *  - 0 on error.\n+ *  - >0 on success.\n+ */\n+uint64_t get_pcpus_mask(struct channel_info *chan_info, unsigned vcpu);\n+\n+/**\n+ * Add a VM as specified by name to the Channel Manager. The name must\n+ * correspond to a valid libvirt domain name.\n+ * This is required prior to adding channels.\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to lookup.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int add_vm(const char *name);\n+\n+/**\n+ * Remove a previously added Virtual Machine from the Channel Manager\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to lookup.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int remove_vm(const char *name);\n+\n+/**\n+ * Add all available channels to the VM as specified by name.\n+ * Channels in the form of paths(/tmp/powermonitor/<vm_name>.<channel_number>\n+ * will only be parsed.\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to lookup.\n+ *\n+ * @return\n+ *  - N the number of channels added for the VM\n+ */\n+int add_all_channels(const char *vm_name);\n+\n+/**\n+ * Add the channel numbers in channel_list to the domain specified by name.\n+ * Channels in the form of paths(/tmp/powermonitor/<vm_name>.<channel_number>\n+ * will only be parsed.\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to add channels.\n+ *\n+ * @param channel_list\n+ *  Pointer to list of unsigned integers, representing the channel number to add\n+ *  It must be allocated outside of this function.\n+ *\n+ * @param num_channels\n+ *  The amount of channel numbers in channel_list\n+ *\n+ * @return\n+ *  - N the number of channels added for the VM\n+ *  - 0 for error\n+ */\n+int add_channels(const char *vm_name, unsigned *channel_list,\n+\t\tunsigned num_channels);\n+\n+/**\n+ * Remove a channel definition from the channel manager. This must only be\n+ * called from the channel monitor thread.\n+ *\n+ * @param chan_info\n+ *  Pointer to a valid struct channel_info.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int remove_channel(struct channel_info *chan_info);\n+\n+/**\n+ * For all channels associated with a Virtual Machine name, update the\n+ * connection status. Valid states are CHANNEL_CONNECTED or CHANNEL_DISABLED\n+ * only.\n+ *\n+ *\n+ * @param name\n+ *  Virtual Machine name to modify all channels.\n+ *\n+ * @param status\n+ *  The status to set each channel\n+ *\n+ * @param num_channels\n+ *  The amount of channel numbers in channel_list\n+ *\n+ * @return\n+ *  - N the number of channels added for the VM\n+ *  - 0 for error\n+ */\n+int set_channel_status_all(const char *name, enum channel_status status);\n+\n+/**\n+ * For all channels in channel_list associated with a Virtual Machine name\n+ * update the connection status of each.\n+ * Valid states are CHANNEL_CONNECTED or CHANNEL_DISABLED only.\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to add channels.\n+ *\n+ * @param channel_list\n+ *  Pointer to list of unsigned integers, representing the channel numbers to\n+ *  modify.\n+ *  It must be allocated outside of this function.\n+ *\n+ * @param num_channels\n+ *  The amount of channel numbers in channel_list\n+ *\n+ * @return\n+ *  - N the number of channels modified for the VM\n+ *  - 0 for error\n+ */\n+int set_channel_status(const char *vm_name, unsigned *channel_list,\n+\t\tunsigned len_channel_list, enum channel_status status);\n+\n+/**\n+ * Populates a pointer to struct vm_info associated with vm_name.\n+ *\n+ * @param vm_name\n+ *  The name of the virtual machine to lookup.\n+ *\n+ *  @param vm_info\n+ *   Pointer to a struct vm_info, this must be allocated prior to calling this\n+ *   function.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int get_info_vm(const char *vm_name, struct vm_info *info);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* CHANNEL_MANAGER_H_ */\ndiff --git a/examples/vm_power_manager/channel_monitor.c b/examples/vm_power_manager/channel_monitor.c\nnew file mode 100644\nindex 0000000..7207a2e\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_monitor.c\n@@ -0,0 +1,228 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <unistd.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <signal.h>\n+#include <errno.h>\n+#include <string.h>\n+#include <sys/types.h>\n+#include <sys/epoll.h>\n+#include <sys/queue.h>\n+\n+#include <rte_config.h>\n+#include <rte_log.h>\n+#include <rte_memory.h>\n+#include <rte_malloc.h>\n+#include <rte_atomic.h>\n+\n+\n+#include \"channel_monitor.h\"\n+#include \"channel_commands.h\"\n+#include \"channel_manager.h\"\n+#include \"power_manager.h\"\n+\n+#define RTE_LOGTYPE_CHANNEL_MONITOR RTE_LOGTYPE_USER1\n+\n+#define MAX_EVENTS 256\n+\n+\n+static volatile unsigned run_loop = 1;\n+static int global_event_fd;\n+static struct epoll_event *global_events_list;\n+\n+void channel_monitor_exit(void)\n+{\n+\trun_loop = 0;\n+\trte_free(global_events_list);\n+}\n+\n+static int\n+process_request(struct channel_packet *pkt, struct channel_info *chan_info)\n+{\n+\tuint64_t core_mask;\n+\n+\tif (chan_info == NULL)\n+\t\treturn -1;\n+\n+\tif (rte_atomic32_cmpset(&(chan_info->status), CHANNEL_CONNECTED,\n+\t\t\tCHANNEL_PROCESSING) == 0)\n+\t\treturn -1;\n+\n+\tif (pkt->command == CPU_POWER) {\n+\t\tcore_mask = get_pcpus_mask(chan_info, pkt->resource_id);\n+\t\tif (core_mask == 0) {\n+\t\t\tRTE_LOG(ERR, CHANNEL_MONITOR, \"Error get physical CPU mask for \"\n+\t\t\t\t\t\"channel '%s' using vCPU(%u)\\n\", chan_info->channel_path,\n+\t\t\t\t\t(unsigned)pkt->unit);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (__builtin_popcountll(core_mask) == 1) {\n+\n+\t\t\tunsigned core_num = __builtin_ffsll(core_mask) - 1;\n+\t\t\tswitch (pkt->unit) {\n+\t\t\tcase(CPU_SCALE_MIN):\n+\t\t\t\tpower_manager_scale_core_min(core_num);\n+\t\t\t\tbreak;\n+\t\t\tcase(CPU_SCALE_MAX):\n+\t\t\t\tpower_manager_scale_core_max(core_num);\n+\t\t\t\tbreak;\n+\t\t\tcase(CPU_SCALE_DOWN):\n+\t\t\t\tpower_manager_scale_core_down(core_num);\n+\t\t\t\tbreak;\n+\t\t\tcase(CPU_SCALE_UP):\n+\t\t\t\tpower_manager_scale_core_up(core_num);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tswitch (pkt->unit) {\n+\t\t\tcase(CPU_SCALE_MIN):\n+\t\t\t\tpower_manager_scale_mask_min(core_mask);\n+\t\t\t\tbreak;\n+\t\t\tcase(CPU_SCALE_MAX):\n+\t\t\t\tpower_manager_scale_mask_max(core_mask);\n+\t\t\t\tbreak;\n+\t\t\tcase(CPU_SCALE_DOWN):\n+\t\t\t\tpower_manager_scale_mask_down(core_mask);\n+\t\t\t\tbreak;\n+\t\t\tcase(CPU_SCALE_UP):\n+\t\t\t\tpower_manager_scale_mask_up(core_mask);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t}\n+\t}\n+\t/* Return is not checked as channel status may have been set to DISABLED\n+\t * from management thread\n+\t */\n+\trte_atomic32_cmpset(&(chan_info->status), CHANNEL_PROCESSING,\n+\t\t\t\tCHANNEL_CONNECTED);\n+\treturn 0;\n+\n+}\n+\n+int\n+add_channel_to_monitor(struct channel_info **chan_info)\n+{\n+\tstruct channel_info *info = *chan_info;\n+\tstruct epoll_event event;\n+\tevent.events = EPOLLIN;\n+\tevent.data.ptr = info;\n+\tif (epoll_ctl(global_event_fd, EPOLL_CTL_ADD, info->fd, &event) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MONITOR, \"Unable to add channel '%s' \"\n+\t\t\t\t\"to epoll\\n\", info->channel_path);\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+remove_channel_from_monitor(struct channel_info *chan_info)\n+{\n+\tif (epoll_ctl(global_event_fd, EPOLL_CTL_DEL, chan_info->fd, NULL) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MONITOR, \"Unable to remove channel '%s' \"\n+\t\t\t\t\"from epoll\\n\", chan_info->channel_path);\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+channel_monitor_init(void)\n+{\n+\tglobal_event_fd = epoll_create1(0);\n+\tif (global_event_fd == 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MONITOR, \"Error creating epoll context with \"\n+\t\t\t\t\"error %s\\n\", strerror(errno));\n+\t\treturn -1;\n+\t}\n+\tglobal_events_list = rte_malloc(\"epoll_events\", sizeof(*global_events_list)\n+\t\t\t* MAX_EVENTS, CACHE_LINE_SIZE);\n+\tif (global_events_list == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MONITOR, \"Unable to rte_malloc for\"\n+\t\t\t\t\"epoll events\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+void\n+run_channel_monitor(void)\n+{\n+\twhile (run_loop) {\n+\t\tint n_events, i;\n+\t\tn_events = epoll_wait(global_event_fd, global_events_list,\n+\t\t\t\tMAX_EVENTS, 1);\n+\t\tif (!run_loop)\n+\t\t\tbreak;\n+\t\tfor (i = 0; i < n_events; i++) {\n+\t\t\tstruct channel_info *chan_info = (struct channel_info *)\n+\t\t\t\t\t\t\t\tglobal_events_list[i].data.ptr;\n+\t\t\tif ((global_events_list[i].events & EPOLLERR) ||\n+\t\t\t\t\t(global_events_list[i].events & EPOLLHUP)) {\n+\t\t\t\tremove_channel(chan_info);\n+\t\t\t}\n+\t\t\tif (global_events_list[i].events & EPOLLIN) {\n+\n+\t\t\t\tint n_bytes, err = 0;\n+\t\t\t\tstruct channel_packet pkt;\n+\t\t\t\tvoid *buffer = &pkt;\n+\t\t\t\tint buffer_len = sizeof(pkt);\n+\t\t\t\twhile (buffer_len > 0) {\n+\t\t\t\t\tn_bytes = read(chan_info->fd, buffer, buffer_len);\n+\t\t\t\t\tif (n_bytes == buffer_len)\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\tif (n_bytes == -1) {\n+\t\t\t\t\t\terr = errno;\n+\t\t\t\t\t\tRTE_LOG(DEBUG, CHANNEL_MONITOR, \"Received error on \"\n+\t\t\t\t\t\t\t\t\"channel '%s' read: %s\\n\",\n+\t\t\t\t\t\t\t\tchan_info->channel_path, strerror(err));\n+\t\t\t\t\t\tremove_channel(chan_info);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t\tbuffer = (char *)buffer + n_bytes;\n+\t\t\t\t\tbuffer_len -= n_bytes;\n+\n+\t\t\t\t}\n+\t\t\t\tif (!err)\n+\t\t\t\t\tprocess_request(&pkt, chan_info);\n+\t\t\t}\n+\t\t}\n+\t}\n+}\ndiff --git a/examples/vm_power_manager/channel_monitor.h b/examples/vm_power_manager/channel_monitor.h\nnew file mode 100644\nindex 0000000..c138607\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_monitor.h\n@@ -0,0 +1,102 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef CHANNEL_MONITOR_H_\n+#define CHANNEL_MONITOR_H_\n+\n+#include \"channel_manager.h\"\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/**\n+ * Setup the Channel Monitor resources required to initialize epoll.\n+ * Must be called first before calling other functions.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int channel_monitor_init(void);\n+\n+/**\n+ * Run the channel monitor, loops forever on on epoll_wait.\n+ *\n+ *\n+ * @return\n+ *  None\n+ */\n+void run_channel_monitor(void);\n+\n+/**\n+ * Exit the Channel Monitor, exiting the epoll_wait loop and events processing.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+void channel_monitor_exit(void);\n+\n+/**\n+ * Add an open channel to monitor via epoll. A pointer to struct channel_info\n+ * will be registered with epoll for event processing.\n+ * It is thread-safe.\n+ *\n+ * @param chan_info\n+ *  Pointer to struct channel_info pointer.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int add_channel_to_monitor(struct channel_info **chan_info);\n+\n+/**\n+ * Remove a previously added channel from epoll control.\n+ *\n+ * @param chan_info\n+ *  Pointer to struct channel_info.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int remove_channel_from_monitor(struct channel_info *chan_info);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+\n+#endif /* CHANNEL_MONITOR_H_ */\n",
    "prefixes": [
        "dpdk-dev",
        "01/10"
    ]
}