Fix tons of deprecation warnings
[samplevnf.git] / VNFs / DPPD-PROX / commands.c
1 /*
2 // Copyright (c) 2010-2020 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <string.h>
18 #include <rte_table_hash.h>
19 #include <rte_version.h>
20 #include <rte_malloc.h>
21 #if RTE_VERSION >= RTE_VERSION_NUM(18,5,0,0)
22 #include <rte_eal_memconfig.h>
23 #endif
24
25 #include "prox_malloc.h"
26 #include "display.h"
27 #include "commands.h"
28 #include "log.h"
29 #include "run.h"
30 #include "lconf.h"
31 #include "hash_utils.h"
32 #include "prox_cfg.h"
33 #include "prox_port_cfg.h"
34 #include "defines.h"
35 #include "handle_qos.h"
36 #include "handle_qinq_encap4.h"
37 #include "quit.h"
38 #include "input.h"
39 #include "rw_reg.h"
40 #include "cqm.h"
41 #include "stats_core.h"
42
43 void start_core_all(int task_id)
44 {
45         uint32_t cores[RTE_MAX_LCORE];
46         uint32_t lcore_id;
47         char tmp[256];
48         int cnt = 0;
49
50         prox_core_to_str(tmp, sizeof(tmp), 0);
51         plog_info("Starting cores: %s\n", tmp);
52
53         lcore_id = -1;
54         while (prox_core_next(&lcore_id, 0) == 0) {
55                 cores[cnt++] = lcore_id;
56         }
57         start_cores(cores, cnt, task_id);
58 }
59
60 void stop_core_all(int task_id)
61 {
62         uint32_t cores[RTE_MAX_LCORE];
63         uint32_t lcore_id;
64         char tmp[256];
65         int cnt = 0;
66
67         prox_core_to_str(tmp, sizeof(tmp), 0);
68         plog_info("Stopping cores: %s\n", tmp);
69
70         lcore_id = -1;
71         while (prox_core_next(&lcore_id, 0) == 0) {
72                 cores[cnt++] = lcore_id;
73         }
74
75         stop_cores(cores, cnt, task_id);
76 }
77
78 static void warn_inactive_cores(uint32_t *cores, int count, const char *prefix)
79 {
80         for (int i = 0; i < count; ++i) {
81                 if (!prox_core_active(cores[i], 0)) {
82                         plog_warn("%s %u: core is not active\n", prefix, cores[i]);
83                 }
84         }
85 }
86
87 static inline int wait_command_handled(struct lcore_cfg *lconf)
88 {
89         uint64_t t1 = rte_rdtsc(), t2;
90         int max_time = 5;
91
92         if (lconf->msg.type == LCONF_MSG_STOP)
93                 max_time = 30;
94
95         while (lconf_is_req(lconf)) {
96                 t2 = rte_rdtsc();
97                 if (t2 - t1 > max_time * rte_get_tsc_hz()) {
98                         // Failed to handle command ...
99                         for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
100                                 struct task_args *targs = &lconf->targs[task_id];
101                                 if (!(targs->flags & TASK_ARG_DROP)) {
102                                         plogx_err("Failed to handle command - task is in NO_DROP and might be stuck...\n");
103                                         return - 1;
104                                 }
105                         }
106                         plogx_err("Failed to handle command\n");
107                         return -1;
108                 }
109         }
110         return 0;
111 }
112
113 static inline void start_l3(struct task_args *targ)
114 {
115         if (!task_is_master(targ)) {
116                 if ((targ->nb_txports != 0)) {
117                         if (targ->flags & (TASK_ARG_L3|TASK_ARG_NDP))
118                                 task_start_l3(targ->tbase, targ);
119                 }
120         }
121 }
122
123 void start_cores(uint32_t *cores, int count, int task_id)
124 {
125         int n_started_cores = 0;
126         uint32_t started_cores[RTE_MAX_LCORE];
127         struct task_args *targ;
128
129         warn_inactive_cores(cores, count, "Can't start core");
130
131         for (int i = 0; i < count; ++i) {
132                 struct lcore_cfg *lconf = &lcore_cfg[cores[i]];
133
134                 if (lconf->n_tasks_run != lconf->n_tasks_all) {
135                         if (task_id == -1) {
136                                 for (uint8_t tid = 0; tid < lconf->n_tasks_all; ++tid) {
137                                         targ = &lconf->targs[tid];
138                                         start_l3(targ);
139                                 }
140                         } else if (task_id < lconf->n_tasks_all) {
141                                 targ = &lconf->targs[task_id];
142                                 start_l3(targ);
143                         } else {
144                                 plog_warn("Invalid task id %d on core %u\n", task_id, cores[i]);
145                                 continue;
146                         }
147                         if (wait_command_handled(lconf) == -1) return;
148                         lconf->msg.type = LCONF_MSG_START;
149                         lconf->msg.task_id = task_id;
150                         lconf_set_req(lconf);
151                         if (task_id == -1)
152                                 plog_info("Starting core %u (all tasks)\n", cores[i]);
153                         else
154                                 plog_info("Starting core %u task %u\n", cores[i], task_id);
155                         started_cores[n_started_cores++] = cores[i];
156                         lconf->flags |= LCONF_FLAG_RUNNING;
157                         rte_eal_remote_launch(lconf_run, NULL, cores[i]);
158                 }
159                 else {
160                         plog_warn("Core %u is already running all its tasks\n", cores[i]);
161                 }
162         }
163
164         /* This function is blocking, so detect when each core has
165            consumed the message. */
166         for (int i = 0; i < n_started_cores; ++i) {
167                 struct lcore_cfg *lconf = &lcore_cfg[started_cores[i]];
168                 plog_info("Waiting for core %u to start...", started_cores[i]);
169                 if (wait_command_handled(lconf) == -1) return;
170                 plog_info(" OK\n");
171         }
172 }
173
174 void stop_cores(uint32_t *cores, int count, int task_id)
175 {
176         int n_stopped_cores = 0;
177         uint32_t stopped_cores[RTE_MAX_LCORE];
178         uint32_t c;
179
180         warn_inactive_cores(cores, count, "Can't stop core");
181
182         for (int i = 0; i < count; ++i) {
183                 struct lcore_cfg *lconf = &lcore_cfg[cores[i]];
184                 if (task_id >= lconf->n_tasks_all) {
185                         plog_warn("Trying to stop invalid task id %d on core %u\n", task_id, cores[i]);
186                         continue;
187                 }
188                 if (lconf->n_tasks_run) {
189                         if (wait_command_handled(lconf) == -1) return;
190
191                         lconf->msg.type = LCONF_MSG_STOP;
192                         lconf->msg.task_id = task_id;
193                         lconf_set_req(lconf);
194                         stopped_cores[n_stopped_cores++] = cores[i];
195                 }
196         }
197
198         for (int i = 0; i < n_stopped_cores; ++i) {
199                 c = stopped_cores[i];
200                 struct lcore_cfg *lconf = &lcore_cfg[c];
201                 if (wait_command_handled(lconf) == -1) return;
202
203                 if (lconf->n_tasks_run == 0) {
204                         plog_info("All tasks stopped on core %u, waiting for core to stop...", c);
205                         rte_eal_wait_lcore(c);
206                         plog_info(" OK\n");
207                         lconf->flags &= ~LCONF_FLAG_RUNNING;
208                 }
209                 else {
210                         plog_info("Stopped task %u on core %u\n", task_id, c);
211                 }
212         }
213 }
214
215 struct size_unit {
216         uint64_t val;
217         uint64_t frac;
218         char     unit[8];
219 };
220
221 static struct size_unit to_size_unit(uint64_t bytes)
222 {
223         struct size_unit ret;
224
225         if (bytes > 1 << 30) {
226                 ret.val = bytes >> 30;
227                 ret.frac = ((bytes - (ret.val << 30)) * 1000) / (1 << 30);
228                 strcpy(ret.unit, "GB");
229         }
230         else if (bytes > 1 << 20) {
231                 ret.val = bytes >> 20;
232                 ret.frac = ((bytes - (ret.val << 20)) * 1000) / (1 << 20);
233                 strcpy(ret.unit, "MB");
234         }
235         else if (bytes > 1 << 10) {
236                 ret.val = bytes >> 10;
237                 ret.frac = (bytes - (ret.val << 10)) * 1000 / (1 << 10);
238                 strcpy(ret.unit, "KB");
239         }
240         else {
241                 ret.val = bytes;
242                 ret.frac = 0;
243                 strcpy(ret.unit, "B");
244         }
245
246         return ret;
247 }
248
249 static int add_multicast_addr(uint8_t port_id, prox_rte_ether_addr *addr)
250 {
251         unsigned int i;
252         int rc = 0;
253
254         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
255
256         if (port_cfg->nb_mc_addr >= NB_MCAST_ADDR) {
257                 plog_err("Already reached maximum number (%d) of mcast addr on port %u\n", NB_MCAST_ADDR, port_id);
258                 return -1;
259         }
260         for (i = 0; i < port_cfg->nb_mc_addr; i++) {
261                 if (prox_rte_is_same_ether_addr(addr, &port_cfg->mc_addr[i])) {
262                         plog_info("multicast address already added to port\n");
263                         return -1;
264                 }
265         }
266
267         prox_rte_ether_addr_copy(addr, &port_cfg->mc_addr[port_cfg->nb_mc_addr]);
268         if ((rc = rte_eth_dev_set_mc_addr_list(port_id, port_cfg->mc_addr, port_cfg->nb_mc_addr + 1)) != 0) {
269                 plog_err("rte_eth_dev_set_mc_addr_list returns %d on port %u\n", rc, port_id);
270                 return rc;
271         }
272
273         port_cfg->nb_mc_addr++;
274         plog_info("rte_eth_dev_set_mc_addr_list(%d addr) on port %u\n", port_cfg->nb_mc_addr, port_id);
275         return rc;
276 }
277
278 static int del_multicast_addr(uint8_t port_id, prox_rte_ether_addr *addr)
279 {
280         unsigned int i;
281         int rc = 0;
282
283         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
284
285         for (i = 0; i < port_cfg->nb_mc_addr; i++) {
286                 if (prox_rte_is_same_ether_addr(addr, &port_cfg->mc_addr[i])) {
287                         // Copy last address to the slot to be deleted
288                         prox_rte_ether_addr_copy(&port_cfg->mc_addr[port_cfg->nb_mc_addr-1], &port_cfg->mc_addr[i]);
289
290                         if ((rc = rte_eth_dev_set_mc_addr_list(port_id, port_cfg->mc_addr, port_cfg->nb_mc_addr - 1)) != 0) {
291                                 plog_err("rte_eth_dev_set_mc_addr_list returns %d on port %u\n", rc, port_id);
292                                 // When set failed, let restore the situation we were before calling the function...
293                                 prox_rte_ether_addr_copy(addr, &port_cfg->mc_addr[i]);
294                                 return rc;
295                         }
296                         port_cfg->nb_mc_addr--;
297                         plog_info("rte_eth_dev_set_mc_addr_list(%d addr) on port %u\n", port_cfg->nb_mc_addr, port_id);
298                         return 0;
299                 }
300         }
301         plog_err("multicast address not found on port %u\n", port_id);
302         return -1;
303 }
304 void cmd_mem_stats(void)
305 {
306         struct rte_malloc_socket_stats sock_stats;
307         uint64_t v;
308         struct size_unit su;
309
310         for (uint32_t i = 0; i < RTE_MAX_NUMA_NODES; ++i) {
311                 if (rte_malloc_get_socket_stats(i, &sock_stats) < 0 || sock_stats.heap_totalsz_bytes == 0)
312                         continue;
313
314                 plogx_info("Socket %u memory stats:\n", i);
315                 su = to_size_unit(sock_stats.heap_totalsz_bytes);
316                 plogx_info("\tHeap_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
317                 su = to_size_unit(sock_stats.heap_freesz_bytes);
318                 plogx_info("\tFree_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
319                 su = to_size_unit(sock_stats.heap_allocsz_bytes);
320                 plogx_info("\tAlloc_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
321                 su = to_size_unit(sock_stats.greatest_free_size);
322                 plogx_info("\tGreatest_free_size: %zu %s\n", su.val, su.unit);
323                 plogx_info("\tAlloc_count: %u\n", sock_stats.alloc_count);
324                 plogx_info("\tFree_count: %u\n", sock_stats.free_count);
325         }
326 }
327
328 static void get_hp_sz_string(char *sz_str, uint64_t hp_sz)
329 {
330         switch (hp_sz >> 20) {
331         case 0:
332                 strcpy(sz_str, " 0 ");
333                 break;
334         case 2:
335                 strcpy(sz_str, "2MB");
336                 break;
337         case 1024:
338                 strcpy(sz_str, "1GB");
339                 break;
340         default:
341                 strcpy(sz_str, "??");
342         }
343 }
344
345 #if RTE_VERSION >= RTE_VERSION_NUM(18,5,0,0)
346 // Print all segments, 1 by 1
347 // Unused for now, keep for reference
348 static int print_all_segments(const struct rte_memseg_list *memseg_list, const struct rte_memseg *memseg, void *arg)
349 {
350         int memseg_list_idx = 0, memseg_idx;
351         int n = (*(int *)arg)++;
352
353 #if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0)
354         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
355         memseg_list_idx = memseg_list - mcfg->memsegs;
356         if ((memseg_list_idx < 0) || (memseg_list_idx >= RTE_MAX_MEMSEG_LISTS)) {
357                 plog_err("Invalid memseg_list_idx = %d; memseg_list = %p, mcfg->memsegs = %p\n", memseg_list_idx, memseg_list, mcfg->memsegs);
358                 return -1;
359         }
360 #endif
361         memseg_idx = rte_fbarray_find_idx(&memseg_list->memseg_arr, memseg);
362         if (memseg_idx < 0) {
363                 plog_err("Invalid memseg_idx = %d; memseg_list = %p, memseg = %p\n", memseg_idx, memseg_list, memseg);
364                 return -1;
365         }
366
367         char sz_str[5];
368         get_hp_sz_string(sz_str, memseg->hugepage_sz);
369         plog_info("Segment %u (sock %d): [%i-%i] [%#lx-%#lx] at %p using %zu pages of %s\n",
370                 n,
371                 memseg->socket_id,
372                 memseg_list_idx,
373                 memseg_idx,
374                 memseg->iova,
375                 memseg->iova+memseg->len,
376                 memseg->addr,
377                 memseg->len/memseg->hugepage_sz, sz_str);
378
379         return 0;
380 }
381
382 // Print memory segments
383 // Contiguous segments are shown as 1 big segment
384 static int print_segments(const struct rte_memseg_list *memseg_list, const struct rte_memseg *memseg, size_t len, void *arg)
385 {
386         int memseg_list_idx = 0, memseg_idx;
387         static int n = 0;
388
389 #if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0)
390         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
391         memseg_list_idx = memseg_list - mcfg->memsegs;
392         if ((memseg_list_idx < 0) || (memseg_list_idx >= RTE_MAX_MEMSEG_LISTS)) {
393                 plog_err("Invalid memseg_list_idx = %d; memseg_list = %p, mcfg->memsegs = %p\n", memseg_list_idx, memseg_list, mcfg->memsegs);
394                 return -1;
395         }
396 #endif
397         memseg_idx = rte_fbarray_find_idx(&memseg_list->memseg_arr, memseg);
398         if (memseg_idx < 0) {
399                 plog_err("Invalid memseg_idx = %d; memseg_list = %p, memseg = %p\n", memseg_idx, memseg_list, memseg);
400                 return -1;
401         }
402
403         char sz_str[5];
404         get_hp_sz_string(sz_str, memseg->hugepage_sz);
405         plog_info("Segment %u (sock %d): [%i-%i] [%#lx-%#lx] at %p using %zu pages of %s\n",
406                 n++,
407                 memseg->socket_id,
408                 memseg_list_idx,
409                 memseg_idx,
410                 memseg->iova,
411                 memseg->iova+len,
412                 memseg->addr,
413                 memseg->hugepage_sz?len/memseg->hugepage_sz:0, sz_str);
414
415         return 0;
416 }
417
418 #endif
419
420 void cmd_mem_layout(void)
421 {
422 #if RTE_VERSION < RTE_VERSION_NUM(18,5,0,0)
423         const struct rte_memseg* memseg = rte_eal_get_physmem_layout();
424
425         plog_info("Memory layout:\n");
426         for (uint32_t i = 0; i < RTE_MAX_MEMSEG; i++) {
427                 if (memseg[i].addr == NULL)
428                         break;
429
430                 char sz_str[5];
431                 get_hp_sz_string(sz_str, memseg[i].hugepage_sz);
432
433                 plog_info("Segment %u: [%#lx-%#lx] at %p using %zu pages of %s\n",
434                           i,
435                           memseg[i].phys_addr,
436                           memseg[i].phys_addr + memseg[i].len,
437                           memseg[i].addr,
438                           memseg[i].len/memseg[i].hugepage_sz, sz_str);
439         }
440 #else
441         int segment_number = 0;
442         //rte_memseg_walk(print_all_segments, &segment_number);
443         rte_memseg_contig_walk(print_segments, &segment_number);
444 #endif
445 }
446
447 void cmd_dump(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets, struct input *input, int rx, int tx)
448 {
449         plog_info("dump %u %u %u\n", lcore_id, task_id, nb_packets);
450         if (lcore_id > RTE_MAX_LCORE) {
451                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
452         }
453         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
454                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
455         }
456         else {
457                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
458
459                 lconf->tasks_all[task_id]->aux->task_rt_dump.input = input;
460
461                 if (wait_command_handled(lconf) == -1) return;
462                 if (rx && tx)
463                         lconf->msg.type = LCONF_MSG_DUMP;
464                 else if (rx)
465                         lconf->msg.type = LCONF_MSG_DUMP_RX;
466                 else if (tx)
467                         lconf->msg.type = LCONF_MSG_DUMP_TX;
468
469                 if (rx || tx) {
470                         lconf->msg.task_id = task_id;
471                         lconf->msg.val  = nb_packets;
472                         lconf_set_req(lconf);
473                 }
474
475                 if (lconf->n_tasks_run == 0) {
476                         lconf_do_flags(lconf);
477                 }
478         }
479 }
480
481 void cmd_trace(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets)
482 {
483         plog_info("trace %u %u %u\n", lcore_id, task_id, nb_packets);
484         if (lcore_id > RTE_MAX_LCORE) {
485                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
486         }
487         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
488                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
489         }
490         else {
491                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
492
493                 if (wait_command_handled(lconf) == -1) return;
494
495                 lconf->msg.type = LCONF_MSG_TRACE;
496                 lconf->msg.task_id = task_id;
497                 lconf->msg.val  = nb_packets;
498                 lconf_set_req(lconf);
499
500                 if (lconf->n_tasks_run == 0) {
501                         lconf_do_flags(lconf);
502                 }
503         }
504 }
505
506 void cmd_rx_bw_start(uint32_t lcore_id)
507 {
508         if (lcore_id > RTE_MAX_LCORE) {
509                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
510         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE) {
511                 plog_warn("rx bandwidt already on core %u\n", lcore_id);
512         } else {
513
514                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
515
516                 if (wait_command_handled(lconf) == -1) return;
517                 lconf->msg.type = LCONF_MSG_RX_BW_START;
518                 lconf_set_req(lconf);
519
520                 if (lconf->n_tasks_run == 0) {
521                         lconf_do_flags(lconf);
522                 }
523         }
524 }
525
526 void cmd_tx_bw_start(uint32_t lcore_id)
527 {
528         if (lcore_id > RTE_MAX_LCORE) {
529                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
530         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE) {
531                 plog_warn("tx bandwidth already running on core %u\n", lcore_id);
532         } else {
533
534                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
535
536                 if (wait_command_handled(lconf) == -1) return;
537                 lconf->msg.type = LCONF_MSG_TX_BW_START;
538                 lconf_set_req(lconf);
539
540                 if (lconf->n_tasks_run == 0) {
541                         lconf_do_flags(lconf);
542                 }
543         }
544 }
545
546 void cmd_rx_bw_stop(uint32_t lcore_id)
547 {
548         if (lcore_id > RTE_MAX_LCORE) {
549                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
550         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE)) {
551                 plog_warn("rx bandwidth not running on core %u\n", lcore_id);
552         } else {
553
554                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
555
556                 if (wait_command_handled(lconf) == -1) return;
557                 lconf->msg.type = LCONF_MSG_RX_BW_STOP;
558                 lconf_set_req(lconf);
559
560                 if (lconf->n_tasks_run == 0) {
561                         lconf_do_flags(lconf);
562                 }
563         }
564 }
565
566 void cmd_tx_bw_stop(uint32_t lcore_id)
567 {
568         if (lcore_id > RTE_MAX_LCORE) {
569                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
570         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE)) {
571                 plog_warn("tx bandwidth not running on core %u\n", lcore_id);
572         } else {
573
574                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
575
576                 if (wait_command_handled(lconf) == -1) return;
577                 lconf->msg.type = LCONF_MSG_TX_BW_STOP;
578                 lconf_set_req(lconf);
579
580                 if (lconf->n_tasks_run == 0) {
581                         lconf_do_flags(lconf);
582                 }
583         }
584 }
585 void cmd_rx_distr_start(uint32_t lcore_id)
586 {
587         if (lcore_id > RTE_MAX_LCORE) {
588                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
589         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) {
590                 plog_warn("rx distribution already xrunning on core %u\n", lcore_id);
591         } else {
592                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
593
594                 if (wait_command_handled(lconf) == -1) return;
595                 lconf->msg.type = LCONF_MSG_RX_DISTR_START;
596                 lconf_set_req(lconf);
597
598                 if (lconf->n_tasks_run == 0) {
599                         lconf_do_flags(lconf);
600                 }
601         }
602 }
603
604 void cmd_tx_distr_start(uint32_t lcore_id)
605 {
606         if (lcore_id > RTE_MAX_LCORE) {
607                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
608         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) {
609                 plog_warn("tx distribution already xrunning on core %u\n", lcore_id);
610         } else {
611                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
612
613                 if (wait_command_handled(lconf) == -1) return;
614                 lconf->msg.type = LCONF_MSG_TX_DISTR_START;
615                 lconf_set_req(lconf);
616
617                 if (lconf->n_tasks_run == 0) {
618                         lconf_do_flags(lconf);
619                 }
620         }
621 }
622
623 void cmd_rx_distr_stop(uint32_t lcore_id)
624 {
625         if (lcore_id > RTE_MAX_LCORE) {
626                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
627         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) == 0) {
628                 plog_warn("rx distribution not running on core %u\n", lcore_id);
629         } else {
630                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
631
632                 if (wait_command_handled(lconf) == -1) return;
633                 lconf->msg.type = LCONF_MSG_RX_DISTR_STOP;
634                 lconf_set_req(lconf);
635
636                 if (lconf->n_tasks_run == 0) {
637                         lconf_do_flags(lconf);
638                 }
639         }
640 }
641
642 void cmd_tx_distr_stop(uint32_t lcore_id)
643 {
644         if (lcore_id > RTE_MAX_LCORE) {
645                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
646         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) == 0) {
647                 plog_warn("tx distribution not running on core %u\n", lcore_id);
648         } else {
649                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
650
651                 if (wait_command_handled(lconf) == -1) return;
652                 lconf->msg.type = LCONF_MSG_TX_DISTR_STOP;
653                 lconf_set_req(lconf);
654
655                 if (lconf->n_tasks_run == 0) {
656                         lconf_do_flags(lconf);
657                 }
658         }
659 }
660
661 void cmd_rx_distr_rst(uint32_t lcore_id)
662 {
663         if (lcore_id > RTE_MAX_LCORE) {
664                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
665         } else {
666                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
667
668                 if (wait_command_handled(lconf) == -1) return;
669                 lconf->msg.type = LCONF_MSG_RX_DISTR_RESET;
670                 lconf_set_req(lconf);
671
672                 if (lconf->n_tasks_run == 0) {
673                         lconf_do_flags(lconf);
674                 }
675         }
676 }
677
678 void cmd_tx_distr_rst(uint32_t lcore_id)
679 {
680         if (lcore_id > RTE_MAX_LCORE) {
681                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
682         } else {
683                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
684
685                 if (wait_command_handled(lconf) == -1) return;
686                 lconf->msg.type = LCONF_MSG_TX_DISTR_RESET;
687                 lconf_set_req(lconf);
688
689                 if (lconf->n_tasks_run == 0) {
690                         lconf_do_flags(lconf);
691                 }
692         }
693 }
694
695 void cmd_rx_distr_show(uint32_t lcore_id)
696 {
697         if (lcore_id > RTE_MAX_LCORE) {
698                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
699         } else {
700                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
701                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
702                         plog_info("t[%u]: ", i);
703                         for (uint32_t j = 0; j < sizeof(t->aux->rx_bucket)/sizeof(t->aux->rx_bucket[0]); ++j) {
704                                 plog_info("%u ", t->aux->rx_bucket[j]);
705                         }
706                         plog_info("\n");
707                 }
708         }
709 }
710 void cmd_tx_distr_show(uint32_t lcore_id)
711 {
712         if (lcore_id > RTE_MAX_LCORE) {
713                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
714         } else {
715                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
716                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
717                         uint64_t tot = 0, avg = 0;
718                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
719                                 tot += t->aux->tx_bucket[j];
720                                 avg += j * t->aux->tx_bucket[j];
721                         }
722                         if (tot) {
723                                 avg = avg / tot;
724                         }
725                         plog_info("t[%u]: %lu: ", i, avg);
726                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
727                                 plog_info("%u ", t->aux->tx_bucket[j]);
728                         }
729                         plog_info("\n");
730                 }
731         }
732 }
733
734 void cmd_ringinfo_all(void)
735 {
736         struct lcore_cfg *lconf;
737         uint32_t lcore_id = -1;
738
739         while(prox_core_next(&lcore_id, 0) == 0) {
740                 lconf = &lcore_cfg[lcore_id];
741                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
742                         cmd_ringinfo(lcore_id, task_id);
743                 }
744         }
745 }
746
747 void cmd_ringinfo(uint8_t lcore_id, uint8_t task_id)
748 {
749         struct lcore_cfg *lconf;
750         struct rte_ring *ring;
751         struct task_args* targ;
752         uint32_t count;
753
754         if (!prox_core_active(lcore_id, 0)) {
755                 plog_info("lcore %u is not active\n", lcore_id);
756                 return;
757         }
758         lconf = &lcore_cfg[lcore_id];
759         if (task_id >= lconf->n_tasks_all) {
760                 plog_warn("Invalid task index %u: lcore %u has %u tasks\n", task_id, lcore_id, lconf->n_tasks_all);
761                 return;
762         }
763
764         targ = &lconf->targs[task_id];
765         plog_info("Core %u task %u: %u rings\n", lcore_id, task_id, targ->nb_rxrings);
766         for (uint8_t i = 0; i < targ->nb_rxrings; ++i) {
767                 ring = targ->rx_rings[i];
768 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
769                 count = ring->prod.mask + 1;
770 #else
771                 count = ring->mask + 1;
772 #endif
773                 plog_info("\tRing %u:\n", i);
774                 plog_info("\t\tFlags: %s,%s\n", ring->flags & RING_F_SP_ENQ? "sp":"mp", ring->flags & RING_F_SC_DEQ? "sc":"mc");
775                 plog_info("\t\tMemory size: %zu bytes\n", rte_ring_get_memsize(count));
776                 plog_info("\t\tOccupied: %u/%u\n", rte_ring_count(ring), count);
777         }
778 }
779
780 void cmd_port_up(uint8_t port_id)
781 {
782         int err;
783
784         if (!port_is_active(port_id)) {
785                 return ;
786         }
787
788         if ((err = rte_eth_dev_set_link_up(port_id)) == 0) {
789                 plog_info("Bringing port %d up\n", port_id);
790         }
791         else {
792                 plog_warn("Failed to bring port %d up with error %d\n", port_id, err);
793         }
794 }
795
796 void cmd_port_down(uint8_t port_id)
797 {
798         int err;
799
800         if (!port_is_active(port_id)) {
801                 return ;
802         }
803
804         if ((err = rte_eth_dev_set_link_down(port_id)) == 0) {
805                 plog_info("Bringing port %d down\n", port_id);
806         }
807         else {
808                 plog_warn("Failed to bring port %d down with error %d\n", port_id, err);
809         }
810 }
811
812 void cmd_xstats(uint8_t port_id)
813 {
814 #if RTE_VERSION >= RTE_VERSION_NUM(16,7,0,0)
815         int n_xstats;
816         struct rte_eth_xstat *eth_xstat = NULL; // id and value
817         struct rte_eth_xstat_name *eth_xstat_name = NULL;       // only names
818         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
819         int rc;
820
821         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
822         eth_xstat_name = prox_zmalloc(n_xstats * sizeof(*eth_xstat_name), port_cfg->socket);
823         PROX_ASSERT(eth_xstat_name);
824         rc = rte_eth_xstats_get_names(port_id, eth_xstat_name, n_xstats);
825         if ((rc < 0) || (rc > n_xstats)) {
826                 if (rc < 0) {
827                         plog_warn("Failed to get xstats_names on port %d with error %d\n", port_id, rc);
828                 } else if (rc > n_xstats) {
829                         plog_warn("Failed to get xstats_names on port %d: too many xstats (%d)\n", port_id, rc);
830                 }
831         }
832
833         eth_xstat = prox_zmalloc(n_xstats * sizeof(*eth_xstat), port_cfg->socket);
834         PROX_ASSERT(eth_xstat);
835         rc = rte_eth_xstats_get(port_id, eth_xstat, n_xstats);
836         if ((rc < 0) || (rc > n_xstats)) {
837                 if (rc < 0) {
838                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
839                 } else if (rc > n_xstats) {
840                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
841                 }
842         } else {
843                 for (int i=0;i<rc;i++) {
844                         plog_info("%s: %ld\n", eth_xstat_name[i].name, eth_xstat[i].value);
845                 }
846         }
847         if (eth_xstat_name)
848                 prox_free(eth_xstat_name);
849         if (eth_xstat)
850                 prox_free(eth_xstat);
851 #else
852 #if RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0)
853         int n_xstats;
854         struct rte_eth_xstats *eth_xstats;
855         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
856         int rc;
857
858         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
859         eth_xstats = prox_zmalloc(n_xstats * sizeof(*eth_xstats), port_cfg->socket);
860         PROX_ASSERT(eth_xstats);
861         rc = rte_eth_xstats_get(port_id, eth_xstats, n_xstats);
862         if ((rc < 0) || (rc > n_xstats)) {
863                 if (rc < 0) {
864                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
865                 } else if (rc > n_xstats) {
866                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
867                 }
868         } else {
869                 for (int i=0;i<rc;i++) {
870                         plog_info("%s: %ld\n", eth_xstats[i].name, eth_xstats[i].value);
871                 }
872         }
873         if (eth_xstats)
874                 prox_free(eth_xstats);
875 #else
876         plog_warn("Failed to get xstats, xstats are not supported in this version of dpdk\n");
877 #endif
878 #endif
879 }
880
881 void cmd_portinfo(int port_id, char *dst, size_t max_len)
882 {
883         char *end = dst + max_len;
884
885         *dst = 0;
886         if (port_id == -1) {
887                 uint8_t max_port_idx = prox_last_port_active() + 1;
888
889                 for (uint8_t port_id = 0; port_id < max_port_idx; ++port_id) {
890                         if (!prox_port_cfg[port_id].active) {
891                                 continue;
892                         }
893                         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
894
895                         dst += snprintf(dst, end - dst,
896                                         "%2d:%10s; "MAC_BYTES_FMT"; %s\n",
897                                         port_id,
898                                         port_cfg->names[0],
899                                         MAC_BYTES(port_cfg->eth_addr.addr_bytes),
900                                         port_cfg->pci_addr);
901                 }
902                 return;
903         }
904
905         if (!port_is_active(port_id)) {
906                 return ;
907         }
908
909         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
910
911         dst += snprintf(dst, end - dst, "Port info for port %u\n", port_id);
912         dst += snprintf(dst, end - dst, "\tName: %s\n", port_cfg->names[0]);
913         dst += snprintf(dst, end - dst, "\tDriver: %s\n", port_cfg->driver_name);
914         dst += snprintf(dst, end - dst, "\tMac address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes));
915         dst += snprintf(dst, end - dst, "\tLink speed: %u Mbps\n", port_cfg->link_speed);
916         dst += snprintf(dst, end - dst, "\tLink max speed: %u Mbps\n", port_cfg->max_link_speed);
917         dst += snprintf(dst, end - dst, "\tLink status: %s\n", port_cfg->link_up? "up" : "down");
918         dst += snprintf(dst, end - dst, "\tSocket: %u\n", port_cfg->socket);
919         dst += snprintf(dst, end - dst, "\tPCI address: %s\n", port_cfg->pci_addr);
920         dst += snprintf(dst, end - dst, "\tPromiscuous: %s\n", port_cfg->promiscuous? "yes" : "no");
921         for (unsigned int i = 0; i < port_cfg->nb_mc_addr; i++) {
922                 dst += snprintf(dst, end - dst, "\tmcast address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->mc_addr[i].addr_bytes));
923         }
924         dst += snprintf(dst, end - dst, "\tNumber of RX/TX descriptors: %u/%u\n", port_cfg->n_rxd, port_cfg->n_txd);
925         dst += snprintf(dst, end - dst, "\tNumber of RX/TX queues: %u/%u (max: %u/%u)\n", port_cfg->n_rxq, port_cfg->n_txq, port_cfg->max_rxq, port_cfg->max_txq);
926         dst += snprintf(dst, end - dst, "\tMemory pools:\n");
927
928         for (uint8_t i = 0; i < 32; ++i) {
929                 if (port_cfg->pool[i]) {
930                         dst += snprintf(dst, end - dst, "\t\tname: %s (%p)\n",
931                                         port_cfg->pool[i]->name, port_cfg->pool[i]);
932                 }
933         }
934 }
935
936 void cmd_read_reg(uint8_t port_id, unsigned int id)
937 {
938 #if RTE_VERSION < RTE_VERSION_NUM(21,11,0,0)
939         unsigned int val, rc;
940         if (!port_is_active(port_id)) {
941                 return ;
942         }
943         rc = read_reg(port_id, id, &val);
944         if (rc) {
945                 plog_warn("Failed to read register %d on port %d\n", id, port_id);
946         }
947         else {
948                 plog_info("Register 0x%08X : %08X \n", id, val);
949         }
950 #else
951         plog_err("cmd_read_reg(%d, %d) not supported on this dpdk version\n", port_id, id);
952 #endif
953 }
954
955 void cmd_reset_port(uint8_t portid)
956 {
957         unsigned int rc;
958         if (!prox_port_cfg[portid].active) {
959                 plog_info("port not active \n");
960                 return;
961         }
962         rte_eth_dev_stop(portid);
963         rc = rte_eth_dev_start(portid);
964         if (rc) {
965                 plog_warn("Failed to restart port %d\n", portid);
966         }
967 }
968
969 void cmd_multicast(uint8_t port_id, unsigned int val, prox_rte_ether_addr *mac)
970 {
971         if (!port_is_active(port_id)) {
972                 return;
973         }
974         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
975         if (val == 1) {
976                 if (port_cfg->nb_mc_addr == 0) {
977                         rte_eth_allmulticast_enable(port_id);
978                 }
979                 if (add_multicast_addr(port_id, mac) != 0) {
980                         if (port_cfg->nb_mc_addr == 0)
981                                 rte_eth_allmulticast_disable(port_id);
982                 }
983         } else if (val == 0) {
984                 if (del_multicast_addr(port_id, mac) == 0) {
985                         if (port_cfg->nb_mc_addr == 0) {
986                                 rte_eth_allmulticast_disable(port_id);
987                         }
988                 }
989         } else {
990                 plog_err("Unexpected value in cmd_multicast on port %d\n", port_id);
991         }
992 }
993
994 void cmd_write_reg(uint8_t port_id, unsigned int id, unsigned int val)
995 {
996 #if RTE_VERSION < RTE_VERSION_NUM(21,11,0,0)
997         if (!port_is_active(port_id)) {
998                 return ;
999         }
1000
1001         plog_info("writing 0x%08X %08X\n", id, val);
1002         write_reg(port_id, id, val);
1003 #else
1004         plog_err("cmd_write_reg(%d, %d, %d) not supported on this dpdk version\n", port_id, id, val);
1005 #endif
1006 }
1007
1008 void cmd_set_vlan_offload(uint8_t port_id, unsigned int val)
1009 {
1010         if (!port_is_active(port_id)) {
1011                 return ;
1012         }
1013
1014         plog_info("setting vlan offload to %d\n", val);
1015         if (val & ~(RTE_ETH_VLAN_STRIP_OFFLOAD | RTE_ETH_VLAN_FILTER_OFFLOAD | RTE_ETH_VLAN_EXTEND_OFFLOAD)) {
1016                 plog_info("wrong vlan offload value\n");
1017         }
1018         int ret = rte_eth_dev_set_vlan_offload(port_id, val);
1019         plog_info("rte_eth_dev_set_vlan_offload return %d\n", ret);
1020 }
1021
1022 void cmd_set_vlan_filter(uint8_t port_id, unsigned int id, unsigned int val)
1023 {
1024         if (!port_is_active(port_id)) {
1025                 return ;
1026         }
1027
1028         plog_info("setting vln filter for vlan %d to %d\n", id, val);
1029         int ret = rte_eth_dev_vlan_filter(port_id, id, val);
1030         plog_info("rte_eth_dev_vlan_filter return %d\n", ret);
1031 }
1032
1033 void cmd_thread_info(uint8_t lcore_id, uint8_t task_id)
1034 {
1035         plog_info("thread_info %u %u \n", lcore_id, task_id);
1036         if (lcore_id > RTE_MAX_LCORE) {
1037                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
1038         }
1039         if (!prox_core_active(lcore_id, 0)) {
1040                 plog_warn("lcore %u is not active\n", lcore_id);
1041                 return;
1042         }
1043         if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
1044                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
1045                 return;
1046         }
1047         if (strcmp(lcore_cfg[lcore_id].targs[task_id].task_init->mode_str, "qos") == 0) {
1048                 struct task_base *task;
1049
1050                 task = lcore_cfg[lcore_id].tasks_all[task_id];
1051                 plog_info("core %d, task %d: %d mbufs stored in QoS\n", lcore_id, task_id,
1052                           task_qos_n_pkts_buffered(task));
1053
1054 #ifdef ENABLE_EXTRA_USER_STATISTICS
1055         }
1056         else if (lcore_cfg[lcore_id].targs[task_id].mode == QINQ_ENCAP4) {
1057                 struct task_qinq_encap4 *task;
1058                 task = (struct task_qinq_encap4 *)(lcore_cfg[lcore_id].tasks_all[task_id]);
1059                 for (int i=0;i<task->n_users;i++) {
1060                         if (task->stats_per_user[i])
1061                                 plog_info("User %d: %d packets\n", i, task->stats_per_user[i]);
1062                 }
1063 #endif
1064         }
1065         else {
1066                 // Only QoS thread info so far
1067                 plog_err("core %d, task %d: not a qos core (%p)\n", lcore_id, task_id, lcore_cfg[lcore_id].thread_x);
1068         }
1069 }
1070
1071 void cmd_rx_tx_info(void)
1072 {
1073         uint32_t lcore_id = -1;
1074         while(prox_core_next(&lcore_id, 0) == 0) {
1075                 for (uint8_t task_id = 0; task_id < lcore_cfg[lcore_id].n_tasks_all; ++task_id) {
1076                         struct task_args *targ = &lcore_cfg[lcore_id].targs[task_id];
1077
1078                         plog_info("Core %u:", lcore_id);
1079                         if (targ->rx_port_queue[0].port != OUT_DISCARD) {
1080                                 for (int i = 0; i < targ->nb_rxports; i++) {
1081                                         plog_info(" RX port %u (queue %u)", targ->rx_port_queue[i].port, targ->rx_port_queue[i].queue);
1082                                 }
1083                         }
1084                         else {
1085                                 for (uint8_t j = 0; j < targ->nb_rxrings; ++j) {
1086                                         plog_info(" RX ring[%u,%u] %p", task_id, j, targ->rx_rings[j]);
1087                                 }
1088                         }
1089                         plog_info(" ==>");
1090                         for (uint8_t j = 0; j < targ->nb_txports; ++j) {
1091                                 plog_info(" TX port %u (queue %u)", targ->tx_port_queue[j].port,
1092                                           targ->tx_port_queue[j].queue);
1093                         }
1094
1095                         for (uint8_t j = 0; j < targ->nb_txrings; ++j) {
1096                                 plog_info(" TX ring %p", targ->tx_rings[j]);
1097                         }
1098
1099                         plog_info("\n");
1100                 }
1101         }
1102 }
1103 void cmd_get_cache_class(uint32_t lcore_id, uint32_t *set)
1104 {
1105         uint64_t tmp_rmid = 0;
1106         cqm_assoc_read(lcore_id, &tmp_rmid);
1107         *set = (uint32_t)(tmp_rmid >> 32);
1108 }
1109
1110 void cmd_get_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t *val)
1111 {
1112         cat_get_class_mask(lcore_id, set, val);
1113 }
1114
1115 void cmd_set_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t val)
1116 {
1117         cat_set_class_mask(lcore_id, set, val);
1118         lcore_cfg[lcore_id].cache_set = set;
1119         uint32_t id = -1;
1120         while(prox_core_next(&id, 0) == 0) {
1121                 if ((lcore_cfg[id].cache_set == set) && (rte_lcore_to_socket_id(id) == rte_lcore_to_socket_id(lcore_id))) {
1122                         plog_info("Updating mask for core %d to %d\n", id, set);
1123                         stats_update_cache_mask(id, val);
1124                 }
1125         }
1126 }
1127
1128 void cmd_set_cache_class(uint32_t lcore_id, uint32_t set)
1129 {
1130         uint64_t tmp_rmid = 0;
1131         uint32_t val = 0;
1132         cqm_assoc_read(lcore_id, &tmp_rmid);
1133         cqm_assoc(lcore_id, (tmp_rmid & 0xffffffff) | ((set * 1L) << 32));
1134         cat_get_class_mask(lcore_id, set, &val);
1135         stats_update_cache_mask(lcore_id, val);
1136 }
1137
1138 void cmd_cache_reset(void)
1139 {
1140         uint8_t sockets[MAX_SOCKETS] = {0};
1141         uint8_t cores[MAX_SOCKETS] = {0};
1142         uint32_t mask = (1 << cat_get_num_ways()) - 1;
1143         uint32_t lcore_id = -1, socket_id;
1144         while(prox_core_next(&lcore_id, 0) == 0) {
1145                 cqm_assoc(lcore_id, 0);
1146                 socket_id = rte_lcore_to_socket_id(lcore_id);
1147                 if (socket_id < MAX_SOCKETS) {
1148                         sockets[socket_id] = 1;
1149                         cores[socket_id] = lcore_id;
1150                 }
1151                 stats_update_cache_mask(lcore_id, mask);
1152                 plog_info("Setting core %d to cache mask %x\n", lcore_id, mask);
1153                 lcore_cfg[lcore_id].cache_set = 0;
1154         }
1155         for (uint32_t s = 0; s < MAX_SOCKETS; s++) {
1156                 if (sockets[s])
1157                         cat_reset_cache(cores[s]);
1158         }
1159         stats_lcore_assoc_rmid();
1160 }
1161
1162 int bypass_task(uint32_t lcore_id, uint32_t task_id)
1163 {
1164         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
1165         struct task_args *targ, *starg, *dtarg;
1166         struct rte_ring *ring = NULL;
1167
1168         if (task_id >= lconf->n_tasks_all)
1169                 return -1;
1170
1171         targ = &lconf->targs[task_id];
1172         if (targ->nb_txrings == 1) {
1173                 plog_info("Task has %d receive and 1 transmmit ring and can be bypassed, %d precedent tasks\n", targ->nb_rxrings, targ->n_prev_tasks);
1174                 // Find source task
1175                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
1176                         starg = targ->prev_tasks[i];
1177                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
1178                                 for (unsigned int k = 0; k < targ->nb_rxrings; k++) {
1179                                         if (starg->tx_rings[j] == targ->rx_rings[k]) {
1180                                                 plog_info("bypassing ring %p and connecting it to %p\n", starg->tx_rings[j], targ->tx_rings[0]);
1181                                                 starg->tx_rings[j] = targ->tx_rings[0];
1182                                                 struct task_base *tbase = starg->tbase;
1183                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1184                                         }
1185                                 }
1186                         }
1187                 }
1188         } else {
1189                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1190                 return -1;
1191         }
1192
1193         return 0;
1194 }
1195
1196 int reconnect_task(uint32_t lcore_id, uint32_t task_id)
1197 {
1198         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
1199         struct task_args *targ, *starg, *dtarg = NULL;
1200         struct rte_ring *ring = NULL;
1201
1202         if (task_id >= lconf->n_tasks_all)
1203                 return -1;
1204
1205         targ = &lconf->targs[task_id];
1206         if (targ->nb_txrings == 1) {
1207                 // Find source task
1208                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
1209                         starg = targ->prev_tasks[i];
1210                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
1211                                 if (starg->tx_rings[j] == targ->tx_rings[0]) {
1212                                         if (targ->n_prev_tasks == targ->nb_rxrings) {
1213                                                 starg->tx_rings[j] = targ->rx_rings[i];
1214                                                 struct task_base *tbase = starg->tbase;
1215                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1216                                                 plog_info("Task has %d receive and 1 transmmit ring and can be reconnected, %d precedent tasks\n", targ->nb_rxrings, targ->n_prev_tasks);
1217                                         } else if (targ->nb_rxrings == 1) {
1218                                                 starg->tx_rings[j] = targ->rx_rings[0];
1219                                                 struct task_base *tbase = starg->tbase;
1220                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1221                                                 plog_info("Task has %d receive and 1 transmmit ring and ring %p can be reconnected, %d precedent tasks\n", targ->nb_rxrings, starg->tx_rings[j], targ->n_prev_tasks);
1222                                         } else {
1223                                                 plog_err("Unexpected configuration: %d precedent tasks, %d rx rings\n", targ->n_prev_tasks, targ->nb_rxrings);
1224                                         }
1225                                 }
1226                         }
1227                 }
1228         } else {
1229                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1230                 return -1;
1231         }
1232
1233         return 0;
1234 }