59688ffaaa2f3dbd82f08806d47779b72daa5bcb
[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_common.h>
11 #include <rte_cycles.h>
12
13 #include "rte_eth_softnic_internals.h"
14 #include "parser.h"
15
16 #ifndef CMD_MAX_TOKENS
17 #define CMD_MAX_TOKENS     256
18 #endif
19
20 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
21 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
22 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
23 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
24 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
25 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
26 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
27 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
28 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
29 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
30 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
31
32 static int
33 is_comment(char *in)
34 {
35         if ((strlen(in) && index("!#%;", in[0])) ||
36                 (strncmp(in, "//", 2) == 0) ||
37                 (strncmp(in, "--", 2) == 0))
38                 return 1;
39
40         return 0;
41 }
42
43 /**
44  * mempool <mempool_name>
45  *  buffer <buffer_size>
46  *  pool <pool_size>
47  *  cache <cache_size>
48  */
49 static void
50 cmd_mempool(struct pmd_internals *softnic,
51         char **tokens,
52         uint32_t n_tokens,
53         char *out,
54         size_t out_size)
55 {
56         struct softnic_mempool_params p;
57         char *name;
58         struct softnic_mempool *mempool;
59
60         if (n_tokens != 8) {
61                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
62                 return;
63         }
64
65         name = tokens[1];
66
67         if (strcmp(tokens[2], "buffer") != 0) {
68                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
69                 return;
70         }
71
72         if (softnic_parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
73                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
74                 return;
75         }
76
77         if (strcmp(tokens[4], "pool") != 0) {
78                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
79                 return;
80         }
81
82         if (softnic_parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
83                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
84                 return;
85         }
86
87         if (strcmp(tokens[6], "cache") != 0) {
88                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
89                 return;
90         }
91
92         if (softnic_parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
93                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
94                 return;
95         }
96
97         mempool = softnic_mempool_create(softnic, name, &p);
98         if (mempool == NULL) {
99                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
100                 return;
101         }
102 }
103
104 /**
105  * link <link_name>
106  *    dev <device_name> | port <port_id>
107  */
108 static void
109 cmd_link(struct pmd_internals *softnic,
110         char **tokens,
111         uint32_t n_tokens,
112         char *out,
113         size_t out_size)
114 {
115         struct softnic_link_params p;
116         struct softnic_link *link;
117         char *name;
118
119         memset(&p, 0, sizeof(p));
120
121         if (n_tokens != 4) {
122                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
123                 return;
124         }
125         name = tokens[1];
126
127         if (strcmp(tokens[2], "dev") == 0) {
128                 p.dev_name = tokens[3];
129         } else if (strcmp(tokens[2], "port") == 0) {
130                 p.dev_name = NULL;
131
132                 if (softnic_parser_read_uint16(&p.port_id, tokens[3]) != 0) {
133                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
134                         return;
135                 }
136         } else {
137                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
138                 return;
139         }
140
141         link = softnic_link_create(softnic, name, &p);
142         if (link == NULL) {
143                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
144                 return;
145         }
146 }
147
148 /**
149  * swq <swq_name>
150  *  size <size>
151  */
152 static void
153 cmd_swq(struct pmd_internals *softnic,
154         char **tokens,
155         uint32_t n_tokens,
156         char *out,
157         size_t out_size)
158 {
159         struct softnic_swq_params p;
160         char *name;
161         struct softnic_swq *swq;
162
163         if (n_tokens != 4) {
164                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
165                 return;
166         }
167
168         name = tokens[1];
169
170         if (strcmp(tokens[2], "size") != 0) {
171                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
172                 return;
173         }
174
175         if (softnic_parser_read_uint32(&p.size, tokens[3]) != 0) {
176                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
177                 return;
178         }
179
180         swq = softnic_swq_create(softnic, name, &p);
181         if (swq == NULL) {
182                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
183                 return;
184         }
185 }
186
187 /**
188  * tap <tap_name>
189  */
190 static void
191 cmd_tap(struct pmd_internals *softnic,
192         char **tokens,
193         uint32_t n_tokens,
194         char *out,
195         size_t out_size)
196 {
197         char *name;
198         struct softnic_tap *tap;
199
200         if (n_tokens != 2) {
201                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
202                 return;
203         }
204
205         name = tokens[1];
206
207         tap = softnic_tap_create(softnic, name);
208         if (tap == NULL) {
209                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
210                 return;
211         }
212 }
213
214 /**
215  * port in action profile <profile_name>
216  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
217  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
218  */
219 static void
220 cmd_port_in_action_profile(struct pmd_internals *softnic,
221         char **tokens,
222         uint32_t n_tokens,
223         char *out,
224         size_t out_size)
225 {
226         struct softnic_port_in_action_profile_params p;
227         struct softnic_port_in_action_profile *ap;
228         char *name;
229         uint32_t t0;
230
231         memset(&p, 0, sizeof(p));
232
233         if (n_tokens < 5) {
234                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
235                 return;
236         }
237
238         if (strcmp(tokens[1], "in") != 0) {
239                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
240                 return;
241         }
242
243         if (strcmp(tokens[2], "action") != 0) {
244                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
245                 return;
246         }
247
248         if (strcmp(tokens[3], "profile") != 0) {
249                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
250                 return;
251         }
252
253         name = tokens[4];
254
255         t0 = 5;
256
257         if (t0 < n_tokens &&
258                 (strcmp(tokens[t0], "filter") == 0)) {
259                 uint32_t size;
260
261                 if (n_tokens < t0 + 10) {
262                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
263                         return;
264                 }
265
266                 if (strcmp(tokens[t0 + 1], "match") == 0) {
267                         p.fltr.filter_on_match = 1;
268                 } else if (strcmp(tokens[t0 + 1], "mismatch") == 0) {
269                         p.fltr.filter_on_match = 0;
270                 } else {
271                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
272                         return;
273                 }
274
275                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
276                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
277                         return;
278                 }
279
280                 if (softnic_parser_read_uint32(&p.fltr.key_offset,
281                         tokens[t0 + 3]) != 0) {
282                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
283                         return;
284                 }
285
286                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
287                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
288                         return;
289                 }
290
291                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
292                 if ((softnic_parse_hex_string(tokens[t0 + 5],
293                         p.fltr.key_mask, &size) != 0) ||
294                         size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
295                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
296                         return;
297                 }
298
299                 if (strcmp(tokens[t0 + 6], "key") != 0) {
300                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
301                         return;
302                 }
303
304                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
305                 if ((softnic_parse_hex_string(tokens[t0 + 7],
306                         p.fltr.key, &size) != 0) ||
307                         size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
308                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
309                         return;
310                 }
311
312                 if (strcmp(tokens[t0 + 8], "port") != 0) {
313                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
314                         return;
315                 }
316
317                 if (softnic_parser_read_uint32(&p.fltr.port_id,
318                         tokens[t0 + 9]) != 0) {
319                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
320                         return;
321                 }
322
323                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
324                 t0 += 10;
325         } /* filter */
326
327         if (t0 < n_tokens &&
328                 (strcmp(tokens[t0], "balance") == 0)) {
329                 uint32_t i;
330
331                 if (n_tokens < t0 + 22) {
332                         snprintf(out, out_size, MSG_ARG_MISMATCH,
333                                 "port in action profile balance");
334                         return;
335                 }
336
337                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
338                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
339                         return;
340                 }
341
342                 if (softnic_parser_read_uint32(&p.lb.key_offset,
343                         tokens[t0 + 2]) != 0) {
344                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
345                         return;
346                 }
347
348                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
349                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
350                         return;
351                 }
352
353                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
354                 if (softnic_parse_hex_string(tokens[t0 + 4],
355                         p.lb.key_mask, &p.lb.key_size) != 0) {
356                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
357                         return;
358                 }
359
360                 if (strcmp(tokens[t0 + 5], "port") != 0) {
361                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
362                         return;
363                 }
364
365                 for (i = 0; i < 16; i++)
366                         if (softnic_parser_read_uint32(&p.lb.port_id[i],
367                         tokens[t0 + 6 + i]) != 0) {
368                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
369                                 return;
370                         }
371
372                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
373                 t0 += 22;
374         } /* balance */
375
376         if (t0 < n_tokens) {
377                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
378                 return;
379         }
380
381         ap = softnic_port_in_action_profile_create(softnic, name, &p);
382         if (ap == NULL) {
383                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
384                 return;
385         }
386 }
387
388 /**
389  * table action profile <profile_name>
390  *  ipv4 | ipv6
391  *  offset <ip_offset>
392  *  fwd
393  *  [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]
394  *  [meter srtcm | trtcm
395  *      tc <n_tc>
396  *      stats none | pkts | bytes | both]
397  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
398  *  [encap ether | vlan | qinq | mpls | pppoe]
399  *  [nat src | dst
400  *      proto udp | tcp]
401  *  [ttl drop | fwd
402  *      stats none | pkts]
403  *  [stats pkts | bytes | both]
404  *  [time]
405  */
406 static void
407 cmd_table_action_profile(struct pmd_internals *softnic,
408         char **tokens,
409         uint32_t n_tokens,
410         char *out,
411         size_t out_size)
412 {
413         struct softnic_table_action_profile_params p;
414         struct softnic_table_action_profile *ap;
415         char *name;
416         uint32_t t0;
417
418         memset(&p, 0, sizeof(p));
419
420         if (n_tokens < 8) {
421                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
422                 return;
423         }
424
425         if (strcmp(tokens[1], "action") != 0) {
426                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
427                 return;
428         }
429
430         if (strcmp(tokens[2], "profile") != 0) {
431                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
432                 return;
433         }
434
435         name = tokens[3];
436
437         if (strcmp(tokens[4], "ipv4") == 0) {
438                 p.common.ip_version = 1;
439         } else if (strcmp(tokens[4], "ipv6") == 0) {
440                 p.common.ip_version = 0;
441         } else {
442                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
443                 return;
444         }
445
446         if (strcmp(tokens[5], "offset") != 0) {
447                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
448                 return;
449         }
450
451         if (softnic_parser_read_uint32(&p.common.ip_offset,
452                 tokens[6]) != 0) {
453                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
454                 return;
455         }
456
457         if (strcmp(tokens[7], "fwd") != 0) {
458                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
459                 return;
460         }
461
462         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
463
464         t0 = 8;
465         if (t0 < n_tokens &&
466                 (strcmp(tokens[t0], "balance") == 0)) {
467                 if (n_tokens < t0 + 7) {
468                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
469                         return;
470                 }
471
472                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
473                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
474                         return;
475                 }
476
477                 if (softnic_parser_read_uint32(&p.lb.key_offset,
478                         tokens[t0 + 2]) != 0) {
479                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
480                         return;
481                 }
482
483                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
484                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
485                         return;
486                 }
487
488                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
489                 if (softnic_parse_hex_string(tokens[t0 + 4],
490                         p.lb.key_mask, &p.lb.key_size) != 0) {
491                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
492                         return;
493                 }
494
495                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
496                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
497                         return;
498                 }
499
500                 if (softnic_parser_read_uint32(&p.lb.out_offset,
501                         tokens[t0 + 6]) != 0) {
502                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
503                         return;
504                 }
505
506                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
507                 t0 += 7;
508         } /* balance */
509
510         if (t0 < n_tokens &&
511                 (strcmp(tokens[t0], "meter") == 0)) {
512                 if (n_tokens < t0 + 6) {
513                         snprintf(out, out_size, MSG_ARG_MISMATCH,
514                                 "table action profile meter");
515                         return;
516                 }
517
518                 if (strcmp(tokens[t0 + 1], "srtcm") == 0) {
519                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
520                 } else if (strcmp(tokens[t0 + 1], "trtcm") == 0) {
521                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
522                 } else {
523                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
524                                 "srtcm or trtcm");
525                         return;
526                 }
527
528                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
529                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
530                         return;
531                 }
532
533                 if (softnic_parser_read_uint32(&p.mtr.n_tc,
534                         tokens[t0 + 3]) != 0) {
535                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
536                         return;
537                 }
538
539                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
540                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
541                         return;
542                 }
543
544                 if (strcmp(tokens[t0 + 5], "none") == 0) {
545                         p.mtr.n_packets_enabled = 0;
546                         p.mtr.n_bytes_enabled = 0;
547                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
548                         p.mtr.n_packets_enabled = 1;
549                         p.mtr.n_bytes_enabled = 0;
550                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
551                         p.mtr.n_packets_enabled = 0;
552                         p.mtr.n_bytes_enabled = 1;
553                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
554                         p.mtr.n_packets_enabled = 1;
555                         p.mtr.n_bytes_enabled = 1;
556                 } else {
557                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
558                                 "none or pkts or bytes or both");
559                         return;
560                 }
561
562                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
563                 t0 += 6;
564         } /* meter */
565
566         if (t0 < n_tokens &&
567                 (strcmp(tokens[t0], "tm") == 0)) {
568                 if (n_tokens < t0 + 5) {
569                         snprintf(out, out_size, MSG_ARG_MISMATCH,
570                                 "table action profile tm");
571                         return;
572                 }
573
574                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
575                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
576                         return;
577                 }
578
579                 if (softnic_parser_read_uint32(&p.tm.n_subports_per_port,
580                         tokens[t0 + 2]) != 0) {
581                         snprintf(out, out_size, MSG_ARG_INVALID,
582                                 "n_subports_per_port");
583                         return;
584                 }
585
586                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
587                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
588                         return;
589                 }
590
591                 if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport,
592                         tokens[t0 + 4]) != 0) {
593                         snprintf(out, out_size, MSG_ARG_INVALID,
594                                 "n_pipes_per_subport");
595                         return;
596                 }
597
598                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
599                 t0 += 5;
600         } /* tm */
601
602         if (t0 < n_tokens &&
603                 (strcmp(tokens[t0], "encap") == 0)) {
604                 if (n_tokens < t0 + 2) {
605                         snprintf(out, out_size, MSG_ARG_MISMATCH,
606                                 "action profile encap");
607                         return;
608                 }
609
610                 if (strcmp(tokens[t0 + 1], "ether") == 0) {
611                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
612                 } else if (strcmp(tokens[t0 + 1], "vlan") == 0) {
613                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
614                 } else if (strcmp(tokens[t0 + 1], "qinq") == 0) {
615                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
616                 } else if (strcmp(tokens[t0 + 1], "mpls") == 0) {
617                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
618                 } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) {
619                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
620                 } else {
621                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
622                         return;
623                 }
624
625                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
626                 t0 += 2;
627         } /* encap */
628
629         if (t0 < n_tokens &&
630                 (strcmp(tokens[t0], "nat") == 0)) {
631                 if (n_tokens < t0 + 4) {
632                         snprintf(out, out_size, MSG_ARG_MISMATCH,
633                                 "table action profile nat");
634                         return;
635                 }
636
637                 if (strcmp(tokens[t0 + 1], "src") == 0) {
638                         p.nat.source_nat = 1;
639                 } else if (strcmp(tokens[t0 + 1], "dst") == 0) {
640                         p.nat.source_nat = 0;
641                 } else {
642                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
643                                 "src or dst");
644                         return;
645                 }
646
647                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
648                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
649                         return;
650                 }
651
652                 if (strcmp(tokens[t0 + 3], "tcp") == 0) {
653                         p.nat.proto = 0x06;
654                 } else if (strcmp(tokens[t0 + 3], "udp") == 0) {
655                         p.nat.proto = 0x11;
656                 } else {
657                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
658                                 "tcp or udp");
659                         return;
660                 }
661
662                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
663                 t0 += 4;
664         } /* nat */
665
666         if (t0 < n_tokens &&
667                 (strcmp(tokens[t0], "ttl") == 0)) {
668                 if (n_tokens < t0 + 4) {
669                         snprintf(out, out_size, MSG_ARG_MISMATCH,
670                                 "table action profile ttl");
671                         return;
672                 }
673
674                 if (strcmp(tokens[t0 + 1], "drop") == 0) {
675                         p.ttl.drop = 1;
676                 } else if (strcmp(tokens[t0 + 1], "fwd") == 0) {
677                         p.ttl.drop = 0;
678                 } else {
679                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
680                                 "drop or fwd");
681                         return;
682                 }
683
684                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
685                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
686                         return;
687                 }
688
689                 if (strcmp(tokens[t0 + 3], "none") == 0) {
690                         p.ttl.n_packets_enabled = 0;
691                 } else if (strcmp(tokens[t0 + 3], "pkts") == 0) {
692                         p.ttl.n_packets_enabled = 1;
693                 } else {
694                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
695                                 "none or pkts");
696                         return;
697                 }
698
699                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
700                 t0 += 4;
701         } /* ttl */
702
703         if (t0 < n_tokens &&
704                 (strcmp(tokens[t0], "stats") == 0)) {
705                 if (n_tokens < t0 + 2) {
706                         snprintf(out, out_size, MSG_ARG_MISMATCH,
707                                 "table action profile stats");
708                         return;
709                 }
710
711                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
712                         p.stats.n_packets_enabled = 1;
713                         p.stats.n_bytes_enabled = 0;
714                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
715                         p.stats.n_packets_enabled = 0;
716                         p.stats.n_bytes_enabled = 1;
717                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
718                         p.stats.n_packets_enabled = 1;
719                         p.stats.n_bytes_enabled = 1;
720                 } else {
721                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
722                                 "pkts or bytes or both");
723                         return;
724                 }
725
726                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
727                 t0 += 2;
728         } /* stats */
729
730         if (t0 < n_tokens &&
731                 (strcmp(tokens[t0], "time") == 0)) {
732                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
733                 t0 += 1;
734         } /* time */
735
736         if (t0 < n_tokens) {
737                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
738                 return;
739         }
740
741         ap = softnic_table_action_profile_create(softnic, name, &p);
742         if (ap == NULL) {
743                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
744                 return;
745         }
746 }
747
748 /**
749  * pipeline <pipeline_name>
750  *  period <timer_period_ms>
751  *  offset_port_id <offset_port_id>
752  */
753 static void
754 cmd_pipeline(struct pmd_internals *softnic,
755         char **tokens,
756         uint32_t n_tokens,
757         char *out,
758         size_t out_size)
759 {
760         struct pipeline_params p;
761         char *name;
762         struct pipeline *pipeline;
763
764         if (n_tokens != 6) {
765                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
766                 return;
767         }
768
769         name = tokens[1];
770
771         if (strcmp(tokens[2], "period") != 0) {
772                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
773                 return;
774         }
775
776         if (softnic_parser_read_uint32(&p.timer_period_ms,
777                 tokens[3]) != 0) {
778                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
779                 return;
780         }
781
782         if (strcmp(tokens[4], "offset_port_id") != 0) {
783                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
784                 return;
785         }
786
787         if (softnic_parser_read_uint32(&p.offset_port_id,
788                 tokens[5]) != 0) {
789                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
790                 return;
791         }
792
793         pipeline = softnic_pipeline_create(softnic, name, &p);
794         if (pipeline == NULL) {
795                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
796                 return;
797         }
798 }
799
800 /**
801  * pipeline <pipeline_name> port in
802  *  bsz <burst_size>
803  *  link <link_name> rxq <queue_id>
804  *  | swq <swq_name>
805  *  | tmgr <tmgr_name>
806  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
807  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
808  *  [action <port_in_action_profile_name>]
809  *  [disabled]
810  */
811 static void
812 cmd_pipeline_port_in(struct pmd_internals *softnic,
813         char **tokens,
814         uint32_t n_tokens,
815         char *out,
816         size_t out_size)
817 {
818         struct softnic_port_in_params p;
819         char *pipeline_name;
820         uint32_t t0;
821         int enabled, status;
822
823         if (n_tokens < 7) {
824                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
825                 return;
826         }
827
828         pipeline_name = tokens[1];
829
830         if (strcmp(tokens[2], "port") != 0) {
831                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
832                 return;
833         }
834
835         if (strcmp(tokens[3], "in") != 0) {
836                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
837                 return;
838         }
839
840         if (strcmp(tokens[4], "bsz") != 0) {
841                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
842                 return;
843         }
844
845         if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
846                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
847                 return;
848         }
849
850         t0 = 6;
851
852         if (strcmp(tokens[t0], "link") == 0) {
853                 if (n_tokens < t0 + 4) {
854                         snprintf(out, out_size, MSG_ARG_MISMATCH,
855                                 "pipeline port in link");
856                         return;
857                 }
858
859                 p.type = PORT_IN_RXQ;
860
861                 p.dev_name = tokens[t0 + 1];
862
863                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
864                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
865                         return;
866                 }
867
868                 if (softnic_parser_read_uint16(&p.rxq.queue_id,
869                         tokens[t0 + 3]) != 0) {
870                         snprintf(out, out_size, MSG_ARG_INVALID,
871                                 "queue_id");
872                         return;
873                 }
874                 t0 += 4;
875         } else if (strcmp(tokens[t0], "swq") == 0) {
876                 if (n_tokens < t0 + 2) {
877                         snprintf(out, out_size, MSG_ARG_MISMATCH,
878                                 "pipeline port in swq");
879                         return;
880                 }
881
882                 p.type = PORT_IN_SWQ;
883
884                 p.dev_name = tokens[t0 + 1];
885
886                 t0 += 2;
887         } else if (strcmp(tokens[t0], "tmgr") == 0) {
888                 if (n_tokens < t0 + 2) {
889                         snprintf(out, out_size, MSG_ARG_MISMATCH,
890                                 "pipeline port in tmgr");
891                         return;
892                 }
893
894                 p.type = PORT_IN_TMGR;
895
896                 p.dev_name = tokens[t0 + 1];
897
898                 t0 += 2;
899         } else if (strcmp(tokens[t0], "tap") == 0) {
900                 if (n_tokens < t0 + 6) {
901                         snprintf(out, out_size, MSG_ARG_MISMATCH,
902                                 "pipeline port in tap");
903                         return;
904                 }
905
906                 p.type = PORT_IN_TAP;
907
908                 p.dev_name = tokens[t0 + 1];
909
910                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
911                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
912                                 "mempool");
913                         return;
914                 }
915
916                 p.tap.mempool_name = tokens[t0 + 3];
917
918                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
919                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
920                                 "mtu");
921                         return;
922                 }
923
924                 if (softnic_parser_read_uint32(&p.tap.mtu,
925                         tokens[t0 + 5]) != 0) {
926                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
927                         return;
928                 }
929
930                 t0 += 6;
931         } else if (strcmp(tokens[t0], "source") == 0) {
932                 if (n_tokens < t0 + 6) {
933                         snprintf(out, out_size, MSG_ARG_MISMATCH,
934                                 "pipeline port in source");
935                         return;
936                 }
937
938                 p.type = PORT_IN_SOURCE;
939
940                 p.dev_name = NULL;
941
942                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
943                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
944                                 "mempool");
945                         return;
946                 }
947
948                 p.source.mempool_name = tokens[t0 + 2];
949
950                 if (strcmp(tokens[t0 + 3], "file") != 0) {
951                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
952                                 "file");
953                         return;
954                 }
955
956                 p.source.file_name = tokens[t0 + 4];
957
958                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
959                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
960                                 "bpp");
961                         return;
962                 }
963
964                 if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt,
965                         tokens[t0 + 6]) != 0) {
966                         snprintf(out, out_size, MSG_ARG_INVALID,
967                                 "n_bytes_per_pkt");
968                         return;
969                 }
970
971                 t0 += 7;
972         } else {
973                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
974                 return;
975         }
976
977         p.action_profile_name = NULL;
978         if (n_tokens > t0 &&
979                 (strcmp(tokens[t0], "action") == 0)) {
980                 if (n_tokens < t0 + 2) {
981                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
982                         return;
983                 }
984
985                 p.action_profile_name = tokens[t0 + 1];
986
987                 t0 += 2;
988         }
989
990         enabled = 1;
991         if (n_tokens > t0 &&
992                 (strcmp(tokens[t0], "disabled") == 0)) {
993                 enabled = 0;
994
995                 t0 += 1;
996         }
997
998         if (n_tokens != t0) {
999                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1000                 return;
1001         }
1002
1003         status = softnic_pipeline_port_in_create(softnic,
1004                 pipeline_name,
1005                 &p,
1006                 enabled);
1007         if (status) {
1008                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1009                 return;
1010         }
1011 }
1012
1013 /**
1014  * pipeline <pipeline_name> port out
1015  *  bsz <burst_size>
1016  *  link <link_name> txq <txq_id>
1017  *  | swq <swq_name>
1018  *  | tmgr <tmgr_name>
1019  *  | tap <tap_name>
1020  *  | sink [file <file_name> pkts <max_n_pkts>]
1021  */
1022 static void
1023 cmd_pipeline_port_out(struct pmd_internals *softnic,
1024         char **tokens,
1025         uint32_t n_tokens,
1026         char *out,
1027         size_t out_size)
1028 {
1029         struct softnic_port_out_params p;
1030         char *pipeline_name;
1031         int status;
1032
1033         memset(&p, 0, sizeof(p));
1034
1035         if (n_tokens < 7) {
1036                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1037                 return;
1038         }
1039
1040         pipeline_name = tokens[1];
1041
1042         if (strcmp(tokens[2], "port") != 0) {
1043                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1044                 return;
1045         }
1046
1047         if (strcmp(tokens[3], "out") != 0) {
1048                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1049                 return;
1050         }
1051
1052         if (strcmp(tokens[4], "bsz") != 0) {
1053                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1054                 return;
1055         }
1056
1057         if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1058                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1059                 return;
1060         }
1061
1062         if (strcmp(tokens[6], "link") == 0) {
1063                 if (n_tokens != 10) {
1064                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1065                                 "pipeline port out link");
1066                         return;
1067                 }
1068
1069                 p.type = PORT_OUT_TXQ;
1070
1071                 p.dev_name = tokens[7];
1072
1073                 if (strcmp(tokens[8], "txq") != 0) {
1074                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1075                         return;
1076                 }
1077
1078                 if (softnic_parser_read_uint16(&p.txq.queue_id,
1079                         tokens[9]) != 0) {
1080                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1081                         return;
1082                 }
1083         } else if (strcmp(tokens[6], "swq") == 0) {
1084                 if (n_tokens != 8) {
1085                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1086                                 "pipeline port out swq");
1087                         return;
1088                 }
1089
1090                 p.type = PORT_OUT_SWQ;
1091
1092                 p.dev_name = tokens[7];
1093         } else if (strcmp(tokens[6], "tmgr") == 0) {
1094                 if (n_tokens != 8) {
1095                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1096                                 "pipeline port out tmgr");
1097                         return;
1098                 }
1099
1100                 p.type = PORT_OUT_TMGR;
1101
1102                 p.dev_name = tokens[7];
1103         } else if (strcmp(tokens[6], "tap") == 0) {
1104                 if (n_tokens != 8) {
1105                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1106                                 "pipeline port out tap");
1107                         return;
1108                 }
1109
1110                 p.type = PORT_OUT_TAP;
1111
1112                 p.dev_name = tokens[7];
1113         } else if (strcmp(tokens[6], "sink") == 0) {
1114                 if ((n_tokens != 7) && (n_tokens != 11)) {
1115                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1116                                 "pipeline port out sink");
1117                         return;
1118                 }
1119
1120                 p.type = PORT_OUT_SINK;
1121
1122                 p.dev_name = NULL;
1123
1124                 if (n_tokens == 7) {
1125                         p.sink.file_name = NULL;
1126                         p.sink.max_n_pkts = 0;
1127                 } else {
1128                         if (strcmp(tokens[7], "file") != 0) {
1129                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1130                                         "file");
1131                                 return;
1132                         }
1133
1134                         p.sink.file_name = tokens[8];
1135
1136                         if (strcmp(tokens[9], "pkts") != 0) {
1137                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1138                                 return;
1139                         }
1140
1141                         if (softnic_parser_read_uint32(&p.sink.max_n_pkts,
1142                                 tokens[10]) != 0) {
1143                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1144                                 return;
1145                         }
1146                 }
1147         } else {
1148                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1149                 return;
1150         }
1151
1152         status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p);
1153         if (status) {
1154                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1155                 return;
1156         }
1157 }
1158
1159 /**
1160  * pipeline <pipeline_name> table
1161  *      match
1162  *      acl
1163  *          ipv4 | ipv6
1164  *          offset <ip_header_offset>
1165  *          size <n_rules>
1166  *      | array
1167  *          offset <key_offset>
1168  *          size <n_keys>
1169  *      | hash
1170  *          ext | lru
1171  *          key <key_size>
1172  *          mask <key_mask>
1173  *          offset <key_offset>
1174  *          buckets <n_buckets>
1175  *          size <n_keys>
1176  *      | lpm
1177  *          ipv4 | ipv6
1178  *          offset <ip_header_offset>
1179  *          size <n_rules>
1180  *      | stub
1181  *  [action <table_action_profile_name>]
1182  */
1183 static void
1184 cmd_pipeline_table(struct pmd_internals *softnic,
1185         char **tokens,
1186         uint32_t n_tokens,
1187         char *out,
1188         size_t out_size)
1189 {
1190         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1191         struct softnic_table_params p;
1192         char *pipeline_name;
1193         uint32_t t0;
1194         int status;
1195
1196         if (n_tokens < 5) {
1197                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1198                 return;
1199         }
1200
1201         pipeline_name = tokens[1];
1202
1203         if (strcmp(tokens[2], "table") != 0) {
1204                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1205                 return;
1206         }
1207
1208         if (strcmp(tokens[3], "match") != 0) {
1209                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1210                 return;
1211         }
1212
1213         t0 = 4;
1214         if (strcmp(tokens[t0], "acl") == 0) {
1215                 if (n_tokens < t0 + 6) {
1216                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1217                                 "pipeline table acl");
1218                         return;
1219                 }
1220
1221                 p.match_type = TABLE_ACL;
1222
1223                 if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
1224                         p.match.acl.ip_version = 1;
1225                 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
1226                         p.match.acl.ip_version = 0;
1227                 } else {
1228                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1229                                 "ipv4 or ipv6");
1230                         return;
1231                 }
1232
1233                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1234                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1235                         return;
1236                 }
1237
1238                 if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset,
1239                         tokens[t0 + 3]) != 0) {
1240                         snprintf(out, out_size, MSG_ARG_INVALID,
1241                                 "ip_header_offset");
1242                         return;
1243                 }
1244
1245                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1246                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1247                         return;
1248                 }
1249
1250                 if (softnic_parser_read_uint32(&p.match.acl.n_rules,
1251                         tokens[t0 + 5]) != 0) {
1252                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1253                         return;
1254                 }
1255
1256                 t0 += 6;
1257         } else if (strcmp(tokens[t0], "array") == 0) {
1258                 if (n_tokens < t0 + 5) {
1259                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1260                                 "pipeline table array");
1261                         return;
1262                 }
1263
1264                 p.match_type = TABLE_ARRAY;
1265
1266                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1267                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1268                         return;
1269                 }
1270
1271                 if (softnic_parser_read_uint32(&p.match.array.key_offset,
1272                         tokens[t0 + 2]) != 0) {
1273                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1274                         return;
1275                 }
1276
1277                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1278                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1279                         return;
1280                 }
1281
1282                 if (softnic_parser_read_uint32(&p.match.array.n_keys,
1283                         tokens[t0 + 4]) != 0) {
1284                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1285                         return;
1286                 }
1287
1288                 t0 += 5;
1289         } else if (strcmp(tokens[t0], "hash") == 0) {
1290                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1291
1292                 if (n_tokens < t0 + 12) {
1293                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1294                                 "pipeline table hash");
1295                         return;
1296                 }
1297
1298                 p.match_type = TABLE_HASH;
1299
1300                 if (strcmp(tokens[t0 + 1], "ext") == 0) {
1301                         p.match.hash.extendable_bucket = 1;
1302                 } else if (strcmp(tokens[t0 + 1], "lru") == 0) {
1303                         p.match.hash.extendable_bucket = 0;
1304                 } else {
1305                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1306                                 "ext or lru");
1307                         return;
1308                 }
1309
1310                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1311                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1312                         return;
1313                 }
1314
1315                 if ((softnic_parser_read_uint32(&p.match.hash.key_size,
1316                         tokens[t0 + 3]) != 0) ||
1317                         p.match.hash.key_size == 0 ||
1318                         p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) {
1319                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1320                         return;
1321                 }
1322
1323                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1324                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1325                         return;
1326                 }
1327
1328                 if ((softnic_parse_hex_string(tokens[t0 + 5],
1329                         key_mask, &key_mask_size) != 0) ||
1330                         key_mask_size != p.match.hash.key_size) {
1331                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1332                         return;
1333                 }
1334                 p.match.hash.key_mask = key_mask;
1335
1336                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1337                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1338                         return;
1339                 }
1340
1341                 if (softnic_parser_read_uint32(&p.match.hash.key_offset,
1342                         tokens[t0 + 7]) != 0) {
1343                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1344                         return;
1345                 }
1346
1347                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1348                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1349                         return;
1350                 }
1351
1352                 if (softnic_parser_read_uint32(&p.match.hash.n_buckets,
1353                         tokens[t0 + 9]) != 0) {
1354                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1355                         return;
1356                 }
1357
1358                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1359                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1360                         return;
1361                 }
1362
1363                 if (softnic_parser_read_uint32(&p.match.hash.n_keys,
1364                         tokens[t0 + 11]) != 0) {
1365                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1366                         return;
1367                 }
1368
1369                 t0 += 12;
1370         } else if (strcmp(tokens[t0], "lpm") == 0) {
1371                 if (n_tokens < t0 + 6) {
1372                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1373                                 "pipeline table lpm");
1374                         return;
1375                 }
1376
1377                 p.match_type = TABLE_LPM;
1378
1379                 if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
1380                         p.match.lpm.key_size = 4;
1381                 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
1382                         p.match.lpm.key_size = 16;
1383                 } else {
1384                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1385                                 "ipv4 or ipv6");
1386                         return;
1387                 }
1388
1389                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1390                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1391                         return;
1392                 }
1393
1394                 if (softnic_parser_read_uint32(&p.match.lpm.key_offset,
1395                         tokens[t0 + 3]) != 0) {
1396                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1397                         return;
1398                 }
1399
1400                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1401                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1402                         return;
1403                 }
1404
1405                 if (softnic_parser_read_uint32(&p.match.lpm.n_rules,
1406                         tokens[t0 + 5]) != 0) {
1407                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1408                         return;
1409                 }
1410
1411                 t0 += 6;
1412         } else if (strcmp(tokens[t0], "stub") == 0) {
1413                 p.match_type = TABLE_STUB;
1414
1415                 t0 += 1;
1416         } else {
1417                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1418                 return;
1419         }
1420
1421         p.action_profile_name = NULL;
1422         if (n_tokens > t0 &&
1423                 (strcmp(tokens[t0], "action") == 0)) {
1424                 if (n_tokens < t0 + 2) {
1425                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1426                         return;
1427                 }
1428
1429                 p.action_profile_name = tokens[t0 + 1];
1430
1431                 t0 += 2;
1432         }
1433
1434         if (n_tokens > t0) {
1435                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1436                 return;
1437         }
1438
1439         status = softnic_pipeline_table_create(softnic, pipeline_name, &p);
1440         if (status) {
1441                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1442                 return;
1443         }
1444 }
1445
1446 /**
1447  * pipeline <pipeline_name> port in <port_id> table <table_id>
1448  */
1449 static void
1450 cmd_pipeline_port_in_table(struct pmd_internals *softnic,
1451         char **tokens,
1452         uint32_t n_tokens,
1453         char *out,
1454         size_t out_size)
1455 {
1456         char *pipeline_name;
1457         uint32_t port_id, table_id;
1458         int status;
1459
1460         if (n_tokens != 7) {
1461                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1462                 return;
1463         }
1464
1465         pipeline_name = tokens[1];
1466
1467         if (strcmp(tokens[2], "port") != 0) {
1468                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1469                 return;
1470         }
1471
1472         if (strcmp(tokens[3], "in") != 0) {
1473                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1474                 return;
1475         }
1476
1477         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1478                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1479                 return;
1480         }
1481
1482         if (strcmp(tokens[5], "table") != 0) {
1483                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1484                 return;
1485         }
1486
1487         if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) {
1488                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1489                 return;
1490         }
1491
1492         status = softnic_pipeline_port_in_connect_to_table(softnic,
1493                 pipeline_name,
1494                 port_id,
1495                 table_id);
1496         if (status) {
1497                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1498                 return;
1499         }
1500 }
1501
1502 /**
1503  * pipeline <pipeline_name> port in <port_id> enable
1504  */
1505 static void
1506 cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
1507         char **tokens,
1508         uint32_t n_tokens,
1509         char *out,
1510         size_t out_size)
1511 {
1512         char *pipeline_name;
1513         uint32_t port_id;
1514         int status;
1515
1516         if (n_tokens != 6) {
1517                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1518                 return;
1519         }
1520
1521         pipeline_name = tokens[1];
1522
1523         if (strcmp(tokens[2], "port") != 0) {
1524                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1525                 return;
1526         }
1527
1528         if (strcmp(tokens[3], "in") != 0) {
1529                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1530                 return;
1531         }
1532
1533         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1534                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1535                 return;
1536         }
1537
1538         if (strcmp(tokens[5], "enable") != 0) {
1539                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1540                 return;
1541         }
1542
1543         status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id);
1544         if (status) {
1545                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1546                 return;
1547         }
1548 }
1549
1550 /**
1551  * pipeline <pipeline_name> port in <port_id> disable
1552  */
1553 static void
1554 cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
1555         char **tokens,
1556         uint32_t n_tokens,
1557         char *out,
1558         size_t out_size)
1559 {
1560         char *pipeline_name;
1561         uint32_t port_id;
1562         int status;
1563
1564         if (n_tokens != 6) {
1565                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1566                 return;
1567         }
1568
1569         pipeline_name = tokens[1];
1570
1571         if (strcmp(tokens[2], "port") != 0) {
1572                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1573                 return;
1574         }
1575
1576         if (strcmp(tokens[3], "in") != 0) {
1577                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1578                 return;
1579         }
1580
1581         if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1582                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1583                 return;
1584         }
1585
1586         if (strcmp(tokens[5], "disable") != 0) {
1587                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1588                 return;
1589         }
1590
1591         status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id);
1592         if (status) {
1593                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1594                 return;
1595         }
1596 }
1597
1598 /**
1599  * <match> ::=
1600  *
1601  * match
1602  *    acl
1603  *       priority <priority>
1604  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
1605  *       <sp0> <sp1> <dp0> <dp1> <proto>
1606  *    | array <pos>
1607  *    | hash
1608  *       raw <key>
1609  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
1610  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
1611  *       | ipv4_addr <addr>
1612  *       | ipv6_addr <addr>
1613  *       | qinq <svlan> <cvlan>
1614  *    | lpm
1615  *       ipv4 | ipv6 <addr> <depth>
1616  */
1617 struct pkt_key_qinq {
1618         uint16_t ethertype_svlan;
1619         uint16_t svlan;
1620         uint16_t ethertype_cvlan;
1621         uint16_t cvlan;
1622 } __attribute__((__packed__));
1623
1624 struct pkt_key_ipv4_5tuple {
1625         uint8_t time_to_live;
1626         uint8_t proto;
1627         uint16_t hdr_checksum;
1628         uint32_t sa;
1629         uint32_t da;
1630         uint16_t sp;
1631         uint16_t dp;
1632 } __attribute__((__packed__));
1633
1634 struct pkt_key_ipv6_5tuple {
1635         uint16_t payload_length;
1636         uint8_t proto;
1637         uint8_t hop_limit;
1638         uint8_t sa[16];
1639         uint8_t da[16];
1640         uint16_t sp;
1641         uint16_t dp;
1642 } __attribute__((__packed__));
1643
1644 struct pkt_key_ipv4_addr {
1645         uint32_t addr;
1646 } __attribute__((__packed__));
1647
1648 struct pkt_key_ipv6_addr {
1649         uint8_t addr[16];
1650 } __attribute__((__packed__));
1651
1652 static uint32_t
1653 parse_match(char **tokens,
1654         uint32_t n_tokens,
1655         char *out,
1656         size_t out_size,
1657         struct softnic_table_rule_match *m)
1658 {
1659         memset(m, 0, sizeof(*m));
1660
1661         if (n_tokens < 2)
1662                 return 0;
1663
1664         if (strcmp(tokens[0], "match") != 0) {
1665                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1666                 return 0;
1667         }
1668
1669         if (strcmp(tokens[1], "acl") == 0) {
1670                 if (n_tokens < 14) {
1671                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1672                         return 0;
1673                 }
1674
1675                 m->match_type = TABLE_ACL;
1676
1677                 if (strcmp(tokens[2], "priority") != 0) {
1678                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
1679                         return 0;
1680                 }
1681
1682                 if (softnic_parser_read_uint32(&m->match.acl.priority,
1683                         tokens[3]) != 0) {
1684                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
1685                         return 0;
1686                 }
1687
1688                 if (strcmp(tokens[4], "ipv4") == 0) {
1689                         struct in_addr saddr, daddr;
1690
1691                         m->match.acl.ip_version = 1;
1692
1693                         if (softnic_parse_ipv4_addr(tokens[5], &saddr) != 0) {
1694                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
1695                                 return 0;
1696                         }
1697                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
1698
1699                         if (softnic_parse_ipv4_addr(tokens[7], &daddr) != 0) {
1700                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
1701                                 return 0;
1702                         }
1703                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
1704                 } else if (strcmp(tokens[4], "ipv6") == 0) {
1705                         struct in6_addr saddr, daddr;
1706
1707                         m->match.acl.ip_version = 0;
1708
1709                         if (softnic_parse_ipv6_addr(tokens[5], &saddr) != 0) {
1710                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
1711                                 return 0;
1712                         }
1713                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
1714
1715                         if (softnic_parse_ipv6_addr(tokens[7], &daddr) != 0) {
1716                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
1717                                 return 0;
1718                         }
1719                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
1720                 } else {
1721                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1722                                 "ipv4 or ipv6");
1723                         return 0;
1724                 }
1725
1726                 if (softnic_parser_read_uint32(&m->match.acl.sa_depth,
1727                         tokens[6]) != 0) {
1728                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
1729                         return 0;
1730                 }
1731
1732                 if (softnic_parser_read_uint32(&m->match.acl.da_depth,
1733                         tokens[8]) != 0) {
1734                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
1735                         return 0;
1736                 }
1737
1738                 if (softnic_parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
1739                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
1740                         return 0;
1741                 }
1742
1743                 if (softnic_parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
1744                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
1745                         return 0;
1746                 }
1747
1748                 if (softnic_parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
1749                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
1750                         return 0;
1751                 }
1752
1753                 if (softnic_parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
1754                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
1755                         return 0;
1756                 }
1757
1758                 if (softnic_parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
1759                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
1760                         return 0;
1761                 }
1762
1763                 m->match.acl.proto_mask = 0xff;
1764
1765                 return 14;
1766         } /* acl */
1767
1768         if (strcmp(tokens[1], "array") == 0) {
1769                 if (n_tokens < 3) {
1770                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1771                         return 0;
1772                 }
1773
1774                 m->match_type = TABLE_ARRAY;
1775
1776                 if (softnic_parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
1777                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
1778                         return 0;
1779                 }
1780
1781                 return 3;
1782         } /* array */
1783
1784         if (strcmp(tokens[1], "hash") == 0) {
1785                 if (n_tokens < 3) {
1786                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1787                         return 0;
1788                 }
1789
1790                 m->match_type = TABLE_HASH;
1791
1792                 if (strcmp(tokens[2], "raw") == 0) {
1793                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
1794
1795                         if (n_tokens < 4) {
1796                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1797                                         tokens[0]);
1798                                 return 0;
1799                         }
1800
1801                         if (softnic_parse_hex_string(tokens[3],
1802                                 m->match.hash.key, &key_size) != 0) {
1803                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
1804                                 return 0;
1805                         }
1806
1807                         return 4;
1808                 } /* hash raw */
1809
1810                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
1811                         struct pkt_key_ipv4_5tuple *ipv4 =
1812                                 (struct pkt_key_ipv4_5tuple *)m->match.hash.key;
1813                         struct in_addr saddr, daddr;
1814                         uint16_t sp, dp;
1815                         uint8_t proto;
1816
1817                         if (n_tokens < 8) {
1818                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1819                                         tokens[0]);
1820                                 return 0;
1821                         }
1822
1823                         if (softnic_parse_ipv4_addr(tokens[3], &saddr) != 0) {
1824                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
1825                                 return 0;
1826                         }
1827
1828                         if (softnic_parse_ipv4_addr(tokens[4], &daddr) != 0) {
1829                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
1830                                 return 0;
1831                         }
1832
1833                         if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) {
1834                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
1835                                 return 0;
1836                         }
1837
1838                         if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) {
1839                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
1840                                 return 0;
1841                         }
1842
1843                         if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) {
1844                                 snprintf(out, out_size, MSG_ARG_INVALID,
1845                                         "proto");
1846                                 return 0;
1847                         }
1848
1849                         ipv4->sa = saddr.s_addr;
1850                         ipv4->da = daddr.s_addr;
1851                         ipv4->sp = rte_cpu_to_be_16(sp);
1852                         ipv4->dp = rte_cpu_to_be_16(dp);
1853                         ipv4->proto = proto;
1854
1855                         return 8;
1856                 } /* hash ipv4_5tuple */
1857
1858                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
1859                         struct pkt_key_ipv6_5tuple *ipv6 =
1860                                 (struct pkt_key_ipv6_5tuple *)m->match.hash.key;
1861                         struct in6_addr saddr, daddr;
1862                         uint16_t sp, dp;
1863                         uint8_t proto;
1864
1865                         if (n_tokens < 8) {
1866                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1867                                         tokens[0]);
1868                                 return 0;
1869                         }
1870
1871                         if (softnic_parse_ipv6_addr(tokens[3], &saddr) != 0) {
1872                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
1873                                 return 0;
1874                         }
1875
1876                         if (softnic_parse_ipv6_addr(tokens[4], &daddr) != 0) {
1877                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
1878                                 return 0;
1879                         }
1880
1881                         if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) {
1882                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
1883                                 return 0;
1884                         }
1885
1886                         if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) {
1887                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
1888                                 return 0;
1889                         }
1890
1891                         if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) {
1892                                 snprintf(out, out_size, MSG_ARG_INVALID,
1893                                         "proto");
1894                                 return 0;
1895                         }
1896
1897                         memcpy(ipv6->sa, saddr.s6_addr, 16);
1898                         memcpy(ipv6->da, daddr.s6_addr, 16);
1899                         ipv6->sp = rte_cpu_to_be_16(sp);
1900                         ipv6->dp = rte_cpu_to_be_16(dp);
1901                         ipv6->proto = proto;
1902
1903                         return 8;
1904                 } /* hash ipv6_5tuple */
1905
1906                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
1907                         struct pkt_key_ipv4_addr *ipv4_addr =
1908                                 (struct pkt_key_ipv4_addr *)m->match.hash.key;
1909                         struct in_addr addr;
1910
1911                         if (n_tokens < 4) {
1912                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1913                                         tokens[0]);
1914                                 return 0;
1915                         }
1916
1917                         if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) {
1918                                 snprintf(out, out_size, MSG_ARG_INVALID,
1919                                         "addr");
1920                                 return 0;
1921                         }
1922
1923                         ipv4_addr->addr = addr.s_addr;
1924
1925                         return 4;
1926                 } /* hash ipv4_addr */
1927
1928                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
1929                         struct pkt_key_ipv6_addr *ipv6_addr =
1930                                 (struct pkt_key_ipv6_addr *)m->match.hash.key;
1931                         struct in6_addr addr;
1932
1933                         if (n_tokens < 4) {
1934                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1935                                         tokens[0]);
1936                                 return 0;
1937                         }
1938
1939                         if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) {
1940                                 snprintf(out, out_size, MSG_ARG_INVALID,
1941                                         "addr");
1942                                 return 0;
1943                         }
1944
1945                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
1946
1947                         return 4;
1948                 } /* hash ipv6_5tuple */
1949
1950                 if (strcmp(tokens[2], "qinq") == 0) {
1951                         struct pkt_key_qinq *qinq =
1952                                 (struct pkt_key_qinq *)m->match.hash.key;
1953                         uint16_t svlan, cvlan;
1954
1955                         if (n_tokens < 5) {
1956                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1957                                         tokens[0]);
1958                                 return 0;
1959                         }
1960
1961                         if ((softnic_parser_read_uint16(&svlan, tokens[3]) != 0) ||
1962                                 svlan > 0xFFF) {
1963                                 snprintf(out, out_size, MSG_ARG_INVALID,
1964                                         "svlan");
1965                                 return 0;
1966                         }
1967
1968                         if ((softnic_parser_read_uint16(&cvlan, tokens[4]) != 0) ||
1969                                 cvlan > 0xFFF) {
1970                                 snprintf(out, out_size, MSG_ARG_INVALID,
1971                                         "cvlan");
1972                                 return 0;
1973                         }
1974
1975                         qinq->svlan = rte_cpu_to_be_16(svlan);
1976                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
1977
1978                         return 5;
1979                 } /* hash qinq */
1980
1981                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1982                 return 0;
1983         } /* hash */
1984
1985         if (strcmp(tokens[1], "lpm") == 0) {
1986                 if (n_tokens < 5) {
1987                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1988                         return 0;
1989                 }
1990
1991                 m->match_type = TABLE_LPM;
1992
1993                 if (strcmp(tokens[2], "ipv4") == 0) {
1994                         struct in_addr addr;
1995
1996                         m->match.lpm.ip_version = 1;
1997
1998                         if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) {
1999                                 snprintf(out, out_size, MSG_ARG_INVALID,
2000                                         "addr");
2001                                 return 0;
2002                         }
2003
2004                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2005                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2006                         struct in6_addr addr;
2007
2008                         m->match.lpm.ip_version = 0;
2009
2010                         if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) {
2011                                 snprintf(out, out_size, MSG_ARG_INVALID,
2012                                         "addr");
2013                                 return 0;
2014                         }
2015
2016                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2017                 } else {
2018                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2019                                 "ipv4 or ipv6");
2020                         return 0;
2021                 }
2022
2023                 if (softnic_parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2024                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2025                         return 0;
2026                 }
2027
2028                 return 5;
2029         } /* lpm */
2030
2031         snprintf(out, out_size, MSG_ARG_MISMATCH,
2032                 "acl or array or hash or lpm");
2033         return 0;
2034 }
2035
2036 /**
2037  * table_action ::=
2038  *
2039  * action
2040  *    fwd
2041  *       drop
2042  *       | port <port_id>
2043  *       | meta
2044  *       | table <table_id>
2045  *    [balance <out0> ... <out7>]
2046  *    [meter
2047  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2048  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2049  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2050  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2051  *    [tm subport <subport_id> pipe <pipe_id>]
2052  *    [encap
2053  *       ether <da> <sa>
2054  *       | vlan <da> <sa> <pcp> <dei> <vid>
2055  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2056  *       | mpls unicast | multicast
2057  *          <da> <sa>
2058  *          label0 <label> <tc> <ttl>
2059  *          [label1 <label> <tc> <ttl>
2060  *          [label2 <label> <tc> <ttl>
2061  *          [label3 <label> <tc> <ttl>]]]
2062  *       | pppoe <da> <sa> <session_id>]
2063  *    [nat ipv4 | ipv6 <addr> <port>]
2064  *    [ttl dec | keep]
2065  *    [stats]
2066  *    [time]
2067  *
2068  * where:
2069  *    <pa> ::= g | y | r | drop
2070  */
2071 static uint32_t
2072 parse_table_action_fwd(char **tokens,
2073         uint32_t n_tokens,
2074         struct softnic_table_rule_action *a)
2075 {
2076         if (n_tokens == 0 ||
2077                 (strcmp(tokens[0], "fwd") != 0))
2078                 return 0;
2079
2080         tokens++;
2081         n_tokens--;
2082
2083         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2084                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2085                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2086                 return 1 + 1;
2087         }
2088
2089         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2090                 uint32_t id;
2091
2092                 if (n_tokens < 2 ||
2093                         softnic_parser_read_uint32(&id, tokens[1]))
2094                         return 0;
2095
2096                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2097                 a->fwd.id = id;
2098                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2099                 return 1 + 2;
2100         }
2101
2102         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2103                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2104                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2105                 return 1 + 1;
2106         }
2107
2108         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2109                 uint32_t id;
2110
2111                 if (n_tokens < 2 ||
2112                         softnic_parser_read_uint32(&id, tokens[1]))
2113                         return 0;
2114
2115                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2116                 a->fwd.id = id;
2117                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2118                 return 1 + 2;
2119         }
2120
2121         return 0;
2122 }
2123
2124 static uint32_t
2125 parse_table_action_balance(char **tokens,
2126         uint32_t n_tokens,
2127         struct softnic_table_rule_action *a)
2128 {
2129         uint32_t i;
2130
2131         if (n_tokens == 0 ||
2132                 (strcmp(tokens[0], "balance") != 0))
2133                 return 0;
2134
2135         tokens++;
2136         n_tokens--;
2137
2138         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
2139                 return 0;
2140
2141         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
2142                 if (softnic_parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
2143                         return 0;
2144
2145         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
2146         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
2147 }
2148
2149 static int
2150 parse_policer_action(char *token, enum rte_table_action_policer *a)
2151 {
2152         if (strcmp(token, "g") == 0) {
2153                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
2154                 return 0;
2155         }
2156
2157         if (strcmp(token, "y") == 0) {
2158                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
2159                 return 0;
2160         }
2161
2162         if (strcmp(token, "r") == 0) {
2163                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
2164                 return 0;
2165         }
2166
2167         if (strcmp(token, "drop") == 0) {
2168                 *a = RTE_TABLE_ACTION_POLICER_DROP;
2169                 return 0;
2170         }
2171
2172         return -1;
2173 }
2174
2175 static uint32_t
2176 parse_table_action_meter_tc(char **tokens,
2177         uint32_t n_tokens,
2178         struct rte_table_action_mtr_tc_params *mtr)
2179 {
2180         if (n_tokens < 9 ||
2181                 strcmp(tokens[0], "meter") ||
2182                 softnic_parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
2183                 strcmp(tokens[2], "policer") ||
2184                 strcmp(tokens[3], "g") ||
2185                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
2186                 strcmp(tokens[5], "y") ||
2187                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
2188                 strcmp(tokens[7], "r") ||
2189                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
2190                 return 0;
2191
2192         return 9;
2193 }
2194
2195 static uint32_t
2196 parse_table_action_meter(char **tokens,
2197         uint32_t n_tokens,
2198         struct softnic_table_rule_action *a)
2199 {
2200         if (n_tokens == 0 ||
2201                 strcmp(tokens[0], "meter"))
2202                 return 0;
2203
2204         tokens++;
2205         n_tokens--;
2206
2207         if (n_tokens < 10 ||
2208                 strcmp(tokens[0], "tc0") ||
2209                 (parse_table_action_meter_tc(tokens + 1,
2210                         n_tokens - 1,
2211                         &a->mtr.mtr[0]) == 0))
2212                 return 0;
2213
2214         tokens += 10;
2215         n_tokens -= 10;
2216
2217         if (n_tokens == 0 ||
2218                 strcmp(tokens[0], "tc1")) {
2219                 a->mtr.tc_mask = 1;
2220                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2221                 return 1 + 10;
2222         }
2223
2224         if (n_tokens < 30 ||
2225                 (parse_table_action_meter_tc(tokens + 1,
2226                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
2227                 strcmp(tokens[10], "tc2") ||
2228                 (parse_table_action_meter_tc(tokens + 11,
2229                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
2230                 strcmp(tokens[20], "tc3") ||
2231                 (parse_table_action_meter_tc(tokens + 21,
2232                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
2233                 return 0;
2234
2235         a->mtr.tc_mask = 0xF;
2236         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2237         return 1 + 10 + 3 * 10;
2238 }
2239
2240 static uint32_t
2241 parse_table_action_tm(char **tokens,
2242         uint32_t n_tokens,
2243         struct softnic_table_rule_action *a)
2244 {
2245         uint32_t subport_id, pipe_id;
2246
2247         if (n_tokens < 5 ||
2248                 strcmp(tokens[0], "tm") ||
2249                 strcmp(tokens[1], "subport") ||
2250                 softnic_parser_read_uint32(&subport_id, tokens[2]) ||
2251                 strcmp(tokens[3], "pipe") ||
2252                 softnic_parser_read_uint32(&pipe_id, tokens[4]))
2253                 return 0;
2254
2255         a->tm.subport_id = subport_id;
2256         a->tm.pipe_id = pipe_id;
2257         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
2258         return 5;
2259 }
2260
2261 static uint32_t
2262 parse_table_action_encap(char **tokens,
2263         uint32_t n_tokens,
2264         struct softnic_table_rule_action *a)
2265 {
2266         if (n_tokens == 0 ||
2267                 strcmp(tokens[0], "encap"))
2268                 return 0;
2269
2270         tokens++;
2271         n_tokens--;
2272
2273         /* ether */
2274         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
2275                 if (n_tokens < 3 ||
2276                         softnic_parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
2277                         softnic_parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
2278                         return 0;
2279
2280                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
2281                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2282                 return 1 + 3;
2283         }
2284
2285         /* vlan */
2286         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
2287                 uint32_t pcp, dei, vid;
2288
2289                 if (n_tokens < 6 ||
2290                         softnic_parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
2291                         softnic_parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
2292                         softnic_parser_read_uint32(&pcp, tokens[3]) ||
2293                         pcp > 0x7 ||
2294                         softnic_parser_read_uint32(&dei, tokens[4]) ||
2295                         dei > 0x1 ||
2296                         softnic_parser_read_uint32(&vid, tokens[5]) ||
2297                         vid > 0xFFF)
2298                         return 0;
2299
2300                 a->encap.vlan.vlan.pcp = pcp & 0x7;
2301                 a->encap.vlan.vlan.dei = dei & 0x1;
2302                 a->encap.vlan.vlan.vid = vid & 0xFFF;
2303                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
2304                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2305                 return 1 + 6;
2306         }
2307
2308         /* qinq */
2309         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
2310                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
2311                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
2312
2313                 if (n_tokens < 9 ||
2314                         softnic_parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
2315                         softnic_parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
2316                         softnic_parser_read_uint32(&svlan_pcp, tokens[3]) ||
2317                         svlan_pcp > 0x7 ||
2318                         softnic_parser_read_uint32(&svlan_dei, tokens[4]) ||
2319                         svlan_dei > 0x1 ||
2320                         softnic_parser_read_uint32(&svlan_vid, tokens[5]) ||
2321                         svlan_vid > 0xFFF ||
2322                         softnic_parser_read_uint32(&cvlan_pcp, tokens[6]) ||
2323                         cvlan_pcp > 0x7 ||
2324                         softnic_parser_read_uint32(&cvlan_dei, tokens[7]) ||
2325                         cvlan_dei > 0x1 ||
2326                         softnic_parser_read_uint32(&cvlan_vid, tokens[8]) ||
2327                         cvlan_vid > 0xFFF)
2328                         return 0;
2329
2330                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
2331                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
2332                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
2333                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
2334                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
2335                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
2336                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
2337                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2338                 return 1 + 9;
2339         }
2340
2341         /* mpls */
2342         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
2343                 uint32_t label, tc, ttl;
2344
2345                 if (n_tokens < 8)
2346                         return 0;
2347
2348                 if (strcmp(tokens[1], "unicast") == 0)
2349                         a->encap.mpls.unicast = 1;
2350                 else if (strcmp(tokens[1], "multicast") == 0)
2351                         a->encap.mpls.unicast = 0;
2352                 else
2353                         return 0;
2354
2355                 if (softnic_parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
2356                         softnic_parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
2357                         strcmp(tokens[4], "label0") ||
2358                         softnic_parser_read_uint32(&label, tokens[5]) ||
2359                         label > 0xFFFFF ||
2360                         softnic_parser_read_uint32(&tc, tokens[6]) ||
2361                         tc > 0x7 ||
2362                         softnic_parser_read_uint32(&ttl, tokens[7]) ||
2363                         ttl > 0x3F)
2364                         return 0;
2365
2366                 a->encap.mpls.mpls[0].label = label;
2367                 a->encap.mpls.mpls[0].tc = tc;
2368                 a->encap.mpls.mpls[0].ttl = ttl;
2369
2370                 tokens += 8;
2371                 n_tokens -= 8;
2372
2373                 if (n_tokens == 0 ||
2374                         strcmp(tokens[0], "label1")) {
2375                         a->encap.mpls.mpls_count = 1;
2376                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
2377                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2378                         return 1 + 8;
2379                 }
2380
2381                 if (n_tokens < 4 ||
2382                         softnic_parser_read_uint32(&label, tokens[1]) ||
2383                         label > 0xFFFFF ||
2384                         softnic_parser_read_uint32(&tc, tokens[2]) ||
2385                         tc > 0x7 ||
2386                         softnic_parser_read_uint32(&ttl, tokens[3]) ||
2387                         ttl > 0x3F)
2388                         return 0;
2389
2390                 a->encap.mpls.mpls[1].label = label;
2391                 a->encap.mpls.mpls[1].tc = tc;
2392                 a->encap.mpls.mpls[1].ttl = ttl;
2393
2394                 tokens += 4;
2395                 n_tokens -= 4;
2396
2397                 if (n_tokens == 0 ||
2398                         strcmp(tokens[0], "label2")) {
2399                         a->encap.mpls.mpls_count = 2;
2400                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
2401                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2402                         return 1 + 8 + 4;
2403                 }
2404
2405                 if (n_tokens < 4 ||
2406                         softnic_parser_read_uint32(&label, tokens[1]) ||
2407                         label > 0xFFFFF ||
2408                         softnic_parser_read_uint32(&tc, tokens[2]) ||
2409                         tc > 0x7 ||
2410                         softnic_parser_read_uint32(&ttl, tokens[3]) ||
2411                         ttl > 0x3F)
2412                         return 0;
2413
2414                 a->encap.mpls.mpls[2].label = label;
2415                 a->encap.mpls.mpls[2].tc = tc;
2416                 a->encap.mpls.mpls[2].ttl = ttl;
2417
2418                 tokens += 4;
2419                 n_tokens -= 4;
2420
2421                 if (n_tokens == 0 ||
2422                         strcmp(tokens[0], "label3")) {
2423                         a->encap.mpls.mpls_count = 3;
2424                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
2425                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2426                         return 1 + 8 + 4 + 4;
2427                 }
2428
2429                 if (n_tokens < 4 ||
2430                         softnic_parser_read_uint32(&label, tokens[1]) ||
2431                         label > 0xFFFFF ||
2432                         softnic_parser_read_uint32(&tc, tokens[2]) ||
2433                         tc > 0x7 ||
2434                         softnic_parser_read_uint32(&ttl, tokens[3]) ||
2435                         ttl > 0x3F)
2436                         return 0;
2437
2438                 a->encap.mpls.mpls[3].label = label;
2439                 a->encap.mpls.mpls[3].tc = tc;
2440                 a->encap.mpls.mpls[3].ttl = ttl;
2441
2442                 a->encap.mpls.mpls_count = 4;
2443                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
2444                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2445                 return 1 + 8 + 4 + 4 + 4;
2446         }
2447
2448         /* pppoe */
2449         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
2450                 if (n_tokens < 4 ||
2451                         softnic_parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
2452                         softnic_parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
2453                         softnic_parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
2454                                 tokens[3]))
2455                         return 0;
2456
2457                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
2458                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2459                 return 1 + 4;
2460         }
2461
2462         return 0;
2463 }
2464
2465 static uint32_t
2466 parse_table_action_nat(char **tokens,
2467         uint32_t n_tokens,
2468         struct softnic_table_rule_action *a)
2469 {
2470         if (n_tokens < 4 ||
2471                 strcmp(tokens[0], "nat"))
2472                 return 0;
2473
2474         if (strcmp(tokens[1], "ipv4") == 0) {
2475                 struct in_addr addr;
2476                 uint16_t port;
2477
2478                 if (softnic_parse_ipv4_addr(tokens[2], &addr) ||
2479                         softnic_parser_read_uint16(&port, tokens[3]))
2480                         return 0;
2481
2482                 a->nat.ip_version = 1;
2483                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2484                 a->nat.port = port;
2485                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
2486                 return 4;
2487         }
2488
2489         if (strcmp(tokens[1], "ipv6") == 0) {
2490                 struct in6_addr addr;
2491                 uint16_t port;
2492
2493                 if (softnic_parse_ipv6_addr(tokens[2], &addr) ||
2494                         softnic_parser_read_uint16(&port, tokens[3]))
2495                         return 0;
2496
2497                 a->nat.ip_version = 0;
2498                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
2499                 a->nat.port = port;
2500                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
2501                 return 4;
2502         }
2503
2504         return 0;
2505 }
2506
2507 static uint32_t
2508 parse_table_action_ttl(char **tokens,
2509         uint32_t n_tokens,
2510         struct softnic_table_rule_action *a)
2511 {
2512         if (n_tokens < 2 ||
2513                 strcmp(tokens[0], "ttl"))
2514                 return 0;
2515
2516         if (strcmp(tokens[1], "dec") == 0)
2517                 a->ttl.decrement = 1;
2518         else if (strcmp(tokens[1], "keep") == 0)
2519                 a->ttl.decrement = 0;
2520         else
2521                 return 0;
2522
2523         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
2524         return 2;
2525 }
2526
2527 static uint32_t
2528 parse_table_action_stats(char **tokens,
2529         uint32_t n_tokens,
2530         struct softnic_table_rule_action *a)
2531 {
2532         if (n_tokens < 1 ||
2533                 strcmp(tokens[0], "stats"))
2534                 return 0;
2535
2536         a->stats.n_packets = 0;
2537         a->stats.n_bytes = 0;
2538         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
2539         return 1;
2540 }
2541
2542 static uint32_t
2543 parse_table_action_time(char **tokens,
2544         uint32_t n_tokens,
2545         struct softnic_table_rule_action *a)
2546 {
2547         if (n_tokens < 1 ||
2548                 strcmp(tokens[0], "time"))
2549                 return 0;
2550
2551         a->time.time = rte_rdtsc();
2552         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
2553         return 1;
2554 }
2555
2556 static uint32_t
2557 parse_table_action(char **tokens,
2558         uint32_t n_tokens,
2559         char *out,
2560         size_t out_size,
2561         struct softnic_table_rule_action *a)
2562 {
2563         uint32_t n_tokens0 = n_tokens;
2564
2565         memset(a, 0, sizeof(*a));
2566
2567         if (n_tokens < 2 ||
2568                 strcmp(tokens[0], "action"))
2569                 return 0;
2570
2571         tokens++;
2572         n_tokens--;
2573
2574         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
2575                 uint32_t n;
2576
2577                 n = parse_table_action_fwd(tokens, n_tokens, a);
2578                 if (n == 0) {
2579                         snprintf(out, out_size, MSG_ARG_INVALID,
2580                                 "action fwd");
2581                         return 0;
2582                 }
2583
2584                 tokens += n;
2585                 n_tokens -= n;
2586         }
2587
2588         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
2589                 uint32_t n;
2590
2591                 n = parse_table_action_balance(tokens, n_tokens, a);
2592                 if (n == 0) {
2593                         snprintf(out, out_size, MSG_ARG_INVALID,
2594                                 "action balance");
2595                         return 0;
2596                 }
2597
2598                 tokens += n;
2599                 n_tokens -= n;
2600         }
2601
2602         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
2603                 uint32_t n;
2604
2605                 n = parse_table_action_meter(tokens, n_tokens, a);
2606                 if (n == 0) {
2607                         snprintf(out, out_size, MSG_ARG_INVALID,
2608                                 "action meter");
2609                         return 0;
2610                 }
2611
2612                 tokens += n;
2613                 n_tokens -= n;
2614         }
2615
2616         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
2617                 uint32_t n;
2618
2619                 n = parse_table_action_tm(tokens, n_tokens, a);
2620                 if (n == 0) {
2621                         snprintf(out, out_size, MSG_ARG_INVALID,
2622                                 "action tm");
2623                         return 0;
2624                 }
2625
2626                 tokens += n;
2627                 n_tokens -= n;
2628         }
2629
2630         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
2631                 uint32_t n;
2632
2633                 n = parse_table_action_encap(tokens, n_tokens, a);
2634                 if (n == 0) {
2635                         snprintf(out, out_size, MSG_ARG_INVALID,
2636                                 "action encap");
2637                         return 0;
2638                 }
2639
2640                 tokens += n;
2641                 n_tokens -= n;
2642         }
2643
2644         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
2645                 uint32_t n;
2646
2647                 n = parse_table_action_nat(tokens, n_tokens, a);
2648                 if (n == 0) {
2649                         snprintf(out, out_size, MSG_ARG_INVALID,
2650                                 "action nat");
2651                         return 0;
2652                 }
2653
2654                 tokens += n;
2655                 n_tokens -= n;
2656         }
2657
2658         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
2659                 uint32_t n;
2660
2661                 n = parse_table_action_ttl(tokens, n_tokens, a);
2662                 if (n == 0) {
2663                         snprintf(out, out_size, MSG_ARG_INVALID,
2664                                 "action ttl");
2665                         return 0;
2666                 }
2667
2668                 tokens += n;
2669                 n_tokens -= n;
2670         }
2671
2672         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
2673                 uint32_t n;
2674
2675                 n = parse_table_action_stats(tokens, n_tokens, a);
2676                 if (n == 0) {
2677                         snprintf(out, out_size, MSG_ARG_INVALID,
2678                                 "action stats");
2679                         return 0;
2680                 }
2681
2682                 tokens += n;
2683                 n_tokens -= n;
2684         }
2685
2686         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
2687                 uint32_t n;
2688
2689                 n = parse_table_action_time(tokens, n_tokens, a);
2690                 if (n == 0) {
2691                         snprintf(out, out_size, MSG_ARG_INVALID,
2692                                 "action time");
2693                         return 0;
2694                 }
2695
2696                 tokens += n;
2697                 n_tokens -= n;
2698         }
2699
2700         if (n_tokens0 - n_tokens == 1) {
2701                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
2702                 return 0;
2703         }
2704
2705         return n_tokens0 - n_tokens;
2706 }
2707
2708 /**
2709  * pipeline <pipeline_name> table <table_id> rule add
2710  *    match <match>
2711  *    action <table_action>
2712  */
2713 static void
2714 cmd_softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
2715         char **tokens,
2716         uint32_t n_tokens,
2717         char *out,
2718         size_t out_size)
2719 {
2720         struct softnic_table_rule_match m;
2721         struct softnic_table_rule_action a;
2722         char *pipeline_name;
2723         void *data;
2724         uint32_t table_id, t0, n_tokens_parsed;
2725         int status;
2726
2727         if (n_tokens < 8) {
2728                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2729                 return;
2730         }
2731
2732         pipeline_name = tokens[1];
2733
2734         if (strcmp(tokens[2], "table") != 0) {
2735                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2736                 return;
2737         }
2738
2739         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
2740                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2741                 return;
2742         }
2743
2744         if (strcmp(tokens[4], "rule") != 0) {
2745                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
2746                 return;
2747         }
2748
2749         if (strcmp(tokens[5], "add") != 0) {
2750                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
2751                 return;
2752         }
2753
2754         t0 = 6;
2755
2756         /* match */
2757         n_tokens_parsed = parse_match(tokens + t0,
2758                 n_tokens - t0,
2759                 out,
2760                 out_size,
2761                 &m);
2762         if (n_tokens_parsed == 0)
2763                 return;
2764         t0 += n_tokens_parsed;
2765
2766         /* action */
2767         n_tokens_parsed = parse_table_action(tokens + t0,
2768                 n_tokens - t0,
2769                 out,
2770                 out_size,
2771                 &a);
2772         if (n_tokens_parsed == 0)
2773                 return;
2774         t0 += n_tokens_parsed;
2775
2776         if (t0 != n_tokens) {
2777                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2778                 return;
2779         }
2780
2781         status = softnic_pipeline_table_rule_add(softnic,
2782                 pipeline_name,
2783                 table_id,
2784                 &m,
2785                 &a,
2786                 &data);
2787         if (status) {
2788                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2789                 return;
2790         }
2791 }
2792
2793 /**
2794  * pipeline <pipeline_name> table <table_id> rule add
2795  *    match
2796  *       default
2797  *    action
2798  *       fwd
2799  *          drop
2800  *          | port <port_id>
2801  *          | meta
2802  *          | table <table_id>
2803  */
2804 static void
2805 cmd_softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
2806         char **tokens,
2807         uint32_t n_tokens,
2808         char *out,
2809         size_t out_size)
2810 {
2811         struct softnic_table_rule_action action;
2812         void *data;
2813         char *pipeline_name;
2814         uint32_t table_id;
2815         int status;
2816
2817         if (n_tokens != 11 &&
2818                 n_tokens != 12) {
2819                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2820                 return;
2821         }
2822
2823         pipeline_name = tokens[1];
2824
2825         if (strcmp(tokens[2], "table") != 0) {
2826                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2827                 return;
2828         }
2829
2830         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
2831                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2832                 return;
2833         }
2834
2835         if (strcmp(tokens[4], "rule") != 0) {
2836                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
2837                 return;
2838         }
2839
2840         if (strcmp(tokens[5], "add") != 0) {
2841                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
2842                 return;
2843         }
2844
2845         if (strcmp(tokens[6], "match") != 0) {
2846                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
2847                 return;
2848         }
2849
2850         if (strcmp(tokens[7], "default") != 0) {
2851                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
2852                 return;
2853         }
2854
2855         if (strcmp(tokens[8], "action") != 0) {
2856                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
2857                 return;
2858         }
2859
2860         if (strcmp(tokens[9], "fwd") != 0) {
2861                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
2862                 return;
2863         }
2864
2865         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
2866
2867         if (strcmp(tokens[10], "drop") == 0) {
2868                 if (n_tokens != 11) {
2869                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2870                         return;
2871                 }
2872
2873                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
2874         } else if (strcmp(tokens[10], "port") == 0) {
2875                 uint32_t id;
2876
2877                 if (n_tokens != 12) {
2878                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2879                         return;
2880                 }
2881
2882                 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) {
2883                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2884                         return;
2885                 }
2886
2887                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
2888                 action.fwd.id = id;
2889         } else if (strcmp(tokens[10], "meta") == 0) {
2890                 if (n_tokens != 11) {
2891                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2892                         return;
2893                 }
2894
2895                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2896         } else if (strcmp(tokens[10], "table") == 0) {
2897                 uint32_t id;
2898
2899                 if (n_tokens != 12) {
2900                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2901                         return;
2902                 }
2903
2904                 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) {
2905                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2906                         return;
2907                 }
2908
2909                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
2910                 action.fwd.id = id;
2911         } else {
2912                 snprintf(out, out_size, MSG_ARG_INVALID,
2913                         "drop or port or meta or table");
2914                 return;
2915         }
2916
2917         status = softnic_pipeline_table_rule_add_default(softnic,
2918                 pipeline_name,
2919                 table_id,
2920                 &action,
2921                 &data);
2922         if (status) {
2923                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2924                 return;
2925         }
2926 }
2927
2928 /**
2929  * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
2930  *
2931  * File <file_name>:
2932  * - line format: match <match> action <action>
2933  */
2934 static int
2935 cli_rule_file_process(const char *file_name,
2936         size_t line_len_max,
2937         struct softnic_table_rule_match *m,
2938         struct softnic_table_rule_action *a,
2939         uint32_t *n_rules,
2940         uint32_t *line_number,
2941         char *out,
2942         size_t out_size);
2943
2944 static void
2945 cmd_softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
2946         char **tokens,
2947         uint32_t n_tokens,
2948         char *out,
2949         size_t out_size)
2950 {
2951         struct softnic_table_rule_match *match;
2952         struct softnic_table_rule_action *action;
2953         void **data;
2954         char *pipeline_name, *file_name;
2955         uint32_t table_id, n_rules, n_rules_parsed, line_number;
2956         int status;
2957
2958         if (n_tokens != 9) {
2959                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2960                 return;
2961         }
2962
2963         pipeline_name = tokens[1];
2964
2965         if (strcmp(tokens[2], "table") != 0) {
2966                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2967                 return;
2968         }
2969
2970         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
2971                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2972                 return;
2973         }
2974
2975         if (strcmp(tokens[4], "rule") != 0) {
2976                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
2977                 return;
2978         }
2979
2980         if (strcmp(tokens[5], "add") != 0) {
2981                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
2982                 return;
2983         }
2984
2985         if (strcmp(tokens[6], "bulk") != 0) {
2986                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
2987                 return;
2988         }
2989
2990         file_name = tokens[7];
2991
2992         if ((softnic_parser_read_uint32(&n_rules, tokens[8]) != 0) ||
2993                 n_rules == 0) {
2994                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2995                 return;
2996         }
2997
2998         /* Memory allocation. */
2999         match = calloc(n_rules, sizeof(struct softnic_table_rule_match));
3000         action = calloc(n_rules, sizeof(struct softnic_table_rule_action));
3001         data = calloc(n_rules, sizeof(void *));
3002         if (match == NULL ||
3003                 action == NULL ||
3004                 data == NULL) {
3005                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3006                 free(data);
3007                 free(action);
3008                 free(match);
3009                 return;
3010         }
3011
3012         /* Load rule file */
3013         n_rules_parsed = n_rules;
3014         status = cli_rule_file_process(file_name,
3015                 1024,
3016                 match,
3017                 action,
3018                 &n_rules_parsed,
3019                 &line_number,
3020                 out,
3021                 out_size);
3022         if (status) {
3023                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3024                 free(data);
3025                 free(action);
3026                 free(match);
3027                 return;
3028         }
3029         if (n_rules_parsed != n_rules) {
3030                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3031                 free(data);
3032                 free(action);
3033                 free(match);
3034                 return;
3035         }
3036
3037         /* Rule bulk add */
3038         status = softnic_pipeline_table_rule_add_bulk(softnic,
3039                 pipeline_name,
3040                 table_id,
3041                 match,
3042                 action,
3043                 data,
3044                 &n_rules);
3045         if (status) {
3046                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3047                 free(data);
3048                 free(action);
3049                 free(match);
3050                 return;
3051         }
3052
3053         /* Memory free */
3054         free(data);
3055         free(action);
3056         free(match);
3057 }
3058
3059 /**
3060  * pipeline <pipeline_name> table <table_id> rule delete
3061  *    match <match>
3062  */
3063 static void
3064 cmd_softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
3065         char **tokens,
3066         uint32_t n_tokens,
3067         char *out,
3068         size_t out_size)
3069 {
3070         struct softnic_table_rule_match m;
3071         char *pipeline_name;
3072         uint32_t table_id, n_tokens_parsed, t0;
3073         int status;
3074
3075         if (n_tokens < 8) {
3076                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3077                 return;
3078         }
3079
3080         pipeline_name = tokens[1];
3081
3082         if (strcmp(tokens[2], "table") != 0) {
3083                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3084                 return;
3085         }
3086
3087         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
3088                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3089                 return;
3090         }
3091
3092         if (strcmp(tokens[4], "rule") != 0) {
3093                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3094                 return;
3095         }
3096
3097         if (strcmp(tokens[5], "delete") != 0) {
3098                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3099                 return;
3100         }
3101
3102         t0 = 6;
3103
3104         /* match */
3105         n_tokens_parsed = parse_match(tokens + t0,
3106                 n_tokens - t0,
3107                 out,
3108                 out_size,
3109                 &m);
3110         if (n_tokens_parsed == 0)
3111                 return;
3112         t0 += n_tokens_parsed;
3113
3114         if (n_tokens != t0) {
3115                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3116                 return;
3117         }
3118
3119         status = softnic_pipeline_table_rule_delete(softnic,
3120                 pipeline_name,
3121                 table_id,
3122                 &m);
3123         if (status) {
3124                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3125                 return;
3126         }
3127 }
3128
3129 /**
3130  * pipeline <pipeline_name> table <table_id> rule delete
3131  *    match
3132  *       default
3133  */
3134 static void
3135 cmd_softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
3136         char **tokens,
3137         uint32_t n_tokens,
3138         char *out,
3139         size_t out_size)
3140 {
3141         char *pipeline_name;
3142         uint32_t table_id;
3143         int status;
3144
3145         if (n_tokens != 8) {
3146                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3147                 return;
3148         }
3149
3150         pipeline_name = tokens[1];
3151
3152         if (strcmp(tokens[2], "table") != 0) {
3153                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3154                 return;
3155         }
3156
3157         if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) {
3158                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3159                 return;
3160         }
3161
3162         if (strcmp(tokens[4], "rule") != 0) {
3163                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3164                 return;
3165         }
3166
3167         if (strcmp(tokens[5], "delete") != 0) {
3168                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3169                 return;
3170         }
3171
3172         if (strcmp(tokens[6], "match") != 0) {
3173                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3174                 return;
3175         }
3176
3177         if (strcmp(tokens[7], "default") != 0) {
3178                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3179                 return;
3180         }
3181
3182         status = softnic_pipeline_table_rule_delete_default(softnic,
3183                 pipeline_name,
3184                 table_id);
3185         if (status) {
3186                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3187                 return;
3188         }
3189 }
3190
3191 /**
3192  * thread <thread_id> pipeline <pipeline_name> enable
3193  */
3194 static void
3195 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
3196         char **tokens,
3197         uint32_t n_tokens,
3198         char *out,
3199         size_t out_size)
3200 {
3201         char *pipeline_name;
3202         uint32_t thread_id;
3203         int status;
3204
3205         if (n_tokens != 5) {
3206                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3207                 return;
3208         }
3209
3210         if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
3211                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
3212                 return;
3213         }
3214
3215         if (strcmp(tokens[2], "pipeline") != 0) {
3216                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
3217                 return;
3218         }
3219
3220         pipeline_name = tokens[3];
3221
3222         if (strcmp(tokens[4], "enable") != 0) {
3223                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
3224                 return;
3225         }
3226
3227         status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name);
3228         if (status) {
3229                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
3230                 return;
3231         }
3232 }
3233
3234 /**
3235  * thread <thread_id> pipeline <pipeline_name> disable
3236  */
3237 static void
3238 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
3239         char **tokens,
3240         uint32_t n_tokens,
3241         char *out,
3242         size_t out_size)
3243 {
3244         char *pipeline_name;
3245         uint32_t thread_id;
3246         int status;
3247
3248         if (n_tokens != 5) {
3249                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3250                 return;
3251         }
3252
3253         if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) {
3254                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
3255                 return;
3256         }
3257
3258         if (strcmp(tokens[2], "pipeline") != 0) {
3259                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
3260                 return;
3261         }
3262
3263         pipeline_name = tokens[3];
3264
3265         if (strcmp(tokens[4], "disable") != 0) {
3266                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
3267                 return;
3268         }
3269
3270         status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name);
3271         if (status) {
3272                 snprintf(out, out_size, MSG_CMD_FAIL,
3273                         "thread pipeline disable");
3274                 return;
3275         }
3276 }
3277
3278 void
3279 softnic_cli_process(char *in, char *out, size_t out_size, void *arg)
3280 {
3281         char *tokens[CMD_MAX_TOKENS];
3282         uint32_t n_tokens = RTE_DIM(tokens);
3283         struct pmd_internals *softnic = arg;
3284         int status;
3285
3286         if (is_comment(in))
3287                 return;
3288
3289         status = softnic_parse_tokenize_string(in, tokens, &n_tokens);
3290         if (status) {
3291                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
3292                 return;
3293         }
3294
3295         if (n_tokens == 0)
3296                 return;
3297
3298         if (strcmp(tokens[0], "mempool") == 0) {
3299                 cmd_mempool(softnic, tokens, n_tokens, out, out_size);
3300                 return;
3301         }
3302
3303         if (strcmp(tokens[0], "link") == 0) {
3304                 cmd_link(softnic, tokens, n_tokens, out, out_size);
3305                 return;
3306         }
3307
3308         if (strcmp(tokens[0], "swq") == 0) {
3309                 cmd_swq(softnic, tokens, n_tokens, out, out_size);
3310                 return;
3311         }
3312
3313         if (strcmp(tokens[0], "tap") == 0) {
3314                 cmd_tap(softnic, tokens, n_tokens, out, out_size);
3315                 return;
3316         }
3317
3318         if (strcmp(tokens[0], "port") == 0) {
3319                 cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size);
3320                 return;
3321         }
3322
3323         if (strcmp(tokens[0], "table") == 0) {
3324                 cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size);
3325                 return;
3326         }
3327
3328         if (strcmp(tokens[0], "pipeline") == 0) {
3329                 if (n_tokens >= 3 &&
3330                         (strcmp(tokens[2], "period") == 0)) {
3331                         cmd_pipeline(softnic, tokens, n_tokens, out, out_size);
3332                         return;
3333                 }
3334
3335                 if (n_tokens >= 5 &&
3336                         (strcmp(tokens[2], "port") == 0) &&
3337                         (strcmp(tokens[3], "in") == 0) &&
3338                         (strcmp(tokens[4], "bsz") == 0)) {
3339                         cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size);
3340                         return;
3341                 }
3342
3343                 if (n_tokens >= 5 &&
3344                         (strcmp(tokens[2], "port") == 0) &&
3345                         (strcmp(tokens[3], "out") == 0) &&
3346                         (strcmp(tokens[4], "bsz") == 0)) {
3347                         cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size);
3348                         return;
3349                 }
3350
3351                 if (n_tokens >= 4 &&
3352                         (strcmp(tokens[2], "table") == 0) &&
3353                         (strcmp(tokens[3], "match") == 0)) {
3354                         cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size);
3355                         return;
3356                 }
3357
3358                 if (n_tokens >= 6 &&
3359                         (strcmp(tokens[2], "port") == 0) &&
3360                         (strcmp(tokens[3], "in") == 0) &&
3361                         (strcmp(tokens[5], "table") == 0)) {
3362                         cmd_pipeline_port_in_table(softnic, tokens, n_tokens,
3363                                 out, out_size);
3364                         return;
3365                 }
3366
3367                 if (n_tokens >= 6 &&
3368                         (strcmp(tokens[2], "port") == 0) &&
3369                         (strcmp(tokens[3], "in") == 0) &&
3370                         (strcmp(tokens[5], "enable") == 0)) {
3371                         cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens,
3372                                 out, out_size);
3373                         return;
3374                 }
3375
3376                 if (n_tokens >= 6 &&
3377                         (strcmp(tokens[2], "port") == 0) &&
3378                         (strcmp(tokens[3], "in") == 0) &&
3379                         (strcmp(tokens[5], "disable") == 0)) {
3380                         cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens,
3381                                 out, out_size);
3382                         return;
3383                 }
3384
3385                 if (n_tokens >= 7 &&
3386                         (strcmp(tokens[2], "table") == 0) &&
3387                         (strcmp(tokens[4], "rule") == 0) &&
3388                         (strcmp(tokens[5], "add") == 0) &&
3389                         (strcmp(tokens[6], "match") == 0)) {
3390                         if (n_tokens >= 8 &&
3391                                 (strcmp(tokens[7], "default") == 0)) {
3392                                 cmd_softnic_pipeline_table_rule_add_default(softnic, tokens,
3393                                         n_tokens, out, out_size);
3394                                 return;
3395                         }
3396
3397                         cmd_softnic_pipeline_table_rule_add(softnic, tokens, n_tokens,
3398                                 out, out_size);
3399                         return;
3400                 }
3401
3402                 if (n_tokens >= 7 &&
3403                         (strcmp(tokens[2], "table") == 0) &&
3404                         (strcmp(tokens[4], "rule") == 0) &&
3405                         (strcmp(tokens[5], "add") == 0) &&
3406                         (strcmp(tokens[6], "bulk") == 0)) {
3407                         cmd_softnic_pipeline_table_rule_add_bulk(softnic, tokens,
3408                                 n_tokens, out, out_size);
3409                         return;
3410                 }
3411
3412                 if (n_tokens >= 7 &&
3413                         (strcmp(tokens[2], "table") == 0) &&
3414                         (strcmp(tokens[4], "rule") == 0) &&
3415                         (strcmp(tokens[5], "delete") == 0) &&
3416                         (strcmp(tokens[6], "match") == 0)) {
3417                         if (n_tokens >= 8 &&
3418                                 (strcmp(tokens[7], "default") == 0)) {
3419                                 cmd_softnic_pipeline_table_rule_delete_default(softnic, tokens,
3420                                         n_tokens, out, out_size);
3421                                 return;
3422                                 }
3423
3424                         cmd_softnic_pipeline_table_rule_delete(softnic, tokens, n_tokens,
3425                                 out, out_size);
3426                         return;
3427                 }
3428         }
3429
3430         if (strcmp(tokens[0], "thread") == 0) {
3431                 if (n_tokens >= 5 &&
3432                         (strcmp(tokens[4], "enable") == 0)) {
3433                         cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens,
3434                                 out, out_size);
3435                         return;
3436                 }
3437
3438                 if (n_tokens >= 5 &&
3439                         (strcmp(tokens[4], "disable") == 0)) {
3440                         cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens,
3441                                 out, out_size);
3442                         return;
3443                 }
3444         }
3445
3446         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
3447 }
3448
3449 int
3450 softnic_cli_script_process(struct pmd_internals *softnic,
3451         const char *file_name,
3452         size_t msg_in_len_max,
3453         size_t msg_out_len_max)
3454 {
3455         char *msg_in = NULL, *msg_out = NULL;
3456         FILE *f = NULL;
3457
3458         /* Check input arguments */
3459         if (file_name == NULL ||
3460                 (strlen(file_name) == 0) ||
3461                 msg_in_len_max == 0 ||
3462                 msg_out_len_max == 0)
3463                 return -EINVAL;
3464
3465         msg_in = malloc(msg_in_len_max + 1);
3466         msg_out = malloc(msg_out_len_max + 1);
3467         if (msg_in == NULL ||
3468                 msg_out == NULL) {
3469                 free(msg_out);
3470                 free(msg_in);
3471                 return -ENOMEM;
3472         }
3473
3474         /* Open input file */
3475         f = fopen(file_name, "r");
3476         if (f == NULL) {
3477                 free(msg_out);
3478                 free(msg_in);
3479                 return -EIO;
3480         }
3481
3482         /* Read file */
3483         for ( ; ; ) {
3484                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
3485                         break;
3486
3487                 printf("%s", msg_in);
3488                 msg_out[0] = 0;
3489
3490                 softnic_cli_process(msg_in,
3491                         msg_out,
3492                         msg_out_len_max,
3493                         softnic);
3494
3495                 if (strlen(msg_out))
3496                         printf("%s", msg_out);
3497         }
3498
3499         /* Close file */
3500         fclose(f);
3501         free(msg_out);
3502         free(msg_in);
3503         return 0;
3504 }
3505
3506 static int
3507 cli_rule_file_process(const char *file_name,
3508         size_t line_len_max,
3509         struct softnic_table_rule_match *m,
3510         struct softnic_table_rule_action *a,
3511         uint32_t *n_rules,
3512         uint32_t *line_number,
3513         char *out,
3514         size_t out_size)
3515 {
3516         FILE *f = NULL;
3517         char *line = NULL;
3518         uint32_t rule_id, line_id;
3519         int status = 0;
3520
3521         /* Check input arguments */
3522         if (file_name == NULL ||
3523                 (strlen(file_name) == 0) ||
3524                 line_len_max == 0) {
3525                 *line_number = 0;
3526                 return -EINVAL;
3527         }
3528
3529         /* Memory allocation */
3530         line = malloc(line_len_max + 1);
3531         if (line == NULL) {
3532                 *line_number = 0;
3533                 return -ENOMEM;
3534         }
3535
3536         /* Open file */
3537         f = fopen(file_name, "r");
3538         if (f == NULL) {
3539                 *line_number = 0;
3540                 free(line);
3541                 return -EIO;
3542         }
3543
3544         /* Read file */
3545         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
3546                 char *tokens[CMD_MAX_TOKENS];
3547                 uint32_t n_tokens, n_tokens_parsed, t0;
3548
3549                 /* Read next line from file. */
3550                 if (fgets(line, line_len_max + 1, f) == NULL)
3551                         break;
3552
3553                 /* Comment. */
3554                 if (is_comment(line))
3555                         continue;
3556
3557                 /* Parse line. */
3558                 n_tokens = RTE_DIM(tokens);
3559                 status = softnic_parse_tokenize_string(line, tokens, &n_tokens);
3560                 if (status) {
3561                         status = -EINVAL;
3562                         break;
3563                 }
3564
3565                 /* Empty line. */
3566                 if (n_tokens == 0)
3567                         continue;
3568                 t0 = 0;
3569
3570                 /* Rule match. */
3571                 n_tokens_parsed = parse_match(tokens + t0,
3572                         n_tokens - t0,
3573                         out,
3574                         out_size,
3575                         &m[rule_id]);
3576                 if (n_tokens_parsed == 0) {
3577                         status = -EINVAL;
3578                         break;
3579                 }
3580                 t0 += n_tokens_parsed;
3581
3582                 /* Rule action. */
3583                 n_tokens_parsed = parse_table_action(tokens + t0,
3584                         n_tokens - t0,
3585                         out,
3586                         out_size,
3587                         &a[rule_id]);
3588                 if (n_tokens_parsed == 0) {
3589                         status = -EINVAL;
3590                         break;
3591                 }
3592                 t0 += n_tokens_parsed;
3593
3594                 /* Line completed. */
3595                 if (t0 < n_tokens) {
3596                         status = -EINVAL;
3597                         break;
3598                 }
3599
3600                 /* Increment rule count */
3601                 rule_id++;
3602         }
3603
3604         /* Close file */
3605         fclose(f);
3606
3607         /* Memory free */
3608         free(line);
3609
3610         *n_rules = rule_id;
3611         *line_number = line_id;
3612         return status;
3613 }