New upstream version 18.08
[deb_dpdk.git] / examples / ip_pipeline / cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <rte_common.h>
11 #include <rte_cycles.h>
12 #include <rte_ethdev.h>
13
14 #include "cli.h"
15 #include "kni.h"
16 #include "link.h"
17 #include "mempool.h"
18 #include "parser.h"
19 #include "pipeline.h"
20 #include "swq.h"
21 #include "tap.h"
22 #include "thread.h"
23 #include "tmgr.h"
24
25 #ifndef CMD_MAX_TOKENS
26 #define CMD_MAX_TOKENS     256
27 #endif
28
29 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
30 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
31 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
32 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
33 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
34 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
35 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
36 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
37 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
38 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
39 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
40
41 static int
42 is_comment(char *in)
43 {
44         if ((strlen(in) && index("!#%;", in[0])) ||
45                 (strncmp(in, "//", 2) == 0) ||
46                 (strncmp(in, "--", 2) == 0))
47                 return 1;
48
49         return 0;
50 }
51
52 static const char cmd_mempool_help[] =
53 "mempool <mempool_name>\n"
54 "   buffer <buffer_size>\n"
55 "   pool <pool_size>\n"
56 "   cache <cache_size>\n"
57 "   cpu <cpu_id>\n";
58
59 static void
60 cmd_mempool(char **tokens,
61         uint32_t n_tokens,
62         char *out,
63         size_t out_size)
64 {
65         struct mempool_params p;
66         char *name;
67         struct mempool *mempool;
68
69         if (n_tokens != 10) {
70                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
71                 return;
72         }
73
74         name = tokens[1];
75
76         if (strcmp(tokens[2], "buffer") != 0) {
77                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
78                 return;
79         }
80
81         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
82                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
83                 return;
84         }
85
86         if (strcmp(tokens[4], "pool") != 0) {
87                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
88                 return;
89         }
90
91         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
92                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
93                 return;
94         }
95
96         if (strcmp(tokens[6], "cache") != 0) {
97                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
98                 return;
99         }
100
101         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
102                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
103                 return;
104         }
105
106         if (strcmp(tokens[8], "cpu") != 0) {
107                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
108                 return;
109         }
110
111         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
112                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
113                 return;
114         }
115
116         mempool = mempool_create(name, &p);
117         if (mempool == NULL) {
118                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
119                 return;
120         }
121 }
122
123 static const char cmd_link_help[] =
124 "link <link_name>\n"
125 "   dev <device_name> | port <port_id>\n"
126 "   rxq <n_queues> <queue_size> <mempool_name>\n"
127 "   txq <n_queues> <queue_size>\n"
128 "   promiscuous on | off\n"
129 "   [rss <qid_0> ... <qid_n>]\n";
130
131 static void
132 cmd_link(char **tokens,
133         uint32_t n_tokens,
134         char *out,
135         size_t out_size)
136 {
137         struct link_params p;
138         struct link_params_rss rss;
139         struct link *link;
140         char *name;
141
142         memset(&p, 0, sizeof(p));
143
144         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
145                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
146                 return;
147         }
148         name = tokens[1];
149
150         if (strcmp(tokens[2], "dev") == 0)
151                 p.dev_name = tokens[3];
152         else if (strcmp(tokens[2], "port") == 0) {
153                 p.dev_name = NULL;
154
155                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
156                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
157                         return;
158                 }
159         } else {
160                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
161                 return;
162         }
163
164         if (strcmp(tokens[4], "rxq") != 0) {
165                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
166                 return;
167         }
168
169         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
170                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
171                 return;
172         }
173         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
174                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
175                 return;
176         }
177
178         p.rx.mempool_name = tokens[7];
179
180         if (strcmp(tokens[8], "txq") != 0) {
181                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
182                 return;
183         }
184
185         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
186                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
187                 return;
188         }
189
190         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
191                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
192                 return;
193         }
194
195         if (strcmp(tokens[11], "promiscuous") != 0) {
196                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
197                 return;
198         }
199
200         if (strcmp(tokens[12], "on") == 0)
201                 p.promiscuous = 1;
202         else if (strcmp(tokens[12], "off") == 0)
203                 p.promiscuous = 0;
204         else {
205                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
206                 return;
207         }
208
209         /* RSS */
210         p.rx.rss = NULL;
211         if (n_tokens > 13) {
212                 uint32_t queue_id, i;
213
214                 if (strcmp(tokens[13], "rss") != 0) {
215                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
216                         return;
217                 }
218
219                 p.rx.rss = &rss;
220
221                 rss.n_queues = 0;
222                 for (i = 14; i < n_tokens; i++) {
223                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
224                                 snprintf(out, out_size, MSG_ARG_INVALID,
225                                         "queue_id");
226                                 return;
227                         }
228
229                         rss.queue_id[rss.n_queues] = queue_id;
230                         rss.n_queues++;
231                 }
232         }
233
234         link = link_create(name, &p);
235         if (link == NULL) {
236                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
237                 return;
238         }
239 }
240
241 /* Print the link stats and info */
242 static void
243 print_link_info(struct link *link, char *out, size_t out_size)
244 {
245         struct rte_eth_stats stats;
246         struct ether_addr mac_addr;
247         struct rte_eth_link eth_link;
248         uint16_t mtu;
249
250         memset(&stats, 0, sizeof(stats));
251         rte_eth_stats_get(link->port_id, &stats);
252
253         rte_eth_macaddr_get(link->port_id, &mac_addr);
254         rte_eth_link_get(link->port_id, &eth_link);
255         rte_eth_dev_get_mtu(link->port_id, &mtu);
256
257         snprintf(out, out_size,
258                 "\n"
259                 "%s: flags=<%s> mtu %u\n"
260                 "\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n"
261                 "\tport# %u  speed %u Mbps\n"
262                 "\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
263                 "\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
264                 "\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
265                 "\tTX errors %" PRIu64"\n",
266                 link->name,
267                 eth_link.link_status == 0 ? "DOWN" : "UP",
268                 mtu,
269                 mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
270                 mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
271                 mac_addr.addr_bytes[4], mac_addr.addr_bytes[5],
272                 link->n_rxq,
273                 link->n_txq,
274                 link->port_id,
275                 eth_link.link_speed,
276                 stats.ipackets,
277                 stats.ibytes,
278                 stats.ierrors,
279                 stats.imissed,
280                 stats.rx_nombuf,
281                 stats.opackets,
282                 stats.obytes,
283                 stats.oerrors);
284 }
285
286 /*
287  * link show [<link_name>]
288  */
289 static void
290 cmd_link_show(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
291 {
292         struct link *link;
293         char *link_name;
294
295         if (n_tokens != 2 && n_tokens != 3) {
296                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
297                 return;
298         }
299
300         if (n_tokens == 2) {
301                 link = link_next(NULL);
302
303                 while (link != NULL) {
304                         out_size = out_size - strlen(out);
305                         out = &out[strlen(out)];
306
307                         print_link_info(link, out, out_size);
308                         link = link_next(link);
309                 }
310         } else {
311                 out_size = out_size - strlen(out);
312                 out = &out[strlen(out)];
313
314                 link_name = tokens[2];
315                 link = link_find(link_name);
316
317                 if (link == NULL) {
318                         snprintf(out, out_size, MSG_ARG_INVALID,
319                                         "Link does not exist");
320                         return;
321                 }
322                 print_link_info(link, out, out_size);
323         }
324 }
325
326 static const char cmd_swq_help[] =
327 "swq <swq_name>\n"
328 "   size <size>\n"
329 "   cpu <cpu_id>\n";
330
331 static void
332 cmd_swq(char **tokens,
333         uint32_t n_tokens,
334         char *out,
335         size_t out_size)
336 {
337         struct swq_params p;
338         char *name;
339         struct swq *swq;
340
341         if (n_tokens != 6) {
342                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
343                 return;
344         }
345
346         name = tokens[1];
347
348         if (strcmp(tokens[2], "size") != 0) {
349                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
350                 return;
351         }
352
353         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
354                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
355                 return;
356         }
357
358         if (strcmp(tokens[4], "cpu") != 0) {
359                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
360                 return;
361         }
362
363         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
364                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
365                 return;
366         }
367
368         swq = swq_create(name, &p);
369         if (swq == NULL) {
370                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
371                 return;
372         }
373 }
374
375 static const char cmd_tmgr_subport_profile_help[] =
376 "tmgr subport profile\n"
377 "   <tb_rate> <tb_size>\n"
378 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
379 "   <tc_period>\n";
380
381 static void
382 cmd_tmgr_subport_profile(char **tokens,
383         uint32_t n_tokens,
384         char *out,
385         size_t out_size)
386 {
387         struct rte_sched_subport_params p;
388         int status, i;
389
390         if (n_tokens != 10) {
391                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
392                 return;
393         }
394
395         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
396                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
397                 return;
398         }
399
400         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
401                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
402                 return;
403         }
404
405         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
406                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
407                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
408                         return;
409                 }
410
411         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
412                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
413                 return;
414         }
415
416         status = tmgr_subport_profile_add(&p);
417         if (status != 0) {
418                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
419                 return;
420         }
421 }
422
423 static const char cmd_tmgr_pipe_profile_help[] =
424 "tmgr pipe profile\n"
425 "   <tb_rate> <tb_size>\n"
426 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
427 "   <tc_period>\n"
428 "   <tc_ov_weight>\n"
429 "   <wrr_weight0..15>\n";
430
431 static void
432 cmd_tmgr_pipe_profile(char **tokens,
433         uint32_t n_tokens,
434         char *out,
435         size_t out_size)
436 {
437         struct rte_sched_pipe_params p;
438         int status, i;
439
440         if (n_tokens != 27) {
441                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
442                 return;
443         }
444
445         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
446                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
447                 return;
448         }
449
450         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
451                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
452                 return;
453         }
454
455         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
456                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
457                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
458                         return;
459                 }
460
461         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
462                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
463                 return;
464         }
465
466 #ifdef RTE_SCHED_SUBPORT_TC_OV
467         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
468                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
469                 return;
470         }
471 #endif
472
473         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
474                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
475                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
476                         return;
477                 }
478
479         status = tmgr_pipe_profile_add(&p);
480         if (status != 0) {
481                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
482                 return;
483         }
484 }
485
486 static const char cmd_tmgr_help[] =
487 "tmgr <tmgr_name>\n"
488 "   rate <rate>\n"
489 "   spp <n_subports_per_port>\n"
490 "   pps <n_pipes_per_subport>\n"
491 "   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>\n"
492 "   fo <frame_overhead>\n"
493 "   mtu <mtu>\n"
494 "   cpu <cpu_id>\n";
495
496 static void
497 cmd_tmgr(char **tokens,
498         uint32_t n_tokens,
499         char *out,
500         size_t out_size)
501 {
502         struct tmgr_port_params p;
503         char *name;
504         struct tmgr_port *tmgr_port;
505         int i;
506
507         if (n_tokens != 19) {
508                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
509                 return;
510         }
511
512         name = tokens[1];
513
514         if (strcmp(tokens[2], "rate") != 0) {
515                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
516                 return;
517         }
518
519         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
520                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
521                 return;
522         }
523
524         if (strcmp(tokens[4], "spp") != 0) {
525                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
526                 return;
527         }
528
529         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
530                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
531                 return;
532         }
533
534         if (strcmp(tokens[6], "pps") != 0) {
535                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
536                 return;
537         }
538
539         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
540                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
541                 return;
542         }
543
544         if (strcmp(tokens[8], "qsize") != 0) {
545                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
546                 return;
547         }
548
549         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
550                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
551                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
552                         return;
553                 }
554
555         if (strcmp(tokens[13], "fo") != 0) {
556                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
557                 return;
558         }
559
560         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
561                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
562                 return;
563         }
564
565         if (strcmp(tokens[15], "mtu") != 0) {
566                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
567                 return;
568         }
569
570         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
571                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
572                 return;
573         }
574
575         if (strcmp(tokens[17], "cpu") != 0) {
576                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
577                 return;
578         }
579
580         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
581                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
582                 return;
583         }
584
585         tmgr_port = tmgr_port_create(name, &p);
586         if (tmgr_port == NULL) {
587                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
588                 return;
589         }
590 }
591
592 static const char cmd_tmgr_subport_help[] =
593 "tmgr <tmgr_name> subport <subport_id>\n"
594 "   profile <subport_profile_id>\n";
595
596 static void
597 cmd_tmgr_subport(char **tokens,
598         uint32_t n_tokens,
599         char *out,
600         size_t out_size)
601 {
602         uint32_t subport_id, subport_profile_id;
603         int status;
604         char *name;
605
606         if (n_tokens != 6) {
607                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
608                 return;
609         }
610
611         name = tokens[1];
612
613         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
614                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
615                 return;
616         }
617
618         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
619                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
620                 return;
621         }
622
623         status = tmgr_subport_config(name, subport_id, subport_profile_id);
624         if (status) {
625                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
626                 return;
627         }
628 }
629
630
631 static const char cmd_tmgr_subport_pipe_help[] =
632 "tmgr <tmgr_name> subport <subport_id> pipe\n"
633 "   from <pipe_id_first> to <pipe_id_last>\n"
634 "   profile <pipe_profile_id>\n";
635
636 static void
637 cmd_tmgr_subport_pipe(char **tokens,
638         uint32_t n_tokens,
639         char *out,
640         size_t out_size)
641 {
642         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
643         int status;
644         char *name;
645
646         if (n_tokens != 11) {
647                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
648                 return;
649         }
650
651         name = tokens[1];
652
653         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
654                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
655                 return;
656         }
657
658         if (strcmp(tokens[4], "pipe") != 0) {
659                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
660                 return;
661         }
662
663         if (strcmp(tokens[5], "from") != 0) {
664                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
665                 return;
666         }
667
668         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
669                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
670                 return;
671         }
672
673         if (strcmp(tokens[7], "to") != 0) {
674                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
675                 return;
676         }
677
678         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
679                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
680                 return;
681         }
682
683         if (strcmp(tokens[9], "profile") != 0) {
684                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
685                 return;
686         }
687
688         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
689                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
690                 return;
691         }
692
693         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
694                         pipe_id_last, pipe_profile_id);
695         if (status) {
696                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
697                 return;
698         }
699 }
700
701
702 static const char cmd_tap_help[] =
703 "tap <tap_name>\n";
704
705 static void
706 cmd_tap(char **tokens,
707         uint32_t n_tokens,
708         char *out,
709         size_t out_size)
710 {
711         char *name;
712         struct tap *tap;
713
714         if (n_tokens != 2) {
715                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
716                 return;
717         }
718
719         name = tokens[1];
720
721         tap = tap_create(name);
722         if (tap == NULL) {
723                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
724                 return;
725         }
726 }
727
728 static const char cmd_kni_help[] =
729 "kni <kni_name>\n"
730 "   link <link_name>\n"
731 "   mempool <mempool_name>\n"
732 "   [thread <thread_id>]\n";
733
734 static void
735 cmd_kni(char **tokens,
736         uint32_t n_tokens,
737         char *out,
738         size_t out_size)
739 {
740         struct kni_params p;
741         char *name;
742         struct kni *kni;
743
744         memset(&p, 0, sizeof(p));
745         if ((n_tokens != 6) && (n_tokens != 8)) {
746                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
747                 return;
748         }
749
750         name = tokens[1];
751
752         if (strcmp(tokens[2], "link") != 0) {
753                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
754                 return;
755         }
756
757         p.link_name = tokens[3];
758
759         if (strcmp(tokens[4], "mempool") != 0) {
760                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
761                 return;
762         }
763
764         p.mempool_name = tokens[5];
765
766         if (n_tokens == 8) {
767                 if (strcmp(tokens[6], "thread") != 0) {
768                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
769                         return;
770                 }
771
772                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
773                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
774                         return;
775                 }
776
777                 p.force_bind = 1;
778         } else
779                 p.force_bind = 0;
780
781         kni = kni_create(name, &p);
782         if (kni == NULL) {
783                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
784                 return;
785         }
786 }
787
788
789 static const char cmd_port_in_action_profile_help[] =
790 "port in action profile <profile_name>\n"
791 "   [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]\n"
792 "   [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]\n";
793
794 static void
795 cmd_port_in_action_profile(char **tokens,
796         uint32_t n_tokens,
797         char *out,
798         size_t out_size)
799 {
800         struct port_in_action_profile_params p;
801         struct port_in_action_profile *ap;
802         char *name;
803         uint32_t t0;
804
805         memset(&p, 0, sizeof(p));
806
807         if (n_tokens < 5) {
808                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
809                 return;
810         }
811
812         if (strcmp(tokens[1], "in") != 0) {
813                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
814                 return;
815         }
816
817         if (strcmp(tokens[2], "action") != 0) {
818                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
819                 return;
820         }
821
822         if (strcmp(tokens[3], "profile") != 0) {
823                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
824                 return;
825         }
826
827         name = tokens[4];
828
829         t0 = 5;
830
831         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
832                 uint32_t size;
833
834                 if (n_tokens < t0 + 10) {
835                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
836                         return;
837                 }
838
839                 if (strcmp(tokens[t0 + 1], "match") == 0)
840                         p.fltr.filter_on_match = 1;
841                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
842                         p.fltr.filter_on_match = 0;
843                 else {
844                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
845                         return;
846                 }
847
848                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
849                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
850                         return;
851                 }
852
853                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
854                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
855                         return;
856                 }
857
858                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
859                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
860                         return;
861                 }
862
863                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
864                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
865                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
866                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
867                         return;
868                 }
869
870                 if (strcmp(tokens[t0 + 6], "key") != 0) {
871                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
872                         return;
873                 }
874
875                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
876                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
877                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
878                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
879                         return;
880                 }
881
882                 if (strcmp(tokens[t0 + 8], "port") != 0) {
883                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
884                         return;
885                 }
886
887                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
888                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
889                         return;
890                 }
891
892                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
893                 t0 += 10;
894         } /* filter */
895
896         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
897                 uint32_t i;
898
899                 if (n_tokens < t0 + 22) {
900                         snprintf(out, out_size, MSG_ARG_MISMATCH,
901                                 "port in action profile balance");
902                         return;
903                 }
904
905                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
906                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
907                         return;
908                 }
909
910                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
911                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
912                         return;
913                 }
914
915                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
916                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
917                         return;
918                 }
919
920                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
921                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
922                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
923                         return;
924                 }
925
926                 if (strcmp(tokens[t0 + 5], "port") != 0) {
927                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
928                         return;
929                 }
930
931                 for (i = 0; i < 16; i++)
932                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
933                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
934                                 return;
935                         }
936
937                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
938                 t0 += 22;
939         } /* balance */
940
941         if (t0 < n_tokens) {
942                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
943                 return;
944         }
945
946         ap = port_in_action_profile_create(name, &p);
947         if (ap == NULL) {
948                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
949                 return;
950         }
951 }
952
953
954 static const char cmd_table_action_profile_help[] =
955 "table action profile <profile_name>\n"
956 "   ipv4 | ipv6\n"
957 "   offset <ip_offset>\n"
958 "   fwd\n"
959 "   [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]\n"
960 "   [meter srtcm | trtcm\n"
961 "       tc <n_tc>\n"
962 "       stats none | pkts | bytes | both]\n"
963 "   [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]\n"
964 "   [encap ether | vlan | qinq | mpls | pppoe]\n"
965 "   [nat src | dst\n"
966 "       proto udp | tcp]\n"
967 "   [ttl drop | fwd\n"
968 "       stats none | pkts]\n"
969 "   [stats pkts | bytes | both]\n"
970 "   [time]\n";
971
972 static void
973 cmd_table_action_profile(char **tokens,
974         uint32_t n_tokens,
975         char *out,
976         size_t out_size)
977 {
978         struct table_action_profile_params p;
979         struct table_action_profile *ap;
980         char *name;
981         uint32_t t0;
982
983         memset(&p, 0, sizeof(p));
984
985         if (n_tokens < 8) {
986                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
987                 return;
988         }
989
990         if (strcmp(tokens[1], "action") != 0) {
991                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
992                 return;
993         }
994
995         if (strcmp(tokens[2], "profile") != 0) {
996                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
997                 return;
998         }
999
1000         name = tokens[3];
1001
1002         if (strcmp(tokens[4], "ipv4") == 0)
1003                 p.common.ip_version = 1;
1004         else if (strcmp(tokens[4], "ipv6") == 0)
1005                 p.common.ip_version = 0;
1006         else {
1007                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
1008                 return;
1009         }
1010
1011         if (strcmp(tokens[5], "offset") != 0) {
1012                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1013                 return;
1014         }
1015
1016         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
1017                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
1018                 return;
1019         }
1020
1021         if (strcmp(tokens[7], "fwd") != 0) {
1022                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
1023                 return;
1024         }
1025
1026         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1027
1028         t0 = 8;
1029         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
1030                 if (n_tokens < t0 + 7) {
1031                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
1032                         return;
1033                 }
1034
1035                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1036                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1037                         return;
1038                 }
1039
1040                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
1041                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1042                         return;
1043                 }
1044
1045                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
1046                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1047                         return;
1048                 }
1049
1050                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1051                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
1052                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1053                         return;
1054                 }
1055
1056                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
1057                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
1058                         return;
1059                 }
1060
1061                 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
1062                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
1063                         return;
1064                 }
1065
1066                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
1067                 t0 += 7;
1068         } /* balance */
1069
1070         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
1071                 if (n_tokens < t0 + 6) {
1072                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1073                                 "table action profile meter");
1074                         return;
1075                 }
1076
1077                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
1078                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
1079                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
1080                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
1081                 else {
1082                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1083                                 "srtcm or trtcm");
1084                         return;
1085                 }
1086
1087                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
1088                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
1089                         return;
1090                 }
1091
1092                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
1093                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1094                         return;
1095                 }
1096
1097                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
1098                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1099                         return;
1100                 }
1101
1102                 if (strcmp(tokens[t0 + 5], "none") == 0) {
1103                         p.mtr.n_packets_enabled = 0;
1104                         p.mtr.n_bytes_enabled = 0;
1105                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1106                         p.mtr.n_packets_enabled = 1;
1107                         p.mtr.n_bytes_enabled = 0;
1108                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1109                         p.mtr.n_packets_enabled = 0;
1110                         p.mtr.n_bytes_enabled = 1;
1111                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
1112                         p.mtr.n_packets_enabled = 1;
1113                         p.mtr.n_bytes_enabled = 1;
1114                 } else {
1115                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1116                                 "none or pkts or bytes or both");
1117                         return;
1118                 }
1119
1120                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1121                 t0 += 6;
1122         } /* meter */
1123
1124         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
1125                 if (n_tokens < t0 + 5) {
1126                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1127                                 "table action profile tm");
1128                         return;
1129                 }
1130
1131                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
1132                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1133                         return;
1134                 }
1135
1136                 if (parser_read_uint32(&p.tm.n_subports_per_port,
1137                         tokens[t0 + 2]) != 0) {
1138                         snprintf(out, out_size, MSG_ARG_INVALID,
1139                                 "n_subports_per_port");
1140                         return;
1141                 }
1142
1143                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1144                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1145                         return;
1146                 }
1147
1148                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1149                         tokens[t0 + 4]) != 0) {
1150                         snprintf(out, out_size, MSG_ARG_INVALID,
1151                                 "n_pipes_per_subport");
1152                         return;
1153                 }
1154
1155                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1156                 t0 += 5;
1157         } /* tm */
1158
1159         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1160                 if (n_tokens < t0 + 2) {
1161                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1162                                 "action profile encap");
1163                         return;
1164                 }
1165
1166                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1167                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1168                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1169                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1170                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1171                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1172                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1173                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1174                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1175                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1176                 else {
1177                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1178                         return;
1179                 }
1180
1181                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1182                 t0 += 2;
1183         } /* encap */
1184
1185         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1186                 if (n_tokens < t0 + 4) {
1187                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1188                                 "table action profile nat");
1189                         return;
1190                 }
1191
1192                 if (strcmp(tokens[t0 + 1], "src") == 0)
1193                         p.nat.source_nat = 1;
1194                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1195                         p.nat.source_nat = 0;
1196                 else {
1197                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1198                                 "src or dst");
1199                         return;
1200                 }
1201
1202                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1203                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1204                         return;
1205                 }
1206
1207                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1208                         p.nat.proto = 0x06;
1209                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1210                         p.nat.proto = 0x11;
1211                 else {
1212                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1213                                 "tcp or udp");
1214                         return;
1215                 }
1216
1217                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1218                 t0 += 4;
1219         } /* nat */
1220
1221         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1222                 if (n_tokens < t0 + 4) {
1223                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1224                                 "table action profile ttl");
1225                         return;
1226                 }
1227
1228                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1229                         p.ttl.drop = 1;
1230                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1231                         p.ttl.drop = 0;
1232                 else {
1233                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1234                                 "drop or fwd");
1235                         return;
1236                 }
1237
1238                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1239                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1240                         return;
1241                 }
1242
1243                 if (strcmp(tokens[t0 + 3], "none") == 0)
1244                         p.ttl.n_packets_enabled = 0;
1245                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1246                         p.ttl.n_packets_enabled = 1;
1247                 else {
1248                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1249                                 "none or pkts");
1250                         return;
1251                 }
1252
1253                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1254                 t0 += 4;
1255         } /* ttl */
1256
1257         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1258                 if (n_tokens < t0 + 2) {
1259                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1260                                 "table action profile stats");
1261                         return;
1262                 }
1263
1264                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1265                         p.stats.n_packets_enabled = 1;
1266                         p.stats.n_bytes_enabled = 0;
1267                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1268                         p.stats.n_packets_enabled = 0;
1269                         p.stats.n_bytes_enabled = 1;
1270                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1271                         p.stats.n_packets_enabled = 1;
1272                         p.stats.n_bytes_enabled = 1;
1273                 } else {
1274                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1275                                 "pkts or bytes or both");
1276                         return;
1277                 }
1278
1279                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1280                 t0 += 2;
1281         } /* stats */
1282
1283         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1284                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1285                 t0 += 1;
1286         } /* time */
1287
1288         if (t0 < n_tokens) {
1289                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1290                 return;
1291         }
1292
1293         ap = table_action_profile_create(name, &p);
1294         if (ap == NULL) {
1295                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1296                 return;
1297         }
1298 }
1299
1300 static const char cmd_pipeline_help[] =
1301 "pipeline <pipeline_name>\n"
1302 "   period <timer_period_ms>\n"
1303 "   offset_port_id <offset_port_id>\n"
1304 "   cpu <cpu_id>\n";
1305
1306 static void
1307 cmd_pipeline(char **tokens,
1308         uint32_t n_tokens,
1309         char *out,
1310         size_t out_size)
1311 {
1312         struct pipeline_params p;
1313         char *name;
1314         struct pipeline *pipeline;
1315
1316         if (n_tokens != 8) {
1317                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1318                 return;
1319         }
1320
1321         name = tokens[1];
1322
1323         if (strcmp(tokens[2], "period") != 0) {
1324                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1325                 return;
1326         }
1327
1328         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1329                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1330                 return;
1331         }
1332
1333         if (strcmp(tokens[4], "offset_port_id") != 0) {
1334                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1335                 return;
1336         }
1337
1338         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1339                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1340                 return;
1341         }
1342
1343         if (strcmp(tokens[6], "cpu") != 0) {
1344                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1345                 return;
1346         }
1347
1348         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1349                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1350                 return;
1351         }
1352
1353         pipeline = pipeline_create(name, &p);
1354         if (pipeline == NULL) {
1355                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1356                 return;
1357         }
1358 }
1359
1360 static const char cmd_pipeline_port_in_help[] =
1361 "pipeline <pipeline_name> port in\n"
1362 "   bsz <burst_size>\n"
1363 "   link <link_name> rxq <queue_id>\n"
1364 "   | swq <swq_name>\n"
1365 "   | tmgr <tmgr_name>\n"
1366 "   | tap <tap_name> mempool <mempool_name> mtu <mtu>\n"
1367 "   | kni <kni_name>\n"
1368 "   | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>\n"
1369 "   [action <port_in_action_profile_name>]\n"
1370 "   [disabled]\n";
1371
1372 static void
1373 cmd_pipeline_port_in(char **tokens,
1374         uint32_t n_tokens,
1375         char *out,
1376         size_t out_size)
1377 {
1378         struct port_in_params p;
1379         char *pipeline_name;
1380         uint32_t t0;
1381         int enabled, status;
1382
1383         if (n_tokens < 7) {
1384                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1385                 return;
1386         }
1387
1388         pipeline_name = tokens[1];
1389
1390         if (strcmp(tokens[2], "port") != 0) {
1391                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1392                 return;
1393         }
1394
1395         if (strcmp(tokens[3], "in") != 0) {
1396                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1397                 return;
1398         }
1399
1400         if (strcmp(tokens[4], "bsz") != 0) {
1401                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1402                 return;
1403         }
1404
1405         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1406                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1407                 return;
1408         }
1409
1410         t0 = 6;
1411
1412         if (strcmp(tokens[t0], "link") == 0) {
1413                 if (n_tokens < t0 + 4) {
1414                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1415                                 "pipeline port in link");
1416                         return;
1417                 }
1418
1419                 p.type = PORT_IN_RXQ;
1420
1421                 p.dev_name = tokens[t0 + 1];
1422
1423                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1424                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1425                         return;
1426                 }
1427
1428                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1429                         snprintf(out, out_size, MSG_ARG_INVALID,
1430                                 "queue_id");
1431                         return;
1432                 }
1433                 t0 += 4;
1434         } else if (strcmp(tokens[t0], "swq") == 0) {
1435                 if (n_tokens < t0 + 2) {
1436                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1437                                 "pipeline port in swq");
1438                         return;
1439                 }
1440
1441                 p.type = PORT_IN_SWQ;
1442
1443                 p.dev_name = tokens[t0 + 1];
1444
1445                 t0 += 2;
1446         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1447                 if (n_tokens < t0 + 2) {
1448                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1449                                 "pipeline port in tmgr");
1450                         return;
1451                 }
1452
1453                 p.type = PORT_IN_TMGR;
1454
1455                 p.dev_name = tokens[t0 + 1];
1456
1457                 t0 += 2;
1458         } else if (strcmp(tokens[t0], "tap") == 0) {
1459                 if (n_tokens < t0 + 6) {
1460                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1461                                 "pipeline port in tap");
1462                         return;
1463                 }
1464
1465                 p.type = PORT_IN_TAP;
1466
1467                 p.dev_name = tokens[t0 + 1];
1468
1469                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1470                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1471                                 "mempool");
1472                         return;
1473                 }
1474
1475                 p.tap.mempool_name = tokens[t0 + 3];
1476
1477                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1478                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1479                                 "mtu");
1480                         return;
1481                 }
1482
1483                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1484                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1485                         return;
1486                 }
1487
1488                 t0 += 6;
1489         } else if (strcmp(tokens[t0], "kni") == 0) {
1490                 if (n_tokens < t0 + 2) {
1491                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1492                                 "pipeline port in kni");
1493                         return;
1494                 }
1495
1496                 p.type = PORT_IN_KNI;
1497
1498                 p.dev_name = tokens[t0 + 1];
1499
1500                 t0 += 2;
1501         } else if (strcmp(tokens[t0], "source") == 0) {
1502                 if (n_tokens < t0 + 6) {
1503                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1504                                 "pipeline port in source");
1505                         return;
1506                 }
1507
1508                 p.type = PORT_IN_SOURCE;
1509
1510                 p.dev_name = NULL;
1511
1512                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1513                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1514                                 "mempool");
1515                         return;
1516                 }
1517
1518                 p.source.mempool_name = tokens[t0 + 2];
1519
1520                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1521                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1522                                 "file");
1523                         return;
1524                 }
1525
1526                 p.source.file_name = tokens[t0 + 4];
1527
1528                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1529                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1530                                 "bpp");
1531                         return;
1532                 }
1533
1534                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1535                         snprintf(out, out_size, MSG_ARG_INVALID,
1536                                 "n_bytes_per_pkt");
1537                         return;
1538                 }
1539
1540                 t0 += 7;
1541         } else {
1542                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1543                 return;
1544         }
1545
1546         p.action_profile_name = NULL;
1547         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1548                 if (n_tokens < t0 + 2) {
1549                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1550                         return;
1551                 }
1552
1553                 p.action_profile_name = tokens[t0 + 1];
1554
1555                 t0 += 2;
1556         }
1557
1558         enabled = 1;
1559         if ((n_tokens > t0) &&
1560                 (strcmp(tokens[t0], "disabled") == 0)) {
1561                 enabled = 0;
1562
1563                 t0 += 1;
1564         }
1565
1566         if (n_tokens != t0) {
1567                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1568                 return;
1569         }
1570
1571         status = pipeline_port_in_create(pipeline_name,
1572                 &p, enabled);
1573         if (status) {
1574                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1575                 return;
1576         }
1577 }
1578
1579 static const char cmd_pipeline_port_out_help[] =
1580 "pipeline <pipeline_name> port out\n"
1581 "   bsz <burst_size>\n"
1582 "   link <link_name> txq <txq_id>\n"
1583 "   | swq <swq_name>\n"
1584 "   | tmgr <tmgr_name>\n"
1585 "   | tap <tap_name>\n"
1586 "   | kni <kni_name>\n"
1587 "   | sink [file <file_name> pkts <max_n_pkts>]\n";
1588
1589 static void
1590 cmd_pipeline_port_out(char **tokens,
1591         uint32_t n_tokens,
1592         char *out,
1593         size_t out_size)
1594 {
1595         struct port_out_params p;
1596         char *pipeline_name;
1597         int status;
1598
1599         memset(&p, 0, sizeof(p));
1600
1601         if (n_tokens < 7) {
1602                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1603                 return;
1604         }
1605
1606         pipeline_name = tokens[1];
1607
1608         if (strcmp(tokens[2], "port") != 0) {
1609                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1610                 return;
1611         }
1612
1613         if (strcmp(tokens[3], "out") != 0) {
1614                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1615                 return;
1616         }
1617
1618         if (strcmp(tokens[4], "bsz") != 0) {
1619                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1620                 return;
1621         }
1622
1623         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1624                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1625                 return;
1626         }
1627
1628         if (strcmp(tokens[6], "link") == 0) {
1629                 if (n_tokens != 10) {
1630                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1631                                 "pipeline port out link");
1632                         return;
1633                 }
1634
1635                 p.type = PORT_OUT_TXQ;
1636
1637                 p.dev_name = tokens[7];
1638
1639                 if (strcmp(tokens[8], "txq") != 0) {
1640                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1641                         return;
1642                 }
1643
1644                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1645                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1646                         return;
1647                 }
1648         } else if (strcmp(tokens[6], "swq") == 0) {
1649                 if (n_tokens != 8) {
1650                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1651                                 "pipeline port out swq");
1652                         return;
1653                 }
1654
1655                 p.type = PORT_OUT_SWQ;
1656
1657                 p.dev_name = tokens[7];
1658         } else if (strcmp(tokens[6], "tmgr") == 0) {
1659                 if (n_tokens != 8) {
1660                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1661                                 "pipeline port out tmgr");
1662                         return;
1663                 }
1664
1665                 p.type = PORT_OUT_TMGR;
1666
1667                 p.dev_name = tokens[7];
1668         } else if (strcmp(tokens[6], "tap") == 0) {
1669                 if (n_tokens != 8) {
1670                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1671                                 "pipeline port out tap");
1672                         return;
1673                 }
1674
1675                 p.type = PORT_OUT_TAP;
1676
1677                 p.dev_name = tokens[7];
1678         } else if (strcmp(tokens[6], "kni") == 0) {
1679                 if (n_tokens != 8) {
1680                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1681                                 "pipeline port out kni");
1682                         return;
1683                 }
1684
1685                 p.type = PORT_OUT_KNI;
1686
1687                 p.dev_name = tokens[7];
1688         } else if (strcmp(tokens[6], "sink") == 0) {
1689                 if ((n_tokens != 7) && (n_tokens != 11)) {
1690                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1691                                 "pipeline port out sink");
1692                         return;
1693                 }
1694
1695                 p.type = PORT_OUT_SINK;
1696
1697                 p.dev_name = NULL;
1698
1699                 if (n_tokens == 7) {
1700                         p.sink.file_name = NULL;
1701                         p.sink.max_n_pkts = 0;
1702                 } else {
1703                         if (strcmp(tokens[7], "file") != 0) {
1704                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1705                                         "file");
1706                                 return;
1707                         }
1708
1709                         p.sink.file_name = tokens[8];
1710
1711                         if (strcmp(tokens[9], "pkts") != 0) {
1712                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1713                                 return;
1714                         }
1715
1716                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1717                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1718                                 return;
1719                         }
1720                 }
1721         } else {
1722                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1723                 return;
1724         }
1725
1726         status = pipeline_port_out_create(pipeline_name, &p);
1727         if (status) {
1728                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1729                 return;
1730         }
1731 }
1732
1733 static const char cmd_pipeline_table_help[] =
1734 "pipeline <pipeline_name> table\n"
1735 "       match\n"
1736 "       acl\n"
1737 "           ipv4 | ipv6\n"
1738 "           offset <ip_header_offset>\n"
1739 "           size <n_rules>\n"
1740 "       | array\n"
1741 "           offset <key_offset>\n"
1742 "           size <n_keys>\n"
1743 "       | hash\n"
1744 "           ext | lru\n"
1745 "           key <key_size>\n"
1746 "           mask <key_mask>\n"
1747 "           offset <key_offset>\n"
1748 "           buckets <n_buckets>\n"
1749 "           size <n_keys>\n"
1750 "       | lpm\n"
1751 "           ipv4 | ipv6\n"
1752 "           offset <ip_header_offset>\n"
1753 "           size <n_rules>\n"
1754 "       | stub\n"
1755 "   [action <table_action_profile_name>]\n";
1756
1757 static void
1758 cmd_pipeline_table(char **tokens,
1759         uint32_t n_tokens,
1760         char *out,
1761         size_t out_size)
1762 {
1763         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1764         struct table_params p;
1765         char *pipeline_name;
1766         uint32_t t0;
1767         int status;
1768
1769         if (n_tokens < 5) {
1770                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1771                 return;
1772         }
1773
1774         pipeline_name = tokens[1];
1775
1776         if (strcmp(tokens[2], "table") != 0) {
1777                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1778                 return;
1779         }
1780
1781         if (strcmp(tokens[3], "match") != 0) {
1782                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1783                 return;
1784         }
1785
1786         t0 = 4;
1787         if (strcmp(tokens[t0], "acl") == 0) {
1788                 if (n_tokens < t0 + 6) {
1789                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1790                                 "pipeline table acl");
1791                         return;
1792                 }
1793
1794                 p.match_type = TABLE_ACL;
1795
1796                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1797                         p.match.acl.ip_version = 1;
1798                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1799                         p.match.acl.ip_version = 0;
1800                 else {
1801                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1802                                 "ipv4 or ipv6");
1803                         return;
1804                 }
1805
1806                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1807                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1808                         return;
1809                 }
1810
1811                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
1812                         tokens[t0 + 3]) != 0) {
1813                         snprintf(out, out_size, MSG_ARG_INVALID,
1814                                 "ip_header_offset");
1815                         return;
1816                 }
1817
1818                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1819                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1820                         return;
1821                 }
1822
1823                 if (parser_read_uint32(&p.match.acl.n_rules,
1824                         tokens[t0 + 5]) != 0) {
1825                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1826                         return;
1827                 }
1828
1829                 t0 += 6;
1830         } else if (strcmp(tokens[t0], "array") == 0) {
1831                 if (n_tokens < t0 + 5) {
1832                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1833                                 "pipeline table array");
1834                         return;
1835                 }
1836
1837                 p.match_type = TABLE_ARRAY;
1838
1839                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1840                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1841                         return;
1842                 }
1843
1844                 if (parser_read_uint32(&p.match.array.key_offset,
1845                         tokens[t0 + 2]) != 0) {
1846                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1847                         return;
1848                 }
1849
1850                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1851                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1852                         return;
1853                 }
1854
1855                 if (parser_read_uint32(&p.match.array.n_keys,
1856                         tokens[t0 + 4]) != 0) {
1857                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1858                         return;
1859                 }
1860
1861                 t0 += 5;
1862         } else if (strcmp(tokens[t0], "hash") == 0) {
1863                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1864
1865                 if (n_tokens < t0 + 12) {
1866                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1867                                 "pipeline table hash");
1868                         return;
1869                 }
1870
1871                 p.match_type = TABLE_HASH;
1872
1873                 if (strcmp(tokens[t0 + 1], "ext") == 0)
1874                         p.match.hash.extendable_bucket = 1;
1875                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
1876                         p.match.hash.extendable_bucket = 0;
1877                 else {
1878                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1879                                 "ext or lru");
1880                         return;
1881                 }
1882
1883                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1884                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1885                         return;
1886                 }
1887
1888                 if ((parser_read_uint32(&p.match.hash.key_size,
1889                         tokens[t0 + 3]) != 0) ||
1890                         (p.match.hash.key_size == 0) ||
1891                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
1892                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1893                         return;
1894                 }
1895
1896                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1897                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1898                         return;
1899                 }
1900
1901                 if ((parse_hex_string(tokens[t0 + 5],
1902                         key_mask, &key_mask_size) != 0) ||
1903                         (key_mask_size != p.match.hash.key_size)) {
1904                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1905                         return;
1906                 }
1907                 p.match.hash.key_mask = key_mask;
1908
1909                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1910                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1911                         return;
1912                 }
1913
1914                 if (parser_read_uint32(&p.match.hash.key_offset,
1915                         tokens[t0 + 7]) != 0) {
1916                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1917                         return;
1918                 }
1919
1920                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1921                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1922                         return;
1923                 }
1924
1925                 if (parser_read_uint32(&p.match.hash.n_buckets,
1926                         tokens[t0 + 9]) != 0) {
1927                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1928                         return;
1929                 }
1930
1931                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1932                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1933                         return;
1934                 }
1935
1936                 if (parser_read_uint32(&p.match.hash.n_keys,
1937                         tokens[t0 + 11]) != 0) {
1938                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1939                         return;
1940                 }
1941
1942                 t0 += 12;
1943         } else if (strcmp(tokens[t0], "lpm") == 0) {
1944                 if (n_tokens < t0 + 6) {
1945                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1946                                 "pipeline table lpm");
1947                         return;
1948                 }
1949
1950                 p.match_type = TABLE_LPM;
1951
1952                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1953                         p.match.lpm.key_size = 4;
1954                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1955                         p.match.lpm.key_size = 16;
1956                 else {
1957                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1958                                 "ipv4 or ipv6");
1959                         return;
1960                 }
1961
1962                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1963                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1964                         return;
1965                 }
1966
1967                 if (parser_read_uint32(&p.match.lpm.key_offset,
1968                         tokens[t0 + 3]) != 0) {
1969                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1970                         return;
1971                 }
1972
1973                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1974                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1975                         return;
1976                 }
1977
1978                 if (parser_read_uint32(&p.match.lpm.n_rules,
1979                         tokens[t0 + 5]) != 0) {
1980                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1981                         return;
1982                 }
1983
1984                 t0 += 6;
1985         } else if (strcmp(tokens[t0], "stub") == 0) {
1986                 p.match_type = TABLE_STUB;
1987
1988                 t0 += 1;
1989         } else {
1990                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1991                 return;
1992         }
1993
1994         p.action_profile_name = NULL;
1995         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1996                 if (n_tokens < t0 + 2) {
1997                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1998                         return;
1999                 }
2000
2001                 p.action_profile_name = tokens[t0 + 1];
2002
2003                 t0 += 2;
2004         }
2005
2006         if (n_tokens > t0) {
2007                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2008                 return;
2009         }
2010
2011         status = pipeline_table_create(pipeline_name, &p);
2012         if (status) {
2013                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2014                 return;
2015         }
2016 }
2017
2018 static const char cmd_pipeline_port_in_table_help[] =
2019 "pipeline <pipeline_name> port in <port_id> table <table_id>\n";
2020
2021 static void
2022 cmd_pipeline_port_in_table(char **tokens,
2023         uint32_t n_tokens,
2024         char *out,
2025         size_t out_size)
2026 {
2027         char *pipeline_name;
2028         uint32_t port_id, table_id;
2029         int status;
2030
2031         if (n_tokens != 7) {
2032                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2033                 return;
2034         }
2035
2036         pipeline_name = tokens[1];
2037
2038         if (strcmp(tokens[2], "port") != 0) {
2039                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2040                 return;
2041         }
2042
2043         if (strcmp(tokens[3], "in") != 0) {
2044                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2045                 return;
2046         }
2047
2048         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2049                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2050                 return;
2051         }
2052
2053         if (strcmp(tokens[5], "table") != 0) {
2054                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2055                 return;
2056         }
2057
2058         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
2059                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2060                 return;
2061         }
2062
2063         status = pipeline_port_in_connect_to_table(pipeline_name,
2064                 port_id,
2065                 table_id);
2066         if (status) {
2067                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2068                 return;
2069         }
2070 }
2071
2072
2073 static const char cmd_pipeline_port_in_stats_help[] =
2074 "pipeline <pipeline_name> port in <port_id> stats read [clear]\n";
2075
2076 #define MSG_PIPELINE_PORT_IN_STATS                         \
2077         "Pkts in: %" PRIu64 "\n"                           \
2078         "Pkts dropped by AH: %" PRIu64 "\n"                \
2079         "Pkts dropped by other: %" PRIu64 "\n"
2080
2081 static void
2082 cmd_pipeline_port_in_stats(char **tokens,
2083         uint32_t n_tokens,
2084         char *out,
2085         size_t out_size)
2086 {
2087         struct rte_pipeline_port_in_stats stats;
2088         char *pipeline_name;
2089         uint32_t port_id;
2090         int clear, status;
2091
2092         if ((n_tokens != 7) && (n_tokens != 8)) {
2093                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2094                 return;
2095         }
2096
2097         pipeline_name = tokens[1];
2098
2099         if (strcmp(tokens[2], "port") != 0) {
2100                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2101                 return;
2102         }
2103
2104         if (strcmp(tokens[3], "in") != 0) {
2105                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2106                 return;
2107         }
2108
2109         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2110                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2111                 return;
2112         }
2113
2114         if (strcmp(tokens[5], "stats") != 0) {
2115                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2116                 return;
2117         }
2118
2119         if (strcmp(tokens[6], "read") != 0) {
2120                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2121                 return;
2122         }
2123
2124         clear = 0;
2125         if (n_tokens == 8) {
2126                 if (strcmp(tokens[7], "clear") != 0) {
2127                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2128                         return;
2129                 }
2130
2131                 clear = 1;
2132         }
2133
2134         status = pipeline_port_in_stats_read(pipeline_name,
2135                 port_id,
2136                 &stats,
2137                 clear);
2138         if (status) {
2139                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2140                 return;
2141         }
2142
2143         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2144                 stats.stats.n_pkts_in,
2145                 stats.n_pkts_dropped_by_ah,
2146                 stats.stats.n_pkts_drop);
2147 }
2148
2149
2150 static const char cmd_pipeline_port_in_enable_help[] =
2151 "pipeline <pipeline_name> port in <port_id> enable\n";
2152
2153 static void
2154 cmd_pipeline_port_in_enable(char **tokens,
2155         uint32_t n_tokens,
2156         char *out,
2157         size_t out_size)
2158 {
2159         char *pipeline_name;
2160         uint32_t port_id;
2161         int status;
2162
2163         if (n_tokens != 6) {
2164                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2165                 return;
2166         }
2167
2168         pipeline_name = tokens[1];
2169
2170         if (strcmp(tokens[2], "port") != 0) {
2171                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2172                 return;
2173         }
2174
2175         if (strcmp(tokens[3], "in") != 0) {
2176                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2177                 return;
2178         }
2179
2180         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2181                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2182                 return;
2183         }
2184
2185         if (strcmp(tokens[5], "enable") != 0) {
2186                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2187                 return;
2188         }
2189
2190         status = pipeline_port_in_enable(pipeline_name, port_id);
2191         if (status) {
2192                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2193                 return;
2194         }
2195 }
2196
2197
2198 static const char cmd_pipeline_port_in_disable_help[] =
2199 "pipeline <pipeline_name> port in <port_id> disable\n";
2200
2201 static void
2202 cmd_pipeline_port_in_disable(char **tokens,
2203         uint32_t n_tokens,
2204         char *out,
2205         size_t out_size)
2206 {
2207         char *pipeline_name;
2208         uint32_t port_id;
2209         int status;
2210
2211         if (n_tokens != 6) {
2212                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2213                 return;
2214         }
2215
2216         pipeline_name = tokens[1];
2217
2218         if (strcmp(tokens[2], "port") != 0) {
2219                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2220                 return;
2221         }
2222
2223         if (strcmp(tokens[3], "in") != 0) {
2224                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2225                 return;
2226         }
2227
2228         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2229                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2230                 return;
2231         }
2232
2233         if (strcmp(tokens[5], "disable") != 0) {
2234                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2235                 return;
2236         }
2237
2238         status = pipeline_port_in_disable(pipeline_name, port_id);
2239         if (status) {
2240                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2241                 return;
2242         }
2243 }
2244
2245
2246 static const char cmd_pipeline_port_out_stats_help[] =
2247 "pipeline <pipeline_name> port out <port_id> stats read [clear]\n";
2248
2249 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2250         "Pkts in: %" PRIu64 "\n"                           \
2251         "Pkts dropped by AH: %" PRIu64 "\n"                \
2252         "Pkts dropped by other: %" PRIu64 "\n"
2253
2254 static void
2255 cmd_pipeline_port_out_stats(char **tokens,
2256         uint32_t n_tokens,
2257         char *out,
2258         size_t out_size)
2259 {
2260         struct rte_pipeline_port_out_stats stats;
2261         char *pipeline_name;
2262         uint32_t port_id;
2263         int clear, status;
2264
2265         if ((n_tokens != 7) && (n_tokens != 8)) {
2266                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2267                 return;
2268         }
2269
2270         pipeline_name = tokens[1];
2271
2272         if (strcmp(tokens[2], "port") != 0) {
2273                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2274                 return;
2275         }
2276
2277         if (strcmp(tokens[3], "out") != 0) {
2278                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2279                 return;
2280         }
2281
2282         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2283                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2284                 return;
2285         }
2286
2287         if (strcmp(tokens[5], "stats") != 0) {
2288                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2289                 return;
2290         }
2291
2292         if (strcmp(tokens[6], "read") != 0) {
2293                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2294                 return;
2295         }
2296
2297         clear = 0;
2298         if (n_tokens == 8) {
2299                 if (strcmp(tokens[7], "clear") != 0) {
2300                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2301                         return;
2302                 }
2303
2304                 clear = 1;
2305         }
2306
2307         status = pipeline_port_out_stats_read(pipeline_name,
2308                 port_id,
2309                 &stats,
2310                 clear);
2311         if (status) {
2312                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2313                 return;
2314         }
2315
2316         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2317                 stats.stats.n_pkts_in,
2318                 stats.n_pkts_dropped_by_ah,
2319                 stats.stats.n_pkts_drop);
2320 }
2321
2322
2323 static const char cmd_pipeline_table_stats_help[] =
2324 "pipeline <pipeline_name> table <table_id> stats read [clear]\n";
2325
2326 #define MSG_PIPELINE_TABLE_STATS                                     \
2327         "Pkts in: %" PRIu64 "\n"                                     \
2328         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2329         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2330         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2331         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2332         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2333
2334 static void
2335 cmd_pipeline_table_stats(char **tokens,
2336         uint32_t n_tokens,
2337         char *out,
2338         size_t out_size)
2339 {
2340         struct rte_pipeline_table_stats stats;
2341         char *pipeline_name;
2342         uint32_t table_id;
2343         int clear, status;
2344
2345         if ((n_tokens != 6) && (n_tokens != 7)) {
2346                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2347                 return;
2348         }
2349
2350         pipeline_name = tokens[1];
2351
2352         if (strcmp(tokens[2], "table") != 0) {
2353                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2354                 return;
2355         }
2356
2357         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2358                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2359                 return;
2360         }
2361
2362         if (strcmp(tokens[4], "stats") != 0) {
2363                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2364                 return;
2365         }
2366
2367         if (strcmp(tokens[5], "read") != 0) {
2368                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2369                 return;
2370         }
2371
2372         clear = 0;
2373         if (n_tokens == 7) {
2374                 if (strcmp(tokens[6], "clear") != 0) {
2375                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2376                         return;
2377                 }
2378
2379                 clear = 1;
2380         }
2381
2382         status = pipeline_table_stats_read(pipeline_name,
2383                 table_id,
2384                 &stats,
2385                 clear);
2386         if (status) {
2387                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2388                 return;
2389         }
2390
2391         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2392                 stats.stats.n_pkts_in,
2393                 stats.stats.n_pkts_lookup_miss,
2394                 stats.n_pkts_dropped_by_lkp_hit_ah,
2395                 stats.n_pkts_dropped_lkp_hit,
2396                 stats.n_pkts_dropped_by_lkp_miss_ah,
2397                 stats.n_pkts_dropped_lkp_miss);
2398 }
2399
2400 /**
2401  * <match> ::=
2402  *
2403  * match
2404  *    acl
2405  *       priority <priority>
2406  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2407  *       <sp0> <sp1> <dp0> <dp1> <proto>
2408  *    | array <pos>
2409  *    | hash
2410  *       raw <key>
2411  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2412  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2413  *       | ipv4_addr <addr>
2414  *       | ipv6_addr <addr>
2415  *       | qinq <svlan> <cvlan>
2416  *    | lpm
2417  *       ipv4 | ipv6 <addr> <depth>
2418  */
2419 struct pkt_key_qinq {
2420         uint16_t ethertype_svlan;
2421         uint16_t svlan;
2422         uint16_t ethertype_cvlan;
2423         uint16_t cvlan;
2424 } __attribute__((__packed__));
2425
2426 struct pkt_key_ipv4_5tuple {
2427         uint8_t time_to_live;
2428         uint8_t proto;
2429         uint16_t hdr_checksum;
2430         uint32_t sa;
2431         uint32_t da;
2432         uint16_t sp;
2433         uint16_t dp;
2434 } __attribute__((__packed__));
2435
2436 struct pkt_key_ipv6_5tuple {
2437         uint16_t payload_length;
2438         uint8_t proto;
2439         uint8_t hop_limit;
2440         uint8_t sa[16];
2441         uint8_t da[16];
2442         uint16_t sp;
2443         uint16_t dp;
2444 } __attribute__((__packed__));
2445
2446 struct pkt_key_ipv4_addr {
2447         uint32_t addr;
2448 } __attribute__((__packed__));
2449
2450 struct pkt_key_ipv6_addr {
2451         uint8_t addr[16];
2452 } __attribute__((__packed__));
2453
2454 static uint32_t
2455 parse_match(char **tokens,
2456         uint32_t n_tokens,
2457         char *out,
2458         size_t out_size,
2459         struct table_rule_match *m)
2460 {
2461         memset(m, 0, sizeof(*m));
2462
2463         if (n_tokens < 2)
2464                 return 0;
2465
2466         if (strcmp(tokens[0], "match") != 0) {
2467                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2468                 return 0;
2469         }
2470
2471         if (strcmp(tokens[1], "acl") == 0) {
2472                 if (n_tokens < 14) {
2473                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2474                         return 0;
2475                 }
2476
2477                 m->match_type = TABLE_ACL;
2478
2479                 if (strcmp(tokens[2], "priority") != 0) {
2480                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2481                         return 0;
2482                 }
2483
2484                 if (parser_read_uint32(&m->match.acl.priority,
2485                         tokens[3]) != 0) {
2486                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2487                         return 0;
2488                 }
2489
2490                 if (strcmp(tokens[4], "ipv4") == 0) {
2491                         struct in_addr saddr, daddr;
2492
2493                         m->match.acl.ip_version = 1;
2494
2495                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2496                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2497                                 return 0;
2498                         }
2499                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2500
2501                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2502                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2503                                 return 0;
2504                         }
2505                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2506                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2507                         struct in6_addr saddr, daddr;
2508
2509                         m->match.acl.ip_version = 0;
2510
2511                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2512                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2513                                 return 0;
2514                         }
2515                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2516
2517                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2518                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2519                                 return 0;
2520                         }
2521                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2522                 } else {
2523                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2524                                 "ipv4 or ipv6");
2525                         return 0;
2526                 }
2527
2528                 if (parser_read_uint32(&m->match.acl.sa_depth,
2529                         tokens[6]) != 0) {
2530                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2531                         return 0;
2532                 }
2533
2534                 if (parser_read_uint32(&m->match.acl.da_depth,
2535                         tokens[8]) != 0) {
2536                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2537                         return 0;
2538                 }
2539
2540                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2541                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2542                         return 0;
2543                 }
2544
2545                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2546                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2547                         return 0;
2548                 }
2549
2550                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2551                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2552                         return 0;
2553                 }
2554
2555                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2556                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2557                         return 0;
2558                 }
2559
2560                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2561                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2562                         return 0;
2563                 }
2564
2565                 m->match.acl.proto_mask = 0xff;
2566
2567                 return 14;
2568         } /* acl */
2569
2570         if (strcmp(tokens[1], "array") == 0) {
2571                 if (n_tokens < 3) {
2572                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2573                         return 0;
2574                 }
2575
2576                 m->match_type = TABLE_ARRAY;
2577
2578                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2579                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2580                         return 0;
2581                 }
2582
2583                 return 3;
2584         } /* array */
2585
2586         if (strcmp(tokens[1], "hash") == 0) {
2587                 if (n_tokens < 3) {
2588                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2589                         return 0;
2590                 }
2591
2592                 m->match_type = TABLE_HASH;
2593
2594                 if (strcmp(tokens[2], "raw") == 0) {
2595                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2596
2597                         if (n_tokens < 4) {
2598                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2599                                         tokens[0]);
2600                                 return 0;
2601                         }
2602
2603                         if (parse_hex_string(tokens[3],
2604                                 m->match.hash.key, &key_size) != 0) {
2605                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2606                                 return 0;
2607                         }
2608
2609                         return 4;
2610                 } /* hash raw */
2611
2612                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2613                         struct pkt_key_ipv4_5tuple *ipv4 =
2614                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2615                         struct in_addr saddr, daddr;
2616                         uint16_t sp, dp;
2617                         uint8_t proto;
2618
2619                         if (n_tokens < 8) {
2620                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2621                                         tokens[0]);
2622                                 return 0;
2623                         }
2624
2625                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2626                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2627                                 return 0;
2628                         }
2629
2630                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2631                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2632                                 return 0;
2633                         }
2634
2635                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2636                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2637                                 return 0;
2638                         }
2639
2640                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2641                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2642                                 return 0;
2643                         }
2644
2645                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2646                                 snprintf(out, out_size, MSG_ARG_INVALID,
2647                                         "proto");
2648                                 return 0;
2649                         }
2650
2651                         ipv4->sa = saddr.s_addr;
2652                         ipv4->da = daddr.s_addr;
2653                         ipv4->sp = rte_cpu_to_be_16(sp);
2654                         ipv4->dp = rte_cpu_to_be_16(dp);
2655                         ipv4->proto = proto;
2656
2657                         return 8;
2658                 } /* hash ipv4_5tuple */
2659
2660                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2661                         struct pkt_key_ipv6_5tuple *ipv6 =
2662                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2663                         struct in6_addr saddr, daddr;
2664                         uint16_t sp, dp;
2665                         uint8_t proto;
2666
2667                         if (n_tokens < 8) {
2668                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2669                                         tokens[0]);
2670                                 return 0;
2671                         }
2672
2673                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2674                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2675                                 return 0;
2676                         }
2677
2678                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2679                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2680                                 return 0;
2681                         }
2682
2683                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2684                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2685                                 return 0;
2686                         }
2687
2688                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2689                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2690                                 return 0;
2691                         }
2692
2693                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2694                                 snprintf(out, out_size, MSG_ARG_INVALID,
2695                                         "proto");
2696                                 return 0;
2697                         }
2698
2699                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2700                         memcpy(ipv6->da, daddr.s6_addr, 16);
2701                         ipv6->sp = rte_cpu_to_be_16(sp);
2702                         ipv6->dp = rte_cpu_to_be_16(dp);
2703                         ipv6->proto = proto;
2704
2705                         return 8;
2706                 } /* hash ipv6_5tuple */
2707
2708                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2709                         struct pkt_key_ipv4_addr *ipv4_addr =
2710                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2711                         struct in_addr addr;
2712
2713                         if (n_tokens < 4) {
2714                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2715                                         tokens[0]);
2716                                 return 0;
2717                         }
2718
2719                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2720                                 snprintf(out, out_size, MSG_ARG_INVALID,
2721                                         "addr");
2722                                 return 0;
2723                         }
2724
2725                         ipv4_addr->addr = addr.s_addr;
2726
2727                         return 4;
2728                 } /* hash ipv4_addr */
2729
2730                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2731                         struct pkt_key_ipv6_addr *ipv6_addr =
2732                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2733                         struct in6_addr addr;
2734
2735                         if (n_tokens < 4) {
2736                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2737                                         tokens[0]);
2738                                 return 0;
2739                         }
2740
2741                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2742                                 snprintf(out, out_size, MSG_ARG_INVALID,
2743                                         "addr");
2744                                 return 0;
2745                         }
2746
2747                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2748
2749                         return 4;
2750                 } /* hash ipv6_5tuple */
2751
2752                 if (strcmp(tokens[2], "qinq") == 0) {
2753                         struct pkt_key_qinq *qinq =
2754                                 (struct pkt_key_qinq *) m->match.hash.key;
2755                         uint16_t svlan, cvlan;
2756
2757                         if (n_tokens < 5) {
2758                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2759                                         tokens[0]);
2760                                 return 0;
2761                         }
2762
2763                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2764                                 (svlan > 0xFFF)) {
2765                                 snprintf(out, out_size, MSG_ARG_INVALID,
2766                                         "svlan");
2767                                 return 0;
2768                         }
2769
2770                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2771                                 (cvlan > 0xFFF)) {
2772                                 snprintf(out, out_size, MSG_ARG_INVALID,
2773                                         "cvlan");
2774                                 return 0;
2775                         }
2776
2777                         qinq->svlan = rte_cpu_to_be_16(svlan);
2778                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
2779
2780                         return 5;
2781                 } /* hash qinq */
2782
2783                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2784                 return 0;
2785         } /* hash */
2786
2787         if (strcmp(tokens[1], "lpm") == 0) {
2788                 if (n_tokens < 5) {
2789                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2790                         return 0;
2791                 }
2792
2793                 m->match_type = TABLE_LPM;
2794
2795                 if (strcmp(tokens[2], "ipv4") == 0) {
2796                         struct in_addr addr;
2797
2798                         m->match.lpm.ip_version = 1;
2799
2800                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2801                                 snprintf(out, out_size, MSG_ARG_INVALID,
2802                                         "addr");
2803                                 return 0;
2804                         }
2805
2806                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2807                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2808                         struct in6_addr addr;
2809
2810                         m->match.lpm.ip_version = 0;
2811
2812                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2813                                 snprintf(out, out_size, MSG_ARG_INVALID,
2814                                         "addr");
2815                                 return 0;
2816                         }
2817
2818                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2819                 } else {
2820                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2821                                 "ipv4 or ipv6");
2822                         return 0;
2823                 }
2824
2825                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2826                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2827                         return 0;
2828                 }
2829
2830                 return 5;
2831         } /* lpm */
2832
2833         snprintf(out, out_size, MSG_ARG_MISMATCH,
2834                 "acl or array or hash or lpm");
2835         return 0;
2836 }
2837
2838 /**
2839  * table_action ::=
2840  *
2841  * action
2842  *    fwd
2843  *       drop
2844  *       | port <port_id>
2845  *       | meta
2846  *       | table <table_id>
2847  *    [balance <out0> ... <out7>]
2848  *    [meter
2849  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2850  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2851  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2852  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2853  *    [tm subport <subport_id> pipe <pipe_id>]
2854  *    [encap
2855  *       ether <da> <sa>
2856  *       | vlan <da> <sa> <pcp> <dei> <vid>
2857  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2858  *       | mpls unicast | multicast
2859  *          <da> <sa>
2860  *          label0 <label> <tc> <ttl>
2861  *          [label1 <label> <tc> <ttl>
2862  *          [label2 <label> <tc> <ttl>
2863  *          [label3 <label> <tc> <ttl>]]]
2864  *       | pppoe <da> <sa> <session_id>]
2865  *    [nat ipv4 | ipv6 <addr> <port>]
2866  *    [ttl dec | keep]
2867  *    [stats]
2868  *    [time]
2869  *
2870  * where:
2871  *    <pa> ::= g | y | r | drop
2872  */
2873 static uint32_t
2874 parse_table_action_fwd(char **tokens,
2875         uint32_t n_tokens,
2876         struct table_rule_action *a)
2877 {
2878         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
2879                 return 0;
2880
2881         tokens++;
2882         n_tokens--;
2883
2884         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2885                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2886                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2887                 return 1 + 1;
2888         }
2889
2890         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2891                 uint32_t id;
2892
2893                 if ((n_tokens < 2) ||
2894                         parser_read_uint32(&id, tokens[1]))
2895                         return 0;
2896
2897                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2898                 a->fwd.id = id;
2899                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2900                 return 1 + 2;
2901         }
2902
2903         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2904                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2905                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2906                 return 1 + 1;
2907         }
2908
2909         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2910                 uint32_t id;
2911
2912                 if ((n_tokens < 2) ||
2913                         parser_read_uint32(&id, tokens[1]))
2914                         return 0;
2915
2916                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2917                 a->fwd.id = id;
2918                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2919                 return 1 + 2;
2920         }
2921
2922         return 0;
2923 }
2924
2925 static uint32_t
2926 parse_table_action_balance(char **tokens,
2927         uint32_t n_tokens,
2928         struct table_rule_action *a)
2929 {
2930         uint32_t i;
2931
2932         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
2933                 return 0;
2934
2935         tokens++;
2936         n_tokens--;
2937
2938         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
2939                 return 0;
2940
2941         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
2942                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
2943                         return 0;
2944
2945         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
2946         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
2947
2948 }
2949
2950 static int
2951 parse_policer_action(char *token, enum rte_table_action_policer *a)
2952 {
2953         if (strcmp(token, "g") == 0) {
2954                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
2955                 return 0;
2956         }
2957
2958         if (strcmp(token, "y") == 0) {
2959                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
2960                 return 0;
2961         }
2962
2963         if (strcmp(token, "r") == 0) {
2964                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
2965                 return 0;
2966         }
2967
2968         if (strcmp(token, "drop") == 0) {
2969                 *a = RTE_TABLE_ACTION_POLICER_DROP;
2970                 return 0;
2971         }
2972
2973         return -1;
2974 }
2975
2976 static uint32_t
2977 parse_table_action_meter_tc(char **tokens,
2978         uint32_t n_tokens,
2979         struct rte_table_action_mtr_tc_params *mtr)
2980 {
2981         if ((n_tokens < 9) ||
2982                 strcmp(tokens[0], "meter") ||
2983                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
2984                 strcmp(tokens[2], "policer") ||
2985                 strcmp(tokens[3], "g") ||
2986                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
2987                 strcmp(tokens[5], "y") ||
2988                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
2989                 strcmp(tokens[7], "r") ||
2990                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
2991                 return 0;
2992
2993         return 9;
2994 }
2995
2996 static uint32_t
2997 parse_table_action_meter(char **tokens,
2998         uint32_t n_tokens,
2999         struct table_rule_action *a)
3000 {
3001         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
3002                 return 0;
3003
3004         tokens++;
3005         n_tokens--;
3006
3007         if ((n_tokens < 10) ||
3008                 strcmp(tokens[0], "tc0") ||
3009                 (parse_table_action_meter_tc(tokens + 1,
3010                         n_tokens - 1,
3011                         &a->mtr.mtr[0]) == 0))
3012                 return 0;
3013
3014         tokens += 10;
3015         n_tokens -= 10;
3016
3017         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
3018                 a->mtr.tc_mask = 1;
3019                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3020                 return 1 + 10;
3021         }
3022
3023         if ((n_tokens < 30) ||
3024                 (parse_table_action_meter_tc(tokens + 1,
3025                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
3026                 strcmp(tokens[10], "tc2") ||
3027                 (parse_table_action_meter_tc(tokens + 11,
3028                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
3029                 strcmp(tokens[20], "tc3") ||
3030                 (parse_table_action_meter_tc(tokens + 21,
3031                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
3032                 return 0;
3033
3034         a->mtr.tc_mask = 0xF;
3035         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3036         return 1 + 10 + 3 * 10;
3037 }
3038
3039 static uint32_t
3040 parse_table_action_tm(char **tokens,
3041         uint32_t n_tokens,
3042         struct table_rule_action *a)
3043 {
3044         uint32_t subport_id, pipe_id;
3045
3046         if ((n_tokens < 5) ||
3047                 strcmp(tokens[0], "tm") ||
3048                 strcmp(tokens[1], "subport") ||
3049                 parser_read_uint32(&subport_id, tokens[2]) ||
3050                 strcmp(tokens[3], "pipe") ||
3051                 parser_read_uint32(&pipe_id, tokens[4]))
3052                 return 0;
3053
3054         a->tm.subport_id = subport_id;
3055         a->tm.pipe_id = pipe_id;
3056         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
3057         return 5;
3058 }
3059
3060 static uint32_t
3061 parse_table_action_encap(char **tokens,
3062         uint32_t n_tokens,
3063         struct table_rule_action *a)
3064 {
3065         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
3066                 return 0;
3067
3068         tokens++;
3069         n_tokens--;
3070
3071         /* ether */
3072         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
3073                 if ((n_tokens < 3) ||
3074                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
3075                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
3076                         return 0;
3077
3078                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
3079                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3080                 return 1 + 3;
3081         }
3082
3083         /* vlan */
3084         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
3085                 uint32_t pcp, dei, vid;
3086
3087                 if ((n_tokens < 6) ||
3088                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3089                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3090                         parser_read_uint32(&pcp, tokens[3]) ||
3091                         (pcp > 0x7) ||
3092                         parser_read_uint32(&dei, tokens[4]) ||
3093                         (dei > 0x1) ||
3094                         parser_read_uint32(&vid, tokens[5]) ||
3095                         (vid > 0xFFF))
3096                         return 0;
3097
3098                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3099                 a->encap.vlan.vlan.dei = dei & 0x1;
3100                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3101                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3102                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3103                 return 1 + 6;
3104         }
3105
3106         /* qinq */
3107         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3108                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3109                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3110
3111                 if ((n_tokens < 9) ||
3112                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3113                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3114                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3115                         (svlan_pcp > 0x7) ||
3116                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3117                         (svlan_dei > 0x1) ||
3118                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3119                         (svlan_vid > 0xFFF) ||
3120                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3121                         (cvlan_pcp > 0x7) ||
3122                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3123                         (cvlan_dei > 0x1) ||
3124                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3125                         (cvlan_vid > 0xFFF))
3126                         return 0;
3127
3128                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3129                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3130                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3131                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3132                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3133                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3134                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3135                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3136                 return 1 + 9;
3137         }
3138
3139         /* mpls */
3140         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3141                 uint32_t label, tc, ttl;
3142
3143                 if (n_tokens < 8)
3144                         return 0;
3145
3146                 if (strcmp(tokens[1], "unicast") == 0)
3147                         a->encap.mpls.unicast = 1;
3148                 else if (strcmp(tokens[1], "multicast") == 0)
3149                         a->encap.mpls.unicast = 0;
3150                 else
3151                         return 0;
3152
3153                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3154                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3155                         strcmp(tokens[4], "label0") ||
3156                         parser_read_uint32(&label, tokens[5]) ||
3157                         (label > 0xFFFFF) ||
3158                         parser_read_uint32(&tc, tokens[6]) ||
3159                         (tc > 0x7) ||
3160                         parser_read_uint32(&ttl, tokens[7]) ||
3161                         (ttl > 0x3F))
3162                         return 0;
3163
3164                 a->encap.mpls.mpls[0].label = label;
3165                 a->encap.mpls.mpls[0].tc = tc;
3166                 a->encap.mpls.mpls[0].ttl = ttl;
3167
3168                 tokens += 8;
3169                 n_tokens -= 8;
3170
3171                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3172                         a->encap.mpls.mpls_count = 1;
3173                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3174                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3175                         return 1 + 8;
3176                 }
3177
3178                 if ((n_tokens < 4) ||
3179                         parser_read_uint32(&label, tokens[1]) ||
3180                         (label > 0xFFFFF) ||
3181                         parser_read_uint32(&tc, tokens[2]) ||
3182                         (tc > 0x7) ||
3183                         parser_read_uint32(&ttl, tokens[3]) ||
3184                         (ttl > 0x3F))
3185                         return 0;
3186
3187                 a->encap.mpls.mpls[1].label = label;
3188                 a->encap.mpls.mpls[1].tc = tc;
3189                 a->encap.mpls.mpls[1].ttl = ttl;
3190
3191                 tokens += 4;
3192                 n_tokens -= 4;
3193
3194                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3195                         a->encap.mpls.mpls_count = 2;
3196                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3197                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3198                         return 1 + 8 + 4;
3199                 }
3200
3201                 if ((n_tokens < 4) ||
3202                         parser_read_uint32(&label, tokens[1]) ||
3203                         (label > 0xFFFFF) ||
3204                         parser_read_uint32(&tc, tokens[2]) ||
3205                         (tc > 0x7) ||
3206                         parser_read_uint32(&ttl, tokens[3]) ||
3207                         (ttl > 0x3F))
3208                         return 0;
3209
3210                 a->encap.mpls.mpls[2].label = label;
3211                 a->encap.mpls.mpls[2].tc = tc;
3212                 a->encap.mpls.mpls[2].ttl = ttl;
3213
3214                 tokens += 4;
3215                 n_tokens -= 4;
3216
3217                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3218                         a->encap.mpls.mpls_count = 3;
3219                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3220                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3221                         return 1 + 8 + 4 + 4;
3222                 }
3223
3224                 if ((n_tokens < 4) ||
3225                         parser_read_uint32(&label, tokens[1]) ||
3226                         (label > 0xFFFFF) ||
3227                         parser_read_uint32(&tc, tokens[2]) ||
3228                         (tc > 0x7) ||
3229                         parser_read_uint32(&ttl, tokens[3]) ||
3230                         (ttl > 0x3F))
3231                         return 0;
3232
3233                 a->encap.mpls.mpls[3].label = label;
3234                 a->encap.mpls.mpls[3].tc = tc;
3235                 a->encap.mpls.mpls[3].ttl = ttl;
3236
3237                 a->encap.mpls.mpls_count = 4;
3238                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3239                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3240                 return 1 + 8 + 4 + 4 + 4;
3241         }
3242
3243         /* pppoe */
3244         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3245                 if ((n_tokens < 4) ||
3246                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3247                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3248                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3249                                 tokens[3]))
3250                         return 0;
3251
3252                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3253                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3254                 return 1 + 4;
3255         }
3256
3257         return 0;
3258 }
3259
3260 static uint32_t
3261 parse_table_action_nat(char **tokens,
3262         uint32_t n_tokens,
3263         struct table_rule_action *a)
3264 {
3265         if ((n_tokens < 4) ||
3266                 strcmp(tokens[0], "nat"))
3267                 return 0;
3268
3269         if (strcmp(tokens[1], "ipv4") == 0) {
3270                 struct in_addr addr;
3271                 uint16_t port;
3272
3273                 if (parse_ipv4_addr(tokens[2], &addr) ||
3274                         parser_read_uint16(&port, tokens[3]))
3275                         return 0;
3276
3277                 a->nat.ip_version = 1;
3278                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3279                 a->nat.port = port;
3280                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3281                 return 4;
3282         }
3283
3284         if (strcmp(tokens[1], "ipv6") == 0) {
3285                 struct in6_addr addr;
3286                 uint16_t port;
3287
3288                 if (parse_ipv6_addr(tokens[2], &addr) ||
3289                         parser_read_uint16(&port, tokens[3]))
3290                         return 0;
3291
3292                 a->nat.ip_version = 0;
3293                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3294                 a->nat.port = port;
3295                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3296                 return 4;
3297         }
3298
3299         return 0;
3300 }
3301
3302 static uint32_t
3303 parse_table_action_ttl(char **tokens,
3304         uint32_t n_tokens,
3305         struct table_rule_action *a)
3306 {
3307         if ((n_tokens < 2) ||
3308                 strcmp(tokens[0], "ttl"))
3309                 return 0;
3310
3311         if (strcmp(tokens[1], "dec") == 0)
3312                 a->ttl.decrement = 1;
3313         else if (strcmp(tokens[1], "keep") == 0)
3314                 a->ttl.decrement = 0;
3315         else
3316                 return 0;
3317
3318         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3319         return 2;
3320 }
3321
3322 static uint32_t
3323 parse_table_action_stats(char **tokens,
3324         uint32_t n_tokens,
3325         struct table_rule_action *a)
3326 {
3327         if ((n_tokens < 1) ||
3328                 strcmp(tokens[0], "stats"))
3329                 return 0;
3330
3331         a->stats.n_packets = 0;
3332         a->stats.n_bytes = 0;
3333         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3334         return 1;
3335 }
3336
3337 static uint32_t
3338 parse_table_action_time(char **tokens,
3339         uint32_t n_tokens,
3340         struct table_rule_action *a)
3341 {
3342         if ((n_tokens < 1) ||
3343                 strcmp(tokens[0], "time"))
3344                 return 0;
3345
3346         a->time.time = rte_rdtsc();
3347         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3348         return 1;
3349 }
3350
3351 static uint32_t
3352 parse_table_action(char **tokens,
3353         uint32_t n_tokens,
3354         char *out,
3355         size_t out_size,
3356         struct table_rule_action *a)
3357 {
3358         uint32_t n_tokens0 = n_tokens;
3359
3360         memset(a, 0, sizeof(*a));
3361
3362         if ((n_tokens < 2) ||
3363                 strcmp(tokens[0], "action"))
3364                 return 0;
3365
3366         tokens++;
3367         n_tokens--;
3368
3369         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
3370                 uint32_t n;
3371
3372                 n = parse_table_action_fwd(tokens, n_tokens, a);
3373                 if (n == 0) {
3374                         snprintf(out, out_size, MSG_ARG_INVALID,
3375                                 "action fwd");
3376                         return 0;
3377                 }
3378
3379                 tokens += n;
3380                 n_tokens -= n;
3381         }
3382
3383         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
3384                 uint32_t n;
3385
3386                 n = parse_table_action_balance(tokens, n_tokens, a);
3387                 if (n == 0) {
3388                         snprintf(out, out_size, MSG_ARG_INVALID,
3389                                 "action balance");
3390                         return 0;
3391                 }
3392
3393                 tokens += n;
3394                 n_tokens -= n;
3395         }
3396
3397         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
3398                 uint32_t n;
3399
3400                 n = parse_table_action_meter(tokens, n_tokens, a);
3401                 if (n == 0) {
3402                         snprintf(out, out_size, MSG_ARG_INVALID,
3403                                 "action meter");
3404                         return 0;
3405                 }
3406
3407                 tokens += n;
3408                 n_tokens -= n;
3409         }
3410
3411         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
3412                 uint32_t n;
3413
3414                 n = parse_table_action_tm(tokens, n_tokens, a);
3415                 if (n == 0) {
3416                         snprintf(out, out_size, MSG_ARG_INVALID,
3417                                 "action tm");
3418                         return 0;
3419                 }
3420
3421                 tokens += n;
3422                 n_tokens -= n;
3423         }
3424
3425         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
3426                 uint32_t n;
3427
3428                 n = parse_table_action_encap(tokens, n_tokens, a);
3429                 if (n == 0) {
3430                         snprintf(out, out_size, MSG_ARG_INVALID,
3431                                 "action encap");
3432                         return 0;
3433                 }
3434
3435                 tokens += n;
3436                 n_tokens -= n;
3437         }
3438
3439         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
3440                 uint32_t n;
3441
3442                 n = parse_table_action_nat(tokens, n_tokens, a);
3443                 if (n == 0) {
3444                         snprintf(out, out_size, MSG_ARG_INVALID,
3445                                 "action nat");
3446                         return 0;
3447                 }
3448
3449                 tokens += n;
3450                 n_tokens -= n;
3451         }
3452
3453         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
3454                 uint32_t n;
3455
3456                 n = parse_table_action_ttl(tokens, n_tokens, a);
3457                 if (n == 0) {
3458                         snprintf(out, out_size, MSG_ARG_INVALID,
3459                                 "action ttl");
3460                         return 0;
3461                 }
3462
3463                 tokens += n;
3464                 n_tokens -= n;
3465         }
3466
3467         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
3468                 uint32_t n;
3469
3470                 n = parse_table_action_stats(tokens, n_tokens, a);
3471                 if (n == 0) {
3472                         snprintf(out, out_size, MSG_ARG_INVALID,
3473                                 "action stats");
3474                         return 0;
3475                 }
3476
3477                 tokens += n;
3478                 n_tokens -= n;
3479         }
3480
3481         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
3482                 uint32_t n;
3483
3484                 n = parse_table_action_time(tokens, n_tokens, a);
3485                 if (n == 0) {
3486                         snprintf(out, out_size, MSG_ARG_INVALID,
3487                                 "action time");
3488                         return 0;
3489                 }
3490
3491                 tokens += n;
3492                 n_tokens -= n;
3493         }
3494
3495         if (n_tokens0 - n_tokens == 1) {
3496                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3497                 return 0;
3498         }
3499
3500         return n_tokens0 - n_tokens;
3501 }
3502
3503
3504 static const char cmd_pipeline_table_rule_add_help[] =
3505 "pipeline <pipeline_name> table <table_id> rule add\n"
3506 "     match <match>\n"
3507 "     action <table_action>\n";
3508
3509 static void
3510 cmd_pipeline_table_rule_add(char **tokens,
3511         uint32_t n_tokens,
3512         char *out,
3513         size_t out_size)
3514 {
3515         struct table_rule_match m;
3516         struct table_rule_action a;
3517         char *pipeline_name;
3518         void *data;
3519         uint32_t table_id, t0, n_tokens_parsed;
3520         int status;
3521
3522         if (n_tokens < 8) {
3523                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3524                 return;
3525         }
3526
3527         pipeline_name = tokens[1];
3528
3529         if (strcmp(tokens[2], "table") != 0) {
3530                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3531                 return;
3532         }
3533
3534         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3535                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3536                 return;
3537         }
3538
3539         if (strcmp(tokens[4], "rule") != 0) {
3540                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3541                 return;
3542         }
3543
3544         if (strcmp(tokens[5], "add") != 0) {
3545                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3546                 return;
3547         }
3548
3549         t0 = 6;
3550
3551         /* match */
3552         n_tokens_parsed = parse_match(tokens + t0,
3553                 n_tokens - t0,
3554                 out,
3555                 out_size,
3556                 &m);
3557         if (n_tokens_parsed == 0)
3558                 return;
3559         t0 += n_tokens_parsed;
3560
3561         /* action */
3562         n_tokens_parsed = parse_table_action(tokens + t0,
3563                 n_tokens - t0,
3564                 out,
3565                 out_size,
3566                 &a);
3567         if (n_tokens_parsed == 0)
3568                 return;
3569         t0 += n_tokens_parsed;
3570
3571         if (t0 != n_tokens) {
3572                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
3573                 return;
3574         }
3575
3576         status = pipeline_table_rule_add(pipeline_name, table_id,
3577                 &m, &a, &data);
3578         if (status) {
3579                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3580                 return;
3581         }
3582 }
3583
3584
3585 static const char cmd_pipeline_table_rule_add_default_help[] =
3586 "pipeline <pipeline_name> table <table_id> rule add\n"
3587 "     match\n"
3588 "        default\n"
3589 "     action\n"
3590 "        fwd\n"
3591 "           drop\n"
3592 "           | port <port_id>\n"
3593 "           | meta\n"
3594 "           | table <table_id>\n";
3595
3596 static void
3597 cmd_pipeline_table_rule_add_default(char **tokens,
3598         uint32_t n_tokens,
3599         char *out,
3600         size_t out_size)
3601 {
3602         struct table_rule_action action;
3603         void *data;
3604         char *pipeline_name;
3605         uint32_t table_id;
3606         int status;
3607
3608         if ((n_tokens != 11) && (n_tokens != 12)) {
3609                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3610                 return;
3611         }
3612
3613         pipeline_name = tokens[1];
3614
3615         if (strcmp(tokens[2], "table") != 0) {
3616                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3617                 return;
3618         }
3619
3620         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3621                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3622                 return;
3623         }
3624
3625         if (strcmp(tokens[4], "rule") != 0) {
3626                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3627                 return;
3628         }
3629
3630         if (strcmp(tokens[5], "add") != 0) {
3631                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3632                 return;
3633         }
3634
3635         if (strcmp(tokens[6], "match") != 0) {
3636                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3637                 return;
3638         }
3639
3640         if (strcmp(tokens[7], "default") != 0) {
3641                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3642                 return;
3643         }
3644
3645         if (strcmp(tokens[8], "action") != 0) {
3646                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3647                 return;
3648         }
3649
3650         if (strcmp(tokens[9], "fwd") != 0) {
3651                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
3652                 return;
3653         }
3654
3655         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
3656
3657         if (strcmp(tokens[10], "drop") == 0) {
3658                 if (n_tokens != 11) {
3659                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3660                         return;
3661                 }
3662
3663                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
3664         } else if (strcmp(tokens[10], "port") == 0) {
3665                 uint32_t id;
3666
3667                 if (n_tokens != 12) {
3668                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3669                         return;
3670                 }
3671
3672                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3673                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
3674                         return;
3675                 }
3676
3677                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
3678                 action.fwd.id = id;
3679         } else if (strcmp(tokens[10], "meta") == 0) {
3680                 if (n_tokens != 11) {
3681                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3682                         return;
3683                 }
3684
3685                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3686         } else if (strcmp(tokens[10], "table") == 0) {
3687                 uint32_t id;
3688
3689                 if (n_tokens != 12) {
3690                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3691                         return;
3692                 }
3693
3694                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3695                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3696                         return;
3697                 }
3698
3699                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
3700                 action.fwd.id = id;
3701         } else {
3702                 snprintf(out, out_size, MSG_ARG_INVALID,
3703                         "drop or port or meta or table");
3704                 return;
3705         }
3706
3707         status = pipeline_table_rule_add_default(pipeline_name,
3708                 table_id,
3709                 &action,
3710                 &data);
3711         if (status) {
3712                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3713                 return;
3714         }
3715 }
3716
3717
3718 static const char cmd_pipeline_table_rule_add_bulk_help[] =
3719 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>\n"
3720 "\n"
3721 "  File <file_name>:\n"
3722 "  - line format: match <match> action <action>\n";
3723
3724 static int
3725 cli_rule_file_process(const char *file_name,
3726         size_t line_len_max,
3727         struct table_rule_match *m,
3728         struct table_rule_action *a,
3729         uint32_t *n_rules,
3730         uint32_t *line_number,
3731         char *out,
3732         size_t out_size);
3733
3734 static void
3735 cmd_pipeline_table_rule_add_bulk(char **tokens,
3736         uint32_t n_tokens,
3737         char *out,
3738         size_t out_size)
3739 {
3740         struct table_rule_match *match;
3741         struct table_rule_action *action;
3742         void **data;
3743         char *pipeline_name, *file_name;
3744         uint32_t table_id, n_rules, n_rules_parsed, line_number;
3745         int status;
3746
3747         if (n_tokens != 9) {
3748                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3749                 return;
3750         }
3751
3752         pipeline_name = tokens[1];
3753
3754         if (strcmp(tokens[2], "table") != 0) {
3755                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3756                 return;
3757         }
3758
3759         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3760                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3761                 return;
3762         }
3763
3764         if (strcmp(tokens[4], "rule") != 0) {
3765                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3766                 return;
3767         }
3768
3769         if (strcmp(tokens[5], "add") != 0) {
3770                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3771                 return;
3772         }
3773
3774         if (strcmp(tokens[6], "bulk") != 0) {
3775                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
3776                 return;
3777         }
3778
3779         file_name = tokens[7];
3780
3781         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
3782                 (n_rules == 0)) {
3783                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
3784                 return;
3785         }
3786
3787         /* Memory allocation. */
3788         match = calloc(n_rules, sizeof(struct table_rule_match));
3789         action = calloc(n_rules, sizeof(struct table_rule_action));
3790         data = calloc(n_rules, sizeof(void *));
3791         if ((match == NULL) || (action == NULL) || (data == NULL)) {
3792                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3793                 free(data);
3794                 free(action);
3795                 free(match);
3796                 return;
3797         }
3798
3799         /* Load rule file */
3800         n_rules_parsed = n_rules;
3801         status = cli_rule_file_process(file_name,
3802                 1024,
3803                 match,
3804                 action,
3805                 &n_rules_parsed,
3806                 &line_number,
3807                 out,
3808                 out_size);
3809         if (status) {
3810                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3811                 free(data);
3812                 free(action);
3813                 free(match);
3814                 return;
3815         }
3816         if (n_rules_parsed != n_rules) {
3817                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3818                 free(data);
3819                 free(action);
3820                 free(match);
3821                 return;
3822         }
3823
3824         /* Rule bulk add */
3825         status = pipeline_table_rule_add_bulk(pipeline_name,
3826                 table_id,
3827                 match,
3828                 action,
3829                 data,
3830                 &n_rules);
3831         if (status) {
3832                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3833                 free(data);
3834                 free(action);
3835                 free(match);
3836                 return;
3837         }
3838
3839         /* Memory free */
3840         free(data);
3841         free(action);
3842         free(match);
3843 }
3844
3845
3846 static const char cmd_pipeline_table_rule_delete_help[] =
3847 "pipeline <pipeline_name> table <table_id> rule delete\n"
3848 "     match <match>\n";
3849
3850 static void
3851 cmd_pipeline_table_rule_delete(char **tokens,
3852         uint32_t n_tokens,
3853         char *out,
3854         size_t out_size)
3855 {
3856         struct table_rule_match m;
3857         char *pipeline_name;
3858         uint32_t table_id, n_tokens_parsed, t0;
3859         int status;
3860
3861         if (n_tokens < 8) {
3862                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3863                 return;
3864         }
3865
3866         pipeline_name = tokens[1];
3867
3868         if (strcmp(tokens[2], "table") != 0) {
3869                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3870                 return;
3871         }
3872
3873         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3874                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3875                 return;
3876         }
3877
3878         if (strcmp(tokens[4], "rule") != 0) {
3879                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3880                 return;
3881         }
3882
3883         if (strcmp(tokens[5], "delete") != 0) {
3884                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3885                 return;
3886         }
3887
3888         t0 = 6;
3889
3890         /* match */
3891         n_tokens_parsed = parse_match(tokens + t0,
3892                 n_tokens - t0,
3893                 out,
3894                 out_size,
3895                 &m);
3896         if (n_tokens_parsed == 0)
3897                 return;
3898         t0 += n_tokens_parsed;
3899
3900         if (n_tokens != t0) {
3901                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3902                 return;
3903         }
3904
3905         status = pipeline_table_rule_delete(pipeline_name,
3906                 table_id,
3907                 &m);
3908         if (status) {
3909                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3910                 return;
3911         }
3912 }
3913
3914
3915 static const char cmd_pipeline_table_rule_delete_default_help[] =
3916 "pipeline <pipeline_name> table <table_id> rule delete\n"
3917 "     match\n"
3918 "        default\n";
3919
3920 static void
3921 cmd_pipeline_table_rule_delete_default(char **tokens,
3922         uint32_t n_tokens,
3923         char *out,
3924         size_t out_size)
3925 {
3926         char *pipeline_name;
3927         uint32_t table_id;
3928         int status;
3929
3930         if (n_tokens != 8) {
3931                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3932                 return;
3933         }
3934
3935         pipeline_name = tokens[1];
3936
3937         if (strcmp(tokens[2], "table") != 0) {
3938                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3939                 return;
3940         }
3941
3942         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3943                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3944                 return;
3945         }
3946
3947         if (strcmp(tokens[4], "rule") != 0) {
3948                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3949                 return;
3950         }
3951
3952         if (strcmp(tokens[5], "delete") != 0) {
3953                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3954                 return;
3955         }
3956
3957         if (strcmp(tokens[6], "match") != 0) {
3958                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3959                 return;
3960         }
3961
3962         if (strcmp(tokens[7], "default") != 0) {
3963                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3964                 return;
3965         }
3966
3967         status = pipeline_table_rule_delete_default(pipeline_name,
3968                 table_id);
3969         if (status) {
3970                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3971                 return;
3972         }
3973 }
3974
3975
3976 static const char cmd_pipeline_table_rule_stats_read_help[] =
3977 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n";
3978
3979 static void
3980 cmd_pipeline_table_rule_stats_read(char **tokens,
3981         uint32_t n_tokens __rte_unused,
3982         char *out,
3983         size_t out_size)
3984 {
3985         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
3986 }
3987
3988
3989 static const char cmd_pipeline_table_meter_profile_add_help[] =
3990 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
3991 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
3992 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
3993
3994 static void
3995 cmd_pipeline_table_meter_profile_add(char **tokens,
3996         uint32_t n_tokens,
3997         char *out,
3998         size_t out_size)
3999 {
4000         struct rte_table_action_meter_profile p;
4001         char *pipeline_name;
4002         uint32_t table_id, meter_profile_id;
4003         int status;
4004
4005         if (n_tokens < 9) {
4006                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4007                 return;
4008         }
4009
4010         pipeline_name = tokens[1];
4011
4012         if (strcmp(tokens[2], "table") != 0) {
4013                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4014                 return;
4015         }
4016
4017         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4018                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4019                 return;
4020         }
4021
4022         if (strcmp(tokens[4], "meter") != 0) {
4023                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4024                 return;
4025         }
4026
4027         if (strcmp(tokens[5], "profile") != 0) {
4028                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4029                 return;
4030         }
4031
4032         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4033                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4034                 return;
4035         }
4036
4037         if (strcmp(tokens[7], "add") != 0) {
4038                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4039                 return;
4040         }
4041
4042         if (strcmp(tokens[8], "srtcm") == 0) {
4043                 if (n_tokens != 15) {
4044                         snprintf(out, out_size, MSG_ARG_MISMATCH,
4045                                 tokens[0]);
4046                         return;
4047                 }
4048
4049                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
4050
4051                 if (strcmp(tokens[9], "cir") != 0) {
4052                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4053                         return;
4054                 }
4055
4056                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
4057                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4058                         return;
4059                 }
4060
4061                 if (strcmp(tokens[11], "cbs") != 0) {
4062                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4063                         return;
4064                 }
4065
4066                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
4067                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4068                         return;
4069                 }
4070
4071                 if (strcmp(tokens[13], "ebs") != 0) {
4072                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
4073                         return;
4074                 }
4075
4076                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
4077                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
4078                         return;
4079                 }
4080         } else if (strcmp(tokens[8], "trtcm") == 0) {
4081                 if (n_tokens != 17) {
4082                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4083                         return;
4084                 }
4085
4086                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
4087
4088                 if (strcmp(tokens[9], "cir") != 0) {
4089                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4090                         return;
4091                 }
4092
4093                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
4094                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4095                         return;
4096                 }
4097
4098                 if (strcmp(tokens[11], "pir") != 0) {
4099                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4100                         return;
4101                 }
4102
4103                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4104                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4105                         return;
4106                 }
4107                 if (strcmp(tokens[13], "cbs") != 0) {
4108                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4109                         return;
4110                 }
4111
4112                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4113                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4114                         return;
4115                 }
4116
4117                 if (strcmp(tokens[15], "pbs") != 0) {
4118                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4119                         return;
4120                 }
4121
4122                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4123                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4124                         return;
4125                 }
4126         } else {
4127                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4128                 return;
4129         }
4130
4131         status = pipeline_table_mtr_profile_add(pipeline_name,
4132                 table_id,
4133                 meter_profile_id,
4134                 &p);
4135         if (status) {
4136                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4137                 return;
4138         }
4139 }
4140
4141
4142 static const char cmd_pipeline_table_meter_profile_delete_help[] =
4143 "pipeline <pipeline_name> table <table_id>\n"
4144 "   meter profile <meter_profile_id> delete\n";
4145
4146 static void
4147 cmd_pipeline_table_meter_profile_delete(char **tokens,
4148         uint32_t n_tokens,
4149         char *out,
4150         size_t out_size)
4151 {
4152         char *pipeline_name;
4153         uint32_t table_id, meter_profile_id;
4154         int status;
4155
4156         if (n_tokens != 8) {
4157                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4158                 return;
4159         }
4160
4161         pipeline_name = tokens[1];
4162
4163         if (strcmp(tokens[2], "table") != 0) {
4164                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4165                 return;
4166         }
4167
4168         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4169                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4170                 return;
4171         }
4172
4173         if (strcmp(tokens[4], "meter") != 0) {
4174                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4175                 return;
4176         }
4177
4178         if (strcmp(tokens[5], "profile") != 0) {
4179                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4180                 return;
4181         }
4182
4183         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4184                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4185                 return;
4186         }
4187
4188         if (strcmp(tokens[7], "delete") != 0) {
4189                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4190                 return;
4191         }
4192
4193         status = pipeline_table_mtr_profile_delete(pipeline_name,
4194                 table_id,
4195                 meter_profile_id);
4196         if (status) {
4197                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4198                 return;
4199         }
4200 }
4201
4202
4203 static const char cmd_pipeline_table_rule_meter_read_help[] =
4204 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n";
4205
4206 static void
4207 cmd_pipeline_table_rule_meter_read(char **tokens,
4208         uint32_t n_tokens __rte_unused,
4209         char *out,
4210         size_t out_size)
4211 {
4212         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4213 }
4214
4215
4216 static const char cmd_pipeline_table_dscp_help[] =
4217 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
4218 "\n"
4219 " File <file_name>:\n"
4220 "   - exactly 64 lines\n"
4221 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
4222
4223 static int
4224 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
4225         const char *file_name,
4226         uint32_t *line_number)
4227 {
4228         FILE *f = NULL;
4229         uint32_t dscp, l;
4230
4231         /* Check input arguments */
4232         if ((dscp_table == NULL) ||
4233                 (file_name == NULL) ||
4234                 (line_number == NULL)) {
4235                 if (line_number)
4236                         *line_number = 0;
4237                 return -EINVAL;
4238         }
4239
4240         /* Open input file */
4241         f = fopen(file_name, "r");
4242         if (f == NULL) {
4243                 *line_number = 0;
4244                 return -EINVAL;
4245         }
4246
4247         /* Read file */
4248         for (dscp = 0, l = 1; ; l++) {
4249                 char line[64];
4250                 char *tokens[3];
4251                 enum rte_meter_color color;
4252                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
4253
4254                 if (fgets(line, sizeof(line), f) == NULL)
4255                         break;
4256
4257                 if (is_comment(line))
4258                         continue;
4259
4260                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
4261                         *line_number = l;
4262                         fclose(f);
4263                         return -EINVAL;
4264                 }
4265
4266                 if (n_tokens == 0)
4267                         continue;
4268
4269                 if ((dscp >= RTE_DIM(dscp_table->entry)) ||
4270                         (n_tokens != RTE_DIM(tokens)) ||
4271                         parser_read_uint32(&tc_id, tokens[0]) ||
4272                         (tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
4273                         parser_read_uint32(&tc_queue_id, tokens[1]) ||
4274                         (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
4275                         (strlen(tokens[2]) != 1)) {
4276                         *line_number = l;
4277                         fclose(f);
4278                         return -EINVAL;
4279                 }
4280
4281                 switch (tokens[2][0]) {
4282                 case 'g':
4283                 case 'G':
4284                         color = e_RTE_METER_GREEN;
4285                         break;
4286
4287                 case 'y':
4288                 case 'Y':
4289                         color = e_RTE_METER_YELLOW;
4290                         break;
4291
4292                 case 'r':
4293                 case 'R':
4294                         color = e_RTE_METER_RED;
4295                         break;
4296
4297                 default:
4298                         *line_number = l;
4299                         fclose(f);
4300                         return -EINVAL;
4301                 }
4302
4303                 dscp_table->entry[dscp].tc_id = tc_id;
4304                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
4305                 dscp_table->entry[dscp].color = color;
4306                 dscp++;
4307         }
4308
4309         /* Close file */
4310         fclose(f);
4311         return 0;
4312 }
4313
4314 static void
4315 cmd_pipeline_table_dscp(char **tokens,
4316         uint32_t n_tokens,
4317         char *out,
4318         size_t out_size)
4319 {
4320         struct rte_table_action_dscp_table dscp_table;
4321         char *pipeline_name, *file_name;
4322         uint32_t table_id, line_number;
4323         int status;
4324
4325         if (n_tokens != 6) {
4326                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4327                 return;
4328         }
4329
4330         pipeline_name = tokens[1];
4331
4332         if (strcmp(tokens[2], "table") != 0) {
4333                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4334                 return;
4335         }
4336
4337         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4338                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4339                 return;
4340         }
4341
4342         if (strcmp(tokens[4], "dscp") != 0) {
4343                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
4344                 return;
4345         }
4346
4347         file_name = tokens[5];
4348
4349         status = load_dscp_table(&dscp_table, file_name, &line_number);
4350         if (status) {
4351                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4352                 return;
4353         }
4354
4355         status = pipeline_table_dscp_table_update(pipeline_name,
4356                 table_id,
4357                 UINT64_MAX,
4358                 &dscp_table);
4359         if (status) {
4360                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4361                 return;
4362         }
4363 }
4364
4365
4366 static const char cmd_pipeline_table_rule_ttl_read_help[] =
4367 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n";
4368
4369 static void
4370 cmd_pipeline_table_rule_ttl_read(char **tokens,
4371         uint32_t n_tokens __rte_unused,
4372         char *out,
4373         size_t out_size)
4374 {
4375         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4376 }
4377
4378
4379 static const char cmd_thread_pipeline_enable_help[] =
4380 "thread <thread_id> pipeline <pipeline_name> enable\n";
4381
4382 static void
4383 cmd_thread_pipeline_enable(char **tokens,
4384         uint32_t n_tokens,
4385         char *out,
4386         size_t out_size)
4387 {
4388         char *pipeline_name;
4389         uint32_t thread_id;
4390         int status;
4391
4392         if (n_tokens != 5) {
4393                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4394                 return;
4395         }
4396
4397         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4398                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4399                 return;
4400         }
4401
4402         if (strcmp(tokens[2], "pipeline") != 0) {
4403                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4404                 return;
4405         }
4406
4407         pipeline_name = tokens[3];
4408
4409         if (strcmp(tokens[4], "enable") != 0) {
4410                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
4411                 return;
4412         }
4413
4414         status = thread_pipeline_enable(thread_id, pipeline_name);
4415         if (status) {
4416                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
4417                 return;
4418         }
4419 }
4420
4421
4422 static const char cmd_thread_pipeline_disable_help[] =
4423 "thread <thread_id> pipeline <pipeline_name> disable\n";
4424
4425 static void
4426 cmd_thread_pipeline_disable(char **tokens,
4427         uint32_t n_tokens,
4428         char *out,
4429         size_t out_size)
4430 {
4431         char *pipeline_name;
4432         uint32_t thread_id;
4433         int status;
4434
4435         if (n_tokens != 5) {
4436                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4437                 return;
4438         }
4439
4440         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4441                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4442                 return;
4443         }
4444
4445         if (strcmp(tokens[2], "pipeline") != 0) {
4446                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4447                 return;
4448         }
4449
4450         pipeline_name = tokens[3];
4451
4452         if (strcmp(tokens[4], "disable") != 0) {
4453                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
4454                 return;
4455         }
4456
4457         status = thread_pipeline_disable(thread_id, pipeline_name);
4458         if (status) {
4459                 snprintf(out, out_size, MSG_CMD_FAIL,
4460                         "thread pipeline disable");
4461                 return;
4462         }
4463 }
4464
4465 static void
4466 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
4467 {
4468         tokens++;
4469         n_tokens--;
4470
4471         if (n_tokens == 0) {
4472                 snprintf(out, out_size,
4473                         "Type 'help <command>' for details on each command.\n\n"
4474                         "List of commands:\n"
4475                         "\tmempool\n"
4476                         "\tlink\n"
4477                         "\tswq\n"
4478                         "\ttmgr subport profile\n"
4479                         "\ttmgr pipe profile\n"
4480                         "\ttmgr\n"
4481                         "\ttmgr subport\n"
4482                         "\ttmgr subport pipe\n"
4483                         "\ttap\n"
4484                         "\tkni\n"
4485                         "\tport in action profile\n"
4486                         "\ttable action profile\n"
4487                         "\tpipeline\n"
4488                         "\tpipeline port in\n"
4489                         "\tpipeline port out\n"
4490                         "\tpipeline table\n"
4491                         "\tpipeline port in table\n"
4492                         "\tpipeline port in stats\n"
4493                         "\tpipeline port in enable\n"
4494                         "\tpipeline port in disable\n"
4495                         "\tpipeline port out stats\n"
4496                         "\tpipeline table stats\n"
4497                         "\tpipeline table rule add\n"
4498                         "\tpipeline table rule add default\n"
4499                         "\tpipeline table rule add bulk\n"
4500                         "\tpipeline table rule delete\n"
4501                         "\tpipeline table rule delete default\n"
4502                         "\tpipeline table rule stats read\n"
4503                         "\tpipeline table meter profile add\n"
4504                         "\tpipeline table meter profile delete\n"
4505                         "\tpipeline table rule meter read\n"
4506                         "\tpipeline table dscp\n"
4507                         "\tpipeline table rule ttl read\n"
4508                         "\tthread pipeline enable\n"
4509                         "\tthread pipeline disable\n\n");
4510                 return;
4511         }
4512
4513         if (strcmp(tokens[0], "mempool") == 0) {
4514                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
4515                 return;
4516         }
4517
4518         if (strcmp(tokens[0], "link") == 0) {
4519                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
4520                 return;
4521         }
4522
4523         if (strcmp(tokens[0], "swq") == 0) {
4524                 snprintf(out, out_size, "\n%s\n", cmd_swq_help);
4525                 return;
4526         }
4527
4528         if (strcmp(tokens[0], "tmgr") == 0) {
4529                 if (n_tokens == 1) {
4530                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
4531                         return;
4532                 }
4533
4534                 if ((n_tokens == 2) &&
4535                         (strcmp(tokens[1], "subport")) == 0) {
4536                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
4537                         return;
4538                 }
4539
4540                 if ((n_tokens == 3) &&
4541                         (strcmp(tokens[1], "subport") == 0) &&
4542                         (strcmp(tokens[2], "profile") == 0)) {
4543                         snprintf(out, out_size, "\n%s\n",
4544                                 cmd_tmgr_subport_profile_help);
4545                         return;
4546                 }
4547
4548                 if ((n_tokens == 3) &&
4549                         (strcmp(tokens[1], "subport") == 0) &&
4550                         (strcmp(tokens[2], "pipe") == 0)) {
4551                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
4552                         return;
4553                 }
4554
4555                 if ((n_tokens == 3) &&
4556                         (strcmp(tokens[1], "pipe") == 0) &&
4557                         (strcmp(tokens[2], "profile") == 0)) {
4558                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
4559                         return;
4560                 }
4561         }
4562
4563         if (strcmp(tokens[0], "tap") == 0) {
4564                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
4565                 return;
4566         }
4567
4568         if (strcmp(tokens[0], "kni") == 0) {
4569                 snprintf(out, out_size, "\n%s\n", cmd_kni_help);
4570                 return;
4571         }
4572
4573         if ((n_tokens == 4) &&
4574                 (strcmp(tokens[0], "port") == 0) &&
4575                 (strcmp(tokens[1], "in") == 0) &&
4576                 (strcmp(tokens[2], "action") == 0) &&
4577                 (strcmp(tokens[3], "profile") == 0)) {
4578                 snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
4579                 return;
4580         }
4581
4582         if ((n_tokens == 3) &&
4583                 (strcmp(tokens[0], "table") == 0) &&
4584                 (strcmp(tokens[1], "action") == 0) &&
4585                 (strcmp(tokens[2], "profile") == 0)) {
4586                 snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
4587                 return;
4588         }
4589
4590         if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
4591                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
4592                 return;
4593         }
4594
4595         if ((strcmp(tokens[0], "pipeline") == 0) &&
4596                 (strcmp(tokens[1], "port") == 0)) {
4597                 if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
4598                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
4599                         return;
4600                 }
4601
4602                 if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
4603                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
4604                         return;
4605                 }
4606
4607                 if ((n_tokens == 4) &&
4608                         (strcmp(tokens[2], "in") == 0) &&
4609                         (strcmp(tokens[3], "table") == 0)) {
4610                         snprintf(out, out_size, "\n%s\n",
4611                                 cmd_pipeline_port_in_table_help);
4612                         return;
4613                 }
4614
4615                 if ((n_tokens == 4) &&
4616                         (strcmp(tokens[2], "in") == 0) &&
4617                         (strcmp(tokens[3], "stats") == 0)) {
4618                         snprintf(out, out_size, "\n%s\n",
4619                                 cmd_pipeline_port_in_stats_help);
4620                         return;
4621                 }
4622
4623                 if ((n_tokens == 4) &&
4624                         (strcmp(tokens[2], "in") == 0) &&
4625                         (strcmp(tokens[3], "enable") == 0)) {
4626                         snprintf(out, out_size, "\n%s\n",
4627                                 cmd_pipeline_port_in_enable_help);
4628                         return;
4629                 }
4630
4631                 if ((n_tokens == 4) &&
4632                         (strcmp(tokens[2], "in") == 0) &&
4633                         (strcmp(tokens[3], "disable") == 0)) {
4634                         snprintf(out, out_size, "\n%s\n",
4635                                 cmd_pipeline_port_in_disable_help);
4636                         return;
4637                 }
4638
4639                 if ((n_tokens == 4) &&
4640                         (strcmp(tokens[2], "out") == 0) &&
4641                         (strcmp(tokens[3], "stats") == 0)) {
4642                         snprintf(out, out_size, "\n%s\n",
4643                                 cmd_pipeline_port_out_stats_help);
4644                         return;
4645                 }
4646         }
4647
4648         if ((strcmp(tokens[0], "pipeline") == 0) &&
4649                 (strcmp(tokens[1], "table") == 0)) {
4650                 if (n_tokens == 2) {
4651                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
4652                         return;
4653                 }
4654
4655                 if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
4656                         snprintf(out, out_size, "\n%s\n",
4657                                 cmd_pipeline_table_stats_help);
4658                         return;
4659                 }
4660
4661                 if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
4662                         snprintf(out, out_size, "\n%s\n",
4663                                 cmd_pipeline_table_dscp_help);
4664                         return;
4665                 }
4666
4667                 if ((n_tokens == 4) &&
4668                         (strcmp(tokens[2], "rule") == 0) &&
4669                         (strcmp(tokens[3], "add") == 0)) {
4670                         snprintf(out, out_size, "\n%s\n",
4671                                 cmd_pipeline_table_rule_add_help);
4672                         return;
4673                 }
4674
4675                 if ((n_tokens == 5) &&
4676                         (strcmp(tokens[2], "rule") == 0) &&
4677                         (strcmp(tokens[3], "add") == 0) &&
4678                         (strcmp(tokens[4], "default") == 0)) {
4679                         snprintf(out, out_size, "\n%s\n",
4680                                 cmd_pipeline_table_rule_add_default_help);
4681                         return;
4682                 }
4683
4684                 if ((n_tokens == 5) &&
4685                         (strcmp(tokens[2], "rule") == 0) &&
4686                         (strcmp(tokens[3], "add") == 0) &&
4687                         (strcmp(tokens[4], "bulk") == 0)) {
4688                         snprintf(out, out_size, "\n%s\n",
4689                                 cmd_pipeline_table_rule_add_bulk_help);
4690                         return;
4691                 }
4692
4693                 if ((n_tokens == 4) &&
4694                         (strcmp(tokens[2], "rule") == 0) &&
4695                         (strcmp(tokens[3], "delete") == 0)) {
4696                         snprintf(out, out_size, "\n%s\n",
4697                                 cmd_pipeline_table_rule_delete_help);
4698                         return;
4699                 }
4700
4701                 if ((n_tokens == 5) &&
4702                         (strcmp(tokens[2], "rule") == 0) &&
4703                         (strcmp(tokens[3], "delete") == 0) &&
4704                         (strcmp(tokens[4], "default") == 0)) {
4705                         snprintf(out, out_size, "\n%s\n",
4706                                 cmd_pipeline_table_rule_delete_default_help);
4707                         return;
4708                 }
4709
4710                 if ((n_tokens == 5) &&
4711                         (strcmp(tokens[2], "rule") == 0) &&
4712                         (strcmp(tokens[3], "stats") == 0) &&
4713                         (strcmp(tokens[4], "read") == 0)) {
4714                         snprintf(out, out_size, "\n%s\n",
4715                                 cmd_pipeline_table_rule_stats_read_help);
4716                         return;
4717                 }
4718
4719                 if ((n_tokens == 5) &&
4720                         (strcmp(tokens[2], "meter") == 0) &&
4721                         (strcmp(tokens[3], "profile") == 0) &&
4722                         (strcmp(tokens[4], "add") == 0)) {
4723                         snprintf(out, out_size, "\n%s\n",
4724                                 cmd_pipeline_table_meter_profile_add_help);
4725                         return;
4726                 }
4727
4728                 if ((n_tokens == 5) &&
4729                         (strcmp(tokens[2], "meter") == 0) &&
4730                         (strcmp(tokens[3], "profile") == 0) &&
4731                         (strcmp(tokens[4], "delete") == 0)) {
4732                         snprintf(out, out_size, "\n%s\n",
4733                                 cmd_pipeline_table_meter_profile_delete_help);
4734                         return;
4735                 }
4736
4737                 if ((n_tokens == 5) &&
4738                         (strcmp(tokens[2], "rule") == 0) &&
4739                         (strcmp(tokens[3], "meter") == 0) &&
4740                         (strcmp(tokens[4], "read") == 0)) {
4741                         snprintf(out, out_size, "\n%s\n",
4742                                 cmd_pipeline_table_rule_meter_read_help);
4743                         return;
4744                 }
4745
4746                 if ((n_tokens == 5) &&
4747                         (strcmp(tokens[2], "rule") == 0) &&
4748                         (strcmp(tokens[3], "ttl") == 0) &&
4749                         (strcmp(tokens[4], "read") == 0)) {
4750                         snprintf(out, out_size, "\n%s\n",
4751                                 cmd_pipeline_table_rule_ttl_read_help);
4752                         return;
4753                 }
4754         }
4755
4756         if ((n_tokens == 3) &&
4757                 (strcmp(tokens[0], "thread") == 0) &&
4758                 (strcmp(tokens[1], "pipeline") == 0)) {
4759                 if (strcmp(tokens[2], "enable") == 0) {
4760                         snprintf(out, out_size, "\n%s\n",
4761                                 cmd_thread_pipeline_enable_help);
4762                         return;
4763                 }
4764
4765                 if (strcmp(tokens[2], "disable") == 0) {
4766                         snprintf(out, out_size, "\n%s\n",
4767                                 cmd_thread_pipeline_disable_help);
4768                         return;
4769                 }
4770         }
4771
4772         snprintf(out, out_size, "Invalid command\n");
4773 }
4774
4775 void
4776 cli_process(char *in, char *out, size_t out_size)
4777 {
4778         char *tokens[CMD_MAX_TOKENS];
4779         uint32_t n_tokens = RTE_DIM(tokens);
4780         int status;
4781
4782         if (is_comment(in))
4783                 return;
4784
4785         status = parse_tokenize_string(in, tokens, &n_tokens);
4786         if (status) {
4787                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
4788                 return;
4789         }
4790
4791         if (n_tokens == 0)
4792                 return;
4793
4794         if (strcmp(tokens[0], "help") == 0) {
4795                 cmd_help(tokens, n_tokens, out, out_size);
4796                 return;
4797         }
4798
4799         if (strcmp(tokens[0], "mempool") == 0) {
4800                 cmd_mempool(tokens, n_tokens, out, out_size);
4801                 return;
4802         }
4803
4804         if (strcmp(tokens[0], "link") == 0) {
4805                 if (strcmp(tokens[1], "show") == 0) {
4806                         cmd_link_show(tokens, n_tokens, out, out_size);
4807                         return;
4808                 }
4809
4810                 cmd_link(tokens, n_tokens, out, out_size);
4811                 return;
4812         }
4813
4814         if (strcmp(tokens[0], "swq") == 0) {
4815                 cmd_swq(tokens, n_tokens, out, out_size);
4816                 return;
4817         }
4818
4819         if (strcmp(tokens[0], "tmgr") == 0) {
4820                 if ((n_tokens >= 3) &&
4821                         (strcmp(tokens[1], "subport") == 0) &&
4822                         (strcmp(tokens[2], "profile") == 0)) {
4823                         cmd_tmgr_subport_profile(tokens, n_tokens,
4824                                 out, out_size);
4825                         return;
4826                 }
4827
4828                 if ((n_tokens >= 3) &&
4829                         (strcmp(tokens[1], "pipe") == 0) &&
4830                         (strcmp(tokens[2], "profile") == 0)) {
4831                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
4832                         return;
4833                 }
4834
4835                 if ((n_tokens >= 5) &&
4836                         (strcmp(tokens[2], "subport") == 0) &&
4837                         (strcmp(tokens[4], "profile") == 0)) {
4838                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
4839                         return;
4840                 }
4841
4842                 if ((n_tokens >= 5) &&
4843                         (strcmp(tokens[2], "subport") == 0) &&
4844                         (strcmp(tokens[4], "pipe") == 0)) {
4845                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
4846                         return;
4847                 }
4848
4849                 cmd_tmgr(tokens, n_tokens, out, out_size);
4850                 return;
4851         }
4852
4853         if (strcmp(tokens[0], "tap") == 0) {
4854                 cmd_tap(tokens, n_tokens, out, out_size);
4855                 return;
4856         }
4857
4858         if (strcmp(tokens[0], "kni") == 0) {
4859                 cmd_kni(tokens, n_tokens, out, out_size);
4860                 return;
4861         }
4862
4863         if (strcmp(tokens[0], "port") == 0) {
4864                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
4865                 return;
4866         }
4867
4868         if (strcmp(tokens[0], "table") == 0) {
4869                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
4870                 return;
4871         }
4872
4873         if (strcmp(tokens[0], "pipeline") == 0) {
4874                 if ((n_tokens >= 3) &&
4875                         (strcmp(tokens[2], "period") == 0)) {
4876                         cmd_pipeline(tokens, n_tokens, out, out_size);
4877                         return;
4878                 }
4879
4880                 if ((n_tokens >= 5) &&
4881                         (strcmp(tokens[2], "port") == 0) &&
4882                         (strcmp(tokens[3], "in") == 0) &&
4883                         (strcmp(tokens[4], "bsz") == 0)) {
4884                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
4885                         return;
4886                 }
4887
4888                 if ((n_tokens >= 5) &&
4889                         (strcmp(tokens[2], "port") == 0) &&
4890                         (strcmp(tokens[3], "out") == 0) &&
4891                         (strcmp(tokens[4], "bsz") == 0)) {
4892                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
4893                         return;
4894                 }
4895
4896                 if ((n_tokens >= 4) &&
4897                         (strcmp(tokens[2], "table") == 0) &&
4898                         (strcmp(tokens[3], "match") == 0)) {
4899                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
4900                         return;
4901                 }
4902
4903                 if ((n_tokens >= 6) &&
4904                         (strcmp(tokens[2], "port") == 0) &&
4905                         (strcmp(tokens[3], "in") == 0) &&
4906                         (strcmp(tokens[5], "table") == 0)) {
4907                         cmd_pipeline_port_in_table(tokens, n_tokens,
4908                                 out, out_size);
4909                         return;
4910                 }
4911
4912                 if ((n_tokens >= 6) &&
4913                         (strcmp(tokens[2], "port") == 0) &&
4914                         (strcmp(tokens[3], "in") == 0) &&
4915                         (strcmp(tokens[5], "stats") == 0)) {
4916                         cmd_pipeline_port_in_stats(tokens, n_tokens,
4917                                 out, out_size);
4918                         return;
4919                 }
4920
4921                 if ((n_tokens >= 6) &&
4922                         (strcmp(tokens[2], "port") == 0) &&
4923                         (strcmp(tokens[3], "in") == 0) &&
4924                         (strcmp(tokens[5], "enable") == 0)) {
4925                         cmd_pipeline_port_in_enable(tokens, n_tokens,
4926                                 out, out_size);
4927                         return;
4928                 }
4929
4930                 if ((n_tokens >= 6) &&
4931                         (strcmp(tokens[2], "port") == 0) &&
4932                         (strcmp(tokens[3], "in") == 0) &&
4933                         (strcmp(tokens[5], "disable") == 0)) {
4934                         cmd_pipeline_port_in_disable(tokens, n_tokens,
4935                                 out, out_size);
4936                         return;
4937                 }
4938
4939                 if ((n_tokens >= 6) &&
4940                         (strcmp(tokens[2], "port") == 0) &&
4941                         (strcmp(tokens[3], "out") == 0) &&
4942                         (strcmp(tokens[5], "stats") == 0)) {
4943                         cmd_pipeline_port_out_stats(tokens, n_tokens,
4944                                 out, out_size);
4945                         return;
4946                 }
4947
4948                 if ((n_tokens >= 5) &&
4949                         (strcmp(tokens[2], "table") == 0) &&
4950                         (strcmp(tokens[4], "stats") == 0)) {
4951                         cmd_pipeline_table_stats(tokens, n_tokens,
4952                                 out, out_size);
4953                         return;
4954                 }
4955
4956                 if ((n_tokens >= 7) &&
4957                         (strcmp(tokens[2], "table") == 0) &&
4958                         (strcmp(tokens[4], "rule") == 0) &&
4959                         (strcmp(tokens[5], "add") == 0) &&
4960                         (strcmp(tokens[6], "match") == 0)) {
4961                         if ((n_tokens >= 8) &&
4962                                 (strcmp(tokens[7], "default") == 0)) {
4963                                 cmd_pipeline_table_rule_add_default(tokens,
4964                                         n_tokens, out, out_size);
4965                                 return;
4966                         }
4967
4968                         cmd_pipeline_table_rule_add(tokens, n_tokens,
4969                                 out, out_size);
4970                         return;
4971                 }
4972
4973                 if ((n_tokens >= 7) &&
4974                         (strcmp(tokens[2], "table") == 0) &&
4975                         (strcmp(tokens[4], "rule") == 0) &&
4976                         (strcmp(tokens[5], "add") == 0) &&
4977                         (strcmp(tokens[6], "bulk") == 0)) {
4978                         cmd_pipeline_table_rule_add_bulk(tokens,
4979                                 n_tokens, out, out_size);
4980                         return;
4981                 }
4982
4983                 if ((n_tokens >= 7) &&
4984                         (strcmp(tokens[2], "table") == 0) &&
4985                         (strcmp(tokens[4], "rule") == 0) &&
4986                         (strcmp(tokens[5], "delete") == 0) &&
4987                         (strcmp(tokens[6], "match") == 0)) {
4988                         if ((n_tokens >= 8) &&
4989                                 (strcmp(tokens[7], "default") == 0)) {
4990                                 cmd_pipeline_table_rule_delete_default(tokens,
4991                                         n_tokens, out, out_size);
4992                                 return;
4993                                 }
4994
4995                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
4996                                 out, out_size);
4997                         return;
4998                 }
4999
5000                 if ((n_tokens >= 7) &&
5001                         (strcmp(tokens[2], "table") == 0) &&
5002                         (strcmp(tokens[4], "rule") == 0) &&
5003                         (strcmp(tokens[5], "read") == 0) &&
5004                         (strcmp(tokens[6], "stats") == 0)) {
5005                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
5006                                 out, out_size);
5007                         return;
5008                 }
5009
5010                 if ((n_tokens >= 8) &&
5011                         (strcmp(tokens[2], "table") == 0) &&
5012                         (strcmp(tokens[4], "meter") == 0) &&
5013                         (strcmp(tokens[5], "profile") == 0) &&
5014                         (strcmp(tokens[7], "add") == 0)) {
5015                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
5016                                 out, out_size);
5017                         return;
5018                 }
5019
5020                 if ((n_tokens >= 8) &&
5021                         (strcmp(tokens[2], "table") == 0) &&
5022                         (strcmp(tokens[4], "meter") == 0) &&
5023                         (strcmp(tokens[5], "profile") == 0) &&
5024                         (strcmp(tokens[7], "delete") == 0)) {
5025                         cmd_pipeline_table_meter_profile_delete(tokens,
5026                                 n_tokens, out, out_size);
5027                         return;
5028                 }
5029
5030                 if ((n_tokens >= 7) &&
5031                         (strcmp(tokens[2], "table") == 0) &&
5032                         (strcmp(tokens[4], "rule") == 0) &&
5033                         (strcmp(tokens[5], "read") == 0) &&
5034                         (strcmp(tokens[6], "meter") == 0)) {
5035                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
5036                                 out, out_size);
5037                         return;
5038                 }
5039
5040                 if ((n_tokens >= 5) &&
5041                         (strcmp(tokens[2], "table") == 0) &&
5042                         (strcmp(tokens[4], "dscp") == 0)) {
5043                         cmd_pipeline_table_dscp(tokens, n_tokens,
5044                                 out, out_size);
5045                         return;
5046                 }
5047
5048                 if ((n_tokens >= 7) &&
5049                         (strcmp(tokens[2], "table") == 0) &&
5050                         (strcmp(tokens[4], "rule") == 0) &&
5051                         (strcmp(tokens[5], "read") == 0) &&
5052                         (strcmp(tokens[6], "ttl") == 0)) {
5053                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
5054                                 out, out_size);
5055                         return;
5056                 }
5057         }
5058
5059         if (strcmp(tokens[0], "thread") == 0) {
5060                 if ((n_tokens >= 5) &&
5061                         (strcmp(tokens[4], "enable") == 0)) {
5062                         cmd_thread_pipeline_enable(tokens, n_tokens,
5063                                 out, out_size);
5064                         return;
5065                 }
5066
5067                 if ((n_tokens >= 5) &&
5068                         (strcmp(tokens[4], "disable") == 0)) {
5069                         cmd_thread_pipeline_disable(tokens, n_tokens,
5070                                 out, out_size);
5071                         return;
5072                 }
5073         }
5074
5075         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
5076 }
5077
5078 int
5079 cli_script_process(const char *file_name,
5080         size_t msg_in_len_max,
5081         size_t msg_out_len_max)
5082 {
5083         char *msg_in = NULL, *msg_out = NULL;
5084         FILE *f = NULL;
5085
5086         /* Check input arguments */
5087         if ((file_name == NULL) ||
5088                 (strlen(file_name) == 0) ||
5089                 (msg_in_len_max == 0) ||
5090                 (msg_out_len_max == 0))
5091                 return -EINVAL;
5092
5093         msg_in = malloc(msg_in_len_max + 1);
5094         msg_out = malloc(msg_out_len_max + 1);
5095         if ((msg_in == NULL) ||
5096                 (msg_out == NULL)) {
5097                 free(msg_out);
5098                 free(msg_in);
5099                 return -ENOMEM;
5100         }
5101
5102         /* Open input file */
5103         f = fopen(file_name, "r");
5104         if (f == NULL) {
5105                 free(msg_out);
5106                 free(msg_in);
5107                 return -EIO;
5108         }
5109
5110         /* Read file */
5111         for ( ; ; ) {
5112                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
5113                         break;
5114
5115                 printf("%s", msg_in);
5116                 msg_out[0] = 0;
5117
5118                 cli_process(msg_in,
5119                         msg_out,
5120                         msg_out_len_max);
5121
5122                 if (strlen(msg_out))
5123                         printf("%s", msg_out);
5124         }
5125
5126         /* Close file */
5127         fclose(f);
5128         free(msg_out);
5129         free(msg_in);
5130         return 0;
5131 }
5132
5133 static int
5134 cli_rule_file_process(const char *file_name,
5135         size_t line_len_max,
5136         struct table_rule_match *m,
5137         struct table_rule_action *a,
5138         uint32_t *n_rules,
5139         uint32_t *line_number,
5140         char *out,
5141         size_t out_size)
5142 {
5143         FILE *f = NULL;
5144         char *line = NULL;
5145         uint32_t rule_id, line_id;
5146         int status = 0;
5147
5148         /* Check input arguments */
5149         if ((file_name == NULL) ||
5150                 (strlen(file_name) == 0) ||
5151                 (line_len_max == 0)) {
5152                 *line_number = 0;
5153                 return -EINVAL;
5154         }
5155
5156         /* Memory allocation */
5157         line = malloc(line_len_max + 1);
5158         if (line == NULL) {
5159                 *line_number = 0;
5160                 return -ENOMEM;
5161         }
5162
5163         /* Open file */
5164         f = fopen(file_name, "r");
5165         if (f == NULL) {
5166                 *line_number = 0;
5167                 free(line);
5168                 return -EIO;
5169         }
5170
5171         /* Read file */
5172         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
5173                 char *tokens[CMD_MAX_TOKENS];
5174                 uint32_t n_tokens, n_tokens_parsed, t0;
5175
5176                 /* Read next line from file. */
5177                 if (fgets(line, line_len_max + 1, f) == NULL)
5178                         break;
5179
5180                 /* Comment. */
5181                 if (is_comment(line))
5182                         continue;
5183
5184                 /* Parse line. */
5185                 n_tokens = RTE_DIM(tokens);
5186                 status = parse_tokenize_string(line, tokens, &n_tokens);
5187                 if (status) {
5188                         status = -EINVAL;
5189                         break;
5190                 }
5191
5192                 /* Empty line. */
5193                 if (n_tokens == 0)
5194                         continue;
5195                 t0 = 0;
5196
5197                 /* Rule match. */
5198                 n_tokens_parsed = parse_match(tokens + t0,
5199                         n_tokens - t0,
5200                         out,
5201                         out_size,
5202                         &m[rule_id]);
5203                 if (n_tokens_parsed == 0) {
5204                         status = -EINVAL;
5205                         break;
5206                 }
5207                 t0 += n_tokens_parsed;
5208
5209                 /* Rule action. */
5210                 n_tokens_parsed = parse_table_action(tokens + t0,
5211                         n_tokens - t0,
5212                         out,
5213                         out_size,
5214                         &a[rule_id]);
5215                 if (n_tokens_parsed == 0) {
5216                         status = -EINVAL;
5217                         break;
5218                 }
5219                 t0 += n_tokens_parsed;
5220
5221                 /* Line completed. */
5222                 if (t0 < n_tokens) {
5223                         status = -EINVAL;
5224                         break;
5225                 }
5226
5227                 /* Increment rule count */
5228                 rule_id++;
5229         }
5230
5231         /* Close file */
5232         fclose(f);
5233
5234         /* Memory free */
5235         free(line);
5236
5237         *n_rules = rule_id;
5238         *line_number = line_id;
5239         return status;
5240 }