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 38*96d3d532SThomas Monjalon struct libvirt_vm_info lvm_info[MAX_CLIENTS]; 39*96d3d532SThomas Monjalon 40e8ae9b66SAlan Carew /* Global pointer to libvirt connection */ 41e8ae9b66SAlan Carew static virConnectPtr global_vir_conn_ptr; 42e8ae9b66SAlan Carew 43e8ae9b66SAlan Carew static unsigned char *global_cpumaps; 44e8ae9b66SAlan Carew static virVcpuInfo *global_vircpuinfo; 45e8ae9b66SAlan Carew static size_t global_maplen; 46e8ae9b66SAlan Carew 47e0207366SDavid Hunt static unsigned int global_n_host_cpus; 48e0207366SDavid Hunt static bool global_hypervisor_available; 49e8ae9b66SAlan Carew 50e8ae9b66SAlan Carew /* 51e8ae9b66SAlan Carew * Represents a single Virtual Machine 52e8ae9b66SAlan Carew */ 53e8ae9b66SAlan Carew struct virtual_machine_info { 54e8ae9b66SAlan Carew char name[CHANNEL_MGR_MAX_NAME_LEN]; 55751227a0SDavid Hunt uint16_t pcpu_map[RTE_MAX_LCORE]; 56751227a0SDavid Hunt struct channel_info *channels[RTE_MAX_LCORE]; 57751227a0SDavid Hunt char channel_mask[RTE_MAX_LCORE]; 58e8ae9b66SAlan Carew uint8_t num_channels; 59e8ae9b66SAlan Carew enum vm_status status; 60e8ae9b66SAlan Carew virDomainPtr domainPtr; 61e8ae9b66SAlan Carew virDomainInfo info; 62e8ae9b66SAlan Carew rte_spinlock_t config_spinlock; 631deb502eSMarcin Hajkowski int allow_query; 64e8ae9b66SAlan Carew LIST_ENTRY(virtual_machine_info) vms_info; 65e8ae9b66SAlan Carew }; 66e8ae9b66SAlan Carew 67e8ae9b66SAlan Carew LIST_HEAD(, virtual_machine_info) vm_list_head; 68e8ae9b66SAlan Carew 69e8ae9b66SAlan Carew static struct virtual_machine_info * 70e8ae9b66SAlan Carew find_domain_by_name(const char *name) 71e8ae9b66SAlan Carew { 72e8ae9b66SAlan Carew struct virtual_machine_info *info; 73e8ae9b66SAlan Carew LIST_FOREACH(info, &vm_list_head, vms_info) { 74e8ae9b66SAlan Carew if (!strncmp(info->name, name, CHANNEL_MGR_MAX_NAME_LEN-1)) 75e8ae9b66SAlan Carew return info; 76e8ae9b66SAlan Carew } 77e8ae9b66SAlan Carew return NULL; 78e8ae9b66SAlan Carew } 79e8ae9b66SAlan Carew 80e8ae9b66SAlan Carew static int 81e8ae9b66SAlan Carew update_pcpus_mask(struct virtual_machine_info *vm_info) 82e8ae9b66SAlan Carew { 83e8ae9b66SAlan Carew virVcpuInfoPtr cpuinfo; 84e8ae9b66SAlan Carew unsigned i, j; 85e8ae9b66SAlan Carew int n_vcpus; 86e8ae9b66SAlan Carew 87751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE*global_maplen); 88e8ae9b66SAlan Carew 89e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 90e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpuPinInfo(vm_info->domainPtr, 91e8ae9b66SAlan Carew vm_info->info.nrVirtCpu, global_cpumaps, global_maplen, 92e8ae9b66SAlan Carew VIR_DOMAIN_AFFECT_CONFIG); 93e8ae9b66SAlan Carew if (n_vcpus < 0) { 94e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for " 95e8ae9b66SAlan Carew "in-active VM '%s'\n", vm_info->name); 96e8ae9b66SAlan Carew return -1; 97e8ae9b66SAlan Carew } 98e8ae9b66SAlan Carew goto update_pcpus; 99e8ae9b66SAlan Carew } 100e8ae9b66SAlan Carew 101e8ae9b66SAlan Carew memset(global_vircpuinfo, 0, sizeof(*global_vircpuinfo)* 102751227a0SDavid Hunt RTE_MAX_LCORE); 103e8ae9b66SAlan Carew 104e8ae9b66SAlan Carew cpuinfo = global_vircpuinfo; 105e8ae9b66SAlan Carew 106e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo, 107751227a0SDavid Hunt RTE_MAX_LCORE, global_cpumaps, global_maplen); 108e8ae9b66SAlan Carew if (n_vcpus < 0) { 109e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for " 110e8ae9b66SAlan Carew "active VM '%s'\n", vm_info->name); 111e8ae9b66SAlan Carew return -1; 112e8ae9b66SAlan Carew } 113e8ae9b66SAlan Carew update_pcpus: 114751227a0SDavid Hunt if (n_vcpus >= RTE_MAX_LCORE) { 115e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Number of vCPUS(%u) is out of range " 116751227a0SDavid Hunt "0...%d\n", n_vcpus, RTE_MAX_LCORE-1); 117e8ae9b66SAlan Carew return -1; 118e8ae9b66SAlan Carew } 119e8ae9b66SAlan Carew if (n_vcpus != vm_info->info.nrVirtCpu) { 120e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Updating the number of vCPUs for VM '%s" 121e8ae9b66SAlan Carew " from %d -> %d\n", vm_info->name, vm_info->info.nrVirtCpu, 122e8ae9b66SAlan Carew n_vcpus); 123e8ae9b66SAlan Carew vm_info->info.nrVirtCpu = n_vcpus; 124e8ae9b66SAlan Carew } 1255776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 126e8ae9b66SAlan Carew for (i = 0; i < vm_info->info.nrVirtCpu; i++) { 127e8ae9b66SAlan Carew for (j = 0; j < global_n_host_cpus; j++) { 1285776b7a3SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps, 1295776b7a3SDavid Hunt global_maplen, i, j) <= 0) 1305776b7a3SDavid Hunt continue; 1315776b7a3SDavid Hunt vm_info->pcpu_map[i] = j; 132e8ae9b66SAlan Carew } 133e8ae9b66SAlan Carew } 1345776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 135e8ae9b66SAlan Carew return 0; 136e8ae9b66SAlan Carew } 137e8ae9b66SAlan Carew 138e8ae9b66SAlan Carew int 1395776b7a3SDavid Hunt set_pcpu(char *vm_name, unsigned int vcpu, unsigned int pcpu) 140e8ae9b66SAlan Carew { 141e8ae9b66SAlan Carew int flags = VIR_DOMAIN_AFFECT_LIVE|VIR_DOMAIN_AFFECT_CONFIG; 142e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 143e8ae9b66SAlan Carew 144751227a0SDavid Hunt if (vcpu >= RTE_MAX_LCORE) { 145e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds max allowable(%d)\n", 146751227a0SDavid Hunt vcpu, RTE_MAX_LCORE-1); 147e8ae9b66SAlan Carew return -1; 148e8ae9b66SAlan Carew } 149e8ae9b66SAlan Carew 150e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 151e8ae9b66SAlan Carew if (vm_info == NULL) { 152e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 153e8ae9b66SAlan Carew return -1; 154e8ae9b66SAlan Carew } 155e8ae9b66SAlan Carew 156e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 157e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU " 158fd73630eSDavid Hunt " for VM '%s', VM is not active\n", 159fd73630eSDavid Hunt vcpu, vm_info->name); 160e8ae9b66SAlan Carew return -1; 161e8ae9b66SAlan Carew } 162e8ae9b66SAlan Carew 163e8ae9b66SAlan Carew if (vcpu >= vm_info->info.nrVirtCpu) { 164e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds the assigned number of " 165e8ae9b66SAlan Carew "vCPUs(%u)\n", vcpu, vm_info->info.nrVirtCpu); 166e8ae9b66SAlan Carew return -1; 167e8ae9b66SAlan Carew } 168751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE * global_maplen); 1695776b7a3SDavid Hunt 1705776b7a3SDavid Hunt VIR_USE_CPU(global_cpumaps, pcpu); 1715776b7a3SDavid Hunt 1725776b7a3SDavid Hunt if (pcpu >= global_n_host_cpus) { 173e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "CPU(%u) exceeds the available " 174fd73630eSDavid Hunt "number of CPUs(%u)\n", 1755776b7a3SDavid Hunt pcpu, global_n_host_cpus); 176e8ae9b66SAlan Carew return -1; 177e8ae9b66SAlan Carew } 1785776b7a3SDavid Hunt 179e8ae9b66SAlan Carew if (virDomainPinVcpuFlags(vm_info->domainPtr, vcpu, global_cpumaps, 180e8ae9b66SAlan Carew global_maplen, flags) < 0) { 181e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU " 182fd73630eSDavid Hunt " for VM '%s'\n", vcpu, 183e8ae9b66SAlan Carew vm_info->name); 184e8ae9b66SAlan Carew return -1; 185e8ae9b66SAlan Carew } 186fd73630eSDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 1875776b7a3SDavid Hunt vm_info->pcpu_map[vcpu] = pcpu; 188fd73630eSDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 189e8ae9b66SAlan Carew return 0; 190e8ae9b66SAlan Carew } 191e8ae9b66SAlan Carew 1925776b7a3SDavid Hunt uint16_t 1935776b7a3SDavid Hunt get_pcpu(struct channel_info *chan_info, unsigned int vcpu) 194e8ae9b66SAlan Carew { 195e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = 196e8ae9b66SAlan Carew (struct virtual_machine_info *)chan_info->priv_info; 197e0207366SDavid Hunt 1985776b7a3SDavid Hunt if (global_hypervisor_available && (vm_info != NULL)) { 1995776b7a3SDavid Hunt uint16_t pcpu; 2005776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 2015776b7a3SDavid Hunt pcpu = vm_info->pcpu_map[vcpu]; 2025776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 2035776b7a3SDavid Hunt return pcpu; 2045776b7a3SDavid Hunt } else 205e0207366SDavid Hunt return 0; 206e8ae9b66SAlan Carew } 207e8ae9b66SAlan Carew 208e8ae9b66SAlan Carew static inline int 209e8ae9b66SAlan Carew channel_exists(struct virtual_machine_info *vm_info, unsigned channel_num) 210e8ae9b66SAlan Carew { 211e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 212fd73630eSDavid Hunt if (vm_info->channel_mask[channel_num] == 1) { 213e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 214e8ae9b66SAlan Carew return 1; 215e8ae9b66SAlan Carew } 216e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 217e8ae9b66SAlan Carew return 0; 218e8ae9b66SAlan Carew } 219e8ae9b66SAlan Carew 220e8ae9b66SAlan Carew 221e8ae9b66SAlan Carew 222e8ae9b66SAlan Carew static int 223e8ae9b66SAlan Carew open_non_blocking_channel(struct channel_info *info) 224e8ae9b66SAlan Carew { 225e8ae9b66SAlan Carew int ret, flags; 226e8ae9b66SAlan Carew struct sockaddr_un sock_addr; 227e8ae9b66SAlan Carew fd_set soc_fd_set; 228e8ae9b66SAlan Carew struct timeval tv; 229e8ae9b66SAlan Carew 230e8ae9b66SAlan Carew info->fd = socket(AF_UNIX, SOCK_STREAM, 0); 2311b897991SLukasz Krakowiak if (info->fd < 0) { 232e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) creating socket for '%s'\n", 233e8ae9b66SAlan Carew strerror(errno), 234e8ae9b66SAlan Carew info->channel_path); 235e8ae9b66SAlan Carew return -1; 236e8ae9b66SAlan Carew } 237e8ae9b66SAlan Carew sock_addr.sun_family = AF_UNIX; 238e8ae9b66SAlan Carew memcpy(&sock_addr.sun_path, info->channel_path, 239e8ae9b66SAlan Carew strlen(info->channel_path)+1); 240e8ae9b66SAlan Carew 241e8ae9b66SAlan Carew /* Get current flags */ 242e8ae9b66SAlan Carew flags = fcntl(info->fd, F_GETFL, 0); 243e8ae9b66SAlan Carew if (flags < 0) { 244e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for" 245e8ae9b66SAlan Carew "'%s'\n", strerror(errno), info->channel_path); 246e8ae9b66SAlan Carew return 1; 247e8ae9b66SAlan Carew } 248e8ae9b66SAlan Carew /* Set to Non Blocking */ 249e8ae9b66SAlan Carew flags |= O_NONBLOCK; 250e8ae9b66SAlan Carew if (fcntl(info->fd, F_SETFL, flags) < 0) { 251e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) setting non-blocking " 252e8ae9b66SAlan Carew "socket for '%s'\n", strerror(errno), info->channel_path); 253e8ae9b66SAlan Carew return -1; 254e8ae9b66SAlan Carew } 255e8ae9b66SAlan Carew ret = connect(info->fd, (struct sockaddr *)&sock_addr, 256e8ae9b66SAlan Carew sizeof(sock_addr)); 257e8ae9b66SAlan Carew if (ret < 0) { 258e8ae9b66SAlan Carew /* ECONNREFUSED error is given when VM is not active */ 259e8ae9b66SAlan Carew if (errno == ECONNREFUSED) { 260e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "VM is not active or has not " 261e8ae9b66SAlan Carew "activated its endpoint to channel %s\n", 262e8ae9b66SAlan Carew info->channel_path); 263e8ae9b66SAlan Carew return -1; 264e8ae9b66SAlan Carew } 265e8ae9b66SAlan Carew /* Wait for tv_sec if in progress */ 266e8ae9b66SAlan Carew else if (errno == EINPROGRESS) { 267e8ae9b66SAlan Carew tv.tv_sec = 2; 268e8ae9b66SAlan Carew tv.tv_usec = 0; 269e8ae9b66SAlan Carew FD_ZERO(&soc_fd_set); 270e8ae9b66SAlan Carew FD_SET(info->fd, &soc_fd_set); 271e8ae9b66SAlan Carew if (select(info->fd+1, NULL, &soc_fd_set, NULL, &tv) > 0) { 272e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Timeout or error on channel " 273e8ae9b66SAlan Carew "'%s'\n", info->channel_path); 274e8ae9b66SAlan Carew return -1; 275e8ae9b66SAlan Carew } 276e8ae9b66SAlan Carew } else { 277e8ae9b66SAlan Carew /* Any other error */ 278e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) connecting socket" 279e8ae9b66SAlan Carew " for '%s'\n", strerror(errno), info->channel_path); 280e8ae9b66SAlan Carew return -1; 281e8ae9b66SAlan Carew } 282e8ae9b66SAlan Carew } 283e8ae9b66SAlan Carew return 0; 284e8ae9b66SAlan Carew } 285e8ae9b66SAlan Carew 286e8ae9b66SAlan Carew static int 2873618326fSDavid Hunt open_host_channel(struct channel_info *info) 2883618326fSDavid Hunt { 2893618326fSDavid Hunt int flags; 2903618326fSDavid Hunt 2913618326fSDavid Hunt info->fd = open(info->channel_path, O_RDWR | O_RSYNC); 2921b897991SLukasz Krakowiak if (info->fd < 0) { 2933618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) opening fifo for '%s'\n", 2943618326fSDavid Hunt strerror(errno), 2953618326fSDavid Hunt info->channel_path); 2963618326fSDavid Hunt return -1; 2973618326fSDavid Hunt } 2983618326fSDavid Hunt 2993618326fSDavid Hunt /* Get current flags */ 3003618326fSDavid Hunt flags = fcntl(info->fd, F_GETFL, 0); 3013618326fSDavid Hunt if (flags < 0) { 3023618326fSDavid Hunt RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for" 3033618326fSDavid Hunt "'%s'\n", strerror(errno), info->channel_path); 3043618326fSDavid Hunt return 1; 3053618326fSDavid Hunt } 3063618326fSDavid Hunt /* Set to Non Blocking */ 3073618326fSDavid Hunt flags |= O_NONBLOCK; 3083618326fSDavid Hunt if (fcntl(info->fd, F_SETFL, flags) < 0) { 3093618326fSDavid Hunt RTE_LOG(WARNING, CHANNEL_MANAGER, 3103618326fSDavid Hunt "Error(%s) setting non-blocking " 3113618326fSDavid Hunt "socket for '%s'\n", 3123618326fSDavid Hunt strerror(errno), info->channel_path); 3133618326fSDavid Hunt return -1; 3143618326fSDavid Hunt } 3153618326fSDavid Hunt return 0; 3163618326fSDavid Hunt } 3173618326fSDavid Hunt 3183618326fSDavid Hunt static int 319e8ae9b66SAlan Carew setup_channel_info(struct virtual_machine_info **vm_info_dptr, 320e8ae9b66SAlan Carew struct channel_info **chan_info_dptr, unsigned channel_num) 321e8ae9b66SAlan Carew { 322e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 323e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = *vm_info_dptr; 324e8ae9b66SAlan Carew 325e8ae9b66SAlan Carew chan_info->channel_num = channel_num; 326e8ae9b66SAlan Carew chan_info->priv_info = (void *)vm_info; 327e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED; 3283618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_BINARY; 329e8ae9b66SAlan Carew if (open_non_blocking_channel(chan_info) < 0) { 330e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open channel: " 331e8ae9b66SAlan Carew "'%s' for VM '%s'\n", 332e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name); 333e8ae9b66SAlan Carew return -1; 334e8ae9b66SAlan Carew } 335e8ae9b66SAlan Carew if (add_channel_to_monitor(&chan_info) < 0) { 336e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: " 337e8ae9b66SAlan Carew "'%s' to epoll ctl for VM '%s'\n", 338e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name); 339e8ae9b66SAlan Carew return -1; 340e8ae9b66SAlan Carew 341e8ae9b66SAlan Carew } 342e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 343e8ae9b66SAlan Carew vm_info->num_channels++; 344fd73630eSDavid Hunt vm_info->channel_mask[channel_num] = 1; 345e8ae9b66SAlan Carew vm_info->channels[channel_num] = chan_info; 346e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED; 347e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 348e8ae9b66SAlan Carew return 0; 349e8ae9b66SAlan Carew } 350e8ae9b66SAlan Carew 351221e7026SMarcin Hajkowski static int 352221e7026SMarcin Hajkowski fifo_path(char *dst, unsigned int len, unsigned int id) 3533618326fSDavid Hunt { 354221e7026SMarcin Hajkowski int cnt; 355221e7026SMarcin Hajkowski 356221e7026SMarcin Hajkowski cnt = snprintf(dst, len, "%s%s%d", CHANNEL_MGR_SOCKET_PATH, 357221e7026SMarcin Hajkowski CHANNEL_MGR_FIFO_PATTERN_NAME, id); 358221e7026SMarcin Hajkowski 359221e7026SMarcin Hajkowski if ((cnt < 0) || (cnt > (int)len - 1)) { 360221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Could not create proper " 361221e7026SMarcin Hajkowski "string for fifo path\n"); 362221e7026SMarcin Hajkowski 363221e7026SMarcin Hajkowski return -1; 364221e7026SMarcin Hajkowski } 365221e7026SMarcin Hajkowski 366221e7026SMarcin Hajkowski return 0; 3673618326fSDavid Hunt } 3683618326fSDavid Hunt 3693618326fSDavid Hunt static int 3703618326fSDavid Hunt setup_host_channel_info(struct channel_info **chan_info_dptr, 3713618326fSDavid Hunt unsigned int channel_num) 3723618326fSDavid Hunt { 3733618326fSDavid Hunt struct channel_info *chan_info = *chan_info_dptr; 3743618326fSDavid Hunt 3753618326fSDavid Hunt chan_info->channel_num = channel_num; 3763618326fSDavid Hunt chan_info->priv_info = (void *)NULL; 3773618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED; 3783618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_JSON; 3793618326fSDavid Hunt 3803618326fSDavid Hunt if (open_host_channel(chan_info) < 0) { 3813618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open host channel: " 3823618326fSDavid Hunt "'%s'\n", 3833618326fSDavid Hunt chan_info->channel_path); 3843618326fSDavid Hunt return -1; 3853618326fSDavid Hunt } 3863618326fSDavid Hunt if (add_channel_to_monitor(&chan_info) < 0) { 3873618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: " 3883618326fSDavid Hunt "'%s' to epoll ctl\n", 3893618326fSDavid Hunt chan_info->channel_path); 3903618326fSDavid Hunt return -1; 3913618326fSDavid Hunt 3923618326fSDavid Hunt } 3933618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED; 3943618326fSDavid Hunt return 0; 3953618326fSDavid Hunt } 3963618326fSDavid Hunt 397e8ae9b66SAlan Carew int 398e8ae9b66SAlan Carew add_all_channels(const char *vm_name) 399e8ae9b66SAlan Carew { 400e8ae9b66SAlan Carew DIR *d; 401e8ae9b66SAlan Carew struct dirent *dir; 402e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 403e8ae9b66SAlan Carew struct channel_info *chan_info; 404e8ae9b66SAlan Carew char *token, *remaining, *tail_ptr; 405e8ae9b66SAlan Carew char socket_name[PATH_MAX]; 406e8ae9b66SAlan Carew unsigned channel_num; 407e8ae9b66SAlan Carew int num_channels_enabled = 0; 408e8ae9b66SAlan Carew 409e8ae9b66SAlan Carew /* verify VM exists */ 410e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 411e8ae9b66SAlan Carew if (vm_info == NULL) { 412e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' not found" 413e8ae9b66SAlan Carew " during channel discovery\n", vm_name); 414e8ae9b66SAlan Carew return 0; 415e8ae9b66SAlan Carew } 416e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 417e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 418e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 419e8ae9b66SAlan Carew return 0; 420e8ae9b66SAlan Carew } 421e8ae9b66SAlan Carew d = opendir(CHANNEL_MGR_SOCKET_PATH); 422e8ae9b66SAlan Carew if (d == NULL) { 423e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error opening directory '%s': %s\n", 424e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, strerror(errno)); 425e8ae9b66SAlan Carew return -1; 426e8ae9b66SAlan Carew } 427e8ae9b66SAlan Carew while ((dir = readdir(d)) != NULL) { 428e8ae9b66SAlan Carew if (!strncmp(dir->d_name, ".", 1) || 429e8ae9b66SAlan Carew !strncmp(dir->d_name, "..", 2)) 430e8ae9b66SAlan Carew continue; 431e8ae9b66SAlan Carew 4326723c0fcSBruce Richardson strlcpy(socket_name, dir->d_name, sizeof(socket_name)); 433e8ae9b66SAlan Carew remaining = socket_name; 434e8ae9b66SAlan Carew /* Extract vm_name from "<vm_name>.<channel_num>" */ 435e8ae9b66SAlan Carew token = strsep(&remaining, "."); 436e8ae9b66SAlan Carew if (remaining == NULL) 437e8ae9b66SAlan Carew continue; 438e8ae9b66SAlan Carew if (strncmp(vm_name, token, CHANNEL_MGR_MAX_NAME_LEN)) 439e8ae9b66SAlan Carew continue; 440e8ae9b66SAlan Carew 441e8ae9b66SAlan Carew /* remaining should contain only <channel_num> */ 442e8ae9b66SAlan Carew errno = 0; 443e8ae9b66SAlan Carew channel_num = (unsigned)strtol(remaining, &tail_ptr, 0); 444e8ae9b66SAlan Carew if ((errno != 0) || (remaining[0] == '\0') || 4455b628fe1SBruce Richardson tail_ptr == NULL || (*tail_ptr != '\0')) { 446e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Malformed channel name" 447e8ae9b66SAlan Carew "'%s' found it should be in the form of " 448e8ae9b66SAlan Carew "'<guest_name>.<channel_num>(decimal)'\n", 449e8ae9b66SAlan Carew dir->d_name); 450e8ae9b66SAlan Carew continue; 451e8ae9b66SAlan Carew } 452751227a0SDavid Hunt if (channel_num >= RTE_MAX_LCORE) { 453e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Channel number(%u) is " 454e8ae9b66SAlan Carew "greater than max allowable: %d, skipping '%s%s'\n", 455751227a0SDavid Hunt channel_num, RTE_MAX_LCORE-1, 456e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 457e8ae9b66SAlan Carew continue; 458e8ae9b66SAlan Carew } 459e8ae9b66SAlan Carew /* if channel has not been added previously */ 460e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_num)) 461e8ae9b66SAlan Carew continue; 462e8ae9b66SAlan Carew 463e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 464fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 465e8ae9b66SAlan Carew if (chan_info == NULL) { 466e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 467e8ae9b66SAlan Carew "channel '%s%s'\n", CHANNEL_MGR_SOCKET_PATH, dir->d_name); 468e8ae9b66SAlan Carew continue; 469e8ae9b66SAlan Carew } 470e8ae9b66SAlan Carew 471e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 472e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s", 473e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 474e8ae9b66SAlan Carew 475e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) { 476e8ae9b66SAlan Carew rte_free(chan_info); 477e8ae9b66SAlan Carew continue; 478e8ae9b66SAlan Carew } 479e8ae9b66SAlan Carew 480e8ae9b66SAlan Carew num_channels_enabled++; 481e8ae9b66SAlan Carew } 482e8ae9b66SAlan Carew closedir(d); 483e8ae9b66SAlan Carew return num_channels_enabled; 484e8ae9b66SAlan Carew } 485e8ae9b66SAlan Carew 486e8ae9b66SAlan Carew int 487e8ae9b66SAlan Carew add_channels(const char *vm_name, unsigned *channel_list, 488e8ae9b66SAlan Carew unsigned len_channel_list) 489e8ae9b66SAlan Carew { 490e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 491e8ae9b66SAlan Carew struct channel_info *chan_info; 492e8ae9b66SAlan Carew char socket_path[PATH_MAX]; 493e8ae9b66SAlan Carew unsigned i; 494e8ae9b66SAlan Carew int num_channels_enabled = 0; 495e8ae9b66SAlan Carew 496e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 497e8ae9b66SAlan Carew if (vm_info == NULL) { 498e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 499e8ae9b66SAlan Carew "not found\n", vm_name); 500e8ae9b66SAlan Carew return 0; 501e8ae9b66SAlan Carew } 502e8ae9b66SAlan Carew 503e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 504e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 505e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 506e8ae9b66SAlan Carew return 0; 507e8ae9b66SAlan Carew } 508e8ae9b66SAlan Carew 509e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 510e8ae9b66SAlan Carew 511751227a0SDavid Hunt if (channel_list[i] >= RTE_MAX_LCORE) { 512e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel(%u) is out of range " 513e8ae9b66SAlan Carew "0...%d\n", channel_list[i], 514751227a0SDavid Hunt RTE_MAX_LCORE-1); 515e8ae9b66SAlan Carew continue; 516e8ae9b66SAlan Carew } 517e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 518e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel already exists, skipping " 519e8ae9b66SAlan Carew "'%s.%u'\n", vm_name, i); 520e8ae9b66SAlan Carew continue; 521e8ae9b66SAlan Carew } 522e8ae9b66SAlan Carew 523e8ae9b66SAlan Carew snprintf(socket_path, sizeof(socket_path), "%s%s.%u", 524e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 525e8ae9b66SAlan Carew errno = 0; 526e8ae9b66SAlan Carew if (access(socket_path, F_OK) < 0) { 527e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: " 528e8ae9b66SAlan Carew "%s\n", socket_path, strerror(errno)); 529e8ae9b66SAlan Carew continue; 530e8ae9b66SAlan Carew } 531e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 532fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 533e8ae9b66SAlan Carew if (chan_info == NULL) { 534e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 535e8ae9b66SAlan Carew "channel '%s'\n", socket_path); 536e8ae9b66SAlan Carew continue; 537e8ae9b66SAlan Carew } 538e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 539e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s.%u", 540e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 541e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) { 542e8ae9b66SAlan Carew rte_free(chan_info); 543e8ae9b66SAlan Carew continue; 544e8ae9b66SAlan Carew } 545e8ae9b66SAlan Carew num_channels_enabled++; 546e8ae9b66SAlan Carew 547e8ae9b66SAlan Carew } 548e8ae9b66SAlan Carew return num_channels_enabled; 549e8ae9b66SAlan Carew } 550e8ae9b66SAlan Carew 551e8ae9b66SAlan Carew int 552221e7026SMarcin Hajkowski add_host_channels(void) 5533618326fSDavid Hunt { 5543618326fSDavid Hunt struct channel_info *chan_info; 5553618326fSDavid Hunt char socket_path[PATH_MAX]; 5563618326fSDavid Hunt int num_channels_enabled = 0; 5573618326fSDavid Hunt int ret; 558221e7026SMarcin Hajkowski struct core_info *ci; 559221e7026SMarcin Hajkowski struct channel_info *chan_infos[RTE_MAX_LCORE]; 560221e7026SMarcin Hajkowski int i; 5613618326fSDavid Hunt 562221e7026SMarcin Hajkowski for (i = 0; i < RTE_MAX_LCORE; i++) 563221e7026SMarcin Hajkowski chan_infos[i] = NULL; 5643618326fSDavid Hunt 565221e7026SMarcin Hajkowski ci = get_core_info(); 566221e7026SMarcin Hajkowski if (ci == NULL) { 567221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot allocate memory for core_info\n"); 5683618326fSDavid Hunt return 0; 5693618326fSDavid Hunt } 5703618326fSDavid Hunt 571221e7026SMarcin Hajkowski for (i = 0; i < ci->core_count; i++) { 572221e7026SMarcin Hajkowski if (ci->cd[i].global_enabled_cpus == 0) 573221e7026SMarcin Hajkowski continue; 574221e7026SMarcin Hajkowski 575221e7026SMarcin Hajkowski ret = fifo_path(socket_path, sizeof(socket_path), i); 576221e7026SMarcin Hajkowski if (ret < 0) 577221e7026SMarcin Hajkowski goto error; 578221e7026SMarcin Hajkowski 579221e7026SMarcin Hajkowski ret = mkfifo(socket_path, 0660); 580221e7026SMarcin Hajkowski RTE_LOG(DEBUG, CHANNEL_MANAGER, "TRY CREATE fifo '%s'\n", 581221e7026SMarcin Hajkowski socket_path); 582221e7026SMarcin Hajkowski if ((errno != EEXIST) && (ret < 0)) { 583221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot create fifo '%s' error: " 5843618326fSDavid Hunt "%s\n", socket_path, strerror(errno)); 585221e7026SMarcin Hajkowski goto error; 5863618326fSDavid Hunt } 5873618326fSDavid Hunt chan_info = rte_malloc(NULL, sizeof(*chan_info), 0); 5883618326fSDavid Hunt if (chan_info == NULL) { 5893618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 5903618326fSDavid Hunt "channel '%s'\n", socket_path); 591221e7026SMarcin Hajkowski goto error; 5923618326fSDavid Hunt } 593221e7026SMarcin Hajkowski chan_infos[i] = chan_info; 594135393d4SDavid Hunt strlcpy(chan_info->channel_path, socket_path, 595221e7026SMarcin Hajkowski sizeof(chan_info->channel_path)); 59660dea75fSLukasz Krakowiak 597221e7026SMarcin Hajkowski if (setup_host_channel_info(&chan_info, i) < 0) { 5983618326fSDavid Hunt rte_free(chan_info); 599221e7026SMarcin Hajkowski chan_infos[i] = NULL; 600221e7026SMarcin Hajkowski goto error; 6013618326fSDavid Hunt } 6023618326fSDavid Hunt num_channels_enabled++; 603221e7026SMarcin Hajkowski } 6043618326fSDavid Hunt 6053618326fSDavid Hunt return num_channels_enabled; 606221e7026SMarcin Hajkowski error: 607221e7026SMarcin Hajkowski /* Clean up the channels opened before we hit an error. */ 608221e7026SMarcin Hajkowski for (i = 0; i < ci->core_count; i++) { 609221e7026SMarcin Hajkowski if (chan_infos[i] != NULL) { 610221e7026SMarcin Hajkowski remove_channel_from_monitor(chan_infos[i]); 611221e7026SMarcin Hajkowski close(chan_infos[i]->fd); 612221e7026SMarcin Hajkowski rte_free(chan_infos[i]); 613221e7026SMarcin Hajkowski } 614221e7026SMarcin Hajkowski } 615221e7026SMarcin Hajkowski return 0; 6163618326fSDavid Hunt } 6173618326fSDavid Hunt 6183618326fSDavid Hunt int 619e8ae9b66SAlan Carew remove_channel(struct channel_info **chan_info_dptr) 620e8ae9b66SAlan Carew { 621e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 622e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 623e8ae9b66SAlan Carew 624e8ae9b66SAlan Carew close(chan_info->fd); 625e8ae9b66SAlan Carew 626e8ae9b66SAlan Carew vm_info = (struct virtual_machine_info *)chan_info->priv_info; 627e8ae9b66SAlan Carew 628e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 629fd73630eSDavid Hunt vm_info->channel_mask[chan_info->channel_num] = 0; 630e8ae9b66SAlan Carew vm_info->num_channels--; 631e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 632e8ae9b66SAlan Carew 633e8ae9b66SAlan Carew rte_free(chan_info); 634e8ae9b66SAlan Carew return 0; 635e8ae9b66SAlan Carew } 636e8ae9b66SAlan Carew 637e8ae9b66SAlan Carew int 638e8ae9b66SAlan Carew set_channel_status_all(const char *vm_name, enum channel_status status) 639e8ae9b66SAlan Carew { 640e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 641e8ae9b66SAlan Carew unsigned i; 642751227a0SDavid Hunt char mask[RTE_MAX_LCORE]; 643e8ae9b66SAlan Carew int num_channels_changed = 0; 644e8ae9b66SAlan Carew 645e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 646e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 647e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 648e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 649e8ae9b66SAlan Carew } 650e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 651e8ae9b66SAlan Carew if (vm_info == NULL) { 652e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to disable channels: VM '%s' " 653e8ae9b66SAlan Carew "not found\n", vm_name); 654e8ae9b66SAlan Carew return 0; 655e8ae9b66SAlan Carew } 656e8ae9b66SAlan Carew 657e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 658751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE); 659751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) { 660fd73630eSDavid Hunt if (mask[i] != 1) 661fd73630eSDavid Hunt continue; 662e8ae9b66SAlan Carew vm_info->channels[i]->status = status; 663e8ae9b66SAlan Carew num_channels_changed++; 664e8ae9b66SAlan Carew } 665e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 666e8ae9b66SAlan Carew return num_channels_changed; 667e8ae9b66SAlan Carew 668e8ae9b66SAlan Carew } 669e8ae9b66SAlan Carew 670e8ae9b66SAlan Carew int 671e8ae9b66SAlan Carew set_channel_status(const char *vm_name, unsigned *channel_list, 672e8ae9b66SAlan Carew unsigned len_channel_list, enum channel_status status) 673e8ae9b66SAlan Carew { 674e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 675e8ae9b66SAlan Carew unsigned i; 676e8ae9b66SAlan Carew int num_channels_changed = 0; 677e8ae9b66SAlan Carew 678e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 679e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 680e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 681e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 682e8ae9b66SAlan Carew } 683e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 684e8ae9b66SAlan Carew if (vm_info == NULL) { 685e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 686e8ae9b66SAlan Carew "not found\n", vm_name); 687e8ae9b66SAlan Carew return 0; 688e8ae9b66SAlan Carew } 689e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 690e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 691e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 692e8ae9b66SAlan Carew vm_info->channels[channel_list[i]]->status = status; 693e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 694e8ae9b66SAlan Carew num_channels_changed++; 695e8ae9b66SAlan Carew } 696e8ae9b66SAlan Carew } 697e8ae9b66SAlan Carew return num_channels_changed; 698e8ae9b66SAlan Carew } 699e8ae9b66SAlan Carew 700dff22404SDavid Hunt void 701dff22404SDavid Hunt get_all_vm(int *num_vm, int *num_vcpu) 702dff22404SDavid Hunt { 703dff22404SDavid Hunt 704dff22404SDavid Hunt virNodeInfo node_info; 705dff22404SDavid Hunt virDomainPtr *domptr; 706fd73630eSDavid Hunt int i, ii, numVcpus[MAX_VCPUS], n_vcpus; 707dff22404SDavid Hunt unsigned int jj; 708dff22404SDavid Hunt const char *vm_name; 709dff22404SDavid Hunt unsigned int domain_flags = VIR_CONNECT_LIST_DOMAINS_RUNNING | 710dff22404SDavid Hunt VIR_CONNECT_LIST_DOMAINS_PERSISTENT; 711dff22404SDavid Hunt unsigned int domain_flag = VIR_DOMAIN_VCPU_CONFIG; 712dff22404SDavid Hunt 713e0207366SDavid Hunt if (!global_hypervisor_available) 714e0207366SDavid Hunt return; 715dff22404SDavid Hunt 716751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE*global_maplen); 717dff22404SDavid Hunt if (virNodeGetInfo(global_vir_conn_ptr, &node_info)) { 718dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n"); 719dff22404SDavid Hunt return; 720dff22404SDavid Hunt } 721dff22404SDavid Hunt 722dff22404SDavid Hunt /* Returns number of pcpus */ 723dff22404SDavid Hunt global_n_host_cpus = (unsigned int)node_info.cpus; 724dff22404SDavid Hunt 725dff22404SDavid Hunt /* Returns number of active domains */ 726dff22404SDavid Hunt *num_vm = virConnectListAllDomains(global_vir_conn_ptr, &domptr, 727dff22404SDavid Hunt domain_flags); 728dff22404SDavid Hunt if (*num_vm <= 0) { 729dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "No Active Domains Running\n"); 730dff22404SDavid Hunt return; 731dff22404SDavid Hunt } 732dff22404SDavid Hunt 733dff22404SDavid Hunt for (i = 0; i < *num_vm; i++) { 734dff22404SDavid Hunt 735dff22404SDavid Hunt /* Get Domain Names */ 736dff22404SDavid Hunt vm_name = virDomainGetName(domptr[i]); 737dff22404SDavid Hunt lvm_info[i].vm_name = vm_name; 738dff22404SDavid Hunt 739dff22404SDavid Hunt /* Get Number of Vcpus */ 740dff22404SDavid Hunt numVcpus[i] = virDomainGetVcpusFlags(domptr[i], domain_flag); 741dff22404SDavid Hunt 742dff22404SDavid Hunt /* Get Number of VCpus & VcpuPinInfo */ 743dff22404SDavid Hunt n_vcpus = virDomainGetVcpuPinInfo(domptr[i], 744dff22404SDavid Hunt numVcpus[i], global_cpumaps, 745dff22404SDavid Hunt global_maplen, domain_flag); 746dff22404SDavid Hunt 747dff22404SDavid Hunt if ((int)n_vcpus > 0) { 748dff22404SDavid Hunt *num_vcpu = n_vcpus; 749dff22404SDavid Hunt lvm_info[i].num_cpus = n_vcpus; 750dff22404SDavid Hunt } 751dff22404SDavid Hunt 752dff22404SDavid Hunt /* Save pcpu in use by libvirt VMs */ 753dff22404SDavid Hunt for (ii = 0; ii < n_vcpus; ii++) { 754dff22404SDavid Hunt for (jj = 0; jj < global_n_host_cpus; jj++) { 755dff22404SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps, 756dff22404SDavid Hunt global_maplen, ii, jj) > 0) { 757fd73630eSDavid Hunt lvm_info[i].pcpus[ii] = jj; 758dff22404SDavid Hunt } 759dff22404SDavid Hunt } 760dff22404SDavid Hunt } 761dff22404SDavid Hunt } 762dff22404SDavid Hunt } 763dff22404SDavid Hunt 764e8ae9b66SAlan Carew int 765e8ae9b66SAlan Carew get_info_vm(const char *vm_name, struct vm_info *info) 766e8ae9b66SAlan Carew { 767e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 768e8ae9b66SAlan Carew unsigned i, channel_num = 0; 769751227a0SDavid Hunt char mask[RTE_MAX_LCORE]; 770e8ae9b66SAlan Carew 771e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 772e8ae9b66SAlan Carew if (vm_info == NULL) { 773e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 774e8ae9b66SAlan Carew return -1; 775e8ae9b66SAlan Carew } 776e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_ACTIVE; 777e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) 778e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_INACTIVE; 779e8ae9b66SAlan Carew 780e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 781e8ae9b66SAlan Carew 782751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE); 783751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) { 784fd73630eSDavid Hunt if (mask[i] != 1) 785fd73630eSDavid Hunt continue; 786e8ae9b66SAlan Carew info->channels[channel_num].channel_num = i; 787e8ae9b66SAlan Carew memcpy(info->channels[channel_num].channel_path, 788fd73630eSDavid Hunt vm_info->channels[i]->channel_path, 789fd73630eSDavid Hunt UNIX_PATH_MAX); 790fd73630eSDavid Hunt info->channels[channel_num].status = 791fd73630eSDavid Hunt vm_info->channels[i]->status; 792fd73630eSDavid Hunt info->channels[channel_num].fd = 793fd73630eSDavid Hunt vm_info->channels[i]->fd; 794e8ae9b66SAlan Carew channel_num++; 795e8ae9b66SAlan Carew } 796e8ae9b66SAlan Carew 7971deb502eSMarcin Hajkowski info->allow_query = vm_info->allow_query; 798e8ae9b66SAlan Carew info->num_channels = channel_num; 799e8ae9b66SAlan Carew info->num_vcpus = vm_info->info.nrVirtCpu; 800e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 801e8ae9b66SAlan Carew 802e8ae9b66SAlan Carew memcpy(info->name, vm_info->name, sizeof(vm_info->name)); 8035776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 804e8ae9b66SAlan Carew for (i = 0; i < info->num_vcpus; i++) { 8055776b7a3SDavid Hunt info->pcpu_map[i] = vm_info->pcpu_map[i]; 806e8ae9b66SAlan Carew } 8075776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 808e8ae9b66SAlan Carew return 0; 809e8ae9b66SAlan Carew } 810e8ae9b66SAlan Carew 811e8ae9b66SAlan Carew int 812e8ae9b66SAlan Carew add_vm(const char *vm_name) 813e8ae9b66SAlan Carew { 814e8ae9b66SAlan Carew struct virtual_machine_info *new_domain; 815e8ae9b66SAlan Carew virDomainPtr dom_ptr; 816e8ae9b66SAlan Carew int i; 817e8ae9b66SAlan Carew 818e8ae9b66SAlan Carew if (find_domain_by_name(vm_name) != NULL) { 819e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add VM: VM '%s' " 820e8ae9b66SAlan Carew "already exists\n", vm_name); 821e8ae9b66SAlan Carew return -1; 822e8ae9b66SAlan Carew } 823e8ae9b66SAlan Carew 824e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 825e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "No connection to hypervisor exists\n"); 826e8ae9b66SAlan Carew return -1; 827e8ae9b66SAlan Carew } 828e8ae9b66SAlan Carew dom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name); 829e8ae9b66SAlan Carew if (dom_ptr == NULL) { 830e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error on VM lookup with libvirt: " 831e8ae9b66SAlan Carew "VM '%s' not found\n", vm_name); 832e8ae9b66SAlan Carew return -1; 833e8ae9b66SAlan Carew } 834e8ae9b66SAlan Carew 835e8ae9b66SAlan Carew new_domain = rte_malloc("virtual_machine_info", sizeof(*new_domain), 836fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 837e8ae9b66SAlan Carew if (new_domain == NULL) { 838e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to allocate memory for VM " 839e8ae9b66SAlan Carew "info\n"); 840e8ae9b66SAlan Carew return -1; 841e8ae9b66SAlan Carew } 842e8ae9b66SAlan Carew new_domain->domainPtr = dom_ptr; 843e8ae9b66SAlan Carew if (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) { 844e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get libvirt VM info\n"); 845e8ae9b66SAlan Carew rte_free(new_domain); 846e8ae9b66SAlan Carew return -1; 847e8ae9b66SAlan Carew } 848751227a0SDavid Hunt if (new_domain->info.nrVirtCpu > RTE_MAX_LCORE) { 849e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error the number of virtual CPUs(%u) is " 850e8ae9b66SAlan Carew "greater than allowable(%d)\n", new_domain->info.nrVirtCpu, 851751227a0SDavid Hunt RTE_MAX_LCORE); 852e8ae9b66SAlan Carew rte_free(new_domain); 853e8ae9b66SAlan Carew return -1; 854e8ae9b66SAlan Carew } 855e8ae9b66SAlan Carew 856751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) 8575776b7a3SDavid Hunt new_domain->pcpu_map[i] = 0; 858751227a0SDavid Hunt 859e8ae9b66SAlan Carew if (update_pcpus_mask(new_domain) < 0) { 860e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting physical CPU pinning\n"); 861e8ae9b66SAlan Carew rte_free(new_domain); 862e8ae9b66SAlan Carew return -1; 863e8ae9b66SAlan Carew } 864e8ae9b66SAlan Carew strncpy(new_domain->name, vm_name, sizeof(new_domain->name)); 86542b3f505SDaniel Mrzyglod new_domain->name[sizeof(new_domain->name) - 1] = '\0'; 866751227a0SDavid Hunt memset(new_domain->channel_mask, 0, RTE_MAX_LCORE); 867e8ae9b66SAlan Carew new_domain->num_channels = 0; 868e8ae9b66SAlan Carew 869e8ae9b66SAlan Carew if (!virDomainIsActive(dom_ptr)) 870e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_INACTIVE; 871e8ae9b66SAlan Carew else 872e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_ACTIVE; 873e8ae9b66SAlan Carew 8741deb502eSMarcin Hajkowski new_domain->allow_query = 0; 875e8ae9b66SAlan Carew rte_spinlock_init(&(new_domain->config_spinlock)); 876e8ae9b66SAlan Carew LIST_INSERT_HEAD(&vm_list_head, new_domain, vms_info); 877e8ae9b66SAlan Carew return 0; 878e8ae9b66SAlan Carew } 879e8ae9b66SAlan Carew 880e8ae9b66SAlan Carew int 881e8ae9b66SAlan Carew remove_vm(const char *vm_name) 882e8ae9b66SAlan Carew { 883e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = find_domain_by_name(vm_name); 884e8ae9b66SAlan Carew 885e8ae9b66SAlan Carew if (vm_info == NULL) { 886e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM: VM '%s' " 887e8ae9b66SAlan Carew "not found\n", vm_name); 888e8ae9b66SAlan Carew return -1; 889e8ae9b66SAlan Carew } 890e8ae9b66SAlan Carew rte_spinlock_lock(&vm_info->config_spinlock); 891e8ae9b66SAlan Carew if (vm_info->num_channels != 0) { 892e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM '%s', there are " 893e8ae9b66SAlan Carew "%"PRId8" channels still active\n", 894e8ae9b66SAlan Carew vm_name, vm_info->num_channels); 895e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 896e8ae9b66SAlan Carew return -1; 897e8ae9b66SAlan Carew } 898e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 899e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 900e8ae9b66SAlan Carew rte_free(vm_info); 901e8ae9b66SAlan Carew return 0; 902e8ae9b66SAlan Carew } 903e8ae9b66SAlan Carew 9041deb502eSMarcin Hajkowski int 9051deb502eSMarcin Hajkowski set_query_status(char *vm_name, 9061deb502eSMarcin Hajkowski bool allow_query) 9071deb502eSMarcin Hajkowski { 9081deb502eSMarcin Hajkowski struct virtual_machine_info *vm_info; 9091deb502eSMarcin Hajkowski 9101deb502eSMarcin Hajkowski vm_info = find_domain_by_name(vm_name); 9111deb502eSMarcin Hajkowski if (vm_info == NULL) { 9121deb502eSMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 9131deb502eSMarcin Hajkowski return -1; 9141deb502eSMarcin Hajkowski } 9151deb502eSMarcin Hajkowski rte_spinlock_lock(&(vm_info->config_spinlock)); 9161deb502eSMarcin Hajkowski vm_info->allow_query = allow_query ? 1 : 0; 9171deb502eSMarcin Hajkowski rte_spinlock_unlock(&(vm_info->config_spinlock)); 9181deb502eSMarcin Hajkowski return 0; 9191deb502eSMarcin Hajkowski } 9201deb502eSMarcin Hajkowski 921e8ae9b66SAlan Carew static void 922e8ae9b66SAlan Carew disconnect_hypervisor(void) 923e8ae9b66SAlan Carew { 924e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 925e8ae9b66SAlan Carew virConnectClose(global_vir_conn_ptr); 926e8ae9b66SAlan Carew global_vir_conn_ptr = NULL; 927e8ae9b66SAlan Carew } 928e8ae9b66SAlan Carew } 929e8ae9b66SAlan Carew 930e8ae9b66SAlan Carew static int 931e8ae9b66SAlan Carew connect_hypervisor(const char *path) 932e8ae9b66SAlan Carew { 933e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 934e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error connecting to %s, connection " 935e8ae9b66SAlan Carew "already established\n", path); 936e8ae9b66SAlan Carew return -1; 937e8ae9b66SAlan Carew } 938e8ae9b66SAlan Carew global_vir_conn_ptr = virConnectOpen(path); 939e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 940e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error failed to open connection to " 941e8ae9b66SAlan Carew "Hypervisor '%s'\n", path); 942e8ae9b66SAlan Carew return -1; 943e8ae9b66SAlan Carew } 944e8ae9b66SAlan Carew return 0; 945e8ae9b66SAlan Carew } 946e8ae9b66SAlan Carew int 947e0207366SDavid Hunt channel_manager_init(const char *path __rte_unused) 948e8ae9b66SAlan Carew { 949f7f14fe3SYong Liu virNodeInfo info; 950e8ae9b66SAlan Carew 951e8ae9b66SAlan Carew LIST_INIT(&vm_list_head); 952e8ae9b66SAlan Carew if (connect_hypervisor(path) < 0) { 953e0207366SDavid Hunt global_n_host_cpus = 64; 954e0207366SDavid Hunt global_hypervisor_available = 0; 955e0207366SDavid Hunt RTE_LOG(INFO, CHANNEL_MANAGER, "Unable to initialize channel manager\n"); 956e0207366SDavid Hunt } else { 957e0207366SDavid Hunt global_hypervisor_available = 1; 958e8ae9b66SAlan Carew 959751227a0SDavid Hunt global_maplen = VIR_CPU_MAPLEN(RTE_MAX_LCORE); 960e8ae9b66SAlan Carew 961e0207366SDavid Hunt global_vircpuinfo = rte_zmalloc(NULL, 962e0207366SDavid Hunt sizeof(*global_vircpuinfo) * 963751227a0SDavid Hunt RTE_MAX_LCORE, RTE_CACHE_LINE_SIZE); 964e8ae9b66SAlan Carew if (global_vircpuinfo == NULL) { 965e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for CPU Info\n"); 966e8ae9b66SAlan Carew goto error; 967e8ae9b66SAlan Carew } 968e0207366SDavid Hunt global_cpumaps = rte_zmalloc(NULL, 969751227a0SDavid Hunt RTE_MAX_LCORE * global_maplen, 970fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 971e0207366SDavid Hunt if (global_cpumaps == NULL) 972e8ae9b66SAlan Carew goto error; 973e8ae9b66SAlan Carew 974f7f14fe3SYong Liu if (virNodeGetInfo(global_vir_conn_ptr, &info)) { 975f7f14fe3SYong Liu RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n"); 976e8ae9b66SAlan Carew goto error; 977e8ae9b66SAlan Carew } 978e0207366SDavid Hunt global_n_host_cpus = (unsigned int)info.cpus; 979e0207366SDavid Hunt } 980f7f14fe3SYong Liu 981e0207366SDavid Hunt 982e8ae9b66SAlan Carew 983751227a0SDavid Hunt if (global_n_host_cpus > RTE_MAX_LCORE) { 984e9f64db9SPablo de Lara RTE_LOG(WARNING, CHANNEL_MANAGER, "The number of host CPUs(%u) exceeds the " 985e9f64db9SPablo de Lara "maximum of %u. No cores over %u should be used.\n", 986751227a0SDavid Hunt global_n_host_cpus, RTE_MAX_LCORE, 987751227a0SDavid Hunt RTE_MAX_LCORE - 1); 988751227a0SDavid Hunt global_n_host_cpus = RTE_MAX_LCORE; 98967ff575eSMarvin Liu } 990e8ae9b66SAlan Carew 991e8ae9b66SAlan Carew return 0; 992e8ae9b66SAlan Carew error: 993e0207366SDavid Hunt if (global_hypervisor_available) 994e8ae9b66SAlan Carew disconnect_hypervisor(); 995e8ae9b66SAlan Carew return -1; 996e8ae9b66SAlan Carew } 997e8ae9b66SAlan Carew 998e8ae9b66SAlan Carew void 999e8ae9b66SAlan Carew channel_manager_exit(void) 1000e8ae9b66SAlan Carew { 1001e8ae9b66SAlan Carew unsigned i; 1002751227a0SDavid Hunt char mask[RTE_MAX_LCORE]; 1003e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 1004e8ae9b66SAlan Carew 1005e8ae9b66SAlan Carew LIST_FOREACH(vm_info, &vm_list_head, vms_info) { 1006e8ae9b66SAlan Carew 1007e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 1008e8ae9b66SAlan Carew 1009751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE); 1010751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) { 1011fd73630eSDavid Hunt if (mask[i] != 1) 1012fd73630eSDavid Hunt continue; 1013fd73630eSDavid Hunt remove_channel_from_monitor( 1014fd73630eSDavid Hunt vm_info->channels[i]); 1015e8ae9b66SAlan Carew close(vm_info->channels[i]->fd); 1016e8ae9b66SAlan Carew rte_free(vm_info->channels[i]); 1017e8ae9b66SAlan Carew } 1018e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 1019e8ae9b66SAlan Carew 1020e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 1021e8ae9b66SAlan Carew rte_free(vm_info); 1022e8ae9b66SAlan Carew } 1023e8ae9b66SAlan Carew 1024e0207366SDavid Hunt if (global_hypervisor_available) { 1025e0207366SDavid Hunt /* Only needed if hypervisor available */ 1026e8ae9b66SAlan Carew rte_free(global_cpumaps); 1027e8ae9b66SAlan Carew rte_free(global_vircpuinfo); 1028e8ae9b66SAlan Carew disconnect_hypervisor(); 1029e8ae9b66SAlan Carew } 1030e0207366SDavid Hunt } 1031