13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 3e8ae9b66SAlan Carew */ 4e8ae9b66SAlan Carew 5e8ae9b66SAlan Carew #include <stdio.h> 6e8ae9b66SAlan Carew #include <stdlib.h> 7e8ae9b66SAlan Carew #include <sys/un.h> 8e8ae9b66SAlan Carew #include <fcntl.h> 9e8ae9b66SAlan Carew #include <unistd.h> 10e8ae9b66SAlan Carew #include <inttypes.h> 11e8ae9b66SAlan Carew #include <dirent.h> 12e8ae9b66SAlan Carew #include <errno.h> 13e8ae9b66SAlan Carew 14e8ae9b66SAlan Carew #include <sys/queue.h> 15e8ae9b66SAlan Carew #include <sys/types.h> 163618326fSDavid Hunt #include <sys/stat.h> 17e8ae9b66SAlan Carew #include <sys/socket.h> 18e8ae9b66SAlan Carew #include <sys/select.h> 19e8ae9b66SAlan Carew 206723c0fcSBruce Richardson #include <rte_string_fns.h> 21e8ae9b66SAlan Carew #include <rte_malloc.h> 22e8ae9b66SAlan Carew #include <rte_memory.h> 23e8ae9b66SAlan Carew #include <rte_mempool.h> 24e8ae9b66SAlan Carew #include <rte_log.h> 25e8ae9b66SAlan Carew #include <rte_atomic.h> 26e8ae9b66SAlan Carew #include <rte_spinlock.h> 27e8ae9b66SAlan Carew 28e8ae9b66SAlan Carew #include <libvirt/libvirt.h> 29e8ae9b66SAlan Carew 30e8ae9b66SAlan Carew #include "channel_manager.h" 31e8ae9b66SAlan Carew #include "channel_commands.h" 32e8ae9b66SAlan Carew #include "channel_monitor.h" 33fd73630eSDavid Hunt #include "power_manager.h" 34e8ae9b66SAlan Carew 35e8ae9b66SAlan Carew 36e8ae9b66SAlan Carew #define RTE_LOGTYPE_CHANNEL_MANAGER RTE_LOGTYPE_USER1 37e8ae9b66SAlan Carew 38e8ae9b66SAlan Carew /* Global pointer to libvirt connection */ 39e8ae9b66SAlan Carew static virConnectPtr global_vir_conn_ptr; 40e8ae9b66SAlan Carew 41e8ae9b66SAlan Carew static unsigned char *global_cpumaps; 42e8ae9b66SAlan Carew static virVcpuInfo *global_vircpuinfo; 43e8ae9b66SAlan Carew static size_t global_maplen; 44e8ae9b66SAlan Carew 45e0207366SDavid Hunt static unsigned int global_n_host_cpus; 46e0207366SDavid Hunt static bool global_hypervisor_available; 47e8ae9b66SAlan Carew 48e8ae9b66SAlan Carew /* 49e8ae9b66SAlan Carew * Represents a single Virtual Machine 50e8ae9b66SAlan Carew */ 51e8ae9b66SAlan Carew struct virtual_machine_info { 52e8ae9b66SAlan Carew char name[CHANNEL_MGR_MAX_NAME_LEN]; 53751227a0SDavid Hunt uint16_t pcpu_map[RTE_MAX_LCORE]; 54751227a0SDavid Hunt struct channel_info *channels[RTE_MAX_LCORE]; 55751227a0SDavid Hunt char channel_mask[RTE_MAX_LCORE]; 56e8ae9b66SAlan Carew uint8_t num_channels; 57e8ae9b66SAlan Carew enum vm_status status; 58e8ae9b66SAlan Carew virDomainPtr domainPtr; 59e8ae9b66SAlan Carew virDomainInfo info; 60e8ae9b66SAlan Carew rte_spinlock_t config_spinlock; 61e8ae9b66SAlan Carew LIST_ENTRY(virtual_machine_info) vms_info; 62e8ae9b66SAlan Carew }; 63e8ae9b66SAlan Carew 64e8ae9b66SAlan Carew LIST_HEAD(, virtual_machine_info) vm_list_head; 65e8ae9b66SAlan Carew 66e8ae9b66SAlan Carew static struct virtual_machine_info * 67e8ae9b66SAlan Carew find_domain_by_name(const char *name) 68e8ae9b66SAlan Carew { 69e8ae9b66SAlan Carew struct virtual_machine_info *info; 70e8ae9b66SAlan Carew LIST_FOREACH(info, &vm_list_head, vms_info) { 71e8ae9b66SAlan Carew if (!strncmp(info->name, name, CHANNEL_MGR_MAX_NAME_LEN-1)) 72e8ae9b66SAlan Carew return info; 73e8ae9b66SAlan Carew } 74e8ae9b66SAlan Carew return NULL; 75e8ae9b66SAlan Carew } 76e8ae9b66SAlan Carew 77e8ae9b66SAlan Carew static int 78e8ae9b66SAlan Carew update_pcpus_mask(struct virtual_machine_info *vm_info) 79e8ae9b66SAlan Carew { 80e8ae9b66SAlan Carew virVcpuInfoPtr cpuinfo; 81e8ae9b66SAlan Carew unsigned i, j; 82e8ae9b66SAlan Carew int n_vcpus; 83e8ae9b66SAlan Carew 84751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE*global_maplen); 85e8ae9b66SAlan Carew 86e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 87e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpuPinInfo(vm_info->domainPtr, 88e8ae9b66SAlan Carew vm_info->info.nrVirtCpu, global_cpumaps, global_maplen, 89e8ae9b66SAlan Carew VIR_DOMAIN_AFFECT_CONFIG); 90e8ae9b66SAlan Carew if (n_vcpus < 0) { 91e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for " 92e8ae9b66SAlan Carew "in-active VM '%s'\n", vm_info->name); 93e8ae9b66SAlan Carew return -1; 94e8ae9b66SAlan Carew } 95e8ae9b66SAlan Carew goto update_pcpus; 96e8ae9b66SAlan Carew } 97e8ae9b66SAlan Carew 98e8ae9b66SAlan Carew memset(global_vircpuinfo, 0, sizeof(*global_vircpuinfo)* 99751227a0SDavid Hunt RTE_MAX_LCORE); 100e8ae9b66SAlan Carew 101e8ae9b66SAlan Carew cpuinfo = global_vircpuinfo; 102e8ae9b66SAlan Carew 103e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo, 104751227a0SDavid Hunt RTE_MAX_LCORE, global_cpumaps, global_maplen); 105e8ae9b66SAlan Carew if (n_vcpus < 0) { 106e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for " 107e8ae9b66SAlan Carew "active VM '%s'\n", vm_info->name); 108e8ae9b66SAlan Carew return -1; 109e8ae9b66SAlan Carew } 110e8ae9b66SAlan Carew update_pcpus: 111751227a0SDavid Hunt if (n_vcpus >= RTE_MAX_LCORE) { 112e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Number of vCPUS(%u) is out of range " 113751227a0SDavid Hunt "0...%d\n", n_vcpus, RTE_MAX_LCORE-1); 114e8ae9b66SAlan Carew return -1; 115e8ae9b66SAlan Carew } 116e8ae9b66SAlan Carew if (n_vcpus != vm_info->info.nrVirtCpu) { 117e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Updating the number of vCPUs for VM '%s" 118e8ae9b66SAlan Carew " from %d -> %d\n", vm_info->name, vm_info->info.nrVirtCpu, 119e8ae9b66SAlan Carew n_vcpus); 120e8ae9b66SAlan Carew vm_info->info.nrVirtCpu = n_vcpus; 121e8ae9b66SAlan Carew } 1225776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 123e8ae9b66SAlan Carew for (i = 0; i < vm_info->info.nrVirtCpu; i++) { 124e8ae9b66SAlan Carew for (j = 0; j < global_n_host_cpus; j++) { 1255776b7a3SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps, 1265776b7a3SDavid Hunt global_maplen, i, j) <= 0) 1275776b7a3SDavid Hunt continue; 1285776b7a3SDavid Hunt vm_info->pcpu_map[i] = j; 129e8ae9b66SAlan Carew } 130e8ae9b66SAlan Carew } 1315776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 132e8ae9b66SAlan Carew return 0; 133e8ae9b66SAlan Carew } 134e8ae9b66SAlan Carew 135e8ae9b66SAlan Carew int 1365776b7a3SDavid Hunt set_pcpu(char *vm_name, unsigned int vcpu, unsigned int pcpu) 137e8ae9b66SAlan Carew { 138e8ae9b66SAlan Carew int flags = VIR_DOMAIN_AFFECT_LIVE|VIR_DOMAIN_AFFECT_CONFIG; 139e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 140e8ae9b66SAlan Carew 141751227a0SDavid Hunt if (vcpu >= RTE_MAX_LCORE) { 142e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds max allowable(%d)\n", 143751227a0SDavid Hunt vcpu, RTE_MAX_LCORE-1); 144e8ae9b66SAlan Carew return -1; 145e8ae9b66SAlan Carew } 146e8ae9b66SAlan Carew 147e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 148e8ae9b66SAlan Carew if (vm_info == NULL) { 149e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 150e8ae9b66SAlan Carew return -1; 151e8ae9b66SAlan Carew } 152e8ae9b66SAlan Carew 153e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 154e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU " 155fd73630eSDavid Hunt " for VM '%s', VM is not active\n", 156fd73630eSDavid Hunt vcpu, vm_info->name); 157e8ae9b66SAlan Carew return -1; 158e8ae9b66SAlan Carew } 159e8ae9b66SAlan Carew 160e8ae9b66SAlan Carew if (vcpu >= vm_info->info.nrVirtCpu) { 161e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds the assigned number of " 162e8ae9b66SAlan Carew "vCPUs(%u)\n", vcpu, vm_info->info.nrVirtCpu); 163e8ae9b66SAlan Carew return -1; 164e8ae9b66SAlan Carew } 165751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE * global_maplen); 1665776b7a3SDavid Hunt 1675776b7a3SDavid Hunt VIR_USE_CPU(global_cpumaps, pcpu); 1685776b7a3SDavid Hunt 1695776b7a3SDavid Hunt if (pcpu >= global_n_host_cpus) { 170e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "CPU(%u) exceeds the available " 171fd73630eSDavid Hunt "number of CPUs(%u)\n", 1725776b7a3SDavid Hunt pcpu, global_n_host_cpus); 173e8ae9b66SAlan Carew return -1; 174e8ae9b66SAlan Carew } 1755776b7a3SDavid Hunt 176e8ae9b66SAlan Carew if (virDomainPinVcpuFlags(vm_info->domainPtr, vcpu, global_cpumaps, 177e8ae9b66SAlan Carew global_maplen, flags) < 0) { 178e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU " 179fd73630eSDavid Hunt " for VM '%s'\n", vcpu, 180e8ae9b66SAlan Carew vm_info->name); 181e8ae9b66SAlan Carew return -1; 182e8ae9b66SAlan Carew } 183fd73630eSDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 1845776b7a3SDavid Hunt vm_info->pcpu_map[vcpu] = pcpu; 185fd73630eSDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 186e8ae9b66SAlan Carew return 0; 187e8ae9b66SAlan Carew } 188e8ae9b66SAlan Carew 1895776b7a3SDavid Hunt uint16_t 1905776b7a3SDavid Hunt get_pcpu(struct channel_info *chan_info, unsigned int vcpu) 191e8ae9b66SAlan Carew { 192e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = 193e8ae9b66SAlan Carew (struct virtual_machine_info *)chan_info->priv_info; 194e0207366SDavid Hunt 1955776b7a3SDavid Hunt if (global_hypervisor_available && (vm_info != NULL)) { 1965776b7a3SDavid Hunt uint16_t pcpu; 1975776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 1985776b7a3SDavid Hunt pcpu = vm_info->pcpu_map[vcpu]; 1995776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 2005776b7a3SDavid Hunt return pcpu; 2015776b7a3SDavid Hunt } else 202e0207366SDavid Hunt return 0; 203e8ae9b66SAlan Carew } 204e8ae9b66SAlan Carew 205e8ae9b66SAlan Carew static inline int 206e8ae9b66SAlan Carew channel_exists(struct virtual_machine_info *vm_info, unsigned channel_num) 207e8ae9b66SAlan Carew { 208e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 209fd73630eSDavid Hunt if (vm_info->channel_mask[channel_num] == 1) { 210e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 211e8ae9b66SAlan Carew return 1; 212e8ae9b66SAlan Carew } 213e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 214e8ae9b66SAlan Carew return 0; 215e8ae9b66SAlan Carew } 216e8ae9b66SAlan Carew 217e8ae9b66SAlan Carew 218e8ae9b66SAlan Carew 219e8ae9b66SAlan Carew static int 220e8ae9b66SAlan Carew open_non_blocking_channel(struct channel_info *info) 221e8ae9b66SAlan Carew { 222e8ae9b66SAlan Carew int ret, flags; 223e8ae9b66SAlan Carew struct sockaddr_un sock_addr; 224e8ae9b66SAlan Carew fd_set soc_fd_set; 225e8ae9b66SAlan Carew struct timeval tv; 226e8ae9b66SAlan Carew 227e8ae9b66SAlan Carew info->fd = socket(AF_UNIX, SOCK_STREAM, 0); 2281b897991SLukasz Krakowiak if (info->fd < 0) { 229e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) creating socket for '%s'\n", 230e8ae9b66SAlan Carew strerror(errno), 231e8ae9b66SAlan Carew info->channel_path); 232e8ae9b66SAlan Carew return -1; 233e8ae9b66SAlan Carew } 234e8ae9b66SAlan Carew sock_addr.sun_family = AF_UNIX; 235e8ae9b66SAlan Carew memcpy(&sock_addr.sun_path, info->channel_path, 236e8ae9b66SAlan Carew strlen(info->channel_path)+1); 237e8ae9b66SAlan Carew 238e8ae9b66SAlan Carew /* Get current flags */ 239e8ae9b66SAlan Carew flags = fcntl(info->fd, F_GETFL, 0); 240e8ae9b66SAlan Carew if (flags < 0) { 241e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for" 242e8ae9b66SAlan Carew "'%s'\n", strerror(errno), info->channel_path); 243e8ae9b66SAlan Carew return 1; 244e8ae9b66SAlan Carew } 245e8ae9b66SAlan Carew /* Set to Non Blocking */ 246e8ae9b66SAlan Carew flags |= O_NONBLOCK; 247e8ae9b66SAlan Carew if (fcntl(info->fd, F_SETFL, flags) < 0) { 248e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) setting non-blocking " 249e8ae9b66SAlan Carew "socket for '%s'\n", strerror(errno), info->channel_path); 250e8ae9b66SAlan Carew return -1; 251e8ae9b66SAlan Carew } 252e8ae9b66SAlan Carew ret = connect(info->fd, (struct sockaddr *)&sock_addr, 253e8ae9b66SAlan Carew sizeof(sock_addr)); 254e8ae9b66SAlan Carew if (ret < 0) { 255e8ae9b66SAlan Carew /* ECONNREFUSED error is given when VM is not active */ 256e8ae9b66SAlan Carew if (errno == ECONNREFUSED) { 257e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "VM is not active or has not " 258e8ae9b66SAlan Carew "activated its endpoint to channel %s\n", 259e8ae9b66SAlan Carew info->channel_path); 260e8ae9b66SAlan Carew return -1; 261e8ae9b66SAlan Carew } 262e8ae9b66SAlan Carew /* Wait for tv_sec if in progress */ 263e8ae9b66SAlan Carew else if (errno == EINPROGRESS) { 264e8ae9b66SAlan Carew tv.tv_sec = 2; 265e8ae9b66SAlan Carew tv.tv_usec = 0; 266e8ae9b66SAlan Carew FD_ZERO(&soc_fd_set); 267e8ae9b66SAlan Carew FD_SET(info->fd, &soc_fd_set); 268e8ae9b66SAlan Carew if (select(info->fd+1, NULL, &soc_fd_set, NULL, &tv) > 0) { 269e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Timeout or error on channel " 270e8ae9b66SAlan Carew "'%s'\n", info->channel_path); 271e8ae9b66SAlan Carew return -1; 272e8ae9b66SAlan Carew } 273e8ae9b66SAlan Carew } else { 274e8ae9b66SAlan Carew /* Any other error */ 275e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) connecting socket" 276e8ae9b66SAlan Carew " for '%s'\n", strerror(errno), info->channel_path); 277e8ae9b66SAlan Carew return -1; 278e8ae9b66SAlan Carew } 279e8ae9b66SAlan Carew } 280e8ae9b66SAlan Carew return 0; 281e8ae9b66SAlan Carew } 282e8ae9b66SAlan Carew 283e8ae9b66SAlan Carew static int 2843618326fSDavid Hunt open_host_channel(struct channel_info *info) 2853618326fSDavid Hunt { 2863618326fSDavid Hunt int flags; 2873618326fSDavid Hunt 2883618326fSDavid Hunt info->fd = open(info->channel_path, O_RDWR | O_RSYNC); 2891b897991SLukasz Krakowiak if (info->fd < 0) { 2903618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) opening fifo for '%s'\n", 2913618326fSDavid Hunt strerror(errno), 2923618326fSDavid Hunt info->channel_path); 2933618326fSDavid Hunt return -1; 2943618326fSDavid Hunt } 2953618326fSDavid Hunt 2963618326fSDavid Hunt /* Get current flags */ 2973618326fSDavid Hunt flags = fcntl(info->fd, F_GETFL, 0); 2983618326fSDavid Hunt if (flags < 0) { 2993618326fSDavid Hunt RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for" 3003618326fSDavid Hunt "'%s'\n", strerror(errno), info->channel_path); 3013618326fSDavid Hunt return 1; 3023618326fSDavid Hunt } 3033618326fSDavid Hunt /* Set to Non Blocking */ 3043618326fSDavid Hunt flags |= O_NONBLOCK; 3053618326fSDavid Hunt if (fcntl(info->fd, F_SETFL, flags) < 0) { 3063618326fSDavid Hunt RTE_LOG(WARNING, CHANNEL_MANAGER, 3073618326fSDavid Hunt "Error(%s) setting non-blocking " 3083618326fSDavid Hunt "socket for '%s'\n", 3093618326fSDavid Hunt strerror(errno), info->channel_path); 3103618326fSDavid Hunt return -1; 3113618326fSDavid Hunt } 3123618326fSDavid Hunt return 0; 3133618326fSDavid Hunt } 3143618326fSDavid Hunt 3153618326fSDavid Hunt static int 316e8ae9b66SAlan Carew setup_channel_info(struct virtual_machine_info **vm_info_dptr, 317e8ae9b66SAlan Carew struct channel_info **chan_info_dptr, unsigned channel_num) 318e8ae9b66SAlan Carew { 319e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 320e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = *vm_info_dptr; 321e8ae9b66SAlan Carew 322e8ae9b66SAlan Carew chan_info->channel_num = channel_num; 323e8ae9b66SAlan Carew chan_info->priv_info = (void *)vm_info; 324e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED; 3253618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_BINARY; 326e8ae9b66SAlan Carew if (open_non_blocking_channel(chan_info) < 0) { 327e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open channel: " 328e8ae9b66SAlan Carew "'%s' for VM '%s'\n", 329e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name); 330e8ae9b66SAlan Carew return -1; 331e8ae9b66SAlan Carew } 332e8ae9b66SAlan Carew if (add_channel_to_monitor(&chan_info) < 0) { 333e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: " 334e8ae9b66SAlan Carew "'%s' to epoll ctl for VM '%s'\n", 335e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name); 336e8ae9b66SAlan Carew return -1; 337e8ae9b66SAlan Carew 338e8ae9b66SAlan Carew } 339e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 340e8ae9b66SAlan Carew vm_info->num_channels++; 341fd73630eSDavid Hunt vm_info->channel_mask[channel_num] = 1; 342e8ae9b66SAlan Carew vm_info->channels[channel_num] = chan_info; 343e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED; 344e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 345e8ae9b66SAlan Carew return 0; 346e8ae9b66SAlan Carew } 347e8ae9b66SAlan Carew 348*221e7026SMarcin Hajkowski static int 349*221e7026SMarcin Hajkowski fifo_path(char *dst, unsigned int len, unsigned int id) 3503618326fSDavid Hunt { 351*221e7026SMarcin Hajkowski int cnt; 352*221e7026SMarcin Hajkowski 353*221e7026SMarcin Hajkowski cnt = snprintf(dst, len, "%s%s%d", CHANNEL_MGR_SOCKET_PATH, 354*221e7026SMarcin Hajkowski CHANNEL_MGR_FIFO_PATTERN_NAME, id); 355*221e7026SMarcin Hajkowski 356*221e7026SMarcin Hajkowski if ((cnt < 0) || (cnt > (int)len - 1)) { 357*221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Could not create proper " 358*221e7026SMarcin Hajkowski "string for fifo path\n"); 359*221e7026SMarcin Hajkowski 360*221e7026SMarcin Hajkowski return -1; 361*221e7026SMarcin Hajkowski } 362*221e7026SMarcin Hajkowski 363*221e7026SMarcin Hajkowski return 0; 3643618326fSDavid Hunt } 3653618326fSDavid Hunt 3663618326fSDavid Hunt static int 3673618326fSDavid Hunt setup_host_channel_info(struct channel_info **chan_info_dptr, 3683618326fSDavid Hunt unsigned int channel_num) 3693618326fSDavid Hunt { 3703618326fSDavid Hunt struct channel_info *chan_info = *chan_info_dptr; 3713618326fSDavid Hunt 3723618326fSDavid Hunt chan_info->channel_num = channel_num; 3733618326fSDavid Hunt chan_info->priv_info = (void *)NULL; 3743618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED; 3753618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_JSON; 3763618326fSDavid Hunt 3773618326fSDavid Hunt if (open_host_channel(chan_info) < 0) { 3783618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open host channel: " 3793618326fSDavid Hunt "'%s'\n", 3803618326fSDavid Hunt chan_info->channel_path); 3813618326fSDavid Hunt return -1; 3823618326fSDavid Hunt } 3833618326fSDavid Hunt if (add_channel_to_monitor(&chan_info) < 0) { 3843618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: " 3853618326fSDavid Hunt "'%s' to epoll ctl\n", 3863618326fSDavid Hunt chan_info->channel_path); 3873618326fSDavid Hunt return -1; 3883618326fSDavid Hunt 3893618326fSDavid Hunt } 3903618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED; 3913618326fSDavid Hunt return 0; 3923618326fSDavid Hunt } 3933618326fSDavid Hunt 394e8ae9b66SAlan Carew int 395e8ae9b66SAlan Carew add_all_channels(const char *vm_name) 396e8ae9b66SAlan Carew { 397e8ae9b66SAlan Carew DIR *d; 398e8ae9b66SAlan Carew struct dirent *dir; 399e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 400e8ae9b66SAlan Carew struct channel_info *chan_info; 401e8ae9b66SAlan Carew char *token, *remaining, *tail_ptr; 402e8ae9b66SAlan Carew char socket_name[PATH_MAX]; 403e8ae9b66SAlan Carew unsigned channel_num; 404e8ae9b66SAlan Carew int num_channels_enabled = 0; 405e8ae9b66SAlan Carew 406e8ae9b66SAlan Carew /* verify VM exists */ 407e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 408e8ae9b66SAlan Carew if (vm_info == NULL) { 409e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' not found" 410e8ae9b66SAlan Carew " during channel discovery\n", vm_name); 411e8ae9b66SAlan Carew return 0; 412e8ae9b66SAlan Carew } 413e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 414e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 415e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 416e8ae9b66SAlan Carew return 0; 417e8ae9b66SAlan Carew } 418e8ae9b66SAlan Carew d = opendir(CHANNEL_MGR_SOCKET_PATH); 419e8ae9b66SAlan Carew if (d == NULL) { 420e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error opening directory '%s': %s\n", 421e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, strerror(errno)); 422e8ae9b66SAlan Carew return -1; 423e8ae9b66SAlan Carew } 424e8ae9b66SAlan Carew while ((dir = readdir(d)) != NULL) { 425e8ae9b66SAlan Carew if (!strncmp(dir->d_name, ".", 1) || 426e8ae9b66SAlan Carew !strncmp(dir->d_name, "..", 2)) 427e8ae9b66SAlan Carew continue; 428e8ae9b66SAlan Carew 4296723c0fcSBruce Richardson strlcpy(socket_name, dir->d_name, sizeof(socket_name)); 430e8ae9b66SAlan Carew remaining = socket_name; 431e8ae9b66SAlan Carew /* Extract vm_name from "<vm_name>.<channel_num>" */ 432e8ae9b66SAlan Carew token = strsep(&remaining, "."); 433e8ae9b66SAlan Carew if (remaining == NULL) 434e8ae9b66SAlan Carew continue; 435e8ae9b66SAlan Carew if (strncmp(vm_name, token, CHANNEL_MGR_MAX_NAME_LEN)) 436e8ae9b66SAlan Carew continue; 437e8ae9b66SAlan Carew 438e8ae9b66SAlan Carew /* remaining should contain only <channel_num> */ 439e8ae9b66SAlan Carew errno = 0; 440e8ae9b66SAlan Carew channel_num = (unsigned)strtol(remaining, &tail_ptr, 0); 441e8ae9b66SAlan Carew if ((errno != 0) || (remaining[0] == '\0') || 4425b628fe1SBruce Richardson tail_ptr == NULL || (*tail_ptr != '\0')) { 443e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Malformed channel name" 444e8ae9b66SAlan Carew "'%s' found it should be in the form of " 445e8ae9b66SAlan Carew "'<guest_name>.<channel_num>(decimal)'\n", 446e8ae9b66SAlan Carew dir->d_name); 447e8ae9b66SAlan Carew continue; 448e8ae9b66SAlan Carew } 449751227a0SDavid Hunt if (channel_num >= RTE_MAX_LCORE) { 450e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Channel number(%u) is " 451e8ae9b66SAlan Carew "greater than max allowable: %d, skipping '%s%s'\n", 452751227a0SDavid Hunt channel_num, RTE_MAX_LCORE-1, 453e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 454e8ae9b66SAlan Carew continue; 455e8ae9b66SAlan Carew } 456e8ae9b66SAlan Carew /* if channel has not been added previously */ 457e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_num)) 458e8ae9b66SAlan Carew continue; 459e8ae9b66SAlan Carew 460e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 461fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 462e8ae9b66SAlan Carew if (chan_info == NULL) { 463e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 464e8ae9b66SAlan Carew "channel '%s%s'\n", CHANNEL_MGR_SOCKET_PATH, dir->d_name); 465e8ae9b66SAlan Carew continue; 466e8ae9b66SAlan Carew } 467e8ae9b66SAlan Carew 468e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 469e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s", 470e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 471e8ae9b66SAlan Carew 472e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) { 473e8ae9b66SAlan Carew rte_free(chan_info); 474e8ae9b66SAlan Carew continue; 475e8ae9b66SAlan Carew } 476e8ae9b66SAlan Carew 477e8ae9b66SAlan Carew num_channels_enabled++; 478e8ae9b66SAlan Carew } 479e8ae9b66SAlan Carew closedir(d); 480e8ae9b66SAlan Carew return num_channels_enabled; 481e8ae9b66SAlan Carew } 482e8ae9b66SAlan Carew 483e8ae9b66SAlan Carew int 484e8ae9b66SAlan Carew add_channels(const char *vm_name, unsigned *channel_list, 485e8ae9b66SAlan Carew unsigned len_channel_list) 486e8ae9b66SAlan Carew { 487e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 488e8ae9b66SAlan Carew struct channel_info *chan_info; 489e8ae9b66SAlan Carew char socket_path[PATH_MAX]; 490e8ae9b66SAlan Carew unsigned i; 491e8ae9b66SAlan Carew int num_channels_enabled = 0; 492e8ae9b66SAlan Carew 493e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 494e8ae9b66SAlan Carew if (vm_info == NULL) { 495e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 496e8ae9b66SAlan Carew "not found\n", vm_name); 497e8ae9b66SAlan Carew return 0; 498e8ae9b66SAlan Carew } 499e8ae9b66SAlan Carew 500e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 501e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 502e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 503e8ae9b66SAlan Carew return 0; 504e8ae9b66SAlan Carew } 505e8ae9b66SAlan Carew 506e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 507e8ae9b66SAlan Carew 508751227a0SDavid Hunt if (channel_list[i] >= RTE_MAX_LCORE) { 509e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel(%u) is out of range " 510e8ae9b66SAlan Carew "0...%d\n", channel_list[i], 511751227a0SDavid Hunt RTE_MAX_LCORE-1); 512e8ae9b66SAlan Carew continue; 513e8ae9b66SAlan Carew } 514e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 515e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel already exists, skipping " 516e8ae9b66SAlan Carew "'%s.%u'\n", vm_name, i); 517e8ae9b66SAlan Carew continue; 518e8ae9b66SAlan Carew } 519e8ae9b66SAlan Carew 520e8ae9b66SAlan Carew snprintf(socket_path, sizeof(socket_path), "%s%s.%u", 521e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 522e8ae9b66SAlan Carew errno = 0; 523e8ae9b66SAlan Carew if (access(socket_path, F_OK) < 0) { 524e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: " 525e8ae9b66SAlan Carew "%s\n", socket_path, strerror(errno)); 526e8ae9b66SAlan Carew continue; 527e8ae9b66SAlan Carew } 528e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 529fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 530e8ae9b66SAlan Carew if (chan_info == NULL) { 531e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 532e8ae9b66SAlan Carew "channel '%s'\n", socket_path); 533e8ae9b66SAlan Carew continue; 534e8ae9b66SAlan Carew } 535e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 536e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s.%u", 537e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 538e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) { 539e8ae9b66SAlan Carew rte_free(chan_info); 540e8ae9b66SAlan Carew continue; 541e8ae9b66SAlan Carew } 542e8ae9b66SAlan Carew num_channels_enabled++; 543e8ae9b66SAlan Carew 544e8ae9b66SAlan Carew } 545e8ae9b66SAlan Carew return num_channels_enabled; 546e8ae9b66SAlan Carew } 547e8ae9b66SAlan Carew 548e8ae9b66SAlan Carew int 549*221e7026SMarcin Hajkowski add_host_channels(void) 5503618326fSDavid Hunt { 5513618326fSDavid Hunt struct channel_info *chan_info; 5523618326fSDavid Hunt char socket_path[PATH_MAX]; 5533618326fSDavid Hunt int num_channels_enabled = 0; 5543618326fSDavid Hunt int ret; 555*221e7026SMarcin Hajkowski struct core_info *ci; 556*221e7026SMarcin Hajkowski struct channel_info *chan_infos[RTE_MAX_LCORE]; 557*221e7026SMarcin Hajkowski int i; 5583618326fSDavid Hunt 559*221e7026SMarcin Hajkowski for (i = 0; i < RTE_MAX_LCORE; i++) 560*221e7026SMarcin Hajkowski chan_infos[i] = NULL; 5613618326fSDavid Hunt 562*221e7026SMarcin Hajkowski ci = get_core_info(); 563*221e7026SMarcin Hajkowski if (ci == NULL) { 564*221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot allocate memory for core_info\n"); 5653618326fSDavid Hunt return 0; 5663618326fSDavid Hunt } 5673618326fSDavid Hunt 568*221e7026SMarcin Hajkowski for (i = 0; i < ci->core_count; i++) { 569*221e7026SMarcin Hajkowski if (ci->cd[i].global_enabled_cpus == 0) 570*221e7026SMarcin Hajkowski continue; 571*221e7026SMarcin Hajkowski 572*221e7026SMarcin Hajkowski ret = fifo_path(socket_path, sizeof(socket_path), i); 573*221e7026SMarcin Hajkowski if (ret < 0) 574*221e7026SMarcin Hajkowski goto error; 575*221e7026SMarcin Hajkowski 576*221e7026SMarcin Hajkowski ret = mkfifo(socket_path, 0660); 577*221e7026SMarcin Hajkowski RTE_LOG(DEBUG, CHANNEL_MANAGER, "TRY CREATE fifo '%s'\n", 578*221e7026SMarcin Hajkowski socket_path); 579*221e7026SMarcin Hajkowski if ((errno != EEXIST) && (ret < 0)) { 580*221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot create fifo '%s' error: " 5813618326fSDavid Hunt "%s\n", socket_path, strerror(errno)); 582*221e7026SMarcin Hajkowski goto error; 5833618326fSDavid Hunt } 5843618326fSDavid Hunt chan_info = rte_malloc(NULL, sizeof(*chan_info), 0); 5853618326fSDavid Hunt if (chan_info == NULL) { 5863618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 5873618326fSDavid Hunt "channel '%s'\n", socket_path); 588*221e7026SMarcin Hajkowski goto error; 5893618326fSDavid Hunt } 590*221e7026SMarcin Hajkowski chan_infos[i] = chan_info; 591*221e7026SMarcin Hajkowski rte_strlcpy(chan_info->channel_path, socket_path, 592*221e7026SMarcin Hajkowski sizeof(chan_info->channel_path)); 59360dea75fSLukasz Krakowiak 594*221e7026SMarcin Hajkowski if (setup_host_channel_info(&chan_info, i) < 0) { 5953618326fSDavid Hunt rte_free(chan_info); 596*221e7026SMarcin Hajkowski chan_infos[i] = NULL; 597*221e7026SMarcin Hajkowski goto error; 5983618326fSDavid Hunt } 5993618326fSDavid Hunt num_channels_enabled++; 600*221e7026SMarcin Hajkowski } 6013618326fSDavid Hunt 6023618326fSDavid Hunt return num_channels_enabled; 603*221e7026SMarcin Hajkowski error: 604*221e7026SMarcin Hajkowski /* Clean up the channels opened before we hit an error. */ 605*221e7026SMarcin Hajkowski for (i = 0; i < ci->core_count; i++) { 606*221e7026SMarcin Hajkowski if (chan_infos[i] != NULL) { 607*221e7026SMarcin Hajkowski remove_channel_from_monitor(chan_infos[i]); 608*221e7026SMarcin Hajkowski close(chan_infos[i]->fd); 609*221e7026SMarcin Hajkowski rte_free(chan_infos[i]); 610*221e7026SMarcin Hajkowski } 611*221e7026SMarcin Hajkowski } 612*221e7026SMarcin Hajkowski return 0; 6133618326fSDavid Hunt } 6143618326fSDavid Hunt 6153618326fSDavid Hunt int 616e8ae9b66SAlan Carew remove_channel(struct channel_info **chan_info_dptr) 617e8ae9b66SAlan Carew { 618e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 619e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 620e8ae9b66SAlan Carew 621e8ae9b66SAlan Carew close(chan_info->fd); 622e8ae9b66SAlan Carew 623e8ae9b66SAlan Carew vm_info = (struct virtual_machine_info *)chan_info->priv_info; 624e8ae9b66SAlan Carew 625e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 626fd73630eSDavid Hunt vm_info->channel_mask[chan_info->channel_num] = 0; 627e8ae9b66SAlan Carew vm_info->num_channels--; 628e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 629e8ae9b66SAlan Carew 630e8ae9b66SAlan Carew rte_free(chan_info); 631e8ae9b66SAlan Carew return 0; 632e8ae9b66SAlan Carew } 633e8ae9b66SAlan Carew 634e8ae9b66SAlan Carew int 635e8ae9b66SAlan Carew set_channel_status_all(const char *vm_name, enum channel_status status) 636e8ae9b66SAlan Carew { 637e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 638e8ae9b66SAlan Carew unsigned i; 639751227a0SDavid Hunt char mask[RTE_MAX_LCORE]; 640e8ae9b66SAlan Carew int num_channels_changed = 0; 641e8ae9b66SAlan Carew 642e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 643e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 644e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 645e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 646e8ae9b66SAlan Carew } 647e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 648e8ae9b66SAlan Carew if (vm_info == NULL) { 649e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to disable channels: VM '%s' " 650e8ae9b66SAlan Carew "not found\n", vm_name); 651e8ae9b66SAlan Carew return 0; 652e8ae9b66SAlan Carew } 653e8ae9b66SAlan Carew 654e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 655751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE); 656751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) { 657fd73630eSDavid Hunt if (mask[i] != 1) 658fd73630eSDavid Hunt continue; 659e8ae9b66SAlan Carew vm_info->channels[i]->status = status; 660e8ae9b66SAlan Carew num_channels_changed++; 661e8ae9b66SAlan Carew } 662e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 663e8ae9b66SAlan Carew return num_channels_changed; 664e8ae9b66SAlan Carew 665e8ae9b66SAlan Carew } 666e8ae9b66SAlan Carew 667e8ae9b66SAlan Carew int 668e8ae9b66SAlan Carew set_channel_status(const char *vm_name, unsigned *channel_list, 669e8ae9b66SAlan Carew unsigned len_channel_list, enum channel_status status) 670e8ae9b66SAlan Carew { 671e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 672e8ae9b66SAlan Carew unsigned i; 673e8ae9b66SAlan Carew int num_channels_changed = 0; 674e8ae9b66SAlan Carew 675e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 676e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 677e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 678e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 679e8ae9b66SAlan Carew } 680e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 681e8ae9b66SAlan Carew if (vm_info == NULL) { 682e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 683e8ae9b66SAlan Carew "not found\n", vm_name); 684e8ae9b66SAlan Carew return 0; 685e8ae9b66SAlan Carew } 686e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 687e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 688e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 689e8ae9b66SAlan Carew vm_info->channels[channel_list[i]]->status = status; 690e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 691e8ae9b66SAlan Carew num_channels_changed++; 692e8ae9b66SAlan Carew } 693e8ae9b66SAlan Carew } 694e8ae9b66SAlan Carew return num_channels_changed; 695e8ae9b66SAlan Carew } 696e8ae9b66SAlan Carew 697dff22404SDavid Hunt void 698dff22404SDavid Hunt get_all_vm(int *num_vm, int *num_vcpu) 699dff22404SDavid Hunt { 700dff22404SDavid Hunt 701dff22404SDavid Hunt virNodeInfo node_info; 702dff22404SDavid Hunt virDomainPtr *domptr; 703fd73630eSDavid Hunt int i, ii, numVcpus[MAX_VCPUS], n_vcpus; 704dff22404SDavid Hunt unsigned int jj; 705dff22404SDavid Hunt const char *vm_name; 706dff22404SDavid Hunt unsigned int domain_flags = VIR_CONNECT_LIST_DOMAINS_RUNNING | 707dff22404SDavid Hunt VIR_CONNECT_LIST_DOMAINS_PERSISTENT; 708dff22404SDavid Hunt unsigned int domain_flag = VIR_DOMAIN_VCPU_CONFIG; 709dff22404SDavid Hunt 710e0207366SDavid Hunt if (!global_hypervisor_available) 711e0207366SDavid Hunt return; 712dff22404SDavid Hunt 713751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE*global_maplen); 714dff22404SDavid Hunt if (virNodeGetInfo(global_vir_conn_ptr, &node_info)) { 715dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n"); 716dff22404SDavid Hunt return; 717dff22404SDavid Hunt } 718dff22404SDavid Hunt 719dff22404SDavid Hunt /* Returns number of pcpus */ 720dff22404SDavid Hunt global_n_host_cpus = (unsigned int)node_info.cpus; 721dff22404SDavid Hunt 722dff22404SDavid Hunt /* Returns number of active domains */ 723dff22404SDavid Hunt *num_vm = virConnectListAllDomains(global_vir_conn_ptr, &domptr, 724dff22404SDavid Hunt domain_flags); 725dff22404SDavid Hunt if (*num_vm <= 0) { 726dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "No Active Domains Running\n"); 727dff22404SDavid Hunt return; 728dff22404SDavid Hunt } 729dff22404SDavid Hunt 730dff22404SDavid Hunt for (i = 0; i < *num_vm; i++) { 731dff22404SDavid Hunt 732dff22404SDavid Hunt /* Get Domain Names */ 733dff22404SDavid Hunt vm_name = virDomainGetName(domptr[i]); 734dff22404SDavid Hunt lvm_info[i].vm_name = vm_name; 735dff22404SDavid Hunt 736dff22404SDavid Hunt /* Get Number of Vcpus */ 737dff22404SDavid Hunt numVcpus[i] = virDomainGetVcpusFlags(domptr[i], domain_flag); 738dff22404SDavid Hunt 739dff22404SDavid Hunt /* Get Number of VCpus & VcpuPinInfo */ 740dff22404SDavid Hunt n_vcpus = virDomainGetVcpuPinInfo(domptr[i], 741dff22404SDavid Hunt numVcpus[i], global_cpumaps, 742dff22404SDavid Hunt global_maplen, domain_flag); 743dff22404SDavid Hunt 744dff22404SDavid Hunt if ((int)n_vcpus > 0) { 745dff22404SDavid Hunt *num_vcpu = n_vcpus; 746dff22404SDavid Hunt lvm_info[i].num_cpus = n_vcpus; 747dff22404SDavid Hunt } 748dff22404SDavid Hunt 749dff22404SDavid Hunt /* Save pcpu in use by libvirt VMs */ 750dff22404SDavid Hunt for (ii = 0; ii < n_vcpus; ii++) { 751dff22404SDavid Hunt for (jj = 0; jj < global_n_host_cpus; jj++) { 752dff22404SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps, 753dff22404SDavid Hunt global_maplen, ii, jj) > 0) { 754fd73630eSDavid Hunt lvm_info[i].pcpus[ii] = jj; 755dff22404SDavid Hunt } 756dff22404SDavid Hunt } 757dff22404SDavid Hunt } 758dff22404SDavid Hunt } 759dff22404SDavid Hunt } 760dff22404SDavid Hunt 761e8ae9b66SAlan Carew int 762e8ae9b66SAlan Carew get_info_vm(const char *vm_name, struct vm_info *info) 763e8ae9b66SAlan Carew { 764e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 765e8ae9b66SAlan Carew unsigned i, channel_num = 0; 766751227a0SDavid Hunt char mask[RTE_MAX_LCORE]; 767e8ae9b66SAlan Carew 768e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 769e8ae9b66SAlan Carew if (vm_info == NULL) { 770e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 771e8ae9b66SAlan Carew return -1; 772e8ae9b66SAlan Carew } 773e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_ACTIVE; 774e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) 775e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_INACTIVE; 776e8ae9b66SAlan Carew 777e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 778e8ae9b66SAlan Carew 779751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE); 780751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) { 781fd73630eSDavid Hunt if (mask[i] != 1) 782fd73630eSDavid Hunt continue; 783e8ae9b66SAlan Carew info->channels[channel_num].channel_num = i; 784e8ae9b66SAlan Carew memcpy(info->channels[channel_num].channel_path, 785fd73630eSDavid Hunt vm_info->channels[i]->channel_path, 786fd73630eSDavid Hunt UNIX_PATH_MAX); 787fd73630eSDavid Hunt info->channels[channel_num].status = 788fd73630eSDavid Hunt vm_info->channels[i]->status; 789fd73630eSDavid Hunt info->channels[channel_num].fd = 790fd73630eSDavid Hunt vm_info->channels[i]->fd; 791e8ae9b66SAlan Carew channel_num++; 792e8ae9b66SAlan Carew } 793e8ae9b66SAlan Carew 794e8ae9b66SAlan Carew info->num_channels = channel_num; 795e8ae9b66SAlan Carew info->num_vcpus = vm_info->info.nrVirtCpu; 796e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 797e8ae9b66SAlan Carew 798e8ae9b66SAlan Carew memcpy(info->name, vm_info->name, sizeof(vm_info->name)); 7995776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 800e8ae9b66SAlan Carew for (i = 0; i < info->num_vcpus; i++) { 8015776b7a3SDavid Hunt info->pcpu_map[i] = vm_info->pcpu_map[i]; 802e8ae9b66SAlan Carew } 8035776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 804e8ae9b66SAlan Carew return 0; 805e8ae9b66SAlan Carew } 806e8ae9b66SAlan Carew 807e8ae9b66SAlan Carew int 808e8ae9b66SAlan Carew add_vm(const char *vm_name) 809e8ae9b66SAlan Carew { 810e8ae9b66SAlan Carew struct virtual_machine_info *new_domain; 811e8ae9b66SAlan Carew virDomainPtr dom_ptr; 812e8ae9b66SAlan Carew int i; 813e8ae9b66SAlan Carew 814e8ae9b66SAlan Carew if (find_domain_by_name(vm_name) != NULL) { 815e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add VM: VM '%s' " 816e8ae9b66SAlan Carew "already exists\n", vm_name); 817e8ae9b66SAlan Carew return -1; 818e8ae9b66SAlan Carew } 819e8ae9b66SAlan Carew 820e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 821e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "No connection to hypervisor exists\n"); 822e8ae9b66SAlan Carew return -1; 823e8ae9b66SAlan Carew } 824e8ae9b66SAlan Carew dom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name); 825e8ae9b66SAlan Carew if (dom_ptr == NULL) { 826e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error on VM lookup with libvirt: " 827e8ae9b66SAlan Carew "VM '%s' not found\n", vm_name); 828e8ae9b66SAlan Carew return -1; 829e8ae9b66SAlan Carew } 830e8ae9b66SAlan Carew 831e8ae9b66SAlan Carew new_domain = rte_malloc("virtual_machine_info", sizeof(*new_domain), 832fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 833e8ae9b66SAlan Carew if (new_domain == NULL) { 834e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to allocate memory for VM " 835e8ae9b66SAlan Carew "info\n"); 836e8ae9b66SAlan Carew return -1; 837e8ae9b66SAlan Carew } 838e8ae9b66SAlan Carew new_domain->domainPtr = dom_ptr; 839e8ae9b66SAlan Carew if (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) { 840e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get libvirt VM info\n"); 841e8ae9b66SAlan Carew rte_free(new_domain); 842e8ae9b66SAlan Carew return -1; 843e8ae9b66SAlan Carew } 844751227a0SDavid Hunt if (new_domain->info.nrVirtCpu > RTE_MAX_LCORE) { 845e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error the number of virtual CPUs(%u) is " 846e8ae9b66SAlan Carew "greater than allowable(%d)\n", new_domain->info.nrVirtCpu, 847751227a0SDavid Hunt RTE_MAX_LCORE); 848e8ae9b66SAlan Carew rte_free(new_domain); 849e8ae9b66SAlan Carew return -1; 850e8ae9b66SAlan Carew } 851e8ae9b66SAlan Carew 852751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) 8535776b7a3SDavid Hunt new_domain->pcpu_map[i] = 0; 854751227a0SDavid Hunt 855e8ae9b66SAlan Carew if (update_pcpus_mask(new_domain) < 0) { 856e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting physical CPU pinning\n"); 857e8ae9b66SAlan Carew rte_free(new_domain); 858e8ae9b66SAlan Carew return -1; 859e8ae9b66SAlan Carew } 860e8ae9b66SAlan Carew strncpy(new_domain->name, vm_name, sizeof(new_domain->name)); 86142b3f505SDaniel Mrzyglod new_domain->name[sizeof(new_domain->name) - 1] = '\0'; 862751227a0SDavid Hunt memset(new_domain->channel_mask, 0, RTE_MAX_LCORE); 863e8ae9b66SAlan Carew new_domain->num_channels = 0; 864e8ae9b66SAlan Carew 865e8ae9b66SAlan Carew if (!virDomainIsActive(dom_ptr)) 866e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_INACTIVE; 867e8ae9b66SAlan Carew else 868e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_ACTIVE; 869e8ae9b66SAlan Carew 870e8ae9b66SAlan Carew rte_spinlock_init(&(new_domain->config_spinlock)); 871e8ae9b66SAlan Carew LIST_INSERT_HEAD(&vm_list_head, new_domain, vms_info); 872e8ae9b66SAlan Carew return 0; 873e8ae9b66SAlan Carew } 874e8ae9b66SAlan Carew 875e8ae9b66SAlan Carew int 876e8ae9b66SAlan Carew remove_vm(const char *vm_name) 877e8ae9b66SAlan Carew { 878e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = find_domain_by_name(vm_name); 879e8ae9b66SAlan Carew 880e8ae9b66SAlan Carew if (vm_info == NULL) { 881e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM: VM '%s' " 882e8ae9b66SAlan Carew "not found\n", vm_name); 883e8ae9b66SAlan Carew return -1; 884e8ae9b66SAlan Carew } 885e8ae9b66SAlan Carew rte_spinlock_lock(&vm_info->config_spinlock); 886e8ae9b66SAlan Carew if (vm_info->num_channels != 0) { 887e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM '%s', there are " 888e8ae9b66SAlan Carew "%"PRId8" channels still active\n", 889e8ae9b66SAlan Carew vm_name, vm_info->num_channels); 890e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 891e8ae9b66SAlan Carew return -1; 892e8ae9b66SAlan Carew } 893e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 894e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 895e8ae9b66SAlan Carew rte_free(vm_info); 896e8ae9b66SAlan Carew return 0; 897e8ae9b66SAlan Carew } 898e8ae9b66SAlan Carew 899e8ae9b66SAlan Carew static void 900e8ae9b66SAlan Carew disconnect_hypervisor(void) 901e8ae9b66SAlan Carew { 902e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 903e8ae9b66SAlan Carew virConnectClose(global_vir_conn_ptr); 904e8ae9b66SAlan Carew global_vir_conn_ptr = NULL; 905e8ae9b66SAlan Carew } 906e8ae9b66SAlan Carew } 907e8ae9b66SAlan Carew 908e8ae9b66SAlan Carew static int 909e8ae9b66SAlan Carew connect_hypervisor(const char *path) 910e8ae9b66SAlan Carew { 911e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 912e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error connecting to %s, connection " 913e8ae9b66SAlan Carew "already established\n", path); 914e8ae9b66SAlan Carew return -1; 915e8ae9b66SAlan Carew } 916e8ae9b66SAlan Carew global_vir_conn_ptr = virConnectOpen(path); 917e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 918e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error failed to open connection to " 919e8ae9b66SAlan Carew "Hypervisor '%s'\n", path); 920e8ae9b66SAlan Carew return -1; 921e8ae9b66SAlan Carew } 922e8ae9b66SAlan Carew return 0; 923e8ae9b66SAlan Carew } 924e8ae9b66SAlan Carew int 925e0207366SDavid Hunt channel_manager_init(const char *path __rte_unused) 926e8ae9b66SAlan Carew { 927f7f14fe3SYong Liu virNodeInfo info; 928e8ae9b66SAlan Carew 929e8ae9b66SAlan Carew LIST_INIT(&vm_list_head); 930e8ae9b66SAlan Carew if (connect_hypervisor(path) < 0) { 931e0207366SDavid Hunt global_n_host_cpus = 64; 932e0207366SDavid Hunt global_hypervisor_available = 0; 933e0207366SDavid Hunt RTE_LOG(INFO, CHANNEL_MANAGER, "Unable to initialize channel manager\n"); 934e0207366SDavid Hunt } else { 935e0207366SDavid Hunt global_hypervisor_available = 1; 936e8ae9b66SAlan Carew 937751227a0SDavid Hunt global_maplen = VIR_CPU_MAPLEN(RTE_MAX_LCORE); 938e8ae9b66SAlan Carew 939e0207366SDavid Hunt global_vircpuinfo = rte_zmalloc(NULL, 940e0207366SDavid Hunt sizeof(*global_vircpuinfo) * 941751227a0SDavid Hunt RTE_MAX_LCORE, RTE_CACHE_LINE_SIZE); 942e8ae9b66SAlan Carew if (global_vircpuinfo == NULL) { 943e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for CPU Info\n"); 944e8ae9b66SAlan Carew goto error; 945e8ae9b66SAlan Carew } 946e0207366SDavid Hunt global_cpumaps = rte_zmalloc(NULL, 947751227a0SDavid Hunt RTE_MAX_LCORE * global_maplen, 948fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 949e0207366SDavid Hunt if (global_cpumaps == NULL) 950e8ae9b66SAlan Carew goto error; 951e8ae9b66SAlan Carew 952f7f14fe3SYong Liu if (virNodeGetInfo(global_vir_conn_ptr, &info)) { 953f7f14fe3SYong Liu RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n"); 954e8ae9b66SAlan Carew goto error; 955e8ae9b66SAlan Carew } 956e0207366SDavid Hunt global_n_host_cpus = (unsigned int)info.cpus; 957e0207366SDavid Hunt } 958f7f14fe3SYong Liu 959e0207366SDavid Hunt 960e8ae9b66SAlan Carew 961751227a0SDavid Hunt if (global_n_host_cpus > RTE_MAX_LCORE) { 962e9f64db9SPablo de Lara RTE_LOG(WARNING, CHANNEL_MANAGER, "The number of host CPUs(%u) exceeds the " 963e9f64db9SPablo de Lara "maximum of %u. No cores over %u should be used.\n", 964751227a0SDavid Hunt global_n_host_cpus, RTE_MAX_LCORE, 965751227a0SDavid Hunt RTE_MAX_LCORE - 1); 966751227a0SDavid Hunt global_n_host_cpus = RTE_MAX_LCORE; 96767ff575eSMarvin Liu } 968e8ae9b66SAlan Carew 969e8ae9b66SAlan Carew return 0; 970e8ae9b66SAlan Carew error: 971e0207366SDavid Hunt if (global_hypervisor_available) 972e8ae9b66SAlan Carew disconnect_hypervisor(); 973e8ae9b66SAlan Carew return -1; 974e8ae9b66SAlan Carew } 975e8ae9b66SAlan Carew 976e8ae9b66SAlan Carew void 977e8ae9b66SAlan Carew channel_manager_exit(void) 978e8ae9b66SAlan Carew { 979e8ae9b66SAlan Carew unsigned i; 980751227a0SDavid Hunt char mask[RTE_MAX_LCORE]; 981e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 982e8ae9b66SAlan Carew 983e8ae9b66SAlan Carew LIST_FOREACH(vm_info, &vm_list_head, vms_info) { 984e8ae9b66SAlan Carew 985e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 986e8ae9b66SAlan Carew 987751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE); 988751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) { 989fd73630eSDavid Hunt if (mask[i] != 1) 990fd73630eSDavid Hunt continue; 991fd73630eSDavid Hunt remove_channel_from_monitor( 992fd73630eSDavid Hunt vm_info->channels[i]); 993e8ae9b66SAlan Carew close(vm_info->channels[i]->fd); 994e8ae9b66SAlan Carew rte_free(vm_info->channels[i]); 995e8ae9b66SAlan Carew } 996e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 997e8ae9b66SAlan Carew 998e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 999e8ae9b66SAlan Carew rte_free(vm_info); 1000e8ae9b66SAlan Carew } 1001e8ae9b66SAlan Carew 1002e0207366SDavid Hunt if (global_hypervisor_available) { 1003e0207366SDavid Hunt /* Only needed if hypervisor available */ 1004e8ae9b66SAlan Carew rte_free(global_cpumaps); 1005e8ae9b66SAlan Carew rte_free(global_vircpuinfo); 1006e8ae9b66SAlan Carew disconnect_hypervisor(); 1007e8ae9b66SAlan Carew } 1008e0207366SDavid Hunt } 1009