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