1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016 Intel Corporation
3 */
4
5 #include <ctype.h>
6 #include <errno.h>
7 #include <getopt.h>
8 #include <inttypes.h>
9 #include <limits.h>
10 #include <sched.h>
11 #include <signal.h>
12 #include <stdio.h>
13
14 #include <rte_common.h>
15 #include <rte_memcpy.h>
16
17 #include <pqos.h>
18
19 #include "cat.h"
20
21 #define BITS_PER_HEX 4
22 #define PQOS_MAX_SOCKETS 8
23 #define PQOS_MAX_SOCKET_CORES 64
24 #define PQOS_MAX_CORES (PQOS_MAX_SOCKET_CORES * PQOS_MAX_SOCKETS)
25
26 static const struct pqos_cap *m_cap;
27 static const struct pqos_cpuinfo *m_cpu;
28 static const struct pqos_capability *m_cap_l3ca;
29 #if PQOS_VERSION <= 103
30 static unsigned m_sockets[PQOS_MAX_SOCKETS];
31 #else
32 static unsigned int *m_sockets;
33 #endif
34 static unsigned m_sock_count;
35 static struct cat_config m_config[PQOS_MAX_CORES];
36 static unsigned m_config_count;
37
38 static unsigned
bits_count(uint64_t bitmask)39 bits_count(uint64_t bitmask)
40 {
41 unsigned count = 0;
42
43 for (; bitmask != 0; count++)
44 bitmask &= bitmask - 1;
45
46 return count;
47 }
48
49 /*
50 * Parse elem, the elem could be single number/range or '(' ')' group
51 * 1) A single number elem, it's just a simple digit. e.g. 9
52 * 2) A single range elem, two digits with a '-' between. e.g. 2-6
53 * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
54 * Within group elem, '-' used for a range separator;
55 * ',' used for a single number.
56 */
57 static int
parse_set(const char * input,rte_cpuset_t * cpusetp)58 parse_set(const char *input, rte_cpuset_t *cpusetp)
59 {
60 unsigned idx;
61 const char *str = input;
62 char *end = NULL;
63 unsigned min, max;
64 const unsigned num = PQOS_MAX_CORES;
65
66 CPU_ZERO(cpusetp);
67
68 while (isblank(*str))
69 str++;
70
71 /* only digit or left bracket is qualify for start point */
72 if ((!isdigit(*str) && *str != '(') || *str == '\0')
73 return -1;
74
75 /* process single number or single range of number */
76 if (*str != '(') {
77 errno = 0;
78 idx = strtoul(str, &end, 10);
79
80 if (errno || end == NULL || idx >= num)
81 return -1;
82
83 while (isblank(*end))
84 end++;
85
86 min = idx;
87 max = idx;
88 if (*end == '-') {
89 /* process single <number>-<number> */
90 end++;
91 while (isblank(*end))
92 end++;
93 if (!isdigit(*end))
94 return -1;
95
96 errno = 0;
97 idx = strtoul(end, &end, 10);
98 if (errno || end == NULL || idx >= num)
99 return -1;
100 max = idx;
101 while (isblank(*end))
102 end++;
103 if (*end != ',' && *end != '\0')
104 return -1;
105 }
106
107 if (*end != ',' && *end != '\0' && *end != '@')
108 return -1;
109
110 for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max);
111 idx++)
112 CPU_SET(idx, cpusetp);
113
114 return end - input;
115 }
116
117 /* process set within bracket */
118 str++;
119 while (isblank(*str))
120 str++;
121 if (*str == '\0')
122 return -1;
123
124 min = PQOS_MAX_CORES;
125 do {
126
127 /* go ahead to the first digit */
128 while (isblank(*str))
129 str++;
130 if (!isdigit(*str))
131 return -1;
132
133 /* get the digit value */
134 errno = 0;
135 idx = strtoul(str, &end, 10);
136 if (errno || end == NULL || idx >= num)
137 return -1;
138
139 /* go ahead to separator '-',',' and ')' */
140 while (isblank(*end))
141 end++;
142 if (*end == '-') {
143 if (min == PQOS_MAX_CORES)
144 min = idx;
145 else /* avoid continuous '-' */
146 return -1;
147 } else if ((*end == ',') || (*end == ')')) {
148 max = idx;
149 if (min == PQOS_MAX_CORES)
150 min = idx;
151 for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max);
152 idx++)
153 CPU_SET(idx, cpusetp);
154
155 min = PQOS_MAX_CORES;
156 } else
157 return -1;
158
159 str = end + 1;
160 } while (*end != '\0' && *end != ')');
161
162 return str - input;
163 }
164
165 /* Test if bitmask is contiguous */
166 static int
is_contiguous(uint64_t bitmask)167 is_contiguous(uint64_t bitmask)
168 {
169 /* check if bitmask is contiguous */
170 unsigned i = 0;
171 unsigned j = 0;
172 const unsigned max_idx = (sizeof(bitmask) * CHAR_BIT);
173
174 if (bitmask == 0)
175 return 0;
176
177 for (i = 0; i < max_idx; i++) {
178 if (((1ULL << i) & bitmask) != 0)
179 j++;
180 else if (j > 0)
181 break;
182 }
183
184 if (bits_count(bitmask) != j) {
185 printf("PQOS: mask 0x%llx is not contiguous.\n",
186 (unsigned long long)bitmask);
187 return 0;
188 }
189
190 return 1;
191 }
192
193 /*
194 * The format pattern: --l3ca='<cbm@cpus>[,<(ccbm,dcbm)@cpus>...]'
195 * cbm could be a single mask or for a CDP enabled system, a group of two masks
196 * ("code cbm" and "data cbm")
197 * '(' and ')' are necessary if it's a group.
198 * cpus could be a single digit/range or a group.
199 * '(' and ')' are necessary if it's a group.
200 *
201 * e.g. '0x00F00@(1,3), 0x0FF00@(4-6), 0xF0000@7'
202 * - CPUs 1 and 3 share its 4 ways with CPUs 4, 5 and 6;
203 * - CPUs 4,5 and 6 share half (4 out of 8 ways) of its L3 with 1 and 3;
204 * - CPUs 4,5 and 6 have exclusive access to 4 out of 8 ways;
205 * - CPU 7 has exclusive access to all of its 4 ways;
206 *
207 * e.g. '(0x00C00,0x00300)@(1,3)' for a CDP enabled system
208 * - cpus 1 and 3 have access to 2 ways for code and 2 ways for data,
209 * code and data ways are not overlapping.;
210 */
211 static int
parse_l3ca(const char * l3ca)212 parse_l3ca(const char *l3ca)
213 {
214 unsigned idx = 0;
215 const char *cbm_start = NULL;
216 char *cbm_end = NULL;
217 const char *end = NULL;
218 int offset;
219 rte_cpuset_t cpuset;
220 uint64_t mask = 0;
221 uint64_t cmask = 0;
222
223 if (l3ca == NULL)
224 goto err;
225
226 /* Get cbm */
227 do {
228 CPU_ZERO(&cpuset);
229 mask = 0;
230 cmask = 0;
231
232 while (isblank(*l3ca))
233 l3ca++;
234
235 if (*l3ca == '\0')
236 goto err;
237
238 /* record mask_set start point */
239 cbm_start = l3ca;
240
241 /* go across a complete bracket */
242 if (*cbm_start == '(') {
243 l3ca += strcspn(l3ca, ")");
244 if (*l3ca++ == '\0')
245 goto err;
246 }
247
248 /* scan the separator '@', ','(next) or '\0'(finish) */
249 l3ca += strcspn(l3ca, "@,");
250
251 if (*l3ca != '@')
252 goto err;
253
254 /* explicit assign cpu_set */
255 offset = parse_set(l3ca + 1, &cpuset);
256 if (offset < 0 || CPU_COUNT(&cpuset) == 0)
257 goto err;
258
259 end = l3ca + 1 + offset;
260
261 if (*end != ',' && *end != '\0')
262 goto err;
263
264 /* parse mask_set from start point */
265 if (*cbm_start == '(') {
266 cbm_start++;
267
268 while (isblank(*cbm_start))
269 cbm_start++;
270
271 if (!isxdigit(*cbm_start))
272 goto err;
273
274 errno = 0;
275 cmask = strtoul(cbm_start, &cbm_end, 16);
276 if (errno != 0 || cbm_end == NULL || cmask == 0)
277 goto err;
278
279 while (isblank(*cbm_end))
280 cbm_end++;
281
282 if (*cbm_end != ',')
283 goto err;
284
285 cbm_end++;
286
287 while (isblank(*cbm_end))
288 cbm_end++;
289
290 if (!isxdigit(*cbm_end))
291 goto err;
292
293 errno = 0;
294 mask = strtoul(cbm_end, &cbm_end, 16);
295 if (errno != 0 || cbm_end == NULL || mask == 0)
296 goto err;
297 } else {
298 while (isblank(*cbm_start))
299 cbm_start++;
300
301 if (!isxdigit(*cbm_start))
302 goto err;
303
304 errno = 0;
305 mask = strtoul(cbm_start, &cbm_end, 16);
306 if (errno != 0 || cbm_end == NULL || mask == 0)
307 goto err;
308
309 }
310
311 if (mask == 0 || is_contiguous(mask) == 0)
312 goto err;
313
314 if (cmask != 0 && is_contiguous(cmask) == 0)
315 goto err;
316
317 rte_memcpy(&m_config[idx].cpumask,
318 &cpuset, sizeof(rte_cpuset_t));
319
320 if (cmask != 0) {
321 m_config[idx].cdp = 1;
322 m_config[idx].code_mask = cmask;
323 m_config[idx].data_mask = mask;
324 } else
325 m_config[idx].mask = mask;
326
327 m_config_count++;
328
329 l3ca = end + 1;
330 idx++;
331 } while (*end != '\0' && idx < PQOS_MAX_CORES);
332
333 return 0;
334
335 err:
336 return -EINVAL;
337 }
338
339 static int
check_cpus_overlapping(void)340 check_cpus_overlapping(void)
341 {
342 unsigned i = 0;
343 unsigned j = 0;
344 rte_cpuset_t mask;
345
346 CPU_ZERO(&mask);
347
348 for (i = 0; i < m_config_count; i++) {
349 for (j = i + 1; j < m_config_count; j++) {
350 RTE_CPU_AND(&mask,
351 &m_config[i].cpumask,
352 &m_config[j].cpumask);
353
354 if (CPU_COUNT(&mask) != 0) {
355 printf("PQOS: Requested CPUs sets are "
356 "overlapping.\n");
357 return -EINVAL;
358 }
359 }
360 }
361
362 return 0;
363 }
364
365 static int
check_cpus(void)366 check_cpus(void)
367 {
368 unsigned i = 0;
369 unsigned cpu_id = 0;
370 unsigned cos_id = 0;
371 int ret = 0;
372
373 for (i = 0; i < m_config_count; i++) {
374 for (cpu_id = 0; cpu_id < PQOS_MAX_CORES; cpu_id++) {
375 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) != 0) {
376
377 ret = pqos_cpu_check_core(m_cpu, cpu_id);
378 if (ret != PQOS_RETVAL_OK) {
379 printf("PQOS: %u is not a valid "
380 "logical core id.\n", cpu_id);
381 ret = -ENODEV;
382 goto exit;
383 }
384
385 #if PQOS_VERSION <= 103
386 ret = pqos_l3ca_assoc_get(cpu_id, &cos_id);
387 #else
388 ret = pqos_alloc_assoc_get(cpu_id, &cos_id);
389 #endif
390 if (ret != PQOS_RETVAL_OK) {
391 printf("PQOS: Failed to read COS "
392 "associated to cpu %u.\n",
393 cpu_id);
394 ret = -EFAULT;
395 goto exit;
396 }
397
398 /*
399 * Check if COS assigned to lcore is different
400 * then default one (#0)
401 */
402 if (cos_id != 0) {
403 printf("PQOS: cpu %u has already "
404 "associated COS#%u. "
405 "Please reset L3CA.\n",
406 cpu_id, cos_id);
407 ret = -EBUSY;
408 goto exit;
409 }
410 }
411 }
412 }
413
414 exit:
415 return ret;
416 }
417
418 static int
check_cdp(void)419 check_cdp(void)
420 {
421 unsigned i = 0;
422
423 for (i = 0; i < m_config_count; i++) {
424 if (m_config[i].cdp == 1 && m_cap_l3ca->u.l3ca->cdp_on == 0) {
425 if (m_cap_l3ca->u.l3ca->cdp == 0) {
426 printf("PQOS: CDP requested but not "
427 "supported.\n");
428 } else {
429 printf("PQOS: CDP requested but not enabled. "
430 "Please enable CDP.\n");
431 }
432 return -ENOTSUP;
433 }
434 }
435
436 return 0;
437 }
438
439 static int
check_cbm_len_and_contention(void)440 check_cbm_len_and_contention(void)
441 {
442 unsigned i = 0;
443 uint64_t mask = 0;
444 const uint64_t not_cbm = (UINT64_MAX << (m_cap_l3ca->u.l3ca->num_ways));
445 const uint64_t cbm_contention_mask = m_cap_l3ca->u.l3ca->way_contention;
446 int ret = 0;
447
448 for (i = 0; i < m_config_count; i++) {
449 if (m_config[i].cdp == 1)
450 mask = m_config[i].code_mask | m_config[i].data_mask;
451 else
452 mask = m_config[i].mask;
453
454 if ((mask & not_cbm) != 0) {
455 printf("PQOS: One or more of requested CBM masks not "
456 "supported by system (too long).\n");
457 ret = -ENOTSUP;
458 break;
459 }
460
461 /* Just a warning */
462 if ((mask & cbm_contention_mask) != 0) {
463 printf("PQOS: One or more of requested CBM masks "
464 "overlap CBM contention mask.\n");
465 break;
466 }
467
468 }
469
470 return ret;
471 }
472
473 static int
check_and_select_classes(unsigned cos_id_map[][PQOS_MAX_SOCKETS])474 check_and_select_classes(unsigned cos_id_map[][PQOS_MAX_SOCKETS])
475 {
476 unsigned i = 0;
477 unsigned j = 0;
478 unsigned phy_pkg_id = 0;
479 unsigned cos_id = 0;
480 unsigned cpu_id = 0;
481 unsigned phy_pkg_lcores[PQOS_MAX_SOCKETS][m_config_count];
482 const unsigned cos_num = m_cap_l3ca->u.l3ca->num_classes;
483 unsigned used_cos_table[PQOS_MAX_SOCKETS][cos_num];
484 int ret = 0;
485
486 memset(phy_pkg_lcores, 0, sizeof(phy_pkg_lcores));
487 memset(used_cos_table, 0, sizeof(used_cos_table));
488
489 /* detect currently used COS */
490 for (j = 0; j < m_cpu->num_cores; j++) {
491 cpu_id = m_cpu->cores[j].lcore;
492
493 #if PQOS_VERSION <= 103
494 ret = pqos_l3ca_assoc_get(cpu_id, &cos_id);
495 #else
496 ret = pqos_alloc_assoc_get(cpu_id, &cos_id);
497 #endif
498 if (ret != PQOS_RETVAL_OK) {
499 printf("PQOS: Failed to read COS associated to "
500 "cpu %u on phy_pkg %u.\n", cpu_id, phy_pkg_id);
501 ret = -EFAULT;
502 goto exit;
503 }
504
505 ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id);
506 if (ret != PQOS_RETVAL_OK) {
507 printf("PQOS: Failed to get socket for cpu %u\n",
508 cpu_id);
509 ret = -EFAULT;
510 goto exit;
511 }
512
513 /* Mark COS as used */
514 if (used_cos_table[phy_pkg_id][cos_id] == 0)
515 used_cos_table[phy_pkg_id][cos_id]++;
516 }
517
518 /* look for avail. COS to fulfill requested config */
519 for (i = 0; i < m_config_count; i++) {
520 for (j = 0; j < m_cpu->num_cores; j++) {
521 cpu_id = m_cpu->cores[j].lcore;
522 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0)
523 continue;
524
525 ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id);
526 if (ret != PQOS_RETVAL_OK) {
527 printf("PQOS: Failed to get socket for "
528 "cpu %u\n", cpu_id);
529 ret = -EFAULT;
530 goto exit;
531 }
532
533 /*
534 * Check if we already have COS selected
535 * to be used for that group on that socket
536 */
537 if (phy_pkg_lcores[phy_pkg_id][i] != 0)
538 continue;
539
540 phy_pkg_lcores[phy_pkg_id][i]++;
541
542 /* Search for avail. COS to be used on that socket */
543 for (cos_id = 0; cos_id < cos_num; cos_id++) {
544 if (used_cos_table[phy_pkg_id][cos_id] == 0) {
545 used_cos_table[phy_pkg_id][cos_id]++;
546 cos_id_map[i][phy_pkg_id] = cos_id;
547 break;
548 }
549 }
550
551 /* If there is no COS available ...*/
552 if (cos_id == cos_num) {
553 ret = -E2BIG;
554 goto exit;
555 }
556 }
557 }
558
559 exit:
560 if (ret != 0)
561 printf("PQOS: Not enough available COS to configure "
562 "requested configuration.\n");
563
564 return ret;
565 }
566
567 static int
configure_cat(unsigned cos_id_map[][PQOS_MAX_SOCKETS])568 configure_cat(unsigned cos_id_map[][PQOS_MAX_SOCKETS])
569 {
570 unsigned phy_pkg_id = 0;
571 unsigned cpu_id = 0;
572 unsigned cos_id = 0;
573 unsigned i = 0;
574 unsigned j = 0;
575 struct pqos_l3ca l3ca = {0};
576 int ret = 0;
577
578 for (i = 0; i < m_config_count; i++) {
579 memset(&l3ca, 0, sizeof(l3ca));
580
581 l3ca.cdp = m_config[i].cdp;
582 if (m_config[i].cdp == 1) {
583 #if PQOS_VERSION <= 103
584 l3ca.code_mask = m_config[i].code_mask;
585 l3ca.data_mask = m_config[i].data_mask;
586 #else
587 l3ca.u.s.code_mask = m_config[i].code_mask;
588 l3ca.u.s.data_mask = m_config[i].data_mask;
589 #endif
590 } else
591 #if PQOS_VERSION <= 103
592 l3ca.ways_mask = m_config[i].mask;
593 #else
594 l3ca.u.ways_mask = m_config[i].mask;
595 #endif
596
597 for (j = 0; j < m_sock_count; j++) {
598 phy_pkg_id = m_sockets[j];
599 if (cos_id_map[i][phy_pkg_id] == 0)
600 continue;
601
602 l3ca.class_id = cos_id_map[i][phy_pkg_id];
603
604 ret = pqos_l3ca_set(phy_pkg_id, 1, &l3ca);
605 if (ret != PQOS_RETVAL_OK) {
606 printf("PQOS: Failed to set COS %u on "
607 "phy_pkg %u.\n", l3ca.class_id,
608 phy_pkg_id);
609 ret = -EFAULT;
610 goto exit;
611 }
612 }
613 }
614
615 for (i = 0; i < m_config_count; i++) {
616 for (j = 0; j < m_cpu->num_cores; j++) {
617 cpu_id = m_cpu->cores[j].lcore;
618 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0)
619 continue;
620
621 ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id);
622 if (ret != PQOS_RETVAL_OK) {
623 printf("PQOS: Failed to get socket for "
624 "cpu %u\n", cpu_id);
625 ret = -EFAULT;
626 goto exit;
627 }
628
629 cos_id = cos_id_map[i][phy_pkg_id];
630
631 #if PQOS_VERSION <= 103
632 ret = pqos_l3ca_assoc_set(cpu_id, cos_id);
633 #else
634 ret = pqos_alloc_assoc_set(cpu_id, cos_id);
635 #endif
636 if (ret != PQOS_RETVAL_OK) {
637 printf("PQOS: Failed to associate COS %u to "
638 "cpu %u\n", cos_id, cpu_id);
639 ret = -EFAULT;
640 goto exit;
641 }
642 }
643 }
644
645 exit:
646 return ret;
647 }
648
649
650 /* Parse the argument given in the command line of the application */
651 static int
parse_args(int argc,char ** argv)652 parse_args(int argc, char **argv)
653 {
654 int opt = 0;
655 int retval = 0;
656 int oldopterr = 0;
657 char **argvopt = argv;
658 char *prgname = argv[0];
659
660 static struct option lgopts[] = {
661 { "l3ca", required_argument, 0, 0 },
662 { NULL, 0, 0, 0 }
663 };
664
665 /* Disable printing messages within getopt() */
666 oldopterr = opterr;
667 opterr = 0;
668
669 opt = getopt_long(argc, argvopt, "", lgopts, NULL);
670 if (opt == 0) {
671 retval = parse_l3ca(optarg);
672 if (retval != 0) {
673 printf("PQOS: Invalid L3CA parameters!\n");
674 goto exit;
675 }
676
677 argv[optind - 1] = prgname;
678 retval = optind - 1;
679 } else
680 retval = 0;
681
682 exit:
683 /* reset getopt lib */
684 optind = 1;
685
686 /* Restore opterr value */
687 opterr = oldopterr;
688
689 return retval;
690 }
691
692 static void
print_cmd_line_config(void)693 print_cmd_line_config(void)
694 {
695 char cpustr[PQOS_MAX_CORES * 3] = {0};
696 unsigned i = 0;
697 unsigned j = 0;
698
699 for (i = 0; i < m_config_count; i++) {
700 unsigned len = 0;
701 memset(cpustr, 0, sizeof(cpustr));
702
703 /* Generate CPU list */
704 for (j = 0; j < PQOS_MAX_CORES; j++) {
705 if (CPU_ISSET(j, &m_config[i].cpumask) != 1)
706 continue;
707
708 len += snprintf(cpustr + len, sizeof(cpustr) - len - 1,
709 "%u,", j);
710
711 if (len >= sizeof(cpustr) - 1)
712 break;
713 }
714
715 if (m_config[i].cdp == 1) {
716 printf("PQOS: CPUs: %s cMASK: 0x%llx, dMASK: "
717 "0x%llx\n", cpustr,
718 (unsigned long long)m_config[i].code_mask,
719 (unsigned long long)m_config[i].data_mask);
720 } else {
721 printf("PQOS: CPUs: %s MASK: 0x%llx\n", cpustr,
722 (unsigned long long)m_config[i].mask);
723 }
724 }
725 }
726
727 /**
728 * @brief Prints CAT configuration
729 */
730 static void
print_cat_config(void)731 print_cat_config(void)
732 {
733 int ret = PQOS_RETVAL_OK;
734 unsigned i = 0;
735
736 for (i = 0; i < m_sock_count; i++) {
737 struct pqos_l3ca tab[PQOS_MAX_L3CA_COS] = {{0} };
738 unsigned num = 0;
739 unsigned n = 0;
740
741 ret = pqos_l3ca_get(m_sockets[i], PQOS_MAX_L3CA_COS, &num, tab);
742 if (ret != PQOS_RETVAL_OK) {
743 printf("PQOS: Error retrieving COS!\n");
744 return;
745 }
746
747 printf("PQOS: COS definitions for Socket %u:\n", m_sockets[i]);
748 for (n = 0; n < num; n++) {
749 if (tab[n].cdp == 1) {
750 printf("PQOS: COS: %u, cMASK: 0x%llx, "
751 "dMASK: 0x%llx\n", tab[n].class_id,
752 #if PQOS_VERSION <= 103
753 (unsigned long long)tab[n].code_mask,
754 (unsigned long long)tab[n].data_mask);
755 #else
756 (unsigned long long)tab[n].u.s.code_mask,
757 (unsigned long long)tab[n].u.s.data_mask);
758 #endif
759 } else {
760 printf("PQOS: COS: %u, MASK: 0x%llx\n",
761 tab[n].class_id,
762 #if PQOS_VERSION <= 103
763 (unsigned long long)tab[n].ways_mask);
764 #else
765 (unsigned long long)tab[n].u.ways_mask);
766 #endif
767 }
768 }
769 }
770
771 for (i = 0; i < m_sock_count; i++) {
772 #if PQOS_VERSION <= 103
773 unsigned lcores[PQOS_MAX_SOCKET_CORES] = {0};
774 #else
775 unsigned int *lcores = NULL;
776 #endif
777 unsigned lcount = 0;
778 unsigned n = 0;
779
780 #if PQOS_VERSION <= 103
781 ret = pqos_cpu_get_cores(m_cpu, m_sockets[i],
782 PQOS_MAX_SOCKET_CORES, &lcount, &lcores[0]);
783 if (ret != PQOS_RETVAL_OK) {
784 #else
785 lcores = pqos_cpu_get_cores(m_cpu, m_sockets[i],
786 &lcount);
787 if (lcores == NULL || lcount == 0) {
788 #endif
789 printf("PQOS: Error retrieving core information!\n");
790 return;
791 }
792
793 printf("PQOS: CPU information for socket %u:\n", m_sockets[i]);
794 for (n = 0; n < lcount; n++) {
795 unsigned class_id = 0;
796
797 #if PQOS_VERSION <= 103
798 ret = pqos_l3ca_assoc_get(lcores[n], &class_id);
799 #else
800 ret = pqos_alloc_assoc_get(lcores[n], &class_id);
801 #endif
802 if (ret == PQOS_RETVAL_OK)
803 printf("PQOS: CPU: %u, COS: %u\n", lcores[n],
804 class_id);
805 else
806 printf("PQOS: CPU: %u, ERROR\n", lcores[n]);
807 }
808
809 #if PQOS_VERSION > 103
810 free(lcores);
811 #endif
812 }
813
814 }
815
816 static int
817 cat_validate(void)
818 {
819 int ret = 0;
820
821 ret = check_cpus();
822 if (ret != 0)
823 return ret;
824
825 ret = check_cdp();
826 if (ret != 0)
827 return ret;
828
829 ret = check_cbm_len_and_contention();
830 if (ret != 0)
831 return ret;
832
833 ret = check_cpus_overlapping();
834 if (ret != 0)
835 return ret;
836
837 return 0;
838 }
839
840 static int
841 cat_set(void)
842 {
843 int ret = 0;
844 unsigned cos_id_map[m_config_count][PQOS_MAX_SOCKETS];
845
846 memset(cos_id_map, 0, sizeof(cos_id_map));
847
848 ret = check_and_select_classes(cos_id_map);
849 if (ret != 0)
850 return ret;
851
852 ret = configure_cat(cos_id_map);
853 if (ret != 0)
854 return ret;
855
856 return 0;
857 }
858
859 static void
860 cat_fini(void)
861 {
862 int ret = 0;
863
864 printf("PQOS: Shutting down PQoS library...\n");
865
866 /* deallocate all the resources */
867 ret = pqos_fini();
868 if (ret != PQOS_RETVAL_OK && ret != PQOS_RETVAL_INIT)
869 printf("PQOS: Error shutting down PQoS library!\n");
870
871 m_cap = NULL;
872 m_cpu = NULL;
873 m_cap_l3ca = NULL;
874 #if PQOS_VERSION <= 103
875 memset(m_sockets, 0, sizeof(m_sockets));
876 #else
877 free(m_sockets);
878 #endif
879 m_sock_count = 0;
880 memset(m_config, 0, sizeof(m_config));
881 m_config_count = 0;
882 }
883
884 void
885 cat_exit(void)
886 {
887 unsigned i = 0;
888 unsigned j = 0;
889 unsigned cpu_id = 0;
890 int ret = 0;
891
892 /* if lib is not initialized, do nothing */
893 if (m_cap == NULL && m_cpu == NULL)
894 return;
895
896 printf("PQOS: Reverting CAT configuration...\n");
897
898 for (i = 0; i < m_config_count; i++) {
899 for (j = 0; j < m_cpu->num_cores; j++) {
900 cpu_id = m_cpu->cores[j].lcore;
901 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0)
902 continue;
903
904 #if PQOS_VERSION <= 103
905 ret = pqos_l3ca_assoc_set(cpu_id, 0);
906 #else
907 ret = pqos_alloc_assoc_set(cpu_id, 0);
908 #endif
909 if (ret != PQOS_RETVAL_OK) {
910 printf("PQOS: Failed to associate COS 0 to "
911 "cpu %u\n", cpu_id);
912 }
913 }
914 }
915
916 cat_fini();
917 }
918
919 static void
920 signal_handler(int signum)
921 {
922 if (signum == SIGINT || signum == SIGTERM) {
923 printf("\nPQOS: Signal %d received, preparing to exit...\n",
924 signum);
925
926 cat_exit();
927
928 /* exit with the expected status */
929 signal(signum, SIG_DFL);
930 kill(getpid(), signum);
931 }
932 }
933
934 int
935 cat_init(int argc, char **argv)
936 {
937 int ret = 0;
938 int args_num = 0;
939 struct pqos_config cfg = {0};
940
941 if (m_cap != NULL || m_cpu != NULL) {
942 printf("PQOS: CAT module already initialized!\n");
943 return -EEXIST;
944 }
945
946 /* Parse cmd line args */
947 ret = parse_args(argc, argv);
948
949 if (ret <= 0)
950 goto err;
951
952 args_num = ret;
953
954 /* Print cmd line configuration */
955 print_cmd_line_config();
956
957 /* PQoS Initialization - Check and initialize CAT capability */
958 cfg.fd_log = STDOUT_FILENO;
959 cfg.verbose = 0;
960 #if PQOS_VERSION <= 103
961 cfg.cdp_cfg = PQOS_REQUIRE_CDP_ANY;
962 #endif
963 ret = pqos_init(&cfg);
964 if (ret != PQOS_RETVAL_OK) {
965 printf("PQOS: Error initializing PQoS library!\n");
966 ret = -EFAULT;
967 goto err;
968 }
969
970 /* Get capability and CPU info pointer */
971 ret = pqos_cap_get(&m_cap, &m_cpu);
972 if (ret != PQOS_RETVAL_OK || m_cap == NULL || m_cpu == NULL) {
973 printf("PQOS: Error retrieving PQoS capabilities!\n");
974 ret = -EFAULT;
975 goto err;
976 }
977
978 /* Get L3CA capabilities */
979 ret = pqos_cap_get_type(m_cap, PQOS_CAP_TYPE_L3CA, &m_cap_l3ca);
980 if (ret != PQOS_RETVAL_OK || m_cap_l3ca == NULL) {
981 printf("PQOS: Error retrieving PQOS_CAP_TYPE_L3CA "
982 "capabilities!\n");
983 ret = -EFAULT;
984 goto err;
985 }
986
987 /* Get CPU socket information */
988 #if PQOS_VERSION <= 103
989 ret = pqos_cpu_get_sockets(m_cpu, PQOS_MAX_SOCKETS, &m_sock_count,
990 m_sockets);
991 if (ret != PQOS_RETVAL_OK) {
992 #else
993 m_sockets = pqos_cpu_get_sockets(m_cpu, &m_sock_count);
994 if (m_sockets == NULL) {
995 #endif
996 printf("PQOS: Error retrieving CPU socket information!\n");
997 ret = -EFAULT;
998 goto err;
999 }
1000
1001 /* Validate cmd line configuration */
1002 ret = cat_validate();
1003 if (ret != 0) {
1004 printf("PQOS: Requested CAT configuration is not valid!\n");
1005 goto err;
1006 }
1007
1008 /* configure system */
1009 ret = cat_set();
1010 if (ret != 0) {
1011 printf("PQOS: Failed to configure CAT!\n");
1012 goto err;
1013 }
1014
1015 signal(SIGINT, signal_handler);
1016 signal(SIGTERM, signal_handler);
1017
1018 ret = atexit(cat_exit);
1019 if (ret != 0) {
1020 printf("PQOS: Cannot set exit function\n");
1021 goto err;
1022 }
1023
1024 /* Print CAT configuration */
1025 print_cat_config();
1026
1027 return args_num;
1028
1029 err:
1030 /* deallocate all the resources */
1031 cat_fini();
1032 return ret;
1033 }
1034