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