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