power: rename public structs
[dpdk.git] / examples / vm_power_manager / channel_monitor.c
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_atomic.h>
29 #include <rte_cycles.h>
30 #include <rte_ethdev.h>
31 #ifdef RTE_NET_I40E
32 #include <rte_pmd_i40e.h>
33 #endif
34 #include <rte_power.h>
35
36 #include <libvirt/libvirt.h>
37 #include "channel_monitor.h"
38 #include "rte_power_guest_channel.h"
39 #include "channel_manager.h"
40 #include "power_manager.h"
41 #include "oob_monitor.h"
42
43 #define RTE_LOGTYPE_CHANNEL_MONITOR RTE_LOGTYPE_USER1
44
45 #define MAX_EVENTS 256
46
47 uint64_t vsi_pkt_count_prev[384];
48 uint64_t rdtsc_prev[384];
49 #define MAX_JSON_STRING_LEN 1024
50 char json_data[MAX_JSON_STRING_LEN];
51
52 double time_period_ms = 1;
53 static volatile unsigned run_loop = 1;
54 static int global_event_fd;
55 static unsigned int policy_is_set;
56 static struct epoll_event *global_events_list;
57 static struct policy policies[RTE_MAX_LCORE];
58
59 #ifdef USE_JANSSON
60
61 union PFID {
62         struct rte_ether_addr addr;
63         uint64_t pfid;
64 };
65
66 static int
67 str_to_ether_addr(const char *a, struct rte_ether_addr *ether_addr)
68 {
69         int i;
70         char *end;
71         unsigned long o[RTE_ETHER_ADDR_LEN];
72
73         i = 0;
74         do {
75                 errno = 0;
76                 o[i] = strtoul(a, &end, 16);
77                 if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
78                         return -1;
79                 a = end + 1;
80         } while (++i != RTE_DIM(o) / sizeof(o[0]) && end[0] != 0);
81
82         /* Junk at the end of line */
83         if (end[0] != 0)
84                 return -1;
85
86         /* Support the format XX:XX:XX:XX:XX:XX */
87         if (i == RTE_ETHER_ADDR_LEN) {
88                 while (i-- != 0) {
89                         if (o[i] > UINT8_MAX)
90                                 return -1;
91                         ether_addr->addr_bytes[i] = (uint8_t)o[i];
92                 }
93         /* Support the format XXXX:XXXX:XXXX */
94         } else if (i == RTE_ETHER_ADDR_LEN / 2) {
95                 while (i-- != 0) {
96                         if (o[i] > UINT16_MAX)
97                                 return -1;
98                         ether_addr->addr_bytes[i * 2] =
99                                         (uint8_t)(o[i] >> 8);
100                         ether_addr->addr_bytes[i * 2 + 1] =
101                                         (uint8_t)(o[i] & 0xff);
102                 }
103         /* unknown format */
104         } else
105                 return -1;
106
107         return 0;
108 }
109
110 static int
111 set_policy_mac(struct rte_power_channel_packet *pkt, int idx, char *mac)
112 {
113         union PFID pfid;
114         int ret;
115
116         /* Use port MAC address as the vfid */
117         ret = str_to_ether_addr(mac, &pfid.addr);
118
119         if (ret != 0) {
120                 RTE_LOG(ERR, CHANNEL_MONITOR,
121                         "Invalid mac address received in JSON\n");
122                 pkt->vfid[idx] = 0;
123                 return -1;
124         }
125
126         printf("Received MAC Address: %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":"
127                         "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n",
128                         pfid.addr.addr_bytes[0], pfid.addr.addr_bytes[1],
129                         pfid.addr.addr_bytes[2], pfid.addr.addr_bytes[3],
130                         pfid.addr.addr_bytes[4], pfid.addr.addr_bytes[5]);
131
132         pkt->vfid[idx] = pfid.pfid;
133         return 0;
134 }
135
136 static char*
137 get_resource_name_from_chn_path(const char *channel_path)
138 {
139         char *substr = NULL;
140
141         substr = strstr(channel_path, CHANNEL_MGR_FIFO_PATTERN_NAME);
142
143         return substr;
144 }
145
146 static int
147 get_resource_id_from_vmname(const char *vm_name)
148 {
149         int result = -1;
150         int off = 0;
151
152         if (vm_name == NULL)
153                 return -1;
154
155         while (vm_name[off] != '\0') {
156                 if (isdigit(vm_name[off]))
157                         break;
158                 off++;
159         }
160         result = atoi(&vm_name[off]);
161         if ((result == 0) && (vm_name[off] != '0'))
162                 return -1;
163
164         return result;
165 }
166
167 static int
168 parse_json_to_pkt(json_t *element, struct rte_power_channel_packet *pkt,
169                                         const char *vm_name)
170 {
171         const char *key;
172         json_t *value;
173         int ret;
174         int resource_id;
175
176         memset(pkt, 0, sizeof(*pkt));
177
178         pkt->nb_mac_to_monitor = 0;
179         pkt->t_boost_status.tbEnabled = false;
180         pkt->workload = LOW;
181         pkt->policy_to_use = TIME;
182         pkt->command = PKT_POLICY;
183         pkt->core_type = CORE_TYPE_PHYSICAL;
184
185         if (vm_name == NULL) {
186                 RTE_LOG(ERR, CHANNEL_MONITOR,
187                         "vm_name is NULL, request rejected !\n");
188                 return -1;
189         }
190
191         json_object_foreach(element, key, value) {
192                 if (!strcmp(key, "policy")) {
193                         /* Recurse in to get the contents of profile */
194                         ret = parse_json_to_pkt(value, pkt, vm_name);
195                         if (ret)
196                                 return ret;
197                 } else if (!strcmp(key, "instruction")) {
198                         /* Recurse in to get the contents of instruction */
199                         ret = parse_json_to_pkt(value, pkt, vm_name);
200                         if (ret)
201                                 return ret;
202                 } else if (!strcmp(key, "command")) {
203                         char command[32];
204                         strlcpy(command, json_string_value(value), 32);
205                         if (!strcmp(command, "power")) {
206                                 pkt->command = CPU_POWER;
207                         } else if (!strcmp(command, "create")) {
208                                 pkt->command = PKT_POLICY;
209                         } else if (!strcmp(command, "destroy")) {
210                                 pkt->command = PKT_POLICY_REMOVE;
211                         } else {
212                                 RTE_LOG(ERR, CHANNEL_MONITOR,
213                                         "Invalid command received in JSON\n");
214                                 return -1;
215                         }
216                 } else if (!strcmp(key, "policy_type")) {
217                         char command[32];
218                         strlcpy(command, json_string_value(value), 32);
219                         if (!strcmp(command, "TIME")) {
220                                 pkt->policy_to_use = TIME;
221                         } else if (!strcmp(command, "TRAFFIC")) {
222                                 pkt->policy_to_use = TRAFFIC;
223                         } else if (!strcmp(command, "WORKLOAD")) {
224                                 pkt->policy_to_use = WORKLOAD;
225                         } else if (!strcmp(command, "BRANCH_RATIO")) {
226                                 pkt->policy_to_use = 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 = HIGH;
237                         } else if (!strcmp(command, "MEDIUM")) {
238                                 pkt->workload = MEDIUM;
239                         } else if (!strcmp(command, "LOW")) {
240                                 pkt->workload = 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 = CPU_POWER_SCALE_UP;
287                         } else if (!strcmp(unit, "SCALE_DOWN")) {
288                                 pkt->unit = CPU_POWER_SCALE_DOWN;
289                         } else if (!strcmp(unit, "SCALE_MAX")) {
290                                 pkt->unit = CPU_POWER_SCALE_MAX;
291                         } else if (!strcmp(unit, "SCALE_MIN")) {
292                                 pkt->unit = CPU_POWER_SCALE_MIN;
293                         } else if (!strcmp(unit, "ENABLE_TURBO")) {
294                                 pkt->unit = CPU_POWER_ENABLE_TURBO;
295                         } else if (!strcmp(unit, "DISABLE_TURBO")) {
296                                 pkt->unit = CPU_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, 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 == 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 == 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 == TRAFFIC) {
483                                 if (get_pfid(&policies[i]) < 0) {
484                                         updated = 1;
485                                         break;
486                                 }
487                         }
488                         core_share_status(i);
489                         policies[i].enabled = 1;
490                         updated = 1;
491                 }
492         }
493         if (!updated) {
494                 for (i = 0; i < RTE_DIM(policies); i++) {
495                         if (policies[i].enabled == 0) {
496                                 policies[i].pkt = *pkt;
497                                 get_pcpu_to_control(&policies[i]);
498                                 /* Check Eth dev only for Traffic policy */
499                                 if (policies[i].pkt.policy_to_use == TRAFFIC) {
500                                         if (get_pfid(&policies[i]) < 0) {
501                                                 updated = 1;
502                                                 break;
503                                         }
504                                 }
505                                 core_share_status(i);
506                                 policies[i].enabled = 1;
507                                 break;
508                         }
509                 }
510         }
511         return 0;
512 }
513
514 static int
515 remove_policy(struct rte_power_channel_packet *pkt __rte_unused)
516 {
517         unsigned int i;
518
519         /*
520          * Disabling the policy is simply a case of setting
521          * enabled to 0
522          */
523         for (i = 0; i < RTE_DIM(policies); i++) {
524                 if (strcmp(policies[i].pkt.vm_name, pkt->vm_name) == 0) {
525                         policies[i].enabled = 0;
526                         return 0;
527                 }
528         }
529         return -1;
530 }
531
532 static uint64_t
533 get_pkt_diff(struct policy *pol)
534 {
535
536         uint64_t vsi_pkt_count,
537                 vsi_pkt_total = 0,
538                 vsi_pkt_count_prev_total = 0;
539         double rdtsc_curr, rdtsc_diff, diff;
540         int x;
541 #ifdef RTE_NET_I40E
542         struct rte_eth_stats vf_stats;
543 #endif
544
545         for (x = 0; x < pol->pkt.nb_mac_to_monitor; x++) {
546
547 #ifdef RTE_NET_I40E
548                 /*Read vsi stats*/
549                 if (rte_pmd_i40e_get_vf_stats(x, pol->pfid[x], &vf_stats) == 0)
550                         vsi_pkt_count = vf_stats.ipackets;
551                 else
552                         vsi_pkt_count = -1;
553 #else
554                 vsi_pkt_count = -1;
555 #endif
556
557                 vsi_pkt_total += vsi_pkt_count;
558
559                 vsi_pkt_count_prev_total += vsi_pkt_count_prev[pol->pfid[x]];
560                 vsi_pkt_count_prev[pol->pfid[x]] = vsi_pkt_count;
561         }
562
563         rdtsc_curr = rte_rdtsc_precise();
564         rdtsc_diff = rdtsc_curr - rdtsc_prev[pol->pfid[x-1]];
565         rdtsc_prev[pol->pfid[x-1]] = rdtsc_curr;
566
567         diff = (vsi_pkt_total - vsi_pkt_count_prev_total) *
568                         ((double)rte_get_tsc_hz() / rdtsc_diff);
569
570         return diff;
571 }
572
573 static void
574 apply_traffic_profile(struct policy *pol)
575 {
576
577         int count;
578         uint64_t diff = 0;
579
580         diff = get_pkt_diff(pol);
581
582         if (diff >= (pol->pkt.traffic_policy.max_max_packet_thresh)) {
583                 for (count = 0; count < pol->pkt.num_vcpu; count++) {
584                         if (pol->core_share[count].status != 1)
585                                 power_manager_scale_core_max(
586                                                 pol->core_share[count].pcpu);
587                 }
588         } else if (diff >= (pol->pkt.traffic_policy.avg_max_packet_thresh)) {
589                 for (count = 0; count < pol->pkt.num_vcpu; count++) {
590                         if (pol->core_share[count].status != 1)
591                                 power_manager_scale_core_med(
592                                                 pol->core_share[count].pcpu);
593                 }
594         } else if (diff < (pol->pkt.traffic_policy.avg_max_packet_thresh)) {
595                 for (count = 0; count < pol->pkt.num_vcpu; count++) {
596                         if (pol->core_share[count].status != 1)
597                                 power_manager_scale_core_min(
598                                                 pol->core_share[count].pcpu);
599                 }
600         }
601 }
602
603 static void
604 apply_time_profile(struct policy *pol)
605 {
606
607         int count, x;
608         struct timeval tv;
609         struct tm *ptm;
610         char time_string[40];
611
612         /* Obtain the time of day, and convert it to a tm struct. */
613         gettimeofday(&tv, NULL);
614         ptm = localtime(&tv.tv_sec);
615         /* Format the date and time, down to a single second. */
616         strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ptm);
617
618         for (x = 0; x < HOURS; x++) {
619
620                 if (ptm->tm_hour == pol->pkt.timer_policy.busy_hours[x]) {
621                         for (count = 0; count < pol->pkt.num_vcpu; count++) {
622                                 if (pol->core_share[count].status != 1) {
623                                         power_manager_scale_core_max(
624                                                 pol->core_share[count].pcpu);
625                                 }
626                         }
627                         break;
628                 } else if (ptm->tm_hour ==
629                                 pol->pkt.timer_policy.quiet_hours[x]) {
630                         for (count = 0; count < pol->pkt.num_vcpu; count++) {
631                                 if (pol->core_share[count].status != 1) {
632                                         power_manager_scale_core_min(
633                                                 pol->core_share[count].pcpu);
634                         }
635                 }
636                         break;
637                 } else if (ptm->tm_hour ==
638                         pol->pkt.timer_policy.hours_to_use_traffic_profile[x]) {
639                         apply_traffic_profile(pol);
640                         break;
641                 }
642         }
643 }
644
645 static void
646 apply_workload_profile(struct policy *pol)
647 {
648
649         int count;
650
651         if (pol->pkt.workload == HIGH) {
652                 for (count = 0; count < pol->pkt.num_vcpu; count++) {
653                         if (pol->core_share[count].status != 1)
654                                 power_manager_scale_core_max(
655                                                 pol->core_share[count].pcpu);
656                 }
657         } else if (pol->pkt.workload == MEDIUM) {
658                 for (count = 0; count < pol->pkt.num_vcpu; count++) {
659                         if (pol->core_share[count].status != 1)
660                                 power_manager_scale_core_med(
661                                                 pol->core_share[count].pcpu);
662                 }
663         } else if (pol->pkt.workload == LOW) {
664                 for (count = 0; count < pol->pkt.num_vcpu; count++) {
665                         if (pol->core_share[count].status != 1)
666                                 power_manager_scale_core_min(
667                                                 pol->core_share[count].pcpu);
668                 }
669         }
670 }
671
672 static void
673 apply_policy(struct policy *pol)
674 {
675
676         struct rte_power_channel_packet *pkt = &pol->pkt;
677
678         /*Check policy to use*/
679         if (pkt->policy_to_use == TRAFFIC)
680                 apply_traffic_profile(pol);
681         else if (pkt->policy_to_use == TIME)
682                 apply_time_profile(pol);
683         else if (pkt->policy_to_use == WORKLOAD)
684                 apply_workload_profile(pol);
685 }
686
687 static int
688 write_binary_packet(void *buffer,
689                 size_t buffer_len,
690                 struct channel_info *chan_info)
691 {
692         int ret;
693
694         if (buffer_len == 0 || buffer == NULL)
695                 return -1;
696
697         if (chan_info->fd < 0) {
698                 RTE_LOG(ERR, CHANNEL_MONITOR, "Channel is not connected\n");
699                 return -1;
700         }
701
702         while (buffer_len > 0) {
703                 ret = write(chan_info->fd, buffer, buffer_len);
704                 if (ret == -1) {
705                         if (errno == EINTR)
706                                 continue;
707                         RTE_LOG(ERR, CHANNEL_MONITOR, "Write function failed due to %s.\n",
708                                         strerror(errno));
709                         return -1;
710                 }
711                 buffer = (char *)buffer + ret;
712                 buffer_len -= ret;
713         }
714         return 0;
715 }
716
717 static int
718 send_freq(struct rte_power_channel_packet *pkt,
719                 struct channel_info *chan_info,
720                 bool freq_list)
721 {
722         unsigned int vcore_id = pkt->resource_id;
723         struct rte_power_channel_packet_freq_list channel_pkt_freq_list;
724         struct vm_info info;
725
726         if (get_info_vm(pkt->vm_name, &info) != 0)
727                 return -1;
728
729         if (!freq_list && vcore_id >= MAX_VCPU_PER_VM)
730                 return -1;
731
732         if (!info.allow_query)
733                 return -1;
734
735         channel_pkt_freq_list.command = CPU_POWER_FREQ_LIST;
736         channel_pkt_freq_list.num_vcpu = info.num_vcpus;
737
738         if (freq_list) {
739                 unsigned int i;
740                 for (i = 0; i < info.num_vcpus; i++)
741                         channel_pkt_freq_list.freq_list[i] =
742                           power_manager_get_current_frequency(info.pcpu_map[i]);
743         } else {
744                 channel_pkt_freq_list.freq_list[vcore_id] =
745                   power_manager_get_current_frequency(info.pcpu_map[vcore_id]);
746         }
747
748         return write_binary_packet(&channel_pkt_freq_list,
749                         sizeof(channel_pkt_freq_list),
750                         chan_info);
751 }
752
753 static int
754 send_capabilities(struct rte_power_channel_packet *pkt,
755                 struct channel_info *chan_info,
756                 bool list_requested)
757 {
758         unsigned int vcore_id = pkt->resource_id;
759         struct rte_power_channel_packet_caps_list channel_pkt_caps_list;
760         struct vm_info info;
761         struct rte_power_core_capabilities caps;
762         int ret;
763
764         if (get_info_vm(pkt->vm_name, &info) != 0)
765                 return -1;
766
767         if (!list_requested && vcore_id >= MAX_VCPU_PER_VM)
768                 return -1;
769
770         if (!info.allow_query)
771                 return -1;
772
773         channel_pkt_caps_list.command = CPU_POWER_CAPS_LIST;
774         channel_pkt_caps_list.num_vcpu = info.num_vcpus;
775
776         if (list_requested) {
777                 unsigned int i;
778                 for (i = 0; i < info.num_vcpus; i++) {
779                         ret = rte_power_get_capabilities(info.pcpu_map[i],
780                                         &caps);
781                         if (ret == 0) {
782                                 channel_pkt_caps_list.turbo[i] =
783                                                 caps.turbo;
784                                 channel_pkt_caps_list.priority[i] =
785                                                 caps.priority;
786                         } else
787                                 return -1;
788
789                 }
790         } else {
791                 ret = rte_power_get_capabilities(info.pcpu_map[vcore_id],
792                                 &caps);
793                 if (ret == 0) {
794                         channel_pkt_caps_list.turbo[vcore_id] =
795                                         caps.turbo;
796                         channel_pkt_caps_list.priority[vcore_id] =
797                                         caps.priority;
798                 } else
799                         return -1;
800         }
801
802         return write_binary_packet(&channel_pkt_caps_list,
803                         sizeof(channel_pkt_caps_list),
804                         chan_info);
805 }
806
807 static int
808 send_ack_for_received_cmd(struct rte_power_channel_packet *pkt,
809                 struct channel_info *chan_info,
810                 uint32_t command)
811 {
812         pkt->command = command;
813         return write_binary_packet(pkt,
814                         sizeof(*pkt),
815                         chan_info);
816 }
817
818 static int
819 process_request(struct rte_power_channel_packet *pkt,
820                 struct channel_info *chan_info)
821 {
822         int ret;
823
824         if (chan_info == NULL)
825                 return -1;
826
827         if (rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_CONNECTED,
828                         CHANNEL_MGR_CHANNEL_PROCESSING) == 0)
829                 return -1;
830
831         if (pkt->command == CPU_POWER) {
832                 unsigned int core_num;
833
834                 if (pkt->core_type == CORE_TYPE_VIRTUAL)
835                         core_num = get_pcpu(chan_info, pkt->resource_id);
836                 else
837                         core_num = pkt->resource_id;
838
839                 RTE_LOG(DEBUG, CHANNEL_MONITOR, "Processing requested cmd for cpu:%d\n",
840                         core_num);
841
842                 int scale_res;
843                 bool valid_unit = true;
844
845                 switch (pkt->unit) {
846                 case(CPU_POWER_SCALE_MIN):
847                         scale_res = power_manager_scale_core_min(core_num);
848                         break;
849                 case(CPU_POWER_SCALE_MAX):
850                         scale_res = power_manager_scale_core_max(core_num);
851                         break;
852                 case(CPU_POWER_SCALE_DOWN):
853                         scale_res = power_manager_scale_core_down(core_num);
854                         break;
855                 case(CPU_POWER_SCALE_UP):
856                         scale_res = power_manager_scale_core_up(core_num);
857                         break;
858                 case(CPU_POWER_ENABLE_TURBO):
859                         scale_res = power_manager_enable_turbo_core(core_num);
860                         break;
861                 case(CPU_POWER_DISABLE_TURBO):
862                         scale_res = power_manager_disable_turbo_core(core_num);
863                         break;
864                 default:
865                         valid_unit = false;
866                         break;
867                 }
868
869                 if (valid_unit) {
870                         ret = send_ack_for_received_cmd(pkt,
871                                         chan_info,
872                                         scale_res >= 0 ?
873                                                 CPU_POWER_CMD_ACK :
874                                                 CPU_POWER_CMD_NACK);
875                         if (ret < 0)
876                                 RTE_LOG(ERR, CHANNEL_MONITOR, "Error during sending ack command.\n");
877                 } else
878                         RTE_LOG(ERR, CHANNEL_MONITOR, "Unexpected unit type.\n");
879
880         }
881
882         if (pkt->command == PKT_POLICY) {
883                 RTE_LOG(INFO, CHANNEL_MONITOR, "Processing policy request %s\n",
884                                 pkt->vm_name);
885                 int ret = send_ack_for_received_cmd(pkt,
886                                 chan_info,
887                                 CPU_POWER_CMD_ACK);
888                 if (ret < 0)
889                         RTE_LOG(ERR, CHANNEL_MONITOR, "Error during sending ack command.\n");
890                 update_policy(pkt);
891                 policy_is_set = 1;
892         }
893
894         if (pkt->command == PKT_POLICY_REMOVE) {
895                 ret = remove_policy(pkt);
896                 if (ret == 0)
897                         RTE_LOG(INFO, CHANNEL_MONITOR,
898                                  "Removed policy %s\n", pkt->vm_name);
899                 else
900                         RTE_LOG(INFO, CHANNEL_MONITOR,
901                                  "Policy %s does not exist\n", pkt->vm_name);
902         }
903
904         if (pkt->command == CPU_POWER_QUERY_FREQ_LIST ||
905                 pkt->command == CPU_POWER_QUERY_FREQ) {
906
907                 RTE_LOG(INFO, CHANNEL_MONITOR,
908                         "Frequency for %s requested.\n", pkt->vm_name);
909                 int ret = send_freq(pkt,
910                                 chan_info,
911                                 pkt->command == CPU_POWER_QUERY_FREQ_LIST);
912                 if (ret < 0)
913                         RTE_LOG(ERR, CHANNEL_MONITOR, "Error during frequency sending.\n");
914         }
915
916         if (pkt->command == CPU_POWER_QUERY_CAPS_LIST ||
917                 pkt->command == CPU_POWER_QUERY_CAPS) {
918
919                 RTE_LOG(INFO, CHANNEL_MONITOR,
920                         "Capabilities for %s requested.\n", pkt->vm_name);
921                 int ret = send_capabilities(pkt,
922                                 chan_info,
923                                 pkt->command == CPU_POWER_QUERY_CAPS_LIST);
924                 if (ret < 0)
925                         RTE_LOG(ERR, CHANNEL_MONITOR, "Error during sending capabilities.\n");
926         }
927
928         /*
929          * Return is not checked as channel status may have been set to DISABLED
930          * from management thread
931          */
932         rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_PROCESSING,
933                         CHANNEL_MGR_CHANNEL_CONNECTED);
934         return 0;
935
936 }
937
938 int
939 add_channel_to_monitor(struct channel_info **chan_info)
940 {
941         struct channel_info *info = *chan_info;
942         struct epoll_event event;
943
944         event.events = EPOLLIN;
945         event.data.ptr = info;
946         if (epoll_ctl(global_event_fd, EPOLL_CTL_ADD, info->fd, &event) < 0) {
947                 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to add channel '%s' "
948                                 "to epoll\n", info->channel_path);
949                 return -1;
950         }
951         RTE_LOG(ERR, CHANNEL_MONITOR, "Added channel '%s' "
952                         "to monitor\n", info->channel_path);
953         return 0;
954 }
955
956 int
957 remove_channel_from_monitor(struct channel_info *chan_info)
958 {
959         if (epoll_ctl(global_event_fd, EPOLL_CTL_DEL,
960                         chan_info->fd, NULL) < 0) {
961                 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to remove channel '%s' "
962                                 "from epoll\n", chan_info->channel_path);
963                 return -1;
964         }
965         return 0;
966 }
967
968 int
969 channel_monitor_init(void)
970 {
971         global_event_fd = epoll_create1(0);
972         if (global_event_fd == 0) {
973                 RTE_LOG(ERR, CHANNEL_MONITOR,
974                                 "Error creating epoll context with error %s\n",
975                                 strerror(errno));
976                 return -1;
977         }
978         global_events_list = rte_malloc("epoll_events",
979                         sizeof(*global_events_list)
980                         * MAX_EVENTS, RTE_CACHE_LINE_SIZE);
981         if (global_events_list == NULL) {
982                 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to rte_malloc for "
983                                 "epoll events\n");
984                 return -1;
985         }
986         return 0;
987 }
988
989 static void
990 read_binary_packet(struct channel_info *chan_info)
991 {
992         struct rte_power_channel_packet pkt;
993         void *buffer = &pkt;
994         int buffer_len = sizeof(pkt);
995         int n_bytes, err = 0;
996
997         while (buffer_len > 0) {
998                 n_bytes = read(chan_info->fd,
999                                 buffer, buffer_len);
1000                 if (n_bytes == buffer_len)
1001                         break;
1002                 if (n_bytes < 0) {
1003                         err = errno;
1004                         RTE_LOG(DEBUG, CHANNEL_MONITOR,
1005                                 "Received error on "
1006                                 "channel '%s' read: %s\n",
1007                                 chan_info->channel_path,
1008                                 strerror(err));
1009                         remove_channel(&chan_info);
1010                         break;
1011                 }
1012                 buffer = (char *)buffer + n_bytes;
1013                 buffer_len -= n_bytes;
1014         }
1015         if (!err)
1016                 process_request(&pkt, chan_info);
1017 }
1018
1019 #ifdef USE_JANSSON
1020 static void
1021 read_json_packet(struct channel_info *chan_info)
1022 {
1023         struct rte_power_channel_packet pkt;
1024         int n_bytes, ret;
1025         json_t *root;
1026         json_error_t error;
1027         const char *resource_name;
1028         char *start, *end;
1029         uint32_t n;
1030
1031
1032         /* read opening brace to closing brace */
1033         do {
1034                 int idx = 0;
1035                 int indent = 0;
1036                 do {
1037                         n_bytes = read(chan_info->fd, &json_data[idx], 1);
1038                         if (n_bytes == 0)
1039                                 break;
1040                         if (json_data[idx] == '{')
1041                                 indent++;
1042                         if (json_data[idx] == '}')
1043                                 indent--;
1044                         if ((indent > 0) || (idx > 0))
1045                                 idx++;
1046                         if (indent <= 0)
1047                                 json_data[idx] = 0;
1048                         if (idx >= MAX_JSON_STRING_LEN-1)
1049                                 break;
1050                 } while (indent > 0);
1051
1052                 json_data[idx] = '\0';
1053
1054                 if (strlen(json_data) == 0)
1055                         continue;
1056
1057                 printf("got [%s]\n", json_data);
1058
1059                 root = json_loads(json_data, 0, &error);
1060
1061                 if (root) {
1062                         resource_name = get_resource_name_from_chn_path(
1063                                 chan_info->channel_path);
1064                         /*
1065                          * Because our data is now in the json
1066                          * object, we can overwrite the pkt
1067                          * with a rte_power_channel_packet struct, using
1068                          * parse_json_to_pkt()
1069                          */
1070                         ret = parse_json_to_pkt(root, &pkt, resource_name);
1071                         json_decref(root);
1072                         if (ret) {
1073                                 RTE_LOG(ERR, CHANNEL_MONITOR,
1074                                         "Error validating JSON profile data\n");
1075                                 break;
1076                         }
1077                         start = strstr(pkt.vm_name,
1078                                         CHANNEL_MGR_FIFO_PATTERN_NAME);
1079                         if (start != NULL) {
1080                                 /* move past pattern to start of fifo id */
1081                                 start += strlen(CHANNEL_MGR_FIFO_PATTERN_NAME);
1082
1083                                 end = start;
1084                                 n = (uint32_t)strtoul(start, &end, 10);
1085
1086                                 if (end[0] == '\0') {
1087                                         /* Add core id to core list */
1088                                         pkt.num_vcpu = 1;
1089                                         pkt.vcpu_to_control[0] = n;
1090                                         process_request(&pkt, chan_info);
1091                                 } else {
1092                                         RTE_LOG(ERR, CHANNEL_MONITOR,
1093                                                 "Cannot extract core id from fifo name\n");
1094                                 }
1095                         } else {
1096                                 process_request(&pkt, chan_info);
1097                         }
1098                 } else {
1099                         RTE_LOG(ERR, CHANNEL_MONITOR,
1100                                         "JSON error on line %d: %s\n",
1101                                         error.line, error.text);
1102                 }
1103         } while (n_bytes > 0);
1104 }
1105 #endif
1106
1107 void
1108 run_channel_monitor(void)
1109 {
1110         while (run_loop) {
1111                 int n_events, i;
1112
1113                 n_events = epoll_wait(global_event_fd, global_events_list,
1114                                 MAX_EVENTS, 1);
1115                 if (!run_loop)
1116                         break;
1117                 for (i = 0; i < n_events; i++) {
1118                         struct channel_info *chan_info = (struct channel_info *)
1119                                         global_events_list[i].data.ptr;
1120                         if ((global_events_list[i].events & EPOLLERR) ||
1121                                 (global_events_list[i].events & EPOLLHUP)) {
1122                                 RTE_LOG(INFO, CHANNEL_MONITOR,
1123                                                 "Remote closed connection for "
1124                                                 "channel '%s'\n",
1125                                                 chan_info->channel_path);
1126                                 remove_channel(&chan_info);
1127                                 continue;
1128                         }
1129                         if (global_events_list[i].events & EPOLLIN) {
1130
1131                                 switch (chan_info->type) {
1132                                 case CHANNEL_TYPE_BINARY:
1133                                         read_binary_packet(chan_info);
1134                                         break;
1135 #ifdef USE_JANSSON
1136                                 case CHANNEL_TYPE_JSON:
1137                                         read_json_packet(chan_info);
1138                                         break;
1139 #endif
1140                                 default:
1141                                         break;
1142                                 }
1143                         }
1144                 }
1145                 rte_delay_us(time_period_ms*1000);
1146                 if (policy_is_set) {
1147                         unsigned int j;
1148
1149                         for (j = 0; j < RTE_DIM(policies); j++) {
1150                                 if (policies[j].enabled == 1)
1151                                         apply_policy(&policies[j]);
1152                         }
1153                 }
1154         }
1155 }