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