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