a66f4888a1ccc600272f6c77e3220287428ff1ea
[samplevnf.git] / VNFs / DPPD-PROX / commands.c
1 /*
2 // Copyright (c) 2010-2017 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_txrings != 0) || (targ->nb_txports != 0)) {
117                         if (targ->flags & TASK_ARG_L3)
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, struct 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 (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         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, struct 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 (is_same_ether_addr(addr, &port_cfg->mc_addr[i])) {
287                         // Copy last address to the slot to be deleted
288                         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                                 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         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
351         int memseg_list_idx, memseg_idx;
352         int n = (*(int *)arg)++;
353
354         memseg_list_idx = memseg_list - mcfg->memsegs;
355         if ((memseg_list_idx < 0) || (memseg_list_idx >= RTE_MAX_MEMSEG_LISTS)) {
356                 plog_err("Invalid memseg_list_idx = %d; memseg_list = %p, mcfg->memsegs = %p\n", memseg_list_idx, memseg_list, mcfg->memsegs);
357                 return -1;
358         }
359         memseg_idx = rte_fbarray_find_idx(&memseg_list->memseg_arr, memseg);
360         if (memseg_idx < 0) {
361                 plog_err("Invalid memseg_idx = %d; memseg_list = %p, memseg = %p\n", memseg_idx, memseg_list, memseg);
362                 return -1;
363         }
364
365         char sz_str[5];
366         get_hp_sz_string(sz_str, memseg->hugepage_sz);
367         plog_info("Segment %u (sock %d): [%i-%i] [%#lx-%#lx] at %p using %zu pages of %s\n",
368                 n,
369                 memseg->socket_id,
370                 memseg_list_idx,
371                 memseg_idx,
372                 memseg->iova,
373                 memseg->iova+memseg->len,
374                 memseg->addr,
375                 memseg->len/memseg->hugepage_sz, sz_str);
376
377         return 0;
378 }
379
380 // Print memory segments
381 // Contiguous segments are shown as 1 big segment
382 static int print_segments(const struct rte_memseg_list *memseg_list, const struct rte_memseg *memseg, size_t len, void *arg)
383 {
384         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
385         int memseg_list_idx, memseg_idx;
386         static int n = 0;
387
388         memseg_list_idx = memseg_list - mcfg->memsegs;
389         if ((memseg_list_idx < 0) || (memseg_list_idx >= RTE_MAX_MEMSEG_LISTS)) {
390                 plog_err("Invalid memseg_list_idx = %d; memseg_list = %p, mcfg->memsegs = %p\n", memseg_list_idx, memseg_list, mcfg->memsegs);
391                 return -1;
392         }
393         memseg_idx = rte_fbarray_find_idx(&memseg_list->memseg_arr, memseg);
394         if (memseg_idx < 0) {
395                 plog_err("Invalid memseg_idx = %d; memseg_list = %p, memseg = %p\n", memseg_idx, memseg_list, memseg);
396                 return -1;
397         }
398
399         char sz_str[5];
400         get_hp_sz_string(sz_str, memseg->hugepage_sz);
401         plog_info("Segment %u (sock %d): [%i-%i] [%#lx-%#lx] at %p using %zu pages of %s\n",
402                 n++,
403                 memseg->socket_id,
404                 memseg_list_idx,
405                 memseg_idx,
406                 memseg->iova,
407                 memseg->iova+len,
408                 memseg->addr,
409                 memseg->hugepage_sz?len/memseg->hugepage_sz:0, sz_str);
410
411         return 0;
412 }
413
414 #endif
415 void cmd_mem_layout(void)
416 {
417 #if RTE_VERSION < RTE_VERSION_NUM(18,5,0,0)
418         const struct rte_memseg* memseg = rte_eal_get_physmem_layout();
419
420         plog_info("Memory layout:\n");
421         for (uint32_t i = 0; i < RTE_MAX_MEMSEG; i++) {
422                 if (memseg[i].addr == NULL)
423                         break;
424
425                 char sz_str[5];
426                 get_hp_sz_string(sz_str, memseg[i].hugepage_sz);
427
428                 plog_info("Segment %u: [%#lx-%#lx] at %p using %zu pages of %s\n",
429                           i,
430                           memseg[i].phys_addr,
431                           memseg[i].phys_addr + memseg[i].len,
432                           memseg[i].addr,
433                           memseg[i].len/memseg[i].hugepage_sz, sz_str);
434         }
435 #else
436         int segment_number = 0;
437         //rte_memseg_walk(print_all_segments, &segment_number);
438         rte_memseg_contig_walk(print_segments, &segment_number);
439 #endif
440 }
441
442 void cmd_dump(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets, struct input *input, int rx, int tx)
443 {
444         plog_info("dump %u %u %u\n", lcore_id, task_id, nb_packets);
445         if (lcore_id > RTE_MAX_LCORE) {
446                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
447         }
448         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
449                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
450         }
451         else {
452                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
453
454                 lconf->tasks_all[task_id]->aux->task_rt_dump.input = input;
455
456                 if (wait_command_handled(lconf) == -1) return;
457                 if (rx && tx)
458                         lconf->msg.type = LCONF_MSG_DUMP;
459                 else if (rx)
460                         lconf->msg.type = LCONF_MSG_DUMP_RX;
461                 else if (tx)
462                         lconf->msg.type = LCONF_MSG_DUMP_TX;
463
464                 if (rx || tx) {
465                         lconf->msg.task_id = task_id;
466                         lconf->msg.val  = nb_packets;
467                         lconf_set_req(lconf);
468                 }
469
470                 if (lconf->n_tasks_run == 0) {
471                         lconf_do_flags(lconf);
472                 }
473         }
474 }
475
476 void cmd_trace(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets)
477 {
478         plog_info("trace %u %u %u\n", lcore_id, task_id, nb_packets);
479         if (lcore_id > RTE_MAX_LCORE) {
480                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
481         }
482         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
483                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
484         }
485         else {
486                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
487
488                 if (wait_command_handled(lconf) == -1) return;
489
490                 lconf->msg.type = LCONF_MSG_TRACE;
491                 lconf->msg.task_id = task_id;
492                 lconf->msg.val  = nb_packets;
493                 lconf_set_req(lconf);
494
495                 if (lconf->n_tasks_run == 0) {
496                         lconf_do_flags(lconf);
497                 }
498         }
499 }
500
501 void cmd_rx_bw_start(uint32_t lcore_id)
502 {
503         if (lcore_id > RTE_MAX_LCORE) {
504                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
505         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE) {
506                 plog_warn("rx bandwidt already on core %u\n", lcore_id);
507         } else {
508
509                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
510
511                 if (wait_command_handled(lconf) == -1) return;
512                 lconf->msg.type = LCONF_MSG_RX_BW_START;
513                 lconf_set_req(lconf);
514
515                 if (lconf->n_tasks_run == 0) {
516                         lconf_do_flags(lconf);
517                 }
518         }
519 }
520
521 void cmd_tx_bw_start(uint32_t lcore_id)
522 {
523         if (lcore_id > RTE_MAX_LCORE) {
524                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
525         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE) {
526                 plog_warn("tx bandwidth already running on core %u\n", lcore_id);
527         } else {
528
529                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
530
531                 if (wait_command_handled(lconf) == -1) return;
532                 lconf->msg.type = LCONF_MSG_TX_BW_START;
533                 lconf_set_req(lconf);
534
535                 if (lconf->n_tasks_run == 0) {
536                         lconf_do_flags(lconf);
537                 }
538         }
539 }
540
541 void cmd_rx_bw_stop(uint32_t lcore_id)
542 {
543         if (lcore_id > RTE_MAX_LCORE) {
544                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
545         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE)) {
546                 plog_warn("rx bandwidth not running on core %u\n", lcore_id);
547         } else {
548
549                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
550
551                 if (wait_command_handled(lconf) == -1) return;
552                 lconf->msg.type = LCONF_MSG_RX_BW_STOP;
553                 lconf_set_req(lconf);
554
555                 if (lconf->n_tasks_run == 0) {
556                         lconf_do_flags(lconf);
557                 }
558         }
559 }
560
561 void cmd_tx_bw_stop(uint32_t lcore_id)
562 {
563         if (lcore_id > RTE_MAX_LCORE) {
564                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
565         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE)) {
566                 plog_warn("tx bandwidth not running on core %u\n", lcore_id);
567         } else {
568
569                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
570
571                 if (wait_command_handled(lconf) == -1) return;
572                 lconf->msg.type = LCONF_MSG_TX_BW_STOP;
573                 lconf_set_req(lconf);
574
575                 if (lconf->n_tasks_run == 0) {
576                         lconf_do_flags(lconf);
577                 }
578         }
579 }
580 void cmd_rx_distr_start(uint32_t lcore_id)
581 {
582         if (lcore_id > RTE_MAX_LCORE) {
583                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
584         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) {
585                 plog_warn("rx distribution already xrunning on core %u\n", lcore_id);
586         } else {
587                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
588
589                 if (wait_command_handled(lconf) == -1) return;
590                 lconf->msg.type = LCONF_MSG_RX_DISTR_START;
591                 lconf_set_req(lconf);
592
593                 if (lconf->n_tasks_run == 0) {
594                         lconf_do_flags(lconf);
595                 }
596         }
597 }
598
599 void cmd_tx_distr_start(uint32_t lcore_id)
600 {
601         if (lcore_id > RTE_MAX_LCORE) {
602                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
603         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) {
604                 plog_warn("tx distribution already xrunning on core %u\n", lcore_id);
605         } else {
606                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
607
608                 if (wait_command_handled(lconf) == -1) return;
609                 lconf->msg.type = LCONF_MSG_TX_DISTR_START;
610                 lconf_set_req(lconf);
611
612                 if (lconf->n_tasks_run == 0) {
613                         lconf_do_flags(lconf);
614                 }
615         }
616 }
617
618 void cmd_rx_distr_stop(uint32_t lcore_id)
619 {
620         if (lcore_id > RTE_MAX_LCORE) {
621                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
622         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) == 0) {
623                 plog_warn("rx distribution not running on core %u\n", lcore_id);
624         } else {
625                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
626
627                 if (wait_command_handled(lconf) == -1) return;
628                 lconf->msg.type = LCONF_MSG_RX_DISTR_STOP;
629                 lconf_set_req(lconf);
630
631                 if (lconf->n_tasks_run == 0) {
632                         lconf_do_flags(lconf);
633                 }
634         }
635 }
636
637 void cmd_tx_distr_stop(uint32_t lcore_id)
638 {
639         if (lcore_id > RTE_MAX_LCORE) {
640                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
641         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) == 0) {
642                 plog_warn("tx distribution not running on core %u\n", lcore_id);
643         } else {
644                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
645
646                 if (wait_command_handled(lconf) == -1) return;
647                 lconf->msg.type = LCONF_MSG_TX_DISTR_STOP;
648                 lconf_set_req(lconf);
649
650                 if (lconf->n_tasks_run == 0) {
651                         lconf_do_flags(lconf);
652                 }
653         }
654 }
655
656 void cmd_rx_distr_rst(uint32_t lcore_id)
657 {
658         if (lcore_id > RTE_MAX_LCORE) {
659                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
660         } else {
661                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
662
663                 if (wait_command_handled(lconf) == -1) return;
664                 lconf->msg.type = LCONF_MSG_RX_DISTR_RESET;
665                 lconf_set_req(lconf);
666
667                 if (lconf->n_tasks_run == 0) {
668                         lconf_do_flags(lconf);
669                 }
670         }
671 }
672
673 void cmd_tx_distr_rst(uint32_t lcore_id)
674 {
675         if (lcore_id > RTE_MAX_LCORE) {
676                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
677         } else {
678                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
679
680                 if (wait_command_handled(lconf) == -1) return;
681                 lconf->msg.type = LCONF_MSG_TX_DISTR_RESET;
682                 lconf_set_req(lconf);
683
684                 if (lconf->n_tasks_run == 0) {
685                         lconf_do_flags(lconf);
686                 }
687         }
688 }
689
690 void cmd_rx_distr_show(uint32_t lcore_id)
691 {
692         if (lcore_id > RTE_MAX_LCORE) {
693                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
694         } else {
695                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
696                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
697                         plog_info("t[%u]: ", i);
698                         for (uint32_t j = 0; j < sizeof(t->aux->rx_bucket)/sizeof(t->aux->rx_bucket[0]); ++j) {
699                                 plog_info("%u ", t->aux->rx_bucket[j]);
700                         }
701                         plog_info("\n");
702                 }
703         }
704 }
705 void cmd_tx_distr_show(uint32_t lcore_id)
706 {
707         if (lcore_id > RTE_MAX_LCORE) {
708                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
709         } else {
710                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
711                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
712                         uint64_t tot = 0, avg = 0;
713                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
714                                 tot += t->aux->tx_bucket[j];
715                                 avg += j * t->aux->tx_bucket[j];
716                         }
717                         if (tot) {
718                                 avg = avg / tot;
719                         }
720                         plog_info("t[%u]: %lu: ", i, avg);
721                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
722                                 plog_info("%u ", t->aux->tx_bucket[j]);
723                         }
724                         plog_info("\n");
725                 }
726         }
727 }
728
729 void cmd_ringinfo_all(void)
730 {
731         struct lcore_cfg *lconf;
732         uint32_t lcore_id = -1;
733
734         while(prox_core_next(&lcore_id, 0) == 0) {
735                 lconf = &lcore_cfg[lcore_id];
736                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
737                         cmd_ringinfo(lcore_id, task_id);
738                 }
739         }
740 }
741
742 void cmd_ringinfo(uint8_t lcore_id, uint8_t task_id)
743 {
744         struct lcore_cfg *lconf;
745         struct rte_ring *ring;
746         struct task_args* targ;
747         uint32_t count;
748
749         if (!prox_core_active(lcore_id, 0)) {
750                 plog_info("lcore %u is not active\n", lcore_id);
751                 return;
752         }
753         lconf = &lcore_cfg[lcore_id];
754         if (task_id >= lconf->n_tasks_all) {
755                 plog_warn("Invalid task index %u: lcore %u has %u tasks\n", task_id, lcore_id, lconf->n_tasks_all);
756                 return;
757         }
758
759         targ = &lconf->targs[task_id];
760         plog_info("Core %u task %u: %u rings\n", lcore_id, task_id, targ->nb_rxrings);
761         for (uint8_t i = 0; i < targ->nb_rxrings; ++i) {
762                 ring = targ->rx_rings[i];
763 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
764                 count = ring->prod.mask + 1;
765 #else
766                 count = ring->mask + 1;
767 #endif
768                 plog_info("\tRing %u:\n", i);
769                 plog_info("\t\tFlags: %s,%s\n", ring->flags & RING_F_SP_ENQ? "sp":"mp", ring->flags & RING_F_SC_DEQ? "sc":"mc");
770                 plog_info("\t\tMemory size: %zu bytes\n", rte_ring_get_memsize(count));
771                 plog_info("\t\tOccupied: %u/%u\n", rte_ring_count(ring), count);
772         }
773 }
774
775 void cmd_port_up(uint8_t port_id)
776 {
777         int err;
778
779         if (!port_is_active(port_id)) {
780                 return ;
781         }
782
783         if ((err = rte_eth_dev_set_link_up(port_id)) == 0) {
784                 plog_info("Bringing port %d up\n", port_id);
785         }
786         else {
787                 plog_warn("Failed to bring port %d up with error %d\n", port_id, err);
788         }
789 }
790
791 void cmd_port_down(uint8_t port_id)
792 {
793         int err;
794
795         if (!port_is_active(port_id)) {
796                 return ;
797         }
798
799         if ((err = rte_eth_dev_set_link_down(port_id)) == 0) {
800                 plog_info("Bringing port %d down\n", port_id);
801         }
802         else {
803                 plog_warn("Failed to bring port %d down with error %d\n", port_id, err);
804         }
805 }
806
807 void cmd_xstats(uint8_t port_id)
808 {
809 #if RTE_VERSION >= RTE_VERSION_NUM(16,7,0,0)
810         int n_xstats;
811         struct rte_eth_xstat *eth_xstat = NULL; // id and value
812         struct rte_eth_xstat_name *eth_xstat_name = NULL;       // only names
813         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
814         int rc;
815
816         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
817         eth_xstat_name = prox_zmalloc(n_xstats * sizeof(*eth_xstat_name), port_cfg->socket);
818         PROX_ASSERT(eth_xstat_name);
819         rc = rte_eth_xstats_get_names(port_id, eth_xstat_name, n_xstats);
820         if ((rc < 0) || (rc > n_xstats)) {
821                 if (rc < 0) {
822                         plog_warn("Failed to get xstats_names on port %d with error %d\n", port_id, rc);
823                 } else if (rc > n_xstats) {
824                         plog_warn("Failed to get xstats_names on port %d: too many xstats (%d)\n", port_id, rc);
825                 }
826         }
827
828         eth_xstat = prox_zmalloc(n_xstats * sizeof(*eth_xstat), port_cfg->socket);
829         PROX_ASSERT(eth_xstat);
830         rc = rte_eth_xstats_get(port_id, eth_xstat, n_xstats);
831         if ((rc < 0) || (rc > n_xstats)) {
832                 if (rc < 0) {
833                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
834                 } else if (rc > n_xstats) {
835                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
836                 }
837         } else {
838                 for (int i=0;i<rc;i++) {
839                         plog_info("%s: %ld\n", eth_xstat_name[i].name, eth_xstat[i].value);
840                 }
841         }
842         if (eth_xstat_name)
843                 prox_free(eth_xstat_name);
844         if (eth_xstat)
845                 prox_free(eth_xstat);
846 #else
847 #if RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0)
848         int n_xstats;
849         struct rte_eth_xstats *eth_xstats;
850         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
851         int rc;
852
853         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
854         eth_xstats = prox_zmalloc(n_xstats * sizeof(*eth_xstats), port_cfg->socket);
855         PROX_ASSERT(eth_xstats);
856         rc = rte_eth_xstats_get(port_id, eth_xstats, n_xstats);
857         if ((rc < 0) || (rc > n_xstats)) {
858                 if (rc < 0) {
859                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
860                 } else if (rc > n_xstats) {
861                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
862                 }
863         } else {
864                 for (int i=0;i<rc;i++) {
865                         plog_info("%s: %ld\n", eth_xstats[i].name, eth_xstats[i].value);
866                 }
867         }
868         if (eth_xstats)
869                 prox_free(eth_xstats);
870 #else
871         plog_warn("Failed to get xstats, xstats are not supported in this version of dpdk\n");
872 #endif
873 #endif
874 }
875
876 void cmd_portinfo(int port_id, char *dst, size_t max_len)
877 {
878         char *end = dst + max_len;
879
880         *dst = 0;
881         if (port_id == -1) {
882                 uint8_t max_port_idx = prox_last_port_active() + 1;
883
884                 for (uint8_t port_id = 0; port_id < max_port_idx; ++port_id) {
885                         if (!prox_port_cfg[port_id].active) {
886                                 continue;
887                         }
888                         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
889
890                         dst += snprintf(dst, end - dst,
891                                         "%2d:%10s; "MAC_BYTES_FMT"; %s\n",
892                                         port_id,
893                                         port_cfg->name,
894                                         MAC_BYTES(port_cfg->eth_addr.addr_bytes),
895                                         port_cfg->pci_addr);
896                 }
897                 return;
898         }
899
900         if (!port_is_active(port_id)) {
901                 return ;
902         }
903
904         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
905
906         dst += snprintf(dst, end - dst, "Port info for port %u\n", port_id);
907         dst += snprintf(dst, end - dst, "\tName: %s\n", port_cfg->name);
908         dst += snprintf(dst, end - dst, "\tDriver: %s\n", port_cfg->driver_name);
909         dst += snprintf(dst, end - dst, "\tMac address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes));
910         dst += snprintf(dst, end - dst, "\tLink speed: %u Mbps\n", port_cfg->link_speed);
911         dst += snprintf(dst, end - dst, "\tLink max speed: %u Mbps\n", port_cfg->max_link_speed);
912         dst += snprintf(dst, end - dst, "\tLink status: %s\n", port_cfg->link_up? "up" : "down");
913         dst += snprintf(dst, end - dst, "\tSocket: %u\n", port_cfg->socket);
914         dst += snprintf(dst, end - dst, "\tPCI address: %s\n", port_cfg->pci_addr);
915         dst += snprintf(dst, end - dst, "\tPromiscuous: %s\n", port_cfg->promiscuous? "yes" : "no");
916         for (unsigned int i = 0; i < port_cfg->nb_mc_addr; i++) {
917                 dst += snprintf(dst, end - dst, "\tmcast address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->mc_addr[i].addr_bytes));
918         }
919         dst += snprintf(dst, end - dst, "\tNumber of RX/TX descriptors: %u/%u\n", port_cfg->n_rxd, port_cfg->n_txd);
920         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);
921         dst += snprintf(dst, end - dst, "\tMemory pools:\n");
922
923         for (uint8_t i = 0; i < 32; ++i) {
924                 if (port_cfg->pool[i]) {
925                         dst += snprintf(dst, end - dst, "\t\tname: %s (%p)\n",
926                                         port_cfg->pool[i]->name, port_cfg->pool[i]);
927                 }
928         }
929 }
930
931 void cmd_read_reg(uint8_t port_id, unsigned int id)
932 {
933         unsigned int val, rc;
934         if (!port_is_active(port_id)) {
935                 return ;
936         }
937         rc = read_reg(port_id, id, &val);
938         if (rc) {
939                 plog_warn("Failed to read register %d on port %d\n", id, port_id);
940         }
941         else {
942                 plog_info("Register 0x%08X : %08X \n", id, val);
943         }
944 }
945
946 void cmd_reset_port(uint8_t portid)
947 {
948         unsigned int rc;
949         if (!prox_port_cfg[portid].active) {
950                 plog_info("port not active \n");
951                 return;
952         }
953         rte_eth_dev_stop(portid);
954         rc = rte_eth_dev_start(portid);
955         if (rc) {
956                 plog_warn("Failed to restart port %d\n", portid);
957         }
958 }
959
960 void cmd_multicast(uint8_t port_id, unsigned int val, struct ether_addr *mac)
961 {
962         if (!port_is_active(port_id)) {
963                 return;
964         }
965         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
966         if (val == 1) {
967                 if (port_cfg->nb_mc_addr == 0) {
968                         rte_eth_allmulticast_enable(port_id);
969                 }
970                 if (add_multicast_addr(port_id, mac) != 0) {
971                         if (port_cfg->nb_mc_addr == 0)
972                                 rte_eth_allmulticast_disable(port_id);
973                 }
974         } else if (val == 0) {
975                 if (del_multicast_addr(port_id, mac) == 0) {
976                         if (port_cfg->nb_mc_addr == 0) {
977                                 rte_eth_allmulticast_disable(port_id);
978                         }
979                 }
980         } else {
981                 plog_err("Unexpected value in cmd_multicast on port %d\n", port_id);
982         }
983 }
984
985 void cmd_write_reg(uint8_t port_id, unsigned int id, unsigned int val)
986 {
987         if (!port_is_active(port_id)) {
988                 return ;
989         }
990
991         plog_info("writing 0x%08X %08X\n", id, val);
992         write_reg(port_id, id, val);
993 }
994
995 void cmd_set_vlan_offload(uint8_t port_id, unsigned int val)
996 {
997         if (!port_is_active(port_id)) {
998                 return ;
999         }
1000
1001         plog_info("setting vlan offload to %d\n", val);
1002         if (val & ~(ETH_VLAN_STRIP_OFFLOAD | ETH_VLAN_FILTER_OFFLOAD | ETH_VLAN_EXTEND_OFFLOAD)) {
1003                 plog_info("wrong vlan offload value\n");
1004         }
1005         int ret = rte_eth_dev_set_vlan_offload(port_id, val);
1006         plog_info("rte_eth_dev_set_vlan_offload return %d\n", ret);
1007 }
1008
1009 void cmd_set_vlan_filter(uint8_t port_id, unsigned int id, unsigned int val)
1010 {
1011         if (!port_is_active(port_id)) {
1012                 return ;
1013         }
1014
1015         plog_info("setting vln filter for vlan %d to %d\n", id, val);
1016         int ret = rte_eth_dev_vlan_filter(port_id, id, val);
1017         plog_info("rte_eth_dev_vlan_filter return %d\n", ret);
1018 }
1019
1020 void cmd_thread_info(uint8_t lcore_id, uint8_t task_id)
1021 {
1022         plog_info("thread_info %u %u \n", lcore_id, task_id);
1023         if (lcore_id > RTE_MAX_LCORE) {
1024                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
1025         }
1026         if (!prox_core_active(lcore_id, 0)) {
1027                 plog_warn("lcore %u is not active\n", lcore_id);
1028                 return;
1029         }
1030         if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
1031                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
1032                 return;
1033         }
1034         if (strcmp(lcore_cfg[lcore_id].targs[task_id].task_init->mode_str, "qos") == 0) {
1035                 struct task_base *task;
1036
1037                 task = lcore_cfg[lcore_id].tasks_all[task_id];
1038                 plog_info("core %d, task %d: %d mbufs stored in QoS\n", lcore_id, task_id,
1039                           task_qos_n_pkts_buffered(task));
1040
1041 #ifdef ENABLE_EXTRA_USER_STATISTICS
1042         }
1043         else if (lcore_cfg[lcore_id].targs[task_id].mode == QINQ_ENCAP4) {
1044                 struct task_qinq_encap4 *task;
1045                 task = (struct task_qinq_encap4 *)(lcore_cfg[lcore_id].tasks_all[task_id]);
1046                 for (int i=0;i<task->n_users;i++) {
1047                         if (task->stats_per_user[i])
1048                                 plog_info("User %d: %d packets\n", i, task->stats_per_user[i]);
1049                 }
1050 #endif
1051         }
1052         else {
1053                 // Only QoS thread info so far
1054                 plog_err("core %d, task %d: not a qos core (%p)\n", lcore_id, task_id, lcore_cfg[lcore_id].thread_x);
1055         }
1056 }
1057
1058 void cmd_rx_tx_info(void)
1059 {
1060         uint32_t lcore_id = -1;
1061         while(prox_core_next(&lcore_id, 0) == 0) {
1062                 for (uint8_t task_id = 0; task_id < lcore_cfg[lcore_id].n_tasks_all; ++task_id) {
1063                         struct task_args *targ = &lcore_cfg[lcore_id].targs[task_id];
1064
1065                         plog_info("Core %u:", lcore_id);
1066                         if (targ->rx_port_queue[0].port != OUT_DISCARD) {
1067                                 for (int i = 0; i < targ->nb_rxports; i++) {
1068                                         plog_info(" RX port %u (queue %u)", targ->rx_port_queue[i].port, targ->rx_port_queue[i].queue);
1069                                 }
1070                         }
1071                         else {
1072                                 for (uint8_t j = 0; j < targ->nb_rxrings; ++j) {
1073                                         plog_info(" RX ring[%u,%u] %p", task_id, j, targ->rx_rings[j]);
1074                                 }
1075                         }
1076                         plog_info(" ==>");
1077                         for (uint8_t j = 0; j < targ->nb_txports; ++j) {
1078                                 plog_info(" TX port %u (queue %u)", targ->tx_port_queue[j].port,
1079                                           targ->tx_port_queue[j].queue);
1080                         }
1081
1082                         for (uint8_t j = 0; j < targ->nb_txrings; ++j) {
1083                                 plog_info(" TX ring %p", targ->tx_rings[j]);
1084                         }
1085
1086                         plog_info("\n");
1087                 }
1088         }
1089 }
1090 void cmd_get_cache_class(uint32_t lcore_id, uint32_t *set)
1091 {
1092         uint64_t tmp_rmid = 0;
1093         cqm_assoc_read(lcore_id, &tmp_rmid);
1094         *set = (uint32_t)(tmp_rmid >> 32);
1095 }
1096
1097 void cmd_get_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t *val)
1098 {
1099         cat_get_class_mask(lcore_id, set, val);
1100 }
1101
1102 void cmd_set_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t val)
1103 {
1104         cat_set_class_mask(lcore_id, set, val);
1105         lcore_cfg[lcore_id].cache_set = set;
1106         uint32_t id = -1;
1107         while(prox_core_next(&id, 0) == 0) {
1108                 if ((lcore_cfg[id].cache_set == set) && (rte_lcore_to_socket_id(id) == rte_lcore_to_socket_id(lcore_id))) {
1109                         plog_info("Updating mask for core %d to %d\n", id, set);
1110                         stats_update_cache_mask(id, val);
1111                 }
1112         }
1113 }
1114
1115 void cmd_set_cache_class(uint32_t lcore_id, uint32_t set)
1116 {
1117         uint64_t tmp_rmid = 0;
1118         uint32_t val = 0;
1119         cqm_assoc_read(lcore_id, &tmp_rmid);
1120         cqm_assoc(lcore_id, (tmp_rmid & 0xffffffff) | ((set * 1L) << 32));
1121         cat_get_class_mask(lcore_id, set, &val);
1122         stats_update_cache_mask(lcore_id, val);
1123 }
1124
1125 void cmd_cache_reset(void)
1126 {
1127         uint8_t sockets[MAX_SOCKETS] = {0};
1128         uint8_t cores[MAX_SOCKETS] = {0};
1129         uint32_t mask = (1 << cat_get_num_ways()) - 1;
1130         uint32_t lcore_id = -1, socket_id;
1131         while(prox_core_next(&lcore_id, 0) == 0) {
1132                 cqm_assoc(lcore_id, 0);
1133                 socket_id = rte_lcore_to_socket_id(lcore_id);
1134                 if (socket_id < MAX_SOCKETS) {
1135                         sockets[socket_id] = 1;
1136                         cores[socket_id] = lcore_id;
1137                 }
1138                 stats_update_cache_mask(lcore_id, mask);
1139                 plog_info("Setting core %d to cache mask %x\n", lcore_id, mask);
1140                 lcore_cfg[lcore_id].cache_set = 0;
1141         }
1142         for (uint32_t s = 0; s < MAX_SOCKETS; s++) {
1143                 if (sockets[s])
1144                         cat_reset_cache(cores[s]);
1145         }
1146         stats_lcore_assoc_rmid();
1147 }
1148
1149 int bypass_task(uint32_t lcore_id, uint32_t task_id)
1150 {
1151         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
1152         struct task_args *targ, *starg, *dtarg;
1153         struct rte_ring *ring = NULL;
1154
1155         if (task_id >= lconf->n_tasks_all)
1156                 return -1;
1157
1158         targ = &lconf->targs[task_id];
1159         if (targ->nb_txrings == 1) {
1160                 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);
1161                 // Find source task
1162                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
1163                         starg = targ->prev_tasks[i];
1164                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
1165                                 for (unsigned int k = 0; k < targ->nb_rxrings; k++) {
1166                                         if (starg->tx_rings[j] == targ->rx_rings[k]) {
1167                                                 plog_info("bypassing ring %p and connecting it to %p\n", starg->tx_rings[j], targ->tx_rings[0]);
1168                                                 starg->tx_rings[j] = targ->tx_rings[0];
1169                                                 struct task_base *tbase = starg->tbase;
1170                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1171                                         }
1172                                 }
1173                         }
1174                 }
1175         } else {
1176                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1177                 return -1;
1178         }
1179
1180         return 0;
1181 }
1182
1183 int reconnect_task(uint32_t lcore_id, uint32_t task_id)
1184 {
1185         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
1186         struct task_args *targ, *starg, *dtarg = NULL;
1187         struct rte_ring *ring = NULL;
1188
1189         if (task_id >= lconf->n_tasks_all)
1190                 return -1;
1191
1192         targ = &lconf->targs[task_id];
1193         if (targ->nb_txrings == 1) {
1194                 // Find source task
1195                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
1196                         starg = targ->prev_tasks[i];
1197                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
1198                                 if (starg->tx_rings[j] == targ->tx_rings[0]) {
1199                                         if (targ->n_prev_tasks == targ->nb_rxrings) {
1200                                                 starg->tx_rings[j] = targ->rx_rings[i];
1201                                                 struct task_base *tbase = starg->tbase;
1202                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1203                                                 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);
1204                                         } else if (targ->nb_rxrings == 1) {
1205                                                 starg->tx_rings[j] = targ->rx_rings[0];
1206                                                 struct task_base *tbase = starg->tbase;
1207                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1208                                                 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);
1209                                         } else {
1210                                                 plog_err("Unexpected configuration: %d precedent tasks, %d rx rings\n", targ->n_prev_tasks, targ->nb_rxrings);
1211                                         }
1212                                 }
1213                         }
1214                 }
1215         } else {
1216                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1217                 return -1;
1218         }
1219
1220         return 0;
1221 }