Merge "PROX generator: performance optimization (2/4)"
[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 {
141                                 targ = &lconf->targs[task_id];
142                                 start_l3(targ);
143                         }
144                         lconf->msg.type = LCONF_MSG_START;
145                         lconf->msg.task_id = task_id;
146                         lconf_set_req(lconf);
147                         if (task_id == -1)
148                                 plog_info("Starting core %u (all tasks)\n", cores[i]);
149                         else
150                                 plog_info("Starting core %u task %u\n", cores[i], task_id);
151                         started_cores[n_started_cores++] = cores[i];
152                         lconf->flags |= LCONF_FLAG_RUNNING;
153                         rte_eal_remote_launch(lconf_run, NULL, cores[i]);
154                 }
155                 else {
156                         plog_warn("Core %u is already running all its tasks\n", cores[i]);
157                 }
158         }
159
160         /* This function is blocking, so detect when each core has
161            consumed the message. */
162         for (int i = 0; i < n_started_cores; ++i) {
163                 struct lcore_cfg *lconf = &lcore_cfg[started_cores[i]];
164                 plog_info("Waiting for core %u to start...", started_cores[i]);
165                 if (wait_command_handled(lconf) == -1) return;
166                 plog_info(" OK\n");
167         }
168 }
169
170 void stop_cores(uint32_t *cores, int count, int task_id)
171 {
172         int n_stopped_cores = 0;
173         uint32_t stopped_cores[RTE_MAX_LCORE];
174         uint32_t c;
175
176         warn_inactive_cores(cores, count, "Can't stop core");
177
178         for (int i = 0; i < count; ++i) {
179                 struct lcore_cfg *lconf = &lcore_cfg[cores[i]];
180                 if (lconf->n_tasks_run) {
181                         if (wait_command_handled(lconf) == -1) return;
182
183                         lconf->msg.type = LCONF_MSG_STOP;
184                         lconf->msg.task_id = task_id;
185                         lconf_set_req(lconf);
186                         stopped_cores[n_stopped_cores++] = cores[i];
187                 }
188         }
189
190         for (int i = 0; i < n_stopped_cores; ++i) {
191                 c = stopped_cores[i];
192                 struct lcore_cfg *lconf = &lcore_cfg[c];
193                 if (wait_command_handled(lconf) == -1) return;
194
195                 if (lconf->n_tasks_run == 0) {
196                         plog_info("All tasks stopped on core %u, waiting for core to stop...", c);
197                         rte_eal_wait_lcore(c);
198                         plog_info(" OK\n");
199                         lconf->flags &= ~LCONF_FLAG_RUNNING;
200                 }
201                 else {
202                         plog_info("Stopped task %u on core %u\n", task_id, c);
203                 }
204         }
205 }
206
207 struct size_unit {
208         uint64_t val;
209         uint64_t frac;
210         char     unit[8];
211 };
212
213 static struct size_unit to_size_unit(uint64_t bytes)
214 {
215         struct size_unit ret;
216
217         if (bytes > 1 << 30) {
218                 ret.val = bytes >> 30;
219                 ret.frac = ((bytes - (ret.val << 30)) * 1000) / (1 << 30);
220                 strcpy(ret.unit, "GB");
221         }
222         else if (bytes > 1 << 20) {
223                 ret.val = bytes >> 20;
224                 ret.frac = ((bytes - (ret.val << 20)) * 1000) / (1 << 20);
225                 strcpy(ret.unit, "MB");
226         }
227         else if (bytes > 1 << 10) {
228                 ret.val = bytes >> 10;
229                 ret.frac = (bytes - (ret.val << 10)) * 1000 / (1 << 10);
230                 strcpy(ret.unit, "KB");
231         }
232         else {
233                 ret.val = bytes;
234                 ret.frac = 0;
235                 strcpy(ret.unit, "B");
236         }
237
238         return ret;
239 }
240
241 void cmd_mem_stats(void)
242 {
243         struct rte_malloc_socket_stats sock_stats;
244         uint64_t v;
245         struct size_unit su;
246
247         for (uint32_t i = 0; i < RTE_MAX_NUMA_NODES; ++i) {
248                 if (rte_malloc_get_socket_stats(i, &sock_stats) < 0 || sock_stats.heap_totalsz_bytes == 0)
249                         continue;
250
251                 plogx_info("Socket %u memory stats:\n", i);
252                 su = to_size_unit(sock_stats.heap_totalsz_bytes);
253                 plogx_info("\tHeap_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
254                 su = to_size_unit(sock_stats.heap_freesz_bytes);
255                 plogx_info("\tFree_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
256                 su = to_size_unit(sock_stats.heap_allocsz_bytes);
257                 plogx_info("\tAlloc_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
258                 su = to_size_unit(sock_stats.greatest_free_size);
259                 plogx_info("\tGreatest_free_size: %zu %s\n", su.val, su.unit);
260                 plogx_info("\tAlloc_count: %u\n", sock_stats.alloc_count);
261                 plogx_info("\tFree_count: %u\n", sock_stats.free_count);
262         }
263 }
264
265 static void get_hp_sz_string(char *sz_str, uint64_t hp_sz)
266 {
267         switch (hp_sz >> 20) {
268         case 0:
269                 strcpy(sz_str, " 0 ");
270                 break;
271         case 2:
272                 strcpy(sz_str, "2MB");
273                 break;
274         case 1024:
275                 strcpy(sz_str, "1GB");
276                 break;
277         default:
278                 strcpy(sz_str, "??");
279         }
280 }
281
282 #if RTE_VERSION >= RTE_VERSION_NUM(18,5,0,0)
283 // Print all segments, 1 by 1
284 // Unused for now, keep for reference
285 static int print_all_segments(const struct rte_memseg_list *memseg_list, const struct rte_memseg *memseg, void *arg)
286 {
287         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
288         int memseg_list_idx, memseg_idx;
289         int n = (*(int *)arg)++;
290
291         memseg_list_idx = memseg_list - mcfg->memsegs;
292         if ((memseg_list_idx < 0) || (memseg_list_idx >= RTE_MAX_MEMSEG_LISTS)) {
293                 plog_err("Invalid memseg_list_idx = %d; memseg_list = %p, mcfg->memsegs = %p\n", memseg_list_idx, memseg_list, mcfg->memsegs);
294                 return -1;
295         }
296         memseg_idx = rte_fbarray_find_idx(&memseg_list->memseg_arr, memseg);
297         if (memseg_idx < 0) {
298                 plog_err("Invalid memseg_idx = %d; memseg_list = %p, memseg = %p\n", memseg_idx, memseg_list, memseg);
299                 return -1;
300         }
301
302         char sz_str[5];
303         get_hp_sz_string(sz_str, memseg->hugepage_sz);
304         plog_info("Segment %u (sock %d): [%i-%i] [%#lx-%#lx] at %p using %zu pages of %s\n",
305                 n,
306                 memseg->socket_id,
307                 memseg_list_idx,
308                 memseg_idx,
309                 memseg->iova,
310                 memseg->iova+memseg->len,
311                 memseg->addr,
312                 memseg->len/memseg->hugepage_sz, sz_str);
313
314         return 0;
315 }
316
317 // Print memory segments
318 // Contiguous segments are shown as 1 big segment
319 static int print_segments(const struct rte_memseg_list *memseg_list, const struct rte_memseg *memseg, size_t len, void *arg)
320 {
321         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
322         int memseg_list_idx, memseg_idx;
323         static int n = 0;
324
325         memseg_list_idx = memseg_list - mcfg->memsegs;
326         if ((memseg_list_idx < 0) || (memseg_list_idx >= RTE_MAX_MEMSEG_LISTS)) {
327                 plog_err("Invalid memseg_list_idx = %d; memseg_list = %p, mcfg->memsegs = %p\n", memseg_list_idx, memseg_list, mcfg->memsegs);
328                 return -1;
329         }
330         memseg_idx = rte_fbarray_find_idx(&memseg_list->memseg_arr, memseg);
331         if (memseg_idx < 0) {
332                 plog_err("Invalid memseg_idx = %d; memseg_list = %p, memseg = %p\n", memseg_idx, memseg_list, memseg);
333                 return -1;
334         }
335
336         char sz_str[5];
337         get_hp_sz_string(sz_str, memseg->hugepage_sz);
338         plog_info("Segment %u (sock %d): [%i-%i] [%#lx-%#lx] at %p using %zu pages of %s\n",
339                 n++,
340                 memseg->socket_id,
341                 memseg_list_idx,
342                 memseg_idx,
343                 memseg->iova,
344                 memseg->iova+len,
345                 memseg->addr,
346                 memseg->hugepage_sz?len/memseg->hugepage_sz:0, sz_str);
347
348         return 0;
349 }
350
351 #endif
352 void cmd_mem_layout(void)
353 {
354 #if RTE_VERSION < RTE_VERSION_NUM(18,5,0,0)
355         const struct rte_memseg* memseg = rte_eal_get_physmem_layout();
356
357         plog_info("Memory layout:\n");
358         for (uint32_t i = 0; i < RTE_MAX_MEMSEG; i++) {
359                 if (memseg[i].addr == NULL)
360                         break;
361
362                 char sz_str[5];
363                 get_hp_sz_string(sz_str, memseg[i].hugepage_sz);
364
365                 plog_info("Segment %u: [%#lx-%#lx] at %p using %zu pages of %s\n",
366                           i,
367                           memseg[i].phys_addr,
368                           memseg[i].phys_addr + memseg[i].len,
369                           memseg[i].addr,
370                           memseg[i].len/memseg[i].hugepage_sz, sz_str);
371         }
372 #else
373         int segment_number = 0;
374         //rte_memseg_walk(print_all_segments, &segment_number);
375         rte_memseg_contig_walk(print_segments, &segment_number);
376 #endif
377 }
378
379 void cmd_dump(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets, struct input *input, int rx, int tx)
380 {
381         plog_info("dump %u %u %u\n", lcore_id, task_id, nb_packets);
382         if (lcore_id > RTE_MAX_LCORE) {
383                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
384         }
385         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
386                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
387         }
388         else {
389                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
390
391                 lconf->tasks_all[task_id]->aux->task_rt_dump.input = input;
392
393                 if (wait_command_handled(lconf) == -1) return;
394                 if (rx && tx)
395                         lconf->msg.type = LCONF_MSG_DUMP;
396                 else if (rx)
397                         lconf->msg.type = LCONF_MSG_DUMP_RX;
398                 else if (tx)
399                         lconf->msg.type = LCONF_MSG_DUMP_TX;
400
401                 if (rx || tx) {
402                         lconf->msg.task_id = task_id;
403                         lconf->msg.val  = nb_packets;
404                         lconf_set_req(lconf);
405                 }
406
407                 if (lconf->n_tasks_run == 0) {
408                         lconf_do_flags(lconf);
409                 }
410         }
411 }
412
413 void cmd_trace(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets)
414 {
415         plog_info("trace %u %u %u\n", lcore_id, task_id, nb_packets);
416         if (lcore_id > RTE_MAX_LCORE) {
417                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
418         }
419         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
420                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
421         }
422         else {
423                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
424
425                 if (wait_command_handled(lconf) == -1) return;
426
427                 lconf->msg.type = LCONF_MSG_TRACE;
428                 lconf->msg.task_id = task_id;
429                 lconf->msg.val  = nb_packets;
430                 lconf_set_req(lconf);
431
432                 if (lconf->n_tasks_run == 0) {
433                         lconf_do_flags(lconf);
434                 }
435         }
436 }
437
438 void cmd_rx_bw_start(uint32_t lcore_id)
439 {
440         if (lcore_id > RTE_MAX_LCORE) {
441                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
442         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE) {
443                 plog_warn("rx bandwidt already on core %u\n", lcore_id);
444         } else {
445
446                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
447
448                 if (wait_command_handled(lconf) == -1) return;
449                 lconf->msg.type = LCONF_MSG_RX_BW_START;
450                 lconf_set_req(lconf);
451
452                 if (lconf->n_tasks_run == 0) {
453                         lconf_do_flags(lconf);
454                 }
455         }
456 }
457
458 void cmd_tx_bw_start(uint32_t lcore_id)
459 {
460         if (lcore_id > RTE_MAX_LCORE) {
461                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
462         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE) {
463                 plog_warn("tx bandwidth already running on core %u\n", lcore_id);
464         } else {
465
466                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
467
468                 if (wait_command_handled(lconf) == -1) return;
469                 lconf->msg.type = LCONF_MSG_TX_BW_START;
470                 lconf_set_req(lconf);
471
472                 if (lconf->n_tasks_run == 0) {
473                         lconf_do_flags(lconf);
474                 }
475         }
476 }
477
478 void cmd_rx_bw_stop(uint32_t lcore_id)
479 {
480         if (lcore_id > RTE_MAX_LCORE) {
481                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
482         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE)) {
483                 plog_warn("rx bandwidth not running on core %u\n", lcore_id);
484         } else {
485
486                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
487
488                 if (wait_command_handled(lconf) == -1) return;
489                 lconf->msg.type = LCONF_MSG_RX_BW_STOP;
490                 lconf_set_req(lconf);
491
492                 if (lconf->n_tasks_run == 0) {
493                         lconf_do_flags(lconf);
494                 }
495         }
496 }
497
498 void cmd_tx_bw_stop(uint32_t lcore_id)
499 {
500         if (lcore_id > RTE_MAX_LCORE) {
501                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
502         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE)) {
503                 plog_warn("tx bandwidth not running on core %u\n", lcore_id);
504         } else {
505
506                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
507
508                 if (wait_command_handled(lconf) == -1) return;
509                 lconf->msg.type = LCONF_MSG_TX_BW_STOP;
510                 lconf_set_req(lconf);
511
512                 if (lconf->n_tasks_run == 0) {
513                         lconf_do_flags(lconf);
514                 }
515         }
516 }
517 void cmd_rx_distr_start(uint32_t lcore_id)
518 {
519         if (lcore_id > RTE_MAX_LCORE) {
520                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
521         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) {
522                 plog_warn("rx distribution already xrunning on core %u\n", lcore_id);
523         } else {
524                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
525
526                 if (wait_command_handled(lconf) == -1) return;
527                 lconf->msg.type = LCONF_MSG_RX_DISTR_START;
528                 lconf_set_req(lconf);
529
530                 if (lconf->n_tasks_run == 0) {
531                         lconf_do_flags(lconf);
532                 }
533         }
534 }
535
536 void cmd_tx_distr_start(uint32_t lcore_id)
537 {
538         if (lcore_id > RTE_MAX_LCORE) {
539                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
540         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) {
541                 plog_warn("tx distribution already xrunning on core %u\n", lcore_id);
542         } else {
543                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
544
545                 if (wait_command_handled(lconf) == -1) return;
546                 lconf->msg.type = LCONF_MSG_TX_DISTR_START;
547                 lconf_set_req(lconf);
548
549                 if (lconf->n_tasks_run == 0) {
550                         lconf_do_flags(lconf);
551                 }
552         }
553 }
554
555 void cmd_rx_distr_stop(uint32_t lcore_id)
556 {
557         if (lcore_id > RTE_MAX_LCORE) {
558                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
559         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) == 0) {
560                 plog_warn("rx distribution not running on core %u\n", lcore_id);
561         } else {
562                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
563
564                 if (wait_command_handled(lconf) == -1) return;
565                 lconf->msg.type = LCONF_MSG_RX_DISTR_STOP;
566                 lconf_set_req(lconf);
567
568                 if (lconf->n_tasks_run == 0) {
569                         lconf_do_flags(lconf);
570                 }
571         }
572 }
573
574 void cmd_tx_distr_stop(uint32_t lcore_id)
575 {
576         if (lcore_id > RTE_MAX_LCORE) {
577                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
578         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) == 0) {
579                 plog_warn("tx distribution not running on core %u\n", lcore_id);
580         } else {
581                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
582
583                 if (wait_command_handled(lconf) == -1) return;
584                 lconf->msg.type = LCONF_MSG_TX_DISTR_STOP;
585                 lconf_set_req(lconf);
586
587                 if (lconf->n_tasks_run == 0) {
588                         lconf_do_flags(lconf);
589                 }
590         }
591 }
592
593 void cmd_rx_distr_rst(uint32_t lcore_id)
594 {
595         if (lcore_id > RTE_MAX_LCORE) {
596                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
597         } else {
598                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
599
600                 if (wait_command_handled(lconf) == -1) return;
601                 lconf->msg.type = LCONF_MSG_RX_DISTR_RESET;
602                 lconf_set_req(lconf);
603
604                 if (lconf->n_tasks_run == 0) {
605                         lconf_do_flags(lconf);
606                 }
607         }
608 }
609
610 void cmd_tx_distr_rst(uint32_t lcore_id)
611 {
612         if (lcore_id > RTE_MAX_LCORE) {
613                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
614         } else {
615                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
616
617                 if (wait_command_handled(lconf) == -1) return;
618                 lconf->msg.type = LCONF_MSG_TX_DISTR_RESET;
619                 lconf_set_req(lconf);
620
621                 if (lconf->n_tasks_run == 0) {
622                         lconf_do_flags(lconf);
623                 }
624         }
625 }
626
627 void cmd_rx_distr_show(uint32_t lcore_id)
628 {
629         if (lcore_id > RTE_MAX_LCORE) {
630                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
631         } else {
632                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
633                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
634                         plog_info("t[%u]: ", i);
635                         for (uint32_t j = 0; j < sizeof(t->aux->rx_bucket)/sizeof(t->aux->rx_bucket[0]); ++j) {
636                                 plog_info("%u ", t->aux->rx_bucket[j]);
637                         }
638                         plog_info("\n");
639                 }
640         }
641 }
642 void cmd_tx_distr_show(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 {
647                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
648                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
649                         uint64_t tot = 0, avg = 0;
650                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
651                                 tot += t->aux->tx_bucket[j];
652                                 avg += j * t->aux->tx_bucket[j];
653                         }
654                         if (tot) {
655                                 avg = avg / tot;
656                         }
657                         plog_info("t[%u]: %lu: ", i, avg);
658                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
659                                 plog_info("%u ", t->aux->tx_bucket[j]);
660                         }
661                         plog_info("\n");
662                 }
663         }
664 }
665
666 void cmd_ringinfo_all(void)
667 {
668         struct lcore_cfg *lconf;
669         uint32_t lcore_id = -1;
670
671         while(prox_core_next(&lcore_id, 0) == 0) {
672                 lconf = &lcore_cfg[lcore_id];
673                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
674                         cmd_ringinfo(lcore_id, task_id);
675                 }
676         }
677 }
678
679 void cmd_ringinfo(uint8_t lcore_id, uint8_t task_id)
680 {
681         struct lcore_cfg *lconf;
682         struct rte_ring *ring;
683         struct task_args* targ;
684         uint32_t count;
685
686         if (!prox_core_active(lcore_id, 0)) {
687                 plog_info("lcore %u is not active\n", lcore_id);
688                 return;
689         }
690         lconf = &lcore_cfg[lcore_id];
691         if (task_id >= lconf->n_tasks_all) {
692                 plog_warn("Invalid task index %u: lcore %u has %u tasks\n", task_id, lcore_id, lconf->n_tasks_all);
693                 return;
694         }
695
696         targ = &lconf->targs[task_id];
697         plog_info("Core %u task %u: %u rings\n", lcore_id, task_id, targ->nb_rxrings);
698         for (uint8_t i = 0; i < targ->nb_rxrings; ++i) {
699                 ring = targ->rx_rings[i];
700 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
701                 count = ring->prod.mask + 1;
702 #else
703                 count = ring->mask + 1;
704 #endif
705                 plog_info("\tRing %u:\n", i);
706                 plog_info("\t\tFlags: %s,%s\n", ring->flags & RING_F_SP_ENQ? "sp":"mp", ring->flags & RING_F_SC_DEQ? "sc":"mc");
707                 plog_info("\t\tMemory size: %zu bytes\n", rte_ring_get_memsize(count));
708                 plog_info("\t\tOccupied: %u/%u\n", rte_ring_count(ring), count);
709         }
710 }
711
712 void cmd_port_up(uint8_t port_id)
713 {
714         int err;
715
716         if (!port_is_active(port_id)) {
717                 return ;
718         }
719
720         if ((err = rte_eth_dev_set_link_up(port_id)) == 0) {
721                 plog_info("Bringing port %d up\n", port_id);
722         }
723         else {
724                 plog_warn("Failed to bring port %d up with error %d\n", port_id, err);
725         }
726 }
727
728 void cmd_port_down(uint8_t port_id)
729 {
730         int err;
731
732         if (!port_is_active(port_id)) {
733                 return ;
734         }
735
736         if ((err = rte_eth_dev_set_link_down(port_id)) == 0) {
737                 plog_info("Bringing port %d down\n", port_id);
738         }
739         else {
740                 plog_warn("Failed to bring port %d down with error %d\n", port_id, err);
741         }
742 }
743
744 void cmd_xstats(uint8_t port_id)
745 {
746 #if RTE_VERSION >= RTE_VERSION_NUM(16,7,0,0)
747         int n_xstats;
748         struct rte_eth_xstat *eth_xstat = NULL; // id and value
749         struct rte_eth_xstat_name *eth_xstat_name = NULL;       // only names
750         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
751         int rc;
752
753         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
754         eth_xstat_name = prox_zmalloc(n_xstats * sizeof(*eth_xstat_name), port_cfg->socket);
755         PROX_ASSERT(eth_xstat_name);
756         rc = rte_eth_xstats_get_names(port_id, eth_xstat_name, n_xstats);
757         if ((rc < 0) || (rc > n_xstats)) {
758                 if (rc < 0) {
759                         plog_warn("Failed to get xstats_names on port %d with error %d\n", port_id, rc);
760                 } else if (rc > n_xstats) {
761                         plog_warn("Failed to get xstats_names on port %d: too many xstats (%d)\n", port_id, rc);
762                 }
763         }
764
765         eth_xstat = prox_zmalloc(n_xstats * sizeof(*eth_xstat), port_cfg->socket);
766         PROX_ASSERT(eth_xstat);
767         rc = rte_eth_xstats_get(port_id, eth_xstat, n_xstats);
768         if ((rc < 0) || (rc > n_xstats)) {
769                 if (rc < 0) {
770                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
771                 } else if (rc > n_xstats) {
772                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
773                 }
774         } else {
775                 for (int i=0;i<rc;i++) {
776                         plog_info("%s: %ld\n", eth_xstat_name[i].name, eth_xstat[i].value);
777                 }
778         }
779         if (eth_xstat_name)
780                 prox_free(eth_xstat_name);
781         if (eth_xstat)
782                 prox_free(eth_xstat);
783 #else
784 #if RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0)
785         int n_xstats;
786         struct rte_eth_xstats *eth_xstats;
787         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
788         int rc;
789
790         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
791         eth_xstats = prox_zmalloc(n_xstats * sizeof(*eth_xstats), port_cfg->socket);
792         PROX_ASSERT(eth_xstats);
793         rc = rte_eth_xstats_get(port_id, eth_xstats, n_xstats);
794         if ((rc < 0) || (rc > n_xstats)) {
795                 if (rc < 0) {
796                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
797                 } else if (rc > n_xstats) {
798                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
799                 }
800         } else {
801                 for (int i=0;i<rc;i++) {
802                         plog_info("%s: %ld\n", eth_xstats[i].name, eth_xstats[i].value);
803                 }
804         }
805         if (eth_xstats)
806                 prox_free(eth_xstats);
807 #else
808         plog_warn("Failed to get xstats, xstats are not supported in this version of dpdk\n");
809 #endif
810 #endif
811 }
812
813 void cmd_portinfo(int port_id, char *dst, size_t max_len)
814 {
815         char *end = dst + max_len;
816
817         *dst = 0;
818         if (port_id == -1) {
819                 uint8_t max_port_idx = prox_last_port_active() + 1;
820
821                 for (uint8_t port_id = 0; port_id < max_port_idx; ++port_id) {
822                         if (!prox_port_cfg[port_id].active) {
823                                 continue;
824                         }
825                         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
826
827                         dst += snprintf(dst, end - dst,
828                                         "%2d:%10s; "MAC_BYTES_FMT"; %s\n",
829                                         port_id,
830                                         port_cfg->name,
831                                         MAC_BYTES(port_cfg->eth_addr.addr_bytes),
832                                         port_cfg->pci_addr);
833                 }
834                 return;
835         }
836
837         if (!port_is_active(port_id)) {
838                 return ;
839         }
840
841         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
842
843         dst += snprintf(dst, end - dst, "Port info for port %u\n", port_id);
844         dst += snprintf(dst, end - dst, "\tName: %s\n", port_cfg->name);
845         dst += snprintf(dst, end - dst, "\tDriver: %s\n", port_cfg->driver_name);
846         dst += snprintf(dst, end - dst, "\tMac address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes));
847         dst += snprintf(dst, end - dst, "\tLink speed: %u Mbps\n", port_cfg->link_speed);
848         dst += snprintf(dst, end - dst, "\tLink max speed: %u Mbps\n", port_cfg->max_link_speed);
849         dst += snprintf(dst, end - dst, "\tLink status: %s\n", port_cfg->link_up? "up" : "down");
850         dst += snprintf(dst, end - dst, "\tSocket: %u\n", port_cfg->socket);
851         dst += snprintf(dst, end - dst, "\tPCI address: %s\n", port_cfg->pci_addr);
852         dst += snprintf(dst, end - dst, "\tPromiscuous: %s\n", port_cfg->promiscuous? "yes" : "no");
853         dst += snprintf(dst, end - dst, "\tNumber of RX/TX descriptors: %u/%u\n", port_cfg->n_rxd, port_cfg->n_txd);
854         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);
855         dst += snprintf(dst, end - dst, "\tMemory pools:\n");
856
857         for (uint8_t i = 0; i < 32; ++i) {
858                 if (port_cfg->pool[i]) {
859                         dst += snprintf(dst, end - dst, "\t\tname: %s (%p)\n",
860                                         port_cfg->pool[i]->name, port_cfg->pool[i]);
861                 }
862         }
863 }
864
865 void cmd_read_reg(uint8_t port_id, unsigned int id)
866 {
867         unsigned int val, rc;
868         if (!port_is_active(port_id)) {
869                 return ;
870         }
871         rc = read_reg(port_id, id, &val);
872         if (rc) {
873                 plog_warn("Failed to read register %d on port %d\n", id, port_id);
874         }
875         else {
876                 plog_info("Register 0x%08X : %08X \n", id, val);
877         }
878 }
879
880 void cmd_reset_port(uint8_t portid)
881 {
882         unsigned int rc;
883         if (!prox_port_cfg[portid].active) {
884                 plog_info("port not active \n");
885                 return;
886         }
887         rte_eth_dev_stop(portid);
888         rc = rte_eth_dev_start(portid);
889         if (rc) {
890                 plog_warn("Failed to restart port %d\n", portid);
891         }
892 }
893 void cmd_write_reg(uint8_t port_id, unsigned int id, unsigned int val)
894 {
895         if (!port_is_active(port_id)) {
896                 return ;
897         }
898
899         plog_info("writing 0x%08X %08X\n", id, val);
900         write_reg(port_id, id, val);
901 }
902
903 void cmd_set_vlan_offload(uint8_t port_id, unsigned int val)
904 {
905         if (!port_is_active(port_id)) {
906                 return ;
907         }
908
909         plog_info("setting vlan offload to %d\n", val);
910         if (val & ~(ETH_VLAN_STRIP_OFFLOAD | ETH_VLAN_FILTER_OFFLOAD | ETH_VLAN_EXTEND_OFFLOAD)) {
911                 plog_info("wrong vlan offload value\n");
912         }
913         int ret = rte_eth_dev_set_vlan_offload(port_id, val);
914         plog_info("rte_eth_dev_set_vlan_offload return %d\n", ret);
915 }
916
917 void cmd_set_vlan_filter(uint8_t port_id, unsigned int id, unsigned int val)
918 {
919         if (!port_is_active(port_id)) {
920                 return ;
921         }
922
923         plog_info("setting vln filter for vlan %d to %d\n", id, val);
924         int ret = rte_eth_dev_vlan_filter(port_id, id, val);
925         plog_info("rte_eth_dev_vlan_filter return %d\n", ret);
926 }
927
928 void cmd_thread_info(uint8_t lcore_id, uint8_t task_id)
929 {
930         plog_info("thread_info %u %u \n", lcore_id, task_id);
931         if (lcore_id > RTE_MAX_LCORE) {
932                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
933         }
934         if (!prox_core_active(lcore_id, 0)) {
935                 plog_warn("lcore %u is not active\n", lcore_id);
936                 return;
937         }
938         if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
939                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
940                 return;
941         }
942         if (strcmp(lcore_cfg[lcore_id].targs[task_id].task_init->mode_str, "qos") == 0) {
943                 struct task_base *task;
944
945                 task = lcore_cfg[lcore_id].tasks_all[task_id];
946                 plog_info("core %d, task %d: %d mbufs stored in QoS\n", lcore_id, task_id,
947                           task_qos_n_pkts_buffered(task));
948
949 #ifdef ENABLE_EXTRA_USER_STATISTICS
950         }
951         else if (lcore_cfg[lcore_id].targs[task_id].mode == QINQ_ENCAP4) {
952                 struct task_qinq_encap4 *task;
953                 task = (struct task_qinq_encap4 *)(lcore_cfg[lcore_id].tasks_all[task_id]);
954                 for (int i=0;i<task->n_users;i++) {
955                         if (task->stats_per_user[i])
956                                 plog_info("User %d: %d packets\n", i, task->stats_per_user[i]);
957                 }
958 #endif
959         }
960         else {
961                 // Only QoS thread info so far
962                 plog_err("core %d, task %d: not a qos core (%p)\n", lcore_id, task_id, lcore_cfg[lcore_id].thread_x);
963         }
964 }
965
966 void cmd_rx_tx_info(void)
967 {
968         uint32_t lcore_id = -1;
969         while(prox_core_next(&lcore_id, 0) == 0) {
970                 for (uint8_t task_id = 0; task_id < lcore_cfg[lcore_id].n_tasks_all; ++task_id) {
971                         struct task_args *targ = &lcore_cfg[lcore_id].targs[task_id];
972
973                         plog_info("Core %u:", lcore_id);
974                         if (targ->rx_port_queue[0].port != OUT_DISCARD) {
975                                 for (int i = 0; i < targ->nb_rxports; i++) {
976                                         plog_info(" RX port %u (queue %u)", targ->rx_port_queue[i].port, targ->rx_port_queue[i].queue);
977                                 }
978                         }
979                         else {
980                                 for (uint8_t j = 0; j < targ->nb_rxrings; ++j) {
981                                         plog_info(" RX ring[%u,%u] %p", task_id, j, targ->rx_rings[j]);
982                                 }
983                         }
984                         plog_info(" ==>");
985                         for (uint8_t j = 0; j < targ->nb_txports; ++j) {
986                                 plog_info(" TX port %u (queue %u)", targ->tx_port_queue[j].port,
987                                           targ->tx_port_queue[j].queue);
988                         }
989
990                         for (uint8_t j = 0; j < targ->nb_txrings; ++j) {
991                                 plog_info(" TX ring %p", targ->tx_rings[j]);
992                         }
993
994                         plog_info("\n");
995                 }
996         }
997 }
998 void cmd_get_cache_class(uint32_t lcore_id, uint32_t *set)
999 {
1000         uint64_t tmp_rmid = 0;
1001         cqm_assoc_read(lcore_id, &tmp_rmid);
1002         *set = (uint32_t)(tmp_rmid >> 32);
1003 }
1004
1005 void cmd_get_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t *val)
1006 {
1007         cat_get_class_mask(lcore_id, set, val);
1008 }
1009
1010 void cmd_set_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t val)
1011 {
1012         cat_set_class_mask(lcore_id, set, val);
1013         lcore_cfg[lcore_id].cache_set = set;
1014         uint32_t id = -1;
1015         while(prox_core_next(&id, 0) == 0) {
1016                 if ((lcore_cfg[id].cache_set == set) && (rte_lcore_to_socket_id(id) == rte_lcore_to_socket_id(lcore_id))) {
1017                         plog_info("Updating mask for core %d to %d\n", id, set);
1018                         stats_update_cache_mask(id, val);
1019                 }
1020         }
1021 }
1022
1023 void cmd_set_cache_class(uint32_t lcore_id, uint32_t set)
1024 {
1025         uint64_t tmp_rmid = 0;
1026         uint32_t val = 0;
1027         cqm_assoc_read(lcore_id, &tmp_rmid);
1028         cqm_assoc(lcore_id, (tmp_rmid & 0xffffffff) | ((set * 1L) << 32));
1029         cat_get_class_mask(lcore_id, set, &val);
1030         stats_update_cache_mask(lcore_id, val);
1031 }
1032
1033 void cmd_cache_reset(void)
1034 {
1035         uint8_t sockets[MAX_SOCKETS] = {0};
1036         uint8_t cores[MAX_SOCKETS] = {0};
1037         uint32_t mask = (1 << cat_get_num_ways()) - 1;
1038         uint32_t lcore_id = -1, socket_id;
1039         while(prox_core_next(&lcore_id, 0) == 0) {
1040                 cqm_assoc(lcore_id, 0);
1041                 socket_id = rte_lcore_to_socket_id(lcore_id);
1042                 if (socket_id < MAX_SOCKETS) {
1043                         sockets[socket_id] = 1;
1044                         cores[socket_id] = lcore_id;
1045                 }
1046                 stats_update_cache_mask(lcore_id, mask);
1047                 plog_info("Setting core %d to cache mask %x\n", lcore_id, mask);
1048                 lcore_cfg[lcore_id].cache_set = 0;
1049         }
1050         for (uint32_t s = 0; s < MAX_SOCKETS; s++) {
1051                 if (sockets[s])
1052                         cat_reset_cache(cores[s]);
1053         }
1054         stats_lcore_assoc_rmid();
1055 }
1056
1057 int bypass_task(uint32_t lcore_id, uint32_t task_id)
1058 {
1059         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
1060         struct task_args *targ, *starg, *dtarg;
1061         struct rte_ring *ring = NULL;
1062
1063         if (task_id >= lconf->n_tasks_all)
1064                 return -1;
1065
1066         targ = &lconf->targs[task_id];
1067         if (targ->nb_txrings == 1) {
1068                 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);
1069                 // Find source task
1070                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
1071                         starg = targ->prev_tasks[i];
1072                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
1073                                 for (unsigned int k = 0; k < targ->nb_rxrings; k++) {
1074                                         if (starg->tx_rings[j] == targ->rx_rings[k]) {
1075                                                 plog_info("bypassing ring %p and connecting it to %p\n", starg->tx_rings[j], targ->tx_rings[0]);
1076                                                 starg->tx_rings[j] = targ->tx_rings[0];
1077                                                 struct task_base *tbase = starg->tbase;
1078                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1079                                         }
1080                                 }
1081                         }
1082                 }
1083         } else {
1084                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1085                 return -1;
1086         }
1087
1088         return 0;
1089 }
1090
1091 int reconnect_task(uint32_t lcore_id, uint32_t task_id)
1092 {
1093         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
1094         struct task_args *targ, *starg, *dtarg = NULL;
1095         struct rte_ring *ring = NULL;
1096
1097         if (task_id >= lconf->n_tasks_all)
1098                 return -1;
1099
1100         targ = &lconf->targs[task_id];
1101         if (targ->nb_txrings == 1) {
1102                 // Find source task
1103                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
1104                         starg = targ->prev_tasks[i];
1105                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
1106                                 if (starg->tx_rings[j] == targ->tx_rings[0]) {
1107                                         if (targ->n_prev_tasks == targ->nb_rxrings) {
1108                                                 starg->tx_rings[j] = targ->rx_rings[i];
1109                                                 struct task_base *tbase = starg->tbase;
1110                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1111                                                 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);
1112                                         } else if (targ->nb_rxrings == 1) {
1113                                                 starg->tx_rings[j] = targ->rx_rings[0];
1114                                                 struct task_base *tbase = starg->tbase;
1115                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1116                                                 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);
1117                                         } else {
1118                                                 plog_err("Unexpected configuration: %d precedent tasks, %d rx rings\n", targ->n_prev_tasks, targ->nb_rxrings);
1119                                         }
1120                                 }
1121                         }
1122                 }
1123         } else {
1124                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1125                 return -1;
1126         }
1127
1128         return 0;
1129 }