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