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 20*6723c0fcSBruce 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]; 535776b7a3SDavid Hunt uint16_t pcpu_map[CHANNEL_CMDS_MAX_CPUS]; 54e8ae9b66SAlan Carew struct channel_info *channels[CHANNEL_CMDS_MAX_VM_CHANNELS]; 55fd73630eSDavid Hunt char channel_mask[POWER_MGR_MAX_CPUS]; 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 84e8ae9b66SAlan Carew memset(global_cpumaps, 0, CHANNEL_CMDS_MAX_CPUS*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)* 99e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_CPUS); 100e8ae9b66SAlan Carew 101e8ae9b66SAlan Carew cpuinfo = global_vircpuinfo; 102e8ae9b66SAlan Carew 103e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo, 104e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_CPUS, 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: 111e8ae9b66SAlan Carew if (n_vcpus >= CHANNEL_CMDS_MAX_CPUS) { 112e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Number of vCPUS(%u) is out of range " 113e8ae9b66SAlan Carew "0...%d\n", n_vcpus, CHANNEL_CMDS_MAX_CPUS-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 141e8ae9b66SAlan Carew if (vcpu >= CHANNEL_CMDS_MAX_CPUS) { 142e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds max allowable(%d)\n", 143e8ae9b66SAlan Carew vcpu, CHANNEL_CMDS_MAX_CPUS-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 } 165e8ae9b66SAlan Carew memset(global_cpumaps, 0 , CHANNEL_CMDS_MAX_CPUS * 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 3483618326fSDavid Hunt static void 3493618326fSDavid Hunt fifo_path(char *dst, unsigned int len) 3503618326fSDavid Hunt { 3513618326fSDavid Hunt snprintf(dst, len, "%sfifo", CHANNEL_MGR_SOCKET_PATH); 3523618326fSDavid Hunt } 3533618326fSDavid Hunt 3543618326fSDavid Hunt static int 3553618326fSDavid Hunt setup_host_channel_info(struct channel_info **chan_info_dptr, 3563618326fSDavid Hunt unsigned int channel_num) 3573618326fSDavid Hunt { 3583618326fSDavid Hunt struct channel_info *chan_info = *chan_info_dptr; 3593618326fSDavid Hunt 3603618326fSDavid Hunt chan_info->channel_num = channel_num; 3613618326fSDavid Hunt chan_info->priv_info = (void *)NULL; 3623618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED; 3633618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_JSON; 3643618326fSDavid Hunt 3653618326fSDavid Hunt fifo_path(chan_info->channel_path, sizeof(chan_info->channel_path)); 3663618326fSDavid Hunt 3673618326fSDavid Hunt if (open_host_channel(chan_info) < 0) { 3683618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open host channel: " 3693618326fSDavid Hunt "'%s'\n", 3703618326fSDavid Hunt chan_info->channel_path); 3713618326fSDavid Hunt return -1; 3723618326fSDavid Hunt } 3733618326fSDavid Hunt if (add_channel_to_monitor(&chan_info) < 0) { 3743618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: " 3753618326fSDavid Hunt "'%s' to epoll ctl\n", 3763618326fSDavid Hunt chan_info->channel_path); 3773618326fSDavid Hunt return -1; 3783618326fSDavid Hunt 3793618326fSDavid Hunt } 3803618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED; 3813618326fSDavid Hunt return 0; 3823618326fSDavid Hunt } 3833618326fSDavid Hunt 384e8ae9b66SAlan Carew int 385e8ae9b66SAlan Carew add_all_channels(const char *vm_name) 386e8ae9b66SAlan Carew { 387e8ae9b66SAlan Carew DIR *d; 388e8ae9b66SAlan Carew struct dirent *dir; 389e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 390e8ae9b66SAlan Carew struct channel_info *chan_info; 391e8ae9b66SAlan Carew char *token, *remaining, *tail_ptr; 392e8ae9b66SAlan Carew char socket_name[PATH_MAX]; 393e8ae9b66SAlan Carew unsigned channel_num; 394e8ae9b66SAlan Carew int num_channels_enabled = 0; 395e8ae9b66SAlan Carew 396e8ae9b66SAlan Carew /* verify VM exists */ 397e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 398e8ae9b66SAlan Carew if (vm_info == NULL) { 399e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' not found" 400e8ae9b66SAlan Carew " during channel discovery\n", vm_name); 401e8ae9b66SAlan Carew return 0; 402e8ae9b66SAlan Carew } 403e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 404e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 405e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 406e8ae9b66SAlan Carew return 0; 407e8ae9b66SAlan Carew } 408e8ae9b66SAlan Carew d = opendir(CHANNEL_MGR_SOCKET_PATH); 409e8ae9b66SAlan Carew if (d == NULL) { 410e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error opening directory '%s': %s\n", 411e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, strerror(errno)); 412e8ae9b66SAlan Carew return -1; 413e8ae9b66SAlan Carew } 414e8ae9b66SAlan Carew while ((dir = readdir(d)) != NULL) { 415e8ae9b66SAlan Carew if (!strncmp(dir->d_name, ".", 1) || 416e8ae9b66SAlan Carew !strncmp(dir->d_name, "..", 2)) 417e8ae9b66SAlan Carew continue; 418e8ae9b66SAlan Carew 419*6723c0fcSBruce Richardson strlcpy(socket_name, dir->d_name, sizeof(socket_name)); 420e8ae9b66SAlan Carew remaining = socket_name; 421e8ae9b66SAlan Carew /* Extract vm_name from "<vm_name>.<channel_num>" */ 422e8ae9b66SAlan Carew token = strsep(&remaining, "."); 423e8ae9b66SAlan Carew if (remaining == NULL) 424e8ae9b66SAlan Carew continue; 425e8ae9b66SAlan Carew if (strncmp(vm_name, token, CHANNEL_MGR_MAX_NAME_LEN)) 426e8ae9b66SAlan Carew continue; 427e8ae9b66SAlan Carew 428e8ae9b66SAlan Carew /* remaining should contain only <channel_num> */ 429e8ae9b66SAlan Carew errno = 0; 430e8ae9b66SAlan Carew channel_num = (unsigned)strtol(remaining, &tail_ptr, 0); 431e8ae9b66SAlan Carew if ((errno != 0) || (remaining[0] == '\0') || 4325b628fe1SBruce Richardson tail_ptr == NULL || (*tail_ptr != '\0')) { 433e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Malformed channel name" 434e8ae9b66SAlan Carew "'%s' found it should be in the form of " 435e8ae9b66SAlan Carew "'<guest_name>.<channel_num>(decimal)'\n", 436e8ae9b66SAlan Carew dir->d_name); 437e8ae9b66SAlan Carew continue; 438e8ae9b66SAlan Carew } 439e8ae9b66SAlan Carew if (channel_num >= CHANNEL_CMDS_MAX_VM_CHANNELS) { 440e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Channel number(%u) is " 441e8ae9b66SAlan Carew "greater than max allowable: %d, skipping '%s%s'\n", 442e8ae9b66SAlan Carew channel_num, CHANNEL_CMDS_MAX_VM_CHANNELS-1, 443e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 444e8ae9b66SAlan Carew continue; 445e8ae9b66SAlan Carew } 446e8ae9b66SAlan Carew /* if channel has not been added previously */ 447e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_num)) 448e8ae9b66SAlan Carew continue; 449e8ae9b66SAlan Carew 450e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 451fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 452e8ae9b66SAlan Carew if (chan_info == NULL) { 453e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 454e8ae9b66SAlan Carew "channel '%s%s'\n", CHANNEL_MGR_SOCKET_PATH, dir->d_name); 455e8ae9b66SAlan Carew continue; 456e8ae9b66SAlan Carew } 457e8ae9b66SAlan Carew 458e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 459e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s", 460e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name); 461e8ae9b66SAlan Carew 462e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) { 463e8ae9b66SAlan Carew rte_free(chan_info); 464e8ae9b66SAlan Carew continue; 465e8ae9b66SAlan Carew } 466e8ae9b66SAlan Carew 467e8ae9b66SAlan Carew num_channels_enabled++; 468e8ae9b66SAlan Carew } 469e8ae9b66SAlan Carew closedir(d); 470e8ae9b66SAlan Carew return num_channels_enabled; 471e8ae9b66SAlan Carew } 472e8ae9b66SAlan Carew 473e8ae9b66SAlan Carew int 474e8ae9b66SAlan Carew add_channels(const char *vm_name, unsigned *channel_list, 475e8ae9b66SAlan Carew unsigned len_channel_list) 476e8ae9b66SAlan Carew { 477e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 478e8ae9b66SAlan Carew struct channel_info *chan_info; 479e8ae9b66SAlan Carew char socket_path[PATH_MAX]; 480e8ae9b66SAlan Carew unsigned i; 481e8ae9b66SAlan Carew int num_channels_enabled = 0; 482e8ae9b66SAlan Carew 483e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 484e8ae9b66SAlan Carew if (vm_info == NULL) { 485e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 486e8ae9b66SAlan Carew "not found\n", vm_name); 487e8ae9b66SAlan Carew return 0; 488e8ae9b66SAlan Carew } 489e8ae9b66SAlan Carew 490e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) { 491e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name); 492e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE; 493e8ae9b66SAlan Carew return 0; 494e8ae9b66SAlan Carew } 495e8ae9b66SAlan Carew 496e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 497e8ae9b66SAlan Carew 498e8ae9b66SAlan Carew if (channel_list[i] >= CHANNEL_CMDS_MAX_VM_CHANNELS) { 499e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel(%u) is out of range " 500e8ae9b66SAlan Carew "0...%d\n", channel_list[i], 501e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_VM_CHANNELS-1); 502e8ae9b66SAlan Carew continue; 503e8ae9b66SAlan Carew } 504e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 505e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel already exists, skipping " 506e8ae9b66SAlan Carew "'%s.%u'\n", vm_name, i); 507e8ae9b66SAlan Carew continue; 508e8ae9b66SAlan Carew } 509e8ae9b66SAlan Carew 510e8ae9b66SAlan Carew snprintf(socket_path, sizeof(socket_path), "%s%s.%u", 511e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 512e8ae9b66SAlan Carew errno = 0; 513e8ae9b66SAlan Carew if (access(socket_path, F_OK) < 0) { 514e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: " 515e8ae9b66SAlan Carew "%s\n", socket_path, strerror(errno)); 516e8ae9b66SAlan Carew continue; 517e8ae9b66SAlan Carew } 518e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info), 519fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 520e8ae9b66SAlan Carew if (chan_info == NULL) { 521e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 522e8ae9b66SAlan Carew "channel '%s'\n", socket_path); 523e8ae9b66SAlan Carew continue; 524e8ae9b66SAlan Carew } 525e8ae9b66SAlan Carew snprintf(chan_info->channel_path, 526e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s.%u", 527e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]); 528e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) { 529e8ae9b66SAlan Carew rte_free(chan_info); 530e8ae9b66SAlan Carew continue; 531e8ae9b66SAlan Carew } 532e8ae9b66SAlan Carew num_channels_enabled++; 533e8ae9b66SAlan Carew 534e8ae9b66SAlan Carew } 535e8ae9b66SAlan Carew return num_channels_enabled; 536e8ae9b66SAlan Carew } 537e8ae9b66SAlan Carew 538e8ae9b66SAlan Carew int 5393618326fSDavid Hunt add_host_channel(void) 5403618326fSDavid Hunt { 5413618326fSDavid Hunt struct channel_info *chan_info; 5423618326fSDavid Hunt char socket_path[PATH_MAX]; 5433618326fSDavid Hunt int num_channels_enabled = 0; 5443618326fSDavid Hunt int ret; 5453618326fSDavid Hunt 5463618326fSDavid Hunt fifo_path(socket_path, sizeof(socket_path)); 5473618326fSDavid Hunt 5483618326fSDavid Hunt ret = mkfifo(socket_path, 0660); 5493618326fSDavid Hunt if ((errno != EEXIST) && (ret < 0)) { 5503618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot create fifo '%s' error: " 5513618326fSDavid Hunt "%s\n", socket_path, strerror(errno)); 5523618326fSDavid Hunt return 0; 5533618326fSDavid Hunt } 5543618326fSDavid Hunt 5553618326fSDavid Hunt if (access(socket_path, F_OK) < 0) { 5563618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: " 5573618326fSDavid Hunt "%s\n", socket_path, strerror(errno)); 5583618326fSDavid Hunt return 0; 5593618326fSDavid Hunt } 5603618326fSDavid Hunt chan_info = rte_malloc(NULL, sizeof(*chan_info), 0); 5613618326fSDavid Hunt if (chan_info == NULL) { 5623618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for " 5633618326fSDavid Hunt "channel '%s'\n", socket_path); 5643618326fSDavid Hunt return 0; 5653618326fSDavid Hunt } 566*6723c0fcSBruce Richardson strlcpy(chan_info->channel_path, socket_path, 567*6723c0fcSBruce Richardson sizeof(chan_info->channel_path)); 5683618326fSDavid Hunt if (setup_host_channel_info(&chan_info, 0) < 0) { 5693618326fSDavid Hunt rte_free(chan_info); 5703618326fSDavid Hunt return 0; 5713618326fSDavid Hunt } 5723618326fSDavid Hunt num_channels_enabled++; 5733618326fSDavid Hunt 5743618326fSDavid Hunt return num_channels_enabled; 5753618326fSDavid Hunt } 5763618326fSDavid Hunt 5773618326fSDavid Hunt int 578e8ae9b66SAlan Carew remove_channel(struct channel_info **chan_info_dptr) 579e8ae9b66SAlan Carew { 580e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 581e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr; 582e8ae9b66SAlan Carew 583e8ae9b66SAlan Carew close(chan_info->fd); 584e8ae9b66SAlan Carew 585e8ae9b66SAlan Carew vm_info = (struct virtual_machine_info *)chan_info->priv_info; 586e8ae9b66SAlan Carew 587e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 588fd73630eSDavid Hunt vm_info->channel_mask[chan_info->channel_num] = 0; 589e8ae9b66SAlan Carew vm_info->num_channels--; 590e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 591e8ae9b66SAlan Carew 592e8ae9b66SAlan Carew rte_free(chan_info); 593e8ae9b66SAlan Carew return 0; 594e8ae9b66SAlan Carew } 595e8ae9b66SAlan Carew 596e8ae9b66SAlan Carew int 597e8ae9b66SAlan Carew set_channel_status_all(const char *vm_name, enum channel_status status) 598e8ae9b66SAlan Carew { 599e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 600e8ae9b66SAlan Carew unsigned i; 601fd73630eSDavid Hunt char mask[POWER_MGR_MAX_CPUS]; 602e8ae9b66SAlan Carew int num_channels_changed = 0; 603e8ae9b66SAlan Carew 604e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 605e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 606e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 607e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 608e8ae9b66SAlan Carew } 609e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 610e8ae9b66SAlan Carew if (vm_info == NULL) { 611e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to disable channels: VM '%s' " 612e8ae9b66SAlan Carew "not found\n", vm_name); 613e8ae9b66SAlan Carew return 0; 614e8ae9b66SAlan Carew } 615e8ae9b66SAlan Carew 616e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 617fd73630eSDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, POWER_MGR_MAX_CPUS); 618fd73630eSDavid Hunt for (i = 0; i < POWER_MGR_MAX_CPUS; i++) { 619fd73630eSDavid Hunt if (mask[i] != 1) 620fd73630eSDavid Hunt continue; 621e8ae9b66SAlan Carew vm_info->channels[i]->status = status; 622e8ae9b66SAlan Carew num_channels_changed++; 623e8ae9b66SAlan Carew } 624e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 625e8ae9b66SAlan Carew return num_channels_changed; 626e8ae9b66SAlan Carew 627e8ae9b66SAlan Carew } 628e8ae9b66SAlan Carew 629e8ae9b66SAlan Carew int 630e8ae9b66SAlan Carew set_channel_status(const char *vm_name, unsigned *channel_list, 631e8ae9b66SAlan Carew unsigned len_channel_list, enum channel_status status) 632e8ae9b66SAlan Carew { 633e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 634e8ae9b66SAlan Carew unsigned i; 635e8ae9b66SAlan Carew int num_channels_changed = 0; 636e8ae9b66SAlan Carew 637e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED || 638e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) { 639e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or " 640e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name); 641e8ae9b66SAlan Carew } 642e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 643e8ae9b66SAlan Carew if (vm_info == NULL) { 644e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' " 645e8ae9b66SAlan Carew "not found\n", vm_name); 646e8ae9b66SAlan Carew return 0; 647e8ae9b66SAlan Carew } 648e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) { 649e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) { 650e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 651e8ae9b66SAlan Carew vm_info->channels[channel_list[i]]->status = status; 652e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 653e8ae9b66SAlan Carew num_channels_changed++; 654e8ae9b66SAlan Carew } 655e8ae9b66SAlan Carew } 656e8ae9b66SAlan Carew return num_channels_changed; 657e8ae9b66SAlan Carew } 658e8ae9b66SAlan Carew 659dff22404SDavid Hunt void 660dff22404SDavid Hunt get_all_vm(int *num_vm, int *num_vcpu) 661dff22404SDavid Hunt { 662dff22404SDavid Hunt 663dff22404SDavid Hunt virNodeInfo node_info; 664dff22404SDavid Hunt virDomainPtr *domptr; 665fd73630eSDavid Hunt int i, ii, numVcpus[MAX_VCPUS], n_vcpus; 666dff22404SDavid Hunt unsigned int jj; 667dff22404SDavid Hunt const char *vm_name; 668dff22404SDavid Hunt unsigned int domain_flags = VIR_CONNECT_LIST_DOMAINS_RUNNING | 669dff22404SDavid Hunt VIR_CONNECT_LIST_DOMAINS_PERSISTENT; 670dff22404SDavid Hunt unsigned int domain_flag = VIR_DOMAIN_VCPU_CONFIG; 671dff22404SDavid Hunt 672e0207366SDavid Hunt if (!global_hypervisor_available) 673e0207366SDavid Hunt return; 674dff22404SDavid Hunt 675dff22404SDavid Hunt memset(global_cpumaps, 0, CHANNEL_CMDS_MAX_CPUS*global_maplen); 676dff22404SDavid Hunt if (virNodeGetInfo(global_vir_conn_ptr, &node_info)) { 677dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n"); 678dff22404SDavid Hunt return; 679dff22404SDavid Hunt } 680dff22404SDavid Hunt 681dff22404SDavid Hunt /* Returns number of pcpus */ 682dff22404SDavid Hunt global_n_host_cpus = (unsigned int)node_info.cpus; 683dff22404SDavid Hunt 684dff22404SDavid Hunt /* Returns number of active domains */ 685dff22404SDavid Hunt *num_vm = virConnectListAllDomains(global_vir_conn_ptr, &domptr, 686dff22404SDavid Hunt domain_flags); 687dff22404SDavid Hunt if (*num_vm <= 0) { 688dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "No Active Domains Running\n"); 689dff22404SDavid Hunt return; 690dff22404SDavid Hunt } 691dff22404SDavid Hunt 692dff22404SDavid Hunt for (i = 0; i < *num_vm; i++) { 693dff22404SDavid Hunt 694dff22404SDavid Hunt /* Get Domain Names */ 695dff22404SDavid Hunt vm_name = virDomainGetName(domptr[i]); 696dff22404SDavid Hunt lvm_info[i].vm_name = vm_name; 697dff22404SDavid Hunt 698dff22404SDavid Hunt /* Get Number of Vcpus */ 699dff22404SDavid Hunt numVcpus[i] = virDomainGetVcpusFlags(domptr[i], domain_flag); 700dff22404SDavid Hunt 701dff22404SDavid Hunt /* Get Number of VCpus & VcpuPinInfo */ 702dff22404SDavid Hunt n_vcpus = virDomainGetVcpuPinInfo(domptr[i], 703dff22404SDavid Hunt numVcpus[i], global_cpumaps, 704dff22404SDavid Hunt global_maplen, domain_flag); 705dff22404SDavid Hunt 706dff22404SDavid Hunt if ((int)n_vcpus > 0) { 707dff22404SDavid Hunt *num_vcpu = n_vcpus; 708dff22404SDavid Hunt lvm_info[i].num_cpus = n_vcpus; 709dff22404SDavid Hunt } 710dff22404SDavid Hunt 711dff22404SDavid Hunt /* Save pcpu in use by libvirt VMs */ 712dff22404SDavid Hunt for (ii = 0; ii < n_vcpus; ii++) { 713dff22404SDavid Hunt for (jj = 0; jj < global_n_host_cpus; jj++) { 714dff22404SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps, 715dff22404SDavid Hunt global_maplen, ii, jj) > 0) { 716fd73630eSDavid Hunt lvm_info[i].pcpus[ii] = jj; 717dff22404SDavid Hunt } 718dff22404SDavid Hunt } 719dff22404SDavid Hunt } 720dff22404SDavid Hunt } 721dff22404SDavid Hunt } 722dff22404SDavid Hunt 723e8ae9b66SAlan Carew int 724e8ae9b66SAlan Carew get_info_vm(const char *vm_name, struct vm_info *info) 725e8ae9b66SAlan Carew { 726e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 727e8ae9b66SAlan Carew unsigned i, channel_num = 0; 728fd73630eSDavid Hunt char mask[POWER_MGR_MAX_CPUS]; 729e8ae9b66SAlan Carew 730e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name); 731e8ae9b66SAlan Carew if (vm_info == NULL) { 732e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name); 733e8ae9b66SAlan Carew return -1; 734e8ae9b66SAlan Carew } 735e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_ACTIVE; 736e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) 737e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_INACTIVE; 738e8ae9b66SAlan Carew 739e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 740e8ae9b66SAlan Carew 741fd73630eSDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, POWER_MGR_MAX_CPUS); 742fd73630eSDavid Hunt for (i = 0; i < POWER_MGR_MAX_CPUS; i++) { 743fd73630eSDavid Hunt if (mask[i] != 1) 744fd73630eSDavid Hunt continue; 745e8ae9b66SAlan Carew info->channels[channel_num].channel_num = i; 746e8ae9b66SAlan Carew memcpy(info->channels[channel_num].channel_path, 747fd73630eSDavid Hunt vm_info->channels[i]->channel_path, 748fd73630eSDavid Hunt UNIX_PATH_MAX); 749fd73630eSDavid Hunt info->channels[channel_num].status = 750fd73630eSDavid Hunt vm_info->channels[i]->status; 751fd73630eSDavid Hunt info->channels[channel_num].fd = 752fd73630eSDavid Hunt vm_info->channels[i]->fd; 753e8ae9b66SAlan Carew channel_num++; 754e8ae9b66SAlan Carew } 755e8ae9b66SAlan Carew 756e8ae9b66SAlan Carew info->num_channels = channel_num; 757e8ae9b66SAlan Carew info->num_vcpus = vm_info->info.nrVirtCpu; 758e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 759e8ae9b66SAlan Carew 760e8ae9b66SAlan Carew memcpy(info->name, vm_info->name, sizeof(vm_info->name)); 7615776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock)); 762e8ae9b66SAlan Carew for (i = 0; i < info->num_vcpus; i++) { 7635776b7a3SDavid Hunt info->pcpu_map[i] = vm_info->pcpu_map[i]; 764e8ae9b66SAlan Carew } 7655776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock)); 766e8ae9b66SAlan Carew return 0; 767e8ae9b66SAlan Carew } 768e8ae9b66SAlan Carew 769e8ae9b66SAlan Carew int 770e8ae9b66SAlan Carew add_vm(const char *vm_name) 771e8ae9b66SAlan Carew { 772e8ae9b66SAlan Carew struct virtual_machine_info *new_domain; 773e8ae9b66SAlan Carew virDomainPtr dom_ptr; 774e8ae9b66SAlan Carew int i; 775e8ae9b66SAlan Carew 776e8ae9b66SAlan Carew if (find_domain_by_name(vm_name) != NULL) { 777e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add VM: VM '%s' " 778e8ae9b66SAlan Carew "already exists\n", vm_name); 779e8ae9b66SAlan Carew return -1; 780e8ae9b66SAlan Carew } 781e8ae9b66SAlan Carew 782e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 783e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "No connection to hypervisor exists\n"); 784e8ae9b66SAlan Carew return -1; 785e8ae9b66SAlan Carew } 786e8ae9b66SAlan Carew dom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name); 787e8ae9b66SAlan Carew if (dom_ptr == NULL) { 788e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error on VM lookup with libvirt: " 789e8ae9b66SAlan Carew "VM '%s' not found\n", vm_name); 790e8ae9b66SAlan Carew return -1; 791e8ae9b66SAlan Carew } 792e8ae9b66SAlan Carew 793e8ae9b66SAlan Carew new_domain = rte_malloc("virtual_machine_info", sizeof(*new_domain), 794fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 795e8ae9b66SAlan Carew if (new_domain == NULL) { 796e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to allocate memory for VM " 797e8ae9b66SAlan Carew "info\n"); 798e8ae9b66SAlan Carew return -1; 799e8ae9b66SAlan Carew } 800e8ae9b66SAlan Carew new_domain->domainPtr = dom_ptr; 801e8ae9b66SAlan Carew if (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) { 802e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get libvirt VM info\n"); 803e8ae9b66SAlan Carew rte_free(new_domain); 804e8ae9b66SAlan Carew return -1; 805e8ae9b66SAlan Carew } 806e8ae9b66SAlan Carew if (new_domain->info.nrVirtCpu > CHANNEL_CMDS_MAX_CPUS) { 807e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error the number of virtual CPUs(%u) is " 808e8ae9b66SAlan Carew "greater than allowable(%d)\n", new_domain->info.nrVirtCpu, 809e8ae9b66SAlan Carew CHANNEL_CMDS_MAX_CPUS); 810e8ae9b66SAlan Carew rte_free(new_domain); 811e8ae9b66SAlan Carew return -1; 812e8ae9b66SAlan Carew } 813e8ae9b66SAlan Carew 814e8ae9b66SAlan Carew for (i = 0; i < CHANNEL_CMDS_MAX_CPUS; i++) { 8155776b7a3SDavid Hunt new_domain->pcpu_map[i] = 0; 816e8ae9b66SAlan Carew } 817e8ae9b66SAlan Carew if (update_pcpus_mask(new_domain) < 0) { 818e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting physical CPU pinning\n"); 819e8ae9b66SAlan Carew rte_free(new_domain); 820e8ae9b66SAlan Carew return -1; 821e8ae9b66SAlan Carew } 822e8ae9b66SAlan Carew strncpy(new_domain->name, vm_name, sizeof(new_domain->name)); 82342b3f505SDaniel Mrzyglod new_domain->name[sizeof(new_domain->name) - 1] = '\0'; 824fd73630eSDavid Hunt memset(new_domain->channel_mask, 0, POWER_MGR_MAX_CPUS); 825e8ae9b66SAlan Carew new_domain->num_channels = 0; 826e8ae9b66SAlan Carew 827e8ae9b66SAlan Carew if (!virDomainIsActive(dom_ptr)) 828e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_INACTIVE; 829e8ae9b66SAlan Carew else 830e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_ACTIVE; 831e8ae9b66SAlan Carew 832e8ae9b66SAlan Carew rte_spinlock_init(&(new_domain->config_spinlock)); 833e8ae9b66SAlan Carew LIST_INSERT_HEAD(&vm_list_head, new_domain, vms_info); 834e8ae9b66SAlan Carew return 0; 835e8ae9b66SAlan Carew } 836e8ae9b66SAlan Carew 837e8ae9b66SAlan Carew int 838e8ae9b66SAlan Carew remove_vm(const char *vm_name) 839e8ae9b66SAlan Carew { 840e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = find_domain_by_name(vm_name); 841e8ae9b66SAlan Carew 842e8ae9b66SAlan Carew if (vm_info == NULL) { 843e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM: VM '%s' " 844e8ae9b66SAlan Carew "not found\n", vm_name); 845e8ae9b66SAlan Carew return -1; 846e8ae9b66SAlan Carew } 847e8ae9b66SAlan Carew rte_spinlock_lock(&vm_info->config_spinlock); 848e8ae9b66SAlan Carew if (vm_info->num_channels != 0) { 849e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM '%s', there are " 850e8ae9b66SAlan Carew "%"PRId8" channels still active\n", 851e8ae9b66SAlan Carew vm_name, vm_info->num_channels); 852e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 853e8ae9b66SAlan Carew return -1; 854e8ae9b66SAlan Carew } 855e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 856e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock); 857e8ae9b66SAlan Carew rte_free(vm_info); 858e8ae9b66SAlan Carew return 0; 859e8ae9b66SAlan Carew } 860e8ae9b66SAlan Carew 861e8ae9b66SAlan Carew static void 862e8ae9b66SAlan Carew disconnect_hypervisor(void) 863e8ae9b66SAlan Carew { 864e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 865e8ae9b66SAlan Carew virConnectClose(global_vir_conn_ptr); 866e8ae9b66SAlan Carew global_vir_conn_ptr = NULL; 867e8ae9b66SAlan Carew } 868e8ae9b66SAlan Carew } 869e8ae9b66SAlan Carew 870e8ae9b66SAlan Carew static int 871e8ae9b66SAlan Carew connect_hypervisor(const char *path) 872e8ae9b66SAlan Carew { 873e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) { 874e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error connecting to %s, connection " 875e8ae9b66SAlan Carew "already established\n", path); 876e8ae9b66SAlan Carew return -1; 877e8ae9b66SAlan Carew } 878e8ae9b66SAlan Carew global_vir_conn_ptr = virConnectOpen(path); 879e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) { 880e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error failed to open connection to " 881e8ae9b66SAlan Carew "Hypervisor '%s'\n", path); 882e8ae9b66SAlan Carew return -1; 883e8ae9b66SAlan Carew } 884e8ae9b66SAlan Carew return 0; 885e8ae9b66SAlan Carew } 886e8ae9b66SAlan Carew int 887e0207366SDavid Hunt channel_manager_init(const char *path __rte_unused) 888e8ae9b66SAlan Carew { 889f7f14fe3SYong Liu virNodeInfo info; 890e8ae9b66SAlan Carew 891e8ae9b66SAlan Carew LIST_INIT(&vm_list_head); 892e8ae9b66SAlan Carew if (connect_hypervisor(path) < 0) { 893e0207366SDavid Hunt global_n_host_cpus = 64; 894e0207366SDavid Hunt global_hypervisor_available = 0; 895e0207366SDavid Hunt RTE_LOG(INFO, CHANNEL_MANAGER, "Unable to initialize channel manager\n"); 896e0207366SDavid Hunt } else { 897e0207366SDavid Hunt global_hypervisor_available = 1; 898e8ae9b66SAlan Carew 899e8ae9b66SAlan Carew global_maplen = VIR_CPU_MAPLEN(CHANNEL_CMDS_MAX_CPUS); 900e8ae9b66SAlan Carew 901e0207366SDavid Hunt global_vircpuinfo = rte_zmalloc(NULL, 902e0207366SDavid Hunt sizeof(*global_vircpuinfo) * 903fdf20fa7SSergio Gonzalez Monroy CHANNEL_CMDS_MAX_CPUS, RTE_CACHE_LINE_SIZE); 904e8ae9b66SAlan Carew if (global_vircpuinfo == NULL) { 905e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for CPU Info\n"); 906e8ae9b66SAlan Carew goto error; 907e8ae9b66SAlan Carew } 908e0207366SDavid Hunt global_cpumaps = rte_zmalloc(NULL, 909e0207366SDavid Hunt CHANNEL_CMDS_MAX_CPUS * global_maplen, 910fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE); 911e0207366SDavid Hunt if (global_cpumaps == NULL) 912e8ae9b66SAlan Carew goto error; 913e8ae9b66SAlan Carew 914f7f14fe3SYong Liu if (virNodeGetInfo(global_vir_conn_ptr, &info)) { 915f7f14fe3SYong Liu RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n"); 916e8ae9b66SAlan Carew goto error; 917e8ae9b66SAlan Carew } 918e0207366SDavid Hunt global_n_host_cpus = (unsigned int)info.cpus; 919e0207366SDavid Hunt } 920f7f14fe3SYong Liu 921e0207366SDavid Hunt 922e8ae9b66SAlan Carew 92367ff575eSMarvin Liu if (global_n_host_cpus > CHANNEL_CMDS_MAX_CPUS) { 924e9f64db9SPablo de Lara RTE_LOG(WARNING, CHANNEL_MANAGER, "The number of host CPUs(%u) exceeds the " 925e9f64db9SPablo de Lara "maximum of %u. No cores over %u should be used.\n", 926e9f64db9SPablo de Lara global_n_host_cpus, CHANNEL_CMDS_MAX_CPUS, 927e9f64db9SPablo de Lara CHANNEL_CMDS_MAX_CPUS - 1); 92867ff575eSMarvin Liu global_n_host_cpus = CHANNEL_CMDS_MAX_CPUS; 92967ff575eSMarvin Liu } 930e8ae9b66SAlan Carew 931e8ae9b66SAlan Carew return 0; 932e8ae9b66SAlan Carew error: 933e0207366SDavid Hunt if (global_hypervisor_available) 934e8ae9b66SAlan Carew disconnect_hypervisor(); 935e8ae9b66SAlan Carew return -1; 936e8ae9b66SAlan Carew } 937e8ae9b66SAlan Carew 938e8ae9b66SAlan Carew void 939e8ae9b66SAlan Carew channel_manager_exit(void) 940e8ae9b66SAlan Carew { 941e8ae9b66SAlan Carew unsigned i; 942fd73630eSDavid Hunt char mask[POWER_MGR_MAX_CPUS]; 943e8ae9b66SAlan Carew struct virtual_machine_info *vm_info; 944e8ae9b66SAlan Carew 945e8ae9b66SAlan Carew LIST_FOREACH(vm_info, &vm_list_head, vms_info) { 946e8ae9b66SAlan Carew 947e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock)); 948e8ae9b66SAlan Carew 949fd73630eSDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, POWER_MGR_MAX_CPUS); 950fd73630eSDavid Hunt for (i = 0; i < POWER_MGR_MAX_CPUS; i++) { 951fd73630eSDavid Hunt if (mask[i] != 1) 952fd73630eSDavid Hunt continue; 953fd73630eSDavid Hunt remove_channel_from_monitor( 954fd73630eSDavid Hunt vm_info->channels[i]); 955e8ae9b66SAlan Carew close(vm_info->channels[i]->fd); 956e8ae9b66SAlan Carew rte_free(vm_info->channels[i]); 957e8ae9b66SAlan Carew } 958e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock)); 959e8ae9b66SAlan Carew 960e8ae9b66SAlan Carew LIST_REMOVE(vm_info, vms_info); 961e8ae9b66SAlan Carew rte_free(vm_info); 962e8ae9b66SAlan Carew } 963e8ae9b66SAlan Carew 964e0207366SDavid Hunt if (global_hypervisor_available) { 965e0207366SDavid Hunt /* Only needed if hypervisor available */ 966e8ae9b66SAlan Carew rte_free(global_cpumaps); 967e8ae9b66SAlan Carew rte_free(global_vircpuinfo); 968e8ae9b66SAlan Carew disconnect_hypervisor(); 969e8ae9b66SAlan Carew } 970e0207366SDavid Hunt } 971