get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1446,
    "url": "https://patches.dpdk.org/api/patches/1446/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1416591732-3735-2-git-send-email-pablo.de.lara.guarch@intel.com/",
    "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",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1416591732-3735-2-git-send-email-pablo.de.lara.guarch@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1416591732-3735-2-git-send-email-pablo.de.lara.guarch@intel.com",
    "date": "2014-11-21T17:42:03",
    "name": "[dpdk-dev,v5,01/10] Channel Manager and Monitor for VM Power Management(Host).",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "d8bf0cefba6f20cec6fd97ea4af6911c4208c5b6",
    "submitter": {
        "id": 9,
        "url": "https://patches.dpdk.org/api/people/9/?format=api",
        "name": "De Lara Guarch, Pablo",
        "email": "pablo.de.lara.guarch@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1416591732-3735-2-git-send-email-pablo.de.lara.guarch@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/1446/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/1446/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 6BEC07FC1;\n\tFri, 21 Nov 2014 18:31:58 +0100 (CET)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby dpdk.org (Postfix) with ESMTP id 3BD457F74\n\tfor <dev@dpdk.org>; Fri, 21 Nov 2014 18:31:46 +0100 (CET)",
            "from fmsmga001.fm.intel.com ([10.253.24.23])\n\tby fmsmga102.fm.intel.com with ESMTP; 21 Nov 2014 09:42:19 -0800",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby fmsmga001.fm.intel.com with ESMTP; 21 Nov 2014 09:42:16 -0800",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tsALHgF5r001841; Fri, 21 Nov 2014 17:42:15 GMT",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id sALHgFoH012196;\n\tFri, 21 Nov 2014 17:42:15 GMT",
            "(from pdelarax@localhost)\n\tby sivswdev02.ir.intel.com with  id sALHgF3T012192;\n\tFri, 21 Nov 2014 17:42:15 GMT"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.07,432,1413270000\"; d=\"scan'208\";a=\"626304564\"",
        "From": "Pablo de Lara <pablo.de.lara.guarch@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 21 Nov 2014 17:42:03 +0000",
        "Message-Id": "<1416591732-3735-2-git-send-email-pablo.de.lara.guarch@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "In-Reply-To": "<1416591732-3735-1-git-send-email-pablo.de.lara.guarch@intel.com>",
        "References": "<1413142571-23069-1-git-send-email-alan.carew@intel.com>\n\t<1416591732-3735-1-git-send-email-pablo.de.lara.guarch@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v5 01/10] Channel Manager and Monitor for VM\n\tPower Management(Host).",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Alan Carew <alan.carew@intel.com>\n\nThe 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>\nSigned-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>\n---\n examples/vm_power_manager/channel_manager.c |  804 +++++++++++++++++++++++++++\n examples/vm_power_manager/channel_manager.h |  314 +++++++++++\n examples/vm_power_manager/channel_monitor.c |  231 ++++++++\n examples/vm_power_manager/channel_monitor.h |  102 ++++\n 4 files changed, 1451 insertions(+), 0 deletions(-)\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..a14f191\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_manager.c\n@@ -0,0 +1,804 @@\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_mempool.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 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\tif ((mask_u64b >> i) & 1) \\\n+\n+/* Global pointer to libvirt connection */\n+static virConnectPtr global_vir_conn_ptr;\n+\n+static unsigned char *global_cpumaps;\n+static virVcpuInfo *global_vircpuinfo;\n+static size_t global_maplen;\n+\n+static unsigned global_n_host_cpus;\n+\n+/*\n+ * Represents a single Virtual Machine\n+ */\n+struct virtual_machine_info {\n+\tchar name[CHANNEL_MGR_MAX_NAME_LEN];\n+\trte_atomic64_t pcpu_mask[CHANNEL_CMDS_MAX_CPUS];\n+\tstruct channel_info *channels[CHANNEL_CMDS_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, CHANNEL_MGR_MAX_NAME_LEN-1))\n+\t\t\treturn info;\n+\t}\n+\treturn NULL;\n+}\n+\n+static int\n+update_pcpus_mask(struct virtual_machine_info *vm_info)\n+{\n+\tvirVcpuInfoPtr cpuinfo;\n+\tunsigned i, j;\n+\tint n_vcpus;\n+\tuint64_t mask;\n+\n+\tmemset(global_cpumaps, 0, CHANNEL_CMDS_MAX_CPUS*global_maplen);\n+\n+\tif (!virDomainIsActive(vm_info->domainPtr)) {\n+\t\tn_vcpus = virDomainGetVcpuPinInfo(vm_info->domainPtr,\n+\t\t\t\tvm_info->info.nrVirtCpu, global_cpumaps, global_maplen,\n+\t\t\t\tVIR_DOMAIN_AFFECT_CONFIG);\n+\t\tif (n_vcpus < 0) {\n+\t\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error getting vCPU info for \"\n+\t\t\t\t\t\"in-active VM '%s'\\n\", vm_info->name);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tgoto update_pcpus;\n+\t}\n+\n+\tmemset(global_vircpuinfo, 0, sizeof(*global_vircpuinfo)*\n+\t\t\tCHANNEL_CMDS_MAX_CPUS);\n+\n+\tcpuinfo = global_vircpuinfo;\n+\n+\tn_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo,\n+\t\t\tCHANNEL_CMDS_MAX_CPUS, global_cpumaps, global_maplen);\n+\tif (n_vcpus < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error getting vCPU info for \"\n+\t\t\t\t\t\t\t\"active VM '%s'\\n\", vm_info->name);\n+\t\treturn -1;\n+\t}\n+update_pcpus:\n+\tif (n_vcpus >= CHANNEL_CMDS_MAX_CPUS) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Number of vCPUS(%u) is out of range \"\n+\t\t\t\t\"0...%d\\n\", n_vcpus, CHANNEL_CMDS_MAX_CPUS-1);\n+\t\treturn -1;\n+\t}\n+\tif (n_vcpus != vm_info->info.nrVirtCpu) {\n+\t\tRTE_LOG(INFO, CHANNEL_MANAGER, \"Updating the number of vCPUs for VM '%s\"\n+\t\t\t\t\" from %d -> %d\\n\", vm_info->name, vm_info->info.nrVirtCpu,\n+\t\t\t\tn_vcpus);\n+\t\tvm_info->info.nrVirtCpu = n_vcpus;\n+\t}\n+\tfor (i = 0; i < vm_info->info.nrVirtCpu; i++) {\n+\t\tmask = 0;\n+\t\tfor (j = 0; j < global_n_host_cpus; j++) {\n+\t\t\tif (VIR_CPU_USABLE(global_cpumaps, global_maplen, i, j) > 0) {\n+\t\t\t\tmask |= 1ULL << j;\n+\t\t\t}\n+\t\t}\n+\t\trte_atomic64_set(&vm_info->pcpu_mask[i], mask);\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+set_pcpus_mask(char *vm_name, unsigned vcpu, uint64_t core_mask)\n+{\n+\tunsigned i = 0;\n+\tint flags = VIR_DOMAIN_AFFECT_LIVE|VIR_DOMAIN_AFFECT_CONFIG;\n+\tstruct virtual_machine_info *vm_info;\n+\tuint64_t mask = core_mask;\n+\n+\tif (vcpu >= CHANNEL_CMDS_MAX_CPUS) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"vCPU(%u) exceeds max allowable(%d)\\n\",\n+\t\t\t\tvcpu, CHANNEL_CMDS_MAX_CPUS-1);\n+\t\treturn -1;\n+\t}\n+\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+\n+\tif (!virDomainIsActive(vm_info->domainPtr)) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to set vCPU(%u) to pCPU \"\n+\t\t\t\t\"mask(0x%\"PRIx64\") for VM '%s', VM is not active\\n\",\n+\t\t\t\tvcpu, core_mask, vm_info->name);\n+\t\treturn -1;\n+\t}\n+\n+\tif (vcpu >= vm_info->info.nrVirtCpu) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"vCPU(%u) exceeds the assigned number of \"\n+\t\t\t\t\"vCPUs(%u)\\n\", vcpu, vm_info->info.nrVirtCpu);\n+\t\treturn -1;\n+\t}\n+\tmemset(global_cpumaps, 0 , CHANNEL_CMDS_MAX_CPUS * global_maplen);\n+\tITERATIVE_BITMASK_CHECK_64(mask, i) {\n+\t\tVIR_USE_CPU(global_cpumaps, i);\n+\t\tif (i >= global_n_host_cpus) {\n+\t\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"CPU(%u) exceeds the available \"\n+\t\t\t\t\t\"number of CPUs(%u)\\n\", i, global_n_host_cpus);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tif (virDomainPinVcpuFlags(vm_info->domainPtr, vcpu, global_cpumaps,\n+\t\t\tglobal_maplen, flags) < 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to set vCPU(%u) to pCPU \"\n+\t\t\t\t\"mask(0x%\"PRIx64\") for VM '%s'\\n\", vcpu, core_mask,\n+\t\t\t\tvm_info->name);\n+\t\treturn -1;\n+\t}\n+\trte_atomic64_set(&vm_info->pcpu_mask[vcpu], core_mask);\n+\treturn 0;\n+\n+}\n+\n+int\n+set_pcpu(char *vm_name, unsigned vcpu, unsigned core_num)\n+{\n+\tuint64_t mask = 1ULL << core_num;\n+\treturn set_pcpus_mask(vm_name, vcpu, mask);\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 rte_atomic64_read(&vm_info->pcpu_mask[vcpu]);\n+}\n+\n+static inline int\n+channel_exists(struct virtual_machine_info *vm_info, unsigned 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+\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_MGR_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_MGR_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 = CHANNEL_MGR_VM_INACTIVE;\n+\t\treturn 0;\n+\t}\n+\td = opendir(CHANNEL_MGR_SOCKET_PATH);\n+\tif (d == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error opening directory '%s': %s\\n\",\n+\t\t\t\tCHANNEL_MGR_SOCKET_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, CHANNEL_MGR_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)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 >= CHANNEL_CMDS_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, CHANNEL_CMDS_MAX_VM_CHANNELS-1,\n+\t\t\t\t\tCHANNEL_MGR_SOCKET_PATH, dir->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\", CHANNEL_MGR_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\",\n+\t\t\t\tCHANNEL_MGR_SOCKET_PATH, dir->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+\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 = CHANNEL_MGR_VM_INACTIVE;\n+\t\treturn 0;\n+\t}\n+\n+\tfor (i = 0; i < len_channel_list; i++) {\n+\n+\t\tif (channel_list[i] >= CHANNEL_CMDS_MAX_VM_CHANNELS) {\n+\t\t\tRTE_LOG(INFO, CHANNEL_MANAGER, \"Channel(%u) is out of range \"\n+\t\t\t\t\t\t\t\"0...%d\\n\", channel_list[i],\n+\t\t\t\t\t\t\tCHANNEL_CMDS_MAX_VM_CHANNELS-1);\n+\t\t\tcontinue;\n+\t\t}\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\",\n+\t\t\t\tCHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]);\n+\t\terrno = 0;\n+\t\tif (access(socket_path, F_OK) < 0) {\n+\t\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Channel path '%s' error: \"\n+\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\tsizeof(chan_info->channel_path), \"%s%s.%u\",\n+\t\t\t\tCHANNEL_MGR_SOCKET_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_dptr)\n+{\n+\tstruct virtual_machine_info *vm_info;\n+\tstruct channel_info *chan_info = *chan_info_dptr;\n+\n+\tclose(chan_info->fd);\n+\n+\tvm_info = (struct virtual_machine_info *)chan_info->priv_info;\n+\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+\n+\trte_free(chan_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 i;\n+\tuint64_t mask;\n+\tint num_channels_changed = 0;\n+\n+\tif (!(status == CHANNEL_MGR_CHANNEL_CONNECTED ||\n+\t\t\tstatus == CHANNEL_MGR_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\tvm_info->channels[i]->status = status;\n+\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_MGR_CHANNEL_CONNECTED ||\n+\t\t\tstatus == CHANNEL_MGR_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 = CHANNEL_MGR_VM_ACTIVE;\n+\tif (!virDomainIsActive(vm_info->domainPtr))\n+\t\tinfo->status = CHANNEL_MGR_VM_INACTIVE;\n+\n+\trte_spinlock_lock(&(vm_info->config_spinlock));\n+\n+\tmask = vm_info->channel_mask;\n+\tITERATIVE_BITMASK_CHECK_64(mask, i) {\n+\t\tinfo->channels[channel_num].channel_num = i;\n+\t\tmemcpy(info->channels[channel_num].channel_path,\n+\t\t\t\tvm_info->channels[i]->channel_path, PATH_MAX);\n+\t\tinfo->channels[channel_num].status = vm_info->channels[i]->status;\n+\t\tinfo->channels[channel_num].fd = vm_info->channels[i]->fd;\n+\t\tchannel_num++;\n+\t}\n+\n+\tinfo->num_channels = channel_num;\n+\tinfo->num_vcpus = vm_info->info.nrVirtCpu;\n+\trte_spinlock_unlock(&(vm_info->config_spinlock));\n+\n+\tmemcpy(info->name, vm_info->name, sizeof(vm_info->name));\n+\tfor (i = 0; i < info->num_vcpus; i++) {\n+\t\tinfo->pcpu_mask[i] = rte_atomic64_read(&vm_info->pcpu_mask[i]);\n+\t}\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+\tint i;\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\"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 > CHANNEL_CMDS_MAX_CPUS) {\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\tCHANNEL_CMDS_MAX_CPUS);\n+\t\trte_free(new_domain);\n+\t\treturn -1;\n+\t}\n+\n+\tfor (i = 0; i < CHANNEL_CMDS_MAX_CPUS; i++) {\n+\t\trte_atomic64_init(&new_domain->pcpu_mask[i]);\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 = CHANNEL_MGR_VM_INACTIVE;\n+\telse\n+\t\tnew_domain->status = CHANNEL_MGR_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+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\"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+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+int\n+channel_manager_init(const char *path)\n+{\n+\tint n_cpus;\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+\t\treturn -1;\n+\t}\n+\n+\tglobal_maplen = VIR_CPU_MAPLEN(CHANNEL_CMDS_MAX_CPUS);\n+\n+\tglobal_vircpuinfo = rte_zmalloc(NULL, sizeof(*global_vircpuinfo) *\n+\t\t\tCHANNEL_CMDS_MAX_CPUS, CACHE_LINE_SIZE);\n+\tif (global_vircpuinfo == NULL) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Error allocating memory for CPU Info\\n\");\n+\t\tgoto error;\n+\t}\n+\tglobal_cpumaps = rte_zmalloc(NULL, CHANNEL_CMDS_MAX_CPUS * global_maplen,\n+\t\t\tCACHE_LINE_SIZE);\n+\tif (global_cpumaps == NULL) {\n+\t\tgoto error;\n+\t}\n+\n+\tn_cpus = virNodeGetCPUMap(global_vir_conn_ptr, NULL, NULL, 0);\n+\tif (n_cpus <= 0) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"Unable to get the number of Host \"\n+\t\t\t\t\"CPUs\\n\");\n+\t\tgoto error;\n+\t}\n+\tglobal_n_host_cpus = (unsigned)n_cpus;\n+\n+\tif (global_n_host_cpus > CHANNEL_CMDS_MAX_CPUS) {\n+\t\tRTE_LOG(ERR, CHANNEL_MANAGER, \"The number of host CPUs(%u) exceeds the \"\n+\t\t\t\t\"maximum of %u\\n\", global_n_host_cpus, CHANNEL_CMDS_MAX_CPUS);\n+\t\tgoto error;\n+\n+\t}\n+\n+\treturn 0;\n+error:\n+\tdisconnect_hypervisor();\n+\treturn -1;\n+}\n+\n+void\n+channel_manager_exit(void)\n+{\n+\tunsigned 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+\n+\t\tmask = vm_info->channel_mask;\n+\t\tITERATIVE_BITMASK_CHECK_64(mask, i) {\n+\t\t\tremove_channel_from_monitor(vm_info->channels[i]);\n+\t\t\tclose(vm_info->channels[i]->fd);\n+\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+\n+\tif (global_cpumaps != NULL)\n+\t\trte_free(global_cpumaps);\n+\tif (global_vircpuinfo != NULL)\n+\t\trte_free(global_vircpuinfo);\n+\tdisconnect_hypervisor();\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..12c29c3\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_manager.h\n@@ -0,0 +1,314 @@\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+#include \"channel_commands.h\"\n+\n+/* Maximum name length including '\\0' terminator */\n+#define CHANNEL_MGR_MAX_NAME_LEN    64\n+\n+/* Maximum number of channels to each Virtual Machine */\n+#define CHANNEL_MGR_MAX_CHANNELS    64\n+\n+/* Hypervisor Path for libvirt(qemu/KVM) */\n+#define CHANNEL_MGR_DEFAULT_HV_PATH \"qemu:///system\"\n+\n+/* File socket directory */\n+#define CHANNEL_MGR_SOCKET_PATH     \"/tmp/powermonitor/\"\n+\n+/* Communication Channel Status */\n+enum channel_status { CHANNEL_MGR_CHANNEL_DISCONNECTED = 0,\n+\tCHANNEL_MGR_CHANNEL_CONNECTED,\n+\tCHANNEL_MGR_CHANNEL_DISABLED,\n+\tCHANNEL_MGR_CHANNEL_PROCESSING};\n+\n+/* VM libvirt(qemu/KVM) connection status */\n+enum vm_status { CHANNEL_MGR_VM_INACTIVE = 0, CHANNEL_MGR_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 channel_num;        /**< CHANNEL_MGR_SOCKET_PATH/<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[CHANNEL_MGR_MAX_NAME_LEN];          /**< VM name */\n+\tenum vm_status status;                        /**< libvirt status */\n+\tuint64_t pcpu_mask[CHANNEL_CMDS_MAX_CPUS];    /**< pCPU mask for each vCPU */\n+\tunsigned num_vcpus;                           /**< number of vCPUS */\n+\tstruct channel_info channels[CHANNEL_MGR_MAX_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+ * Set the Physical CPU mask for the specified vCPU.\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to lookup\n+ *\n+ * @param vcpu\n+ *  The virtual CPU to set.\n+ *\n+ * @param core_mask\n+ *  The core mask of the physical CPU(s) to bind the vCPU\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int set_pcpus_mask(char *vm_name, unsigned vcpu, uint64_t core_mask);\n+\n+/**\n+ * Set the Physical CPU for the specified vCPU.\n+ * It is not thread-safe.\n+ *\n+ * @param name\n+ *  Virtual Machine name to lookup\n+ *\n+ * @param vcpu\n+ *  The virtual CPU to set.\n+ *\n+ * @param core_num\n+ *  The core number of the physical CPU(s) to bind the vCPU\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int set_pcpu(char *vm_name, unsigned vcpu, unsigned core_num);\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\n+ * (CHANNEL_MGR_SOCKET_PATH/<vm_name>.<channel_number>) 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\n+ * (CHANNEL_MGR_SOCKET_PATH/<vm_name>.<channel_number>) 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_dptr);\n+\n+/**\n+ * For all channels associated with a Virtual Machine name, update the\n+ * connection status. Valid states are CHANNEL_MGR_CHANNEL_CONNECTED or\n+ * CHANNEL_MGR_CHANNEL_DISABLED 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_MGR_CHANNEL_CONNECTED or\n+ * CHANNEL_MGR_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..3674c7c\n--- /dev/null\n+++ b/examples/vm_power_manager/channel_monitor.c\n@@ -0,0 +1,231 @@\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_MGR_CHANNEL_CONNECTED,\n+\t\t\tCHANNEL_MGR_CHANNEL_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+\n+\t\t\tswitch (pkt->unit) {\n+\t\t\tcase(CPU_POWER_SCALE_MIN):\n+\t\t\t\t\tpower_manager_scale_core_min(core_num);\n+\t\t\tbreak;\n+\t\t\tcase(CPU_POWER_SCALE_MAX):\n+\t\t\t\t\tpower_manager_scale_core_max(core_num);\n+\t\t\tbreak;\n+\t\t\tcase(CPU_POWER_SCALE_DOWN):\n+\t\t\t\t\tpower_manager_scale_core_down(core_num);\n+\t\t\tbreak;\n+\t\t\tcase(CPU_POWER_SCALE_UP):\n+\t\t\t\t\tpower_manager_scale_core_up(core_num);\n+\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_POWER_SCALE_MIN):\n+\t\t\t\t\tpower_manager_scale_mask_min(core_mask);\n+\t\t\tbreak;\n+\t\t\tcase(CPU_POWER_SCALE_MAX):\n+\t\t\t\t\tpower_manager_scale_mask_max(core_mask);\n+\t\t\tbreak;\n+\t\t\tcase(CPU_POWER_SCALE_DOWN):\n+\t\t\t\t\tpower_manager_scale_mask_down(core_mask);\n+\t\t\tbreak;\n+\t\t\tcase(CPU_POWER_SCALE_UP):\n+\t\t\t\t\tpower_manager_scale_mask_up(core_mask);\n+\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_MGR_CHANNEL_PROCESSING,\n+\t\t\tCHANNEL_MGR_CHANNEL_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\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\tRTE_LOG(DEBUG, CHANNEL_MONITOR, \"Remote closed connection for \"\n+\t\t\t\t\t\t\"channel '%s'\\n\", chan_info->channel_path);\n+\t\t\t\tremove_channel(&chan_info);\n+\t\t\t\tcontinue;\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+\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",
        "v5",
        "01/10"
    ]
}