Simplify cores_task_are_valid()
[samplevnf.git] / VNFs / DPPD-PROX / cmd_parser.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 <stdio.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <rte_cycles.h>
21 #include <rte_version.h>
22
23 #include "input.h"
24 #include "cmd_parser.h"
25 #include "commands.h"
26 #include "run.h"
27 #include "display.h"
28 #include "log.h"
29 #include "prox_cfg.h"
30 #include "prox_port_cfg.h"
31 #include "task_base.h"
32 #include "lconf.h"
33 #include "main.h"
34 #include "parse_utils.h"
35 #include "stats_parser.h"
36 #include "stats_port.h"
37 #include "stats_latency.h"
38 #include "stats_global.h"
39 #include "stats_prio_task.h"
40
41 #include "handle_routing.h"
42 #include "handle_qinq_decap4.h"
43 #include "handle_lat.h"
44 #include "handle_arp.h"
45 #include "handle_gen.h"
46 #include "handle_acl.h"
47 #include "handle_irq.h"
48 #include "defines.h"
49 #include "prox_cfg.h"
50 #include "version.h"
51 #include "stats_latency.h"
52 #include "handle_cgnat.h"
53 #include "handle_impair.h"
54 #include "rx_pkt.h"
55
56 static int core_task_is_valid(int lcore_id, int task_id)
57 {
58         if (lcore_id >= RTE_MAX_LCORE) {
59                 plog_err("Invalid core id %u (lcore ID above %d)\n", lcore_id, RTE_MAX_LCORE);
60                 return 0;
61         }
62         else if (!prox_core_active(lcore_id, 0)) {
63                 plog_err("Invalid core id %u (lcore is not active)\n", lcore_id);
64                 return 0;
65         }
66         else if (task_id >= lcore_cfg[lcore_id].n_tasks_all) {
67                 plog_err("Invalid task id (valid task IDs for core %u are below %u)\n",
68                          lcore_id, lcore_cfg[lcore_id].n_tasks_all);
69                 return 0;
70         }
71         return 1;
72 }
73
74 static int cores_task_are_valid(unsigned int *lcores, int task_id, unsigned int nb_cores)
75 {
76         unsigned int lcore_id;
77         for (unsigned int i = 0; i < nb_cores; i++) {
78                 lcore_id = lcores[i];
79                 if (core_task_is_valid(lcore_id, task_id) == 0)
80                         return 0;
81         }
82         return 1;
83 }
84
85 static int parse_core_task(const char *str, uint32_t *lcore_id, uint32_t *task_id, unsigned int *nb_cores)
86 {
87         char str_lcore_id[128];
88         int ret;
89
90         if (2 != sscanf(str, "%s %u", str_lcore_id, task_id))
91                 return -1;
92
93         if ((ret = parse_list_set(lcore_id, str_lcore_id, RTE_MAX_LCORE)) <= 0) {
94                 plog_err("Invalid core while parsing command (%s)\n", get_parse_err());
95                 return -1;
96         }
97         *nb_cores = ret;
98
99         return 0;
100 }
101
102 static const char *strchr_skip_twice(const char *str, int chr)
103 {
104         str = strchr(str, chr);
105         if (!str)
106                 return NULL;
107         str = str + 1;
108
109         str = strchr(str, chr);
110         if (!str)
111                 return NULL;
112         return str + 1;
113 }
114
115 static int parse_cmd_quit(const char *str, struct input *input)
116 {
117         if (strcmp(str, "") != 0) {
118                 return -1;
119         }
120
121         quit();
122         return 0;
123 }
124
125 static int parse_cmd_quit_force(const char *str, struct input *input)
126 {
127         if (strcmp(str, "") != 0) {
128                 return -1;
129         }
130
131         abort();
132 }
133
134 static int parse_cmd_history(const char *str, struct input *input)
135 {
136         if (strcmp(str, "") != 0) {
137                 return -1;
138         }
139
140         if (input->history) {
141                 input->history(input);
142                 return 0;
143         }
144         plog_err("Invalid history comand ");
145         return -1;
146 }
147
148 static int parse_cmd_echo(const char *str, struct input *input)
149 {
150         if (strcmp(str, "") == 0) {
151                 return -1;
152         }
153
154         char resolved[2048];
155
156         if (parse_vars(resolved, sizeof(resolved), str)) {
157                 return 0;
158         }
159
160         if (input->reply) {
161                 if (strlen(resolved) + 2 < sizeof(resolved)) {
162                         resolved[strlen(resolved) + 1] = 0;
163                         resolved[strlen(resolved)] = '\n';
164                 }
165                 else
166                         return 0;
167
168                 input->reply(input, resolved, strlen(resolved));
169         } else
170                 plog_info("%s\n", resolved);
171
172         return 0;
173 }
174
175 static int parse_cmd_reset_stats(const char *str, struct input *input)
176 {
177         if (strcmp(str, "") != 0) {
178                 return -1;
179         }
180
181         stats_reset();
182         return 0;
183 }
184
185 static int parse_cmd_reset_lat_stats(const char *str, struct input *input)
186 {
187         if (strcmp(str, "") != 0) {
188                 return -1;
189         }
190
191         stats_latency_reset();
192         return 0;
193 }
194
195 static int parse_cmd_trace(const char *str, struct input *input)
196 {
197         unsigned lcores[RTE_MAX_LCORE], task_id, nb_packets, nb_cores;
198
199         if (parse_core_task(str, lcores, &task_id, &nb_cores))
200                 return -1;
201         if (!(str = strchr_skip_twice(str, ' ')))
202                 return -1;
203         if (sscanf(str, "%u", &nb_packets) != 1)
204                 return -1;
205
206         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
207                 for (unsigned int i = 0; i < nb_cores; i++) {
208                         cmd_trace(lcores[i], task_id, nb_packets);
209                 }
210         }
211         return 0;
212 }
213
214 static int parse_cmd_dump_rx(const char *str, struct input *input)
215 {
216         unsigned lcores[RTE_MAX_LCORE], task_id, nb_packets, nb_cores;
217
218         if (parse_core_task(str, lcores, &task_id, &nb_cores))
219                 return -1;
220         if (!(str = strchr_skip_twice(str, ' ')))
221                 return -1;
222         if (sscanf(str, "%u", &nb_packets) != 1) {
223                 return -1;
224         }
225
226         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
227                 for (unsigned int i = 0; i < nb_cores; i++) {
228                         if (lcores[i] > RTE_MAX_LCORE) {
229                                 plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE);
230                                 return -1;
231                         } else if (task_id >= lcore_cfg[lcores[i]].n_tasks_all) {
232                                 plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcores[i]].n_tasks_all - 1);
233                                 return -1;
234                         } else {
235                                 struct lcore_cfg *lconf = &lcore_cfg[lcores[i]];
236                                 struct task_base *tbase = lconf->tasks_all[task_id];
237                                 int prev_count = tbase->aux->rx_prev_count;
238                                 if (((prev_count) && (tbase->aux->rx_pkt_prev[prev_count - 1] == rx_pkt_dummy))
239                                         || (tbase->rx_pkt == rx_pkt_dummy)) {
240                                         plog_warn("Unable to dump_rx as rx_pkt_dummy\n");
241                                         return -1;
242                                 }
243                         }
244                         cmd_dump(lcores[i], task_id, nb_packets, input, 1, 0);
245                 }
246         }
247         return 0;
248 }
249
250 static int parse_cmd_pps_unit(const char *str, struct input *input)
251 {
252         uint32_t val;
253
254         if (sscanf(str, "%u", &val) != 1) {
255                 return -1;
256         }
257         display_set_pps_unit(val);
258         return 0;
259 }
260
261 static int parse_cmd_dump_tx(const char *str, struct input *input)
262 {
263         unsigned lcores[RTE_MAX_LCORE], task_id, nb_packets, nb_cores;
264
265         if (parse_core_task(str, lcores, &task_id, &nb_cores))
266                 return -1;
267         if (!(str = strchr_skip_twice(str, ' ')))
268                 return -1;
269         if (sscanf(str, "%u", &nb_packets) != 1) {
270                 return -1;
271         }
272
273         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
274                 for (unsigned int i = 0; i < nb_cores; i++) {
275                         cmd_dump(lcores[i], task_id, nb_packets, input, 0, 1);
276                 }
277         }
278         return 0;
279 }
280
281 static int parse_cmd_rate(const char *str, struct input *input)
282 {
283         unsigned queue, port, rate;
284
285         if (sscanf(str, "%u %u %u", &queue, &port, &rate) != 3) {
286                 return -1;
287         }
288
289         if (port > PROX_MAX_PORTS) {
290                 plog_err("Max port id allowed is %u (specified %u)\n", PROX_MAX_PORTS, port);
291         }
292         else if (!prox_port_cfg[port].active) {
293                 plog_err("Port %u not active\n", port);
294         }
295         else if (queue >= prox_port_cfg[port].n_txq) {
296                 plog_err("Number of active queues is %u\n",
297                          prox_port_cfg[port].n_txq);
298         }
299         else if (rate > prox_port_cfg[port].link_speed) {
300                 plog_err("Max rate allowed on port %u queue %u is %u Mbps\n",
301                          port, queue, prox_port_cfg[port].link_speed);
302         }
303         else {
304                 if (rate == 0) {
305                         plog_info("Disabling rate limiting on port %u queue %u\n",
306                                   port, queue);
307                 }
308                 else {
309                         plog_info("Setting rate limiting to %u Mbps on port %u queue %u\n",
310                                   rate, port, queue);
311                 }
312                 rte_eth_set_queue_rate_limit(port, queue, rate);
313         }
314         return 0;
315 }
316
317 int task_is_mode_and_submode(uint32_t lcore_id, uint32_t task_id, const char *mode, const char *sub_mode)
318 {
319         struct task_args *targs = &lcore_cfg[lcore_id].targs[task_id];
320
321         return !strcmp(targs->task_init->mode_str, mode) && !strcmp(targs->sub_mode_str, sub_mode);
322 }
323
324 int task_is_mode(uint32_t lcore_id, uint32_t task_id, const char *mode)
325 {
326         struct task_init *t = lcore_cfg[lcore_id].targs[task_id].task_init;
327
328         return !strcmp(t->mode_str, mode);
329 }
330
331 int task_is_sub_mode(uint32_t lcore_id, uint32_t task_id, const char *sub_mode)
332 {
333         struct task_args *targs = &lcore_cfg[lcore_id].targs[task_id];
334
335         return !strcmp(targs->sub_mode_str, sub_mode);
336 }
337
338 static void log_pkt_count(uint32_t count, uint32_t lcore_id, uint32_t task_id)
339 {
340         if (count == UINT32_MAX)
341                 plog_info("Core %u task %u will keep sending packets\n", lcore_id, task_id);
342         else if (count == 0)
343                 plog_info("Core %u task %u waits for next count command\n", lcore_id, task_id);
344         else
345                 plog_info("Core %u task %u stopping after %u packets\n", lcore_id, task_id, count);
346 }
347
348 static int parse_cmd_count(const char *str, struct input *input)
349 {
350         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, count, nb_cores;
351
352         if (parse_core_task(str, lcores, &task_id, &nb_cores))
353                 return -1;
354         if (!(str = strchr_skip_twice(str, ' ')))
355                 return -1;
356         if (sscanf(str, "%u", &count) != 1)
357                 return -1;
358
359         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
360                 for (unsigned int i = 0; i < nb_cores; i++) {
361                         lcore_id = lcores[i];
362                         if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
363                                 plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
364                         }
365                         else {
366                                 struct task_base *task = lcore_cfg[lcore_id].tasks_all[task_id];
367
368                                 log_pkt_count(count, lcore_id, task_id);
369                                 task_gen_set_pkt_count(task, count);
370                         }
371                 }
372         }
373         return 0;
374 }
375
376 static int parse_cmd_set_probability(const char *str, struct input *input)
377 {
378         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
379         float probability;
380
381         if (parse_core_task(str, lcores, &task_id, &nb_cores))
382                 return -1;
383         if (!(str = strchr_skip_twice(str, ' ')))
384                 return -1;
385         if (sscanf(str, "%f", &probability) != 1)
386                 return -1;
387
388         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
389                 for (unsigned int i = 0; i < nb_cores; i++) {
390                         lcore_id = lcores[i];
391                         if ((!task_is_mode_and_submode(lcore_id, task_id, "impair", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "impair", "l3"))){
392                                 plog_err("Core %u task %u is not impairing packets\n", lcore_id, task_id);
393                         } else {
394                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
395                                 task_impair_set_proba(tbase, probability);
396                         }
397                 }
398         }
399         return 0;
400 }
401
402 static int parse_cmd_delay_us(const char *str, struct input *input)
403 {
404         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, delay_us, nb_cores;
405
406         if (parse_core_task(str, lcores, &task_id, &nb_cores))
407                 return -1;
408         if (!(str = strchr_skip_twice(str, ' ')))
409                 return -1;
410         if (sscanf(str, "%d", &delay_us) != 1)
411                 return -1;
412
413         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
414                 for (unsigned int i = 0; i < nb_cores; i++) {
415                         lcore_id = lcores[i];
416                         if ((!task_is_mode_and_submode(lcore_id, task_id, "impair", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "impair", "l3"))){
417                                 plog_err("Core %u task %u is not impairing packets\n", lcore_id, task_id);
418                         } else {
419                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
420                                 task_impair_set_delay_us(tbase, delay_us, 0);
421                         }
422                 }
423         }
424         return 0;
425 }
426
427 static int parse_cmd_random_delay_us(const char *str, struct input *input)
428 {
429         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, delay_us, nb_cores;
430
431         if (parse_core_task(str, lcores, &task_id, &nb_cores))
432                 return -1;
433         if (!(str = strchr_skip_twice(str, ' ')))
434                 return -1;
435         if (sscanf(str, "%d", &delay_us) != 1)
436                 return -1;
437
438         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
439                 for (unsigned int i = 0; i < nb_cores; i++) {
440                         lcore_id = lcores[i];
441                         if ((!task_is_mode_and_submode(lcore_id, task_id, "impair", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "impair", "l3"))){
442                                 plog_err("Core %u task %u is not impairing packets\n", lcore_id, task_id);
443                         } else {
444                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
445                                 task_impair_set_delay_us(tbase, 0, delay_us);
446                         }
447                 }
448         }
449         return 0;
450 }
451
452 static int parse_cmd_bypass(const char *str, struct input *input)
453 {
454         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, pkt_size, nb_cores;
455
456         if (parse_core_task(str, lcores, &task_id, &nb_cores))
457                 return -1;
458         if ((prox_cfg.flags & DSF_ENABLE_BYPASS) == 0) {
459                 plog_err("enable bypass not set => command not supported\n");
460                 return -1;
461         }
462
463         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
464                 for (unsigned int i = 0; i < nb_cores; i++) {
465                         lcore_id = lcores[i];
466                         if (bypass_task(lcore_id, task_id) != 0)
467                                 return -1;
468                 }
469         }
470         return 0;
471 }
472
473 static int parse_cmd_reconnect(const char *str, struct input *input)
474 {
475         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, pkt_size, nb_cores;
476
477         if (parse_core_task(str, lcores, &task_id, &nb_cores))
478                 return -1;
479         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
480                 for (unsigned int i = 0; i < nb_cores; i++) {
481                         lcore_id = lcores[i];
482                         if (reconnect_task(lcore_id, task_id) != 0)
483                                 return -1;
484                 }
485         }
486         return 0;
487 }
488
489 static int parse_cmd_pkt_size(const char *str, struct input *input)
490 {
491         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, pkt_size, nb_cores;
492
493         if (parse_core_task(str, lcores, &task_id, &nb_cores))
494                 return -1;
495         if (!(str = strchr_skip_twice(str, ' ')))
496                 return -1;
497         if (sscanf(str, "%d", &pkt_size) != 1)
498                 return -1;
499
500         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
501                 for (unsigned int i = 0; i < nb_cores; i++) {
502                         lcore_id = lcores[i];
503                         if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
504                                 plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
505                         } else {
506                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
507                                 task_gen_set_pkt_size(tbase, pkt_size); /* error printed within function */
508                         }
509                 }
510         }
511         return 0;
512 }
513
514 static int parse_cmd_speed(const char *str, struct input *input)
515 {
516         unsigned lcores[RTE_MAX_LCORE], task_id, lcore_id, nb_cores;
517         float speed;
518         unsigned i;
519
520         if (parse_core_task(str, lcores, &task_id, &nb_cores))
521                 return -1;
522         if (!(str = strchr_skip_twice(str, ' ')))
523                 return -1;
524         if (sscanf(str, "%f", &speed) != 1) {
525                 return -1;
526         }
527
528         if (!cores_task_are_valid(lcores, task_id, nb_cores)) {
529                 return 0;
530         }
531
532         for (i = 0; i < nb_cores; i++) {
533                 lcore_id = lcores[i];
534                 if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
535                         plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
536                 }
537                 else if (speed > 1000.0f || speed < 0.0f) {     // Up to 100 Gbps
538                         plog_err("Speed out of range (must be betweeen 0%% and 1000%%)\n");
539                 }
540                 else {
541                         struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
542                         uint64_t bps = speed * 12500000;
543
544                         plog_info("Setting rate to %"PRIu64" Bps\n", bps);
545
546                         task_gen_set_rate(tbase, bps);
547                 }
548         }
549         return 0;
550 }
551
552 static int parse_cmd_speed_byte(const char *str, struct input *input)
553 {
554         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
555         uint64_t bps;
556
557         if (parse_core_task(str, lcores, &task_id, &nb_cores))
558                 return -1;
559         if (!(str = strchr_skip_twice(str, ' ')))
560                 return -1;
561         if (sscanf(str, "%"PRIu64"", &bps) != 1)
562                 return -1;
563
564         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
565                 for (unsigned int i = 0; i < nb_cores; i++) {
566                         lcore_id = lcores[i];
567
568                         if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
569                                 plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
570                         }
571                         else if (bps > 12500000000) {   // Up to 100Gbps
572                                 plog_err("Speed out of range (must be <= 12500000000)\n");
573                         }
574                         else {
575                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
576
577                                 plog_info("Setting rate to %"PRIu64" Bps\n", bps);
578                                 task_gen_set_rate(tbase, bps);
579                         }
580                 }
581         }
582         return 0;
583 }
584
585 static int parse_cmd_reset_randoms_all(const char *str, struct input *input)
586 {
587         if (strcmp(str, "") != 0) {
588                 return -1;
589         }
590
591         unsigned task_id, lcore_id = -1;
592         while (prox_core_next(&lcore_id, 0) == 0) {
593                 for (task_id = 0; task_id < lcore_cfg[lcore_id].n_tasks_all; task_id++) {
594                         if ((task_is_mode_and_submode(lcore_id, task_id, "gen", "")) || (task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
595                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
596                                 uint32_t n_rands = task_gen_get_n_randoms(tbase);
597
598                                 plog_info("Resetting randoms on core %d task %d from %d randoms\n", lcore_id, task_id, n_rands);
599                                 task_gen_reset_randoms(tbase);
600                         }
601                 }
602         }
603         return 0;
604 }
605
606 static int parse_cmd_reset_values_all(const char *str, struct input *input)
607 {
608         if (strcmp(str, "") != 0) {
609                 return -1;
610         }
611
612         unsigned task_id, lcore_id = -1;
613         while (prox_core_next(&lcore_id, 0) == 0) {
614                 for (task_id = 0; task_id < lcore_cfg[lcore_id].n_tasks_all; task_id++) {
615                         if ((task_is_mode_and_submode(lcore_id, task_id, "gen", "")) || (task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
616                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
617
618                                 plog_info("Resetting values on core %d task %d\n", lcore_id, task_id);
619                                 task_gen_reset_values(tbase);
620                         }
621                 }
622         }
623         return 0;
624 }
625
626 static int parse_cmd_reset_values(const char *str, struct input *input)
627 {
628         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
629
630         if (parse_core_task(str, lcores, &task_id, &nb_cores))
631                 return -1;
632
633         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
634                 for (unsigned int i = 0; i < nb_cores; i++) {
635                         lcore_id = lcores[i];
636                         if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
637                                 plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
638                         }
639                         else {
640                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
641
642                                 plog_info("Resetting values on core %d task %d\n", lcore_id, task_id);
643                                 task_gen_reset_values(tbase);
644                         }
645                 }
646         }
647         return 0;
648 }
649
650 static int parse_cmd_set_value(const char *str, struct input *input)
651 {
652         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, value, nb_cores;
653         unsigned short offset;
654         uint8_t value_len;
655
656         if (parse_core_task(str, lcores, &task_id, &nb_cores))
657                 return -1;
658         if (!(str = strchr_skip_twice(str, ' ')))
659                 return -1;
660         if (sscanf(str, "%hu %u %hhu", &offset, &value, &value_len) != 3) {
661                 return -1;
662         }
663
664         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
665                 for (unsigned int i = 0; i < nb_cores; i++) {
666                         lcore_id = lcores[i];
667                         if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
668                                 plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
669                         }
670                         else if (offset > ETHER_MAX_LEN) {
671                                 plog_err("Offset out of range (must be less then %u)\n", ETHER_MAX_LEN);
672                         }
673                         else if (value_len > 4) {
674                                 plog_err("Length out of range (must be less then 4)\n");
675                         }
676                         else {
677                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
678
679                                 if (task_gen_set_value(tbase, value, offset, value_len))
680                                         plog_info("Unable to set Byte %"PRIu16" to %"PRIu8" - too many value set\n", offset, value);
681                                 else
682                                         plog_info("Setting Byte %"PRIu16" to %"PRIu32"\n", offset, value);
683                         }
684                 }
685         }
686         return 0;
687 }
688
689 static int parse_cmd_set_random(const char *str, struct input *input)
690 {
691         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
692         unsigned short offset;
693         uint8_t value_len;
694         char rand_str[64];
695         int16_t rand_id = -1;
696
697         if (parse_core_task(str, lcores, &task_id, &nb_cores))
698                 return -1;
699         if (!(str = strchr_skip_twice(str, ' ')))
700                 return -1;
701         if (sscanf(str, "%hu %32s %hhu", &offset, rand_str, &value_len) != 3) {
702                 return -1;
703         }
704
705         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
706                 for (unsigned int i = 0; i < nb_cores; i++) {
707                         lcore_id = lcores[i];
708                         if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) {
709                                 plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id);
710                         }
711                         else if (offset > ETHER_MAX_LEN) {
712                                 plog_err("Offset out of range (must be less then %u)\n", ETHER_MAX_LEN);
713                         }
714                         else if (value_len > 4) {
715                                 plog_err("Length out of range (must be less then 4)\n");
716                         } else {
717                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
718
719                                 if (task_gen_add_rand(tbase, rand_str, offset, rand_id)) {
720                                         plog_warn("Random not added on core %u task %u\n", lcore_id, task_id);
721                                 }
722                         }
723                 }
724         }
725         return 0;
726 }
727
728 static int parse_cmd_thread_info(const char *str, struct input *input)
729 {
730         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
731
732         if (parse_core_task(str, lcores, &task_id, &nb_cores))
733                 return -1;
734         for (unsigned int i = 0; i < nb_cores; i++) {
735                 cmd_thread_info(lcores[i], task_id);
736         }
737         return 0;
738 }
739
740 static int parse_cmd_verbose(const char *str, struct input *input)
741 {
742         unsigned id;
743
744         if (sscanf(str, "%u", &id) != 1) {
745                 return -1;
746         }
747
748         if (plog_set_lvl(id) != 0) {
749                 plog_err("Cannot set log level to %u\n", id);
750         }
751         return 0;
752 }
753
754 static int parse_cmd_arp_add(const char *str, struct input *input)
755 {
756         struct arp_msg amsg;
757         struct arp_msg *pmsg = &amsg;
758         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
759         struct rte_ring *ring;
760
761         if (parse_core_task(str, lcores, &task_id, &nb_cores))
762                 return -1;
763         if (!(str = strchr_skip_twice(str, ' ')))
764                 return -1;
765         if (strcmp(str, ""))
766                 return -1;
767         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
768                 if (str_to_arp_msg(&amsg, str) == 0) {
769                         for (unsigned int i = 0; i < nb_cores; i++) {
770                                 lcore_id = lcores[i];
771                                 ring = ctrl_rings[lcore_id*MAX_TASKS_PER_CORE + task_id];
772                                 if (!ring) {
773                                         plog_err("No ring for control messages to core %u task %u\n", lcore_id, task_id);
774                                 }
775                                 else {
776 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
777                                         while (rte_ring_sp_enqueue_bulk(ring, (void *const *)&pmsg, 1));
778 #else
779                                         while (rte_ring_sp_enqueue_bulk(ring, (void *const *)&pmsg, 1, NULL) == 0);
780 #endif
781                                         while (!rte_ring_empty(ring));
782                                 }
783                         }
784                         return 0;
785                 }
786         }
787         return -1;
788 }
789
790 static int parse_cmd_rule_add(const char *str, struct input *input)
791 {
792         struct rte_ring *ring;
793         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
794
795         if (parse_core_task(str, lcores, &task_id, &nb_cores))
796                 return -1;
797         if (!(str = strchr_skip_twice(str, ' ')))
798                 return -1;
799         if (strcmp(str, ""))
800                 return -1;
801         char *fields[9];
802         char str_cpy[255];
803         strncpy(str_cpy, str, 255);
804         // example add rule command: rule add 15 0 1&0x0fff 1&0x0fff 0&0 128.0.0.0/1 128.0.0.0/1 5000-5000 5000-5000 allow
805         int ret = rte_strsplit(str_cpy, 255, fields, 9, ' ');
806         if (ret != 8) {
807                 return -1;
808         }
809
810         struct acl4_rule rule;
811         struct acl4_rule *prule = &rule;
812         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
813                 if (str_to_rule(&rule, fields, -1, 1) == 0) {
814                         for (unsigned int i = 0; i < nb_cores; i++) {
815                                 lcore_id = lcores[i];
816                                 ring = ctrl_rings[lcore_id*MAX_TASKS_PER_CORE + task_id];
817                                 if (!ring) {
818                                         plog_err("No ring for control messages to core %u task %u\n", lcore_id, task_id);
819                                 }
820                                 else {
821 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
822                                         while (rte_ring_sp_enqueue_bulk(ring, (void *const *)&prule, 1));
823 #else
824                                         while (rte_ring_sp_enqueue_bulk(ring, (void *const *)&prule, 1, NULL) == 0);
825 #endif
826                                         while (!rte_ring_empty(ring));
827                                 }
828                         }
829                         return 0;
830                 }
831         }
832         return -1;
833 }
834
835 static int parse_cmd_gateway_ip(const char *str, struct input *input)
836 {
837         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, ip[4], nb_cores, i;
838
839         if (parse_core_task(str, lcores, &task_id, &nb_cores))
840                 return -1;
841         if (!(str = strchr_skip_twice(str, ' ')))
842                 return -1;
843         if (!strcmp(str, ""))
844                 return -1;
845         if (sscanf(str, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) {
846                 return -1;
847         }
848         for (i = 0; i < nb_cores; i++) {
849                 lcore_id = lcores[i];
850
851                 if (!task_is_sub_mode(lcore_id, task_id, "l3")) {
852                         plog_err("Core %u task %u is not in l3 mode\n", lcore_id, task_id);
853                 }
854                 else {
855                         uint32_t gateway_ip = ((ip[3] & 0xFF) << 24) | ((ip[2] & 0xFF) << 16) | ((ip[1] & 0xFF) << 8) | ((ip[0] & 0xFF) << 0);
856                         struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
857                         plog_info("Setting gateway ip to %s\n", str);
858                         task_set_gateway_ip(tbase, gateway_ip);
859                 }
860         }
861         return 0;
862 }
863
864 static int parse_cmd_local_ip(const char *str, struct input *input)
865 {
866         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, ip[4], nb_cores, i;
867
868         if (parse_core_task(str, lcores, &task_id, &nb_cores))
869                 return -1;
870         if (!(str = strchr_skip_twice(str, ' ')))
871                 return -1;
872         if (!strcmp(str, ""))
873                 return -1;
874         if (sscanf(str, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) {
875                 return -1;
876         }
877         for (i = 0; i < nb_cores; i++) {
878                 lcore_id = lcores[i];
879                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
880                 uint32_t local_ip = ((ip[3] & 0xFF) << 24) | ((ip[2] & 0xFF) << 16) | ((ip[1] & 0xFF) << 8) | ((ip[0] & 0xFF) << 0);
881                 if (!task_is_mode_and_submode(lcore_id, task_id, "arp", "local")) {
882                         if (!task_is_sub_mode(lcore_id, task_id, "l3")) {
883                                 plog_err("Core %u task %u is not in l3 mode\n", lcore_id, task_id);
884                         } else {
885                                 plog_info("Setting local ip to %s\n", str);
886                                 task_set_local_ip(tbase, local_ip);
887                         }
888                 } else {
889                         plog_info("Setting local ip to %s\n", str);
890                         task_arp_set_local_ip(tbase, local_ip);
891                 }
892         }
893         return 0;
894 }
895
896 static int parse_cmd_route_add(const char *str, struct input *input)
897 {
898         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, prefix, next_hop_idx, ip[4], nb_cores;
899
900         if (parse_core_task(str, lcores, &task_id, &nb_cores))
901                 return -1;
902         if (!(str = strchr_skip_twice(str, ' ')))
903                 return -1;
904         if (strcmp(str, ""))
905                 return -1;
906         if (sscanf(str, "%u.%u.%u.%u/%u %u", ip, ip + 1, ip + 2, ip + 3,
907                    &prefix, &next_hop_idx) != 8) {
908                 return -1;
909         }
910         struct rte_ring *ring;
911
912         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
913                 for (unsigned int i = 0; i < nb_cores; i++) {
914                         lcore_id = lcores[i];
915                         ring = ctrl_rings[lcore_id*MAX_TASKS_PER_CORE + task_id];
916                         if (!ring) {
917                                 plog_err("No ring for control messages to core %u task %u\n", lcore_id, task_id);
918                         }
919                         else {
920                                 struct route_msg rmsg;
921                                 struct route_msg *pmsg = &rmsg;
922
923                                 rmsg.ip_bytes[0] = ip[0];
924                                 rmsg.ip_bytes[1] = ip[1];
925                                 rmsg.ip_bytes[2] = ip[2];
926                                 rmsg.ip_bytes[3] = ip[3];
927                                 rmsg.prefix = prefix;
928                                 rmsg.nh = next_hop_idx;
929 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
930                                 while (rte_ring_sp_enqueue_bulk(ring, (void *const *)&pmsg, 1));
931 #else
932                                 while (rte_ring_sp_enqueue_bulk(ring, (void *const *)&pmsg, 1, NULL) == 0);
933 #endif
934                                 while (!rte_ring_empty(ring));
935                         }
936                 }
937         }
938         return 0;
939 }
940
941 static int parse_cmd_start(const char *str, struct input *input)
942 {
943         int task_id = -1;
944
945         if (strncmp(str, "all", 3) == 0) {
946                 str += 3;
947                 sscanf(str, "%d", &task_id);
948
949                 start_core_all(task_id);
950                 req_refresh();
951                 return 0;
952         }
953
954         uint32_t cores[64] = {0};
955         int ret;
956         ret = parse_list_set(cores, str, 64);
957         if (ret < 0) {
958                 return -1;
959         }
960         str = strchr(str, ' ');
961
962         if (str) {
963                 sscanf(str, "%d", &task_id);
964         }
965         start_cores(cores, ret, task_id);
966         req_refresh();
967         return 0;
968 }
969
970 static int parse_cmd_stop(const char *str, struct input *input)
971 {
972         int task_id = -1;
973
974         if (strncmp(str, "all", 3) == 0) {
975                 str += 3;
976                 sscanf(str, "%d", &task_id);
977                 stop_core_all(task_id);
978                 req_refresh();
979                 return 0;
980         }
981
982         uint32_t cores[64] = {0};
983         int ret;
984         ret = parse_list_set(cores, str, 64);
985         if (ret < 0) {
986                 return -1;
987         }
988         str = strchr(str, ' ');
989
990         if (str) {
991                 sscanf(str, "%d", &task_id);
992         }
993         stop_cores(cores, ret, task_id);
994         req_refresh();
995
996         return 0;
997 }
998
999 static int parse_cmd_rx_distr_start(const char *str, struct input *input)
1000 {
1001         unsigned lcore_id[RTE_MAX_LCORE];
1002
1003         int nb_cores;
1004
1005         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1006
1007         if (nb_cores <= 0) {
1008                 return -1;
1009         }
1010
1011         for (int i = 0; i < nb_cores; ++i)
1012                 cmd_rx_distr_start(lcore_id[i]);
1013         return 0;
1014 }
1015
1016 static int parse_cmd_tx_distr_start(const char *str, struct input *input)
1017 {
1018         unsigned lcore_id[RTE_MAX_LCORE];
1019
1020         int nb_cores;
1021
1022         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1023
1024         if (nb_cores <= 0) {
1025                 return -1;
1026         }
1027
1028         for (int i = 0; i < nb_cores; ++i)
1029                 cmd_tx_distr_start(lcore_id[i]);
1030         return 0;
1031 }
1032
1033 static int parse_cmd_rx_distr_stop(const char *str, struct input *input)
1034 {
1035         unsigned lcore_id[RTE_MAX_LCORE];
1036
1037         int nb_cores;
1038
1039         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1040
1041         if (nb_cores <= 0) {
1042                 return -1;
1043         }
1044
1045         for (int i = 0; i < nb_cores; ++i)
1046                 cmd_rx_distr_stop(lcore_id[i]);
1047         return 0;
1048 }
1049
1050 static int parse_cmd_tx_distr_stop(const char *str, struct input *input)
1051 {
1052         unsigned lcore_id[RTE_MAX_LCORE];
1053
1054         int nb_cores;
1055
1056         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1057
1058         if (nb_cores <= 0) {
1059                 return -1;
1060         }
1061
1062         for (int i = 0; i < nb_cores; ++i)
1063                 cmd_tx_distr_stop(lcore_id[i]);
1064         return 0;
1065 }
1066
1067 static int parse_cmd_rx_distr_reset(const char *str, struct input *input)
1068 {
1069         unsigned lcore_id[RTE_MAX_LCORE];
1070
1071         int nb_cores;
1072
1073         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1074
1075         if (nb_cores <= 0) {
1076                 return -1;
1077         }
1078
1079         for (int i = 0; i < nb_cores; ++i)
1080                 cmd_rx_distr_rst(lcore_id[i]);
1081         return 0;
1082 }
1083
1084 static int parse_cmd_tx_distr_reset(const char *str, struct input *input)
1085 {
1086         unsigned lcore_id[RTE_MAX_LCORE];
1087
1088         int nb_cores;
1089
1090         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1091
1092         if (nb_cores <= 0) {
1093                 return -1;
1094         }
1095
1096         for (int i = 0; i < nb_cores; ++i)
1097                 cmd_tx_distr_rst(lcore_id[i]);
1098         return 0;
1099 }
1100
1101 static int parse_cmd_rx_distr_show(const char *str, struct input *input)
1102 {
1103         unsigned lcore_id[RTE_MAX_LCORE];
1104
1105         int nb_cores;
1106
1107         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1108
1109         if (nb_cores <= 0) {
1110                 return -1;
1111         }
1112
1113         for (int i = 0; i < nb_cores; ++i)
1114                 cmd_rx_distr_show(lcore_id[i]);
1115         return 0;
1116 }
1117
1118 static int parse_cmd_tx_distr_show(const char *str, struct input *input)
1119 {
1120         unsigned lcore_id[RTE_MAX_LCORE];
1121
1122         int nb_cores;
1123
1124         nb_cores = parse_list_set(lcore_id, str, sizeof(lcore_id)/sizeof(lcore_id[0]));
1125
1126         if (nb_cores <= 0) {
1127                 return -1;
1128         }
1129
1130         for (int i = 0; i < nb_cores; ++i)
1131                 cmd_tx_distr_show(lcore_id[i]);
1132         return 0;
1133 }
1134
1135 static int parse_cmd_tot_stats(const char *str, struct input *input)
1136 {
1137         if (strcmp("", str) != 0) {
1138                 return -1;
1139         }
1140
1141         struct global_stats_sample *gsl = stats_get_global_stats(1);
1142         uint64_t tot_rx = gsl->host_rx_packets;
1143         uint64_t tot_tx = gsl->host_tx_packets;
1144         uint64_t last_tsc = gsl->tsc;
1145
1146         if (input->reply) {
1147                 char buf[128];
1148                 snprintf(buf, sizeof(buf), "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"\n",
1149                          tot_rx, tot_tx, last_tsc, rte_get_tsc_hz());
1150                 input->reply(input, buf, strlen(buf));
1151         }
1152         else {
1153                 plog_info("RX: %"PRIu64", TX: %"PRIu64"\n", tot_rx, tot_tx);
1154         }
1155         return 0;
1156 }
1157
1158 static int parse_cmd_update_interval(const char *str, struct input *input)
1159 {
1160         unsigned val;
1161
1162         if (sscanf(str, "%u", &val) != 1) {
1163                 return -1;
1164         }
1165
1166         if (val == 0) {
1167                 plog_err("Minimum update interval is 1 ms\n");
1168         }
1169         else {
1170                 plog_info("Setting update interval to %d ms\n", val);
1171                 set_update_interval(val);
1172         }
1173         return 0;
1174 }
1175
1176 static int parse_cmd_mem_info(const char *str, struct input *input)
1177 {
1178         if (strcmp("", str) != 0) {
1179                 return -1;
1180         }
1181
1182         cmd_mem_stats();
1183         cmd_mem_layout();
1184         return 0;
1185 }
1186
1187 static int parse_cmd_tot_ierrors_tot(const char *str, struct input *input)
1188 {
1189         if (strcmp(str, "") != 0) {
1190                 return -1;
1191         }
1192
1193         struct global_stats_sample *gsl = stats_get_global_stats(1);
1194         uint64_t tot = gsl->nics_ierrors;
1195         uint64_t last_tsc = gsl->tsc;
1196
1197         if (input->reply) {
1198                 char buf[128];
1199                 snprintf(buf, sizeof(buf),
1200                          "%"PRIu64",%"PRIu64",%"PRIu64"\n",
1201                          tot, last_tsc, rte_get_tsc_hz());
1202                 input->reply(input, buf, strlen(buf));
1203         }
1204         else {
1205                 plog_info("ierrors: %"PRIu64"\n", tot);
1206         }
1207         return 0;
1208 }
1209
1210 static int parse_cmd_tot_imissed_tot(const char *str, struct input *input)
1211 {
1212         if (strcmp(str, "") != 0) {
1213                 return -1;
1214         }
1215
1216         struct global_stats_sample *gsl = stats_get_global_stats(1);
1217         uint64_t tot = gsl->nics_imissed;
1218         uint64_t last_tsc = gsl->tsc;
1219
1220         if (input->reply) {
1221                 char buf[128];
1222                 snprintf(buf, sizeof(buf),
1223                          "%"PRIu64",%"PRIu64",%"PRIu64"\n",
1224                          tot, last_tsc, rte_get_tsc_hz());
1225                 input->reply(input, buf, strlen(buf));
1226         }
1227         else {
1228                 plog_info("imissed: %"PRIu64"\n", tot);
1229         }
1230         return 0;
1231 }
1232
1233 static int parse_cmd_reset_port(const char *str, struct input *input)
1234 {
1235         uint32_t port_id;
1236
1237         if (sscanf(str, "%u", &port_id ) != 1) {
1238                 return -1;
1239         }
1240
1241         cmd_reset_port(port_id);
1242         return 0;
1243 }
1244
1245 static int parse_cmd_write_reg(const char *str, struct input *input)
1246 {
1247         uint32_t port_id;
1248         uint32_t id, val;
1249
1250         if (sscanf(str, "%u %x %u", &port_id, &id, &val) != 3) {
1251                 return -1;
1252         }
1253
1254         cmd_write_reg(port_id, id, val);
1255         return 0;
1256 }
1257
1258 static int parse_cmd_read_reg(const char *str, struct input *input)
1259 {
1260         uint32_t port_id;
1261         uint32_t id;
1262
1263         if (sscanf(str, "%u %x", &port_id, &id) != 2) {
1264                 return -1;
1265         }
1266
1267         cmd_read_reg(port_id, id);
1268         return 0;
1269 }
1270
1271 static int parse_cmd_cache_reset(const char *str, struct input *input)
1272 {
1273         cmd_cache_reset();
1274         return 0;
1275 }
1276
1277 static int parse_cmd_set_cache_class_mask(const char *str, struct input *input)
1278 {
1279         uint32_t lcore_id;
1280         uint32_t set;
1281         uint32_t val;
1282
1283         if (sscanf(str, "%u %u %u", &lcore_id, &set, &val) != 3) {
1284                 return -1;
1285         }
1286
1287         cmd_set_cache_class_mask(lcore_id, set, val);
1288         return 0;
1289 }
1290
1291 static int parse_cmd_set_cache_class(const char *str, struct input *input)
1292 {
1293         uint32_t lcore_id;
1294         uint32_t set;
1295
1296         if (sscanf(str, "%u %u", &lcore_id, &set) != 2) {
1297                 return -1;
1298         }
1299
1300         cmd_set_cache_class(lcore_id, set);
1301         return 0;
1302 }
1303
1304 static int parse_cmd_get_cache_class_mask(const char *str, struct input *input)
1305 {
1306         uint32_t lcore_id;
1307         uint32_t set;
1308         uint32_t val = 0;
1309
1310         if (sscanf(str, "%u %u", &lcore_id, &set) != 2) {
1311                 return -1;
1312         }
1313
1314         cmd_get_cache_class_mask(lcore_id, set, &val);
1315         if (input->reply) {
1316                 char buf[128];
1317                 snprintf(buf, sizeof(buf), "%d, %d, %x\n", lcore_id, set, val);
1318                 input->reply(input, buf, strlen(buf));
1319         } else {
1320                 plog_info("core=%d, set=%d, mask=%x\n", lcore_id, set, val);
1321         }
1322         return 0;
1323 }
1324
1325 static int parse_cmd_get_cache_class(const char *str, struct input *input)
1326 {
1327         uint32_t lcore_id;
1328         uint32_t set;
1329         uint32_t val;
1330
1331         if (sscanf(str, "%u", &lcore_id) != 1) {
1332                 return -1;
1333         }
1334
1335         cmd_get_cache_class(lcore_id, &set);
1336         if (input->reply) {
1337                 char buf[128];
1338                 snprintf(buf, sizeof(buf), "%d, %d\n", lcore_id, set);
1339                 input->reply(input, buf, strlen(buf));
1340         } else {
1341                 plog_info("core=%d, cos=%d\n", lcore_id, set);
1342         }
1343         return 0;
1344 }
1345
1346 static int parse_cmd_get_cache_mask(const char *str, struct input *input)
1347 {
1348         uint32_t lcore_id;
1349         uint32_t set;
1350         uint32_t mask;
1351
1352         if (sscanf(str, "%u", &lcore_id) != 1) {
1353                 return -1;
1354         }
1355
1356         cmd_get_cache_class(lcore_id, &set);
1357         cmd_get_cache_class_mask(lcore_id, set, &mask);
1358         if (input->reply) {
1359                 char buf[128];
1360                 snprintf(buf, sizeof(buf), "%d, %x\n", lcore_id, mask);
1361                 input->reply(input, buf, strlen(buf));
1362         } else {
1363                 plog_info("core=%d, mask=%x\n", lcore_id, mask);
1364         }
1365         return 0;
1366 }
1367
1368 static int parse_cmd_set_vlan_offload(const char *str, struct input *input)
1369 {
1370         uint32_t port_id;
1371         uint32_t val;
1372
1373         if (sscanf(str, "%u %u", &port_id, &val) != 2) {
1374                 return -1;
1375         }
1376
1377         cmd_set_vlan_offload(port_id, val);
1378         return 0;
1379 }
1380
1381 static int parse_cmd_set_vlan_filter(const char *str, struct input *input)
1382 {
1383         uint32_t port_id;
1384         uint32_t id, val;
1385
1386         if (sscanf(str, "%u %d %u", &port_id, &id, &val) != 3) {
1387                 return -1;
1388         }
1389
1390         cmd_set_vlan_filter(port_id, id, val);
1391         return 0;
1392 }
1393
1394 static int parse_cmd_ring_info_all(const char *str, struct input *input)
1395 {
1396         if (strcmp(str, "") != 0) {
1397                 return -1;
1398         }
1399         cmd_ringinfo_all();
1400         return 0;
1401 }
1402
1403 static int parse_cmd_port_up(const char *str, struct input *input)
1404 {
1405         unsigned val;
1406
1407         if (sscanf(str, "%u", &val) != 1) {
1408                 return -1;
1409         }
1410
1411         cmd_port_up(val);
1412         return 0;
1413 }
1414
1415 static int parse_cmd_port_down(const char *str, struct input *input)
1416 {
1417         unsigned val;
1418
1419         if (sscanf(str, "%u", &val) != 1) {
1420                 return -1;
1421         }
1422
1423         cmd_port_down(val);
1424         return 0;
1425 }
1426
1427 static int parse_cmd_port_link_state(const char *str, struct input *input)
1428 {
1429         unsigned val;
1430
1431         if (sscanf(str, "%u", &val) != 1) {
1432                 return -1;
1433         }
1434
1435         if (!port_is_active(val))
1436                 return -1;
1437
1438         int active = prox_port_cfg[val].link_up;
1439         const char *state = active? "up\n" : "down\n";
1440
1441         if (input->reply)
1442                 input->reply(input, state, strlen(state));
1443         else
1444                 plog_info("%s", state);
1445
1446         return 0;
1447 }
1448
1449 static int parse_cmd_xstats(const char *str, struct input *input)
1450 {
1451         unsigned val;
1452
1453         if (sscanf(str, "%u", &val) != 1) {
1454                 return -1;
1455         }
1456
1457         cmd_xstats(val);
1458         return 0;
1459 }
1460
1461 static int parse_cmd_stats(const char *str, struct input *input)
1462 {
1463         if (strcmp(str, "") == 0)
1464                 return -1;
1465
1466         char buf[32768];
1467         char ret2[32768];
1468         char *ret = ret2;
1469         int list = 0;
1470
1471         strncpy(buf, str, sizeof(buf) - 1);
1472         char *tok;
1473         uint64_t stat_val;
1474
1475         while ((tok = strchr(str, ','))) {
1476                 *tok = 0;
1477                 stat_val = stats_parser_get(str);
1478
1479                 ret += sprintf(ret, "%s%"PRIu64"", list? "," :"", stat_val);
1480                 list = 1;
1481                 str = tok + 1;
1482         }
1483
1484         stat_val = stats_parser_get(str);
1485         ret += sprintf(ret, "%s%"PRIu64"", list? "," :"", stat_val);
1486
1487         sprintf(ret, "\n");
1488
1489         if (input->reply)
1490                 input->reply(input, ret2, strlen(ret2));
1491         else
1492                 plog_info("%s", ret2);
1493         return 0;
1494 }
1495
1496 static void replace_char(char *str, char to_replace, char by)
1497 {
1498         for (size_t i = 0; str[i] != '\0'; ++i) {
1499                 if (str[i] == to_replace)
1500                         str[i] = by;
1501         }
1502 }
1503
1504 static int parse_cmd_port_info(const char *str, struct input *input)
1505 {
1506         int val;
1507
1508         if (strcmp(str, "all") == 0) {
1509                 val = -1;
1510         }
1511         else if (sscanf(str, "%d", &val) != 1) {
1512                 return -1;
1513         }
1514
1515         char port_info[2048];
1516
1517         cmd_portinfo(val, port_info, sizeof(port_info));
1518
1519         if (input->reply) {
1520                 replace_char(port_info, '\n', ',');
1521                 port_info[strlen(port_info) - 1] = '\n';
1522                 input->reply(input, port_info, strlen(port_info));
1523         } else
1524                 plog_info("%s", port_info);
1525
1526         return 0;
1527 }
1528
1529 static int parse_cmd_ring_info(const char *str, struct input *input)
1530 {
1531         unsigned lcores[RTE_MAX_LCORE], task_id, nb_cores;
1532
1533         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1534                 return -1;
1535
1536         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1537                 for (unsigned int i = 0; i < nb_cores; i++) {
1538                         cmd_ringinfo(lcores[i], task_id);
1539                 }
1540         }
1541         return 0;
1542 }
1543
1544 static int parse_cmd_port_stats(const char *str, struct input *input)
1545 {
1546         unsigned val;
1547
1548         if (sscanf(str, "%u", &val) != 1) {
1549                 return -1;
1550         }
1551
1552         struct get_port_stats s;
1553         if (stats_port(val, &s)) {
1554                 plog_err("Invalid port %u\n", val);
1555                 return 0;
1556         }
1557         char buf[256];
1558         snprintf(buf, sizeof(buf),
1559                  "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64","
1560                  "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64","
1561                  "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"\n",
1562                  s.no_mbufs_diff, s.ierrors_diff + s.imissed_diff,
1563                  s.rx_bytes_diff, s.tx_bytes_diff,
1564                  s.rx_pkts_diff, s.tx_pkts_diff,
1565                  s.rx_tot, s.tx_tot,
1566                  s.no_mbufs_tot, s.ierrors_tot + s.imissed_tot,
1567                  s.last_tsc, s.prev_tsc);
1568         plog_info("%s", buf);
1569         if (input->reply)
1570                 input->reply(input, buf, strlen(buf));
1571         return 0;
1572 }
1573
1574 static int parse_cmd_multi_port_stats(const char *str, struct input *input)
1575 {
1576         uint32_t ports[PROX_MAX_PORTS];
1577         int nb_ports = parse_list_set(ports, str, PROX_MAX_PORTS);
1578         if (nb_ports <= 0) {
1579                 return -1;
1580         }
1581
1582         char buf[PROX_MAX_PORTS * (11+5*21) + 1], *pbuf = buf;
1583         int left = sizeof(buf);
1584         for (int i = 0; i < nb_ports; ++i) {
1585                 struct get_port_stats s;
1586                 if (stats_port(ports[i], &s)) {
1587                         plog_err("Invalid port %u\n", ports[i]);
1588                         return 0;
1589                 }
1590
1591                 int len = snprintf(pbuf, left,
1592                                 "%u,"
1593                                 "%"PRIu64",%"PRIu64","
1594                                 "%"PRIu64",%"PRIu64","
1595                                 "%"PRIu64";",
1596                                 //TODO: adjust buf size above when adding fields
1597                                 ports[i],
1598                                 s.rx_tot, s.tx_tot,
1599                                 s.no_mbufs_tot, s.ierrors_tot + s.imissed_tot,
1600                                 s.last_tsc);
1601                 if ((len < 0) || (len >= left)) {
1602                         plog_err("Cannot print stats for port %u\n", ports[i]);
1603                         return 0;
1604                 }
1605                 pbuf += len;
1606                 left -= len;
1607         }
1608         pbuf--;
1609         *pbuf = '\n';
1610
1611         plog_info("%s", buf);
1612         if (input->reply)
1613                 input->reply(input, buf, sizeof(buf) - left);
1614         return 0;
1615 }
1616
1617 static int parse_cmd_core_stats(const char *str, struct input *input)
1618 {
1619         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1620
1621         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1622                 return -1;
1623
1624         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1625                 for (unsigned int i = 0; i < nb_cores; i++) {
1626                         lcore_id = lcores[i];
1627                         uint64_t tot_rx = stats_core_task_tot_rx(lcore_id, task_id);
1628                         uint64_t tot_tx = stats_core_task_tot_tx(lcore_id, task_id);
1629                         uint64_t tot_drop = stats_core_task_tot_drop(lcore_id, task_id);
1630                         uint64_t last_tsc = stats_core_task_last_tsc(lcore_id, task_id);
1631
1632                         if (input->reply) {
1633                                 char buf[128];
1634                                 snprintf(buf, sizeof(buf),
1635                                         "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"\n",
1636                                         tot_rx, tot_tx, tot_drop, last_tsc, rte_get_tsc_hz());
1637                                 input->reply(input, buf, strlen(buf));
1638                         }
1639                         else {
1640                                 plog_info("RX: %"PRIu64", TX: %"PRIu64", DROP: %"PRIu64"\n",
1641                                         tot_rx, tot_tx, tot_drop);
1642                         }
1643                 }
1644         }
1645         return 0;
1646 }
1647
1648 static int parse_cmd_dp_core_stats(const char *str, struct input *input)
1649 {
1650         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1651
1652         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1653                 return -1;
1654
1655         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1656                 for (unsigned int i = 0; i < nb_cores; i++) {
1657                         lcore_id = lcores[i];
1658                         uint64_t tot_rx = stats_core_task_tot_rx(lcore_id, task_id);
1659                         uint64_t tot_tx = stats_core_task_tot_tx(lcore_id, task_id);
1660                         uint64_t tot_rx_non_dp = stats_core_task_tot_rx_non_dp(lcore_id, task_id);
1661                         uint64_t tot_tx_non_dp = stats_core_task_tot_tx_non_dp(lcore_id, task_id);
1662                         uint64_t tot_drop = stats_core_task_tot_drop(lcore_id, task_id);
1663                         uint64_t last_tsc = stats_core_task_last_tsc(lcore_id, task_id);
1664
1665                         if (input->reply) {
1666                                 char buf[128];
1667                                 snprintf(buf, sizeof(buf),
1668                                         "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"\n",
1669                                         tot_rx, tot_tx, tot_rx_non_dp, tot_tx_non_dp, tot_drop, last_tsc, rte_get_tsc_hz());
1670                                 input->reply(input, buf, strlen(buf));
1671                         }
1672                         else {
1673                                 plog_info("RX: %"PRIu64", TX: %"PRIu64", RX_NON_DP:  %"PRIu64", TX_NON_DP: %"PRIu64", DROP: %"PRIu64"\n",
1674                                         tot_rx, tot_tx, tot_rx_non_dp, tot_tx_non_dp, tot_drop);
1675                         }
1676                 }
1677         }
1678         return 0;
1679 }
1680
1681 static int parse_cmd_lat_stats(const char *str, struct input *input)
1682 {
1683         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1684
1685         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1686                 return -1;
1687
1688         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1689                 for (unsigned int i = 0; i < nb_cores; i++) {
1690                         lcore_id = lcores[i];
1691                         if (!task_is_mode(lcore_id, task_id, "lat")) {
1692                                 plog_err("Core %u task %u is not measuring latency\n", lcore_id, task_id);
1693                         }
1694                         else {
1695                                 struct stats_latency *stats = stats_latency_find(lcore_id, task_id);
1696                                 struct stats_latency *tot = stats_latency_tot_find(lcore_id, task_id);
1697
1698                                 uint64_t last_tsc = stats_core_task_last_tsc(lcore_id, task_id);
1699                                 uint64_t lat_min_usec = time_unit_to_usec(&stats->min.time);
1700                                 uint64_t lat_max_usec = time_unit_to_usec(&stats->max.time);
1701                                 uint64_t tot_lat_min_usec = time_unit_to_usec(&tot->min.time);
1702                                 uint64_t tot_lat_max_usec = time_unit_to_usec(&tot->max.time);
1703                                 uint64_t lat_avg_usec = time_unit_to_usec(&stats->avg.time);
1704
1705                                 if (input->reply) {
1706                                         char buf[128];
1707                                         snprintf(buf, sizeof(buf),
1708                                                 "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"\n",
1709                                                  lat_min_usec,
1710                                                  lat_max_usec,
1711                                                  lat_avg_usec,
1712                                                  tot_lat_min_usec,
1713                                                  tot_lat_max_usec,
1714                                                  last_tsc,
1715                                                  rte_get_tsc_hz());
1716                                         input->reply(input, buf, strlen(buf));
1717                                 }
1718                                 else {
1719                                         plog_info("min: %"PRIu64", max: %"PRIu64", avg: %"PRIu64", min since reset: %"PRIu64", max since reset: %"PRIu64"\n",
1720                                                   lat_min_usec,
1721                                                   lat_max_usec,
1722                                                   lat_avg_usec,
1723                                                   tot_lat_min_usec,
1724                                                   tot_lat_max_usec);
1725                                 }
1726                         }
1727                 }
1728         }
1729         return 0;
1730 }
1731
1732 static int parse_cmd_show_irq_buckets(const char *str, struct input *input)
1733 {
1734         char buf[4096] = {0};
1735         unsigned int i, c;
1736         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1737
1738         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1739                 return -1;
1740
1741         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1742                 for (c = 0; c < nb_cores; c++) {
1743                         lcore_id = lcores[c];
1744                         get_irq_buckets_by_core_task(buf, lcore_id, task_id);
1745                         plog_info("%s", buf);
1746                         if (input->reply)
1747                                 input->reply(input, buf, strlen(buf));
1748                         buf[0] = 0;
1749                 }
1750         }
1751         return 0;
1752 }
1753
1754 static int parse_cmd_irq(const char *str, struct input *input)
1755 {
1756         unsigned int i, c;
1757         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1758
1759         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1760                 return -1;
1761
1762         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1763                 for (c = 0; c < nb_cores; c++) {
1764                         lcore_id = lcores[c];
1765                         if (!task_is_mode(lcore_id, task_id, "irq")) {
1766                                 plog_err("Core %u task %u is not in irq mode\n", lcore_id, task_id);
1767                         } else {
1768                                 struct task_irq *task_irq = (struct task_irq *)(lcore_cfg[lcore_id].tasks_all[task_id]);
1769
1770                                 task_irq_show_stats(task_irq, input);
1771                         }
1772                 }
1773         }
1774         return 0;
1775 }
1776
1777 static void task_lat_show_latency_histogram(uint8_t lcore_id, uint8_t task_id, struct input *input)
1778 {
1779 #ifdef LATENCY_HISTOGRAM
1780         uint64_t *buckets;
1781
1782         stats_core_lat_histogram(lcore_id, task_id, &buckets);
1783
1784         if (buckets == NULL)
1785                 return;
1786
1787         if (input->reply) {
1788                 char buf[4096] = {0};
1789                 for (size_t i = 0; i < 128; i++)
1790                         sprintf(buf+strlen(buf), "Bucket [%zu]: %"PRIu64"\n", i, buckets[i]);
1791                 input->reply(input, buf, strlen(buf));
1792         }
1793         else {
1794                 for (size_t i = 0; i < 128; i++)
1795                         if (buckets[i])
1796                                 plog_info("Bucket [%zu]: %"PRIu64"\n", i, buckets[i]);
1797         }
1798 #else
1799         plog_info("LATENCY_DETAILS disabled\n");
1800 #endif
1801 }
1802
1803 static int parse_cmd_lat_packets(const char *str, struct input *input)
1804 {
1805         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1806
1807         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1808                 return -1;
1809
1810         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1811                 for (unsigned int i = 0; i < nb_cores; i++) {
1812                         lcore_id = lcores[i];
1813                         if (!task_is_mode(lcore_id, task_id, "lat")) {
1814                                 plog_err("Core %u task %u is not measuring latency\n", lcore_id, task_id);
1815                         }
1816                         else {
1817                                 task_lat_show_latency_histogram(lcore_id, task_id, input);
1818                         }
1819                 }
1820         }
1821         return 0;
1822 }
1823
1824 static int parse_cmd_cgnat_public_hash(const char *str, struct input *input)
1825 {
1826         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1827
1828         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1829                 return -1;
1830
1831         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1832                 for (unsigned int i = 0; i < nb_cores; i++) {
1833                         lcore_id = lcores[i];
1834
1835                         if (!task_is_mode(lcore_id, task_id, "cgnat")) {
1836                                 plog_err("Core %u task %u is not cgnat\n", lcore_id, task_id);
1837                         }
1838                         else {
1839                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
1840                                 task_cgnat_dump_public_hash((struct task_nat *)tbase);
1841                         }
1842                 }
1843         }
1844         return 0;
1845 }
1846
1847 static int parse_cmd_cgnat_private_hash(const char *str, struct input *input)
1848 {
1849         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1850         uint32_t val;
1851
1852         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1853                 return -1;
1854
1855         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1856                 for (unsigned int i = 0; i < nb_cores; i++) {
1857                         lcore_id = lcores[i];
1858
1859                         if (!task_is_mode(lcore_id, task_id, "cgnat")) {
1860                                 plog_err("Core %u task %u is not cgnat\n", lcore_id, task_id);
1861                         }
1862                         else {
1863                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
1864                                 task_cgnat_dump_private_hash((struct task_nat *)tbase);
1865                         }
1866                 }
1867         }
1868         return 0;
1869 }
1870
1871 static int parse_cmd_accuracy(const char *str, struct input *input)
1872 {
1873         unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
1874         uint32_t val;
1875
1876         if (parse_core_task(str, lcores, &task_id, &nb_cores))
1877                 return -1;
1878         if (!(str = strchr_skip_twice(str, ' ')))
1879                 return -1;
1880         if (sscanf(str, "%"PRIu32"", &val) != 1)
1881                 return -1;
1882
1883         if (cores_task_are_valid(lcores, task_id, nb_cores)) {
1884                 for (unsigned int i = 0; i < nb_cores; i++) {
1885                         lcore_id = lcores[i];
1886
1887                         if (!task_is_mode(lcore_id, task_id, "lat")) {
1888                                 plog_err("Core %u task %u is not measuring latency\n", lcore_id, task_id);
1889                         }
1890                         else {
1891                                 struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
1892
1893                                 task_lat_set_accuracy_limit((struct task_lat *)tbase, val);
1894                         }
1895                 }
1896         }
1897         return 0;
1898 }
1899
1900 static int parse_cmd_rx_tx_info(const char *str, struct input *input)
1901 {
1902         if (strcmp(str, "") != 0) {
1903                 return -1;
1904         }
1905
1906         cmd_rx_tx_info();
1907         return 0;
1908 }
1909
1910 static int parse_cmd_version(const char *str, struct input *input)
1911 {
1912         if (strcmp(str, "") != 0) {
1913                 return -1;
1914         }
1915
1916         if (input->reply) {
1917                 uint64_t version =
1918                         ((uint64_t)VERSION_MAJOR) << 24 |
1919                         ((uint64_t)VERSION_MINOR) << 16 |
1920                         ((uint64_t)VERSION_REV) << 8;
1921
1922                 char buf[128];
1923                 snprintf(buf, sizeof(buf), "%"PRIu64",%"PRIu64"\n", version, (uint64_t)RTE_VERSION);
1924                 input->reply(input, buf, strlen(buf));
1925         }
1926         else {
1927                 plog_info("prox version: %d.%d, DPDK version: %s\n",
1928                           VERSION_MAJOR, VERSION_MINOR,
1929                           rte_version() + sizeof(RTE_VER_PREFIX));
1930         }
1931         return 0;
1932 }
1933
1934 struct cmd_str {
1935         const char *cmd;
1936         const char *args;
1937         const char *help;
1938         int (*parse)(const char *args, struct input *input);
1939 };
1940
1941 static int parse_cmd_help(const char *str, struct input *input);
1942
1943 static struct cmd_str cmd_strings[] = {
1944         {"history", "", "Print command history", parse_cmd_history},
1945         {"echo", "", "echo parameter, useful to resolving variables", parse_cmd_echo},
1946         {"quit", "", "Stop all cores and quit", parse_cmd_quit},
1947         {"quit_force", "", "Quit without waiting on cores to stop", parse_cmd_quit_force},
1948         {"help", "<substr>", "Show list of commands that have <substr> as a substring. If no substring is provided, all commands are shown.", parse_cmd_help},
1949         {"verbose", "<level>", "Set verbosity level", parse_cmd_verbose},
1950         {"thread info", "<core_id> <task_id>", "", parse_cmd_thread_info},
1951         {"mem info", "", "Show information about system memory (number of huge pages and addresses of these huge pages)", parse_cmd_mem_info},
1952         {"update interval", "<value>", "Update statistics refresh rate, in msec (must be >=10). Default is 1 second", parse_cmd_update_interval},
1953         {"rx tx info", "", "Print connections between tasks on all cores", parse_cmd_rx_tx_info},
1954         {"start", "<core list>|all <task_id>", "Start core <core_id> or all cores", parse_cmd_start},
1955         {"stop", "<core list>|all <task_id>", "Stop core <core id> or all cores", parse_cmd_stop},
1956
1957         {"dump", "<core id> <task id> <nb packets>", "Create a hex dump of <nb_packets> from <task_id> on <core_id> showing how packets have changed between RX and TX.", parse_cmd_trace},
1958         {"dump_rx", "<core id> <task id> <nb packets>", "Create a hex dump of <nb_packets> from <task_id> on <core_id> at RX", parse_cmd_dump_rx},
1959         {"dump_tx", "<core id> <task id> <nb packets>", "Create a hex dump of <nb_packets> from <task_id> on <core_id> at TX", parse_cmd_dump_tx},
1960         {"rx distr start", "", "Start gathering statistical distribution of received packets", parse_cmd_rx_distr_start},
1961         {"rx distr stop", "", "Stop gathering statistical distribution of received packets", parse_cmd_rx_distr_stop},
1962         {"rx distr reset", "", "Reset gathered statistical distribution of received packets", parse_cmd_rx_distr_reset},
1963         {"rx distr show", "", "Display gathered statistical distribution of received packets", parse_cmd_rx_distr_show},
1964         {"tx distr start", "", "Start gathering statistical distribution of xmitted packets", parse_cmd_tx_distr_start},
1965         {"tx distr stop", "", "Stop gathering statistical distribution of xmitted packets", parse_cmd_tx_distr_stop},
1966         {"tx distr reset", "", "Reset gathered statistical distribution of xmitted packets", parse_cmd_tx_distr_reset},
1967         {"tx distr show", "", "Display gathered statistical distribution of xmitted packets", parse_cmd_tx_distr_show},
1968
1969         {"rate", "<port id> <queue id> <rate>", "rate does not include preamble, SFD and IFG", parse_cmd_rate},
1970         {"count","<core id> <task id> <count>", "Generate <count> packets", parse_cmd_count},
1971         {"bypass", "<core_id> <task_id>", "Bypass task", parse_cmd_bypass},
1972         {"reconnect", "<core_id> <task_id>", "Reconnect task", parse_cmd_reconnect},
1973         {"pkt_size", "<core_id> <task_id> <pkt_size>", "Set the packet size to <pkt_size>", parse_cmd_pkt_size},
1974         {"speed", "<core_id> <task_id> <speed percentage>", "Change the speed to <speed percentage> at which packets are being generated on core <core_id> in task <task_id>.", parse_cmd_speed},
1975         {"speed_byte", "<core_id> <task_id> <speed>", "Change speed to <speed>. The speed is specified in units of bytes per second.", parse_cmd_speed_byte},
1976         {"set value", "<core_id> <task_id> <offset> <value> <value_len>", "Set <value_len> bytes to <value> at offset <offset> in packets generated on <core_id> <task_id>", parse_cmd_set_value},
1977         {"set random", "<core_id> <task_id> <offset> <random_str> <value_len>", "Set <value_len> bytes to <rand_str> at offset <offset> in packets generated on <core_id> <task_id>", parse_cmd_set_random},
1978         {"reset values all", "", "Undo all \"set value\" commands on all cores/tasks", parse_cmd_reset_values_all},
1979         {"reset randoms all", "", "Undo all \"set random\" commands on all cores/tasks", parse_cmd_reset_randoms_all},
1980         {"reset values", "<core id> <task id>", "Undo all \"set value\" commands on specified core/task", parse_cmd_reset_values},
1981
1982         {"arp add", "<core id> <task id> <port id> <gre id> <svlan> <cvlan> <ip addr> <mac addr> <user>", "Add a single ARP entry into a CPE table on <core id>/<task id>.", parse_cmd_arp_add},
1983         {"rule add", "<core id> <task id> svlan_id&mask cvlan_id&mask ip_proto&mask source_ip/prefix destination_ip/prefix range dport_range action", "Add a rule to the ACL table on <core id>/<task id>", parse_cmd_rule_add},
1984         {"route add", "<core id> <task id> <ip/prefix> <next hop id>", "Add a route to the routing table on core <core id> <task id>. Example: route add 10.0.16.0/24 9", parse_cmd_route_add},
1985         {"gateway ip", "<core id> <task id> <ip>", "Define/Change IP address of destination gateway on core <core id> <task id>.", parse_cmd_gateway_ip},
1986         {"local ip", "<core id> <task id> <ip>", "Define/Change IP address of destination gateway on core <core id> <task id>.", parse_cmd_local_ip},
1987
1988         {"pps unit", "", "Change core stats pps unit", parse_cmd_pps_unit},
1989         {"reset stats", "", "Reset all statistics", parse_cmd_reset_stats},
1990         {"reset lat stats", "", "Reset all latency statistics", parse_cmd_reset_lat_stats},
1991         {"tot stats", "", "Print total RX and TX packets", parse_cmd_tot_stats},
1992         {"tot ierrors tot", "", "Print total number of ierrors since reset", parse_cmd_tot_ierrors_tot},
1993         {"tot imissed tot", "", "Print total number of imissed since reset", parse_cmd_tot_imissed_tot},
1994         {"lat stats", "<core id> <task id>", "Print min,max,avg latency as measured during last sampling interval", parse_cmd_lat_stats},
1995         {"irq stats", "<core id> <task id>", "Print irq related infos", parse_cmd_irq},
1996         {"show irq buckets", "<core id> <task id>", "Print irq buckets", parse_cmd_show_irq_buckets},
1997         {"lat packets", "<core id> <task id>", "Print the latency for each of the last set of packets", parse_cmd_lat_packets},
1998         {"accuracy limit", "<core id> <task id> <nsec>", "Only consider latency of packets that were measured with an error no more than <nsec>", parse_cmd_accuracy},
1999         {"core stats", "<core id> <task id>", "Print rx/tx/drop for task <task id> running on core <core id>", parse_cmd_core_stats},
2000         {"dp core stats", "<core id> <task id>", "Print rx/tx/non_dp_rx/non_dp_tx/drop for task <task id> running on core <core id>", parse_cmd_dp_core_stats},
2001         {"port_stats", "<port id>", "Print rate for no_mbufs, ierrors + imissed, rx_bytes, tx_bytes, rx_pkts, tx_pkts; totals for RX, TX, no_mbufs, ierrors + imissed for port <port id>", parse_cmd_port_stats},
2002         {"multi port stats", "<port list>", "Get stats for multiple ports, semi-colon separated: port id, total for rx_pkts, tx_pkts, no_mbufs, ierrors + imissed, last_tsc", parse_cmd_multi_port_stats},
2003         {"read reg", "", "Read register", parse_cmd_read_reg},
2004         {"write reg", "", "Read register", parse_cmd_write_reg},
2005         {"set vlan offload", "", "Set Vlan offload", parse_cmd_set_vlan_offload},
2006         {"set vlan filter", "", "Set Vlan filter", parse_cmd_set_vlan_filter},
2007         {"reset cache", "", "Reset cache", parse_cmd_cache_reset},
2008         {"set cache class mask", "<core id> <class> <mask>", "Set cache class mask for <core id>", parse_cmd_set_cache_class_mask},
2009         {"get cache class mask", "<core id> <class>", "Get cache class mask", parse_cmd_get_cache_class_mask},
2010         {"set cache class", "<core id> <class>", "Set cache class", parse_cmd_set_cache_class},
2011         {"get cache class", "<core id>", "Get cache class", parse_cmd_get_cache_class},
2012         {"get cache mask", "<core id>", "Get cache mask", parse_cmd_get_cache_mask},
2013         {"reset port", "", "Reset port", parse_cmd_reset_port},
2014         {"ring info all", "", "Get information about ring, such as ring size and number of elements in the ring", parse_cmd_ring_info_all},
2015         {"ring info", "<core id> <task id>", "Get information about ring on core <core id> in task <task id>, such as ring size and number of elements in the ring", parse_cmd_ring_info},
2016         {"port info", "<port id> [brief?]", "Get port related information, such as MAC address, socket, number of descriptors..., . Adding \"brief\" after command prints short version of output.", parse_cmd_port_info},
2017         {"port up", "<port id>", "Set the port up", parse_cmd_port_up},
2018         {"port down", "<port id>", "Set the port down", parse_cmd_port_down},
2019         {"port link state", "<port id>", "Get link state (up or down) for port", parse_cmd_port_link_state},
2020         {"port xstats", "<port id>", "Get extra statistics for the port", parse_cmd_xstats},
2021         {"stats", "<stats_path>", "Get stats as specified by <stats_path>. A comma-separated list of <stats_path> can be supplied", parse_cmd_stats},
2022         {"cgnat dump public hash", "<core id> <task id>", "Dump cgnat public hash table", parse_cmd_cgnat_public_hash},
2023         {"cgnat dump private hash", "<core id> <task id>", "Dump cgnat private hash table", parse_cmd_cgnat_private_hash},
2024         {"delay_us", "<core_id> <task_id> <delay_us>", "Set the delay in usec for the impair mode to <delay_us>", parse_cmd_delay_us},
2025         {"random delay_us", "<core_id> <task_id> <random delay_us>", "Set the delay in usec for the impair mode to <random delay_us>", parse_cmd_random_delay_us},
2026         {"probability", "<core_id> <task_id> <probability>", "Set the percent of forwarded packets for the impair mode", parse_cmd_set_probability},
2027         {"version", "", "Show version", parse_cmd_version},
2028         {0,0,0,0},
2029 };
2030
2031 static int parse_cmd_help(const char *str, struct input *input)
2032 {
2033         /* str contains the arguments, all commands that have str as a
2034            substring will be shown. */
2035         size_t len, len2, longest_cmd = 0;
2036         for (size_t i = 0; i < cmd_parser_n_cmd(); ++i) {
2037                 if (longest_cmd <strlen(cmd_strings[i].cmd))
2038                         longest_cmd = strlen(cmd_strings[i].cmd);
2039         }
2040         /* A single call to log will be executed after the help string
2041            has been built. The reason for this is to make use of the
2042            built-in pager. */
2043         char buf[32768] = {0};
2044
2045         for (size_t i = 0; i < cmd_parser_n_cmd(); ++i) {
2046                 int is_substr = 0;
2047                 const size_t cmd_len = strlen(cmd_strings[i].cmd);
2048                 for (size_t j = 0; j < cmd_len; ++j) {
2049                         is_substr = 1;
2050                         for (size_t k = 0; k < strlen(str); ++k) {
2051                                 if (str[k] != (cmd_strings[i].cmd + j)[k]) {
2052                                         is_substr = 0;
2053                                         break;
2054                                 }
2055                         }
2056                         if (is_substr)
2057                                 break;
2058                 }
2059                 if (!is_substr)
2060                         continue;
2061
2062                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", cmd_strings[i].cmd);
2063                 len = strlen(cmd_strings[i].cmd);
2064                 while (len < longest_cmd) {
2065                         len++;
2066                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " ");
2067                 }
2068
2069                 if (strlen(cmd_strings[i].args)) {
2070                         char tmp[256] = {0};
2071                         strncpy(tmp, cmd_strings[i].args, 128);
2072                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "Arguments: %s\n", tmp);
2073                         len2 = len;
2074                         if (strlen(cmd_strings[i].help)) {
2075                                 while (len2) {
2076                                         len2--;
2077                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " ");
2078                                 }
2079                         }
2080                 }
2081
2082                 if (strlen(cmd_strings[i].help)) {
2083                         int add = 0;
2084                         const char *h = cmd_strings[i].help;
2085                         do {
2086                                 if (add) {
2087                                         len2 = len;
2088                                         while (len2) {
2089                                                 len2--;
2090                                                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " ");
2091                                         }
2092                                 }
2093                                 char tmp[128] = {0};
2094                                 const size_t max_len = strlen(h) > 80? 80 : strlen(h);
2095                                 size_t len3 = max_len;
2096                                 if (len3 == 80) {
2097                                         while (len3 && h[len3] != ' ')
2098                                                 len3--;
2099                                         if (len3 == 0)
2100                                                 len3 = max_len;
2101                                 }
2102
2103                                 strncpy(tmp, h, len3);
2104                                 h += len3;
2105                                 while (h[0] == ' ' && strlen(h))
2106                                         h++;
2107
2108                                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s\n", tmp);
2109                                 add = 1;
2110                         } while(strlen(h));
2111                 }
2112                 if (strlen(cmd_strings[i].help) == 0&& strlen(cmd_strings[i].args) == 0) {
2113                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
2114                 }
2115         }
2116         plog_info("%s", buf);
2117
2118         return 0;
2119 }
2120
2121 const char *cmd_parser_cmd(size_t i)
2122 {
2123         i = i < cmd_parser_n_cmd()? i: cmd_parser_n_cmd();
2124         return cmd_strings[i].cmd;
2125 }
2126
2127 size_t cmd_parser_n_cmd(void)
2128 {
2129         return sizeof(cmd_strings)/sizeof(cmd_strings[0]) - 1;
2130 }
2131
2132 void cmd_parser_parse(const char *str, struct input *input)
2133 {
2134         size_t skip;
2135
2136         for (size_t i = 0; i < cmd_parser_n_cmd(); ++i) {
2137                 skip = strlen(cmd_strings[i].cmd);
2138                 if (strncmp(cmd_strings[i].cmd, str, skip) == 0 &&
2139                     (str[skip] == ' ' || str[skip] == 0)) {
2140                         while (str[skip] == ' ')
2141                                 skip++;
2142
2143                         if (cmd_strings[i].parse(str + skip, input) != 0) {
2144                                 plog_warn("Invalid syntax for command '%s': %s %s\n",
2145                                           cmd_strings[i].cmd, cmd_strings[i].args, cmd_strings[i].help);
2146                         }
2147                         return ;
2148                 }
2149         }
2150
2151         plog_err("Unknown command: '%s'\n", str);
2152 }