vFW: Updating config and script files of vFW
[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
22 #include "prox_malloc.h"
23 #include "display.h"
24 #include "commands.h"
25 #include "log.h"
26 #include "run.h"
27 #include "lconf.h"
28 #include "hash_utils.h"
29 #include "prox_cfg.h"
30 #include "prox_port_cfg.h"
31 #include "defines.h"
32 #include "handle_qos.h"
33 #include "handle_qinq_encap4.h"
34 #include "quit.h"
35 #include "input.h"
36 #include "rw_reg.h"
37 #include "cqm.h"
38 #include "stats_core.h"
39
40 void start_core_all(int task_id)
41 {
42         uint32_t cores[RTE_MAX_LCORE];
43         uint32_t lcore_id;
44         char tmp[256];
45         int cnt = 0;
46
47         prox_core_to_str(tmp, sizeof(tmp), 0);
48         plog_info("Starting cores: %s\n", tmp);
49
50         lcore_id = -1;
51         while (prox_core_next(&lcore_id, 0) == 0) {
52                 cores[cnt++] = lcore_id;
53         }
54         start_cores(cores, cnt, task_id);
55 }
56
57 void stop_core_all(int task_id)
58 {
59         uint32_t cores[RTE_MAX_LCORE];
60         uint32_t lcore_id;
61         char tmp[256];
62         int cnt = 0;
63
64         prox_core_to_str(tmp, sizeof(tmp), 0);
65         plog_info("Stopping cores: %s\n", tmp);
66
67         lcore_id = -1;
68         while (prox_core_next(&lcore_id, 0) == 0) {
69                 cores[cnt++] = lcore_id;
70         }
71
72         stop_cores(cores, cnt, task_id);
73 }
74
75 static void warn_inactive_cores(uint32_t *cores, int count, const char *prefix)
76 {
77         for (int i = 0; i < count; ++i) {
78                 if (!prox_core_active(cores[i], 0)) {
79                         plog_warn("%s %u: core is not active\n", prefix, cores[i]);
80                 }
81         }
82 }
83
84 static inline int wait_command_handled(struct lcore_cfg *lconf)
85 {
86         uint64_t t1 = rte_rdtsc(), t2;
87         while (lconf_is_req(lconf)) {
88                 t2 = rte_rdtsc();
89                 if (t2 - t1 > 5 * rte_get_tsc_hz()) {
90                         // Failed to handle command ...
91                         for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
92                                 struct task_args *targs = &lconf->targs[task_id];
93                                 if (!(targs->flags & TASK_ARG_DROP)) {
94                                         plogx_err("Failed to handle command - task is in NO_DROP and might be stuck...\n");
95                                         return - 1;
96                                 }
97                         }
98                         plogx_err("Failed to handle command\n");
99                         return -1;
100                 }
101         }
102         return 0;
103 }
104 void start_cores(uint32_t *cores, int count, int task_id)
105 {
106         int n_started_cores = 0;
107         uint32_t started_cores[RTE_MAX_LCORE];
108
109         warn_inactive_cores(cores, count, "Can't start core");
110
111         for (int i = 0; i < count; ++i) {
112                 struct lcore_cfg *lconf = &lcore_cfg[cores[i]];
113
114                 if (lconf->n_tasks_run != lconf->n_tasks_all) {
115
116                         lconf->msg.type = LCONF_MSG_START;
117                         lconf->msg.task_id = task_id;
118                         lconf_set_req(lconf);
119                         if (task_id == -1)
120                                 plog_info("Starting core %u (all tasks)\n", cores[i]);
121                         else
122                                 plog_info("Starting core %u task %u\n", cores[i], task_id);
123                         started_cores[n_started_cores++] = cores[i];
124                         lconf->flags |= LCONF_FLAG_RUNNING;
125                         rte_eal_remote_launch(lconf_run, NULL, cores[i]);
126                 }
127                 else {
128                         plog_warn("Core %u is already running all its tasks\n", cores[i]);
129                 }
130         }
131
132         /* This function is blocking, so detect when each core has
133            consumed the message. */
134         for (int i = 0; i < n_started_cores; ++i) {
135                 struct lcore_cfg *lconf = &lcore_cfg[started_cores[i]];
136                 plog_info("Waiting for core %u to start...", started_cores[i]);
137                 if (wait_command_handled(lconf) == -1) return;
138                 plog_info(" OK\n");
139         }
140 }
141
142 void stop_cores(uint32_t *cores, int count, int task_id)
143 {
144         int n_stopped_cores = 0;
145         uint32_t stopped_cores[RTE_MAX_LCORE];
146         uint32_t c;
147
148         warn_inactive_cores(cores, count, "Can't stop core");
149
150         for (int i = 0; i < count; ++i) {
151                 struct lcore_cfg *lconf = &lcore_cfg[cores[i]];
152                 if (lconf->n_tasks_run) {
153                         if (wait_command_handled(lconf) == -1) return;
154
155                         lconf->msg.type = LCONF_MSG_STOP;
156                         lconf->msg.task_id = task_id;
157                         lconf_set_req(lconf);
158                         stopped_cores[n_stopped_cores++] = cores[i];
159                 }
160         }
161
162         for (int i = 0; i < n_stopped_cores; ++i) {
163                 c = stopped_cores[i];
164                 struct lcore_cfg *lconf = &lcore_cfg[c];
165                 if (wait_command_handled(lconf) == -1) return;
166
167                 if (lconf->n_tasks_run == 0) {
168                         plog_info("All tasks stopped on core %u, waiting for core to stop...", c);
169                         rte_eal_wait_lcore(c);
170                         plog_info(" OK\n");
171                         lconf->flags &= ~LCONF_FLAG_RUNNING;
172                 }
173                 else {
174                         plog_info("Stopped task %u on core %u\n", task_id, c);
175                 }
176         }
177 }
178
179 struct size_unit {
180         uint64_t val;
181         uint64_t frac;
182         char     unit[8];
183 };
184
185 static struct size_unit to_size_unit(uint64_t bytes)
186 {
187         struct size_unit ret;
188
189         if (bytes > 1 << 30) {
190                 ret.val = bytes >> 30;
191                 ret.frac = ((bytes - (ret.val << 30)) * 1000) / (1 << 30);
192                 strcpy(ret.unit, "GB");
193         }
194         else if (bytes > 1 << 20) {
195                 ret.val = bytes >> 20;
196                 ret.frac = ((bytes - (ret.val << 20)) * 1000) / (1 << 20);
197                 strcpy(ret.unit, "MB");
198         }
199         else if (bytes > 1 << 10) {
200                 ret.val = bytes >> 10;
201                 ret.frac = (bytes - (ret.val << 10)) * 1000 / (1 << 10);
202                 strcpy(ret.unit, "KB");
203         }
204         else {
205                 ret.val = bytes;
206                 ret.frac = 0;
207                 strcpy(ret.unit, "B");
208         }
209
210         return ret;
211 }
212
213 void cmd_mem_stats(void)
214 {
215         struct rte_malloc_socket_stats sock_stats;
216         uint64_t v;
217         struct size_unit su;
218
219         for (uint32_t i = 0; i < RTE_MAX_NUMA_NODES; ++i) {
220                 if (rte_malloc_get_socket_stats(i, &sock_stats) < 0 || sock_stats.heap_totalsz_bytes == 0)
221                         continue;
222
223                 plogx_info("Socket %u memory stats:\n", i);
224                 su = to_size_unit(sock_stats.heap_totalsz_bytes);
225                 plogx_info("\tHeap_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
226                 su = to_size_unit(sock_stats.heap_freesz_bytes);
227                 plogx_info("\tFree_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
228                 su = to_size_unit(sock_stats.heap_allocsz_bytes);
229                 plogx_info("\tAlloc_size: %zu.%03zu %s\n", su.val, su.frac, su.unit);
230                 su = to_size_unit(sock_stats.greatest_free_size);
231                 plogx_info("\tGreatest_free_size: %zu %s\n", su.val, su.unit);
232                 plogx_info("\tAlloc_count: %u\n", sock_stats.alloc_count);
233                 plogx_info("\tFree_count: %u\n", sock_stats.free_count);
234         }
235 }
236
237 void cmd_mem_layout(void)
238 {
239         const struct rte_memseg* memseg = rte_eal_get_physmem_layout();
240
241         plog_info("Memory layout:\n");
242         for (uint32_t i = 0; i < RTE_MAX_MEMSEG; i++) {
243                 if (memseg[i].addr == NULL)
244                         break;
245
246                 const char *sz_str;
247                 switch (memseg[i].hugepage_sz >> 20) {
248                 case 2:
249                         sz_str = "2MB";
250                         break;
251                 case 1024:
252                         sz_str = "1GB";
253                         break;
254                 default:
255                         sz_str = "??";
256                 }
257
258                 plog_info("Segment %u: [%#lx-%#lx] at %p using %zu pages of %s\n",
259                           i,
260                           memseg[i].phys_addr,
261                           memseg[i].phys_addr + memseg[i].len,
262                           memseg[i].addr,
263                           memseg[i].len/memseg[i].hugepage_sz, sz_str);
264         }
265 }
266
267 void cmd_dump(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets, struct input *input, int rx, int tx)
268 {
269         plog_info("dump %u %u %u\n", lcore_id, task_id, nb_packets);
270         if (lcore_id > RTE_MAX_LCORE) {
271                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
272         }
273         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
274                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
275         }
276         else {
277                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
278
279                 lconf->tasks_all[task_id]->aux->task_rt_dump.input = input;
280
281                 if (wait_command_handled(lconf) == -1) return;
282                 if (rx && tx)
283                         lconf->msg.type = LCONF_MSG_DUMP;
284                 else if (rx)
285                         lconf->msg.type = LCONF_MSG_DUMP_RX;
286                 else if (tx)
287                         lconf->msg.type = LCONF_MSG_DUMP_TX;
288
289                 if (rx || tx) {
290                         lconf->msg.task_id = task_id;
291                         lconf->msg.val  = nb_packets;
292                         lconf_set_req(lconf);
293                 }
294
295                 if (lconf->n_tasks_run == 0) {
296                         lconf_do_flags(lconf);
297                 }
298         }
299 }
300
301 void cmd_trace(uint8_t lcore_id, uint8_t task_id, uint32_t nb_packets)
302 {
303         plog_info("trace %u %u %u\n", lcore_id, task_id, nb_packets);
304         if (lcore_id > RTE_MAX_LCORE) {
305                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
306         }
307         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
308                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
309         }
310         else {
311                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
312
313                 if (wait_command_handled(lconf) == -1) return;
314
315                 lconf->msg.type = LCONF_MSG_TRACE;
316                 lconf->msg.task_id = task_id;
317                 lconf->msg.val  = nb_packets;
318                 lconf_set_req(lconf);
319
320                 if (lconf->n_tasks_run == 0) {
321                         lconf_do_flags(lconf);
322                 }
323         }
324 }
325
326 void cmd_rx_bw_start(uint32_t lcore_id)
327 {
328         if (lcore_id > RTE_MAX_LCORE) {
329                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
330         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE) {
331                 plog_warn("rx bandwidt already on core %u\n", lcore_id);
332         } else {
333
334                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
335
336                 if (wait_command_handled(lconf) == -1) return;
337                 lconf->msg.type = LCONF_MSG_RX_BW_START;
338                 lconf_set_req(lconf);
339
340                 if (lconf->n_tasks_run == 0) {
341                         lconf_do_flags(lconf);
342                 }
343         }
344 }
345
346 void cmd_tx_bw_start(uint32_t lcore_id)
347 {
348         if (lcore_id > RTE_MAX_LCORE) {
349                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
350         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE) {
351                 plog_warn("tx bandwidth already running on core %u\n", lcore_id);
352         } else {
353
354                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
355
356                 if (wait_command_handled(lconf) == -1) return;
357                 lconf->msg.type = LCONF_MSG_TX_BW_START;
358                 lconf_set_req(lconf);
359
360                 if (lconf->n_tasks_run == 0) {
361                         lconf_do_flags(lconf);
362                 }
363         }
364 }
365
366 void cmd_rx_bw_stop(uint32_t lcore_id)
367 {
368         if (lcore_id > RTE_MAX_LCORE) {
369                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
370         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_BW_ACTIVE)) {
371                 plog_warn("rx bandwidth not running on core %u\n", lcore_id);
372         } else {
373
374                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
375
376                 if (wait_command_handled(lconf) == -1) return;
377                 lconf->msg.type = LCONF_MSG_RX_BW_STOP;
378                 lconf_set_req(lconf);
379
380                 if (lconf->n_tasks_run == 0) {
381                         lconf_do_flags(lconf);
382                 }
383         }
384 }
385
386 void cmd_tx_bw_stop(uint32_t lcore_id)
387 {
388         if (lcore_id > RTE_MAX_LCORE) {
389                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
390         } else if (!(lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_BW_ACTIVE)) {
391                 plog_warn("tx bandwidth not running on core %u\n", lcore_id);
392         } else {
393
394                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
395
396                 if (wait_command_handled(lconf) == -1) return;
397                 lconf->msg.type = LCONF_MSG_TX_BW_STOP;
398                 lconf_set_req(lconf);
399
400                 if (lconf->n_tasks_run == 0) {
401                         lconf_do_flags(lconf);
402                 }
403         }
404 }
405 void cmd_rx_distr_start(uint32_t lcore_id)
406 {
407         if (lcore_id > RTE_MAX_LCORE) {
408                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
409         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) {
410                 plog_warn("rx distribution already xrunning on core %u\n", lcore_id);
411         } else {
412                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
413
414                 if (wait_command_handled(lconf) == -1) return;
415                 lconf->msg.type = LCONF_MSG_RX_DISTR_START;
416                 lconf_set_req(lconf);
417
418                 if (lconf->n_tasks_run == 0) {
419                         lconf_do_flags(lconf);
420                 }
421         }
422 }
423
424 void cmd_tx_distr_start(uint32_t lcore_id)
425 {
426         if (lcore_id > RTE_MAX_LCORE) {
427                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
428         } else if (lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) {
429                 plog_warn("tx distribution already xrunning on core %u\n", lcore_id);
430         } else {
431                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
432
433                 if (wait_command_handled(lconf) == -1) return;
434                 lconf->msg.type = LCONF_MSG_TX_DISTR_START;
435                 lconf_set_req(lconf);
436
437                 if (lconf->n_tasks_run == 0) {
438                         lconf_do_flags(lconf);
439                 }
440         }
441 }
442
443 void cmd_rx_distr_stop(uint32_t lcore_id)
444 {
445         if (lcore_id > RTE_MAX_LCORE) {
446                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
447         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_RX_DISTR_ACTIVE) == 0) {
448                 plog_warn("rx distribution not running on core %u\n", lcore_id);
449         } else {
450                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
451
452                 if (wait_command_handled(lconf) == -1) return;
453                 lconf->msg.type = LCONF_MSG_RX_DISTR_STOP;
454                 lconf_set_req(lconf);
455
456                 if (lconf->n_tasks_run == 0) {
457                         lconf_do_flags(lconf);
458                 }
459         }
460 }
461
462 void cmd_tx_distr_stop(uint32_t lcore_id)
463 {
464         if (lcore_id > RTE_MAX_LCORE) {
465                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
466         } else if ((lcore_cfg[lcore_id].flags & LCONF_FLAG_TX_DISTR_ACTIVE) == 0) {
467                 plog_warn("tx distribution not running on core %u\n", lcore_id);
468         } else {
469                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
470
471                 if (wait_command_handled(lconf) == -1) return;
472                 lconf->msg.type = LCONF_MSG_TX_DISTR_STOP;
473                 lconf_set_req(lconf);
474
475                 if (lconf->n_tasks_run == 0) {
476                         lconf_do_flags(lconf);
477                 }
478         }
479 }
480
481 void cmd_rx_distr_rst(uint32_t lcore_id)
482 {
483         if (lcore_id > RTE_MAX_LCORE) {
484                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
485         } else {
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_DISTR_RESET;
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_distr_rst(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 {
503                 struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
504
505                 if (wait_command_handled(lconf) == -1) return;
506                 lconf->msg.type = LCONF_MSG_TX_DISTR_RESET;
507                 lconf_set_req(lconf);
508
509                 if (lconf->n_tasks_run == 0) {
510                         lconf_do_flags(lconf);
511                 }
512         }
513 }
514
515 void cmd_rx_distr_show(uint32_t lcore_id)
516 {
517         if (lcore_id > RTE_MAX_LCORE) {
518                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
519         } else {
520                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
521                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
522                         plog_info("t[%u]: ", i);
523                         for (uint32_t j = 0; j < sizeof(t->aux->rx_bucket)/sizeof(t->aux->rx_bucket[0]); ++j) {
524                                 plog_info("%u ", t->aux->rx_bucket[j]);
525                         }
526                         plog_info("\n");
527                 }
528         }
529 }
530 void cmd_tx_distr_show(uint32_t lcore_id)
531 {
532         if (lcore_id > RTE_MAX_LCORE) {
533                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
534         } else {
535                 for (uint32_t i = 0; i < lcore_cfg[lcore_id].n_tasks_all; ++i) {
536                         struct task_base *t = lcore_cfg[lcore_id].tasks_all[i];
537                         uint64_t tot = 0, avg = 0;
538                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
539                                 tot += t->aux->tx_bucket[j];
540                                 avg += j * t->aux->tx_bucket[j];
541                         }
542                         if (tot) {
543                                 avg = avg / tot;
544                         }
545                         plog_info("t[%u]: %lu: ", i, avg);
546                         for (uint32_t j = 0; j < sizeof(t->aux->tx_bucket)/sizeof(t->aux->tx_bucket[0]); ++j) {
547                                 plog_info("%u ", t->aux->tx_bucket[j]);
548                         }
549                         plog_info("\n");
550                 }
551         }
552 }
553
554 void cmd_ringinfo_all(void)
555 {
556         struct lcore_cfg *lconf;
557         uint32_t lcore_id = -1;
558
559         while(prox_core_next(&lcore_id, 0) == 0) {
560                 lconf = &lcore_cfg[lcore_id];
561                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
562                         cmd_ringinfo(lcore_id, task_id);
563                 }
564         }
565 }
566
567 void cmd_ringinfo(uint8_t lcore_id, uint8_t task_id)
568 {
569         struct lcore_cfg *lconf;
570         struct rte_ring *ring;
571         struct task_args* targ;
572         uint32_t count;
573
574         if (!prox_core_active(lcore_id, 0)) {
575                 plog_info("lcore %u is not active\n", lcore_id);
576                 return;
577         }
578         lconf = &lcore_cfg[lcore_id];
579         if (task_id >= lconf->n_tasks_all) {
580                 plog_warn("Invalid task index %u: lcore %u has %u tasks\n", task_id, lcore_id, lconf->n_tasks_all);
581                 return;
582         }
583
584         targ = &lconf->targs[task_id];
585         plog_info("Core %u task %u: %u rings\n", lcore_id, task_id, targ->nb_rxrings);
586         for (uint8_t i = 0; i < targ->nb_rxrings; ++i) {
587                 ring = targ->rx_rings[i];
588 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
589                 count = ring->prod.mask + 1;
590 #else
591                 count = ring->mask + 1;
592 #endif
593                 plog_info("\tRing %u:\n", i);
594                 plog_info("\t\tFlags: %s,%s\n", ring->flags & RING_F_SP_ENQ? "sp":"mp", ring->flags & RING_F_SC_DEQ? "sc":"mc");
595                 plog_info("\t\tMemory size: %zu bytes\n", rte_ring_get_memsize(count));
596                 plog_info("\t\tOccupied: %u/%u\n", rte_ring_count(ring), count);
597         }
598 }
599
600 void cmd_port_up(uint8_t port_id)
601 {
602         int err;
603
604         if (!port_is_active(port_id)) {
605                 return ;
606         }
607
608         if ((err = rte_eth_dev_set_link_up(port_id)) == 0) {
609                 plog_info("Bringing port %d up\n", port_id);
610         }
611         else {
612                 plog_warn("Failed to bring port %d up with error %d\n", port_id, err);
613         }
614 }
615
616 void cmd_port_down(uint8_t port_id)
617 {
618         int err;
619
620         if (!port_is_active(port_id)) {
621                 return ;
622         }
623
624         if ((err = rte_eth_dev_set_link_down(port_id)) == 0) {
625                 plog_info("Bringing port %d down\n", port_id);
626         }
627         else {
628                 plog_warn("Failed to bring port %d down with error %d\n", port_id, err);
629         }
630 }
631
632 void cmd_xstats(uint8_t port_id)
633 {
634 #if RTE_VERSION >= RTE_VERSION_NUM(16,7,0,0)
635         int n_xstats;
636         struct rte_eth_xstat *eth_xstat = NULL; // id and value
637         struct rte_eth_xstat_name *eth_xstat_name = NULL;       // only names
638         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
639         int rc;
640
641         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
642         eth_xstat_name = prox_zmalloc(n_xstats * sizeof(*eth_xstat_name), port_cfg->socket);
643         PROX_ASSERT(eth_xstat_name);
644         rc = rte_eth_xstats_get_names(port_id, eth_xstat_name, n_xstats);
645         if ((rc < 0) || (rc > n_xstats)) {
646                 if (rc < 0) {
647                         plog_warn("Failed to get xstats_names on port %d with error %d\n", port_id, rc);
648                 } else if (rc > n_xstats) {
649                         plog_warn("Failed to get xstats_names on port %d: too many xstats (%d)\n", port_id, rc);
650                 }
651         }
652
653         eth_xstat = prox_zmalloc(n_xstats * sizeof(*eth_xstat), port_cfg->socket);
654         PROX_ASSERT(eth_xstat);
655         rc = rte_eth_xstats_get(port_id, eth_xstat, n_xstats);
656         if ((rc < 0) || (rc > n_xstats)) {
657                 if (rc < 0) {
658                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
659                 } else if (rc > n_xstats) {
660                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
661                 }
662         } else {
663                 for (int i=0;i<rc;i++) {
664                         plog_info("%s: %ld\n", eth_xstat_name[i].name, eth_xstat[i].value);
665                 }
666         }
667         if (eth_xstat_name)
668                 prox_free(eth_xstat_name);
669         if (eth_xstat)
670                 prox_free(eth_xstat);
671 #else
672 #if RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0)
673         int n_xstats;
674         struct rte_eth_xstats *eth_xstats;
675         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
676         int rc;
677
678         n_xstats = rte_eth_xstats_get(port_id, NULL, 0);
679         eth_xstats = prox_zmalloc(n_xstats * sizeof(*eth_xstats), port_cfg->socket);
680         PROX_ASSERT(eth_xstats);
681         rc = rte_eth_xstats_get(port_id, eth_xstats, n_xstats);
682         if ((rc < 0) || (rc > n_xstats)) {
683                 if (rc < 0) {
684                         plog_warn("Failed to get xstats on port %d with error %d\n", port_id, rc);
685                 } else if (rc > n_xstats) {
686                         plog_warn("Failed to get xstats on port %d: too many xstats (%d)\n", port_id, rc);
687                 }
688         } else {
689                 for (int i=0;i<rc;i++) {
690                         plog_info("%s: %ld\n", eth_xstats[i].name, eth_xstats[i].value);
691                 }
692         }
693         if (eth_xstats)
694                 prox_free(eth_xstats);
695 #else
696         plog_warn("Failed to get xstats, xstats are not supported in this version of dpdk\n");
697 #endif
698 #endif
699 }
700
701 void cmd_portinfo(int port_id, char *dst, size_t max_len)
702 {
703         char *end = dst + max_len;
704
705         *dst = 0;
706         if (port_id == -1) {
707                 uint8_t max_port_idx = prox_last_port_active() + 1;
708
709                 for (uint8_t port_id = 0; port_id < max_port_idx; ++port_id) {
710                         if (!prox_port_cfg[port_id].active) {
711                                 continue;
712                         }
713                         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
714
715                         dst += snprintf(dst, end - dst,
716                                         "%2d:%10s; "MAC_BYTES_FMT"; %s\n",
717                                         port_id,
718                                         port_cfg->name,
719                                         MAC_BYTES(port_cfg->eth_addr.addr_bytes),
720                                         port_cfg->pci_addr);
721                 }
722                 return;
723         }
724
725         if (!port_is_active(port_id)) {
726                 return ;
727         }
728
729         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
730
731         dst += snprintf(dst, end - dst, "Port info for port %u\n", port_id);
732         dst += snprintf(dst, end - dst, "\tName: %s\n", port_cfg->name);
733         dst += snprintf(dst, end - dst, "\tDriver: %s\n", port_cfg->driver_name);
734         dst += snprintf(dst, end - dst, "\tMac address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes));
735         dst += snprintf(dst, end - dst, "\tLink speed: %u Mbps\n", port_cfg->link_speed);
736         dst += snprintf(dst, end - dst, "\tLink status: %s\n", port_cfg->link_up? "up" : "down");
737         dst += snprintf(dst, end - dst, "\tSocket: %u\n", port_cfg->socket);
738         dst += snprintf(dst, end - dst, "\tPCI address: %s\n", port_cfg->pci_addr);
739         dst += snprintf(dst, end - dst, "\tPromiscuous: %s\n", port_cfg->promiscuous? "yes" : "no");
740         dst += snprintf(dst, end - dst, "\tNumber of RX/TX descriptors: %u/%u\n", port_cfg->n_rxd, port_cfg->n_txd);
741         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);
742         dst += snprintf(dst, end - dst, "\tMemory pools:\n");
743
744         for (uint8_t i = 0; i < 32; ++i) {
745                 if (port_cfg->pool[i]) {
746                         dst += snprintf(dst, end - dst, "\t\tname: %s (%p)\n",
747                                         port_cfg->pool[i]->name, port_cfg->pool[i]);
748                 }
749         }
750 }
751
752 void cmd_read_reg(uint8_t port_id, unsigned int id)
753 {
754         unsigned int val, rc;
755         if (!port_is_active(port_id)) {
756                 return ;
757         }
758         rc = read_reg(port_id, id, &val);
759         if (rc) {
760                 plog_warn("Failed to read register %d on port %d\n", id, port_id);
761         }
762         else {
763                 plog_info("Register 0x%08X : %08X \n", id, val);
764         }
765 }
766
767 void cmd_reset_port(uint8_t portid)
768 {
769         unsigned int rc;
770         if (!prox_port_cfg[portid].active) {
771                 plog_info("port not active \n");
772                 return;
773         }
774         rte_eth_dev_stop(portid);
775         rc = rte_eth_dev_start(portid);
776         if (rc) {
777                 plog_warn("Failed to restart port %d\n", portid);
778         }
779 }
780 void cmd_write_reg(uint8_t port_id, unsigned int id, unsigned int val)
781 {
782         if (!port_is_active(port_id)) {
783                 return ;
784         }
785
786         plog_info("writing 0x%08X %08X\n", id, val);
787         write_reg(port_id, id, val);
788 }
789
790 void cmd_set_vlan_offload(uint8_t port_id, unsigned int val)
791 {
792         if (!port_is_active(port_id)) {
793                 return ;
794         }
795
796         plog_info("setting vlan offload to %d\n", val);
797         if (val & ~(ETH_VLAN_STRIP_OFFLOAD | ETH_VLAN_FILTER_OFFLOAD | ETH_VLAN_EXTEND_OFFLOAD)) {
798                 plog_info("wrong vlan offload value\n");
799         }
800         int ret = rte_eth_dev_set_vlan_offload(port_id, val);
801         plog_info("rte_eth_dev_set_vlan_offload return %d\n", ret);
802 }
803
804 void cmd_set_vlan_filter(uint8_t port_id, unsigned int id, unsigned int val)
805 {
806         if (!port_is_active(port_id)) {
807                 return ;
808         }
809
810         plog_info("setting vln filter for vlan %d to %d\n", id, val);
811         int ret = rte_eth_dev_vlan_filter(port_id, id, val);
812         plog_info("rte_eth_dev_vlan_filter return %d\n", ret);
813 }
814
815 void cmd_thread_info(uint8_t lcore_id, uint8_t task_id)
816 {
817         plog_info("thread_info %u %u \n", lcore_id, task_id);
818         if (lcore_id > RTE_MAX_LCORE) {
819                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
820         }
821         if (!prox_core_active(lcore_id, 0)) {
822                 plog_warn("lcore %u is not active\n", lcore_id);
823                 return;
824         }
825         if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
826                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcore_id].n_tasks_all - 1);
827                 return;
828         }
829         if (strcmp(lcore_cfg[lcore_id].targs[task_id].task_init->mode_str, "qos") == 0) {
830                 struct task_base *task;
831
832                 task = lcore_cfg[lcore_id].tasks_all[task_id];
833                 plog_info("core %d, task %d: %d mbufs stored in QoS\n", lcore_id, task_id,
834                           task_qos_n_pkts_buffered(task));
835
836 #ifdef ENABLE_EXTRA_USER_STATISTICS
837         }
838         else if (lcore_cfg[lcore_id].targs[task_id].mode == QINQ_ENCAP4) {
839                 struct task_qinq_encap4 *task;
840                 task = (struct task_qinq_encap4 *)(lcore_cfg[lcore_id].tasks_all[task_id]);
841                 for (int i=0;i<task->n_users;i++) {
842                         if (task->stats_per_user[i])
843                                 plog_info("User %d: %d packets\n", i, task->stats_per_user[i]);
844                 }
845 #endif
846         }
847         else {
848                 // Only QoS thread info so far
849                 plog_err("core %d, task %d: not a qos core (%p)\n", lcore_id, task_id, lcore_cfg[lcore_id].thread_x);
850         }
851 }
852
853 void cmd_rx_tx_info(void)
854 {
855         uint32_t lcore_id = -1;
856         while(prox_core_next(&lcore_id, 0) == 0) {
857                 for (uint8_t task_id = 0; task_id < lcore_cfg[lcore_id].n_tasks_all; ++task_id) {
858                         struct task_args *targ = &lcore_cfg[lcore_id].targs[task_id];
859
860                         plog_info("Core %u:", lcore_id);
861                         if (targ->rx_port_queue[0].port != OUT_DISCARD) {
862                                 for (int i = 0; i < targ->nb_rxports; i++) {
863                                         plog_info(" RX port %u (queue %u)", targ->rx_port_queue[i].port, targ->rx_port_queue[i].queue);
864                                 }
865                         }
866                         else {
867                                 for (uint8_t j = 0; j < targ->nb_rxrings; ++j) {
868                                         plog_info(" RX ring[%u,%u] %p", task_id, j, targ->rx_rings[j]);
869                                 }
870                         }
871                         plog_info(" ==>");
872                         for (uint8_t j = 0; j < targ->nb_txports; ++j) {
873                                 plog_info(" TX port %u (queue %u)", targ->tx_port_queue[j].port,
874                                           targ->tx_port_queue[j].queue);
875                         }
876
877                         for (uint8_t j = 0; j < targ->nb_txrings; ++j) {
878                                 plog_info(" TX ring %p", targ->tx_rings[j]);
879                         }
880
881                         plog_info("\n");
882                 }
883         }
884 }
885 void cmd_get_cache_class(uint32_t lcore_id, uint32_t *set)
886 {
887         uint64_t tmp_rmid = 0;
888         cqm_assoc_read(lcore_id, &tmp_rmid);
889         *set = (uint32_t)(tmp_rmid >> 32);
890 }
891
892 void cmd_get_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t *val)
893 {
894         cat_get_class_mask(lcore_id, set, val);
895 }
896
897 void cmd_set_cache_class_mask(uint32_t lcore_id, uint32_t set, uint32_t val)
898 {
899         cat_set_class_mask(lcore_id, set, val);
900         lcore_cfg[lcore_id].cache_set = set;
901         uint32_t id = -1;
902         while(prox_core_next(&id, 0) == 0) {
903                 if ((lcore_cfg[id].cache_set == set) && (rte_lcore_to_socket_id(id) == rte_lcore_to_socket_id(lcore_id))) {
904                         plog_info("Updating mask for core %d to %d\n", id, set);
905                         stats_update_cache_mask(id, val);
906                 }
907         }
908 }
909
910 void cmd_set_cache_class(uint32_t lcore_id, uint32_t set)
911 {
912         uint64_t tmp_rmid = 0;
913         uint32_t val = 0;
914         cqm_assoc_read(lcore_id, &tmp_rmid);
915         cqm_assoc(lcore_id, (tmp_rmid & 0xffffffff) | ((set * 1L) << 32));
916         cat_get_class_mask(lcore_id, set, &val);
917         stats_update_cache_mask(lcore_id, val);
918 }
919
920 void cmd_cache_reset(void)
921 {
922         uint8_t sockets[MAX_SOCKETS] = {0};
923         uint8_t cores[MAX_SOCKETS] = {0};
924         uint32_t mask = (1 << cat_get_num_ways()) - 1;
925         uint32_t lcore_id = -1, socket_id;
926         while(prox_core_next(&lcore_id, 0) == 0) {
927                 cqm_assoc(lcore_id, 0);
928                 socket_id = rte_lcore_to_socket_id(lcore_id);
929                 if (socket_id < MAX_SOCKETS) {
930                         sockets[socket_id] = 1;
931                         cores[socket_id] = lcore_id;
932                 }
933                 stats_update_cache_mask(lcore_id, mask);
934                 plog_info("Setting core %d to cache mask %x\n", lcore_id, mask);
935                 lcore_cfg[lcore_id].cache_set = 0;
936         }
937         for (uint32_t s = 0; s < MAX_SOCKETS; s++) {
938                 if (sockets[s])
939                         cat_reset_cache(cores[s]);
940         }
941         stats_lcore_assoc_rmid();
942 }
943
944 int bypass_task(uint32_t lcore_id, uint32_t task_id)
945 {
946         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
947         struct task_args *targ, *starg, *dtarg;
948         struct rte_ring *ring = NULL;
949
950         if (task_id >= lconf->n_tasks_all)
951                 return -1;
952
953         targ = &lconf->targs[task_id];
954         if (targ->nb_txrings == 1) {
955                 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);
956                 // Find source task
957                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
958                         starg = targ->prev_tasks[i];
959                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
960                                 for (unsigned int k = 0; k < targ->nb_rxrings; k++) {
961                                         if (starg->tx_rings[j] == targ->rx_rings[k]) {
962                                                 plog_info("bypassing ring %p and connecting it to %p\n", starg->tx_rings[j], targ->tx_rings[0]);
963                                                 starg->tx_rings[j] = targ->tx_rings[0];
964                                                 struct task_base *tbase = starg->tbase;
965                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
966                                         }
967                                 }
968                         }
969                 }
970         } else {
971                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
972                 return -1;
973         }
974
975         return 0;
976 }
977
978 int reconnect_task(uint32_t lcore_id, uint32_t task_id)
979 {
980         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
981         struct task_args *targ, *starg, *dtarg = NULL;
982         struct rte_ring *ring = NULL;
983
984         if (task_id >= lconf->n_tasks_all)
985                 return -1;
986
987         targ = &lconf->targs[task_id];
988         if (targ->nb_txrings == 1) {
989                 // Find source task
990                 for (unsigned int i = 0; i < targ->n_prev_tasks; i++) {
991                         starg = targ->prev_tasks[i];
992                         for (unsigned int j = 0; j < starg->nb_txrings; j++) {
993                                 if (starg->tx_rings[j] == targ->tx_rings[0]) {
994                                         if (targ->n_prev_tasks == targ->nb_rxrings) {
995                                                 starg->tx_rings[j] = targ->rx_rings[i];
996                                                 struct task_base *tbase = starg->tbase;
997                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
998                                                 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);
999                                         } else if (targ->nb_rxrings == 1) {
1000                                                 starg->tx_rings[j] = targ->rx_rings[0];
1001                                                 struct task_base *tbase = starg->tbase;
1002                                                 tbase->tx_params_sw.tx_rings[j] = starg->tx_rings[j];
1003                                                 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);
1004                                         } else {
1005                                                 plog_err("Unexpected configuration: %d precedent tasks, %d rx rings\n", targ->n_prev_tasks, targ->nb_rxrings);
1006                                         }
1007                                 }
1008                         }
1009                 }
1010         } else {
1011                 plog_info("Task has %d receive and %d transmit ring and cannot be bypassed\n", targ->nb_rxrings, targ->nb_txrings);
1012                 return -1;
1013         }
1014
1015         return 0;
1016 }