1e8ae9b66SAlan Carew /*- 2e8ae9b66SAlan Carew * BSD LICENSE 3e8ae9b66SAlan Carew * 4e8ae9b66SAlan Carew * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5e8ae9b66SAlan Carew * All rights reserved. 6e8ae9b66SAlan Carew * 7e8ae9b66SAlan Carew * Redistribution and use in source and binary forms, with or without 8e8ae9b66SAlan Carew * modification, are permitted provided that the following conditions 9e8ae9b66SAlan Carew * are met: 10e8ae9b66SAlan Carew * 11e8ae9b66SAlan Carew * * Redistributions of source code must retain the above copyright 12e8ae9b66SAlan Carew * notice, this list of conditions and the following disclaimer. 13e8ae9b66SAlan Carew * * Redistributions in binary form must reproduce the above copyright 14e8ae9b66SAlan Carew * notice, this list of conditions and the following disclaimer in 15e8ae9b66SAlan Carew * the documentation and/or other materials provided with the 16e8ae9b66SAlan Carew * distribution. 17e8ae9b66SAlan Carew * * Neither the name of Intel Corporation nor the names of its 18e8ae9b66SAlan Carew * contributors may be used to endorse or promote products derived 19e8ae9b66SAlan Carew * from this software without specific prior written permission. 20e8ae9b66SAlan Carew * 21e8ae9b66SAlan Carew * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22e8ae9b66SAlan Carew * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23e8ae9b66SAlan Carew * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24e8ae9b66SAlan Carew * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25e8ae9b66SAlan Carew * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26e8ae9b66SAlan Carew * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27e8ae9b66SAlan Carew * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28e8ae9b66SAlan Carew * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29e8ae9b66SAlan Carew * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30e8ae9b66SAlan Carew * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31e8ae9b66SAlan Carew * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32e8ae9b66SAlan Carew */ 33e8ae9b66SAlan Carew 34e8ae9b66SAlan Carew #include <stdio.h> 35e8ae9b66SAlan Carew #include <stdlib.h> 36e8ae9b66SAlan Carew #include <sys/un.h> 37e8ae9b66SAlan Carew #include <fcntl.h> 38e8ae9b66SAlan Carew #include <unistd.h> 39e8ae9b66SAlan Carew #include <inttypes.h> 40e8ae9b66SAlan Carew #include <dirent.h> 41e8ae9b66SAlan Carew #include <errno.h> 42e8ae9b66SAlan Carew 43e8ae9b66SAlan Carew #include <sys/queue.h> 44e8ae9b66SAlan Carew #include <sys/types.h> 45e8ae9b66SAlan Carew #include <sys/socket.h> 46e8ae9b66SAlan Carew #include <sys/select.h> 47e8ae9b66SAlan Carew 48e8ae9b66SAlan Carew #include <rte_config.h> 49e8ae9b66SAlan Carew #include <rte_malloc.h> 50e8ae9b66SAlan Carew #include <rte_memory.h> 51e8ae9b66SAlan Carew #include <rte_mempool.h> 52e8ae9b66SAlan Carew #include <rte_log.h> 53e8ae9b66SAlan Carew #include <rte_atomic.h> 54e8ae9b66SAlan Carew #include <rte_spinlock.h> 55e8ae9b66SAlan Carew 56e8ae9b66SAlan Carew #include <libvirt/libvirt.h> 57e8ae9b66SAlan Carew 58e8ae9b66SAlan Carew #include "channel_manager.h" 59e8ae9b66SAlan Carew #include "channel_commands.h" 60e8ae9b66SAlan Carew #include "channel_monitor.h" 61e8ae9b66SAlan Carew 62e8ae9b66SAlan Carew 63e8ae9b66SAlan Carew #define RTE_LOGTYPE_CHANNEL_MANAGER RTE_LOGTYPE_USER1 64e8ae9b66SAlan Carew 65e8ae9b66SAlan Carew #define ITERATIVE_BITMASK_CHECK_64(mask_u64b, i) \ 66e8ae9b66SAlan Carew for (i = 0; mask_u64b; mask_u64b &= ~(1ULL << i++)) \ 67e8ae9b66SAlan Carew if ((mask_u64b >> i) & 1) \ 68e8ae9b66SAlan Carew 69e8ae9b66SAlan Carew /* Global pointer to libvirt connection */ 70e8ae9b66SAlan Carew static virConnectPtr global_vir_conn_ptr; 71e8ae9b66SAlan Carew 72e8ae9b66SAlan Carew static unsigned char *global_cpumaps; 73e8ae9b66SAlan Carew static virVcpuInfo *global_vircpuinfo; 74e8ae9b66SAlan Carew static size_t global_maplen; 75e8ae9b66SAlan Carew 76e8ae9b66SAlan Carew static unsigned global_n_host_cpus; 77e8ae9b66SAlan Carew 78e8ae9b66SAlan Carew /* 79e8ae9b66SAlan Carew * Represents a single Virtual Machine 80e8ae9b66SAlan Carew */ 81e8ae9b66SAlan Carew struct virtual_machine_info { 82e8ae9b66SAlan Carew char name[CHANNEL_MGR_MAX_NAME_LEN]; 83e8ae9b66SAlan Carew rte_atomic64_t pcpu_mask[CHANNEL_CMDS_MAX_CPUS]; 84e8ae9b66SAlan Carew struct channel_info *channels[CHANNEL_CMDS_MAX_VM_CHANNELS]; 85e8ae9b66SAlan Carew uint64_t channel_mask; 86e8ae9b66SAlan Carew uint8_t num_channels; 87e8ae9b66SAlan Carew enum vm_status status; 88e8ae9b66SAlan Carew virDomainPtr domainPtr; 89e8ae9b66SAlan Carew virDomainInfo info; 90e8ae9b66SAlan Carew rte_spinlock_t config_spinlock; 91e8ae9b66SAlan Carew LIST_ENTRY(virtual_machine_info) vms_info; 92e8ae9b66SAlan Carew }; 93e8ae9b66SAlan Carew 94e8ae9b66SAlan Carew LIST_HEAD(, virtual_machine_info) vm_list_head; 95e8ae9b66SAlan Carew 96e8ae9b66SAlan Carew static struct virtual_machine_info * 97e8ae9b66SAlan Carew find_domain_by_name(const char *name) 98e8ae9b66SAlan Carew { 99e8ae9b66SAlan Carew struct virtual_machine_info *info; 100e8ae9b66SAlan Carew LIST_FOREACH(info, &vm_list_head, vms_info) { 101e8ae9b66SAlan Carew if (!strncmp(info->name, name, CHANNEL_MGR_MAX_NAME_LEN-1)) 102e8ae9b66SAlan Carew return info; 103e8ae9b66SAlan Carew } 104e8ae9b66SAlan Carew return NULL; 105e8ae9b66SAlan Carew } 106e8ae9b66SAlan Carew 107e8ae9b66SAlan Carew static int 108e8ae9b66SAlan Carew update_pcpus_mask(struct virtual_machine_info *vm_info) 109e8ae9b66SAlan Carew { 110e8ae9b66SAlan Carew virVcpuInfoPtr cpuinfo; 111e8ae9b66SAlan Carew unsigned i, j; 112e8ae9b66SAlan Carew int n_vcpus; 113e8ae9b66SAlan Carew uint64_t mask; 114e8ae9b66SAlan Carew 115e8ae9b66SAlan Carew memset(global_cpumaps, 0, CHANNEL_CMDS_MAX_CPUS*global_maplen); 116e8ae9b66SAlan Carew 117e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 118e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpuPinInfo(vm_info->domainPtr, 119e8ae9b66SAlan Carew vm_info->info.nrVirtCpu, global_cpumaps, global_maplen, 120e8ae9b66SAlan Carew VIR_DOMAIN_AFFECT_CONFIG); 121e8ae9b66SAlan Carew if (n_vcpus < 0) { 122e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for " 123e8ae9b66SAlan Carew "in-active VM '%s'\n", vm_info->name); 124e8ae9b66SAlan Carew return -1; 125e8ae9b66SAlan Carew } 126e8ae9b66SAlan Carew goto update_pcpus; 127e8ae9b66SAlan Carew } 128e8ae9b66SAlan Carew 129e8ae9b66SAlan Carew memset(global_vircpuinfo, 0, sizeof(*global_vircpuinfo)* 130e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_CPUS); 131e8ae9b66SAlan Carew 132e8ae9b66SAlan Carew cpuinfo = global_vircpuinfo; 133e8ae9b66SAlan Carew 134e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo, 135e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_CPUS, global_cpumaps, global_maplen); 136e8ae9b66SAlan Carew if (n_vcpus < 0) { 137e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for " 138e8ae9b66SAlan Carew "active VM '%s'\n", vm_info->name); 139e8ae9b66SAlan Carew return -1; 140e8ae9b66SAlan Carew } 141e8ae9b66SAlan Carew update_pcpus: 142e8ae9b66SAlan Carew if (n_vcpus >= CHANNEL_CMDS_MAX_CPUS) { 143e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Number of vCPUS(%u) is out of range " 144e8ae9b66SAlan Carew "0...%d\n", n_vcpus, CHANNEL_CMDS_MAX_CPUS-1); 145e8ae9b66SAlan Carew return -1; 146e8ae9b66SAlan Carew } 147e8ae9b66SAlan Carew if (n_vcpus != vm_info->info.nrVirtCpu) { 148e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Updating the number of vCPUs for VM '%s" 149e8ae9b66SAlan Carew " from %d -> %d\n", vm_info->name, vm_info->info.nrVirtCpu, 150e8ae9b66SAlan Carew n_vcpus); 151e8ae9b66SAlan Carew vm_info->info.nrVirtCpu = n_vcpus; 152e8ae9b66SAlan Carew } 153e8ae9b66SAlan Carew for (i = 0; i < vm_info->info.nrVirtCpu; i++) { 154e8ae9b66SAlan Carew mask = 0; 155e8ae9b66SAlan Carew for (j = 0; j < global_n_host_cpus; j++) { 156e8ae9b66SAlan Carew if (VIR_CPU_USABLE(global_cpumaps, global_maplen, i, j) > 0) { 157e8ae9b66SAlan Carew mask |= 1ULL << j; 158e8ae9b66SAlan Carew } 159e8ae9b66SAlan Carew } 160e8ae9b66SAlan Carew rte_atomic64_set(&vm_info->pcpu_mask[i], mask); 161e8ae9b66SAlan Carew } 162e8ae9b66SAlan Carew return 0; 163e8ae9b66SAlan Carew } 164e8ae9b66SAlan Carew 165e8ae9b66SAlan Carew int 166e8ae9b66SAlan Carew set_pcpus_mask(char *vm_name, unsigned vcpu, uint64_t core_mask) 167e8ae9b66SAlan Carew { 168e8ae9b66SAlan Carew unsigned i = 0; 169e8ae9b66SAlan Carew int flags = VIR_DOMAIN_AFFECT_LIVE|VIR_DOMAIN_AFFECT_CONFIG; 170e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 171e8ae9b66SAlan Carew uint64_t mask = core_mask; 172e8ae9b66SAlan Carew 173e8ae9b66SAlan Carew if (vcpu >= CHANNEL_CMDS_MAX_CPUS) { 174e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds max allowable(%d)\n", 175e8ae9b66SAlan Carew vcpu, CHANNEL_CMDS_MAX_CPUS-1); 176e8ae9b66SAlan Carew return -1; 177e8ae9b66SAlan Carew } 178e8ae9b66SAlan Carew 179e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 180e8ae9b66SAlan Carew if (vm_info == NULL) { 181e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 182e8ae9b66SAlan Carew return -1; 183e8ae9b66SAlan Carew } 184e8ae9b66SAlan Carew 185e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 186e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU " 187e8ae9b66SAlan Carew "mask(0x%"PRIx64") for VM '%s', VM is not active\n", 188e8ae9b66SAlan Carew vcpu, core_mask, vm_info->name); 189e8ae9b66SAlan Carew return -1; 190e8ae9b66SAlan Carew } 191e8ae9b66SAlan Carew 192e8ae9b66SAlan Carew if (vcpu >= vm_info->info.nrVirtCpu) { 193e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds the assigned number of " 194e8ae9b66SAlan Carew "vCPUs(%u)\n", vcpu, vm_info->info.nrVirtCpu); 195e8ae9b66SAlan Carew return -1; 196e8ae9b66SAlan Carew } 197e8ae9b66SAlan Carew memset(global_cpumaps, 0 , CHANNEL_CMDS_MAX_CPUS * global_maplen); 198e8ae9b66SAlan Carew ITERATIVE_BITMASK_CHECK_64(mask, i) { 199e8ae9b66SAlan Carew VIR_USE_CPU(global_cpumaps, i); 200e8ae9b66SAlan Carew if (i >= global_n_host_cpus) { 201e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "CPU(%u) exceeds the available " 202e8ae9b66SAlan Carew "number of CPUs(%u)\n", i, global_n_host_cpus); 203e8ae9b66SAlan Carew return -1; 204e8ae9b66SAlan Carew } 205e8ae9b66SAlan Carew } 206e8ae9b66SAlan Carew if (virDomainPinVcpuFlags(vm_info->domainPtr, vcpu, global_cpumaps, 207e8ae9b66SAlan Carew global_maplen, flags) < 0) { 208e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU " 209e8ae9b66SAlan Carew "mask(0x%"PRIx64") for VM '%s'\n", vcpu, core_mask, 210e8ae9b66SAlan Carew vm_info->name); 211e8ae9b66SAlan Carew return -1; 212e8ae9b66SAlan Carew } 213e8ae9b66SAlan Carew rte_atomic64_set(&vm_info->pcpu_mask[vcpu], core_mask); 214e8ae9b66SAlan Carew return 0; 215e8ae9b66SAlan Carew 216e8ae9b66SAlan Carew } 217e8ae9b66SAlan Carew 218e8ae9b66SAlan Carew int 219e8ae9b66SAlan Carew set_pcpu(char *vm_name, unsigned vcpu, unsigned core_num) 220e8ae9b66SAlan Carew { 221e8ae9b66SAlan Carew uint64_t mask = 1ULL << core_num; 222e8ae9b66SAlan Carew 223e8ae9b66SAlan Carew return set_pcpus_mask(vm_name, vcpu, mask); 224e8ae9b66SAlan Carew } 225e8ae9b66SAlan Carew 226e8ae9b66SAlan Carew uint64_t 227e8ae9b66SAlan Carew get_pcpus_mask(struct channel_info *chan_info, unsigned vcpu) 228e8ae9b66SAlan Carew { 229e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = 230e8ae9b66SAlan Carew (struct virtual_machine_info *)chan_info->priv_info; 231e8ae9b66SAlan Carew return rte_atomic64_read(&vm_info->pcpu_mask[vcpu]); 232e8ae9b66SAlan Carew } 233e8ae9b66SAlan Carew 234e8ae9b66SAlan Carew static inline int 235e8ae9b66SAlan Carew channel_exists(struct virtual_machine_info *vm_info, unsigned channel_num) 236e8ae9b66SAlan Carew { 237e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 238e8ae9b66SAlan Carew if (vm_info->channel_mask & (1ULL << channel_num)) { 239e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 240e8ae9b66SAlan Carew return 1; 241e8ae9b66SAlan Carew } 242e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 243e8ae9b66SAlan Carew return 0; 244e8ae9b66SAlan Carew } 245e8ae9b66SAlan Carew 246e8ae9b66SAlan Carew 247e8ae9b66SAlan Carew 248e8ae9b66SAlan Carew static int 249e8ae9b66SAlan Carew open_non_blocking_channel(struct channel_info *info) 250e8ae9b66SAlan Carew { 251e8ae9b66SAlan Carew int ret, flags; 252e8ae9b66SAlan Carew struct sockaddr_un sock_addr; 253e8ae9b66SAlan Carew fd_set soc_fd_set; 254e8ae9b66SAlan Carew struct timeval tv; 255e8ae9b66SAlan Carew 256e8ae9b66SAlan Carew info->fd = socket(AF_UNIX, SOCK_STREAM, 0); 257e8ae9b66SAlan Carew if (info->fd == -1) { 258e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) creating socket for '%s'\n", 259e8ae9b66SAlan Carew strerror(errno), 260e8ae9b66SAlan Carew info->channel_path); 261e8ae9b66SAlan Carew return -1; 262e8ae9b66SAlan Carew } 263e8ae9b66SAlan Carew sock_addr.sun_family = AF_UNIX; 264e8ae9b66SAlan Carew memcpy(&sock_addr.sun_path, info->channel_path, 265e8ae9b66SAlan Carew strlen(info->channel_path)+1); 266e8ae9b66SAlan Carew 267e8ae9b66SAlan Carew /* Get current flags */ 268e8ae9b66SAlan Carew flags = fcntl(info->fd, F_GETFL, 0); 269e8ae9b66SAlan Carew if (flags < 0) { 270e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for" 271e8ae9b66SAlan Carew "'%s'\n", strerror(errno), info->channel_path); 272e8ae9b66SAlan Carew return 1; 273e8ae9b66SAlan Carew } 274e8ae9b66SAlan Carew /* Set to Non Blocking */ 275e8ae9b66SAlan Carew flags |= O_NONBLOCK; 276e8ae9b66SAlan Carew if (fcntl(info->fd, F_SETFL, flags) < 0) { 277e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) setting non-blocking " 278e8ae9b66SAlan Carew "socket for '%s'\n", strerror(errno), info->channel_path); 279e8ae9b66SAlan Carew return -1; 280e8ae9b66SAlan Carew } 281e8ae9b66SAlan Carew ret = connect(info->fd, (struct sockaddr *)&sock_addr, 282e8ae9b66SAlan Carew sizeof(sock_addr)); 283e8ae9b66SAlan Carew if (ret < 0) { 284e8ae9b66SAlan Carew /* ECONNREFUSED error is given when VM is not active */ 285e8ae9b66SAlan Carew if (errno == ECONNREFUSED) { 286e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "VM is not active or has not " 287e8ae9b66SAlan Carew "activated its endpoint to channel %s\n", 288e8ae9b66SAlan Carew info->channel_path); 289e8ae9b66SAlan Carew return -1; 290e8ae9b66SAlan Carew } 291e8ae9b66SAlan Carew /* Wait for tv_sec if in progress */ 292e8ae9b66SAlan Carew else if (errno == EINPROGRESS) { 293e8ae9b66SAlan Carew tv.tv_sec = 2; 294e8ae9b66SAlan Carew tv.tv_usec = 0; 295e8ae9b66SAlan Carew FD_ZERO(&soc_fd_set); 296e8ae9b66SAlan Carew FD_SET(info->fd, &soc_fd_set); 297e8ae9b66SAlan Carew if (select(info->fd+1, NULL, &soc_fd_set, NULL, &tv) > 0) { 298e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Timeout or error on channel " 299e8ae9b66SAlan Carew "'%s'\n", info->channel_path); 300e8ae9b66SAlan Carew return -1; 301e8ae9b66SAlan Carew } 302e8ae9b66SAlan Carew } else { 303e8ae9b66SAlan Carew /* Any other error */ 304e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) connecting socket" 305e8ae9b66SAlan Carew " for '%s'\n", strerror(errno), info->channel_path); 306e8ae9b66SAlan Carew return -1; 307e8ae9b66SAlan Carew } 308e8ae9b66SAlan Carew } 309e8ae9b66SAlan Carew return 0; 310e8ae9b66SAlan Carew } 311e8ae9b66SAlan Carew 312e8ae9b66SAlan Carew static int 313e8ae9b66SAlan Carew setup_channel_info(struct virtual_machine_info **vm_info_dptr, 314e8ae9b66SAlan Carew struct channel_info **chan_info_dptr, unsigned channel_num) 315e8ae9b66SAlan Carew { 316e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 317e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = *vm_info_dptr; 318e8ae9b66SAlan Carew 319e8ae9b66SAlan Carew chan_info->channel_num = channel_num; 320e8ae9b66SAlan Carew chan_info->priv_info = (void *)vm_info; 321e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED; 322e8ae9b66SAlan Carew if (open_non_blocking_channel(chan_info) < 0) { 323e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open channel: " 324e8ae9b66SAlan Carew "'%s' for VM '%s'\n", 325e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name); 326e8ae9b66SAlan Carew return -1; 327e8ae9b66SAlan Carew } 328e8ae9b66SAlan Carew if (add_channel_to_monitor(&chan_info) < 0) { 329e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: " 330e8ae9b66SAlan Carew "'%s' to epoll ctl for VM '%s'\n", 331e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name); 332e8ae9b66SAlan Carew return -1; 333e8ae9b66SAlan Carew 334e8ae9b66SAlan Carew } 335e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 336e8ae9b66SAlan Carew vm_info->num_channels++; 337e8ae9b66SAlan Carew vm_info->channel_mask |= 1ULL << channel_num; 338e8ae9b66SAlan Carew vm_info->channels[channel_num] = chan_info; 339e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED; 340e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 341e8ae9b66SAlan Carew return 0; 342e8ae9b66SAlan Carew } 343e8ae9b66SAlan Carew 344e8ae9b66SAlan Carew int 345e8ae9b66SAlan Carew add_all_channels(const char *vm_name) 346e8ae9b66SAlan Carew { 347e8ae9b66SAlan Carew DIR *d; 348e8ae9b66SAlan Carew struct dirent *dir; 349e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 350e8ae9b66SAlan Carew struct channel_info *chan_info; 351e8ae9b66SAlan Carew char *token, *remaining, *tail_ptr; 352e8ae9b66SAlan Carew char socket_name[PATH_MAX]; 353e8ae9b66SAlan Carew unsigned channel_num; 354e8ae9b66SAlan Carew int num_channels_enabled = 0; 355e8ae9b66SAlan Carew 356e8ae9b66SAlan Carew /* verify VM exists */ 357e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 358e8ae9b66SAlan Carew if (vm_info == NULL) { 359e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' not found" 360e8ae9b66SAlan Carew " during channel discovery\n", vm_name); 361e8ae9b66SAlan Carew return 0; 362e8ae9b66SAlan Carew } 363e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 364e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 365e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 366e8ae9b66SAlan Carew return 0; 367e8ae9b66SAlan Carew } 368e8ae9b66SAlan Carew d = opendir(CHANNEL_MGR_SOCKET_PATH); 369e8ae9b66SAlan Carew if (d == NULL) { 370e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error opening directory '%s': %s\n", 371e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, strerror(errno)); 372e8ae9b66SAlan Carew return -1; 373e8ae9b66SAlan Carew } 374e8ae9b66SAlan Carew while ((dir = readdir(d)) != NULL) { 375e8ae9b66SAlan Carew if (!strncmp(dir->d_name, ".", 1) || 376e8ae9b66SAlan Carew !strncmp(dir->d_name, "..", 2)) 377e8ae9b66SAlan Carew continue; 378e8ae9b66SAlan Carew 379e8ae9b66SAlan Carew snprintf(socket_name, sizeof(socket_name), "%s", dir->d_name); 380e8ae9b66SAlan Carew remaining = socket_name; 381e8ae9b66SAlan Carew /* Extract vm_name from "<vm_name>.<channel_num>" */ 382e8ae9b66SAlan Carew token = strsep(&remaining, "."); 383e8ae9b66SAlan Carew if (remaining == NULL) 384e8ae9b66SAlan Carew continue; 385e8ae9b66SAlan Carew if (strncmp(vm_name, token, CHANNEL_MGR_MAX_NAME_LEN)) 386e8ae9b66SAlan Carew continue; 387e8ae9b66SAlan Carew 388e8ae9b66SAlan Carew /* remaining should contain only <channel_num> */ 389e8ae9b66SAlan Carew errno = 0; 390e8ae9b66SAlan Carew channel_num = (unsigned)strtol(remaining, &tail_ptr, 0); 391e8ae9b66SAlan Carew if ((errno != 0) || (remaining[0] == '\0') || 392e8ae9b66SAlan Carew (*tail_ptr != '\0') || tail_ptr == NULL) { 393e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Malformed channel name" 394e8ae9b66SAlan Carew "'%s' found it should be in the form of " 395e8ae9b66SAlan Carew "'<guest_name>.<channel_num>(decimal)'\n", 396e8ae9b66SAlan Carew dir->d_name); 397e8ae9b66SAlan Carew continue; 398e8ae9b66SAlan Carew } 399e8ae9b66SAlan Carew if (channel_num >= CHANNEL_CMDS_MAX_VM_CHANNELS) { 400e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Channel number(%u) is " 401e8ae9b66SAlan Carew "greater than max allowable: %d, skipping '%s%s'\n", 402e8ae9b66SAlan Carew channel_num, CHANNEL_CMDS_MAX_VM_CHANNELS-1, 403e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 404e8ae9b66SAlan Carew continue; 405e8ae9b66SAlan Carew } 406e8ae9b66SAlan Carew /* if channel has not been added previously */ 407e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_num)) 408e8ae9b66SAlan Carew continue; 409e8ae9b66SAlan Carew 410e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 411fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 412e8ae9b66SAlan Carew if (chan_info == NULL) { 413e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 414e8ae9b66SAlan Carew "channel '%s%s'\n", CHANNEL_MGR_SOCKET_PATH, dir->d_name); 415e8ae9b66SAlan Carew continue; 416e8ae9b66SAlan Carew } 417e8ae9b66SAlan Carew 418e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 419e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s", 420e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 421e8ae9b66SAlan Carew 422e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) { 423e8ae9b66SAlan Carew rte_free(chan_info); 424e8ae9b66SAlan Carew continue; 425e8ae9b66SAlan Carew } 426e8ae9b66SAlan Carew 427e8ae9b66SAlan Carew num_channels_enabled++; 428e8ae9b66SAlan Carew } 429e8ae9b66SAlan Carew closedir(d); 430e8ae9b66SAlan Carew return num_channels_enabled; 431e8ae9b66SAlan Carew } 432e8ae9b66SAlan Carew 433e8ae9b66SAlan Carew int 434e8ae9b66SAlan Carew add_channels(const char *vm_name, unsigned *channel_list, 435e8ae9b66SAlan Carew unsigned len_channel_list) 436e8ae9b66SAlan Carew { 437e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 438e8ae9b66SAlan Carew struct channel_info *chan_info; 439e8ae9b66SAlan Carew char socket_path[PATH_MAX]; 440e8ae9b66SAlan Carew unsigned i; 441e8ae9b66SAlan Carew int num_channels_enabled = 0; 442e8ae9b66SAlan Carew 443e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 444e8ae9b66SAlan Carew if (vm_info == NULL) { 445e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 446e8ae9b66SAlan Carew "not found\n", vm_name); 447e8ae9b66SAlan Carew return 0; 448e8ae9b66SAlan Carew } 449e8ae9b66SAlan Carew 450e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 451e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 452e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 453e8ae9b66SAlan Carew return 0; 454e8ae9b66SAlan Carew } 455e8ae9b66SAlan Carew 456e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 457e8ae9b66SAlan Carew 458e8ae9b66SAlan Carew if (channel_list[i] >= CHANNEL_CMDS_MAX_VM_CHANNELS) { 459e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel(%u) is out of range " 460e8ae9b66SAlan Carew "0...%d\n", channel_list[i], 461e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_VM_CHANNELS-1); 462e8ae9b66SAlan Carew continue; 463e8ae9b66SAlan Carew } 464e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 465e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel already exists, skipping " 466e8ae9b66SAlan Carew "'%s.%u'\n", vm_name, i); 467e8ae9b66SAlan Carew continue; 468e8ae9b66SAlan Carew } 469e8ae9b66SAlan Carew 470e8ae9b66SAlan Carew snprintf(socket_path, sizeof(socket_path), "%s%s.%u", 471e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 472e8ae9b66SAlan Carew errno = 0; 473e8ae9b66SAlan Carew if (access(socket_path, F_OK) < 0) { 474e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: " 475e8ae9b66SAlan Carew "%s\n", socket_path, strerror(errno)); 476e8ae9b66SAlan Carew continue; 477e8ae9b66SAlan Carew } 478e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 479fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 480e8ae9b66SAlan Carew if (chan_info == NULL) { 481e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 482e8ae9b66SAlan Carew "channel '%s'\n", socket_path); 483e8ae9b66SAlan Carew continue; 484e8ae9b66SAlan Carew } 485e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 486e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s.%u", 487e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 488e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) { 489e8ae9b66SAlan Carew rte_free(chan_info); 490e8ae9b66SAlan Carew continue; 491e8ae9b66SAlan Carew } 492e8ae9b66SAlan Carew num_channels_enabled++; 493e8ae9b66SAlan Carew 494e8ae9b66SAlan Carew } 495e8ae9b66SAlan Carew return num_channels_enabled; 496e8ae9b66SAlan Carew } 497e8ae9b66SAlan Carew 498e8ae9b66SAlan Carew int 499e8ae9b66SAlan Carew remove_channel(struct channel_info **chan_info_dptr) 500e8ae9b66SAlan Carew { 501e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 502e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 503e8ae9b66SAlan Carew 504e8ae9b66SAlan Carew close(chan_info->fd); 505e8ae9b66SAlan Carew 506e8ae9b66SAlan Carew vm_info = (struct virtual_machine_info *)chan_info->priv_info; 507e8ae9b66SAlan Carew 508e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 509e8ae9b66SAlan Carew vm_info->channel_mask &= ~(1ULL << chan_info->channel_num); 510e8ae9b66SAlan Carew vm_info->num_channels--; 511e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 512e8ae9b66SAlan Carew 513e8ae9b66SAlan Carew rte_free(chan_info); 514e8ae9b66SAlan Carew return 0; 515e8ae9b66SAlan Carew } 516e8ae9b66SAlan Carew 517e8ae9b66SAlan Carew int 518e8ae9b66SAlan Carew set_channel_status_all(const char *vm_name, enum channel_status status) 519e8ae9b66SAlan Carew { 520e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 521e8ae9b66SAlan Carew unsigned i; 522e8ae9b66SAlan Carew uint64_t mask; 523e8ae9b66SAlan Carew int num_channels_changed = 0; 524e8ae9b66SAlan Carew 525e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 526e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 527e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 528e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 529e8ae9b66SAlan Carew } 530e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 531e8ae9b66SAlan Carew if (vm_info == NULL) { 532e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to disable channels: VM '%s' " 533e8ae9b66SAlan Carew "not found\n", vm_name); 534e8ae9b66SAlan Carew return 0; 535e8ae9b66SAlan Carew } 536e8ae9b66SAlan Carew 537e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 538e8ae9b66SAlan Carew mask = vm_info->channel_mask; 539e8ae9b66SAlan Carew ITERATIVE_BITMASK_CHECK_64(mask, i) { 540e8ae9b66SAlan Carew vm_info->channels[i]->status = status; 541e8ae9b66SAlan Carew num_channels_changed++; 542e8ae9b66SAlan Carew } 543e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 544e8ae9b66SAlan Carew return num_channels_changed; 545e8ae9b66SAlan Carew 546e8ae9b66SAlan Carew } 547e8ae9b66SAlan Carew 548e8ae9b66SAlan Carew int 549e8ae9b66SAlan Carew set_channel_status(const char *vm_name, unsigned *channel_list, 550e8ae9b66SAlan Carew unsigned len_channel_list, enum channel_status status) 551e8ae9b66SAlan Carew { 552e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 553e8ae9b66SAlan Carew unsigned i; 554e8ae9b66SAlan Carew int num_channels_changed = 0; 555e8ae9b66SAlan Carew 556e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 557e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 558e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 559e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 560e8ae9b66SAlan Carew } 561e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 562e8ae9b66SAlan Carew if (vm_info == NULL) { 563e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 564e8ae9b66SAlan Carew "not found\n", vm_name); 565e8ae9b66SAlan Carew return 0; 566e8ae9b66SAlan Carew } 567e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 568e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 569e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 570e8ae9b66SAlan Carew vm_info->channels[channel_list[i]]->status = status; 571e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 572e8ae9b66SAlan Carew num_channels_changed++; 573e8ae9b66SAlan Carew } 574e8ae9b66SAlan Carew } 575e8ae9b66SAlan Carew return num_channels_changed; 576e8ae9b66SAlan Carew } 577e8ae9b66SAlan Carew 578e8ae9b66SAlan Carew int 579e8ae9b66SAlan Carew get_info_vm(const char *vm_name, struct vm_info *info) 580e8ae9b66SAlan Carew { 581e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 582e8ae9b66SAlan Carew unsigned i, channel_num = 0; 583e8ae9b66SAlan Carew uint64_t mask; 584e8ae9b66SAlan Carew 585e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 586e8ae9b66SAlan Carew if (vm_info == NULL) { 587e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 588e8ae9b66SAlan Carew return -1; 589e8ae9b66SAlan Carew } 590e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_ACTIVE; 591e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) 592e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_INACTIVE; 593e8ae9b66SAlan Carew 594e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 595e8ae9b66SAlan Carew 596e8ae9b66SAlan Carew mask = vm_info->channel_mask; 597e8ae9b66SAlan Carew ITERATIVE_BITMASK_CHECK_64(mask, i) { 598e8ae9b66SAlan Carew info->channels[channel_num].channel_num = i; 599e8ae9b66SAlan Carew memcpy(info->channels[channel_num].channel_path, 600*0d74597cSBruce Richardson vm_info->channels[i]->channel_path, UNIX_PATH_MAX); 601e8ae9b66SAlan Carew info->channels[channel_num].status = vm_info->channels[i]->status; 602e8ae9b66SAlan Carew info->channels[channel_num].fd = vm_info->channels[i]->fd; 603e8ae9b66SAlan Carew channel_num++; 604e8ae9b66SAlan Carew } 605e8ae9b66SAlan Carew 606e8ae9b66SAlan Carew info->num_channels = channel_num; 607e8ae9b66SAlan Carew info->num_vcpus = vm_info->info.nrVirtCpu; 608e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 609e8ae9b66SAlan Carew 610e8ae9b66SAlan Carew memcpy(info->name, vm_info->name, sizeof(vm_info->name)); 611e8ae9b66SAlan Carew for (i = 0; i < info->num_vcpus; i++) { 612e8ae9b66SAlan Carew info->pcpu_mask[i] = rte_atomic64_read(&vm_info->pcpu_mask[i]); 613e8ae9b66SAlan Carew } 614e8ae9b66SAlan Carew return 0; 615e8ae9b66SAlan Carew } 616e8ae9b66SAlan Carew 617e8ae9b66SAlan Carew int 618e8ae9b66SAlan Carew add_vm(const char *vm_name) 619e8ae9b66SAlan Carew { 620e8ae9b66SAlan Carew struct virtual_machine_info *new_domain; 621e8ae9b66SAlan Carew virDomainPtr dom_ptr; 622e8ae9b66SAlan Carew int i; 623e8ae9b66SAlan Carew 624e8ae9b66SAlan Carew if (find_domain_by_name(vm_name) != NULL) { 625e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add VM: VM '%s' " 626e8ae9b66SAlan Carew "already exists\n", vm_name); 627e8ae9b66SAlan Carew return -1; 628e8ae9b66SAlan Carew } 629e8ae9b66SAlan Carew 630e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 631e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "No connection to hypervisor exists\n"); 632e8ae9b66SAlan Carew return -1; 633e8ae9b66SAlan Carew } 634e8ae9b66SAlan Carew dom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name); 635e8ae9b66SAlan Carew if (dom_ptr == NULL) { 636e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error on VM lookup with libvirt: " 637e8ae9b66SAlan Carew "VM '%s' not found\n", vm_name); 638e8ae9b66SAlan Carew return -1; 639e8ae9b66SAlan Carew } 640e8ae9b66SAlan Carew 641e8ae9b66SAlan Carew new_domain = rte_malloc("virtual_machine_info", sizeof(*new_domain), 642fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 643e8ae9b66SAlan Carew if (new_domain == NULL) { 644e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to allocate memory for VM " 645e8ae9b66SAlan Carew "info\n"); 646e8ae9b66SAlan Carew return -1; 647e8ae9b66SAlan Carew } 648e8ae9b66SAlan Carew new_domain->domainPtr = dom_ptr; 649e8ae9b66SAlan Carew if (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) { 650e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get libvirt VM info\n"); 651e8ae9b66SAlan Carew rte_free(new_domain); 652e8ae9b66SAlan Carew return -1; 653e8ae9b66SAlan Carew } 654e8ae9b66SAlan Carew if (new_domain->info.nrVirtCpu > CHANNEL_CMDS_MAX_CPUS) { 655e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error the number of virtual CPUs(%u) is " 656e8ae9b66SAlan Carew "greater than allowable(%d)\n", new_domain->info.nrVirtCpu, 657e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_CPUS); 658e8ae9b66SAlan Carew rte_free(new_domain); 659e8ae9b66SAlan Carew return -1; 660e8ae9b66SAlan Carew } 661e8ae9b66SAlan Carew 662e8ae9b66SAlan Carew for (i = 0; i < CHANNEL_CMDS_MAX_CPUS; i++) { 663e8ae9b66SAlan Carew rte_atomic64_init(&new_domain->pcpu_mask[i]); 664e8ae9b66SAlan Carew } 665e8ae9b66SAlan Carew if (update_pcpus_mask(new_domain) < 0) { 666e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting physical CPU pinning\n"); 667e8ae9b66SAlan Carew rte_free(new_domain); 668e8ae9b66SAlan Carew return -1; 669e8ae9b66SAlan Carew } 670e8ae9b66SAlan Carew strncpy(new_domain->name, vm_name, sizeof(new_domain->name)); 671e8ae9b66SAlan Carew new_domain->channel_mask = 0; 672e8ae9b66SAlan Carew new_domain->num_channels = 0; 673e8ae9b66SAlan Carew 674e8ae9b66SAlan Carew if (!virDomainIsActive(dom_ptr)) 675e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_INACTIVE; 676e8ae9b66SAlan Carew else 677e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_ACTIVE; 678e8ae9b66SAlan Carew 679e8ae9b66SAlan Carew rte_spinlock_init(&(new_domain->config_spinlock)); 680e8ae9b66SAlan Carew LIST_INSERT_HEAD(&vm_list_head, new_domain, vms_info); 681e8ae9b66SAlan Carew return 0; 682e8ae9b66SAlan Carew } 683e8ae9b66SAlan Carew 684e8ae9b66SAlan Carew int 685e8ae9b66SAlan Carew remove_vm(const char *vm_name) 686e8ae9b66SAlan Carew { 687e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = find_domain_by_name(vm_name); 688e8ae9b66SAlan Carew 689e8ae9b66SAlan Carew if (vm_info == NULL) { 690e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM: VM '%s' " 691e8ae9b66SAlan Carew "not found\n", vm_name); 692e8ae9b66SAlan Carew return -1; 693e8ae9b66SAlan Carew } 694e8ae9b66SAlan Carew rte_spinlock_lock(&vm_info->config_spinlock); 695e8ae9b66SAlan Carew if (vm_info->num_channels != 0) { 696e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM '%s', there are " 697e8ae9b66SAlan Carew "%"PRId8" channels still active\n", 698e8ae9b66SAlan Carew vm_name, vm_info->num_channels); 699e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 700e8ae9b66SAlan Carew return -1; 701e8ae9b66SAlan Carew } 702e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 703e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 704e8ae9b66SAlan Carew rte_free(vm_info); 705e8ae9b66SAlan Carew return 0; 706e8ae9b66SAlan Carew } 707e8ae9b66SAlan Carew 708e8ae9b66SAlan Carew static void 709e8ae9b66SAlan Carew disconnect_hypervisor(void) 710e8ae9b66SAlan Carew { 711e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 712e8ae9b66SAlan Carew virConnectClose(global_vir_conn_ptr); 713e8ae9b66SAlan Carew global_vir_conn_ptr = NULL; 714e8ae9b66SAlan Carew } 715e8ae9b66SAlan Carew } 716e8ae9b66SAlan Carew 717e8ae9b66SAlan Carew static int 718e8ae9b66SAlan Carew connect_hypervisor(const char *path) 719e8ae9b66SAlan Carew { 720e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 721e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error connecting to %s, connection " 722e8ae9b66SAlan Carew "already established\n", path); 723e8ae9b66SAlan Carew return -1; 724e8ae9b66SAlan Carew } 725e8ae9b66SAlan Carew global_vir_conn_ptr = virConnectOpen(path); 726e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 727e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error failed to open connection to " 728e8ae9b66SAlan Carew "Hypervisor '%s'\n", path); 729e8ae9b66SAlan Carew return -1; 730e8ae9b66SAlan Carew } 731e8ae9b66SAlan Carew return 0; 732e8ae9b66SAlan Carew } 733e8ae9b66SAlan Carew 734e8ae9b66SAlan Carew int 735e8ae9b66SAlan Carew channel_manager_init(const char *path) 736e8ae9b66SAlan Carew { 737e8ae9b66SAlan Carew int n_cpus; 738e8ae9b66SAlan Carew 739e8ae9b66SAlan Carew LIST_INIT(&vm_list_head); 740e8ae9b66SAlan Carew if (connect_hypervisor(path) < 0) { 741e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to initialize channel manager\n"); 742e8ae9b66SAlan Carew return -1; 743e8ae9b66SAlan Carew } 744e8ae9b66SAlan Carew 745e8ae9b66SAlan Carew global_maplen = VIR_CPU_MAPLEN(CHANNEL_CMDS_MAX_CPUS); 746e8ae9b66SAlan Carew 747e8ae9b66SAlan Carew global_vircpuinfo = rte_zmalloc(NULL, sizeof(*global_vircpuinfo) * 748fdf20fa7SSergio Gonzalez Monroy CHANNEL_CMDS_MAX_CPUS, RTE_CACHE_LINE_SIZE); 749e8ae9b66SAlan Carew if (global_vircpuinfo == NULL) { 750e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for CPU Info\n"); 751e8ae9b66SAlan Carew goto error; 752e8ae9b66SAlan Carew } 753e8ae9b66SAlan Carew global_cpumaps = rte_zmalloc(NULL, CHANNEL_CMDS_MAX_CPUS * global_maplen, 754fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 755e8ae9b66SAlan Carew if (global_cpumaps == NULL) { 756e8ae9b66SAlan Carew goto error; 757e8ae9b66SAlan Carew } 758e8ae9b66SAlan Carew 759e8ae9b66SAlan Carew n_cpus = virNodeGetCPUMap(global_vir_conn_ptr, NULL, NULL, 0); 760e8ae9b66SAlan Carew if (n_cpus <= 0) { 761e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get the number of Host " 762e8ae9b66SAlan Carew "CPUs\n"); 763e8ae9b66SAlan Carew goto error; 764e8ae9b66SAlan Carew } 765e8ae9b66SAlan Carew global_n_host_cpus = (unsigned)n_cpus; 766e8ae9b66SAlan Carew 767e8ae9b66SAlan Carew if (global_n_host_cpus > CHANNEL_CMDS_MAX_CPUS) { 768e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "The number of host CPUs(%u) exceeds the " 769e8ae9b66SAlan Carew "maximum of %u\n", global_n_host_cpus, CHANNEL_CMDS_MAX_CPUS); 770e8ae9b66SAlan Carew goto error; 771e8ae9b66SAlan Carew 772e8ae9b66SAlan Carew } 773e8ae9b66SAlan Carew 774e8ae9b66SAlan Carew return 0; 775e8ae9b66SAlan Carew error: 776e8ae9b66SAlan Carew disconnect_hypervisor(); 777e8ae9b66SAlan Carew return -1; 778e8ae9b66SAlan Carew } 779e8ae9b66SAlan Carew 780e8ae9b66SAlan Carew void 781e8ae9b66SAlan Carew channel_manager_exit(void) 782e8ae9b66SAlan Carew { 783e8ae9b66SAlan Carew unsigned i; 784e8ae9b66SAlan Carew uint64_t mask; 785e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 786e8ae9b66SAlan Carew 787e8ae9b66SAlan Carew LIST_FOREACH(vm_info, &vm_list_head, vms_info) { 788e8ae9b66SAlan Carew 789e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 790e8ae9b66SAlan Carew 791e8ae9b66SAlan Carew mask = vm_info->channel_mask; 792e8ae9b66SAlan Carew ITERATIVE_BITMASK_CHECK_64(mask, i) { 793e8ae9b66SAlan Carew remove_channel_from_monitor(vm_info->channels[i]); 794e8ae9b66SAlan Carew close(vm_info->channels[i]->fd); 795e8ae9b66SAlan Carew rte_free(vm_info->channels[i]); 796e8ae9b66SAlan Carew } 797e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 798e8ae9b66SAlan Carew 799e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 800e8ae9b66SAlan Carew rte_free(vm_info); 801e8ae9b66SAlan Carew } 802e8ae9b66SAlan Carew 803e8ae9b66SAlan Carew if (global_cpumaps != NULL) 804e8ae9b66SAlan Carew rte_free(global_cpumaps); 805e8ae9b66SAlan Carew if (global_vircpuinfo != NULL) 806e8ae9b66SAlan Carew rte_free(global_vircpuinfo); 807e8ae9b66SAlan Carew disconnect_hypervisor(); 808e8ae9b66SAlan Carew } 809