xref: /dpdk/examples/vm_power_manager/channel_manager.c (revision f7f14fe390cae1705fef8372e1df4ff61ce24fd2)
1e8ae9b66SAlan Carew /*-
2e8ae9b66SAlan Carew  *   BSD LICENSE
3e8ae9b66SAlan Carew  *
4e8ae9b66SAlan Carew  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5e8ae9b66SAlan Carew  *   All rights reserved.
6e8ae9b66SAlan Carew  *
7e8ae9b66SAlan Carew  *   Redistribution and use in source and binary forms, with or without
8e8ae9b66SAlan Carew  *   modification, are permitted provided that the following conditions
9e8ae9b66SAlan Carew  *   are met:
10e8ae9b66SAlan Carew  *
11e8ae9b66SAlan Carew  *     * Redistributions of source code must retain the above copyright
12e8ae9b66SAlan Carew  *       notice, this list of conditions and the following disclaimer.
13e8ae9b66SAlan Carew  *     * Redistributions in binary form must reproduce the above copyright
14e8ae9b66SAlan Carew  *       notice, this list of conditions and the following disclaimer in
15e8ae9b66SAlan Carew  *       the documentation and/or other materials provided with the
16e8ae9b66SAlan Carew  *       distribution.
17e8ae9b66SAlan Carew  *     * Neither the name of Intel Corporation nor the names of its
18e8ae9b66SAlan Carew  *       contributors may be used to endorse or promote products derived
19e8ae9b66SAlan Carew  *       from this software without specific prior written permission.
20e8ae9b66SAlan Carew  *
21e8ae9b66SAlan Carew  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22e8ae9b66SAlan Carew  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23e8ae9b66SAlan Carew  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24e8ae9b66SAlan Carew  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25e8ae9b66SAlan Carew  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e8ae9b66SAlan Carew  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27e8ae9b66SAlan Carew  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28e8ae9b66SAlan Carew  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29e8ae9b66SAlan Carew  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30e8ae9b66SAlan Carew  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31e8ae9b66SAlan Carew  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32e8ae9b66SAlan Carew  */
33e8ae9b66SAlan Carew 
34e8ae9b66SAlan Carew #include <stdio.h>
35e8ae9b66SAlan Carew #include <stdlib.h>
36e8ae9b66SAlan Carew #include <sys/un.h>
37e8ae9b66SAlan Carew #include <fcntl.h>
38e8ae9b66SAlan Carew #include <unistd.h>
39e8ae9b66SAlan Carew #include <inttypes.h>
40e8ae9b66SAlan Carew #include <dirent.h>
41e8ae9b66SAlan Carew #include <errno.h>
42e8ae9b66SAlan Carew 
43e8ae9b66SAlan Carew #include <sys/queue.h>
44e8ae9b66SAlan Carew #include <sys/types.h>
45e8ae9b66SAlan Carew #include <sys/socket.h>
46e8ae9b66SAlan Carew #include <sys/select.h>
47e8ae9b66SAlan Carew 
48e8ae9b66SAlan Carew #include <rte_config.h>
49e8ae9b66SAlan Carew #include <rte_malloc.h>
50e8ae9b66SAlan Carew #include <rte_memory.h>
51e8ae9b66SAlan Carew #include <rte_mempool.h>
52e8ae9b66SAlan Carew #include <rte_log.h>
53e8ae9b66SAlan Carew #include <rte_atomic.h>
54e8ae9b66SAlan Carew #include <rte_spinlock.h>
55e8ae9b66SAlan Carew 
56e8ae9b66SAlan Carew #include <libvirt/libvirt.h>
57e8ae9b66SAlan Carew 
58e8ae9b66SAlan Carew #include "channel_manager.h"
59e8ae9b66SAlan Carew #include "channel_commands.h"
60e8ae9b66SAlan Carew #include "channel_monitor.h"
61e8ae9b66SAlan Carew 
62e8ae9b66SAlan Carew 
63e8ae9b66SAlan Carew #define RTE_LOGTYPE_CHANNEL_MANAGER RTE_LOGTYPE_USER1
64e8ae9b66SAlan Carew 
65e8ae9b66SAlan Carew #define ITERATIVE_BITMASK_CHECK_64(mask_u64b, i) \
66e8ae9b66SAlan Carew 		for (i = 0; mask_u64b; mask_u64b &= ~(1ULL << i++)) \
67e8ae9b66SAlan Carew 		if ((mask_u64b >> i) & 1) \
68e8ae9b66SAlan Carew 
69e8ae9b66SAlan Carew /* Global pointer to libvirt connection */
70e8ae9b66SAlan Carew static virConnectPtr global_vir_conn_ptr;
71e8ae9b66SAlan Carew 
72e8ae9b66SAlan Carew static unsigned char *global_cpumaps;
73e8ae9b66SAlan Carew static virVcpuInfo *global_vircpuinfo;
74e8ae9b66SAlan Carew static size_t global_maplen;
75e8ae9b66SAlan Carew 
76e8ae9b66SAlan Carew static unsigned global_n_host_cpus;
77e8ae9b66SAlan Carew 
78e8ae9b66SAlan Carew /*
79e8ae9b66SAlan Carew  * Represents a single Virtual Machine
80e8ae9b66SAlan Carew  */
81e8ae9b66SAlan Carew struct virtual_machine_info {
82e8ae9b66SAlan Carew 	char name[CHANNEL_MGR_MAX_NAME_LEN];
83e8ae9b66SAlan Carew 	rte_atomic64_t pcpu_mask[CHANNEL_CMDS_MAX_CPUS];
84e8ae9b66SAlan Carew 	struct channel_info *channels[CHANNEL_CMDS_MAX_VM_CHANNELS];
85e8ae9b66SAlan Carew 	uint64_t channel_mask;
86e8ae9b66SAlan Carew 	uint8_t num_channels;
87e8ae9b66SAlan Carew 	enum vm_status status;
88e8ae9b66SAlan Carew 	virDomainPtr domainPtr;
89e8ae9b66SAlan Carew 	virDomainInfo info;
90e8ae9b66SAlan Carew 	rte_spinlock_t config_spinlock;
91e8ae9b66SAlan Carew 	LIST_ENTRY(virtual_machine_info) vms_info;
92e8ae9b66SAlan Carew };
93e8ae9b66SAlan Carew 
94e8ae9b66SAlan Carew LIST_HEAD(, virtual_machine_info) vm_list_head;
95e8ae9b66SAlan Carew 
96e8ae9b66SAlan Carew static struct virtual_machine_info *
97e8ae9b66SAlan Carew find_domain_by_name(const char *name)
98e8ae9b66SAlan Carew {
99e8ae9b66SAlan Carew 	struct virtual_machine_info *info;
100e8ae9b66SAlan Carew 	LIST_FOREACH(info, &vm_list_head, vms_info) {
101e8ae9b66SAlan Carew 		if (!strncmp(info->name, name, CHANNEL_MGR_MAX_NAME_LEN-1))
102e8ae9b66SAlan Carew 			return info;
103e8ae9b66SAlan Carew 	}
104e8ae9b66SAlan Carew 	return NULL;
105e8ae9b66SAlan Carew }
106e8ae9b66SAlan Carew 
107e8ae9b66SAlan Carew static int
108e8ae9b66SAlan Carew update_pcpus_mask(struct virtual_machine_info *vm_info)
109e8ae9b66SAlan Carew {
110e8ae9b66SAlan Carew 	virVcpuInfoPtr cpuinfo;
111e8ae9b66SAlan Carew 	unsigned i, j;
112e8ae9b66SAlan Carew 	int n_vcpus;
113e8ae9b66SAlan Carew 	uint64_t mask;
114e8ae9b66SAlan Carew 
115e8ae9b66SAlan Carew 	memset(global_cpumaps, 0, CHANNEL_CMDS_MAX_CPUS*global_maplen);
116e8ae9b66SAlan Carew 
117e8ae9b66SAlan Carew 	if (!virDomainIsActive(vm_info->domainPtr)) {
118e8ae9b66SAlan Carew 		n_vcpus = virDomainGetVcpuPinInfo(vm_info->domainPtr,
119e8ae9b66SAlan Carew 				vm_info->info.nrVirtCpu, global_cpumaps, global_maplen,
120e8ae9b66SAlan Carew 				VIR_DOMAIN_AFFECT_CONFIG);
121e8ae9b66SAlan Carew 		if (n_vcpus < 0) {
122e8ae9b66SAlan Carew 			RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for "
123e8ae9b66SAlan Carew 					"in-active VM '%s'\n", vm_info->name);
124e8ae9b66SAlan Carew 			return -1;
125e8ae9b66SAlan Carew 		}
126e8ae9b66SAlan Carew 		goto update_pcpus;
127e8ae9b66SAlan Carew 	}
128e8ae9b66SAlan Carew 
129e8ae9b66SAlan Carew 	memset(global_vircpuinfo, 0, sizeof(*global_vircpuinfo)*
130e8ae9b66SAlan Carew 			CHANNEL_CMDS_MAX_CPUS);
131e8ae9b66SAlan Carew 
132e8ae9b66SAlan Carew 	cpuinfo = global_vircpuinfo;
133e8ae9b66SAlan Carew 
134e8ae9b66SAlan Carew 	n_vcpus = virDomainGetVcpus(vm_info->domainPtr, cpuinfo,
135e8ae9b66SAlan Carew 			CHANNEL_CMDS_MAX_CPUS, global_cpumaps, global_maplen);
136e8ae9b66SAlan Carew 	if (n_vcpus < 0) {
137e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting vCPU info for "
138e8ae9b66SAlan Carew 				"active VM '%s'\n", vm_info->name);
139e8ae9b66SAlan Carew 		return -1;
140e8ae9b66SAlan Carew 	}
141e8ae9b66SAlan Carew update_pcpus:
142e8ae9b66SAlan Carew 	if (n_vcpus >= CHANNEL_CMDS_MAX_CPUS) {
143e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Number of vCPUS(%u) is out of range "
144e8ae9b66SAlan Carew 				"0...%d\n", n_vcpus, CHANNEL_CMDS_MAX_CPUS-1);
145e8ae9b66SAlan Carew 		return -1;
146e8ae9b66SAlan Carew 	}
147e8ae9b66SAlan Carew 	if (n_vcpus != vm_info->info.nrVirtCpu) {
148e8ae9b66SAlan Carew 		RTE_LOG(INFO, CHANNEL_MANAGER, "Updating the number of vCPUs for VM '%s"
149e8ae9b66SAlan Carew 				" from %d -> %d\n", vm_info->name, vm_info->info.nrVirtCpu,
150e8ae9b66SAlan Carew 				n_vcpus);
151e8ae9b66SAlan Carew 		vm_info->info.nrVirtCpu = n_vcpus;
152e8ae9b66SAlan Carew 	}
153e8ae9b66SAlan Carew 	for (i = 0; i < vm_info->info.nrVirtCpu; i++) {
154e8ae9b66SAlan Carew 		mask = 0;
155e8ae9b66SAlan Carew 		for (j = 0; j < global_n_host_cpus; j++) {
156e8ae9b66SAlan Carew 			if (VIR_CPU_USABLE(global_cpumaps, global_maplen, i, j) > 0) {
157e8ae9b66SAlan Carew 				mask |= 1ULL << j;
158e8ae9b66SAlan Carew 			}
159e8ae9b66SAlan Carew 		}
160e8ae9b66SAlan Carew 		rte_atomic64_set(&vm_info->pcpu_mask[i], mask);
161e8ae9b66SAlan Carew 	}
162e8ae9b66SAlan Carew 	return 0;
163e8ae9b66SAlan Carew }
164e8ae9b66SAlan Carew 
165e8ae9b66SAlan Carew int
166e8ae9b66SAlan Carew set_pcpus_mask(char *vm_name, unsigned vcpu, uint64_t core_mask)
167e8ae9b66SAlan Carew {
168e8ae9b66SAlan Carew 	unsigned i = 0;
169e8ae9b66SAlan Carew 	int flags = VIR_DOMAIN_AFFECT_LIVE|VIR_DOMAIN_AFFECT_CONFIG;
170e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
171e8ae9b66SAlan Carew 	uint64_t mask = core_mask;
172e8ae9b66SAlan Carew 
173e8ae9b66SAlan Carew 	if (vcpu >= CHANNEL_CMDS_MAX_CPUS) {
174e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds max allowable(%d)\n",
175e8ae9b66SAlan Carew 				vcpu, CHANNEL_CMDS_MAX_CPUS-1);
176e8ae9b66SAlan Carew 		return -1;
177e8ae9b66SAlan Carew 	}
178e8ae9b66SAlan Carew 
179e8ae9b66SAlan Carew 	vm_info = find_domain_by_name(vm_name);
180e8ae9b66SAlan Carew 	if (vm_info == NULL) {
181e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name);
182e8ae9b66SAlan Carew 		return -1;
183e8ae9b66SAlan Carew 	}
184e8ae9b66SAlan Carew 
185e8ae9b66SAlan Carew 	if (!virDomainIsActive(vm_info->domainPtr)) {
186e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU "
187e8ae9b66SAlan Carew 				"mask(0x%"PRIx64") for VM '%s', VM is not active\n",
188e8ae9b66SAlan Carew 				vcpu, core_mask, vm_info->name);
189e8ae9b66SAlan Carew 		return -1;
190e8ae9b66SAlan Carew 	}
191e8ae9b66SAlan Carew 
192e8ae9b66SAlan Carew 	if (vcpu >= vm_info->info.nrVirtCpu) {
193e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "vCPU(%u) exceeds the assigned number of "
194e8ae9b66SAlan Carew 				"vCPUs(%u)\n", vcpu, vm_info->info.nrVirtCpu);
195e8ae9b66SAlan Carew 		return -1;
196e8ae9b66SAlan Carew 	}
197e8ae9b66SAlan Carew 	memset(global_cpumaps, 0 , CHANNEL_CMDS_MAX_CPUS * global_maplen);
198e8ae9b66SAlan Carew 	ITERATIVE_BITMASK_CHECK_64(mask, i) {
199e8ae9b66SAlan Carew 		VIR_USE_CPU(global_cpumaps, i);
200e8ae9b66SAlan Carew 		if (i >= global_n_host_cpus) {
201e8ae9b66SAlan Carew 			RTE_LOG(ERR, CHANNEL_MANAGER, "CPU(%u) exceeds the available "
202e8ae9b66SAlan Carew 					"number of CPUs(%u)\n", i, global_n_host_cpus);
203e8ae9b66SAlan Carew 			return -1;
204e8ae9b66SAlan Carew 		}
205e8ae9b66SAlan Carew 	}
206e8ae9b66SAlan Carew 	if (virDomainPinVcpuFlags(vm_info->domainPtr, vcpu, global_cpumaps,
207e8ae9b66SAlan Carew 			global_maplen, flags) < 0) {
208e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to set vCPU(%u) to pCPU "
209e8ae9b66SAlan Carew 				"mask(0x%"PRIx64") for VM '%s'\n", vcpu, core_mask,
210e8ae9b66SAlan Carew 				vm_info->name);
211e8ae9b66SAlan Carew 		return -1;
212e8ae9b66SAlan Carew 	}
213e8ae9b66SAlan Carew 	rte_atomic64_set(&vm_info->pcpu_mask[vcpu], core_mask);
214e8ae9b66SAlan Carew 	return 0;
215e8ae9b66SAlan Carew 
216e8ae9b66SAlan Carew }
217e8ae9b66SAlan Carew 
218e8ae9b66SAlan Carew int
219e8ae9b66SAlan Carew set_pcpu(char *vm_name, unsigned vcpu, unsigned core_num)
220e8ae9b66SAlan Carew {
221e8ae9b66SAlan Carew 	uint64_t mask = 1ULL << core_num;
222e8ae9b66SAlan Carew 
223e8ae9b66SAlan Carew 	return set_pcpus_mask(vm_name, vcpu, mask);
224e8ae9b66SAlan Carew }
225e8ae9b66SAlan Carew 
226e8ae9b66SAlan Carew uint64_t
227e8ae9b66SAlan Carew get_pcpus_mask(struct channel_info *chan_info, unsigned vcpu)
228e8ae9b66SAlan Carew {
229e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info =
230e8ae9b66SAlan Carew 			(struct virtual_machine_info *)chan_info->priv_info;
231e8ae9b66SAlan Carew 	return rte_atomic64_read(&vm_info->pcpu_mask[vcpu]);
232e8ae9b66SAlan Carew }
233e8ae9b66SAlan Carew 
234e8ae9b66SAlan Carew static inline int
235e8ae9b66SAlan Carew channel_exists(struct virtual_machine_info *vm_info, unsigned channel_num)
236e8ae9b66SAlan Carew {
237e8ae9b66SAlan Carew 	rte_spinlock_lock(&(vm_info->config_spinlock));
238e8ae9b66SAlan Carew 	if (vm_info->channel_mask & (1ULL << channel_num)) {
239e8ae9b66SAlan Carew 		rte_spinlock_unlock(&(vm_info->config_spinlock));
240e8ae9b66SAlan Carew 		return 1;
241e8ae9b66SAlan Carew 	}
242e8ae9b66SAlan Carew 	rte_spinlock_unlock(&(vm_info->config_spinlock));
243e8ae9b66SAlan Carew 	return 0;
244e8ae9b66SAlan Carew }
245e8ae9b66SAlan Carew 
246e8ae9b66SAlan Carew 
247e8ae9b66SAlan Carew 
248e8ae9b66SAlan Carew static int
249e8ae9b66SAlan Carew open_non_blocking_channel(struct channel_info *info)
250e8ae9b66SAlan Carew {
251e8ae9b66SAlan Carew 	int ret, flags;
252e8ae9b66SAlan Carew 	struct sockaddr_un sock_addr;
253e8ae9b66SAlan Carew 	fd_set soc_fd_set;
254e8ae9b66SAlan Carew 	struct timeval tv;
255e8ae9b66SAlan Carew 
256e8ae9b66SAlan Carew 	info->fd = socket(AF_UNIX, SOCK_STREAM, 0);
257e8ae9b66SAlan Carew 	if (info->fd == -1) {
258e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error(%s) creating socket for '%s'\n",
259e8ae9b66SAlan Carew 				strerror(errno),
260e8ae9b66SAlan Carew 				info->channel_path);
261e8ae9b66SAlan Carew 		return -1;
262e8ae9b66SAlan Carew 	}
263e8ae9b66SAlan Carew 	sock_addr.sun_family = AF_UNIX;
264e8ae9b66SAlan Carew 	memcpy(&sock_addr.sun_path, info->channel_path,
265e8ae9b66SAlan Carew 			strlen(info->channel_path)+1);
266e8ae9b66SAlan Carew 
267e8ae9b66SAlan Carew 	/* Get current flags */
268e8ae9b66SAlan Carew 	flags = fcntl(info->fd, F_GETFL, 0);
269e8ae9b66SAlan Carew 	if (flags < 0) {
270e8ae9b66SAlan Carew 		RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) fcntl get flags socket for"
271e8ae9b66SAlan Carew 				"'%s'\n", strerror(errno), info->channel_path);
272e8ae9b66SAlan Carew 		return 1;
273e8ae9b66SAlan Carew 	}
274e8ae9b66SAlan Carew 	/* Set to Non Blocking */
275e8ae9b66SAlan Carew 	flags |= O_NONBLOCK;
276e8ae9b66SAlan Carew 	if (fcntl(info->fd, F_SETFL, flags) < 0) {
277e8ae9b66SAlan Carew 		RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) setting non-blocking "
278e8ae9b66SAlan Carew 				"socket for '%s'\n", strerror(errno), info->channel_path);
279e8ae9b66SAlan Carew 		return -1;
280e8ae9b66SAlan Carew 	}
281e8ae9b66SAlan Carew 	ret = connect(info->fd, (struct sockaddr *)&sock_addr,
282e8ae9b66SAlan Carew 			sizeof(sock_addr));
283e8ae9b66SAlan Carew 	if (ret < 0) {
284e8ae9b66SAlan Carew 		/* ECONNREFUSED error is given when VM is not active */
285e8ae9b66SAlan Carew 		if (errno == ECONNREFUSED) {
286e8ae9b66SAlan Carew 			RTE_LOG(WARNING, CHANNEL_MANAGER, "VM is not active or has not "
287e8ae9b66SAlan Carew 					"activated its endpoint to channel %s\n",
288e8ae9b66SAlan Carew 					info->channel_path);
289e8ae9b66SAlan Carew 			return -1;
290e8ae9b66SAlan Carew 		}
291e8ae9b66SAlan Carew 		/* Wait for tv_sec if in progress */
292e8ae9b66SAlan Carew 		else if (errno == EINPROGRESS) {
293e8ae9b66SAlan Carew 			tv.tv_sec = 2;
294e8ae9b66SAlan Carew 			tv.tv_usec = 0;
295e8ae9b66SAlan Carew 			FD_ZERO(&soc_fd_set);
296e8ae9b66SAlan Carew 			FD_SET(info->fd, &soc_fd_set);
297e8ae9b66SAlan Carew 			if (select(info->fd+1, NULL, &soc_fd_set, NULL, &tv) > 0) {
298e8ae9b66SAlan Carew 				RTE_LOG(WARNING, CHANNEL_MANAGER, "Timeout or error on channel "
299e8ae9b66SAlan Carew 						"'%s'\n", info->channel_path);
300e8ae9b66SAlan Carew 				return -1;
301e8ae9b66SAlan Carew 			}
302e8ae9b66SAlan Carew 		} else {
303e8ae9b66SAlan Carew 			/* Any other error */
304e8ae9b66SAlan Carew 			RTE_LOG(WARNING, CHANNEL_MANAGER, "Error(%s) connecting socket"
305e8ae9b66SAlan Carew 					" for '%s'\n", strerror(errno), info->channel_path);
306e8ae9b66SAlan Carew 			return -1;
307e8ae9b66SAlan Carew 		}
308e8ae9b66SAlan Carew 	}
309e8ae9b66SAlan Carew 	return 0;
310e8ae9b66SAlan Carew }
311e8ae9b66SAlan Carew 
312e8ae9b66SAlan Carew static int
313e8ae9b66SAlan Carew setup_channel_info(struct virtual_machine_info **vm_info_dptr,
314e8ae9b66SAlan Carew 		struct channel_info **chan_info_dptr, unsigned channel_num)
315e8ae9b66SAlan Carew {
316e8ae9b66SAlan Carew 	struct channel_info *chan_info = *chan_info_dptr;
317e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info = *vm_info_dptr;
318e8ae9b66SAlan Carew 
319e8ae9b66SAlan Carew 	chan_info->channel_num = channel_num;
320e8ae9b66SAlan Carew 	chan_info->priv_info = (void *)vm_info;
321e8ae9b66SAlan Carew 	chan_info->status = CHANNEL_MGR_CHANNEL_DISCONNECTED;
322e8ae9b66SAlan Carew 	if (open_non_blocking_channel(chan_info) < 0) {
323e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Could not open channel: "
324e8ae9b66SAlan Carew 				"'%s' for VM '%s'\n",
325e8ae9b66SAlan Carew 				chan_info->channel_path, vm_info->name);
326e8ae9b66SAlan Carew 		return -1;
327e8ae9b66SAlan Carew 	}
328e8ae9b66SAlan Carew 	if (add_channel_to_monitor(&chan_info) < 0) {
329e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Could add channel: "
330e8ae9b66SAlan Carew 				"'%s' to epoll ctl for VM '%s'\n",
331e8ae9b66SAlan Carew 				chan_info->channel_path, vm_info->name);
332e8ae9b66SAlan Carew 		return -1;
333e8ae9b66SAlan Carew 
334e8ae9b66SAlan Carew 	}
335e8ae9b66SAlan Carew 	rte_spinlock_lock(&(vm_info->config_spinlock));
336e8ae9b66SAlan Carew 	vm_info->num_channels++;
337e8ae9b66SAlan Carew 	vm_info->channel_mask |= 1ULL << channel_num;
338e8ae9b66SAlan Carew 	vm_info->channels[channel_num] = chan_info;
339e8ae9b66SAlan Carew 	chan_info->status = CHANNEL_MGR_CHANNEL_CONNECTED;
340e8ae9b66SAlan Carew 	rte_spinlock_unlock(&(vm_info->config_spinlock));
341e8ae9b66SAlan Carew 	return 0;
342e8ae9b66SAlan Carew }
343e8ae9b66SAlan Carew 
344e8ae9b66SAlan Carew int
345e8ae9b66SAlan Carew add_all_channels(const char *vm_name)
346e8ae9b66SAlan Carew {
347e8ae9b66SAlan Carew 	DIR *d;
348e8ae9b66SAlan Carew 	struct dirent *dir;
349e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
350e8ae9b66SAlan Carew 	struct channel_info *chan_info;
351e8ae9b66SAlan Carew 	char *token, *remaining, *tail_ptr;
352e8ae9b66SAlan Carew 	char socket_name[PATH_MAX];
353e8ae9b66SAlan Carew 	unsigned channel_num;
354e8ae9b66SAlan Carew 	int num_channels_enabled = 0;
355e8ae9b66SAlan Carew 
356e8ae9b66SAlan Carew 	/* verify VM exists */
357e8ae9b66SAlan Carew 	vm_info = find_domain_by_name(vm_name);
358e8ae9b66SAlan Carew 	if (vm_info == NULL) {
359e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' not found"
360e8ae9b66SAlan Carew 				" during channel discovery\n", vm_name);
361e8ae9b66SAlan Carew 		return 0;
362e8ae9b66SAlan Carew 	}
363e8ae9b66SAlan Carew 	if (!virDomainIsActive(vm_info->domainPtr)) {
364e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name);
365e8ae9b66SAlan Carew 		vm_info->status = CHANNEL_MGR_VM_INACTIVE;
366e8ae9b66SAlan Carew 		return 0;
367e8ae9b66SAlan Carew 	}
368e8ae9b66SAlan Carew 	d = opendir(CHANNEL_MGR_SOCKET_PATH);
369e8ae9b66SAlan Carew 	if (d == NULL) {
370e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error opening directory '%s': %s\n",
371e8ae9b66SAlan Carew 				CHANNEL_MGR_SOCKET_PATH, strerror(errno));
372e8ae9b66SAlan Carew 		return -1;
373e8ae9b66SAlan Carew 	}
374e8ae9b66SAlan Carew 	while ((dir = readdir(d)) != NULL) {
375e8ae9b66SAlan Carew 		if (!strncmp(dir->d_name, ".", 1) ||
376e8ae9b66SAlan Carew 				!strncmp(dir->d_name, "..", 2))
377e8ae9b66SAlan Carew 			continue;
378e8ae9b66SAlan Carew 
379e8ae9b66SAlan Carew 		snprintf(socket_name, sizeof(socket_name), "%s", dir->d_name);
380e8ae9b66SAlan Carew 		remaining = socket_name;
381e8ae9b66SAlan Carew 		/* Extract vm_name from "<vm_name>.<channel_num>" */
382e8ae9b66SAlan Carew 		token = strsep(&remaining, ".");
383e8ae9b66SAlan Carew 		if (remaining == NULL)
384e8ae9b66SAlan Carew 			continue;
385e8ae9b66SAlan Carew 		if (strncmp(vm_name, token, CHANNEL_MGR_MAX_NAME_LEN))
386e8ae9b66SAlan Carew 			continue;
387e8ae9b66SAlan Carew 
388e8ae9b66SAlan Carew 		/* remaining should contain only <channel_num> */
389e8ae9b66SAlan Carew 		errno = 0;
390e8ae9b66SAlan Carew 		channel_num = (unsigned)strtol(remaining, &tail_ptr, 0);
391e8ae9b66SAlan Carew 		if ((errno != 0) || (remaining[0] == '\0') ||
3925b628fe1SBruce Richardson 				tail_ptr == NULL || (*tail_ptr != '\0')) {
393e8ae9b66SAlan Carew 			RTE_LOG(WARNING, CHANNEL_MANAGER, "Malformed channel name"
394e8ae9b66SAlan Carew 					"'%s' found it should be in the form of "
395e8ae9b66SAlan Carew 					"'<guest_name>.<channel_num>(decimal)'\n",
396e8ae9b66SAlan Carew 					dir->d_name);
397e8ae9b66SAlan Carew 			continue;
398e8ae9b66SAlan Carew 		}
399e8ae9b66SAlan Carew 		if (channel_num >= CHANNEL_CMDS_MAX_VM_CHANNELS) {
400e8ae9b66SAlan Carew 			RTE_LOG(WARNING, CHANNEL_MANAGER, "Channel number(%u) is "
401e8ae9b66SAlan Carew 					"greater than max allowable: %d, skipping '%s%s'\n",
402e8ae9b66SAlan Carew 					channel_num, CHANNEL_CMDS_MAX_VM_CHANNELS-1,
403e8ae9b66SAlan Carew 					CHANNEL_MGR_SOCKET_PATH, dir->d_name);
404e8ae9b66SAlan Carew 			continue;
405e8ae9b66SAlan Carew 		}
406e8ae9b66SAlan Carew 		/* if channel has not been added previously */
407e8ae9b66SAlan Carew 		if (channel_exists(vm_info, channel_num))
408e8ae9b66SAlan Carew 			continue;
409e8ae9b66SAlan Carew 
410e8ae9b66SAlan Carew 		chan_info = rte_malloc(NULL, sizeof(*chan_info),
411fdf20fa7SSergio Gonzalez Monroy 				RTE_CACHE_LINE_SIZE);
412e8ae9b66SAlan Carew 		if (chan_info == NULL) {
413e8ae9b66SAlan Carew 			RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for "
414e8ae9b66SAlan Carew 				"channel '%s%s'\n", CHANNEL_MGR_SOCKET_PATH, dir->d_name);
415e8ae9b66SAlan Carew 			continue;
416e8ae9b66SAlan Carew 		}
417e8ae9b66SAlan Carew 
418e8ae9b66SAlan Carew 		snprintf(chan_info->channel_path,
419e8ae9b66SAlan Carew 				sizeof(chan_info->channel_path), "%s%s",
420e8ae9b66SAlan Carew 				CHANNEL_MGR_SOCKET_PATH, dir->d_name);
421e8ae9b66SAlan Carew 
422e8ae9b66SAlan Carew 		if (setup_channel_info(&vm_info, &chan_info, channel_num) < 0) {
423e8ae9b66SAlan Carew 			rte_free(chan_info);
424e8ae9b66SAlan Carew 			continue;
425e8ae9b66SAlan Carew 		}
426e8ae9b66SAlan Carew 
427e8ae9b66SAlan Carew 		num_channels_enabled++;
428e8ae9b66SAlan Carew 	}
429e8ae9b66SAlan Carew 	closedir(d);
430e8ae9b66SAlan Carew 	return num_channels_enabled;
431e8ae9b66SAlan Carew }
432e8ae9b66SAlan Carew 
433e8ae9b66SAlan Carew int
434e8ae9b66SAlan Carew add_channels(const char *vm_name, unsigned *channel_list,
435e8ae9b66SAlan Carew 		unsigned len_channel_list)
436e8ae9b66SAlan Carew {
437e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
438e8ae9b66SAlan Carew 	struct channel_info *chan_info;
439e8ae9b66SAlan Carew 	char socket_path[PATH_MAX];
440e8ae9b66SAlan Carew 	unsigned i;
441e8ae9b66SAlan Carew 	int num_channels_enabled = 0;
442e8ae9b66SAlan Carew 
443e8ae9b66SAlan Carew 	vm_info = find_domain_by_name(vm_name);
444e8ae9b66SAlan Carew 	if (vm_info == NULL) {
445e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' "
446e8ae9b66SAlan Carew 				"not found\n", vm_name);
447e8ae9b66SAlan Carew 		return 0;
448e8ae9b66SAlan Carew 	}
449e8ae9b66SAlan Carew 
450e8ae9b66SAlan Carew 	if (!virDomainIsActive(vm_info->domainPtr)) {
451e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "VM: '%s' is not active\n", vm_name);
452e8ae9b66SAlan Carew 		vm_info->status = CHANNEL_MGR_VM_INACTIVE;
453e8ae9b66SAlan Carew 		return 0;
454e8ae9b66SAlan Carew 	}
455e8ae9b66SAlan Carew 
456e8ae9b66SAlan Carew 	for (i = 0; i < len_channel_list; i++) {
457e8ae9b66SAlan Carew 
458e8ae9b66SAlan Carew 		if (channel_list[i] >= CHANNEL_CMDS_MAX_VM_CHANNELS) {
459e8ae9b66SAlan Carew 			RTE_LOG(INFO, CHANNEL_MANAGER, "Channel(%u) is out of range "
460e8ae9b66SAlan Carew 							"0...%d\n", channel_list[i],
461e8ae9b66SAlan Carew 							CHANNEL_CMDS_MAX_VM_CHANNELS-1);
462e8ae9b66SAlan Carew 			continue;
463e8ae9b66SAlan Carew 		}
464e8ae9b66SAlan Carew 		if (channel_exists(vm_info, channel_list[i])) {
465e8ae9b66SAlan Carew 			RTE_LOG(INFO, CHANNEL_MANAGER, "Channel already exists, skipping  "
466e8ae9b66SAlan Carew 					"'%s.%u'\n", vm_name, i);
467e8ae9b66SAlan Carew 			continue;
468e8ae9b66SAlan Carew 		}
469e8ae9b66SAlan Carew 
470e8ae9b66SAlan Carew 		snprintf(socket_path, sizeof(socket_path), "%s%s.%u",
471e8ae9b66SAlan Carew 				CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]);
472e8ae9b66SAlan Carew 		errno = 0;
473e8ae9b66SAlan Carew 		if (access(socket_path, F_OK) < 0) {
474e8ae9b66SAlan Carew 			RTE_LOG(ERR, CHANNEL_MANAGER, "Channel path '%s' error: "
475e8ae9b66SAlan Carew 					"%s\n", socket_path, strerror(errno));
476e8ae9b66SAlan Carew 			continue;
477e8ae9b66SAlan Carew 		}
478e8ae9b66SAlan Carew 		chan_info = rte_malloc(NULL, sizeof(*chan_info),
479fdf20fa7SSergio Gonzalez Monroy 				RTE_CACHE_LINE_SIZE);
480e8ae9b66SAlan Carew 		if (chan_info == NULL) {
481e8ae9b66SAlan Carew 			RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for "
482e8ae9b66SAlan Carew 					"channel '%s'\n", socket_path);
483e8ae9b66SAlan Carew 			continue;
484e8ae9b66SAlan Carew 		}
485e8ae9b66SAlan Carew 		snprintf(chan_info->channel_path,
486e8ae9b66SAlan Carew 				sizeof(chan_info->channel_path), "%s%s.%u",
487e8ae9b66SAlan Carew 				CHANNEL_MGR_SOCKET_PATH, vm_name, channel_list[i]);
488e8ae9b66SAlan Carew 		if (setup_channel_info(&vm_info, &chan_info, channel_list[i]) < 0) {
489e8ae9b66SAlan Carew 			rte_free(chan_info);
490e8ae9b66SAlan Carew 			continue;
491e8ae9b66SAlan Carew 		}
492e8ae9b66SAlan Carew 		num_channels_enabled++;
493e8ae9b66SAlan Carew 
494e8ae9b66SAlan Carew 	}
495e8ae9b66SAlan Carew 	return num_channels_enabled;
496e8ae9b66SAlan Carew }
497e8ae9b66SAlan Carew 
498e8ae9b66SAlan Carew int
499e8ae9b66SAlan Carew remove_channel(struct channel_info **chan_info_dptr)
500e8ae9b66SAlan Carew {
501e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
502e8ae9b66SAlan Carew 	struct channel_info *chan_info = *chan_info_dptr;
503e8ae9b66SAlan Carew 
504e8ae9b66SAlan Carew 	close(chan_info->fd);
505e8ae9b66SAlan Carew 
506e8ae9b66SAlan Carew 	vm_info = (struct virtual_machine_info *)chan_info->priv_info;
507e8ae9b66SAlan Carew 
508e8ae9b66SAlan Carew 	rte_spinlock_lock(&(vm_info->config_spinlock));
509e8ae9b66SAlan Carew 	vm_info->channel_mask &= ~(1ULL << chan_info->channel_num);
510e8ae9b66SAlan Carew 	vm_info->num_channels--;
511e8ae9b66SAlan Carew 	rte_spinlock_unlock(&(vm_info->config_spinlock));
512e8ae9b66SAlan Carew 
513e8ae9b66SAlan Carew 	rte_free(chan_info);
514e8ae9b66SAlan Carew 	return 0;
515e8ae9b66SAlan Carew }
516e8ae9b66SAlan Carew 
517e8ae9b66SAlan Carew int
518e8ae9b66SAlan Carew set_channel_status_all(const char *vm_name, enum channel_status status)
519e8ae9b66SAlan Carew {
520e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
521e8ae9b66SAlan Carew 	unsigned i;
522e8ae9b66SAlan Carew 	uint64_t mask;
523e8ae9b66SAlan Carew 	int num_channels_changed = 0;
524e8ae9b66SAlan Carew 
525e8ae9b66SAlan Carew 	if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED ||
526e8ae9b66SAlan Carew 			status == CHANNEL_MGR_CHANNEL_DISABLED)) {
527e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or "
528e8ae9b66SAlan Carew 				"disabled: Unable to change status for VM '%s'\n", vm_name);
529e8ae9b66SAlan Carew 	}
530e8ae9b66SAlan Carew 	vm_info = find_domain_by_name(vm_name);
531e8ae9b66SAlan Carew 	if (vm_info == NULL) {
532e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to disable channels: VM '%s' "
533e8ae9b66SAlan Carew 				"not found\n", vm_name);
534e8ae9b66SAlan Carew 		return 0;
535e8ae9b66SAlan Carew 	}
536e8ae9b66SAlan Carew 
537e8ae9b66SAlan Carew 	rte_spinlock_lock(&(vm_info->config_spinlock));
538e8ae9b66SAlan Carew 	mask = vm_info->channel_mask;
539e8ae9b66SAlan Carew 	ITERATIVE_BITMASK_CHECK_64(mask, i) {
540e8ae9b66SAlan Carew 		vm_info->channels[i]->status = status;
541e8ae9b66SAlan Carew 		num_channels_changed++;
542e8ae9b66SAlan Carew 	}
543e8ae9b66SAlan Carew 	rte_spinlock_unlock(&(vm_info->config_spinlock));
544e8ae9b66SAlan Carew 	return num_channels_changed;
545e8ae9b66SAlan Carew 
546e8ae9b66SAlan Carew }
547e8ae9b66SAlan Carew 
548e8ae9b66SAlan Carew int
549e8ae9b66SAlan Carew set_channel_status(const char *vm_name, unsigned *channel_list,
550e8ae9b66SAlan Carew 		unsigned len_channel_list, enum channel_status status)
551e8ae9b66SAlan Carew {
552e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
553e8ae9b66SAlan Carew 	unsigned i;
554e8ae9b66SAlan Carew 	int num_channels_changed = 0;
555e8ae9b66SAlan Carew 
556e8ae9b66SAlan Carew 	if (!(status == CHANNEL_MGR_CHANNEL_CONNECTED ||
557e8ae9b66SAlan Carew 			status == CHANNEL_MGR_CHANNEL_DISABLED)) {
558e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Channels can only be enabled or "
559e8ae9b66SAlan Carew 				"disabled: Unable to change status for VM '%s'\n", vm_name);
560e8ae9b66SAlan Carew 	}
561e8ae9b66SAlan Carew 	vm_info = find_domain_by_name(vm_name);
562e8ae9b66SAlan Carew 	if (vm_info == NULL) {
563e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add channels: VM '%s' "
564e8ae9b66SAlan Carew 				"not found\n", vm_name);
565e8ae9b66SAlan Carew 		return 0;
566e8ae9b66SAlan Carew 	}
567e8ae9b66SAlan Carew 	for (i = 0; i < len_channel_list; i++) {
568e8ae9b66SAlan Carew 		if (channel_exists(vm_info, channel_list[i])) {
569e8ae9b66SAlan Carew 			rte_spinlock_lock(&(vm_info->config_spinlock));
570e8ae9b66SAlan Carew 			vm_info->channels[channel_list[i]]->status = status;
571e8ae9b66SAlan Carew 			rte_spinlock_unlock(&(vm_info->config_spinlock));
572e8ae9b66SAlan Carew 			num_channels_changed++;
573e8ae9b66SAlan Carew 		}
574e8ae9b66SAlan Carew 	}
575e8ae9b66SAlan Carew 	return num_channels_changed;
576e8ae9b66SAlan Carew }
577e8ae9b66SAlan Carew 
578e8ae9b66SAlan Carew int
579e8ae9b66SAlan Carew get_info_vm(const char *vm_name, struct vm_info *info)
580e8ae9b66SAlan Carew {
581e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
582e8ae9b66SAlan Carew 	unsigned i, channel_num = 0;
583e8ae9b66SAlan Carew 	uint64_t mask;
584e8ae9b66SAlan Carew 
585e8ae9b66SAlan Carew 	vm_info = find_domain_by_name(vm_name);
586e8ae9b66SAlan Carew 	if (vm_info == NULL) {
587e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "VM '%s' not found\n", vm_name);
588e8ae9b66SAlan Carew 		return -1;
589e8ae9b66SAlan Carew 	}
590e8ae9b66SAlan Carew 	info->status = CHANNEL_MGR_VM_ACTIVE;
591e8ae9b66SAlan Carew 	if (!virDomainIsActive(vm_info->domainPtr))
592e8ae9b66SAlan Carew 		info->status = CHANNEL_MGR_VM_INACTIVE;
593e8ae9b66SAlan Carew 
594e8ae9b66SAlan Carew 	rte_spinlock_lock(&(vm_info->config_spinlock));
595e8ae9b66SAlan Carew 
596e8ae9b66SAlan Carew 	mask = vm_info->channel_mask;
597e8ae9b66SAlan Carew 	ITERATIVE_BITMASK_CHECK_64(mask, i) {
598e8ae9b66SAlan Carew 		info->channels[channel_num].channel_num = i;
599e8ae9b66SAlan Carew 		memcpy(info->channels[channel_num].channel_path,
6000d74597cSBruce Richardson 				vm_info->channels[i]->channel_path, UNIX_PATH_MAX);
601e8ae9b66SAlan Carew 		info->channels[channel_num].status = vm_info->channels[i]->status;
602e8ae9b66SAlan Carew 		info->channels[channel_num].fd = vm_info->channels[i]->fd;
603e8ae9b66SAlan Carew 		channel_num++;
604e8ae9b66SAlan Carew 	}
605e8ae9b66SAlan Carew 
606e8ae9b66SAlan Carew 	info->num_channels = channel_num;
607e8ae9b66SAlan Carew 	info->num_vcpus = vm_info->info.nrVirtCpu;
608e8ae9b66SAlan Carew 	rte_spinlock_unlock(&(vm_info->config_spinlock));
609e8ae9b66SAlan Carew 
610e8ae9b66SAlan Carew 	memcpy(info->name, vm_info->name, sizeof(vm_info->name));
611e8ae9b66SAlan Carew 	for (i = 0; i < info->num_vcpus; i++) {
612e8ae9b66SAlan Carew 		info->pcpu_mask[i] = rte_atomic64_read(&vm_info->pcpu_mask[i]);
613e8ae9b66SAlan Carew 	}
614e8ae9b66SAlan Carew 	return 0;
615e8ae9b66SAlan Carew }
616e8ae9b66SAlan Carew 
617e8ae9b66SAlan Carew int
618e8ae9b66SAlan Carew add_vm(const char *vm_name)
619e8ae9b66SAlan Carew {
620e8ae9b66SAlan Carew 	struct virtual_machine_info *new_domain;
621e8ae9b66SAlan Carew 	virDomainPtr dom_ptr;
622e8ae9b66SAlan Carew 	int i;
623e8ae9b66SAlan Carew 
624e8ae9b66SAlan Carew 	if (find_domain_by_name(vm_name) != NULL) {
625e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to add VM: VM '%s' "
626e8ae9b66SAlan Carew 				"already exists\n", vm_name);
627e8ae9b66SAlan Carew 		return -1;
628e8ae9b66SAlan Carew 	}
629e8ae9b66SAlan Carew 
630e8ae9b66SAlan Carew 	if (global_vir_conn_ptr == NULL) {
631e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "No connection to hypervisor exists\n");
632e8ae9b66SAlan Carew 		return -1;
633e8ae9b66SAlan Carew 	}
634e8ae9b66SAlan Carew 	dom_ptr = virDomainLookupByName(global_vir_conn_ptr, vm_name);
635e8ae9b66SAlan Carew 	if (dom_ptr == NULL) {
636e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error on VM lookup with libvirt: "
637e8ae9b66SAlan Carew 				"VM '%s' not found\n", vm_name);
638e8ae9b66SAlan Carew 		return -1;
639e8ae9b66SAlan Carew 	}
640e8ae9b66SAlan Carew 
641e8ae9b66SAlan Carew 	new_domain = rte_malloc("virtual_machine_info", sizeof(*new_domain),
642fdf20fa7SSergio Gonzalez Monroy 			RTE_CACHE_LINE_SIZE);
643e8ae9b66SAlan Carew 	if (new_domain == NULL) {
644e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to allocate memory for VM "
645e8ae9b66SAlan Carew 				"info\n");
646e8ae9b66SAlan Carew 		return -1;
647e8ae9b66SAlan Carew 	}
648e8ae9b66SAlan Carew 	new_domain->domainPtr = dom_ptr;
649e8ae9b66SAlan Carew 	if (virDomainGetInfo(new_domain->domainPtr, &new_domain->info) != 0) {
650e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to get libvirt VM info\n");
651e8ae9b66SAlan Carew 		rte_free(new_domain);
652e8ae9b66SAlan Carew 		return -1;
653e8ae9b66SAlan Carew 	}
654e8ae9b66SAlan Carew 	if (new_domain->info.nrVirtCpu > CHANNEL_CMDS_MAX_CPUS) {
655e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error the number of virtual CPUs(%u) is "
656e8ae9b66SAlan Carew 				"greater than allowable(%d)\n", new_domain->info.nrVirtCpu,
657e8ae9b66SAlan Carew 				CHANNEL_CMDS_MAX_CPUS);
658e8ae9b66SAlan Carew 		rte_free(new_domain);
659e8ae9b66SAlan Carew 		return -1;
660e8ae9b66SAlan Carew 	}
661e8ae9b66SAlan Carew 
662e8ae9b66SAlan Carew 	for (i = 0; i < CHANNEL_CMDS_MAX_CPUS; i++) {
663e8ae9b66SAlan Carew 		rte_atomic64_init(&new_domain->pcpu_mask[i]);
664e8ae9b66SAlan Carew 	}
665e8ae9b66SAlan Carew 	if (update_pcpus_mask(new_domain) < 0) {
666e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error getting physical CPU pinning\n");
667e8ae9b66SAlan Carew 		rte_free(new_domain);
668e8ae9b66SAlan Carew 		return -1;
669e8ae9b66SAlan Carew 	}
670e8ae9b66SAlan Carew 	strncpy(new_domain->name, vm_name, sizeof(new_domain->name));
671e8ae9b66SAlan Carew 	new_domain->channel_mask = 0;
672e8ae9b66SAlan Carew 	new_domain->num_channels = 0;
673e8ae9b66SAlan Carew 
674e8ae9b66SAlan Carew 	if (!virDomainIsActive(dom_ptr))
675e8ae9b66SAlan Carew 		new_domain->status = CHANNEL_MGR_VM_INACTIVE;
676e8ae9b66SAlan Carew 	else
677e8ae9b66SAlan Carew 		new_domain->status = CHANNEL_MGR_VM_ACTIVE;
678e8ae9b66SAlan Carew 
679e8ae9b66SAlan Carew 	rte_spinlock_init(&(new_domain->config_spinlock));
680e8ae9b66SAlan Carew 	LIST_INSERT_HEAD(&vm_list_head, new_domain, vms_info);
681e8ae9b66SAlan Carew 	return 0;
682e8ae9b66SAlan Carew }
683e8ae9b66SAlan Carew 
684e8ae9b66SAlan Carew int
685e8ae9b66SAlan Carew remove_vm(const char *vm_name)
686e8ae9b66SAlan Carew {
687e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info = find_domain_by_name(vm_name);
688e8ae9b66SAlan Carew 
689e8ae9b66SAlan Carew 	if (vm_info == NULL) {
690e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM: VM '%s' "
691e8ae9b66SAlan Carew 				"not found\n", vm_name);
692e8ae9b66SAlan Carew 		return -1;
693e8ae9b66SAlan Carew 	}
694e8ae9b66SAlan Carew 	rte_spinlock_lock(&vm_info->config_spinlock);
695e8ae9b66SAlan Carew 	if (vm_info->num_channels != 0) {
696e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to remove VM '%s', there are "
697e8ae9b66SAlan Carew 				"%"PRId8" channels still active\n",
698e8ae9b66SAlan Carew 				vm_name, vm_info->num_channels);
699e8ae9b66SAlan Carew 		rte_spinlock_unlock(&vm_info->config_spinlock);
700e8ae9b66SAlan Carew 		return -1;
701e8ae9b66SAlan Carew 	}
702e8ae9b66SAlan Carew 	LIST_REMOVE(vm_info, vms_info);
703e8ae9b66SAlan Carew 	rte_spinlock_unlock(&vm_info->config_spinlock);
704e8ae9b66SAlan Carew 	rte_free(vm_info);
705e8ae9b66SAlan Carew 	return 0;
706e8ae9b66SAlan Carew }
707e8ae9b66SAlan Carew 
708e8ae9b66SAlan Carew static void
709e8ae9b66SAlan Carew disconnect_hypervisor(void)
710e8ae9b66SAlan Carew {
711e8ae9b66SAlan Carew 	if (global_vir_conn_ptr != NULL) {
712e8ae9b66SAlan Carew 		virConnectClose(global_vir_conn_ptr);
713e8ae9b66SAlan Carew 		global_vir_conn_ptr = NULL;
714e8ae9b66SAlan Carew 	}
715e8ae9b66SAlan Carew }
716e8ae9b66SAlan Carew 
717e8ae9b66SAlan Carew static int
718e8ae9b66SAlan Carew connect_hypervisor(const char *path)
719e8ae9b66SAlan Carew {
720e8ae9b66SAlan Carew 	if (global_vir_conn_ptr != NULL) {
721e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error connecting to %s, connection "
722e8ae9b66SAlan Carew 				"already established\n", path);
723e8ae9b66SAlan Carew 		return -1;
724e8ae9b66SAlan Carew 	}
725e8ae9b66SAlan Carew 	global_vir_conn_ptr = virConnectOpen(path);
726e8ae9b66SAlan Carew 	if (global_vir_conn_ptr == NULL) {
727e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error failed to open connection to "
728e8ae9b66SAlan Carew 				"Hypervisor '%s'\n", path);
729e8ae9b66SAlan Carew 		return -1;
730e8ae9b66SAlan Carew 	}
731e8ae9b66SAlan Carew 	return 0;
732e8ae9b66SAlan Carew }
733e8ae9b66SAlan Carew 
734e8ae9b66SAlan Carew int
735e8ae9b66SAlan Carew channel_manager_init(const char *path)
736e8ae9b66SAlan Carew {
737*f7f14fe3SYong Liu 	virNodeInfo info;
738e8ae9b66SAlan Carew 
739e8ae9b66SAlan Carew 	LIST_INIT(&vm_list_head);
740e8ae9b66SAlan Carew 	if (connect_hypervisor(path) < 0) {
741e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to initialize channel manager\n");
742e8ae9b66SAlan Carew 		return -1;
743e8ae9b66SAlan Carew 	}
744e8ae9b66SAlan Carew 
745e8ae9b66SAlan Carew 	global_maplen = VIR_CPU_MAPLEN(CHANNEL_CMDS_MAX_CPUS);
746e8ae9b66SAlan Carew 
747e8ae9b66SAlan Carew 	global_vircpuinfo = rte_zmalloc(NULL, sizeof(*global_vircpuinfo) *
748fdf20fa7SSergio Gonzalez Monroy 			CHANNEL_CMDS_MAX_CPUS, RTE_CACHE_LINE_SIZE);
749e8ae9b66SAlan Carew 	if (global_vircpuinfo == NULL) {
750e8ae9b66SAlan Carew 		RTE_LOG(ERR, CHANNEL_MANAGER, "Error allocating memory for CPU Info\n");
751e8ae9b66SAlan Carew 		goto error;
752e8ae9b66SAlan Carew 	}
753e8ae9b66SAlan Carew 	global_cpumaps = rte_zmalloc(NULL, CHANNEL_CMDS_MAX_CPUS * global_maplen,
754fdf20fa7SSergio Gonzalez Monroy 			RTE_CACHE_LINE_SIZE);
755e8ae9b66SAlan Carew 	if (global_cpumaps == NULL) {
756e8ae9b66SAlan Carew 		goto error;
757e8ae9b66SAlan Carew 	}
758e8ae9b66SAlan Carew 
759*f7f14fe3SYong Liu 	if (virNodeGetInfo(global_vir_conn_ptr, &info)) {
760*f7f14fe3SYong Liu 		RTE_LOG(ERR, CHANNEL_MANAGER, "Unable to retrieve node Info\n");
761e8ae9b66SAlan Carew 		goto error;
762e8ae9b66SAlan Carew 	}
763*f7f14fe3SYong Liu 
764*f7f14fe3SYong Liu 	global_n_host_cpus = (unsigned)info.cpus;
765e8ae9b66SAlan Carew 
76667ff575eSMarvin Liu 	if (global_n_host_cpus > CHANNEL_CMDS_MAX_CPUS) {
767e9f64db9SPablo de Lara 		RTE_LOG(WARNING, CHANNEL_MANAGER, "The number of host CPUs(%u) exceeds the "
768e9f64db9SPablo de Lara 				"maximum of %u. No cores over %u should be used.\n",
769e9f64db9SPablo de Lara 				global_n_host_cpus, CHANNEL_CMDS_MAX_CPUS,
770e9f64db9SPablo de Lara 				CHANNEL_CMDS_MAX_CPUS - 1);
77167ff575eSMarvin Liu 		global_n_host_cpus = CHANNEL_CMDS_MAX_CPUS;
77267ff575eSMarvin Liu 	}
773e8ae9b66SAlan Carew 
774e8ae9b66SAlan Carew 	return 0;
775e8ae9b66SAlan Carew error:
776e8ae9b66SAlan Carew 	disconnect_hypervisor();
777e8ae9b66SAlan Carew 	return -1;
778e8ae9b66SAlan Carew }
779e8ae9b66SAlan Carew 
780e8ae9b66SAlan Carew void
781e8ae9b66SAlan Carew channel_manager_exit(void)
782e8ae9b66SAlan Carew {
783e8ae9b66SAlan Carew 	unsigned i;
784e8ae9b66SAlan Carew 	uint64_t mask;
785e8ae9b66SAlan Carew 	struct virtual_machine_info *vm_info;
786e8ae9b66SAlan Carew 
787e8ae9b66SAlan Carew 	LIST_FOREACH(vm_info, &vm_list_head, vms_info) {
788e8ae9b66SAlan Carew 
789e8ae9b66SAlan Carew 		rte_spinlock_lock(&(vm_info->config_spinlock));
790e8ae9b66SAlan Carew 
791e8ae9b66SAlan Carew 		mask = vm_info->channel_mask;
792e8ae9b66SAlan Carew 		ITERATIVE_BITMASK_CHECK_64(mask, i) {
793e8ae9b66SAlan Carew 			remove_channel_from_monitor(vm_info->channels[i]);
794e8ae9b66SAlan Carew 			close(vm_info->channels[i]->fd);
795e8ae9b66SAlan Carew 			rte_free(vm_info->channels[i]);
796e8ae9b66SAlan Carew 		}
797e8ae9b66SAlan Carew 		rte_spinlock_unlock(&(vm_info->config_spinlock));
798e8ae9b66SAlan Carew 
799e8ae9b66SAlan Carew 		LIST_REMOVE(vm_info, vms_info);
800e8ae9b66SAlan Carew 		rte_free(vm_info);
801e8ae9b66SAlan Carew 	}
802e8ae9b66SAlan Carew 
803e8ae9b66SAlan Carew 	rte_free(global_cpumaps);
804e8ae9b66SAlan Carew 	rte_free(global_vircpuinfo);
805e8ae9b66SAlan Carew 	disconnect_hypervisor();
806e8ae9b66SAlan Carew }
807