net/softnic: add command to enable/disable pipeline
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_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_eth_softnic_internals.h"
11 #include "parser.h"
12
13 #ifndef CMD_MAX_TOKENS
14 #define CMD_MAX_TOKENS     256
15 #endif
16
17 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
18 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
19 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
20 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
21 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
22 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
23 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
24 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
25 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
26 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
27 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
28
29 static int
30 is_comment(char *in)
31 {
32         if ((strlen(in) && index("!#%;", in[0])) ||
33                 (strncmp(in, "//", 2) == 0) ||
34                 (strncmp(in, "--", 2) == 0))
35                 return 1;
36
37         return 0;
38 }
39
40 /**
41  * mempool <mempool_name>
42  *  buffer <buffer_size>
43  *  pool <pool_size>
44  *  cache <cache_size>
45  */
46 static void
47 cmd_mempool(struct pmd_internals *softnic,
48         char **tokens,
49         uint32_t n_tokens,
50         char *out,
51         size_t out_size)
52 {
53         struct softnic_mempool_params p;
54         char *name;
55         struct softnic_mempool *mempool;
56
57         if (n_tokens != 8) {
58                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
59                 return;
60         }
61
62         name = tokens[1];
63
64         if (strcmp(tokens[2], "buffer") != 0) {
65                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
66                 return;
67         }
68
69         if (softnic_parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
70                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
71                 return;
72         }
73
74         if (strcmp(tokens[4], "pool") != 0) {
75                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
76                 return;
77         }
78
79         if (softnic_parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
80                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
81                 return;
82         }
83
84         if (strcmp(tokens[6], "cache") != 0) {
85                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
86                 return;
87         }
88
89         if (softnic_parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
90                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
91                 return;
92         }
93
94         mempool = softnic_mempool_create(softnic, name, &p);
95         if (mempool == NULL) {
96                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
97                 return;
98         }
99 }
100
101 /**
102  * link <link_name>
103  *    dev <device_name> | port <port_id>
104  */
105 static void
106 cmd_link(struct pmd_internals *softnic,
107         char **tokens,
108         uint32_t n_tokens,
109         char *out,
110         size_t out_size)
111 {
112         struct softnic_link_params p;
113         struct softnic_link *link;
114         char *name;
115
116         memset(&p, 0, sizeof(p));
117
118         if (n_tokens != 4) {
119                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
120                 return;
121         }
122         name = tokens[1];
123
124         if (strcmp(tokens[2], "dev") == 0) {
125                 p.dev_name = tokens[3];
126         } else if (strcmp(tokens[2], "port") == 0) {
127                 p.dev_name = NULL;
128
129                 if (softnic_parser_read_uint16(&p.port_id, tokens[3]) != 0) {
130                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
131                         return;
132                 }
133         } else {
134                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
135                 return;
136         }
137
138         link = softnic_link_create(softnic, name, &p);
139         if (link == NULL) {
140                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
141                 return;
142         }
143 }
144
145 /**
146  * swq <swq_name>
147  *  size <size>
148  */
149 static void
150 cmd_swq(struct pmd_internals *softnic,
151         char **tokens,
152         uint32_t n_tokens,
153         char *out,
154         size_t out_size)
155 {
156         struct softnic_swq_params p;
157         char *name;
158         struct softnic_swq *swq;
159
160         if (n_tokens != 4) {
161                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
162                 return;
163         }
164
165         name = tokens[1];
166
167         if (strcmp(tokens[2], "size") != 0) {
168                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
169                 return;
170         }
171
172         if (softnic_parser_read_uint32(&p.size, tokens[3]) != 0) {
173                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
174                 return;
175         }
176
177         swq = softnic_swq_create(softnic, name, &p);
178         if (swq == NULL) {
179                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
180                 return;
181         }
182 }
183
184 /**
185  * tap <tap_name>
186  */
187 static void
188 cmd_tap(struct pmd_internals *softnic,
189         char **tokens,
190         uint32_t n_tokens,
191         char *out,
192         size_t out_size)
193 {
194         char *name;
195         struct softnic_tap *tap;
196
197         if (n_tokens != 2) {
198                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
199                 return;
200         }
201
202         name = tokens[1];
203
204         tap = softnic_tap_create(softnic, name);
205         if (tap == NULL) {
206                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
207                 return;
208         }
209 }
210
211 /**
212  * port in action profile <profile_name>
213  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
214  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
215  */
216 static void
217 cmd_port_in_action_profile(struct pmd_internals *softnic,
218         char **tokens,
219         uint32_t n_tokens,
220         char *out,
221         size_t out_size)
222 {
223         struct softnic_port_in_action_profile_params p;
224         struct softnic_port_in_action_profile *ap;
225         char *name;
226         uint32_t t0;
227
228         memset(&p, 0, sizeof(p));
229
230         if (n_tokens < 5) {
231                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
232                 return;
233         }
234
235         if (strcmp(tokens[1], "in") != 0) {
236                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
237                 return;
238         }
239
240         if (strcmp(tokens[2], "action") != 0) {
241                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
242                 return;
243         }
244
245         if (strcmp(tokens[3], "profile") != 0) {
246                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
247                 return;
248         }
249
250         name = tokens[4];
251
252         t0 = 5;
253
254         if (t0 < n_tokens &&
255                 (strcmp(tokens[t0], "filter") == 0)) {
256                 uint32_t size;
257
258                 if (n_tokens < t0 + 10) {
259                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
260                         return;
261                 }
262
263                 if (strcmp(tokens[t0 + 1], "match") == 0) {
264                         p.fltr.filter_on_match = 1;
265                 } else if (strcmp(tokens[t0 + 1], "mismatch") == 0) {
266                         p.fltr.filter_on_match = 0;
267                 } else {
268                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
269                         return;
270                 }
271
272                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
273                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
274                         return;
275                 }
276
277                 if (softnic_parser_read_uint32(&p.fltr.key_offset,
278                         tokens[t0 + 3]) != 0) {
279                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
280                         return;
281                 }
282
283                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
284                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
285                         return;
286                 }
287
288                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
289                 if ((softnic_parse_hex_string(tokens[t0 + 5],
290                         p.fltr.key_mask, &size) != 0) ||
291                         size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
292                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
293                         return;
294                 }
295
296                 if (strcmp(tokens[t0 + 6], "key") != 0) {
297                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
298                         return;
299                 }
300
301                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
302                 if ((softnic_parse_hex_string(tokens[t0 + 7],
303                         p.fltr.key, &size) != 0) ||
304                         size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
305                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
306                         return;
307                 }
308
309                 if (strcmp(tokens[t0 + 8], "port") != 0) {
310                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
311                         return;
312                 }
313
314                 if (softnic_parser_read_uint32(&p.fltr.port_id,
315                         tokens[t0 + 9]) != 0) {
316                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
317                         return;
318                 }
319
320                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
321                 t0 += 10;
322         } /* filter */
323
324         if (t0 < n_tokens &&
325                 (strcmp(tokens[t0], "balance") == 0)) {
326                 uint32_t i;
327
328                 if (n_tokens < t0 + 22) {
329                         snprintf(out, out_size, MSG_ARG_MISMATCH,
330                                 "port in action profile balance");
331                         return;
332                 }
333
334                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
335                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
336                         return;
337                 }
338
339                 if (softnic_parser_read_uint32(&p.lb.key_offset,
340                         tokens[t0 + 2]) != 0) {
341                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
342                         return;
343                 }
344
345                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
346                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
347                         return;
348                 }
349
350                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
351                 if (softnic_parse_hex_string(tokens[t0 + 4],
352                         p.lb.key_mask, &p.lb.key_size) != 0) {
353                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
354                         return;
355                 }
356
357                 if (strcmp(tokens[t0 + 5], "port") != 0) {
358                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
359                         return;
360                 }
361
362                 for (i = 0; i < 16; i++)
363                         if (softnic_parser_read_uint32(&p.lb.port_id[i],
364                         tokens[t0 + 6 + i]) != 0) {
365                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
366                                 return;
367                         }
368
369                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
370                 t0 += 22;
371         } /* balance */
372
373         if (t0 < n_tokens) {
374                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
375                 return;
376         }
377
378         ap = softnic_port_in_action_profile_create(softnic, name, &p);
379         if (ap == NULL) {
380                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
381                 return;
382         }
383 }
384
385 /**
386  * table action profile <profile_name>
387  *  ipv4 | ipv6
388  *  offset <ip_offset>
389  *  fwd
390  *  [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]
391  *  [meter srtcm | trtcm
392  *      tc <n_tc>
393  *      stats none | pkts | bytes | both]
394  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
395  *  [encap ether | vlan | qinq | mpls | pppoe]
396  *  [nat src | dst
397  *      proto udp | tcp]
398  *  [ttl drop | fwd
399  *      stats none | pkts]
400  *  [stats pkts | bytes | both]
401  *  [time]
402  */
403 static void
404 cmd_table_action_profile(struct pmd_internals *softnic,
405         char **tokens,
406         uint32_t n_tokens,
407         char *out,
408         size_t out_size)
409 {
410         struct softnic_table_action_profile_params p;
411         struct softnic_table_action_profile *ap;
412         char *name;
413         uint32_t t0;
414
415         memset(&p, 0, sizeof(p));
416
417         if (n_tokens < 8) {
418                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
419                 return;
420         }
421
422         if (strcmp(tokens[1], "action") != 0) {
423                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
424                 return;
425         }
426
427         if (strcmp(tokens[2], "profile") != 0) {
428                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
429                 return;
430         }
431
432         name = tokens[3];
433
434         if (strcmp(tokens[4], "ipv4") == 0) {
435                 p.common.ip_version = 1;
436         } else if (strcmp(tokens[4], "ipv6") == 0) {
437                 p.common.ip_version = 0;
438         } else {
439                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
440                 return;
441         }
442
443         if (strcmp(tokens[5], "offset") != 0) {
444                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
445                 return;
446         }
447
448         if (softnic_parser_read_uint32(&p.common.ip_offset,
449                 tokens[6]) != 0) {
450                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
451                 return;
452         }
453
454         if (strcmp(tokens[7], "fwd") != 0) {
455                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
456                 return;
457         }
458
459         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
460
461         t0 = 8;
462         if (t0 < n_tokens &&
463                 (strcmp(tokens[t0], "balance") == 0)) {
464                 if (n_tokens < t0 + 7) {
465                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
466                         return;
467                 }
468
469                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
470                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
471                         return;
472                 }
473
474                 if (softnic_parser_read_uint32(&p.lb.key_offset,
475                         tokens[t0 + 2]) != 0) {
476                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
477                         return;
478                 }
479
480                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
481                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
482                         return;
483                 }
484
485                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
486                 if (softnic_parse_hex_string(tokens[t0 + 4],
487                         p.lb.key_mask, &p.lb.key_size) != 0) {
488                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
489                         return;
490                 }
491
492                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
493                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
494                         return;
495                 }
496
497                 if (softnic_parser_read_uint32(&p.lb.out_offset,
498                         tokens[t0 + 6]) != 0) {
499                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
500                         return;
501                 }
502
503                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
504                 t0 += 7;
505         } /* balance */
506
507         if (t0 < n_tokens &&
508                 (strcmp(tokens[t0], "meter") == 0)) {
509                 if (n_tokens < t0 + 6) {
510                         snprintf(out, out_size, MSG_ARG_MISMATCH,
511                                 "table action profile meter");
512                         return;
513                 }
514
515                 if (strcmp(tokens[t0 + 1], "srtcm") == 0) {
516                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
517                 } else if (strcmp(tokens[t0 + 1], "trtcm") == 0) {
518                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
519                 } else {
520                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
521                                 "srtcm or trtcm");
522                         return;
523                 }
524
525                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
526                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
527                         return;
528                 }
529
530                 if (softnic_parser_read_uint32(&p.mtr.n_tc,
531                         tokens[t0 + 3]) != 0) {
532                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
533                         return;
534                 }
535
536                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
537                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
538                         return;
539                 }
540
541                 if (strcmp(tokens[t0 + 5], "none") == 0) {
542                         p.mtr.n_packets_enabled = 0;
543                         p.mtr.n_bytes_enabled = 0;
544                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
545                         p.mtr.n_packets_enabled = 1;
546                         p.mtr.n_bytes_enabled = 0;
547                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
548                         p.mtr.n_packets_enabled = 0;
549                         p.mtr.n_bytes_enabled = 1;
550                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
551                         p.mtr.n_packets_enabled = 1;
552                         p.mtr.n_bytes_enabled = 1;
553                 } else {
554                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
555                                 "none or pkts or bytes or both");
556                         return;
557                 }
558
559                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
560                 t0 += 6;
561         } /* meter */
562
563         if (t0 < n_tokens &&
564                 (strcmp(tokens[t0], "tm") == 0)) {
565                 if (n_tokens < t0 + 5) {
566                         snprintf(out, out_size, MSG_ARG_MISMATCH,
567                                 "table action profile tm");
568                         return;
569                 }
570
571                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
572                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
573                         return;
574                 }
575
576                 if (softnic_parser_read_uint32(&p.tm.n_subports_per_port,
577                         tokens[t0 + 2]) != 0) {
578                         snprintf(out, out_size, MSG_ARG_INVALID,
579                                 "n_subports_per_port");
580                         return;
581                 }
582
583                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
584                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
585                         return;
586                 }
587
588                 if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport,
589                         tokens[t0 + 4]) != 0) {
590                         snprintf(out, out_size, MSG_ARG_INVALID,
591                                 "n_pipes_per_subport");
592                         return;
593                 }
594
595                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
596                 t0 += 5;
597         } /* tm */
598
599         if (t0 < n_tokens &&
600                 (strcmp(tokens[t0], "encap") == 0)) {
601                 if (n_tokens < t0 + 2) {
602                         snprintf(out, out_size, MSG_ARG_MISMATCH,
603                                 "action profile encap");
604                         return;
605                 }
606
607                 if (strcmp(tokens[t0 + 1], "ether") == 0) {
608                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
609                 } else if (strcmp(tokens[t0 + 1], "vlan") == 0) {
610                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
611                 } else if (strcmp(tokens[t0 + 1], "qinq") == 0) {
612                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
613                 } else if (strcmp(tokens[t0 + 1], "mpls") == 0) {
614                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
615                 } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) {
616                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
617                 } else {
618                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
619                         return;
620                 }
621
622                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
623                 t0 += 2;
624         } /* encap */
625
626         if (t0 < n_tokens &&
627                 (strcmp(tokens[t0], "nat") == 0)) {
628                 if (n_tokens < t0 + 4) {
629                         snprintf(out, out_size, MSG_ARG_MISMATCH,
630                                 "table action profile nat");
631                         return;
632                 }
633
634                 if (strcmp(tokens[t0 + 1], "src") == 0) {
635                         p.nat.source_nat = 1;
636                 } else if (strcmp(tokens[t0 + 1], "dst") == 0) {
637                         p.nat.source_nat = 0;
638                 } else {
639                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
640                                 "src or dst");
641                         return;
642                 }
643
644                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
645                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
646                         return;
647                 }
648
649                 if (strcmp(tokens[t0 + 3], "tcp") == 0) {
650                         p.nat.proto = 0x06;
651                 } else if (strcmp(tokens[t0 + 3], "udp") == 0) {
652                         p.nat.proto = 0x11;
653                 } else {
654                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
655                                 "tcp or udp");
656                         return;
657                 }
658
659                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
660                 t0 += 4;
661         } /* nat */
662
663         if (t0 < n_tokens &&
664                 (strcmp(tokens[t0], "ttl") == 0)) {
665                 if (n_tokens < t0 + 4) {
666                         snprintf(out, out_size, MSG_ARG_MISMATCH,
667                                 "table action profile ttl");
668                         return;
669                 }
670
671                 if (strcmp(tokens[t0 + 1], "drop") == 0) {
672                         p.ttl.drop = 1;
673                 } else if (strcmp(tokens[t0 + 1], "fwd") == 0) {
674                         p.ttl.drop = 0;
675                 } else {
676                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
677                                 "drop or fwd");
678                         return;
679                 }
680
681                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
682                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
683                         return;
684                 }
685
686                 if (strcmp(tokens[t0 + 3], "none") == 0) {
687                         p.ttl.n_packets_enabled = 0;
688                 } else if (strcmp(tokens[t0 + 3], "pkts") == 0) {
689                         p.ttl.n_packets_enabled = 1;
690                 } else {
691                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
692                                 "none or pkts");
693                         return;
694                 }
695
696                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
697                 t0 += 4;
698         } /* ttl */
699
700         if (t0 < n_tokens &&
701                 (strcmp(tokens[t0], "stats") == 0)) {
702                 if (n_tokens < t0 + 2) {
703                         snprintf(out, out_size, MSG_ARG_MISMATCH,
704                                 "table action profile stats");
705                         return;
706                 }
707
708                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
709                         p.stats.n_packets_enabled = 1;
710                         p.stats.n_bytes_enabled = 0;
711                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
712                         p.stats.n_packets_enabled = 0;
713                         p.stats.n_bytes_enabled = 1;
714                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
715                         p.stats.n_packets_enabled = 1;
716                         p.stats.n_bytes_enabled = 1;
717                 } else {
718                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
719                                 "pkts or bytes or both");
720                         return;
721                 }
722
723                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
724                 t0 += 2;
725         } /* stats */
726
727         if (t0 < n_tokens &&
728                 (strcmp(tokens[t0], "time") == 0)) {
729                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
730                 t0 += 1;
731         } /* time */
732
733         if (t0 < n_tokens) {
734                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
735                 return;
736         }
737
738         ap = softnic_table_action_profile_create(softnic, name, &p);
739         if (ap == NULL) {
740                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
741                 return;
742         }
743 }
744
745 /**
746  * pipeline <pipeline_name>
747  *  period <timer_period_ms>
748  *  offset_port_id <offset_port_id>
749  */
750 static void
751 cmd_pipeline(struct pmd_internals *softnic,
752         char **tokens,
753         uint32_t n_tokens,
754         char *out,
755         size_t out_size)
756 {
757         struct pipeline_params p;
758         char *name;
759         struct pipeline *pipeline;
760
761         if (n_tokens != 6) {
762                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
763                 return;
764         }
765
766         name = tokens[1];
767
768         if (strcmp(tokens[2], "period") != 0) {
769                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
770                 return;
771         }
772
773         if (softnic_parser_read_uint32(&p.timer_period_ms,
774                 tokens[3]) != 0) {
775                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
776                 return;
777         }
778
779         if (strcmp(tokens[4], "offset_port_id") != 0) {
780                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
781                 return;
782         }
783
784         if (softnic_parser_read_uint32(&p.offset_port_id,
785                 tokens[5]) != 0) {
786                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
787                 return;
788         }
789
790         pipeline = softnic_pipeline_create(softnic, name, &p);
791         if (pipeline == NULL) {
792                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
793                 return;
794         }
795 }
796
797 /**
798  * pipeline <pipeline_name> port in
799  *  bsz <burst_size>
800  *  link <link_name> rxq <queue_id>
801  *  | swq <swq_name>
802  *  | tmgr <tmgr_name>
803  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
804  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
805  *  [action <port_in_action_profile_name>]
806  *  [disabled]
807  */
808 static void
809 cmd_pipeline_port_in(struct pmd_internals *softnic,
810         char **tokens,
811         uint32_t n_tokens,
812         char *out,
813         size_t out_size)
814 {
815         struct softnic_port_in_params p;
816         char *pipeline_name;
817         uint32_t t0;
818         int enabled, status;
819
820         if (n_tokens < 7) {
821                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
822                 return;
823         }
824
825         pipeline_name = tokens[1];
826
827         if (strcmp(tokens[2], "port") != 0) {
828                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
829                 return;
830         }
831
832         if (strcmp(tokens[3], "in") != 0) {
833                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
834                 return;
835         }
836
837         if (strcmp(tokens[4], "bsz") != 0) {
838                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
839                 return;
840         }
841
842         if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
843                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
844                 return;
845         }
846
847         t0 = 6;
848
849         if (strcmp(tokens[t0], "link") == 0) {
850                 if (n_tokens < t0 + 4) {
851                         snprintf(out, out_size, MSG_ARG_MISMATCH,
852                                 "pipeline port in link");
853                         return;
854                 }
855
856                 p.type = PORT_IN_RXQ;
857
858                 p.dev_name = tokens[t0 + 1];
859
860                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
861                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
862                         return;
863                 }
864
865                 if (softnic_parser_read_uint16(&p.rxq.queue_id,
866                         tokens[t0 + 3]) != 0) {
867                         snprintf(out, out_size, MSG_ARG_INVALID,
868                                 "queue_id");
869                         return;
870                 }
871                 t0 += 4;
872         } else if (strcmp(tokens[t0], "swq") == 0) {
873                 if (n_tokens < t0 + 2) {
874                         snprintf(out, out_size, MSG_ARG_MISMATCH,
875                                 "pipeline port in swq");
876                         return;
877                 }
878
879                 p.type = PORT_IN_SWQ;
880
881                 p.dev_name = tokens[t0 + 1];
882
883                 t0 += 2;
884         } else if (strcmp(tokens[t0], "tmgr") == 0) {
885                 if (n_tokens < t0 + 2) {
886                         snprintf(out, out_size, MSG_ARG_MISMATCH,
887                                 "pipeline port in tmgr");
888                         return;
889                 }
890
891                 p.type = PORT_IN_TMGR;
892
893                 p.dev_name = tokens[t0 + 1];
894
895                 t0 += 2;
896         } else if (strcmp(tokens[t0], "tap") == 0) {
897                 if (n_tokens < t0 + 6) {
898                         snprintf(out, out_size, MSG_ARG_MISMATCH,
899                                 "pipeline port in tap");
900                         return;
901                 }
902
903                 p.type = PORT_IN_TAP;
904
905                 p.dev_name = tokens[t0 + 1];
906
907                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
908                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
909                                 "mempool");
910                         return;
911                 }
912
913                 p.tap.mempool_name = tokens[t0 + 3];
914
915                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
916                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
917                                 "mtu");
918                         return;
919                 }
920
921                 if (softnic_parser_read_uint32(&p.tap.mtu,
922                         tokens[t0 + 5]) != 0) {
923                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
924                         return;
925                 }
926
927                 t0 += 6;
928         } else if (strcmp(tokens[t0], "source") == 0) {
929                 if (n_tokens < t0 + 6) {
930                         snprintf(out, out_size, MSG_ARG_MISMATCH,
931                                 "pipeline port in source");
932                         return;
933                 }
934
935                 p.type = PORT_IN_SOURCE;
936
937                 p.dev_name = NULL;
938
939                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
940                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
941                                 "mempool");
942                         return;
943                 }
944
945                 p.source.mempool_name = tokens[t0 + 2];
946
947                 if (strcmp(tokens[t0 + 3], "file") != 0) {
948                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
949                                 "file");
950                         return;
951                 }
952
953                 p.source.file_name = tokens[t0 + 4];
954
955                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
956                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
957                                 "bpp");
958                         return;
959                 }
960
961                 if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt,
962                         tokens[t0 + 6]) != 0) {
963                         snprintf(out, out_size, MSG_ARG_INVALID,
964                                 "n_bytes_per_pkt");
965                         return;
966                 }
967
968                 t0 += 7;
969         } else {
970                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
971                 return;
972         }
973
974         p.action_profile_name = NULL;
975         if (n_tokens > t0 &&
976                 (strcmp(tokens[t0], "action") == 0)) {
977                 if (n_tokens < t0 + 2) {
978                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
979                         return;
980                 }
981
982                 p.action_profile_name = tokens[t0 + 1];
983
984                 t0 += 2;
985         }
986
987         enabled = 1;
988         if (n_tokens > t0 &&
989                 (strcmp(tokens[t0], "disabled") == 0)) {
990                 enabled = 0;
991
992                 t0 += 1;
993         }
994
995         if (n_tokens != t0) {
996                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
997                 return;
998         }
999
1000         status = softnic_pipeline_port_in_create(softnic,
1001                 pipeline_name,
1002                 &p,
1003                 enabled);
1004         if (status) {
1005                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1006                 return;
1007         }
1008 }
1009
1010 /**
1011  * pipeline <pipeline_name> port out
1012  *  bsz <burst_size>
1013  *  link <link_name> txq <txq_id>
1014  *  | swq <swq_name>
1015  *  | tmgr <tmgr_name>
1016  *  | tap <tap_name>
1017  *  | sink [file <file_name> pkts <max_n_pkts>]
1018  */
1019 static void
1020 cmd_pipeline_port_out(struct pmd_internals *softnic,
1021         char **tokens,
1022         uint32_t n_tokens,
1023         char *out,
1024         size_t out_size)
1025 {
1026         struct softnic_port_out_params p;
1027         char *pipeline_name;
1028         int status;
1029
1030         memset(&p, 0, sizeof(p));
1031
1032         if (n_tokens < 7) {
1033                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1034                 return;
1035         }
1036
1037         pipeline_name = tokens[1];
1038
1039         if (strcmp(tokens[2], "port") != 0) {
1040                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1041                 return;
1042         }
1043
1044         if (strcmp(tokens[3], "out") != 0) {
1045                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1046                 return;
1047         }
1048
1049         if (strcmp(tokens[4], "bsz") != 0) {
1050                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1051                 return;
1052         }
1053
1054         if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1055                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1056                 return;
1057         }
1058
1059         if (strcmp(tokens[6], "link") == 0) {
1060                 if (n_tokens != 10) {
1061                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1062                                 "pipeline port out link");
1063                         return;
1064                 }
1065
1066                 p.type = PORT_OUT_TXQ;
1067
1068                 p.dev_name = tokens[7];
1069
1070                 if (strcmp(tokens[8], "txq") != 0) {
1071                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1072                         return;
1073                 }
1074
1075                 if (softnic_parser_read_uint16(&p.txq.queue_id,
1076                         tokens[9]) != 0) {
1077                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1078                         return;
1079                 }
1080         } else if (strcmp(tokens[6], "swq") == 0) {
1081                 if (n_tokens != 8) {
1082                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1083                                 "pipeline port out swq");
1084                         return;
1085                 }
1086
1087                 p.type = PORT_OUT_SWQ;
1088
1089                 p.dev_name = tokens[7];
1090         } else if (strcmp(tokens[6], "tmgr") == 0) {
1091                 if (n_tokens != 8) {
1092                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1093                                 "pipeline port out tmgr");
1094                         return;
1095                 }
1096
1097                 p.type = PORT_OUT_TMGR;
1098
1099                 p.dev_name = tokens[7];
1100         } else if (strcmp(tokens[6], "tap") == 0) {
1101                 if (n_tokens != 8) {
1102                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1103                                 "pipeline port out tap");
1104                         return;
1105                 }
1106
1107                 p.type = PORT_OUT_TAP;
1108
1109                 p.dev_name = tokens[7];
1110         } else if (strcmp(tokens[6], "sink") == 0) {
1111                 if ((n_tokens != 7) && (n_tokens != 11)) {
1112                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1113                                 "pipeline port out sink");
1114                         return;
1115                 }
1116
1117                 p.type = PORT_OUT_SINK;
1118
1119                 p.dev_name = NULL;
1120
1121                 if (n_tokens == 7) {
1122                         p.sink.file_name = NULL;
1123                         p.sink.max_n_pkts = 0;
1124                 } else {
1125                         if (strcmp(tokens[7], "file") != 0) {
1126                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1127                                         "file");
1128                                 return;
1129                         }
1130
1131                         p.sink.file_name = tokens[8];
1132
1133                         if (strcmp(tokens[9], "pkts") != 0) {
1134                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1135                                 return;
1136                         }
1137
1138                         if (softnic_parser_read_uint32(&p.sink.max_n_pkts,
1139                                 tokens[10]) != 0) {
1140                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1141                                 return;
1142                         }
1143                 }
1144         } else {
1145                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1146                 return;
1147         }
1148
1149         status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p);
1150         if (status) {
1151                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1152                 return;
1153         }
1154 }
1155
1156 /**
1157  * pipeline <pipeline_name> table
1158  *      match
1159  *      acl
1160  *          ipv4 | ipv6
1161  *          offset <ip_header_offset>
1162  *          size <n_rules>
1163  *      | array
1164  *          offset <key_offset>
1165  *          size <n_keys>
1166  *      | hash
1167  *          ext | lru
1168  *          key <key_size>
1169  *          mask <key_mask>
1170  *          offset <key_offset>
1171  *          buckets <n_buckets>
1172  *          size <n_keys>
1173  *      | lpm
1174  *          ipv4 | ipv6
1175  *          offset <ip_header_offset>
1176  *          size <n_rules>
1177  *      | stub
1178  *  [action <table_action_profile_name>]
1179  */
1180 static void
1181 cmd_pipeline_table(struct pmd_internals *softnic,
1182         char **tokens,
1183         uint32_t n_tokens,
1184         char *out,
1185         size_t out_size)
1186 {
1187         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1188         struct softnic_table_params p;
1189         char *pipeline_name;
1190         uint32_t t0;
1191         int status;
1192
1193         if (n_tokens < 5) {
1194                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1195                 return;
1196         }
1197
1198         pipeline_name = tokens[1];
1199
1200         if (strcmp(tokens[2], "table") != 0) {
1201                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1202                 return;
1203         }
1204
1205         if (strcmp(tokens[3], "match") != 0) {
1206                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1207                 return;
1208         }
1209
1210         t0 = 4;
1211         if (strcmp(tokens[t0], "acl") == 0) {
1212                 if (n_tokens < t0 + 6) {
1213                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1214                                 "pipeline table acl");
1215                         return;
1216                 }
1217
1218                 p.match_type = TABLE_ACL;
1219
1220                 if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
1221                         p.match.acl.ip_version = 1;
1222                 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
1223                         p.match.acl.ip_version = 0;
1224                 } else {
1225                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1226                                 "ipv4 or ipv6");
1227                         return;
1228                 }
1229
1230                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1231                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1232                         return;
1233                 }
1234
1235                 if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset,
1236                         tokens[t0 + 3]) != 0) {
1237                         snprintf(out, out_size, MSG_ARG_INVALID,
1238                                 "ip_header_offset");
1239                         return;
1240                 }
1241
1242                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1243                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1244                         return;
1245                 }
1246
1247                 if (softnic_parser_read_uint32(&p.match.acl.n_rules,
1248                         tokens[t0 + 5]) != 0) {
1249                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1250                         return;
1251                 }
1252
1253                 t0 += 6;
1254         } else if (strcmp(tokens[t0], "array") == 0) {
1255                 if (n_tokens < t0 + 5) {
1256                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1257                                 "pipeline table array");
1258                         return;
1259                 }
1260
1261                 p.match_type = TABLE_ARRAY;
1262
1263                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1264                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1265                         return;
1266                 }
1267
1268                 if (softnic_parser_read_uint32(&p.match.array.key_offset,
1269                         tokens[t0 + 2]) != 0) {
1270                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1271                         return;
1272                 }
1273
1274                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1275                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1276                         return;
1277                 }
1278
1279                 if (softnic_parser_read_uint32(&p.match.array.n_keys,
1280                         tokens[t0 + 4]) != 0) {
1281                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1282                         return;
1283                 }
1284
1285                 t0 += 5;
1286         } else if (strcmp(tokens[t0], "hash") == 0) {
1287                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1288
1289                 if (n_tokens < t0 + 12) {
1290                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1291                                 "pipeline table hash");
1292                         return;
1293                 }
1294
1295                 p.match_type = TABLE_HASH;
1296
1297                 if (strcmp(tokens[t0 + 1], "ext") == 0) {
1298                         p.match.hash.extendable_bucket = 1;
1299                 } else if (strcmp(tokens[t0 + 1], "lru") == 0) {
1300                         p.match.hash.extendable_bucket = 0;
1301                 } else {
1302                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1303                                 "ext or lru");
1304                         return;
1305                 }
1306
1307                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1308                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1309                         return;
1310                 }
1311
1312                 if ((softnic_parser_read_uint32(&p.match.hash.key_size,
1313                         tokens[t0 + 3]) != 0) ||
1314                         p.match.hash.key_size == 0 ||
1315                         p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) {
1316                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1317                         return;
1318                 }
1319
1320                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1321                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1322                         return;
1323                 }
1324
1325                 if ((softnic_parse_hex_string(tokens[t0 + 5],
1326                         key_mask, &key_mask_size) != 0) ||
1327                         key_mask_size != p.match.hash.key_size) {
1328                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1329                         return;
1330                 }
1331                 p.match.hash.key_mask = key_mask;
1332
1333                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1334                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1335                         return;
1336                 }
1337
1338                 if (softnic_parser_read_uint32(&p.match.hash.key_offset,
1339                         tokens[t0 + 7]) != 0) {
1340                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1341                         return;
1342                 }
1343
1344                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1345                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1346                         return;
1347                 }
1348
1349                 if (softnic_parser_read_uint32(&p.match.hash.n_buckets,
1350                         tokens[t0 + 9]) != 0) {
1351                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1352                         return;
1353                 }
1354
1355                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1356                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1357                         return;
1358                 }
1359
1360                 if (softnic_parser_read_uint32(&p.match.hash.n_keys,
1361                         tokens[t0 + 11]) != 0) {
1362                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1363                         return;
1364                 }
1365
1366                 t0 += 12;
1367         } else if (strcmp(tokens[t0], "lpm") == 0) {
1368                 if (n_tokens < t0 + 6) {
1369                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1370                                 "pipeline table lpm");
1371                         return;
1372                 }
1373
1374                 p.match_type = TABLE_LPM;
1375
1376                 if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
1377                         p.match.lpm.key_size = 4;
1378                 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
1379                         p.match.lpm.key_size = 16;
1380                 } else {
1381                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1382                                 "ipv4 or ipv6");
1383                         return;
1384                 }
1385
1386                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1387                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1388                         return;
1389                 }
1390
1391                 if (softnic_parser_read_uint32(&p.match.lpm.key_offset,
1392                         tokens[t0 + 3]) != 0) {
1393                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1394                         return;
1395                 }
1396
1397                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1398                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1399                         return;
1400                 }
1401
1402                 if (softnic_parser_read_uint32(&p.match.lpm.n_rules,
1403                         tokens[t0 + 5]) != 0) {
1404                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1405                         return;
1406                 }
1407
1408                 t0 += 6;
1409         } else if (strcmp(tokens[t0], "stub") == 0) {
1410                 p.match_type = TABLE_STUB;
1411
1412                 t0 += 1;
1413         } else {
1414                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1415                 return;
1416         }
1417
1418         p.action_profile_name = NULL;
1419         if (n_tokens > t0 &&
1420                 (strcmp(tokens[t0], "action") == 0)) {
1421                 if (n_tokens < t0 + 2) {
1422                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1423                         return;
1424                 }
1425
1426                 p.action_profile_name = tokens[t0 + 1];
1427
1428                 t0 += 2;
1429         }
1430
1431         if (n_tokens > t0) {
1432                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1433                 return;
1434         }
1435
1436         status = softnic_pipeline_table_create(softnic, pipeline_name, &p);
1437         if (status) {
1438                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1439                 return;
1440         }
1441 }
1442
1443 /**
1444  * pipeline <pipeline_name> port in <port_id> table <table_id>
1445  */
1446 static void
1447 cmd_pipeline_port_in_table(struct pmd_internals *softnic,
1448         char **tokens,
1449         uint32_t n_tokens,
1450         char *out,
1451         size_t out_size)
1452 {
1453         char *pipeline_name;
1454         uint32_t port_id, table_id;
1455         int status;
1456
1457         if (n_tokens != 7) {
1458                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1459                 return;
1460         }
1461
1462         pipeline_name = tokens[1];
1463
1464         if (strcmp(tokens[2], "port") != 0) {
1465                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1466                 return;
1467         }
1468
1469         if (strcmp(tokens[3], "in") != 0) {
1470                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1471                 return;
1472         }
1473
1474         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1475                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1476                 return;
1477         }
1478
1479         if (strcmp(tokens[5], "table") != 0) {
1480                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1481                 return;
1482         }
1483
1484         if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) {
1485                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1486                 return;
1487         }
1488
1489         status = softnic_pipeline_port_in_connect_to_table(softnic,
1490                 pipeline_name,
1491                 port_id,
1492                 table_id);
1493         if (status) {
1494                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1495                 return;
1496         }
1497 }
1498
1499 /**
1500  * pipeline <pipeline_name> port in <port_id> enable
1501  */
1502 static void
1503 cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
1504         char **tokens,
1505         uint32_t n_tokens,
1506         char *out,
1507         size_t out_size)
1508 {
1509         char *pipeline_name;
1510         uint32_t port_id;
1511         int status;
1512
1513         if (n_tokens != 6) {
1514                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1515                 return;
1516         }
1517
1518         pipeline_name = tokens[1];
1519
1520         if (strcmp(tokens[2], "port") != 0) {
1521                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1522                 return;
1523         }
1524
1525         if (strcmp(tokens[3], "in") != 0) {
1526                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1527                 return;
1528         }
1529
1530         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1531                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1532                 return;
1533         }
1534
1535         if (strcmp(tokens[5], "enable") != 0) {
1536                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1537                 return;
1538         }
1539
1540         status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id);
1541         if (status) {
1542                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1543                 return;
1544         }
1545 }
1546
1547 /**
1548  * pipeline <pipeline_name> port in <port_id> disable
1549  */
1550 static void
1551 cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
1552         char **tokens,
1553         uint32_t n_tokens,
1554         char *out,
1555         size_t out_size)
1556 {
1557         char *pipeline_name;
1558         uint32_t port_id;
1559         int status;
1560
1561         if (n_tokens != 6) {
1562                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1563                 return;
1564         }
1565
1566         pipeline_name = tokens[1];
1567
1568         if (strcmp(tokens[2], "port") != 0) {
1569                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1570                 return;
1571         }
1572
1573         if (strcmp(tokens[3], "in") != 0) {
1574                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1575                 return;
1576         }
1577
1578         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1579                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1580                 return;
1581         }
1582
1583         if (strcmp(tokens[5], "disable") != 0) {
1584                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1585                 return;
1586         }
1587
1588         status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id);
1589         if (status) {
1590                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1591                 return;
1592         }
1593 }
1594
1595 /**
1596  * thread <thread_id> pipeline <pipeline_name> enable
1597  */
1598 static void
1599 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
1600         char **tokens,
1601         uint32_t n_tokens,
1602         char *out,
1603         size_t out_size)
1604 {
1605         char *pipeline_name;
1606         uint32_t thread_id;
1607         int status;
1608
1609         if (n_tokens != 5) {
1610                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1611                 return;
1612         }
1613
1614         if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
1615                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1616                 return;
1617         }
1618
1619         if (strcmp(tokens[2], "pipeline") != 0) {
1620                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1621                 return;
1622         }
1623
1624         pipeline_name = tokens[3];
1625
1626         if (strcmp(tokens[4], "enable") != 0) {
1627                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1628                 return;
1629         }
1630
1631         status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name);
1632         if (status) {
1633                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
1634                 return;
1635         }
1636 }
1637
1638 /**
1639  * thread <thread_id> pipeline <pipeline_name> disable
1640  */
1641 static void
1642 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
1643         char **tokens,
1644         uint32_t n_tokens,
1645         char *out,
1646         size_t out_size)
1647 {
1648         char *pipeline_name;
1649         uint32_t thread_id;
1650         int status;
1651
1652         if (n_tokens != 5) {
1653                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1654                 return;
1655         }
1656
1657         if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
1658                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1659                 return;
1660         }
1661
1662         if (strcmp(tokens[2], "pipeline") != 0) {
1663                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1664                 return;
1665         }
1666
1667         pipeline_name = tokens[3];
1668
1669         if (strcmp(tokens[4], "disable") != 0) {
1670                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1671                 return;
1672         }
1673
1674         status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name);
1675         if (status) {
1676                 snprintf(out, out_size, MSG_CMD_FAIL,
1677                         "thread pipeline disable");
1678                 return;
1679         }
1680 }
1681
1682 void
1683 softnic_cli_process(char *in, char *out, size_t out_size, void *arg)
1684 {
1685         char *tokens[CMD_MAX_TOKENS];
1686         uint32_t n_tokens = RTE_DIM(tokens);
1687         struct pmd_internals *softnic = arg;
1688         int status;
1689
1690         if (is_comment(in))
1691                 return;
1692
1693         status = softnic_parse_tokenize_string(in, tokens, &n_tokens);
1694         if (status) {
1695                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
1696                 return;
1697         }
1698
1699         if (n_tokens == 0)
1700                 return;
1701
1702         if (strcmp(tokens[0], "mempool") == 0) {
1703                 cmd_mempool(softnic, tokens, n_tokens, out, out_size);
1704                 return;
1705         }
1706
1707         if (strcmp(tokens[0], "link") == 0) {
1708                 cmd_link(softnic, tokens, n_tokens, out, out_size);
1709                 return;
1710         }
1711
1712         if (strcmp(tokens[0], "swq") == 0) {
1713                 cmd_swq(softnic, tokens, n_tokens, out, out_size);
1714                 return;
1715         }
1716
1717         if (strcmp(tokens[0], "tap") == 0) {
1718                 cmd_tap(softnic, tokens, n_tokens, out, out_size);
1719                 return;
1720         }
1721
1722         if (strcmp(tokens[0], "port") == 0) {
1723                 cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size);
1724                 return;
1725         }
1726
1727         if (strcmp(tokens[0], "table") == 0) {
1728                 cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size);
1729                 return;
1730         }
1731
1732         if (strcmp(tokens[0], "pipeline") == 0) {
1733                 if (n_tokens >= 3 &&
1734                         (strcmp(tokens[2], "period") == 0)) {
1735                         cmd_pipeline(softnic, tokens, n_tokens, out, out_size);
1736                         return;
1737                 }
1738
1739                 if (n_tokens >= 5 &&
1740                         (strcmp(tokens[2], "port") == 0) &&
1741                         (strcmp(tokens[3], "in") == 0) &&
1742                         (strcmp(tokens[4], "bsz") == 0)) {
1743                         cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size);
1744                         return;
1745                 }
1746
1747                 if (n_tokens >= 5 &&
1748                         (strcmp(tokens[2], "port") == 0) &&
1749                         (strcmp(tokens[3], "out") == 0) &&
1750                         (strcmp(tokens[4], "bsz") == 0)) {
1751                         cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size);
1752                         return;
1753                 }
1754
1755                 if (n_tokens >= 4 &&
1756                         (strcmp(tokens[2], "table") == 0) &&
1757                         (strcmp(tokens[3], "match") == 0)) {
1758                         cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size);
1759                         return;
1760                 }
1761
1762                 if (n_tokens >= 6 &&
1763                         (strcmp(tokens[2], "port") == 0) &&
1764                         (strcmp(tokens[3], "in") == 0) &&
1765                         (strcmp(tokens[5], "table") == 0)) {
1766                         cmd_pipeline_port_in_table(softnic, tokens, n_tokens,
1767                                 out, out_size);
1768                         return;
1769                 }
1770
1771                 if (n_tokens >= 6 &&
1772                         (strcmp(tokens[2], "port") == 0) &&
1773                         (strcmp(tokens[3], "in") == 0) &&
1774                         (strcmp(tokens[5], "enable") == 0)) {
1775                         cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens,
1776                                 out, out_size);
1777                         return;
1778                 }
1779
1780                 if (n_tokens >= 6 &&
1781                         (strcmp(tokens[2], "port") == 0) &&
1782                         (strcmp(tokens[3], "in") == 0) &&
1783                         (strcmp(tokens[5], "disable") == 0)) {
1784                         cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens,
1785                                 out, out_size);
1786                         return;
1787                 }
1788         }
1789
1790         if (strcmp(tokens[0], "thread") == 0) {
1791                 if ((n_tokens >= 5) &&
1792                         (strcmp(tokens[4], "enable") == 0)) {
1793                         cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens,
1794                                 out, out_size);
1795                         return;
1796                 }
1797
1798                 if ((n_tokens >= 5) &&
1799                         (strcmp(tokens[4], "disable") == 0)) {
1800                         cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens,
1801                                 out, out_size);
1802                         return;
1803                 }
1804         }
1805
1806         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
1807 }
1808
1809 int
1810 softnic_cli_script_process(struct pmd_internals *softnic,
1811         const char *file_name,
1812         size_t msg_in_len_max,
1813         size_t msg_out_len_max)
1814 {
1815         char *msg_in = NULL, *msg_out = NULL;
1816         FILE *f = NULL;
1817
1818         /* Check input arguments */
1819         if (file_name == NULL ||
1820                 strlen(file_name) == 0 ||
1821                 msg_in_len_max == 0 ||
1822                 msg_out_len_max == 0)
1823                 return -EINVAL;
1824
1825         msg_in = malloc(msg_in_len_max + 1);
1826         msg_out = malloc(msg_out_len_max + 1);
1827         if (msg_in == NULL ||
1828                 msg_out == NULL) {
1829                 free(msg_out);
1830                 free(msg_in);
1831                 return -ENOMEM;
1832         }
1833
1834         /* Open input file */
1835         f = fopen(file_name, "r");
1836         if (f == NULL) {
1837                 free(msg_out);
1838                 free(msg_in);
1839                 return -EIO;
1840         }
1841
1842         /* Read file */
1843         for ( ; ; ) {
1844                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
1845                         break;
1846
1847                 printf("%s", msg_in);
1848                 msg_out[0] = 0;
1849
1850                 softnic_cli_process(msg_in,
1851                         msg_out,
1852                         msg_out_len_max,
1853                         softnic);
1854
1855                 if (strlen(msg_out))
1856                         printf("%s", msg_out);
1857         }
1858
1859         /* Close file */
1860         fclose(f);
1861         free(msg_out);
1862         free(msg_in);
1863         return 0;
1864 }