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