1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <unistd.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <signal.h> 10 #include <errno.h> 11 #include <string.h> 12 #include <fcntl.h> 13 #include <sys/types.h> 14 #include <sys/epoll.h> 15 #include <sys/queue.h> 16 #include <sys/time.h> 17 #include <sys/socket.h> 18 #include <sys/select.h> 19 #ifdef USE_JANSSON 20 #include <jansson.h> 21 #else 22 #pragma message "Jansson dev libs unavailable, not including JSON parsing" 23 #endif 24 #include <rte_string_fns.h> 25 #include <rte_log.h> 26 #include <rte_memory.h> 27 #include <rte_malloc.h> 28 #include <rte_cycles.h> 29 #include <rte_ethdev.h> 30 #ifdef RTE_NET_I40E 31 #include <rte_pmd_i40e.h> 32 #endif 33 #include <rte_power.h> 34 35 #include <libvirt/libvirt.h> 36 #include "channel_monitor.h" 37 #include "channel_manager.h" 38 #include "power_manager.h" 39 #include "oob_monitor.h" 40 41 #define RTE_LOGTYPE_CHANNEL_MONITOR RTE_LOGTYPE_USER1 42 43 #define MAX_EVENTS 256 44 45 uint64_t vsi_pkt_count_prev[384]; 46 uint64_t rdtsc_prev[384]; 47 #define MAX_JSON_STRING_LEN 1024 48 char json_data[MAX_JSON_STRING_LEN]; 49 50 double time_period_ms = 1; 51 static volatile unsigned run_loop = 1; 52 static int global_event_fd; 53 static unsigned int policy_is_set; 54 static struct epoll_event *global_events_list; 55 static struct policy policies[RTE_MAX_LCORE]; 56 57 #ifdef USE_JANSSON 58 59 union PFID { 60 struct rte_ether_addr addr; 61 uint64_t pfid; 62 }; 63 64 static int 65 str_to_ether_addr(const char *a, struct rte_ether_addr *ether_addr) 66 { 67 int i; 68 char *end; 69 unsigned long o[RTE_ETHER_ADDR_LEN]; 70 71 i = 0; 72 do { 73 errno = 0; 74 o[i] = strtoul(a, &end, 16); 75 if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0)) 76 return -1; 77 a = end + 1; 78 } while (++i != RTE_DIM(o) / sizeof(o[0]) && end[0] != 0); 79 80 /* Junk at the end of line */ 81 if (end[0] != 0) 82 return -1; 83 84 /* Support the format XX:XX:XX:XX:XX:XX */ 85 if (i == RTE_ETHER_ADDR_LEN) { 86 while (i-- != 0) { 87 if (o[i] > UINT8_MAX) 88 return -1; 89 ether_addr->addr_bytes[i] = (uint8_t)o[i]; 90 } 91 /* Support the format XXXX:XXXX:XXXX */ 92 } else if (i == RTE_ETHER_ADDR_LEN / 2) { 93 while (i-- != 0) { 94 if (o[i] > UINT16_MAX) 95 return -1; 96 ether_addr->addr_bytes[i * 2] = 97 (uint8_t)(o[i] >> 8); 98 ether_addr->addr_bytes[i * 2 + 1] = 99 (uint8_t)(o[i] & 0xff); 100 } 101 /* unknown format */ 102 } else 103 return -1; 104 105 return 0; 106 } 107 108 static int 109 set_policy_mac(struct rte_power_channel_packet *pkt, int idx, char *mac) 110 { 111 union PFID pfid; 112 int ret; 113 114 /* Use port MAC address as the vfid */ 115 ret = str_to_ether_addr(mac, &pfid.addr); 116 117 if (ret != 0) { 118 RTE_LOG(ERR, CHANNEL_MONITOR, 119 "Invalid mac address received in JSON\n"); 120 pkt->vfid[idx] = 0; 121 return -1; 122 } 123 124 printf("Received MAC Address: %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":" 125 "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n", 126 RTE_ETHER_ADDR_BYTES(&pfid.addr)); 127 128 pkt->vfid[idx] = pfid.pfid; 129 return 0; 130 } 131 132 static char* 133 get_resource_name_from_chn_path(const char *channel_path) 134 { 135 char *substr = NULL; 136 137 substr = strstr(channel_path, CHANNEL_MGR_FIFO_PATTERN_NAME); 138 139 return substr; 140 } 141 142 static int 143 get_resource_id_from_vmname(const char *vm_name) 144 { 145 int result = -1; 146 int off = 0; 147 148 if (vm_name == NULL) 149 return -1; 150 151 while (vm_name[off] != '\0') { 152 if (isdigit(vm_name[off])) 153 break; 154 off++; 155 } 156 result = atoi(&vm_name[off]); 157 if ((result == 0) && (vm_name[off] != '0')) 158 return -1; 159 160 return result; 161 } 162 163 static int 164 parse_json_to_pkt(json_t *element, struct rte_power_channel_packet *pkt, 165 const char *vm_name) 166 { 167 const char *key; 168 json_t *value; 169 int ret; 170 int resource_id; 171 172 memset(pkt, 0, sizeof(*pkt)); 173 174 pkt->nb_mac_to_monitor = 0; 175 pkt->t_boost_status.tbEnabled = false; 176 pkt->workload = RTE_POWER_WL_LOW; 177 pkt->policy_to_use = RTE_POWER_POLICY_TIME; 178 pkt->command = RTE_POWER_PKT_POLICY; 179 pkt->core_type = RTE_POWER_CORE_TYPE_PHYSICAL; 180 181 if (vm_name == NULL) { 182 RTE_LOG(ERR, CHANNEL_MONITOR, 183 "vm_name is NULL, request rejected !\n"); 184 return -1; 185 } 186 187 json_object_foreach(element, key, value) { 188 if (!strcmp(key, "policy")) { 189 /* Recurse in to get the contents of profile */ 190 ret = parse_json_to_pkt(value, pkt, vm_name); 191 if (ret) 192 return ret; 193 } else if (!strcmp(key, "instruction")) { 194 /* Recurse in to get the contents of instruction */ 195 ret = parse_json_to_pkt(value, pkt, vm_name); 196 if (ret) 197 return ret; 198 } else if (!strcmp(key, "command")) { 199 char command[32]; 200 strlcpy(command, json_string_value(value), 32); 201 if (!strcmp(command, "power")) { 202 pkt->command = RTE_POWER_CPU_POWER; 203 } else if (!strcmp(command, "create")) { 204 pkt->command = RTE_POWER_PKT_POLICY; 205 } else if (!strcmp(command, "destroy")) { 206 pkt->command = RTE_POWER_PKT_POLICY_REMOVE; 207 } else { 208 RTE_LOG(ERR, CHANNEL_MONITOR, 209 "Invalid command received in JSON\n"); 210 return -1; 211 } 212 } else if (!strcmp(key, "policy_type")) { 213 char command[32]; 214 strlcpy(command, json_string_value(value), 32); 215 if (!strcmp(command, "TIME")) { 216 pkt->policy_to_use = 217 RTE_POWER_POLICY_TIME; 218 } else if (!strcmp(command, "TRAFFIC")) { 219 pkt->policy_to_use = 220 RTE_POWER_POLICY_TRAFFIC; 221 } else if (!strcmp(command, "WORKLOAD")) { 222 pkt->policy_to_use = 223 RTE_POWER_POLICY_WORKLOAD; 224 } else if (!strcmp(command, "BRANCH_RATIO")) { 225 pkt->policy_to_use = 226 RTE_POWER_POLICY_BRANCH_RATIO; 227 } else { 228 RTE_LOG(ERR, CHANNEL_MONITOR, 229 "Wrong policy_type received in JSON\n"); 230 return -1; 231 } 232 } else if (!strcmp(key, "workload")) { 233 char command[32]; 234 strlcpy(command, json_string_value(value), 32); 235 if (!strcmp(command, "HIGH")) { 236 pkt->workload = RTE_POWER_WL_HIGH; 237 } else if (!strcmp(command, "MEDIUM")) { 238 pkt->workload = RTE_POWER_WL_MEDIUM; 239 } else if (!strcmp(command, "LOW")) { 240 pkt->workload = RTE_POWER_WL_LOW; 241 } else { 242 RTE_LOG(ERR, CHANNEL_MONITOR, 243 "Wrong workload received in JSON\n"); 244 return -1; 245 } 246 } else if (!strcmp(key, "busy_hours")) { 247 unsigned int i; 248 size_t size = json_array_size(value); 249 250 for (i = 0; i < size; i++) { 251 int hour = (int)json_integer_value( 252 json_array_get(value, i)); 253 pkt->timer_policy.busy_hours[i] = hour; 254 } 255 } else if (!strcmp(key, "quiet_hours")) { 256 unsigned int i; 257 size_t size = json_array_size(value); 258 259 for (i = 0; i < size; i++) { 260 int hour = (int)json_integer_value( 261 json_array_get(value, i)); 262 pkt->timer_policy.quiet_hours[i] = hour; 263 } 264 } else if (!strcmp(key, "mac_list")) { 265 unsigned int i; 266 size_t size = json_array_size(value); 267 268 for (i = 0; i < size; i++) { 269 char mac[32]; 270 strlcpy(mac, 271 json_string_value(json_array_get(value, i)), 272 32); 273 set_policy_mac(pkt, i, mac); 274 } 275 pkt->nb_mac_to_monitor = size; 276 } else if (!strcmp(key, "avg_packet_thresh")) { 277 pkt->traffic_policy.avg_max_packet_thresh = 278 (uint32_t)json_integer_value(value); 279 } else if (!strcmp(key, "max_packet_thresh")) { 280 pkt->traffic_policy.max_max_packet_thresh = 281 (uint32_t)json_integer_value(value); 282 } else if (!strcmp(key, "unit")) { 283 char unit[32]; 284 strlcpy(unit, json_string_value(value), 32); 285 if (!strcmp(unit, "SCALE_UP")) { 286 pkt->unit = RTE_POWER_SCALE_UP; 287 } else if (!strcmp(unit, "SCALE_DOWN")) { 288 pkt->unit = RTE_POWER_SCALE_DOWN; 289 } else if (!strcmp(unit, "SCALE_MAX")) { 290 pkt->unit = RTE_POWER_SCALE_MAX; 291 } else if (!strcmp(unit, "SCALE_MIN")) { 292 pkt->unit = RTE_POWER_SCALE_MIN; 293 } else if (!strcmp(unit, "ENABLE_TURBO")) { 294 pkt->unit = RTE_POWER_ENABLE_TURBO; 295 } else if (!strcmp(unit, "DISABLE_TURBO")) { 296 pkt->unit = RTE_POWER_DISABLE_TURBO; 297 } else { 298 RTE_LOG(ERR, CHANNEL_MONITOR, 299 "Invalid command received in JSON\n"); 300 return -1; 301 } 302 } else { 303 RTE_LOG(ERR, CHANNEL_MONITOR, 304 "Unknown key received in JSON string: %s\n", 305 key); 306 } 307 308 resource_id = get_resource_id_from_vmname(vm_name); 309 if (resource_id < 0) { 310 RTE_LOG(ERR, CHANNEL_MONITOR, 311 "Could not get resource_id from vm_name:%s\n", 312 vm_name); 313 return -1; 314 } 315 strlcpy(pkt->vm_name, vm_name, RTE_POWER_VM_MAX_NAME_SZ); 316 pkt->resource_id = resource_id; 317 } 318 return 0; 319 } 320 #endif 321 322 void channel_monitor_exit(void) 323 { 324 run_loop = 0; 325 rte_free(global_events_list); 326 } 327 328 static void 329 core_share(int pNo, int z, int x, int t) 330 { 331 if (policies[pNo].core_share[z].pcpu == lvm_info[x].pcpus[t]) { 332 if (strcmp(policies[pNo].pkt.vm_name, 333 lvm_info[x].vm_name) != 0) { 334 policies[pNo].core_share[z].status = 1; 335 power_manager_scale_core_max( 336 policies[pNo].core_share[z].pcpu); 337 } 338 } 339 } 340 341 static void 342 core_share_status(int pNo) 343 { 344 345 int noVms = 0, noVcpus = 0, z, x, t; 346 347 get_all_vm(&noVms, &noVcpus); 348 349 /* Reset Core Share Status. */ 350 for (z = 0; z < noVcpus; z++) 351 policies[pNo].core_share[z].status = 0; 352 353 /* Foreach vcpu in a policy. */ 354 for (z = 0; z < policies[pNo].pkt.num_vcpu; z++) { 355 /* Foreach VM on the platform. */ 356 for (x = 0; x < noVms; x++) { 357 /* Foreach vcpu of VMs on platform. */ 358 for (t = 0; t < lvm_info[x].num_cpus; t++) 359 core_share(pNo, z, x, t); 360 } 361 } 362 } 363 364 365 static int 366 pcpu_monitor(struct policy *pol, struct core_info *ci, int pcpu, int count) 367 { 368 int ret = 0; 369 370 if (pol->pkt.policy_to_use == RTE_POWER_POLICY_BRANCH_RATIO) { 371 ci->cd[pcpu].oob_enabled = 1; 372 ret = add_core_to_monitor(pcpu); 373 if (ret == 0) 374 RTE_LOG(INFO, CHANNEL_MONITOR, 375 "Monitoring pcpu %d OOB for %s\n", 376 pcpu, pol->pkt.vm_name); 377 else 378 RTE_LOG(ERR, CHANNEL_MONITOR, 379 "Error monitoring pcpu %d OOB for %s\n", 380 pcpu, pol->pkt.vm_name); 381 382 } else { 383 pol->core_share[count].pcpu = pcpu; 384 RTE_LOG(INFO, CHANNEL_MONITOR, 385 "Monitoring pcpu %d for %s\n", 386 pcpu, pol->pkt.vm_name); 387 } 388 return ret; 389 } 390 391 static void 392 get_pcpu_to_control(struct policy *pol) 393 { 394 395 /* Convert vcpu to pcpu. */ 396 struct vm_info info; 397 int pcpu, count; 398 struct core_info *ci; 399 400 ci = get_core_info(); 401 402 RTE_LOG(DEBUG, CHANNEL_MONITOR, 403 "Looking for pcpu for %s\n", pol->pkt.vm_name); 404 405 /* 406 * So now that we're handling virtual and physical cores, we need to 407 * differenciate between them when adding them to the branch monitor. 408 * Virtual cores need to be converted to physical cores. 409 */ 410 if (pol->pkt.core_type == RTE_POWER_CORE_TYPE_VIRTUAL) { 411 /* 412 * If the cores in the policy are virtual, we need to map them 413 * to physical core. We look up the vm info and use that for 414 * the mapping. 415 */ 416 get_info_vm(pol->pkt.vm_name, &info); 417 for (count = 0; count < pol->pkt.num_vcpu; count++) { 418 pcpu = info.pcpu_map[pol->pkt.vcpu_to_control[count]]; 419 pcpu_monitor(pol, ci, pcpu, count); 420 } 421 } else { 422 /* 423 * If the cores in the policy are physical, we just use 424 * those core id's directly. 425 */ 426 for (count = 0; count < pol->pkt.num_vcpu; count++) { 427 pcpu = pol->pkt.vcpu_to_control[count]; 428 pcpu_monitor(pol, ci, pcpu, count); 429 } 430 } 431 } 432 433 static int 434 get_pfid(struct policy *pol) 435 { 436 437 int i, x, ret = 0; 438 439 for (i = 0; i < pol->pkt.nb_mac_to_monitor; i++) { 440 441 RTE_ETH_FOREACH_DEV(x) { 442 #ifdef RTE_NET_I40E 443 ret = rte_pmd_i40e_query_vfid_by_mac(x, 444 (struct rte_ether_addr *)&(pol->pkt.vfid[i])); 445 #else 446 ret = -ENOTSUP; 447 #endif 448 if (ret != -EINVAL) { 449 pol->port[i] = x; 450 break; 451 } 452 } 453 if (ret == -EINVAL || ret == -ENOTSUP || ret == ENODEV) { 454 RTE_LOG(INFO, CHANNEL_MONITOR, 455 "Error with Policy. MAC not found on " 456 "attached ports "); 457 pol->enabled = 0; 458 return ret; 459 } 460 pol->pfid[i] = ret; 461 } 462 return 1; 463 } 464 465 static int 466 update_policy(struct rte_power_channel_packet *pkt) 467 { 468 469 unsigned int updated = 0; 470 unsigned int i; 471 472 473 RTE_LOG(INFO, CHANNEL_MONITOR, 474 "Applying policy for %s\n", pkt->vm_name); 475 476 for (i = 0; i < RTE_DIM(policies); i++) { 477 if (strcmp(policies[i].pkt.vm_name, pkt->vm_name) == 0) { 478 /* Copy the contents of *pkt into the policy.pkt */ 479 policies[i].pkt = *pkt; 480 get_pcpu_to_control(&policies[i]); 481 /* Check Eth dev only for Traffic policy */ 482 if (policies[i].pkt.policy_to_use == 483 RTE_POWER_POLICY_TRAFFIC) { 484 if (get_pfid(&policies[i]) < 0) { 485 updated = 1; 486 break; 487 } 488 } 489 core_share_status(i); 490 policies[i].enabled = 1; 491 updated = 1; 492 } 493 } 494 if (!updated) { 495 for (i = 0; i < RTE_DIM(policies); i++) { 496 if (policies[i].enabled == 0) { 497 policies[i].pkt = *pkt; 498 get_pcpu_to_control(&policies[i]); 499 /* Check Eth dev only for Traffic policy */ 500 if (policies[i].pkt.policy_to_use == 501 RTE_POWER_POLICY_TRAFFIC) { 502 if (get_pfid(&policies[i]) < 0) { 503 updated = 1; 504 break; 505 } 506 } 507 core_share_status(i); 508 policies[i].enabled = 1; 509 break; 510 } 511 } 512 } 513 return 0; 514 } 515 516 static int 517 remove_policy(struct rte_power_channel_packet *pkt __rte_unused) 518 { 519 unsigned int i; 520 521 /* 522 * Disabling the policy is simply a case of setting 523 * enabled to 0 524 */ 525 for (i = 0; i < RTE_DIM(policies); i++) { 526 if (strcmp(policies[i].pkt.vm_name, pkt->vm_name) == 0) { 527 policies[i].enabled = 0; 528 return 0; 529 } 530 } 531 return -1; 532 } 533 534 static uint64_t 535 get_pkt_diff(struct policy *pol) 536 { 537 538 uint64_t vsi_pkt_count, 539 vsi_pkt_total = 0, 540 vsi_pkt_count_prev_total = 0; 541 double rdtsc_curr, rdtsc_diff, diff; 542 int x; 543 #ifdef RTE_NET_I40E 544 struct rte_eth_stats vf_stats; 545 #endif 546 547 for (x = 0; x < pol->pkt.nb_mac_to_monitor; x++) { 548 549 #ifdef RTE_NET_I40E 550 /*Read vsi stats*/ 551 if (rte_pmd_i40e_get_vf_stats(x, pol->pfid[x], &vf_stats) == 0) 552 vsi_pkt_count = vf_stats.ipackets; 553 else 554 vsi_pkt_count = -1; 555 #else 556 vsi_pkt_count = -1; 557 #endif 558 559 vsi_pkt_total += vsi_pkt_count; 560 561 vsi_pkt_count_prev_total += vsi_pkt_count_prev[pol->pfid[x]]; 562 vsi_pkt_count_prev[pol->pfid[x]] = vsi_pkt_count; 563 } 564 565 rdtsc_curr = rte_rdtsc_precise(); 566 rdtsc_diff = rdtsc_curr - rdtsc_prev[pol->pfid[x-1]]; 567 rdtsc_prev[pol->pfid[x-1]] = rdtsc_curr; 568 569 diff = (vsi_pkt_total - vsi_pkt_count_prev_total) * 570 ((double)rte_get_tsc_hz() / rdtsc_diff); 571 572 return diff; 573 } 574 575 static void 576 apply_traffic_profile(struct policy *pol) 577 { 578 579 int count; 580 uint64_t diff = 0; 581 582 diff = get_pkt_diff(pol); 583 584 if (diff >= (pol->pkt.traffic_policy.max_max_packet_thresh)) { 585 for (count = 0; count < pol->pkt.num_vcpu; count++) { 586 if (pol->core_share[count].status != 1) 587 power_manager_scale_core_max( 588 pol->core_share[count].pcpu); 589 } 590 } else if (diff >= (pol->pkt.traffic_policy.avg_max_packet_thresh)) { 591 for (count = 0; count < pol->pkt.num_vcpu; count++) { 592 if (pol->core_share[count].status != 1) 593 power_manager_scale_core_med( 594 pol->core_share[count].pcpu); 595 } 596 } else if (diff < (pol->pkt.traffic_policy.avg_max_packet_thresh)) { 597 for (count = 0; count < pol->pkt.num_vcpu; count++) { 598 if (pol->core_share[count].status != 1) 599 power_manager_scale_core_min( 600 pol->core_share[count].pcpu); 601 } 602 } 603 } 604 605 static void 606 apply_time_profile(struct policy *pol) 607 { 608 609 int count, x; 610 struct timeval tv; 611 struct tm *ptm; 612 char time_string[40]; 613 614 /* Obtain the time of day, and convert it to a tm struct. */ 615 gettimeofday(&tv, NULL); 616 ptm = localtime(&tv.tv_sec); 617 /* Format the date and time, down to a single second. */ 618 strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ptm); 619 620 for (x = 0; x < RTE_POWER_HOURS_PER_DAY; x++) { 621 622 if (ptm->tm_hour == pol->pkt.timer_policy.busy_hours[x]) { 623 for (count = 0; count < pol->pkt.num_vcpu; count++) { 624 if (pol->core_share[count].status != 1) { 625 power_manager_scale_core_max( 626 pol->core_share[count].pcpu); 627 } 628 } 629 break; 630 } else if (ptm->tm_hour == 631 pol->pkt.timer_policy.quiet_hours[x]) { 632 for (count = 0; count < pol->pkt.num_vcpu; count++) { 633 if (pol->core_share[count].status != 1) { 634 power_manager_scale_core_min( 635 pol->core_share[count].pcpu); 636 } 637 } 638 break; 639 } else if (ptm->tm_hour == 640 pol->pkt.timer_policy.hours_to_use_traffic_profile[x]) { 641 apply_traffic_profile(pol); 642 break; 643 } 644 } 645 } 646 647 static void 648 apply_workload_profile(struct policy *pol) 649 { 650 651 int count; 652 653 if (pol->pkt.workload == RTE_POWER_WL_HIGH) { 654 for (count = 0; count < pol->pkt.num_vcpu; count++) { 655 if (pol->core_share[count].status != 1) 656 power_manager_scale_core_max( 657 pol->core_share[count].pcpu); 658 } 659 } else if (pol->pkt.workload == RTE_POWER_WL_MEDIUM) { 660 for (count = 0; count < pol->pkt.num_vcpu; count++) { 661 if (pol->core_share[count].status != 1) 662 power_manager_scale_core_med( 663 pol->core_share[count].pcpu); 664 } 665 } else if (pol->pkt.workload == RTE_POWER_WL_LOW) { 666 for (count = 0; count < pol->pkt.num_vcpu; count++) { 667 if (pol->core_share[count].status != 1) 668 power_manager_scale_core_min( 669 pol->core_share[count].pcpu); 670 } 671 } 672 } 673 674 static void 675 apply_policy(struct policy *pol) 676 { 677 678 struct rte_power_channel_packet *pkt = &pol->pkt; 679 680 /*Check policy to use*/ 681 if (pkt->policy_to_use == RTE_POWER_POLICY_TRAFFIC) 682 apply_traffic_profile(pol); 683 else if (pkt->policy_to_use == RTE_POWER_POLICY_TIME) 684 apply_time_profile(pol); 685 else if (pkt->policy_to_use == RTE_POWER_POLICY_WORKLOAD) 686 apply_workload_profile(pol); 687 } 688 689 static int 690 write_binary_packet(void *buffer, 691 size_t buffer_len, 692 struct channel_info *chan_info) 693 { 694 int ret; 695 696 if (buffer_len == 0 || buffer == NULL) 697 return -1; 698 699 if (chan_info->fd < 0) { 700 RTE_LOG(ERR, CHANNEL_MONITOR, "Channel is not connected\n"); 701 return -1; 702 } 703 704 while (buffer_len > 0) { 705 ret = write(chan_info->fd, buffer, buffer_len); 706 if (ret == -1) { 707 if (errno == EINTR) 708 continue; 709 RTE_LOG(ERR, CHANNEL_MONITOR, "Write function failed due to %s.\n", 710 strerror(errno)); 711 return -1; 712 } 713 buffer = (char *)buffer + ret; 714 buffer_len -= ret; 715 } 716 return 0; 717 } 718 719 static int 720 send_freq(struct rte_power_channel_packet *pkt, 721 struct channel_info *chan_info, 722 bool freq_list) 723 { 724 unsigned int vcore_id = pkt->resource_id; 725 struct rte_power_channel_packet_freq_list channel_pkt_freq_list; 726 struct vm_info info; 727 728 if (get_info_vm(pkt->vm_name, &info) != 0) 729 return -1; 730 731 if (!freq_list && vcore_id >= RTE_POWER_MAX_VCPU_PER_VM) 732 return -1; 733 734 if (!info.allow_query) 735 return -1; 736 737 channel_pkt_freq_list.command = RTE_POWER_FREQ_LIST; 738 channel_pkt_freq_list.num_vcpu = info.num_vcpus; 739 740 if (freq_list) { 741 unsigned int i; 742 for (i = 0; i < info.num_vcpus; i++) 743 channel_pkt_freq_list.freq_list[i] = 744 power_manager_get_current_frequency(info.pcpu_map[i]); 745 } else { 746 channel_pkt_freq_list.freq_list[vcore_id] = 747 power_manager_get_current_frequency(info.pcpu_map[vcore_id]); 748 } 749 750 return write_binary_packet(&channel_pkt_freq_list, 751 sizeof(channel_pkt_freq_list), 752 chan_info); 753 } 754 755 static int 756 send_capabilities(struct rte_power_channel_packet *pkt, 757 struct channel_info *chan_info, 758 bool list_requested) 759 { 760 unsigned int vcore_id = pkt->resource_id; 761 struct rte_power_channel_packet_caps_list channel_pkt_caps_list; 762 struct vm_info info; 763 struct rte_power_core_capabilities caps; 764 int ret; 765 766 if (get_info_vm(pkt->vm_name, &info) != 0) 767 return -1; 768 769 if (!list_requested && vcore_id >= RTE_POWER_MAX_VCPU_PER_VM) 770 return -1; 771 772 if (!info.allow_query) 773 return -1; 774 775 channel_pkt_caps_list.command = RTE_POWER_CAPS_LIST; 776 channel_pkt_caps_list.num_vcpu = info.num_vcpus; 777 778 if (list_requested) { 779 unsigned int i; 780 for (i = 0; i < info.num_vcpus; i++) { 781 ret = rte_power_get_capabilities(info.pcpu_map[i], 782 &caps); 783 if (ret == 0) { 784 channel_pkt_caps_list.turbo[i] = 785 caps.turbo; 786 channel_pkt_caps_list.priority[i] = 787 caps.priority; 788 } else 789 return -1; 790 791 } 792 } else { 793 ret = rte_power_get_capabilities(info.pcpu_map[vcore_id], 794 &caps); 795 if (ret == 0) { 796 channel_pkt_caps_list.turbo[vcore_id] = 797 caps.turbo; 798 channel_pkt_caps_list.priority[vcore_id] = 799 caps.priority; 800 } else 801 return -1; 802 } 803 804 return write_binary_packet(&channel_pkt_caps_list, 805 sizeof(channel_pkt_caps_list), 806 chan_info); 807 } 808 809 static int 810 send_ack_for_received_cmd(struct rte_power_channel_packet *pkt, 811 struct channel_info *chan_info, 812 uint32_t command) 813 { 814 pkt->command = command; 815 return write_binary_packet(pkt, 816 sizeof(*pkt), 817 chan_info); 818 } 819 820 static int 821 process_request(struct rte_power_channel_packet *pkt, 822 struct channel_info *chan_info) 823 { 824 int ret; 825 826 if (chan_info == NULL) 827 return -1; 828 829 uint32_t channel_connected = CHANNEL_MGR_CHANNEL_CONNECTED; 830 if (__atomic_compare_exchange_n(&(chan_info->status), &channel_connected, 831 CHANNEL_MGR_CHANNEL_PROCESSING, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED) == 0) 832 return -1; 833 834 if (pkt->command == RTE_POWER_CPU_POWER) { 835 unsigned int core_num; 836 837 if (pkt->core_type == RTE_POWER_CORE_TYPE_VIRTUAL) 838 core_num = get_pcpu(chan_info, pkt->resource_id); 839 else 840 core_num = pkt->resource_id; 841 842 RTE_LOG(DEBUG, CHANNEL_MONITOR, "Processing requested cmd for cpu:%d\n", 843 core_num); 844 845 int scale_res; 846 bool valid_unit = true; 847 848 switch (pkt->unit) { 849 case(RTE_POWER_SCALE_MIN): 850 scale_res = power_manager_scale_core_min(core_num); 851 break; 852 case(RTE_POWER_SCALE_MAX): 853 scale_res = power_manager_scale_core_max(core_num); 854 break; 855 case(RTE_POWER_SCALE_DOWN): 856 scale_res = power_manager_scale_core_down(core_num); 857 break; 858 case(RTE_POWER_SCALE_UP): 859 scale_res = power_manager_scale_core_up(core_num); 860 break; 861 case(RTE_POWER_ENABLE_TURBO): 862 scale_res = power_manager_enable_turbo_core(core_num); 863 break; 864 case(RTE_POWER_DISABLE_TURBO): 865 scale_res = power_manager_disable_turbo_core(core_num); 866 break; 867 default: 868 valid_unit = false; 869 break; 870 } 871 872 if (valid_unit) { 873 ret = send_ack_for_received_cmd(pkt, 874 chan_info, 875 scale_res >= 0 ? 876 RTE_POWER_CMD_ACK : 877 RTE_POWER_CMD_NACK); 878 if (ret < 0) 879 RTE_LOG(ERR, CHANNEL_MONITOR, "Error during sending ack command.\n"); 880 } else 881 RTE_LOG(ERR, CHANNEL_MONITOR, "Unexpected unit type.\n"); 882 883 } 884 885 if (pkt->command == RTE_POWER_PKT_POLICY) { 886 RTE_LOG(INFO, CHANNEL_MONITOR, "Processing policy request %s\n", 887 pkt->vm_name); 888 int ret = send_ack_for_received_cmd(pkt, 889 chan_info, 890 RTE_POWER_CMD_ACK); 891 if (ret < 0) 892 RTE_LOG(ERR, CHANNEL_MONITOR, "Error during sending ack command.\n"); 893 update_policy(pkt); 894 policy_is_set = 1; 895 } 896 897 if (pkt->command == RTE_POWER_PKT_POLICY_REMOVE) { 898 ret = remove_policy(pkt); 899 if (ret == 0) 900 RTE_LOG(INFO, CHANNEL_MONITOR, 901 "Removed policy %s\n", pkt->vm_name); 902 else 903 RTE_LOG(INFO, CHANNEL_MONITOR, 904 "Policy %s does not exist\n", pkt->vm_name); 905 } 906 907 if (pkt->command == RTE_POWER_QUERY_FREQ_LIST || 908 pkt->command == RTE_POWER_QUERY_FREQ) { 909 910 RTE_LOG(INFO, CHANNEL_MONITOR, 911 "Frequency for %s requested.\n", pkt->vm_name); 912 int ret = send_freq(pkt, 913 chan_info, 914 pkt->command == RTE_POWER_QUERY_FREQ_LIST); 915 if (ret < 0) 916 RTE_LOG(ERR, CHANNEL_MONITOR, "Error during frequency sending.\n"); 917 } 918 919 if (pkt->command == RTE_POWER_QUERY_CAPS_LIST || 920 pkt->command == RTE_POWER_QUERY_CAPS) { 921 922 RTE_LOG(INFO, CHANNEL_MONITOR, 923 "Capabilities for %s requested.\n", pkt->vm_name); 924 int ret = send_capabilities(pkt, 925 chan_info, 926 pkt->command == RTE_POWER_QUERY_CAPS_LIST); 927 if (ret < 0) 928 RTE_LOG(ERR, CHANNEL_MONITOR, "Error during sending capabilities.\n"); 929 } 930 931 /* 932 * Return is not checked as channel status may have been set to DISABLED 933 * from management thread 934 */ 935 uint32_t channel_processing = CHANNEL_MGR_CHANNEL_PROCESSING; 936 __atomic_compare_exchange_n(&(chan_info->status), &channel_processing, 937 CHANNEL_MGR_CHANNEL_CONNECTED, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); 938 return 0; 939 940 } 941 942 int 943 add_channel_to_monitor(struct channel_info **chan_info) 944 { 945 struct channel_info *info = *chan_info; 946 struct epoll_event event; 947 948 event.events = EPOLLIN; 949 event.data.ptr = info; 950 if (epoll_ctl(global_event_fd, EPOLL_CTL_ADD, info->fd, &event) < 0) { 951 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to add channel '%s' " 952 "to epoll\n", info->channel_path); 953 return -1; 954 } 955 RTE_LOG(ERR, CHANNEL_MONITOR, "Added channel '%s' " 956 "to monitor\n", info->channel_path); 957 return 0; 958 } 959 960 int 961 remove_channel_from_monitor(struct channel_info *chan_info) 962 { 963 if (epoll_ctl(global_event_fd, EPOLL_CTL_DEL, 964 chan_info->fd, NULL) < 0) { 965 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to remove channel '%s' " 966 "from epoll\n", chan_info->channel_path); 967 return -1; 968 } 969 return 0; 970 } 971 972 int 973 channel_monitor_init(void) 974 { 975 global_event_fd = epoll_create1(0); 976 if (global_event_fd == 0) { 977 RTE_LOG(ERR, CHANNEL_MONITOR, 978 "Error creating epoll context with error %s\n", 979 strerror(errno)); 980 return -1; 981 } 982 global_events_list = rte_malloc("epoll_events", 983 sizeof(*global_events_list) 984 * MAX_EVENTS, RTE_CACHE_LINE_SIZE); 985 if (global_events_list == NULL) { 986 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to rte_malloc for " 987 "epoll events\n"); 988 return -1; 989 } 990 return 0; 991 } 992 993 static void 994 read_binary_packet(struct channel_info *chan_info) 995 { 996 struct rte_power_channel_packet pkt; 997 void *buffer = &pkt; 998 int buffer_len = sizeof(pkt); 999 int n_bytes, err = 0; 1000 1001 while (buffer_len > 0) { 1002 n_bytes = read(chan_info->fd, 1003 buffer, buffer_len); 1004 if (n_bytes == buffer_len) 1005 break; 1006 if (n_bytes < 0) { 1007 err = errno; 1008 RTE_LOG(DEBUG, CHANNEL_MONITOR, 1009 "Received error on " 1010 "channel '%s' read: %s\n", 1011 chan_info->channel_path, 1012 strerror(err)); 1013 remove_channel(&chan_info); 1014 break; 1015 } 1016 buffer = (char *)buffer + n_bytes; 1017 buffer_len -= n_bytes; 1018 } 1019 if (!err) 1020 process_request(&pkt, chan_info); 1021 } 1022 1023 #ifdef USE_JANSSON 1024 static void 1025 read_json_packet(struct channel_info *chan_info) 1026 { 1027 struct rte_power_channel_packet pkt; 1028 int n_bytes, ret; 1029 json_t *root; 1030 json_error_t error; 1031 const char *resource_name; 1032 char *start, *end; 1033 uint32_t n; 1034 1035 1036 /* read opening brace to closing brace */ 1037 do { 1038 int idx = 0; 1039 int indent = 0; 1040 do { 1041 n_bytes = read(chan_info->fd, &json_data[idx], 1); 1042 if (n_bytes == 0) 1043 break; 1044 if (json_data[idx] == '{') 1045 indent++; 1046 if (json_data[idx] == '}') 1047 indent--; 1048 if ((indent > 0) || (idx > 0)) 1049 idx++; 1050 if (indent <= 0) 1051 json_data[idx] = 0; 1052 if (idx >= MAX_JSON_STRING_LEN-1) 1053 break; 1054 } while (indent > 0); 1055 1056 json_data[idx] = '\0'; 1057 1058 if (strlen(json_data) == 0) 1059 continue; 1060 1061 printf("got [%s]\n", json_data); 1062 1063 root = json_loads(json_data, 0, &error); 1064 1065 if (root) { 1066 resource_name = get_resource_name_from_chn_path( 1067 chan_info->channel_path); 1068 /* 1069 * Because our data is now in the json 1070 * object, we can overwrite the pkt 1071 * with a rte_power_channel_packet struct, using 1072 * parse_json_to_pkt() 1073 */ 1074 ret = parse_json_to_pkt(root, &pkt, resource_name); 1075 json_decref(root); 1076 if (ret) { 1077 RTE_LOG(ERR, CHANNEL_MONITOR, 1078 "Error validating JSON profile data\n"); 1079 break; 1080 } 1081 start = strstr(pkt.vm_name, 1082 CHANNEL_MGR_FIFO_PATTERN_NAME); 1083 if (start != NULL) { 1084 /* move past pattern to start of fifo id */ 1085 start += strlen(CHANNEL_MGR_FIFO_PATTERN_NAME); 1086 1087 end = start; 1088 n = (uint32_t)strtoul(start, &end, 10); 1089 1090 if (end[0] == '\0') { 1091 /* Add core id to core list */ 1092 pkt.num_vcpu = 1; 1093 pkt.vcpu_to_control[0] = n; 1094 process_request(&pkt, chan_info); 1095 } else { 1096 RTE_LOG(ERR, CHANNEL_MONITOR, 1097 "Cannot extract core id from fifo name\n"); 1098 } 1099 } else { 1100 process_request(&pkt, chan_info); 1101 } 1102 } else { 1103 RTE_LOG(ERR, CHANNEL_MONITOR, 1104 "JSON error on line %d: %s\n", 1105 error.line, error.text); 1106 } 1107 } while (n_bytes > 0); 1108 } 1109 #endif 1110 1111 void 1112 run_channel_monitor(void) 1113 { 1114 while (run_loop) { 1115 int n_events, i; 1116 1117 n_events = epoll_wait(global_event_fd, global_events_list, 1118 MAX_EVENTS, 1); 1119 if (!run_loop) 1120 break; 1121 for (i = 0; i < n_events; i++) { 1122 struct channel_info *chan_info = (struct channel_info *) 1123 global_events_list[i].data.ptr; 1124 if ((global_events_list[i].events & EPOLLERR) || 1125 (global_events_list[i].events & EPOLLHUP)) { 1126 RTE_LOG(INFO, CHANNEL_MONITOR, 1127 "Remote closed connection for " 1128 "channel '%s'\n", 1129 chan_info->channel_path); 1130 remove_channel(&chan_info); 1131 continue; 1132 } 1133 if (global_events_list[i].events & EPOLLIN) { 1134 1135 switch (chan_info->type) { 1136 case CHANNEL_TYPE_BINARY: 1137 read_binary_packet(chan_info); 1138 break; 1139 #ifdef USE_JANSSON 1140 case CHANNEL_TYPE_JSON: 1141 read_json_packet(chan_info); 1142 break; 1143 #endif 1144 default: 1145 break; 1146 } 1147 } 1148 } 1149 rte_delay_us(time_period_ms*1000); 1150 if (policy_is_set) { 1151 unsigned int j; 1152 1153 for (j = 0; j < RTE_DIM(policies); j++) { 1154 if (policies[j].enabled == 1) 1155 apply_policy(&policies[j]); 1156 } 1157 } 1158 } 1159 } 1160