3deaff9c4e8a660712f86604a8da1d9dd30c5c60
[deb_dpdk.git] / examples / ip_pipeline / pipeline / pipeline_routing.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <cmdline_parse.h>
35 #include <cmdline_parse_num.h>
36 #include <cmdline_parse_string.h>
37
38 #include "app.h"
39 #include "pipeline_common_fe.h"
40 #include "pipeline_routing.h"
41 #include "parser.h"
42
43 struct app_pipeline_routing_route {
44         struct pipeline_routing_route_key key;
45         struct pipeline_routing_route_data data;
46         void *entry_ptr;
47
48         TAILQ_ENTRY(app_pipeline_routing_route) node;
49 };
50
51 struct app_pipeline_routing_arp_entry {
52         struct pipeline_routing_arp_key key;
53         struct ether_addr macaddr;
54         void *entry_ptr;
55
56         TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
57 };
58
59 struct pipeline_routing {
60         /* Parameters */
61         struct app_params *app;
62         uint32_t pipeline_id;
63         uint32_t n_ports_in;
64         uint32_t n_ports_out;
65         struct pipeline_routing_params rp;
66
67         /* Links */
68         uint32_t link_id[PIPELINE_MAX_PORT_OUT];
69
70         /* Routes */
71         TAILQ_HEAD(, app_pipeline_routing_route) routes;
72         uint32_t n_routes;
73
74         uint32_t default_route_present;
75         uint32_t default_route_port_id;
76         void *default_route_entry_ptr;
77
78         /* ARP entries */
79         TAILQ_HEAD(, app_pipeline_routing_arp_entry) arp_entries;
80         uint32_t n_arp_entries;
81
82         uint32_t default_arp_entry_present;
83         uint32_t default_arp_entry_port_id;
84         void *default_arp_entry_ptr;
85 };
86
87 static int
88 app_pipeline_routing_find_link(struct pipeline_routing *p,
89         uint32_t link_id,
90         uint32_t *port_id)
91 {
92         uint32_t i;
93
94         for (i = 0; i < p->n_ports_out; i++)
95                 if (p->link_id[i] == link_id) {
96                         *port_id = i;
97                         return 0;
98                 }
99
100         return -1;
101 }
102
103 static void
104 app_pipeline_routing_link_op(__rte_unused struct app_params *app,
105         uint32_t link_id,
106         uint32_t up,
107         void *arg)
108 {
109         struct pipeline_routing_route_key key0, key1;
110         struct pipeline_routing *p = arg;
111         struct app_link_params *lp;
112         uint32_t port_id, netmask;
113         int status;
114
115         if (app == NULL)
116                 return;
117
118         APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
119         if (lp == NULL)
120                 return;
121
122         status = app_pipeline_routing_find_link(p,
123                 link_id,
124                 &port_id);
125         if (status)
126                 return;
127
128         netmask = (~0U) << (32 - lp->depth);
129
130         /* Local network (directly attached network) */
131         key0.type = PIPELINE_ROUTING_ROUTE_IPV4;
132         key0.key.ipv4.ip = lp->ip & netmask;
133         key0.key.ipv4.depth = lp->depth;
134
135         /* Local termination */
136         key1.type = PIPELINE_ROUTING_ROUTE_IPV4;
137         key1.key.ipv4.ip = lp->ip;
138         key1.key.ipv4.depth = 32;
139
140         if (up) {
141                 struct pipeline_routing_route_data data0, data1;
142
143                 /* Local network (directly attached network) */
144                 memset(&data0, 0, sizeof(data0));
145                 data0.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
146                         PIPELINE_ROUTING_ROUTE_ARP;
147                 if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
148                         data0.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
149                 if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
150                         data0.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
151                         data0.l2.mpls.n_labels = 1;
152                 }
153                 data0.port_id = port_id;
154
155                 if (p->rp.n_arp_entries)
156                         app_pipeline_routing_add_route(app,
157                                 p->pipeline_id,
158                                 &key0,
159                                 &data0);
160
161                 /* Local termination */
162                 memset(&data1, 0, sizeof(data1));
163                 data1.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
164                         PIPELINE_ROUTING_ROUTE_ARP;
165                 if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
166                         data1.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
167                 if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
168                         data1.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
169                         data1.l2.mpls.n_labels = 1;
170                 }
171                 data1.port_id = p->rp.port_local_dest;
172
173                 app_pipeline_routing_add_route(app,
174                         p->pipeline_id,
175                         &key1,
176                         &data1);
177         } else {
178                 /* Local network (directly attached network) */
179                 if (p->rp.n_arp_entries)
180                         app_pipeline_routing_delete_route(app,
181                                 p->pipeline_id,
182                                 &key0);
183
184                 /* Local termination */
185                 app_pipeline_routing_delete_route(app,
186                         p->pipeline_id,
187                         &key1);
188         }
189 }
190
191 static int
192 app_pipeline_routing_set_link_op(
193         struct app_params *app,
194         struct pipeline_routing *p)
195 {
196         uint32_t port_id;
197
198         for (port_id = 0; port_id < p->n_ports_out; port_id++) {
199                 struct app_link_params *link;
200                 uint32_t link_id;
201                 int status;
202
203                 link = app_pipeline_track_pktq_out_to_link(app,
204                         p->pipeline_id,
205                         port_id);
206                 if (link == NULL)
207                         continue;
208
209                 link_id = link - app->link_params;
210                 p->link_id[port_id] = link_id;
211
212                 status = app_link_set_op(app,
213                         link_id,
214                         p->pipeline_id,
215                         app_pipeline_routing_link_op,
216                         (void *) p);
217                 if (status)
218                         return status;
219         }
220
221         return 0;
222 }
223
224 static void *
225 app_pipeline_routing_init(struct pipeline_params *params,
226         void *arg)
227 {
228         struct app_params *app = (struct app_params *) arg;
229         struct pipeline_routing *p;
230         uint32_t pipeline_id, size;
231         int status;
232
233         /* Check input arguments */
234         if ((params == NULL) ||
235                 (params->n_ports_in == 0) ||
236                 (params->n_ports_out == 0))
237                 return NULL;
238
239         APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
240
241         /* Memory allocation */
242         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_routing));
243         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
244         if (p == NULL)
245                 return NULL;
246
247         /* Initialization */
248         p->app = app;
249         p->pipeline_id = pipeline_id;
250         p->n_ports_in = params->n_ports_in;
251         p->n_ports_out = params->n_ports_out;
252
253         status = pipeline_routing_parse_args(&p->rp, params);
254         if (status) {
255                 rte_free(p);
256                 return NULL;
257         }
258         TAILQ_INIT(&p->routes);
259         p->n_routes = 0;
260
261         TAILQ_INIT(&p->arp_entries);
262         p->n_arp_entries = 0;
263
264         app_pipeline_routing_set_link_op(app, p);
265
266         return p;
267 }
268
269 static int
270 app_pipeline_routing_post_init(void *pipeline)
271 {
272         struct pipeline_routing *p = pipeline;
273
274         /* Check input arguments */
275         if (p == NULL)
276                 return -1;
277
278         return app_pipeline_routing_set_macaddr(p->app, p->pipeline_id);
279 }
280
281 static int
282 app_pipeline_routing_free(void *pipeline)
283 {
284         struct pipeline_routing *p = pipeline;
285
286         /* Check input arguments */
287         if (p == NULL)
288                 return -1;
289
290         /* Free resources */
291         while (!TAILQ_EMPTY(&p->routes)) {
292                 struct app_pipeline_routing_route *route;
293
294                 route = TAILQ_FIRST(&p->routes);
295                 TAILQ_REMOVE(&p->routes, route, node);
296                 rte_free(route);
297         }
298
299         while (!TAILQ_EMPTY(&p->arp_entries)) {
300                 struct app_pipeline_routing_arp_entry *arp_entry;
301
302                 arp_entry = TAILQ_FIRST(&p->arp_entries);
303                 TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
304                 rte_free(arp_entry);
305         }
306
307         rte_free(p);
308         return 0;
309 }
310
311 static struct app_pipeline_routing_route *
312 app_pipeline_routing_find_route(struct pipeline_routing *p,
313                 const struct pipeline_routing_route_key *key)
314 {
315         struct app_pipeline_routing_route *it, *found;
316
317         found = NULL;
318         TAILQ_FOREACH(it, &p->routes, node) {
319                 if ((key->type == it->key.type) &&
320                         (key->key.ipv4.ip == it->key.key.ipv4.ip) &&
321                         (key->key.ipv4.depth == it->key.key.ipv4.depth)) {
322                         found = it;
323                         break;
324                 }
325         }
326
327         return found;
328 }
329
330 static struct app_pipeline_routing_arp_entry *
331 app_pipeline_routing_find_arp_entry(struct pipeline_routing *p,
332                 const struct pipeline_routing_arp_key *key)
333 {
334         struct app_pipeline_routing_arp_entry *it, *found;
335
336         found = NULL;
337         TAILQ_FOREACH(it, &p->arp_entries, node) {
338                 if ((key->type == it->key.type) &&
339                         (key->key.ipv4.port_id == it->key.key.ipv4.port_id) &&
340                         (key->key.ipv4.ip == it->key.key.ipv4.ip)) {
341                         found = it;
342                         break;
343                 }
344         }
345
346         return found;
347 }
348
349 static void
350 print_route(const struct app_pipeline_routing_route *route)
351 {
352         if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
353                 const struct pipeline_routing_route_key_ipv4 *key =
354                                 &route->key.key.ipv4;
355
356                 printf("IP Prefix = %" PRIu32 ".%" PRIu32
357                         ".%" PRIu32 ".%" PRIu32 "/%" PRIu32
358                         " => (Port = %" PRIu32,
359
360                         (key->ip >> 24) & 0xFF,
361                         (key->ip >> 16) & 0xFF,
362                         (key->ip >> 8) & 0xFF,
363                         key->ip & 0xFF,
364
365                         key->depth,
366                         route->data.port_id);
367
368                 if (route->data.flags & PIPELINE_ROUTING_ROUTE_LOCAL)
369                         printf(", Local");
370                 else if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
371                         printf(
372                                 ", Next Hop IP = %" PRIu32 ".%" PRIu32
373                                 ".%" PRIu32 ".%" PRIu32,
374
375                                 (route->data.ethernet.ip >> 24) & 0xFF,
376                                 (route->data.ethernet.ip >> 16) & 0xFF,
377                                 (route->data.ethernet.ip >> 8) & 0xFF,
378                                 route->data.ethernet.ip & 0xFF);
379                 else
380                         printf(
381                                 ", Next Hop HWaddress = %02" PRIx32
382                                 ":%02" PRIx32 ":%02" PRIx32
383                                 ":%02" PRIx32 ":%02" PRIx32
384                                 ":%02" PRIx32,
385
386                                 route->data.ethernet.macaddr.addr_bytes[0],
387                                 route->data.ethernet.macaddr.addr_bytes[1],
388                                 route->data.ethernet.macaddr.addr_bytes[2],
389                                 route->data.ethernet.macaddr.addr_bytes[3],
390                                 route->data.ethernet.macaddr.addr_bytes[4],
391                                 route->data.ethernet.macaddr.addr_bytes[5]);
392
393                 if (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)
394                         printf(", QinQ SVLAN = %" PRIu32 " CVLAN = %" PRIu32,
395                                 route->data.l2.qinq.svlan,
396                                 route->data.l2.qinq.cvlan);
397
398                 if (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {
399                         uint32_t i;
400
401                         printf(", MPLS labels");
402                         for (i = 0; i < route->data.l2.mpls.n_labels; i++)
403                                 printf(" %" PRIu32,
404                                         route->data.l2.mpls.labels[i]);
405                 }
406
407                 printf(")\n");
408         }
409 }
410
411 static void
412 print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
413 {
414         printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32
415                 ".%" PRIu32 ".%" PRIu32
416                 ") => HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
417                 ":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\n",
418
419                 entry->key.key.ipv4.port_id,
420                 (entry->key.key.ipv4.ip >> 24) & 0xFF,
421                 (entry->key.key.ipv4.ip >> 16) & 0xFF,
422                 (entry->key.key.ipv4.ip >> 8) & 0xFF,
423                 entry->key.key.ipv4.ip & 0xFF,
424
425                 entry->macaddr.addr_bytes[0],
426                 entry->macaddr.addr_bytes[1],
427                 entry->macaddr.addr_bytes[2],
428                 entry->macaddr.addr_bytes[3],
429                 entry->macaddr.addr_bytes[4],
430                 entry->macaddr.addr_bytes[5]);
431 }
432
433 static int
434 app_pipeline_routing_route_ls(struct app_params *app, uint32_t pipeline_id)
435 {
436         struct pipeline_routing *p;
437         struct app_pipeline_routing_route *it;
438
439         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
440         if (p == NULL)
441                 return -EINVAL;
442
443         TAILQ_FOREACH(it, &p->routes, node)
444                 print_route(it);
445
446         if (p->default_route_present)
447                 printf("Default route: port %" PRIu32 " (entry ptr = %p)\n",
448                                 p->default_route_port_id,
449                                 p->default_route_entry_ptr);
450         else
451                 printf("Default: DROP\n");
452
453         return 0;
454 }
455
456 int
457 app_pipeline_routing_add_route(struct app_params *app,
458         uint32_t pipeline_id,
459         struct pipeline_routing_route_key *key,
460         struct pipeline_routing_route_data *data)
461 {
462         struct pipeline_routing *p;
463
464         struct pipeline_routing_route_add_msg_req *req;
465         struct pipeline_routing_route_add_msg_rsp *rsp;
466
467         struct app_pipeline_routing_route *entry;
468
469         int new_entry;
470
471         /* Check input arguments */
472         if ((app == NULL) ||
473                 (key == NULL) ||
474                 (data == NULL))
475                 return -1;
476
477         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
478         if (p == NULL)
479                 return -1;
480
481         switch (key->type) {
482         case PIPELINE_ROUTING_ROUTE_IPV4:
483         {
484                 uint32_t depth = key->key.ipv4.depth;
485                 uint32_t netmask;
486
487                 /* key */
488                 if ((depth == 0) || (depth > 32))
489                         return -1;
490
491                 netmask = (~0U) << (32 - depth);
492                 key->key.ipv4.ip &= netmask;
493
494                 /* data */
495                 if (data->port_id >= p->n_ports_out)
496                         return -1;
497
498                 /* Valid range of VLAN tags 12 bits */
499                 if (data->flags & PIPELINE_ROUTING_ROUTE_QINQ)
500                         if ((data->l2.qinq.svlan & 0xF000) ||
501                                         (data->l2.qinq.cvlan & 0xF000))
502                                 return -1;
503
504                 /* Max number of MPLS labels supported */
505                 if (data->flags & PIPELINE_ROUTING_ROUTE_MPLS) {
506                         uint32_t i;
507
508                         if (data->l2.mpls.n_labels >
509                                         PIPELINE_ROUTING_MPLS_LABELS_MAX)
510                                 return -1;
511
512                         /* Max MPLS label value 20 bits */
513                         for (i = 0; i < data->l2.mpls.n_labels; i++)
514                                 if (data->l2.mpls.labels[i] & 0xFFF00000)
515                                         return -1;
516                 }
517         }
518         break;
519
520         default:
521                 return -1;
522         }
523
524         /* Find existing rule or allocate new rule */
525         entry = app_pipeline_routing_find_route(p, key);
526         new_entry = (entry == NULL);
527         if (entry == NULL) {
528                 entry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);
529
530                 if (entry == NULL)
531                         return -1;
532         }
533
534         /* Allocate and write request */
535         req = app_msg_alloc(app);
536         if (req == NULL) {
537                 if (new_entry)
538                         rte_free(entry);
539                 return -1;
540         }
541
542         req->type = PIPELINE_MSG_REQ_CUSTOM;
543         req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD;
544         memcpy(&req->key, key, sizeof(*key));
545         memcpy(&req->data, data, sizeof(*data));
546
547         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
548         if (rsp == NULL) {
549                 if (new_entry)
550                         rte_free(entry);
551                 return -1;
552         }
553
554         /* Read response and write entry */
555         if (rsp->status ||
556                 (rsp->entry_ptr == NULL) ||
557                 ((new_entry == 0) && (rsp->key_found == 0)) ||
558                 ((new_entry == 1) && (rsp->key_found == 1))) {
559                 app_msg_free(app, rsp);
560                 if (new_entry)
561                         rte_free(entry);
562                 return -1;
563         }
564
565         memcpy(&entry->key, key, sizeof(*key));
566         memcpy(&entry->data, data, sizeof(*data));
567         entry->entry_ptr = rsp->entry_ptr;
568
569         /* Commit entry */
570         if (new_entry) {
571                 TAILQ_INSERT_TAIL(&p->routes, entry, node);
572                 p->n_routes++;
573         }
574
575         /* Message buffer free */
576         app_msg_free(app, rsp);
577         return 0;
578 }
579
580 int
581 app_pipeline_routing_delete_route(struct app_params *app,
582         uint32_t pipeline_id,
583         struct pipeline_routing_route_key *key)
584 {
585         struct pipeline_routing *p;
586
587         struct pipeline_routing_route_delete_msg_req *req;
588         struct pipeline_routing_route_delete_msg_rsp *rsp;
589
590         struct app_pipeline_routing_route *entry;
591
592         /* Check input arguments */
593         if ((app == NULL) ||
594                 (key == NULL))
595                 return -1;
596
597         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
598         if (p == NULL)
599                 return -1;
600
601         switch (key->type) {
602         case PIPELINE_ROUTING_ROUTE_IPV4:
603         {
604                 uint32_t depth = key->key.ipv4.depth;
605                 uint32_t netmask;
606
607                 /* key */
608                 if ((depth == 0) || (depth > 32))
609                         return -1;
610
611                 netmask = (~0U) << (32 - depth);
612                 key->key.ipv4.ip &= netmask;
613         }
614         break;
615
616         default:
617                 return -1;
618         }
619
620         /* Find rule */
621         entry = app_pipeline_routing_find_route(p, key);
622         if (entry == NULL)
623                 return 0;
624
625         /* Allocate and write request */
626         req = app_msg_alloc(app);
627         if (req == NULL)
628                 return -1;
629
630         req->type = PIPELINE_MSG_REQ_CUSTOM;
631         req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL;
632         memcpy(&req->key, key, sizeof(*key));
633
634         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
635         if (rsp == NULL)
636                 return -1;
637
638         /* Read response */
639         if (rsp->status || !rsp->key_found) {
640                 app_msg_free(app, rsp);
641                 return -1;
642         }
643
644         /* Remove route */
645         TAILQ_REMOVE(&p->routes, entry, node);
646         p->n_routes--;
647         rte_free(entry);
648
649         /* Free response */
650         app_msg_free(app, rsp);
651
652         return 0;
653 }
654
655 int
656 app_pipeline_routing_add_default_route(struct app_params *app,
657         uint32_t pipeline_id,
658         uint32_t port_id)
659 {
660         struct pipeline_routing *p;
661
662         struct pipeline_routing_route_add_default_msg_req *req;
663         struct pipeline_routing_route_add_default_msg_rsp *rsp;
664
665         /* Check input arguments */
666         if (app == NULL)
667                 return -1;
668
669         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
670         if (p == NULL)
671                 return -1;
672
673         if (port_id >= p->n_ports_out)
674                 return -1;
675
676         /* Allocate and write request */
677         req = app_msg_alloc(app);
678         if (req == NULL)
679                 return -1;
680
681         req->type = PIPELINE_MSG_REQ_CUSTOM;
682         req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT;
683         req->port_id = port_id;
684
685         /* Send request and wait for response */
686         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
687         if (rsp == NULL)
688                 return -1;
689
690         /* Read response and write route */
691         if (rsp->status || (rsp->entry_ptr == NULL)) {
692                 app_msg_free(app, rsp);
693                 return -1;
694         }
695
696         p->default_route_port_id = port_id;
697         p->default_route_entry_ptr = rsp->entry_ptr;
698
699         /* Commit route */
700         p->default_route_present = 1;
701
702         /* Free response */
703         app_msg_free(app, rsp);
704
705         return 0;
706 }
707
708 int
709 app_pipeline_routing_delete_default_route(struct app_params *app,
710         uint32_t pipeline_id)
711 {
712         struct pipeline_routing *p;
713
714         struct pipeline_routing_arp_delete_default_msg_req *req;
715         struct pipeline_routing_arp_delete_default_msg_rsp *rsp;
716
717         /* Check input arguments */
718         if (app == NULL)
719                 return -1;
720
721         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
722         if (p == NULL)
723                 return -1;
724
725         /* Allocate and write request */
726         req = app_msg_alloc(app);
727         if (req == NULL)
728                 return -1;
729
730         req->type = PIPELINE_MSG_REQ_CUSTOM;
731         req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT;
732
733         /* Send request and wait for response */
734         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
735         if (rsp == NULL)
736                 return -1;
737
738         /* Read response and write route */
739         if (rsp->status) {
740                 app_msg_free(app, rsp);
741                 return -1;
742         }
743
744         /* Commit route */
745         p->default_route_present = 0;
746
747         /* Free response */
748         app_msg_free(app, rsp);
749
750         return 0;
751 }
752
753 static int
754 app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
755 {
756         struct pipeline_routing *p;
757         struct app_pipeline_routing_arp_entry *it;
758
759         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
760         if (p == NULL)
761                 return -EINVAL;
762
763         TAILQ_FOREACH(it, &p->arp_entries, node)
764                 print_arp_entry(it);
765
766         if (p->default_arp_entry_present)
767                 printf("Default entry: port %" PRIu32 " (entry ptr = %p)\n",
768                                 p->default_arp_entry_port_id,
769                                 p->default_arp_entry_ptr);
770         else
771                 printf("Default: DROP\n");
772
773         return 0;
774 }
775
776 int
777 app_pipeline_routing_add_arp_entry(struct app_params *app, uint32_t pipeline_id,
778                 struct pipeline_routing_arp_key *key,
779                 struct ether_addr *macaddr)
780 {
781         struct pipeline_routing *p;
782
783         struct pipeline_routing_arp_add_msg_req *req;
784         struct pipeline_routing_arp_add_msg_rsp *rsp;
785
786         struct app_pipeline_routing_arp_entry *entry;
787
788         int new_entry;
789
790         /* Check input arguments */
791         if ((app == NULL) ||
792                 (key == NULL) ||
793                 (macaddr == NULL))
794                 return -1;
795
796         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
797         if (p == NULL)
798                 return -1;
799
800         switch (key->type) {
801         case PIPELINE_ROUTING_ARP_IPV4:
802         {
803                 uint32_t port_id = key->key.ipv4.port_id;
804
805                 /* key */
806                 if (port_id >= p->n_ports_out)
807                         return -1;
808         }
809         break;
810
811         default:
812                 return -1;
813         }
814
815         /* Find existing entry or allocate new */
816         entry = app_pipeline_routing_find_arp_entry(p, key);
817         new_entry = (entry == NULL);
818         if (entry == NULL) {
819                 entry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);
820
821                 if (entry == NULL)
822                         return -1;
823         }
824
825         /* Message buffer allocation */
826         req = app_msg_alloc(app);
827         if (req == NULL) {
828                 if (new_entry)
829                         rte_free(entry);
830                 return -1;
831         }
832
833         req->type = PIPELINE_MSG_REQ_CUSTOM;
834         req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD;
835         memcpy(&req->key, key, sizeof(*key));
836         ether_addr_copy(macaddr, &req->macaddr);
837
838         /* Send request and wait for response */
839         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
840         if (rsp == NULL) {
841                 if (new_entry)
842                         rte_free(entry);
843                 return -1;
844         }
845
846         /* Read response and write entry */
847         if (rsp->status ||
848                 (rsp->entry_ptr == NULL) ||
849                 ((new_entry == 0) && (rsp->key_found == 0)) ||
850                 ((new_entry == 1) && (rsp->key_found == 1))) {
851                 app_msg_free(app, rsp);
852                 if (new_entry)
853                         rte_free(entry);
854                 return -1;
855         }
856
857         memcpy(&entry->key, key, sizeof(*key));
858         ether_addr_copy(macaddr, &entry->macaddr);
859         entry->entry_ptr = rsp->entry_ptr;
860
861         /* Commit entry */
862         if (new_entry) {
863                 TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
864                 p->n_arp_entries++;
865         }
866
867         /* Message buffer free */
868         app_msg_free(app, rsp);
869         return 0;
870 }
871
872 int
873 app_pipeline_routing_delete_arp_entry(struct app_params *app,
874         uint32_t pipeline_id,
875         struct pipeline_routing_arp_key *key)
876 {
877         struct pipeline_routing *p;
878
879         struct pipeline_routing_arp_delete_msg_req *req;
880         struct pipeline_routing_arp_delete_msg_rsp *rsp;
881
882         struct app_pipeline_routing_arp_entry *entry;
883
884         /* Check input arguments */
885         if ((app == NULL) ||
886                 (key == NULL))
887                 return -1;
888
889         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
890         if (p == NULL)
891                 return -EINVAL;
892
893         switch (key->type) {
894         case PIPELINE_ROUTING_ARP_IPV4:
895         {
896                 uint32_t port_id = key->key.ipv4.port_id;
897
898                 /* key */
899                 if (port_id >= p->n_ports_out)
900                         return -1;
901         }
902         break;
903
904         default:
905                 return -1;
906         }
907
908         /* Find rule */
909         entry = app_pipeline_routing_find_arp_entry(p, key);
910         if (entry == NULL)
911                 return 0;
912
913         /* Allocate and write request */
914         req = app_msg_alloc(app);
915         if (req == NULL)
916                 return -1;
917
918         req->type = PIPELINE_MSG_REQ_CUSTOM;
919         req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL;
920         memcpy(&req->key, key, sizeof(*key));
921
922         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
923         if (rsp == NULL)
924                 return -1;
925
926         /* Read response */
927         if (rsp->status || !rsp->key_found) {
928                 app_msg_free(app, rsp);
929                 return -1;
930         }
931
932         /* Remove entry */
933         TAILQ_REMOVE(&p->arp_entries, entry, node);
934         p->n_arp_entries--;
935         rte_free(entry);
936
937         /* Free response */
938         app_msg_free(app, rsp);
939
940         return 0;
941 }
942
943 int
944 app_pipeline_routing_add_default_arp_entry(struct app_params *app,
945                 uint32_t pipeline_id,
946                 uint32_t port_id)
947 {
948         struct pipeline_routing *p;
949
950         struct pipeline_routing_arp_add_default_msg_req *req;
951         struct pipeline_routing_arp_add_default_msg_rsp *rsp;
952
953         /* Check input arguments */
954         if (app == NULL)
955                 return -1;
956
957         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
958         if (p == NULL)
959                 return -1;
960
961         if (port_id >= p->n_ports_out)
962                 return -1;
963
964         /* Allocate and write request */
965         req = app_msg_alloc(app);
966         if (req == NULL)
967                 return -1;
968
969         req->type = PIPELINE_MSG_REQ_CUSTOM;
970         req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT;
971         req->port_id = port_id;
972
973         /* Send request and wait for response */
974         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
975         if (rsp == NULL)
976                 return -1;
977
978         /* Read response and write entry */
979         if (rsp->status || rsp->entry_ptr == NULL) {
980                 app_msg_free(app, rsp);
981                 return -1;
982         }
983
984         p->default_arp_entry_port_id = port_id;
985         p->default_arp_entry_ptr = rsp->entry_ptr;
986
987         /* Commit entry */
988         p->default_arp_entry_present = 1;
989
990         /* Free response */
991         app_msg_free(app, rsp);
992
993         return 0;
994 }
995
996 int
997 app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
998         uint32_t pipeline_id)
999 {
1000         struct pipeline_routing *p;
1001
1002         struct pipeline_routing_arp_delete_default_msg_req *req;
1003         struct pipeline_routing_arp_delete_default_msg_rsp *rsp;
1004
1005         /* Check input arguments */
1006         if (app == NULL)
1007                 return -1;
1008
1009         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
1010         if (p == NULL)
1011                 return -EINVAL;
1012
1013         /* Allocate and write request */
1014         req = app_msg_alloc(app);
1015         if (req == NULL)
1016                 return -ENOMEM;
1017
1018         req->type = PIPELINE_MSG_REQ_CUSTOM;
1019         req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT;
1020
1021         /* Send request and wait for response */
1022         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
1023         if (rsp == NULL)
1024                 return -ETIMEDOUT;
1025
1026         /* Read response and write entry */
1027         if (rsp->status) {
1028                 app_msg_free(app, rsp);
1029                 return rsp->status;
1030         }
1031
1032         /* Commit entry */
1033         p->default_arp_entry_present = 0;
1034
1035         /* Free response */
1036         app_msg_free(app, rsp);
1037
1038         return 0;
1039 }
1040
1041 int
1042 app_pipeline_routing_set_macaddr(struct app_params *app,
1043         uint32_t pipeline_id)
1044 {
1045         struct app_pipeline_params *p;
1046         struct pipeline_routing_set_macaddr_msg_req *req;
1047         struct pipeline_routing_set_macaddr_msg_rsp *rsp;
1048         uint32_t port_id;
1049
1050         /* Check input arguments */
1051         if (app == NULL)
1052                 return -EINVAL;
1053
1054         APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
1055         if (p == NULL)
1056                 return -EINVAL;
1057
1058         /* Allocate and write request */
1059         req = app_msg_alloc(app);
1060         if (req == NULL)
1061                 return -ENOMEM;
1062
1063         req->type = PIPELINE_MSG_REQ_CUSTOM;
1064         req->subtype = PIPELINE_ROUTING_MSG_REQ_SET_MACADDR;
1065
1066         memset(req->macaddr, 0, sizeof(req->macaddr));
1067         for (port_id = 0; port_id < p->n_pktq_out; port_id++) {
1068                 struct app_link_params *link;
1069
1070                 link = app_pipeline_track_pktq_out_to_link(app,
1071                         pipeline_id,
1072                         port_id);
1073                 if (link)
1074                         req->macaddr[port_id] = link->mac_addr;
1075         }
1076
1077         /* Send request and wait for response */
1078         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
1079         if (rsp == NULL)
1080                 return -ETIMEDOUT;
1081
1082         /* Read response and write entry */
1083         if (rsp->status) {
1084                 app_msg_free(app, rsp);
1085                 return rsp->status;
1086         }
1087
1088         /* Free response */
1089         app_msg_free(app, rsp);
1090
1091         return 0;
1092 }
1093
1094 /*
1095  * route
1096  *
1097  * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
1098  *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
1099  *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
1100  *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
1101  *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
1102  *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
1103  *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
1104  *
1105  * route add default:
1106  *    p <pipelineid> route add default <portid>
1107  *
1108  * route del:
1109  *    p <pipelineid> route del <ipaddr> <depth>
1110  *
1111  * route del default:
1112  *    p <pipelineid> route del default
1113  *
1114  * route ls:
1115  *    p <pipelineid> route ls
1116  */
1117
1118 struct cmd_route_result {
1119         cmdline_fixed_string_t p_string;
1120         uint32_t p;
1121         cmdline_fixed_string_t route_string;
1122         cmdline_multi_string_t multi_string;
1123 };
1124
1125 static void
1126 cmd_route_parsed(
1127         void *parsed_result,
1128         __rte_unused struct cmdline *cl,
1129         void *data)
1130 {
1131         struct cmd_route_result *params = parsed_result;
1132         struct app_params *app = data;
1133
1134         char *tokens[16];
1135         uint32_t n_tokens = RTE_DIM(tokens);
1136         int status;
1137
1138         status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
1139         if (status != 0) {
1140                 printf(CMD_MSG_TOO_MANY_ARGS, "route");
1141                 return;
1142         }
1143
1144         /* route add */
1145         if ((n_tokens >= 2) &&
1146                 (strcmp(tokens[0], "add") == 0) &&
1147                 strcmp(tokens[1], "default")) {
1148                 struct pipeline_routing_route_key key;
1149                 struct pipeline_routing_route_data route_data;
1150                 struct in_addr ipv4, nh_ipv4;
1151                 struct ether_addr mac_addr;
1152                 uint32_t depth, port_id, svlan, cvlan, i;
1153                 uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
1154                 uint32_t n_labels = RTE_DIM(mpls_labels);
1155
1156                 memset(&key, 0, sizeof(key));
1157                 memset(&route_data, 0, sizeof(route_data));
1158
1159                 if (n_tokens < 7) {
1160                         printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
1161                         return;
1162                 }
1163
1164                 if (parse_ipv4_addr(tokens[1], &ipv4)) {
1165                         printf(CMD_MSG_INVALID_ARG, "ipaddr");
1166                         return;
1167                 }
1168
1169                 if (parser_read_uint32(&depth, tokens[2])) {
1170                         printf(CMD_MSG_INVALID_ARG, "depth");
1171                         return;
1172                 }
1173
1174                 if (strcmp(tokens[3], "port")) {
1175                         printf(CMD_MSG_ARG_NOT_FOUND, "port");
1176                         return;
1177                 }
1178
1179                 if (parser_read_uint32(&port_id, tokens[4])) {
1180                         printf(CMD_MSG_INVALID_ARG, "portid");
1181                         return;
1182                 }
1183
1184                 if (strcmp(tokens[5], "ether")) {
1185                         printf(CMD_MSG_ARG_NOT_FOUND, "ether");
1186                         return;
1187                 }
1188
1189                 if (parse_mac_addr(tokens[6], &mac_addr)) {
1190                         if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
1191                                 printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
1192                                 return;
1193                         }
1194
1195                         route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
1196                 }
1197
1198                 if (n_tokens > 7) {
1199                         if (strcmp(tokens[7], "mpls") == 0) {
1200                                 if (n_tokens != 9) {
1201                                         printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
1202                                         return;
1203                                 }
1204
1205                                 if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
1206                                         printf(CMD_MSG_INVALID_ARG, "mpls labels");
1207                                         return;
1208                                 }
1209
1210                                 route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
1211                         } else if (strcmp(tokens[7], "qinq") == 0) {
1212                                 if (n_tokens != 10) {
1213                                         printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
1214                                         return;
1215                                 }
1216
1217                                 if (parser_read_uint32(&svlan, tokens[8])) {
1218                                         printf(CMD_MSG_INVALID_ARG, "svlan");
1219                                         return;
1220                                 }
1221                                 if (parser_read_uint32(&cvlan, tokens[9])) {
1222                                         printf(CMD_MSG_INVALID_ARG, "cvlan");
1223                                         return;
1224                                 }
1225
1226                                 route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
1227                         } else {
1228                                 printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
1229                                 return;
1230                         }
1231                 }
1232
1233                 switch (route_data.flags) {
1234                 case 0:
1235                         route_data.port_id = port_id;
1236                         route_data.ethernet.macaddr = mac_addr;
1237                         break;
1238
1239                 case PIPELINE_ROUTING_ROUTE_ARP:
1240                         route_data.port_id = port_id;
1241                         route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
1242                         break;
1243
1244                 case PIPELINE_ROUTING_ROUTE_MPLS:
1245                         route_data.port_id = port_id;
1246                         route_data.ethernet.macaddr = mac_addr;
1247                         for (i = 0; i < n_labels; i++)
1248                                 route_data.l2.mpls.labels[i] = mpls_labels[i];
1249                         route_data.l2.mpls.n_labels = n_labels;
1250                         break;
1251
1252                 case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
1253                         route_data.port_id = port_id;
1254                         route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
1255                         for (i = 0; i < n_labels; i++)
1256                                 route_data.l2.mpls.labels[i] = mpls_labels[i];
1257                         route_data.l2.mpls.n_labels = n_labels;
1258                         break;
1259
1260                 case PIPELINE_ROUTING_ROUTE_QINQ:
1261                         route_data.port_id = port_id;
1262                         route_data.ethernet.macaddr = mac_addr;
1263                         route_data.l2.qinq.svlan = svlan;
1264                         route_data.l2.qinq.cvlan = cvlan;
1265                         break;
1266
1267                 case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
1268                 default:
1269                         route_data.port_id = port_id;
1270                         route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
1271                         route_data.l2.qinq.svlan = svlan;
1272                         route_data.l2.qinq.cvlan = cvlan;
1273                         break;
1274                 }
1275
1276                 key.type = PIPELINE_ROUTING_ROUTE_IPV4;
1277                 key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
1278                 key.key.ipv4.depth = depth;
1279
1280                 status = app_pipeline_routing_add_route(app,
1281                         params->p,
1282                         &key,
1283                         &route_data);
1284                 if (status != 0)
1285                         printf(CMD_MSG_FAIL, "route add");
1286
1287                 return;
1288         } /* route add */
1289
1290         /* route add default */
1291         if ((n_tokens >= 2) &&
1292                 (strcmp(tokens[0], "add") == 0) &&
1293                 (strcmp(tokens[1], "default") == 0)) {
1294                 uint32_t port_id;
1295
1296                 if (n_tokens != 3) {
1297                         printf(CMD_MSG_MISMATCH_ARGS, "route add default");
1298                         return;
1299                 }
1300
1301                 if (parser_read_uint32(&port_id, tokens[2])) {
1302                         printf(CMD_MSG_INVALID_ARG, "portid");
1303                         return;
1304                 }
1305
1306                 status = app_pipeline_routing_add_default_route(app,
1307                         params->p,
1308                         port_id);
1309                 if (status != 0)
1310                         printf(CMD_MSG_FAIL, "route add default");
1311
1312                 return;
1313         } /* route add default */
1314
1315         /* route del*/
1316         if ((n_tokens >= 2) &&
1317                 (strcmp(tokens[0], "del") == 0) &&
1318                 strcmp(tokens[1], "default")) {
1319                 struct pipeline_routing_route_key key;
1320                 struct in_addr ipv4;
1321                 uint32_t depth;
1322
1323                 memset(&key, 0, sizeof(key));
1324
1325                 if (n_tokens != 3) {
1326                         printf(CMD_MSG_MISMATCH_ARGS, "route del");
1327                         return;
1328                 }
1329
1330                 if (parse_ipv4_addr(tokens[1], &ipv4)) {
1331                         printf(CMD_MSG_INVALID_ARG, "ipaddr");
1332                         return;
1333                 }
1334
1335                 if (parser_read_uint32(&depth, tokens[2])) {
1336                         printf(CMD_MSG_INVALID_ARG, "depth");
1337                         return;
1338                 }
1339
1340                 key.type = PIPELINE_ROUTING_ROUTE_IPV4;
1341                 key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
1342                 key.key.ipv4.depth = depth;
1343
1344                 status = app_pipeline_routing_delete_route(app, params->p, &key);
1345                 if (status != 0)
1346                         printf(CMD_MSG_FAIL, "route del");
1347
1348                 return;
1349         } /* route del */
1350
1351         /* route del default */
1352         if ((n_tokens >= 2) &&
1353                 (strcmp(tokens[0], "del") == 0) &&
1354                 (strcmp(tokens[1], "default") == 0)) {
1355                 if (n_tokens != 2) {
1356                         printf(CMD_MSG_MISMATCH_ARGS, "route del default");
1357                         return;
1358                 }
1359
1360                 status = app_pipeline_routing_delete_default_route(app,
1361                         params->p);
1362                 if (status != 0)
1363                         printf(CMD_MSG_FAIL, "route del default");
1364
1365                 return;
1366         } /* route del default */
1367
1368         /* route ls */
1369         if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
1370                 if (n_tokens != 1) {
1371                         printf(CMD_MSG_MISMATCH_ARGS, "route ls");
1372                         return;
1373                 }
1374
1375                 status = app_pipeline_routing_route_ls(app, params->p);
1376                 if (status != 0)
1377                         printf(CMD_MSG_FAIL, "route ls");
1378
1379                 return;
1380         } /* route ls */
1381
1382         printf(CMD_MSG_MISMATCH_ARGS, "route");
1383 }
1384
1385 static cmdline_parse_token_string_t cmd_route_p_string =
1386         TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
1387
1388 static cmdline_parse_token_num_t cmd_route_p =
1389         TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
1390
1391 static cmdline_parse_token_string_t cmd_route_route_string =
1392         TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
1393
1394 static cmdline_parse_token_string_t cmd_route_multi_string =
1395         TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
1396         TOKEN_STRING_MULTI);
1397
1398 static cmdline_parse_inst_t cmd_route = {
1399         .f = cmd_route_parsed,
1400         .data = NULL,
1401         .help_str = "route add / add default / del / del default / ls",
1402         .tokens = {
1403                 (void *)&cmd_route_p_string,
1404                 (void *)&cmd_route_p,
1405                 (void *)&cmd_route_route_string,
1406                 (void *)&cmd_route_multi_string,
1407                 NULL,
1408         },
1409 };
1410
1411 /*
1412  * arp
1413  *
1414  * arp add:
1415  *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
1416  *
1417  * arp add default:
1418  *    p <pipelineid> arp add default <portid>
1419  *
1420  * arp del:
1421  *    p <pipelineid> arp del <portid> <ipaddr>
1422  *
1423  * arp del default:
1424  *    p <pipelineid> arp del default
1425  *
1426  * arp ls:
1427  *    p <pipelineid> arp ls
1428  */
1429
1430 struct cmd_arp_result {
1431         cmdline_fixed_string_t p_string;
1432         uint32_t p;
1433         cmdline_fixed_string_t arp_string;
1434         cmdline_multi_string_t multi_string;
1435 };
1436
1437 static void
1438 cmd_arp_parsed(
1439         void *parsed_result,
1440         __rte_unused struct cmdline *cl,
1441         void *data)
1442 {
1443         struct cmd_arp_result *params = parsed_result;
1444         struct app_params *app = data;
1445
1446         char *tokens[16];
1447         uint32_t n_tokens = RTE_DIM(tokens);
1448         int status;
1449
1450         status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
1451         if (status != 0) {
1452                 printf(CMD_MSG_TOO_MANY_ARGS, "arp");
1453                 return;
1454         }
1455
1456         /* arp add */
1457         if ((n_tokens >= 2) &&
1458                 (strcmp(tokens[0], "add") == 0) &&
1459                 strcmp(tokens[1], "default")) {
1460                 struct pipeline_routing_arp_key key;
1461                 struct in_addr ipv4;
1462                 struct ether_addr mac_addr;
1463                 uint32_t port_id;
1464
1465                 memset(&key, 0, sizeof(key));
1466
1467                 if (n_tokens != 4) {
1468                         printf(CMD_MSG_MISMATCH_ARGS, "arp add");
1469                         return;
1470                 }
1471
1472                 if (parser_read_uint32(&port_id, tokens[1])) {
1473                         printf(CMD_MSG_INVALID_ARG, "portid");
1474                         return;
1475                 }
1476
1477                 if (parse_ipv4_addr(tokens[2], &ipv4)) {
1478                         printf(CMD_MSG_INVALID_ARG, "ipaddr");
1479                         return;
1480                 }
1481
1482                 if (parse_mac_addr(tokens[3], &mac_addr)) {
1483                         printf(CMD_MSG_INVALID_ARG, "macaddr");
1484                         return;
1485                 }
1486
1487                 key.type = PIPELINE_ROUTING_ARP_IPV4;
1488                 key.key.ipv4.port_id = port_id;
1489                 key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
1490
1491                 status = app_pipeline_routing_add_arp_entry(app,
1492                         params->p,
1493                         &key,
1494                         &mac_addr);
1495                 if (status != 0)
1496                         printf(CMD_MSG_FAIL, "arp add");
1497
1498                 return;
1499         } /* arp add */
1500
1501         /* arp add default */
1502         if ((n_tokens >= 2) &&
1503                 (strcmp(tokens[0], "add") == 0) &&
1504                 (strcmp(tokens[1], "default") == 0)) {
1505                 uint32_t port_id;
1506
1507                 if (n_tokens != 3) {
1508                         printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
1509                         return;
1510                 }
1511
1512                 if (parser_read_uint32(&port_id, tokens[2])) {
1513                         printf(CMD_MSG_INVALID_ARG, "portid");
1514                         return;
1515                 }
1516
1517                 status = app_pipeline_routing_add_default_arp_entry(app,
1518                         params->p,
1519                         port_id);
1520                 if (status != 0)
1521                         printf(CMD_MSG_FAIL, "arp add default");
1522
1523                 return;
1524         } /* arp add default */
1525
1526         /* arp del*/
1527         if ((n_tokens >= 2) &&
1528                 (strcmp(tokens[0], "del") == 0) &&
1529                 strcmp(tokens[1], "default")) {
1530                 struct pipeline_routing_arp_key key;
1531                 struct in_addr ipv4;
1532                 uint32_t port_id;
1533
1534                 memset(&key, 0, sizeof(key));
1535
1536                 if (n_tokens != 3) {
1537                         printf(CMD_MSG_MISMATCH_ARGS, "arp del");
1538                         return;
1539                 }
1540
1541                 if (parser_read_uint32(&port_id, tokens[1])) {
1542                         printf(CMD_MSG_INVALID_ARG, "portid");
1543                         return;
1544                 }
1545
1546                 if (parse_ipv4_addr(tokens[2], &ipv4)) {
1547                         printf(CMD_MSG_INVALID_ARG, "ipaddr");
1548                         return;
1549                 }
1550
1551                 key.type = PIPELINE_ROUTING_ARP_IPV4;
1552                 key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
1553                 key.key.ipv4.port_id = port_id;
1554
1555                 status = app_pipeline_routing_delete_arp_entry(app,
1556                         params->p,
1557                         &key);
1558                 if (status != 0)
1559                         printf(CMD_MSG_FAIL, "arp del");
1560
1561                 return;
1562         } /* arp del */
1563
1564         /* arp del default */
1565         if ((n_tokens >= 2) &&
1566                 (strcmp(tokens[0], "del") == 0) &&
1567                 (strcmp(tokens[1], "default") == 0)) {
1568                         if (n_tokens != 2) {
1569                                 printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
1570                                 return;
1571                         }
1572
1573                         status = app_pipeline_routing_delete_default_arp_entry(app,
1574                                 params->p);
1575                         if (status != 0)
1576                                 printf(CMD_MSG_FAIL, "arp del default");
1577
1578                         return;
1579         } /* arp del default */
1580
1581         /* arp ls */
1582         if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
1583                 if (n_tokens != 1) {
1584                         printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
1585                         return;
1586                 }
1587
1588                 status = app_pipeline_routing_arp_ls(app, params->p);
1589                 if (status != 0)
1590                         printf(CMD_MSG_FAIL, "arp ls");
1591
1592                 return;
1593         } /* arp ls */
1594
1595         printf(CMD_MSG_FAIL, "arp");
1596 }
1597
1598 static cmdline_parse_token_string_t cmd_arp_p_string =
1599         TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
1600
1601 static cmdline_parse_token_num_t cmd_arp_p =
1602         TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
1603
1604 static cmdline_parse_token_string_t cmd_arp_arp_string =
1605         TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
1606
1607 static cmdline_parse_token_string_t cmd_arp_multi_string =
1608         TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
1609         TOKEN_STRING_MULTI);
1610
1611 static cmdline_parse_inst_t cmd_arp = {
1612         .f = cmd_arp_parsed,
1613         .data = NULL,
1614         .help_str = "arp add / add default / del / del default / ls",
1615         .tokens = {
1616                 (void *)&cmd_arp_p_string,
1617                 (void *)&cmd_arp_p,
1618                 (void *)&cmd_arp_arp_string,
1619                 (void *)&cmd_arp_multi_string,
1620                 NULL,
1621         },
1622 };
1623
1624 static cmdline_parse_ctx_t pipeline_cmds[] = {
1625         (cmdline_parse_inst_t *)&cmd_route,
1626         (cmdline_parse_inst_t *)&cmd_arp,
1627         NULL,
1628 };
1629
1630 static struct pipeline_fe_ops pipeline_routing_fe_ops = {
1631         .f_init = app_pipeline_routing_init,
1632         .f_post_init = app_pipeline_routing_post_init,
1633         .f_free = app_pipeline_routing_free,
1634         .f_track = app_pipeline_track_default,
1635         .cmds = pipeline_cmds,
1636 };
1637
1638 struct pipeline_type pipeline_routing = {
1639         .name = "ROUTING",
1640         .be_ops = &pipeline_routing_be_ops,
1641         .fe_ops = &pipeline_routing_fe_ops,
1642 };