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 <fcntl.h>
8e8ae9b66SAlan Carew #include <unistd.h>
9e8ae9b66SAlan Carew #include <inttypes.h>
10e8ae9b66SAlan Carew #include <dirent.h>
11e8ae9b66SAlan Carew #include <errno.h>
12e8ae9b66SAlan Carew
13e8ae9b66SAlan Carew #include <sys/queue.h>
14e8ae9b66SAlan Carew #include <sys/types.h>
153618326fSDavid Hunt #include <sys/stat.h>
16e8ae9b66SAlan Carew #include <sys/socket.h>
17e8ae9b66SAlan Carew #include <sys/select.h>
18e8ae9b66SAlan Carew
196723c0fcSBruce Richardson #include <rte_string_fns.h>
20e8ae9b66SAlan Carew #include <rte_malloc.h>
21e8ae9b66SAlan Carew #include <rte_memory.h>
22e8ae9b66SAlan Carew #include <rte_mempool.h>
23e8ae9b66SAlan Carew #include <rte_log.h>
24e8ae9b66SAlan Carew #include <rte_spinlock.h>
25*9c20d0fdSHamza Khan #include <rte_tailq.h>
26e8ae9b66SAlan Carew
27e8ae9b66SAlan Carew #include <libvirt/libvirt.h>
28e8ae9b66SAlan Carew
29e8ae9b66SAlan Carew #include "channel_manager.h"
30e8ae9b66SAlan Carew #include "channel_monitor.h"
31fd73630eSDavid Hunt #include "power_manager.h"
32e8ae9b66SAlan Carew
33e8ae9b66SAlan Carew
34e8ae9b66SAlan Carew #define RTE_LOGTYPE_CHANNEL_MANAGER RTE_LOGTYPE_USER1
35e8ae9b66SAlan Carew
3696d3d532SThomas Monjalon struct libvirt_vm_info lvm_info[MAX_CLIENTS];
3796d3d532SThomas Monjalon
38e8ae9b66SAlan Carew /* Global pointer to libvirt connection */
39e8ae9b66SAlan Carew static virConnectPtr global_vir_conn_ptr;
40e8ae9b66SAlan Carew
41e8ae9b66SAlan Carew static unsigned char *global_cpumaps;
42e8ae9b66SAlan Carew static virVcpuInfo *global_vircpuinfo;
43e8ae9b66SAlan Carew static size_t global_maplen;
44e8ae9b66SAlan Carew
45e0207366SDavid Hunt static unsigned int global_n_host_cpus;
46e0207366SDavid Hunt static bool global_hypervisor_available;
47e8ae9b66SAlan Carew
48e8ae9b66SAlan Carew /*
49e8ae9b66SAlan Carew * Represents a single Virtual Machine
50e8ae9b66SAlan Carew */
51e8ae9b66SAlan Carew struct virtual_machine_info {
52e8ae9b66SAlan Carew char name[CHANNEL_MGR_MAX_NAME_LEN];
53751227a0SDavid Hunt uint16_t pcpu_map[RTE_MAX_LCORE];
54751227a0SDavid Hunt struct channel_info *channels[RTE_MAX_LCORE];
55751227a0SDavid Hunt char channel_mask[RTE_MAX_LCORE];
56e8ae9b66SAlan Carew uint8_t num_channels;
57e8ae9b66SAlan Carew enum vm_status status;
58e8ae9b66SAlan Carew virDomainPtr domainPtr;
59e8ae9b66SAlan Carew virDomainInfo info;
60e8ae9b66SAlan Carew rte_spinlock_t config_spinlock;
611deb502eSMarcin Hajkowski int allow_query;
62*9c20d0fdSHamza Khan RTE_TAILQ_ENTRY(virtual_machine_info) vms_info;
63e8ae9b66SAlan Carew };
64e8ae9b66SAlan Carew
65*9c20d0fdSHamza Khan RTE_TAILQ_HEAD(, virtual_machine_info) vm_list_head;
66e8ae9b66SAlan Carew
67e8ae9b66SAlan Carew static struct virtual_machine_info *
find_domain_by_name(const char * name)68e8ae9b66SAlan Carew find_domain_by_name(const char *name)
69e8ae9b66SAlan Carew {
70e8ae9b66SAlan Carew struct virtual_machine_info *info;
71*9c20d0fdSHamza Khan RTE_TAILQ_FOREACH(info, &vm_list_head, vms_info) {
72e8ae9b66SAlan Carew if (!strncmp(info->name, name, CHANNEL_MGR_MAX_NAME_LEN-1))
73e8ae9b66SAlan Carew return info;
74e8ae9b66SAlan Carew }
75e8ae9b66SAlan Carew return NULL;
76e8ae9b66SAlan Carew }
77e8ae9b66SAlan Carew
78e8ae9b66SAlan Carew static int
update_pcpus_mask(struct virtual_machine_info * vm_info)79e8ae9b66SAlan Carew update_pcpus_mask(struct virtual_machine_info *vm_info)
80e8ae9b66SAlan Carew {
81e8ae9b66SAlan Carew virVcpuInfoPtr cpuinfo;
82e8ae9b66SAlan Carew unsigned i, j;
83e8ae9b66SAlan Carew int n_vcpus;
84e8ae9b66SAlan Carew
85751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE*global_maplen);
86e8ae9b66SAlan Carew
87e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) {
88e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpuPinInfo(vm_info->domainPtr,
89e8ae9b66SAlan Carew vm_info->info.nrVirtCpu, global_cpumaps, global_maplen,
90e8ae9b66SAlan Carew VIR_DOMAIN_AFFECT_CONFIG);
91e8ae9b66SAlan Carew if (n_vcpus < 0) {
92e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for "
93e8ae9b66SAlan Carew "in-active VM '%s'\n", vm_info->name);
94e8ae9b66SAlan Carew return -1;
95e8ae9b66SAlan Carew }
96e8ae9b66SAlan Carew goto update_pcpus;
97e8ae9b66SAlan Carew }
98e8ae9b66SAlan Carew
99e8ae9b66SAlan Carew memset(global_vircpuinfo, 0, sizeof(*global_vircpuinfo)*
100751227a0SDavid Hunt RTE_MAX_LCORE);
101e8ae9b66SAlan Carew
102e8ae9b66SAlan Carew cpuinfo = global_vircpuinfo;
103e8ae9b66SAlan Carew
104e8ae9b66SAlan Carew n_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo,
105751227a0SDavid Hunt RTE_MAX_LCORE, global_cpumaps, global_maplen);
106e8ae9b66SAlan Carew if (n_vcpus < 0) {
107e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for "
108e8ae9b66SAlan Carew "active VM '%s'\n", vm_info->name);
109e8ae9b66SAlan Carew return -1;
110e8ae9b66SAlan Carew }
111e8ae9b66SAlan Carew update_pcpus:
112751227a0SDavid Hunt if (n_vcpus >= RTE_MAX_LCORE) {
113e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Number of vCPUS(%u) is out of range "
114751227a0SDavid Hunt "0...%d\n", n_vcpus, RTE_MAX_LCORE-1);
115e8ae9b66SAlan Carew return -1;
116e8ae9b66SAlan Carew }
117e8ae9b66SAlan Carew if (n_vcpus != vm_info->info.nrVirtCpu) {
118e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Updating the number of vCPUs for VM '%s"
119e8ae9b66SAlan Carew " from %d -> %d\n", vm_info->name, vm_info->info.nrVirtCpu,
120e8ae9b66SAlan Carew n_vcpus);
121e8ae9b66SAlan Carew vm_info->info.nrVirtCpu = n_vcpus;
122e8ae9b66SAlan Carew }
1235776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock));
124e8ae9b66SAlan Carew for (i = 0; i < vm_info->info.nrVirtCpu; i++) {
125e8ae9b66SAlan Carew for (j = 0; j < global_n_host_cpus; j++) {
1265776b7a3SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps,
1275776b7a3SDavid Hunt global_maplen, i, j) <= 0)
1285776b7a3SDavid Hunt continue;
1295776b7a3SDavid Hunt vm_info->pcpu_map[i] = j;
130e8ae9b66SAlan Carew }
131e8ae9b66SAlan Carew }
1325776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock));
133e8ae9b66SAlan Carew return 0;
134e8ae9b66SAlan Carew }
135e8ae9b66SAlan Carew
136e8ae9b66SAlan Carew int
set_pcpu(char * vm_name,unsigned int vcpu,unsigned int pcpu)1375776b7a3SDavid Hunt set_pcpu(char *vm_name, unsigned int vcpu, unsigned int pcpu)
138e8ae9b66SAlan Carew {
139e8ae9b66SAlan Carew int flags = VIR_DOMAIN_AFFECT_LIVE|VIR_DOMAIN_AFFECT_CONFIG;
140e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
141e8ae9b66SAlan Carew
142751227a0SDavid Hunt if (vcpu >= RTE_MAX_LCORE) {
143e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds max allowable(%d)\n",
144751227a0SDavid Hunt vcpu, RTE_MAX_LCORE-1);
145e8ae9b66SAlan Carew return -1;
146e8ae9b66SAlan Carew }
147e8ae9b66SAlan Carew
148e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name);
149e8ae9b66SAlan Carew if (vm_info == NULL) {
150e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name);
151e8ae9b66SAlan Carew return -1;
152e8ae9b66SAlan Carew }
153e8ae9b66SAlan Carew
154e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) {
155e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU "
156fd73630eSDavid Hunt " for VM '%s', VM is not active\n",
157fd73630eSDavid Hunt vcpu, vm_info->name);
158e8ae9b66SAlan Carew return -1;
159e8ae9b66SAlan Carew }
160e8ae9b66SAlan Carew
161e8ae9b66SAlan Carew if (vcpu >= vm_info->info.nrVirtCpu) {
162e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds the assigned number of "
163e8ae9b66SAlan Carew "vCPUs(%u)\n", vcpu, vm_info->info.nrVirtCpu);
164e8ae9b66SAlan Carew return -1;
165e8ae9b66SAlan Carew }
166751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE * global_maplen);
1675776b7a3SDavid Hunt
1685776b7a3SDavid Hunt VIR_USE_CPU(global_cpumaps, pcpu);
1695776b7a3SDavid Hunt
1705776b7a3SDavid Hunt if (pcpu >= global_n_host_cpus) {
171e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "CPU(%u) exceeds the available "
172fd73630eSDavid Hunt "number of CPUs(%u)\n",
1735776b7a3SDavid Hunt pcpu, global_n_host_cpus);
174e8ae9b66SAlan Carew return -1;
175e8ae9b66SAlan Carew }
1765776b7a3SDavid Hunt
177e8ae9b66SAlan Carew if (virDomainPinVcpuFlags(vm_info->domainPtr, vcpu, global_cpumaps,
178e8ae9b66SAlan Carew global_maplen, flags) < 0) {
179e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU "
180fd73630eSDavid Hunt " for VM '%s'\n", vcpu,
181e8ae9b66SAlan Carew vm_info->name);
182e8ae9b66SAlan Carew return -1;
183e8ae9b66SAlan Carew }
184fd73630eSDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock));
1855776b7a3SDavid Hunt vm_info->pcpu_map[vcpu] = pcpu;
186fd73630eSDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock));
187e8ae9b66SAlan Carew return 0;
188e8ae9b66SAlan Carew }
189e8ae9b66SAlan Carew
1905776b7a3SDavid Hunt uint16_t
get_pcpu(struct channel_info * chan_info,unsigned int vcpu)1915776b7a3SDavid Hunt get_pcpu(struct channel_info *chan_info, unsigned int vcpu)
192e8ae9b66SAlan Carew {
193e8ae9b66SAlan Carew struct virtual_machine_info *vm_info =
194e8ae9b66SAlan Carew (struct virtual_machine_info *)chan_info->priv_info;
195e0207366SDavid Hunt
1965776b7a3SDavid Hunt if (global_hypervisor_available && (vm_info != NULL)) {
1975776b7a3SDavid Hunt uint16_t pcpu;
1985776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock));
1995776b7a3SDavid Hunt pcpu = vm_info->pcpu_map[vcpu];
2005776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock));
2015776b7a3SDavid Hunt return pcpu;
2025776b7a3SDavid Hunt } else
203e0207366SDavid Hunt return 0;
204e8ae9b66SAlan Carew }
205e8ae9b66SAlan Carew
206e8ae9b66SAlan Carew static inline int
channel_exists(struct virtual_machine_info * vm_info,unsigned channel_num)207e8ae9b66SAlan Carew channel_exists(struct virtual_machine_info *vm_info, unsigned channel_num)
208e8ae9b66SAlan Carew {
209e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
210fd73630eSDavid Hunt if (vm_info->channel_mask[channel_num] == 1) {
211e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
212e8ae9b66SAlan Carew return 1;
213e8ae9b66SAlan Carew }
214e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
215e8ae9b66SAlan Carew return 0;
216e8ae9b66SAlan Carew }
217e8ae9b66SAlan Carew
218e8ae9b66SAlan Carew
219e8ae9b66SAlan Carew
220e8ae9b66SAlan Carew static int
open_non_blocking_channel(struct channel_info * info)221e8ae9b66SAlan Carew open_non_blocking_channel(struct channel_info *info)
222e8ae9b66SAlan Carew {
223e8ae9b66SAlan Carew int ret, flags;
224e8ae9b66SAlan Carew struct sockaddr_un sock_addr;
225e8ae9b66SAlan Carew fd_set soc_fd_set;
226e8ae9b66SAlan Carew struct timeval tv;
227e8ae9b66SAlan Carew
228e8ae9b66SAlan Carew info->fd = socket(AF_UNIX, SOCK_STREAM, 0);
2291b897991SLukasz Krakowiak if (info->fd < 0) {
230e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) creating socket for '%s'\n",
231e8ae9b66SAlan Carew strerror(errno),
232e8ae9b66SAlan Carew info->channel_path);
233e8ae9b66SAlan Carew return -1;
234e8ae9b66SAlan Carew }
235e8ae9b66SAlan Carew sock_addr.sun_family = AF_UNIX;
236e8ae9b66SAlan Carew memcpy(&sock_addr.sun_path, info->channel_path,
237e8ae9b66SAlan Carew strlen(info->channel_path)+1);
238e8ae9b66SAlan Carew
239e8ae9b66SAlan Carew /* Get current flags */
240e8ae9b66SAlan Carew flags = fcntl(info->fd, F_GETFL, 0);
241e8ae9b66SAlan Carew if (flags < 0) {
242e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for"
243e8ae9b66SAlan Carew "'%s'\n", strerror(errno), info->channel_path);
244e8ae9b66SAlan Carew return 1;
245e8ae9b66SAlan Carew }
246e8ae9b66SAlan Carew /* Set to Non Blocking */
247e8ae9b66SAlan Carew flags |= O_NONBLOCK;
248e8ae9b66SAlan Carew if (fcntl(info->fd, F_SETFL, flags) < 0) {
249e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) setting non-blocking "
250e8ae9b66SAlan Carew "socket for '%s'\n", strerror(errno), info->channel_path);
251e8ae9b66SAlan Carew return -1;
252e8ae9b66SAlan Carew }
253e8ae9b66SAlan Carew ret = connect(info->fd, (struct sockaddr *)&sock_addr,
254e8ae9b66SAlan Carew sizeof(sock_addr));
255e8ae9b66SAlan Carew if (ret < 0) {
256e8ae9b66SAlan Carew /* ECONNREFUSED error is given when VM is not active */
257e8ae9b66SAlan Carew if (errno == ECONNREFUSED) {
258e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "VM is not active or has not "
259e8ae9b66SAlan Carew "activated its endpoint to channel %s\n",
260e8ae9b66SAlan Carew info->channel_path);
261e8ae9b66SAlan Carew return -1;
262e8ae9b66SAlan Carew }
263e8ae9b66SAlan Carew /* Wait for tv_sec if in progress */
264e8ae9b66SAlan Carew else if (errno == EINPROGRESS) {
265e8ae9b66SAlan Carew tv.tv_sec = 2;
266e8ae9b66SAlan Carew tv.tv_usec = 0;
267e8ae9b66SAlan Carew FD_ZERO(&soc_fd_set);
268e8ae9b66SAlan Carew FD_SET(info->fd, &soc_fd_set);
269e8ae9b66SAlan Carew if (select(info->fd+1, NULL, &soc_fd_set, NULL, &tv) > 0) {
270e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Timeout or error on channel "
271e8ae9b66SAlan Carew "'%s'\n", info->channel_path);
272e8ae9b66SAlan Carew return -1;
273e8ae9b66SAlan Carew }
274e8ae9b66SAlan Carew } else {
275e8ae9b66SAlan Carew /* Any other error */
276e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) connecting socket"
277e8ae9b66SAlan Carew " for '%s'\n", strerror(errno), info->channel_path);
278e8ae9b66SAlan Carew return -1;
279e8ae9b66SAlan Carew }
280e8ae9b66SAlan Carew }
281e8ae9b66SAlan Carew return 0;
282e8ae9b66SAlan Carew }
283e8ae9b66SAlan Carew
284e8ae9b66SAlan Carew static int
open_host_channel(struct channel_info * info)2853618326fSDavid Hunt open_host_channel(struct channel_info *info)
2863618326fSDavid Hunt {
2873618326fSDavid Hunt int flags;
2883618326fSDavid Hunt
2893618326fSDavid Hunt info->fd = open(info->channel_path, O_RDWR | O_RSYNC);
2901b897991SLukasz Krakowiak if (info->fd < 0) {
2913618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) opening fifo for '%s'\n",
2923618326fSDavid Hunt strerror(errno),
2933618326fSDavid Hunt info->channel_path);
2943618326fSDavid Hunt return -1;
2953618326fSDavid Hunt }
2963618326fSDavid Hunt
2973618326fSDavid Hunt /* Get current flags */
2983618326fSDavid Hunt flags = fcntl(info->fd, F_GETFL, 0);
2993618326fSDavid Hunt if (flags < 0) {
3003618326fSDavid Hunt RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for"
3013618326fSDavid Hunt "'%s'\n", strerror(errno), info->channel_path);
3023618326fSDavid Hunt return 1;
3033618326fSDavid Hunt }
3043618326fSDavid Hunt /* Set to Non Blocking */
3053618326fSDavid Hunt flags |= O_NONBLOCK;
3063618326fSDavid Hunt if (fcntl(info->fd, F_SETFL, flags) < 0) {
3073618326fSDavid Hunt RTE_LOG(WARNING, CHANNEL_MANAGER,
3083618326fSDavid Hunt "Error(%s) setting non-blocking "
3093618326fSDavid Hunt "socket for '%s'\n",
3103618326fSDavid Hunt strerror(errno), info->channel_path);
3113618326fSDavid Hunt return -1;
3123618326fSDavid Hunt }
3133618326fSDavid Hunt return 0;
3143618326fSDavid Hunt }
3153618326fSDavid Hunt
3163618326fSDavid Hunt static int
setup_channel_info(struct virtual_machine_info ** vm_info_dptr,struct channel_info ** chan_info_dptr,unsigned channel_num)317e8ae9b66SAlan Carew setup_channel_info(struct virtual_machine_info **vm_info_dptr,
318e8ae9b66SAlan Carew struct channel_info **chan_info_dptr, unsigned channel_num)
319e8ae9b66SAlan Carew {
320e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr;
321e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = *vm_info_dptr;
322e8ae9b66SAlan Carew
323e8ae9b66SAlan Carew chan_info->channel_num = channel_num;
324e8ae9b66SAlan Carew chan_info->priv_info = (void *)vm_info;
325e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED;
3263618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_BINARY;
327e8ae9b66SAlan Carew if (open_non_blocking_channel(chan_info) < 0) {
328e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open channel: "
329e8ae9b66SAlan Carew "'%s' for VM '%s'\n",
330e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name);
331e8ae9b66SAlan Carew return -1;
332e8ae9b66SAlan Carew }
333e8ae9b66SAlan Carew if (add_channel_to_monitor(&chan_info) < 0) {
334e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: "
335e8ae9b66SAlan Carew "'%s' to epoll ctl for VM '%s'\n",
336e8ae9b66SAlan Carew chan_info->channel_path, vm_info->name);
337e8ae9b66SAlan Carew return -1;
338e8ae9b66SAlan Carew
339e8ae9b66SAlan Carew }
340e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
341e8ae9b66SAlan Carew vm_info->num_channels++;
342fd73630eSDavid Hunt vm_info->channel_mask[channel_num] = 1;
343e8ae9b66SAlan Carew vm_info->channels[channel_num] = chan_info;
344e8ae9b66SAlan Carew chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED;
345e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
346e8ae9b66SAlan Carew return 0;
347e8ae9b66SAlan Carew }
348e8ae9b66SAlan Carew
349221e7026SMarcin Hajkowski static int
fifo_path(char * dst,unsigned int len,unsigned int id)350221e7026SMarcin Hajkowski fifo_path(char *dst, unsigned int len, unsigned int id)
3513618326fSDavid Hunt {
352221e7026SMarcin Hajkowski int cnt;
353221e7026SMarcin Hajkowski
354221e7026SMarcin Hajkowski cnt = snprintf(dst, len, "%s%s%d", CHANNEL_MGR_SOCKET_PATH,
355221e7026SMarcin Hajkowski CHANNEL_MGR_FIFO_PATTERN_NAME, id);
356221e7026SMarcin Hajkowski
357221e7026SMarcin Hajkowski if ((cnt < 0) || (cnt > (int)len - 1)) {
358221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Could not create proper "
359221e7026SMarcin Hajkowski "string for fifo path\n");
360221e7026SMarcin Hajkowski
361221e7026SMarcin Hajkowski return -1;
362221e7026SMarcin Hajkowski }
363221e7026SMarcin Hajkowski
364221e7026SMarcin Hajkowski return 0;
3653618326fSDavid Hunt }
3663618326fSDavid Hunt
3673618326fSDavid Hunt static int
setup_host_channel_info(struct channel_info ** chan_info_dptr,unsigned int channel_num)3683618326fSDavid Hunt setup_host_channel_info(struct channel_info **chan_info_dptr,
3693618326fSDavid Hunt unsigned int channel_num)
3703618326fSDavid Hunt {
3713618326fSDavid Hunt struct channel_info *chan_info = *chan_info_dptr;
3723618326fSDavid Hunt
3733618326fSDavid Hunt chan_info->channel_num = channel_num;
3743618326fSDavid Hunt chan_info->priv_info = (void *)NULL;
3753618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED;
3763618326fSDavid Hunt chan_info->type = CHANNEL_TYPE_JSON;
3773618326fSDavid Hunt
3783618326fSDavid Hunt if (open_host_channel(chan_info) < 0) {
3793618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open host channel: "
3803618326fSDavid Hunt "'%s'\n",
3813618326fSDavid Hunt chan_info->channel_path);
3823618326fSDavid Hunt return -1;
3833618326fSDavid Hunt }
3843618326fSDavid Hunt if (add_channel_to_monitor(&chan_info) < 0) {
3853618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: "
3863618326fSDavid Hunt "'%s' to epoll ctl\n",
3873618326fSDavid Hunt chan_info->channel_path);
3883618326fSDavid Hunt return -1;
3893618326fSDavid Hunt
3903618326fSDavid Hunt }
3913618326fSDavid Hunt chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED;
3923618326fSDavid Hunt return 0;
3933618326fSDavid Hunt }
3943618326fSDavid Hunt
395e8ae9b66SAlan Carew int
add_all_channels(const char * vm_name)396e8ae9b66SAlan Carew add_all_channels(const char *vm_name)
397e8ae9b66SAlan Carew {
398e8ae9b66SAlan Carew DIR *d;
399e8ae9b66SAlan Carew struct dirent *dir;
400e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
401e8ae9b66SAlan Carew struct channel_info *chan_info;
402e8ae9b66SAlan Carew char *token, *remaining, *tail_ptr;
403e8ae9b66SAlan Carew char socket_name[PATH_MAX];
404e8ae9b66SAlan Carew unsigned channel_num;
405e8ae9b66SAlan Carew int num_channels_enabled = 0;
406e8ae9b66SAlan Carew
407e8ae9b66SAlan Carew /* verify VM exists */
408e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name);
409e8ae9b66SAlan Carew if (vm_info == NULL) {
410e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' not found"
411e8ae9b66SAlan Carew " during channel discovery\n", vm_name);
412e8ae9b66SAlan Carew return 0;
413e8ae9b66SAlan Carew }
414e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) {
415e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name);
416e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE;
417e8ae9b66SAlan Carew return 0;
418e8ae9b66SAlan Carew }
419e8ae9b66SAlan Carew d = opendir(CHANNEL_MGR_SOCKET_PATH);
420e8ae9b66SAlan Carew if (d == NULL) {
421e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error opening directory '%s': %s\n",
422e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, strerror(errno));
423e8ae9b66SAlan Carew return -1;
424e8ae9b66SAlan Carew }
425e8ae9b66SAlan Carew while ((dir = readdir(d)) != NULL) {
426e8ae9b66SAlan Carew if (!strncmp(dir->d_name, ".", 1) ||
427e8ae9b66SAlan Carew !strncmp(dir->d_name, "..", 2))
428e8ae9b66SAlan Carew continue;
429e8ae9b66SAlan Carew
4306723c0fcSBruce Richardson strlcpy(socket_name, dir->d_name, sizeof(socket_name));
431e8ae9b66SAlan Carew remaining = socket_name;
432e8ae9b66SAlan Carew /* Extract vm_name from "<vm_name>.<channel_num>" */
433e8ae9b66SAlan Carew token = strsep(&remaining, ".");
434e8ae9b66SAlan Carew if (remaining == NULL)
435e8ae9b66SAlan Carew continue;
436e8ae9b66SAlan Carew if (strncmp(vm_name, token, CHANNEL_MGR_MAX_NAME_LEN))
437e8ae9b66SAlan Carew continue;
438e8ae9b66SAlan Carew
439e8ae9b66SAlan Carew /* remaining should contain only <channel_num> */
440e8ae9b66SAlan Carew errno = 0;
441e8ae9b66SAlan Carew channel_num = (unsigned)strtol(remaining, &tail_ptr, 0);
442e8ae9b66SAlan Carew if ((errno != 0) || (remaining[0] == '\0') ||
4435b628fe1SBruce Richardson tail_ptr == NULL || (*tail_ptr != '\0')) {
444e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Malformed channel name"
445e8ae9b66SAlan Carew "'%s' found it should be in the form of "
446e8ae9b66SAlan Carew "'<guest_name>.<channel_num>(decimal)'\n",
447e8ae9b66SAlan Carew dir->d_name);
448e8ae9b66SAlan Carew continue;
449e8ae9b66SAlan Carew }
450751227a0SDavid Hunt if (channel_num >= RTE_MAX_LCORE) {
451e8ae9b66SAlan Carew RTE_LOG(WARNING, CHANNEL_MANAGER, "Channel number(%u) is "
452e8ae9b66SAlan Carew "greater than max allowable: %d, skipping '%s%s'\n",
453751227a0SDavid Hunt channel_num, RTE_MAX_LCORE-1,
454e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name);
455e8ae9b66SAlan Carew continue;
456e8ae9b66SAlan Carew }
457e8ae9b66SAlan Carew /* if channel has not been added previously */
458e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_num))
459e8ae9b66SAlan Carew continue;
460e8ae9b66SAlan Carew
461e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info),
462fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE);
463e8ae9b66SAlan Carew if (chan_info == NULL) {
464e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for "
465e8ae9b66SAlan Carew "channel '%s%s'\n", CHANNEL_MGR_SOCKET_PATH, dir->d_name);
466e8ae9b66SAlan Carew continue;
467e8ae9b66SAlan Carew }
468e8ae9b66SAlan Carew
469a9f57cfcSBruce Richardson if ((size_t)snprintf(chan_info->channel_path,
470e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s",
471a9f57cfcSBruce Richardson CHANNEL_MGR_SOCKET_PATH, dir->d_name)
472a9f57cfcSBruce Richardson >= sizeof(chan_info->channel_path)) {
473a9f57cfcSBruce Richardson RTE_LOG(ERR, CHANNEL_MANAGER, "Pathname too long for channel '%s%s'\n",
474e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, dir->d_name);
475a9f57cfcSBruce Richardson rte_free(chan_info);
476a9f57cfcSBruce Richardson continue;
477a9f57cfcSBruce Richardson }
478e8ae9b66SAlan Carew
479e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) {
480e8ae9b66SAlan Carew rte_free(chan_info);
481e8ae9b66SAlan Carew continue;
482e8ae9b66SAlan Carew }
483e8ae9b66SAlan Carew
484e8ae9b66SAlan Carew num_channels_enabled++;
485e8ae9b66SAlan Carew }
486e8ae9b66SAlan Carew closedir(d);
487e8ae9b66SAlan Carew return num_channels_enabled;
488e8ae9b66SAlan Carew }
489e8ae9b66SAlan Carew
490e8ae9b66SAlan Carew int
add_channels(const char * vm_name,unsigned * channel_list,unsigned len_channel_list)491e8ae9b66SAlan Carew add_channels(const char *vm_name, unsigned *channel_list,
492e8ae9b66SAlan Carew unsigned len_channel_list)
493e8ae9b66SAlan Carew {
494e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
495e8ae9b66SAlan Carew struct channel_info *chan_info;
496e8ae9b66SAlan Carew char socket_path[PATH_MAX];
497e8ae9b66SAlan Carew unsigned i;
498e8ae9b66SAlan Carew int num_channels_enabled = 0;
499e8ae9b66SAlan Carew
500e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name);
501e8ae9b66SAlan Carew if (vm_info == NULL) {
502e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' "
503e8ae9b66SAlan Carew "not found\n", vm_name);
504e8ae9b66SAlan Carew return 0;
505e8ae9b66SAlan Carew }
506e8ae9b66SAlan Carew
507e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr)) {
508e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name);
509e8ae9b66SAlan Carew vm_info->status = CHANNEL_MGR_VM_INACTIVE;
510e8ae9b66SAlan Carew return 0;
511e8ae9b66SAlan Carew }
512e8ae9b66SAlan Carew
513e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) {
514751227a0SDavid Hunt if (channel_list[i] >= RTE_MAX_LCORE) {
515e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel(%u) is out of range "
516e8ae9b66SAlan Carew "0...%d\n", channel_list[i],
517751227a0SDavid Hunt RTE_MAX_LCORE-1);
518e8ae9b66SAlan Carew continue;
519e8ae9b66SAlan Carew }
520e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) {
521e8ae9b66SAlan Carew RTE_LOG(INFO, CHANNEL_MANAGER, "Channel already exists, skipping "
522e8ae9b66SAlan Carew "'%s.%u'\n", vm_name, i);
523e8ae9b66SAlan Carew continue;
524e8ae9b66SAlan Carew }
525e8ae9b66SAlan Carew
526e8ae9b66SAlan Carew snprintf(socket_path, sizeof(socket_path), "%s%s.%u",
527e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]);
528e8ae9b66SAlan Carew errno = 0;
529e8ae9b66SAlan Carew if (access(socket_path, F_OK) < 0) {
530e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: "
531e8ae9b66SAlan Carew "%s\n", socket_path, strerror(errno));
532e8ae9b66SAlan Carew continue;
533e8ae9b66SAlan Carew }
534e8ae9b66SAlan Carew chan_info = rte_malloc(NULL, sizeof(*chan_info),
535fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE);
536e8ae9b66SAlan Carew if (chan_info == NULL) {
537e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for "
538e8ae9b66SAlan Carew "channel '%s'\n", socket_path);
539e8ae9b66SAlan Carew continue;
540e8ae9b66SAlan Carew }
541e8ae9b66SAlan Carew snprintf(chan_info->channel_path,
542e8ae9b66SAlan Carew sizeof(chan_info->channel_path), "%s%s.%u",
543e8ae9b66SAlan Carew CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]);
544e8ae9b66SAlan Carew if (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) {
545e8ae9b66SAlan Carew rte_free(chan_info);
546e8ae9b66SAlan Carew continue;
547e8ae9b66SAlan Carew }
548e8ae9b66SAlan Carew num_channels_enabled++;
549e8ae9b66SAlan Carew
550e8ae9b66SAlan Carew }
551e8ae9b66SAlan Carew return num_channels_enabled;
552e8ae9b66SAlan Carew }
553e8ae9b66SAlan Carew
554e8ae9b66SAlan Carew int
add_host_channels(void)555221e7026SMarcin Hajkowski add_host_channels(void)
5563618326fSDavid Hunt {
5573618326fSDavid Hunt struct channel_info *chan_info;
5583618326fSDavid Hunt char socket_path[PATH_MAX];
5593618326fSDavid Hunt int num_channels_enabled = 0;
5603618326fSDavid Hunt int ret;
561221e7026SMarcin Hajkowski struct core_info *ci;
562221e7026SMarcin Hajkowski struct channel_info *chan_infos[RTE_MAX_LCORE];
563221e7026SMarcin Hajkowski int i;
5643618326fSDavid Hunt
565221e7026SMarcin Hajkowski for (i = 0; i < RTE_MAX_LCORE; i++)
566221e7026SMarcin Hajkowski chan_infos[i] = NULL;
5673618326fSDavid Hunt
568221e7026SMarcin Hajkowski ci = get_core_info();
569221e7026SMarcin Hajkowski if (ci == NULL) {
570221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot allocate memory for core_info\n");
5713618326fSDavid Hunt return 0;
5723618326fSDavid Hunt }
5733618326fSDavid Hunt
574221e7026SMarcin Hajkowski for (i = 0; i < ci->core_count; i++) {
575b49c677aSDavid Hunt if (rte_lcore_index(i) == -1)
576b49c677aSDavid Hunt continue;
577b49c677aSDavid Hunt
578221e7026SMarcin Hajkowski if (ci->cd[i].global_enabled_cpus == 0)
579221e7026SMarcin Hajkowski continue;
580221e7026SMarcin Hajkowski
581221e7026SMarcin Hajkowski ret = fifo_path(socket_path, sizeof(socket_path), i);
582221e7026SMarcin Hajkowski if (ret < 0)
583221e7026SMarcin Hajkowski goto error;
584221e7026SMarcin Hajkowski
585221e7026SMarcin Hajkowski ret = mkfifo(socket_path, 0660);
586221e7026SMarcin Hajkowski RTE_LOG(DEBUG, CHANNEL_MANAGER, "TRY CREATE fifo '%s'\n",
587221e7026SMarcin Hajkowski socket_path);
588221e7026SMarcin Hajkowski if ((errno != EEXIST) && (ret < 0)) {
589221e7026SMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "Cannot create fifo '%s' error: "
5903618326fSDavid Hunt "%s\n", socket_path, strerror(errno));
591221e7026SMarcin Hajkowski goto error;
5923618326fSDavid Hunt }
5933618326fSDavid Hunt chan_info = rte_malloc(NULL, sizeof(*chan_info), 0);
5943618326fSDavid Hunt if (chan_info == NULL) {
5953618326fSDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for "
5963618326fSDavid Hunt "channel '%s'\n", socket_path);
597221e7026SMarcin Hajkowski goto error;
5983618326fSDavid Hunt }
599221e7026SMarcin Hajkowski chan_infos[i] = chan_info;
600135393d4SDavid Hunt strlcpy(chan_info->channel_path, socket_path,
601221e7026SMarcin Hajkowski sizeof(chan_info->channel_path));
60260dea75fSLukasz Krakowiak
603221e7026SMarcin Hajkowski if (setup_host_channel_info(&chan_info, i) < 0) {
6043618326fSDavid Hunt rte_free(chan_info);
605221e7026SMarcin Hajkowski chan_infos[i] = NULL;
606221e7026SMarcin Hajkowski goto error;
6073618326fSDavid Hunt }
6083618326fSDavid Hunt num_channels_enabled++;
609221e7026SMarcin Hajkowski }
6103618326fSDavid Hunt
6113618326fSDavid Hunt return num_channels_enabled;
612221e7026SMarcin Hajkowski error:
613221e7026SMarcin Hajkowski /* Clean up the channels opened before we hit an error. */
614221e7026SMarcin Hajkowski for (i = 0; i < ci->core_count; i++) {
615221e7026SMarcin Hajkowski if (chan_infos[i] != NULL) {
616221e7026SMarcin Hajkowski remove_channel_from_monitor(chan_infos[i]);
617221e7026SMarcin Hajkowski close(chan_infos[i]->fd);
618221e7026SMarcin Hajkowski rte_free(chan_infos[i]);
619221e7026SMarcin Hajkowski }
620221e7026SMarcin Hajkowski }
621221e7026SMarcin Hajkowski return 0;
6223618326fSDavid Hunt }
6233618326fSDavid Hunt
6243618326fSDavid Hunt int
remove_channel(struct channel_info ** chan_info_dptr)625e8ae9b66SAlan Carew remove_channel(struct channel_info **chan_info_dptr)
626e8ae9b66SAlan Carew {
627e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
628e8ae9b66SAlan Carew struct channel_info *chan_info = *chan_info_dptr;
629e8ae9b66SAlan Carew
630e8ae9b66SAlan Carew close(chan_info->fd);
631e8ae9b66SAlan Carew
632e8ae9b66SAlan Carew vm_info = (struct virtual_machine_info *)chan_info->priv_info;
633e8ae9b66SAlan Carew
634e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
635fd73630eSDavid Hunt vm_info->channel_mask[chan_info->channel_num] = 0;
636e8ae9b66SAlan Carew vm_info->num_channels--;
637e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
638e8ae9b66SAlan Carew
639e8ae9b66SAlan Carew rte_free(chan_info);
640e8ae9b66SAlan Carew return 0;
641e8ae9b66SAlan Carew }
642e8ae9b66SAlan Carew
643e8ae9b66SAlan Carew int
set_channel_status_all(const char * vm_name,enum channel_status status)644e8ae9b66SAlan Carew set_channel_status_all(const char *vm_name, enum channel_status status)
645e8ae9b66SAlan Carew {
646e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
647e8ae9b66SAlan Carew unsigned i;
648751227a0SDavid Hunt char mask[RTE_MAX_LCORE];
649e8ae9b66SAlan Carew int num_channels_changed = 0;
650e8ae9b66SAlan Carew
651e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED ||
652e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) {
653e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or "
654e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name);
655e8ae9b66SAlan Carew }
656e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name);
657e8ae9b66SAlan Carew if (vm_info == NULL) {
658e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to disable channels: VM '%s' "
659e8ae9b66SAlan Carew "not found\n", vm_name);
660e8ae9b66SAlan Carew return 0;
661e8ae9b66SAlan Carew }
662e8ae9b66SAlan Carew
663e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
664751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE);
665751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) {
666fd73630eSDavid Hunt if (mask[i] != 1)
667fd73630eSDavid Hunt continue;
668e8ae9b66SAlan Carew vm_info->channels[i]->status = status;
669e8ae9b66SAlan Carew num_channels_changed++;
670e8ae9b66SAlan Carew }
671e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
672e8ae9b66SAlan Carew return num_channels_changed;
673e8ae9b66SAlan Carew
674e8ae9b66SAlan Carew }
675e8ae9b66SAlan Carew
676e8ae9b66SAlan Carew int
set_channel_status(const char * vm_name,unsigned * channel_list,unsigned len_channel_list,enum channel_status status)677e8ae9b66SAlan Carew set_channel_status(const char *vm_name, unsigned *channel_list,
678e8ae9b66SAlan Carew unsigned len_channel_list, enum channel_status status)
679e8ae9b66SAlan Carew {
680e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
681e8ae9b66SAlan Carew unsigned i;
682e8ae9b66SAlan Carew int num_channels_changed = 0;
683e8ae9b66SAlan Carew
684e8ae9b66SAlan Carew if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED ||
685e8ae9b66SAlan Carew status == CHANNEL_MGR_CHANNEL_DISABLED)) {
686e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or "
687e8ae9b66SAlan Carew "disabled: Unable to change status for VM '%s'\n", vm_name);
688e8ae9b66SAlan Carew }
689e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name);
690e8ae9b66SAlan Carew if (vm_info == NULL) {
691e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' "
692e8ae9b66SAlan Carew "not found\n", vm_name);
693e8ae9b66SAlan Carew return 0;
694e8ae9b66SAlan Carew }
695e8ae9b66SAlan Carew for (i = 0; i < len_channel_list; i++) {
696e8ae9b66SAlan Carew if (channel_exists(vm_info, channel_list[i])) {
697e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
698e8ae9b66SAlan Carew vm_info->channels[channel_list[i]]->status = status;
699e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
700e8ae9b66SAlan Carew num_channels_changed++;
701e8ae9b66SAlan Carew }
702e8ae9b66SAlan Carew }
703e8ae9b66SAlan Carew return num_channels_changed;
704e8ae9b66SAlan Carew }
705e8ae9b66SAlan Carew
706dff22404SDavid Hunt void
get_all_vm(int * num_vm,int * num_vcpu)707dff22404SDavid Hunt get_all_vm(int *num_vm, int *num_vcpu)
708dff22404SDavid Hunt {
709dff22404SDavid Hunt
710dff22404SDavid Hunt virNodeInfo node_info;
711dff22404SDavid Hunt virDomainPtr *domptr;
712fd73630eSDavid Hunt int i, ii, numVcpus[MAX_VCPUS], n_vcpus;
713dff22404SDavid Hunt unsigned int jj;
714dff22404SDavid Hunt const char *vm_name;
715dff22404SDavid Hunt unsigned int domain_flags = VIR_CONNECT_LIST_DOMAINS_RUNNING |
716dff22404SDavid Hunt VIR_CONNECT_LIST_DOMAINS_PERSISTENT;
717dff22404SDavid Hunt unsigned int domain_flag = VIR_DOMAIN_VCPU_CONFIG;
718dff22404SDavid Hunt
719e0207366SDavid Hunt if (!global_hypervisor_available)
720e0207366SDavid Hunt return;
721dff22404SDavid Hunt
722751227a0SDavid Hunt memset(global_cpumaps, 0, RTE_MAX_LCORE*global_maplen);
723dff22404SDavid Hunt if (virNodeGetInfo(global_vir_conn_ptr, &node_info)) {
724dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n");
725dff22404SDavid Hunt return;
726dff22404SDavid Hunt }
727dff22404SDavid Hunt
728dff22404SDavid Hunt /* Returns number of pcpus */
729dff22404SDavid Hunt global_n_host_cpus = (unsigned int)node_info.cpus;
730dff22404SDavid Hunt
731dff22404SDavid Hunt /* Returns number of active domains */
732dff22404SDavid Hunt *num_vm = virConnectListAllDomains(global_vir_conn_ptr, &domptr,
733dff22404SDavid Hunt domain_flags);
734dff22404SDavid Hunt if (*num_vm <= 0) {
735dff22404SDavid Hunt RTE_LOG(ERR, CHANNEL_MANAGER, "No Active Domains Running\n");
736dff22404SDavid Hunt return;
737dff22404SDavid Hunt }
738dff22404SDavid Hunt
739dff22404SDavid Hunt for (i = 0; i < *num_vm; i++) {
740dff22404SDavid Hunt
741dff22404SDavid Hunt /* Get Domain Names */
742dff22404SDavid Hunt vm_name = virDomainGetName(domptr[i]);
743dff22404SDavid Hunt lvm_info[i].vm_name = vm_name;
744dff22404SDavid Hunt
745dff22404SDavid Hunt /* Get Number of Vcpus */
746dff22404SDavid Hunt numVcpus[i] = virDomainGetVcpusFlags(domptr[i], domain_flag);
747dff22404SDavid Hunt
748dff22404SDavid Hunt /* Get Number of VCpus & VcpuPinInfo */
749dff22404SDavid Hunt n_vcpus = virDomainGetVcpuPinInfo(domptr[i],
750dff22404SDavid Hunt numVcpus[i], global_cpumaps,
751dff22404SDavid Hunt global_maplen, domain_flag);
752dff22404SDavid Hunt
753dff22404SDavid Hunt if ((int)n_vcpus > 0) {
754dff22404SDavid Hunt *num_vcpu = n_vcpus;
755dff22404SDavid Hunt lvm_info[i].num_cpus = n_vcpus;
756dff22404SDavid Hunt }
757dff22404SDavid Hunt
758dff22404SDavid Hunt /* Save pcpu in use by libvirt VMs */
759dff22404SDavid Hunt for (ii = 0; ii < n_vcpus; ii++) {
760dff22404SDavid Hunt for (jj = 0; jj < global_n_host_cpus; jj++) {
761dff22404SDavid Hunt if (VIR_CPU_USABLE(global_cpumaps,
762dff22404SDavid Hunt global_maplen, ii, jj) > 0) {
763fd73630eSDavid Hunt lvm_info[i].pcpus[ii] = jj;
764dff22404SDavid Hunt }
765dff22404SDavid Hunt }
766dff22404SDavid Hunt }
767dff22404SDavid Hunt }
768dff22404SDavid Hunt }
769dff22404SDavid Hunt
770e8ae9b66SAlan Carew int
get_info_vm(const char * vm_name,struct vm_info * info)771e8ae9b66SAlan Carew get_info_vm(const char *vm_name, struct vm_info *info)
772e8ae9b66SAlan Carew {
773e8ae9b66SAlan Carew struct virtual_machine_info *vm_info;
774e8ae9b66SAlan Carew unsigned i, channel_num = 0;
775751227a0SDavid Hunt char mask[RTE_MAX_LCORE];
776e8ae9b66SAlan Carew
777e8ae9b66SAlan Carew vm_info = find_domain_by_name(vm_name);
778e8ae9b66SAlan Carew if (vm_info == NULL) {
779e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name);
780e8ae9b66SAlan Carew return -1;
781e8ae9b66SAlan Carew }
782e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_ACTIVE;
783e8ae9b66SAlan Carew if (!virDomainIsActive(vm_info->domainPtr))
784e8ae9b66SAlan Carew info->status = CHANNEL_MGR_VM_INACTIVE;
785e8ae9b66SAlan Carew
786e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
787e8ae9b66SAlan Carew
788751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE);
789751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) {
790fd73630eSDavid Hunt if (mask[i] != 1)
791fd73630eSDavid Hunt continue;
792e8ae9b66SAlan Carew info->channels[channel_num].channel_num = i;
793e8ae9b66SAlan Carew memcpy(info->channels[channel_num].channel_path,
794fd73630eSDavid Hunt vm_info->channels[i]->channel_path,
795fd73630eSDavid Hunt UNIX_PATH_MAX);
796fd73630eSDavid Hunt info->channels[channel_num].status =
797fd73630eSDavid Hunt vm_info->channels[i]->status;
798fd73630eSDavid Hunt info->channels[channel_num].fd =
799fd73630eSDavid Hunt vm_info->channels[i]->fd;
800e8ae9b66SAlan Carew channel_num++;
801e8ae9b66SAlan Carew }
802e8ae9b66SAlan Carew
8031deb502eSMarcin Hajkowski info->allow_query = vm_info->allow_query;
804e8ae9b66SAlan Carew info->num_channels = channel_num;
805e8ae9b66SAlan Carew info->num_vcpus = vm_info->info.nrVirtCpu;
806e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
807e8ae9b66SAlan Carew
808e8ae9b66SAlan Carew memcpy(info->name, vm_info->name, sizeof(vm_info->name));
8095776b7a3SDavid Hunt rte_spinlock_lock(&(vm_info->config_spinlock));
810e8ae9b66SAlan Carew for (i = 0; i < info->num_vcpus; i++) {
8115776b7a3SDavid Hunt info->pcpu_map[i] = vm_info->pcpu_map[i];
812e8ae9b66SAlan Carew }
8135776b7a3SDavid Hunt rte_spinlock_unlock(&(vm_info->config_spinlock));
814e8ae9b66SAlan Carew return 0;
815e8ae9b66SAlan Carew }
816e8ae9b66SAlan Carew
817e8ae9b66SAlan Carew int
add_vm(const char * vm_name)818e8ae9b66SAlan Carew add_vm(const char *vm_name)
819e8ae9b66SAlan Carew {
820e8ae9b66SAlan Carew struct virtual_machine_info *new_domain;
821e8ae9b66SAlan Carew virDomainPtr dom_ptr;
822e8ae9b66SAlan Carew int i;
823e8ae9b66SAlan Carew
824e8ae9b66SAlan Carew if (find_domain_by_name(vm_name) != NULL) {
825e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add VM: VM '%s' "
826e8ae9b66SAlan Carew "already exists\n", vm_name);
827e8ae9b66SAlan Carew return -1;
828e8ae9b66SAlan Carew }
829e8ae9b66SAlan Carew
830e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) {
831e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "No connection to hypervisor exists\n");
832e8ae9b66SAlan Carew return -1;
833e8ae9b66SAlan Carew }
834e8ae9b66SAlan Carew dom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name);
835e8ae9b66SAlan Carew if (dom_ptr == NULL) {
836e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error on VM lookup with libvirt: "
837e8ae9b66SAlan Carew "VM '%s' not found\n", vm_name);
838e8ae9b66SAlan Carew return -1;
839e8ae9b66SAlan Carew }
840e8ae9b66SAlan Carew
841e8ae9b66SAlan Carew new_domain = rte_malloc("virtual_machine_info", sizeof(*new_domain),
842fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE);
843e8ae9b66SAlan Carew if (new_domain == NULL) {
844e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to allocate memory for VM "
845e8ae9b66SAlan Carew "info\n");
846e8ae9b66SAlan Carew return -1;
847e8ae9b66SAlan Carew }
848e8ae9b66SAlan Carew new_domain->domainPtr = dom_ptr;
849e8ae9b66SAlan Carew if (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) {
850e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get libvirt VM info\n");
851e8ae9b66SAlan Carew rte_free(new_domain);
852e8ae9b66SAlan Carew return -1;
853e8ae9b66SAlan Carew }
854751227a0SDavid Hunt if (new_domain->info.nrVirtCpu > RTE_MAX_LCORE) {
855e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error the number of virtual CPUs(%u) is "
856e8ae9b66SAlan Carew "greater than allowable(%d)\n", new_domain->info.nrVirtCpu,
857751227a0SDavid Hunt RTE_MAX_LCORE);
858e8ae9b66SAlan Carew rte_free(new_domain);
859e8ae9b66SAlan Carew return -1;
860e8ae9b66SAlan Carew }
861e8ae9b66SAlan Carew
862751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++)
8635776b7a3SDavid Hunt new_domain->pcpu_map[i] = 0;
864751227a0SDavid Hunt
865e8ae9b66SAlan Carew if (update_pcpus_mask(new_domain) < 0) {
866e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting physical CPU pinning\n");
867e8ae9b66SAlan Carew rte_free(new_domain);
868e8ae9b66SAlan Carew return -1;
869e8ae9b66SAlan Carew }
870e8ae9b66SAlan Carew strncpy(new_domain->name, vm_name, sizeof(new_domain->name));
87142b3f505SDaniel Mrzyglod new_domain->name[sizeof(new_domain->name) - 1] = '\0';
872751227a0SDavid Hunt memset(new_domain->channel_mask, 0, RTE_MAX_LCORE);
873e8ae9b66SAlan Carew new_domain->num_channels = 0;
874e8ae9b66SAlan Carew
875e8ae9b66SAlan Carew if (!virDomainIsActive(dom_ptr))
876e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_INACTIVE;
877e8ae9b66SAlan Carew else
878e8ae9b66SAlan Carew new_domain->status = CHANNEL_MGR_VM_ACTIVE;
879e8ae9b66SAlan Carew
8801deb502eSMarcin Hajkowski new_domain->allow_query = 0;
881e8ae9b66SAlan Carew rte_spinlock_init(&(new_domain->config_spinlock));
882*9c20d0fdSHamza Khan TAILQ_INSERT_HEAD(&vm_list_head, new_domain, vms_info);
883e8ae9b66SAlan Carew return 0;
884e8ae9b66SAlan Carew }
885e8ae9b66SAlan Carew
886e8ae9b66SAlan Carew int
remove_vm(const char * vm_name)887e8ae9b66SAlan Carew remove_vm(const char *vm_name)
888e8ae9b66SAlan Carew {
889e8ae9b66SAlan Carew struct virtual_machine_info *vm_info = find_domain_by_name(vm_name);
890e8ae9b66SAlan Carew
891e8ae9b66SAlan Carew if (vm_info == NULL) {
892e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM: VM '%s' "
893e8ae9b66SAlan Carew "not found\n", vm_name);
894e8ae9b66SAlan Carew return -1;
895e8ae9b66SAlan Carew }
896e8ae9b66SAlan Carew rte_spinlock_lock(&vm_info->config_spinlock);
897e8ae9b66SAlan Carew if (vm_info->num_channels != 0) {
898e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM '%s', there are "
899e8ae9b66SAlan Carew "%"PRId8" channels still active\n",
900e8ae9b66SAlan Carew vm_name, vm_info->num_channels);
901e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock);
902e8ae9b66SAlan Carew return -1;
903e8ae9b66SAlan Carew }
904*9c20d0fdSHamza Khan TAILQ_REMOVE(&vm_list_head, vm_info, vms_info);
905e8ae9b66SAlan Carew rte_spinlock_unlock(&vm_info->config_spinlock);
906e8ae9b66SAlan Carew rte_free(vm_info);
907e8ae9b66SAlan Carew return 0;
908e8ae9b66SAlan Carew }
909e8ae9b66SAlan Carew
9101deb502eSMarcin Hajkowski int
set_query_status(char * vm_name,bool allow_query)9111deb502eSMarcin Hajkowski set_query_status(char *vm_name,
9121deb502eSMarcin Hajkowski bool allow_query)
9131deb502eSMarcin Hajkowski {
9141deb502eSMarcin Hajkowski struct virtual_machine_info *vm_info;
9151deb502eSMarcin Hajkowski
9161deb502eSMarcin Hajkowski vm_info = find_domain_by_name(vm_name);
9171deb502eSMarcin Hajkowski if (vm_info == NULL) {
9181deb502eSMarcin Hajkowski RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name);
9191deb502eSMarcin Hajkowski return -1;
9201deb502eSMarcin Hajkowski }
9211deb502eSMarcin Hajkowski rte_spinlock_lock(&(vm_info->config_spinlock));
9221deb502eSMarcin Hajkowski vm_info->allow_query = allow_query ? 1 : 0;
9231deb502eSMarcin Hajkowski rte_spinlock_unlock(&(vm_info->config_spinlock));
9241deb502eSMarcin Hajkowski return 0;
9251deb502eSMarcin Hajkowski }
9261deb502eSMarcin Hajkowski
927e8ae9b66SAlan Carew static void
disconnect_hypervisor(void)928e8ae9b66SAlan Carew disconnect_hypervisor(void)
929e8ae9b66SAlan Carew {
930e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) {
931e8ae9b66SAlan Carew virConnectClose(global_vir_conn_ptr);
932e8ae9b66SAlan Carew global_vir_conn_ptr = NULL;
933e8ae9b66SAlan Carew }
934e8ae9b66SAlan Carew }
935e8ae9b66SAlan Carew
936e8ae9b66SAlan Carew static int
connect_hypervisor(const char * path)937e8ae9b66SAlan Carew connect_hypervisor(const char *path)
938e8ae9b66SAlan Carew {
939e8ae9b66SAlan Carew if (global_vir_conn_ptr != NULL) {
940e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error connecting to %s, connection "
941e8ae9b66SAlan Carew "already established\n", path);
942e8ae9b66SAlan Carew return -1;
943e8ae9b66SAlan Carew }
944e8ae9b66SAlan Carew global_vir_conn_ptr = virConnectOpen(path);
945e8ae9b66SAlan Carew if (global_vir_conn_ptr == NULL) {
946e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error failed to open connection to "
947e8ae9b66SAlan Carew "Hypervisor '%s'\n", path);
948e8ae9b66SAlan Carew return -1;
949e8ae9b66SAlan Carew }
950e8ae9b66SAlan Carew return 0;
951e8ae9b66SAlan Carew }
952e8ae9b66SAlan Carew int
channel_manager_init(const char * path __rte_unused)953e0207366SDavid Hunt channel_manager_init(const char *path __rte_unused)
954e8ae9b66SAlan Carew {
955f7f14fe3SYong Liu virNodeInfo info;
956e8ae9b66SAlan Carew
957*9c20d0fdSHamza Khan TAILQ_INIT(&vm_list_head);
958e8ae9b66SAlan Carew if (connect_hypervisor(path) < 0) {
959e0207366SDavid Hunt global_n_host_cpus = 64;
960e0207366SDavid Hunt global_hypervisor_available = 0;
961e0207366SDavid Hunt RTE_LOG(INFO, CHANNEL_MANAGER, "Unable to initialize channel manager\n");
962e0207366SDavid Hunt } else {
963e0207366SDavid Hunt global_hypervisor_available = 1;
964e8ae9b66SAlan Carew
965751227a0SDavid Hunt global_maplen = VIR_CPU_MAPLEN(RTE_MAX_LCORE);
966e8ae9b66SAlan Carew
967e0207366SDavid Hunt global_vircpuinfo = rte_zmalloc(NULL,
968e0207366SDavid Hunt sizeof(*global_vircpuinfo) *
969751227a0SDavid Hunt RTE_MAX_LCORE, RTE_CACHE_LINE_SIZE);
970e8ae9b66SAlan Carew if (global_vircpuinfo == NULL) {
971e8ae9b66SAlan Carew RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for CPU Info\n");
972e8ae9b66SAlan Carew goto error;
973e8ae9b66SAlan Carew }
974e0207366SDavid Hunt global_cpumaps = rte_zmalloc(NULL,
975751227a0SDavid Hunt RTE_MAX_LCORE * global_maplen,
976fdf20fa7SSergio Gonzalez Monroy RTE_CACHE_LINE_SIZE);
977e0207366SDavid Hunt if (global_cpumaps == NULL)
978e8ae9b66SAlan Carew goto error;
979e8ae9b66SAlan Carew
980f7f14fe3SYong Liu if (virNodeGetInfo(global_vir_conn_ptr, &info)) {
981f7f14fe3SYong Liu RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n");
982e8ae9b66SAlan Carew goto error;
983e8ae9b66SAlan Carew }
984e0207366SDavid Hunt global_n_host_cpus = (unsigned int)info.cpus;
985e0207366SDavid Hunt }
986f7f14fe3SYong Liu
987e0207366SDavid Hunt
988e8ae9b66SAlan Carew
989751227a0SDavid Hunt if (global_n_host_cpus > RTE_MAX_LCORE) {
990e9f64db9SPablo de Lara RTE_LOG(WARNING, CHANNEL_MANAGER, "The number of host CPUs(%u) exceeds the "
991e9f64db9SPablo de Lara "maximum of %u. No cores over %u should be used.\n",
992751227a0SDavid Hunt global_n_host_cpus, RTE_MAX_LCORE,
993751227a0SDavid Hunt RTE_MAX_LCORE - 1);
994751227a0SDavid Hunt global_n_host_cpus = RTE_MAX_LCORE;
99567ff575eSMarvin Liu }
996e8ae9b66SAlan Carew
997e8ae9b66SAlan Carew return 0;
998e8ae9b66SAlan Carew error:
999e0207366SDavid Hunt if (global_hypervisor_available)
1000e8ae9b66SAlan Carew disconnect_hypervisor();
1001e8ae9b66SAlan Carew return -1;
1002e8ae9b66SAlan Carew }
1003e8ae9b66SAlan Carew
1004e8ae9b66SAlan Carew void
channel_manager_exit(void)1005e8ae9b66SAlan Carew channel_manager_exit(void)
1006e8ae9b66SAlan Carew {
1007e8ae9b66SAlan Carew unsigned i;
1008751227a0SDavid Hunt char mask[RTE_MAX_LCORE];
1009*9c20d0fdSHamza Khan struct virtual_machine_info *vm_info, *tmp;
1010e8ae9b66SAlan Carew
1011*9c20d0fdSHamza Khan RTE_TAILQ_FOREACH_SAFE(vm_info, &vm_list_head, vms_info, tmp) {
1012e8ae9b66SAlan Carew
1013e8ae9b66SAlan Carew rte_spinlock_lock(&(vm_info->config_spinlock));
1014e8ae9b66SAlan Carew
1015751227a0SDavid Hunt memcpy(mask, (char *)vm_info->channel_mask, RTE_MAX_LCORE);
1016751227a0SDavid Hunt for (i = 0; i < RTE_MAX_LCORE; i++) {
1017fd73630eSDavid Hunt if (mask[i] != 1)
1018fd73630eSDavid Hunt continue;
1019fd73630eSDavid Hunt remove_channel_from_monitor(
1020fd73630eSDavid Hunt vm_info->channels[i]);
1021e8ae9b66SAlan Carew close(vm_info->channels[i]->fd);
1022e8ae9b66SAlan Carew rte_free(vm_info->channels[i]);
1023e8ae9b66SAlan Carew }
1024e8ae9b66SAlan Carew rte_spinlock_unlock(&(vm_info->config_spinlock));
1025e8ae9b66SAlan Carew
1026*9c20d0fdSHamza Khan TAILQ_REMOVE(&vm_list_head, vm_info, vms_info);
1027e8ae9b66SAlan Carew rte_free(vm_info);
1028e8ae9b66SAlan Carew }
1029e8ae9b66SAlan Carew
1030e0207366SDavid Hunt if (global_hypervisor_available) {
1031e0207366SDavid Hunt /* Only needed if hypervisor available */
1032e8ae9b66SAlan Carew rte_free(global_cpumaps);
1033e8ae9b66SAlan Carew rte_free(global_vircpuinfo);
1034e8ae9b66SAlan Carew disconnect_hypervisor();
1035e8ae9b66SAlan Carew }
1036e0207366SDavid Hunt }
1037