New upstream version 18.02
[deb_dpdk.git] / 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 }