ip: add support for buffer offload metadata in ip midchain
[vpp.git] / src / vnet / ip / ip_test.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2021 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <vat/vat.h>
19 #include <vlibapi/api.h>
20 #include <vlibmemory/api.h>
21 #include <vppinfra/error.h>
22 #include <vpp/api/types.h>
23 #include <vnet/mpls/packet.h>
24 #include <vnet/ip/ip_types_api.h>
25
26 #define __plugin_msg_base ip_test_main.msg_id_base
27 #include <vlibapi/vat_helper_macros.h>
28
29 /* Declare message IDs */
30 #include <vnet/format_fns.h>
31 #include <vnet/ip/ip.api_enum.h>
32 #include <vnet/ip/ip.api_types.h>
33 #include <vlibmemory/vlib.api_types.h>
34
35 #define vl_endianfun /* define message structures */
36 #include <vnet/ip/ip.api.h>
37 #undef vl_endianfun
38
39 #define vl_calcsizefun
40 #include <vnet/ip/ip.api.h>
41 #undef vl_calcsizefun
42
43 typedef struct
44 {
45   /* API message ID base */
46   u16 msg_id_base;
47   vat_main_t *vat_main;
48 } ip_test_main_t;
49
50 static ip_test_main_t ip_test_main;
51
52 static int
53 api_ip_route_add_del_v2 (vat_main_t *vam)
54 {
55   return -1;
56 }
57
58 static void
59 set_ip4_address (vl_api_address_t *a, u32 v)
60 {
61   if (a->af == ADDRESS_IP4)
62     {
63       ip4_address_t *i = (ip4_address_t *) &a->un.ip4;
64       i->as_u32 = v;
65     }
66 }
67
68 static void
69 increment_v4_address (vl_api_ip4_address_t *i)
70 {
71   ip4_address_t *a = (ip4_address_t *) i;
72   u32 v;
73
74   v = ntohl (a->as_u32) + 1;
75   a->as_u32 = ntohl (v);
76 }
77
78 static void
79 increment_v6_address (vl_api_ip6_address_t *i)
80 {
81   ip6_address_t *a = (ip6_address_t *) i;
82   u64 v0, v1;
83
84   v0 = clib_net_to_host_u64 (a->as_u64[0]);
85   v1 = clib_net_to_host_u64 (a->as_u64[1]);
86
87   v1 += 1;
88   if (v1 == 0)
89     v0 += 1;
90   a->as_u64[0] = clib_net_to_host_u64 (v0);
91   a->as_u64[1] = clib_net_to_host_u64 (v1);
92 }
93
94 static void
95 increment_address (vl_api_address_t *a)
96 {
97   if (a->af == ADDRESS_IP4)
98     increment_v4_address (&a->un.ip4);
99   else if (a->af == ADDRESS_IP6)
100     increment_v6_address (&a->un.ip6);
101 }
102
103 static uword
104 unformat_fib_path (unformat_input_t *input, va_list *args)
105 {
106   vat_main_t *vam = va_arg (*args, vat_main_t *);
107   vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t *);
108   u32 weight, preference;
109   mpls_label_t out_label;
110
111   clib_memset (path, 0, sizeof (*path));
112   path->weight = 1;
113   path->sw_if_index = ~0;
114   path->rpf_id = ~0;
115   path->n_labels = 0;
116
117   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
118     {
119       if (unformat (input, "%U %U", unformat_vl_api_ip4_address,
120                     &path->nh.address.ip4, api_unformat_sw_if_index, vam,
121                     &path->sw_if_index))
122         {
123           path->proto = FIB_API_PATH_NH_PROTO_IP4;
124         }
125       else if (unformat (input, "%U %U", unformat_vl_api_ip6_address,
126                          &path->nh.address.ip6, api_unformat_sw_if_index, vam,
127                          &path->sw_if_index))
128         {
129           path->proto = FIB_API_PATH_NH_PROTO_IP6;
130         }
131       else if (unformat (input, "weight %u", &weight))
132         {
133           path->weight = weight;
134         }
135       else if (unformat (input, "preference %u", &preference))
136         {
137           path->preference = preference;
138         }
139       else if (unformat (input, "%U next-hop-table %d",
140                          unformat_vl_api_ip4_address, &path->nh.address.ip4,
141                          &path->table_id))
142         {
143           path->proto = FIB_API_PATH_NH_PROTO_IP4;
144         }
145       else if (unformat (input, "%U next-hop-table %d",
146                          unformat_vl_api_ip6_address, &path->nh.address.ip6,
147                          &path->table_id))
148         {
149           path->proto = FIB_API_PATH_NH_PROTO_IP6;
150         }
151       else if (unformat (input, "%U", unformat_vl_api_ip4_address,
152                          &path->nh.address.ip4))
153         {
154           /*
155            * the recursive next-hops are by default in the default table
156            */
157           path->table_id = 0;
158           path->sw_if_index = ~0;
159           path->proto = FIB_API_PATH_NH_PROTO_IP4;
160         }
161       else if (unformat (input, "%U", unformat_vl_api_ip6_address,
162                          &path->nh.address.ip6))
163         {
164           /*
165            * the recursive next-hops are by default in the default table
166            */
167           path->table_id = 0;
168           path->sw_if_index = ~0;
169           path->proto = FIB_API_PATH_NH_PROTO_IP6;
170         }
171       else if (unformat (input, "resolve-via-host"))
172         {
173           path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_HOST;
174         }
175       else if (unformat (input, "resolve-via-attached"))
176         {
177           path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED;
178         }
179       else if (unformat (input, "ip4-lookup-in-table %d", &path->table_id))
180         {
181           path->type = FIB_API_PATH_TYPE_LOCAL;
182           path->sw_if_index = ~0;
183           path->proto = FIB_API_PATH_NH_PROTO_IP4;
184         }
185       else if (unformat (input, "ip6-lookup-in-table %d", &path->table_id))
186         {
187           path->type = FIB_API_PATH_TYPE_LOCAL;
188           path->sw_if_index = ~0;
189           path->proto = FIB_API_PATH_NH_PROTO_IP6;
190         }
191       else if (unformat (input, "sw_if_index %d", &path->sw_if_index))
192         ;
193       else if (unformat (input, "via-label %d", &path->nh.via_label))
194         {
195           path->proto = FIB_API_PATH_NH_PROTO_MPLS;
196           path->sw_if_index = ~0;
197         }
198       else if (unformat (input, "l2-input-on %d", &path->sw_if_index))
199         {
200           path->proto = FIB_API_PATH_NH_PROTO_ETHERNET;
201           path->type = FIB_API_PATH_TYPE_INTERFACE_RX;
202         }
203       else if (unformat (input, "local"))
204         {
205           path->type = FIB_API_PATH_TYPE_LOCAL;
206         }
207       else if (unformat (input, "out-labels"))
208         {
209           while (unformat (input, "%d", &out_label))
210             {
211               path->label_stack[path->n_labels].label = out_label;
212               path->label_stack[path->n_labels].is_uniform = 0;
213               path->label_stack[path->n_labels].ttl = 64;
214               path->n_labels++;
215             }
216         }
217       else if (unformat (input, "via"))
218         {
219           /* new path, back up and return */
220           unformat_put_input (input);
221           unformat_put_input (input);
222           unformat_put_input (input);
223           unformat_put_input (input);
224           break;
225         }
226       else
227         {
228           return (0);
229         }
230     }
231
232   path->proto = ntohl (path->proto);
233   path->type = ntohl (path->type);
234   path->flags = ntohl (path->flags);
235   path->table_id = ntohl (path->table_id);
236   path->sw_if_index = ntohl (path->sw_if_index);
237
238   return (1);
239 }
240
241 static int
242 api_ip_route_add_del (vat_main_t *vam)
243 {
244   unformat_input_t *i = vam->input;
245   vl_api_ip_route_add_del_t *mp;
246   u32 vrf_id = 0;
247   u8 is_add = 1;
248   u8 is_multipath = 0;
249   u8 prefix_set = 0;
250   u8 path_count = 0;
251   vl_api_prefix_t pfx = {};
252   vl_api_fib_path_t paths[8];
253   int count = 1;
254   int j;
255   f64 before = 0;
256   u32 random_add_del = 0;
257   u32 *random_vector = 0;
258   u32 random_seed = 0xdeaddabe;
259
260   /* Parse args required to build the message */
261   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
262     {
263       if (unformat (i, "%U", unformat_vl_api_prefix, &pfx))
264         prefix_set = 1;
265       else if (unformat (i, "del"))
266         is_add = 0;
267       else if (unformat (i, "add"))
268         is_add = 1;
269       else if (unformat (i, "vrf %d", &vrf_id))
270         ;
271       else if (unformat (i, "count %d", &count))
272         ;
273       else if (unformat (i, "random"))
274         random_add_del = 1;
275       else if (unformat (i, "multipath"))
276         is_multipath = 1;
277       else if (unformat (i, "seed %d", &random_seed))
278         ;
279       else if (unformat (i, "via %U", unformat_fib_path, vam,
280                          &paths[path_count]))
281         {
282           path_count++;
283           if (8 == path_count)
284             {
285               errmsg ("max 8 paths");
286               return -99;
287             }
288         }
289       else
290         {
291           clib_warning ("parse error '%U'", format_unformat_error, i);
292           return -99;
293         }
294     }
295
296   if (!path_count)
297     {
298       errmsg ("specify a path; via ...");
299       return -99;
300     }
301   if (prefix_set == 0)
302     {
303       errmsg ("missing prefix");
304       return -99;
305     }
306
307   /* Generate a pile of unique, random routes */
308   if (random_add_del)
309     {
310       ip4_address_t *i = (ip4_address_t *) &paths[0].nh.address.ip4;
311       u32 this_random_address;
312       uword *random_hash;
313
314       random_hash = hash_create (count, sizeof (uword));
315
316       hash_set (random_hash, i->as_u32, 1);
317       for (j = 0; j <= count; j++)
318         {
319           do
320             {
321               this_random_address = random_u32 (&random_seed);
322               this_random_address = clib_host_to_net_u32 (this_random_address);
323             }
324           while (hash_get (random_hash, this_random_address));
325           vec_add1 (random_vector, this_random_address);
326           hash_set (random_hash, this_random_address, 1);
327         }
328       hash_free (random_hash);
329       set_ip4_address (&pfx.address, random_vector[0]);
330     }
331
332   if (count > 1)
333     {
334       /* Turn on async mode */
335       vam->async_mode = 1;
336       vam->async_errors = 0;
337       before = vat_time_now (vam);
338     }
339
340   for (j = 0; j < count; j++)
341     {
342       /* Construct the API message */
343       M2 (IP_ROUTE_ADD_DEL, mp, sizeof (vl_api_fib_path_t) * path_count);
344
345       mp->is_add = is_add;
346       mp->is_multipath = is_multipath;
347
348       clib_memcpy (&mp->route.prefix, &pfx, sizeof (pfx));
349       mp->route.table_id = ntohl (vrf_id);
350       mp->route.n_paths = path_count;
351
352       clib_memcpy (&mp->route.paths, &paths, sizeof (paths[0]) * path_count);
353
354       if (random_add_del)
355         set_ip4_address (&pfx.address, random_vector[j + 1]);
356       else
357         increment_address (&pfx.address);
358       /* send it... */
359       S (mp);
360       /* If we receive SIGTERM, stop now... */
361       if (vam->do_exit)
362         break;
363     }
364
365   /* When testing multiple add/del ops, use a control-ping to sync */
366   if (count > 1)
367     {
368       vl_api_control_ping_t *mp_ping;
369       f64 after;
370       f64 timeout;
371
372       /* Shut off async mode */
373       vam->async_mode = 0;
374
375       PING (&ip_test_main, mp_ping);
376       S (mp_ping);
377
378       timeout = vat_time_now (vam) + 1.0;
379       while (vat_time_now (vam) < timeout)
380         if (vam->result_ready == 1)
381           goto out;
382       vam->retval = -99;
383
384     out:
385       if (vam->retval == -99)
386         errmsg ("timeout");
387
388       if (vam->async_errors > 0)
389         {
390           errmsg ("%d asynchronous errors", vam->async_errors);
391           vam->retval = -98;
392         }
393       vam->async_errors = 0;
394       after = vat_time_now (vam);
395
396       /* slim chance, but we might have eaten SIGTERM on the first iteration */
397       if (j > 0)
398         count = j;
399
400       print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", count,
401              after - before, count / (after - before));
402     }
403   else
404     {
405       int ret;
406
407       /* Wait for a reply... */
408       W (ret);
409       return ret;
410     }
411
412   /* Return the good/bad news */
413   return (vam->retval);
414 }
415
416 static int
417 api_ip_table_add_del (vat_main_t *vam)
418 {
419   unformat_input_t *i = vam->input;
420   vl_api_ip_table_add_del_t *mp;
421   u32 table_id = ~0;
422   u8 is_ipv6 = 0;
423   u8 is_add = 1;
424   int ret = 0;
425
426   /* Parse args required to build the message */
427   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
428     {
429       if (unformat (i, "ipv6"))
430         is_ipv6 = 1;
431       else if (unformat (i, "del"))
432         is_add = 0;
433       else if (unformat (i, "add"))
434         is_add = 1;
435       else if (unformat (i, "table %d", &table_id))
436         ;
437       else
438         {
439           clib_warning ("parse error '%U'", format_unformat_error, i);
440           return -99;
441         }
442     }
443
444   if (~0 == table_id)
445     {
446       errmsg ("missing table-ID");
447       return -99;
448     }
449
450   /* Construct the API message */
451   M (IP_TABLE_ADD_DEL, mp);
452
453   mp->table.table_id = ntohl (table_id);
454   mp->table.is_ip6 = is_ipv6;
455   mp->is_add = is_add;
456
457   /* send it... */
458   S (mp);
459
460   /* Wait for a reply... */
461   W (ret);
462
463   return ret;
464 }
465
466 static int
467 api_ip_table_replace_begin (vat_main_t *vam)
468 {
469   unformat_input_t *i = vam->input;
470   vl_api_ip_table_replace_begin_t *mp;
471   u32 table_id = 0;
472   u8 is_ipv6 = 0;
473
474   int ret;
475   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
476     {
477       if (unformat (i, "table %d", &table_id))
478         ;
479       else if (unformat (i, "ipv6"))
480         is_ipv6 = 1;
481       else
482         {
483           clib_warning ("parse error '%U'", format_unformat_error, i);
484           return -99;
485         }
486     }
487
488   M (IP_TABLE_REPLACE_BEGIN, mp);
489
490   mp->table.table_id = ntohl (table_id);
491   mp->table.is_ip6 = is_ipv6;
492
493   S (mp);
494   W (ret);
495   return ret;
496 }
497
498 static int
499 api_ip_table_flush (vat_main_t *vam)
500 {
501   unformat_input_t *i = vam->input;
502   vl_api_ip_table_flush_t *mp;
503   u32 table_id = 0;
504   u8 is_ipv6 = 0;
505
506   int ret;
507   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
508     {
509       if (unformat (i, "table %d", &table_id))
510         ;
511       else if (unformat (i, "ipv6"))
512         is_ipv6 = 1;
513       else
514         {
515           clib_warning ("parse error '%U'", format_unformat_error, i);
516           return -99;
517         }
518     }
519
520   M (IP_TABLE_FLUSH, mp);
521
522   mp->table.table_id = ntohl (table_id);
523   mp->table.is_ip6 = is_ipv6;
524
525   S (mp);
526   W (ret);
527   return ret;
528 }
529
530 static int
531 api_ip_table_allocate (vat_main_t *vam)
532 {
533   return -1;
534 }
535
536 static void
537 vl_api_ip_table_allocate_reply_t_handler (vl_api_ip_table_allocate_reply_t *mp)
538 {
539 }
540
541 static void
542 vl_api_ip_route_add_del_v2_reply_t_handler (
543   vl_api_ip_route_add_del_v2_reply_t *mp)
544 {
545 }
546
547 static void
548 vl_api_ip_route_details_t_handler (vl_api_ip_route_details_t *mp)
549 {
550 }
551
552 static void
553 vl_api_ip_route_v2_details_t_handler (vl_api_ip_route_v2_details_t *mp)
554 {
555 }
556
557 static void
558 vl_api_ip_route_add_del_reply_t_handler (vl_api_ip_route_add_del_reply_t *mp)
559 {
560   vat_main_t *vam = ip_test_main.vat_main;
561   vam->result_ready = 1;
562 }
563
564 static void
565 vl_api_ip_route_lookup_reply_t_handler (vl_api_ip_route_lookup_reply_t *mp)
566 {
567 }
568
569 static void
570 vl_api_ip_route_lookup_v2_reply_t_handler (
571   vl_api_ip_route_lookup_v2_reply_t *mp)
572 {
573 }
574
575 static int
576 api_set_ip_flow_hash_router_id (vat_main_t *vat)
577 {
578   return -1;
579 }
580
581 static int
582 api_ip_route_lookup (vat_main_t *vat)
583 {
584   return -1;
585 }
586
587 static int
588 api_ip_route_lookup_v2 (vat_main_t *vat)
589 {
590   return -1;
591 }
592
593 static int
594 api_set_ip_flow_hash (vat_main_t *vam)
595 {
596   unformat_input_t *i = vam->input;
597   vl_api_set_ip_flow_hash_t *mp;
598   u32 vrf_id = 0;
599   u8 is_ipv6 = 0;
600   u8 vrf_id_set = 0;
601   u8 src = 0;
602   u8 dst = 0;
603   u8 sport = 0;
604   u8 dport = 0;
605   u8 proto = 0;
606   u8 reverse = 0;
607   int ret;
608
609   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
610     {
611       if (unformat (i, "vrf %d", &vrf_id))
612         vrf_id_set = 1;
613       else if (unformat (i, "ipv6"))
614         is_ipv6 = 1;
615       else if (unformat (i, "src"))
616         src = 1;
617       else if (unformat (i, "dst"))
618         dst = 1;
619       else if (unformat (i, "sport"))
620         sport = 1;
621       else if (unformat (i, "dport"))
622         dport = 1;
623       else if (unformat (i, "proto"))
624         proto = 1;
625       else if (unformat (i, "reverse"))
626         reverse = 1;
627
628       else
629         {
630           clib_warning ("parse error '%U'", format_unformat_error, i);
631           return -99;
632         }
633     }
634
635   if (vrf_id_set == 0)
636     {
637       errmsg ("missing vrf id");
638       return -99;
639     }
640
641   M (SET_IP_FLOW_HASH, mp);
642   mp->src = src;
643   mp->dst = dst;
644   mp->sport = sport;
645   mp->dport = dport;
646   mp->proto = proto;
647   mp->reverse = reverse;
648   mp->vrf_id = ntohl (vrf_id);
649   mp->is_ipv6 = is_ipv6;
650
651   S (mp);
652   W (ret);
653   return ret;
654 }
655
656 static int
657 api_mfib_signal_dump (vat_main_t *vat)
658 {
659   return -1;
660 }
661
662 static int
663 api_ip_punt_police (vat_main_t *vat)
664 {
665   return -1;
666 }
667
668 static int
669 api_ip_punt_redirect (vat_main_t *vat)
670 {
671   return -1;
672 }
673
674 static int
675 api_add_del_ip_punt_redirect_v2 (vat_main_t *vat)
676 {
677   return -1;
678 }
679
680 static int
681 api_ip_punt_redirect_dump (vat_main_t *vat)
682 {
683   return -1;
684 }
685
686 static void
687 vl_api_ip_punt_redirect_details_t_handler (
688   vl_api_ip_punt_redirect_details_t *mp)
689 {
690   /**/
691 }
692
693 static int
694 api_ip_punt_redirect_v2_dump (vat_main_t *vat)
695 {
696   return -1;
697 }
698
699 static void
700 vl_api_ip_punt_redirect_v2_details_t_handler (
701   vl_api_ip_punt_redirect_v2_details_t *mp)
702 {
703   /**/
704 }
705
706 static int
707 api_ip_address_dump (vat_main_t *vam)
708 {
709   unformat_input_t *i = vam->input;
710   vl_api_ip_address_dump_t *mp;
711   vl_api_control_ping_t *mp_ping;
712   u32 sw_if_index = ~0;
713   u8 sw_if_index_set = 0;
714   u8 ipv4_set = 0;
715   u8 ipv6_set = 0;
716   int ret;
717
718   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
719     {
720       if (unformat (i, "sw_if_index %d", &sw_if_index))
721         sw_if_index_set = 1;
722       else if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
723         sw_if_index_set = 1;
724       else if (unformat (i, "ipv4"))
725         ipv4_set = 1;
726       else if (unformat (i, "ipv6"))
727         ipv6_set = 1;
728       else
729         break;
730     }
731
732   if (ipv4_set && ipv6_set)
733     {
734       errmsg ("ipv4 and ipv6 flags cannot be both set");
735       return -99;
736     }
737
738   if ((!ipv4_set) && (!ipv6_set))
739     {
740       errmsg ("no ipv4 nor ipv6 flag set");
741       return -99;
742     }
743
744   if (sw_if_index_set == 0)
745     {
746       errmsg ("missing interface name or sw_if_index");
747       return -99;
748     }
749
750   vam->current_sw_if_index = sw_if_index;
751   vam->is_ipv6 = ipv6_set;
752
753   M (IP_ADDRESS_DUMP, mp);
754   mp->sw_if_index = ntohl (sw_if_index);
755   mp->is_ipv6 = ipv6_set;
756   S (mp);
757
758   /* Use a control ping for synchronization */
759   PING (&ip_test_main, mp_ping);
760   S (mp_ping);
761
762   W (ret);
763   return ret;
764 }
765
766 static void
767 vl_api_sw_interface_ip6_get_link_local_address_reply_t_handler (
768   vl_api_sw_interface_ip6_get_link_local_address_reply_t *mp)
769 {
770 }
771
772 static int
773 api_sw_interface_ip6_set_link_local_address (vat_main_t *vam)
774 {
775   return -1;
776 }
777
778 static int
779 api_sw_interface_ip6_get_link_local_address (vat_main_t *vam)
780 {
781   return -1;
782 }
783
784 static int
785 api_ip_path_mtu_replace_end (vat_main_t *vam)
786 {
787   return -1;
788 }
789
790 static int
791 api_ioam_enable (vat_main_t *vam)
792 {
793   unformat_input_t *input = vam->input;
794   vl_api_ioam_enable_t *mp;
795   u32 id = 0;
796   int has_trace_option = 0;
797   int has_pot_option = 0;
798   int has_seqno_option = 0;
799   int has_analyse_option = 0;
800   int ret;
801
802   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
803     {
804       if (unformat (input, "trace"))
805         has_trace_option = 1;
806       else if (unformat (input, "pot"))
807         has_pot_option = 1;
808       else if (unformat (input, "seqno"))
809         has_seqno_option = 1;
810       else if (unformat (input, "analyse"))
811         has_analyse_option = 1;
812       else
813         break;
814     }
815   M (IOAM_ENABLE, mp);
816   mp->id = htons (id);
817   mp->seqno = has_seqno_option;
818   mp->analyse = has_analyse_option;
819   mp->pot_enable = has_pot_option;
820   mp->trace_enable = has_trace_option;
821
822   S (mp);
823   W (ret);
824   return ret;
825 }
826
827 static int
828 api_ip_reassembly_get (vat_main_t *vam)
829 {
830   return -1;
831 }
832
833 static int
834 api_ip_path_mtu_replace_begin (vat_main_t *vam)
835 {
836   return -1;
837 }
838
839 static int
840 api_ip_path_mtu_update (vat_main_t *vam)
841 {
842   return -1;
843 }
844
845 static int
846 api_ioam_disable (vat_main_t *vam)
847 {
848   vl_api_ioam_disable_t *mp;
849   int ret;
850
851   M (IOAM_DISABLE, mp);
852   S (mp);
853   W (ret);
854   return ret;
855 }
856
857 static int
858 api_ip_source_and_port_range_check_add_del (vat_main_t *vam)
859 {
860   unformat_input_t *input = vam->input;
861   vl_api_ip_source_and_port_range_check_add_del_t *mp;
862
863   u16 *low_ports = 0;
864   u16 *high_ports = 0;
865   u16 this_low;
866   u16 this_hi;
867   vl_api_prefix_t prefix;
868   u32 tmp, tmp2;
869   u8 prefix_set = 0;
870   u32 vrf_id = ~0;
871   u8 is_add = 1;
872   int ret;
873
874   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
875     {
876       if (unformat (input, "%U", unformat_vl_api_prefix, &prefix))
877         prefix_set = 1;
878       else if (unformat (input, "vrf %d", &vrf_id))
879         ;
880       else if (unformat (input, "del"))
881         is_add = 0;
882       else if (unformat (input, "port %d", &tmp))
883         {
884           if (tmp == 0 || tmp > 65535)
885             {
886               errmsg ("port %d out of range", tmp);
887               return -99;
888             }
889           this_low = tmp;
890           this_hi = this_low + 1;
891           vec_add1 (low_ports, this_low);
892           vec_add1 (high_ports, this_hi);
893         }
894       else if (unformat (input, "range %d - %d", &tmp, &tmp2))
895         {
896           if ((tmp > tmp2) || (tmp == 0) || (tmp2 > 65535))
897             {
898               errmsg ("incorrect range parameters");
899               return -99;
900             }
901           this_low = tmp;
902           /* Note: in debug CLI +1 is added to high before
903              passing to real fn that does "the work"
904              (ip_source_and_port_range_check_add_del).
905              This fn is a wrapper around the binary API fn a
906              control plane will call, which expects this increment
907              to have occurred. Hence letting the binary API control
908              plane fn do the increment for consistency between VAT
909              and other control planes.
910            */
911           this_hi = tmp2;
912           vec_add1 (low_ports, this_low);
913           vec_add1 (high_ports, this_hi);
914         }
915       else
916         break;
917     }
918
919   if (prefix_set == 0)
920     {
921       errmsg ("<address>/<mask> not specified");
922       return -99;
923     }
924
925   if (vrf_id == ~0)
926     {
927       errmsg ("VRF ID required, not specified");
928       return -99;
929     }
930
931   if (vrf_id == 0)
932     {
933       errmsg ("VRF ID should not be default. Should be distinct VRF for this "
934               "purpose.");
935       return -99;
936     }
937
938   if (vec_len (low_ports) == 0)
939     {
940       errmsg ("At least one port or port range required");
941       return -99;
942     }
943
944   M (IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, mp);
945
946   mp->is_add = is_add;
947
948   clib_memcpy (&mp->prefix, &prefix, sizeof (prefix));
949
950   mp->number_of_ranges = vec_len (low_ports);
951
952   clib_memcpy (mp->low_ports, low_ports, vec_len (low_ports));
953   vec_free (low_ports);
954
955   clib_memcpy (mp->high_ports, high_ports, vec_len (high_ports));
956   vec_free (high_ports);
957
958   mp->vrf_id = ntohl (vrf_id);
959
960   S (mp);
961   W (ret);
962   return ret;
963 }
964
965 static int
966 api_ip_reassembly_set (vat_main_t *vat)
967 {
968   return -1;
969 }
970
971 static int
972 api_ip_container_proxy_add_del (vat_main_t *vam)
973 {
974   vl_api_ip_container_proxy_add_del_t *mp;
975   unformat_input_t *i = vam->input;
976   u32 sw_if_index = ~0;
977   vl_api_prefix_t pfx = {};
978   u8 is_add = 1;
979   int ret;
980
981   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
982     {
983       if (unformat (i, "del"))
984         is_add = 0;
985       else if (unformat (i, "add"))
986         ;
987       if (unformat (i, "%U", unformat_vl_api_prefix, &pfx))
988         ;
989       else if (unformat (i, "sw_if_index %u", &sw_if_index))
990         ;
991       else
992         break;
993     }
994   if (sw_if_index == ~0 || pfx.len == 0)
995     {
996       errmsg ("address and sw_if_index must be set");
997       return -99;
998     }
999
1000   M (IP_CONTAINER_PROXY_ADD_DEL, mp);
1001
1002   mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
1003   mp->is_add = is_add;
1004   clib_memcpy (&mp->pfx, &pfx, sizeof (pfx));
1005
1006   S (mp);
1007   W (ret);
1008   return ret;
1009 }
1010
1011 static int
1012 api_ip_reassembly_enable_disable (vat_main_t *vat)
1013 {
1014   return -1;
1015 }
1016
1017 static int
1018 api_ip_local_reass_enable_disable (vat_main_t *vat)
1019 {
1020   return -1;
1021 }
1022
1023 static int
1024 api_ip_local_reass_get (vat_main_t *vat)
1025 {
1026   return -1;
1027 }
1028
1029 static void
1030 vl_api_ip_local_reass_get_reply_t_handler (
1031   vl_api_ip_local_reass_get_reply_t *mp)
1032 {
1033 }
1034
1035 static void
1036 vl_api_ip_reassembly_get_reply_t_handler (vl_api_ip_reassembly_get_reply_t *mp)
1037 {
1038 }
1039
1040 int
1041 api_ip_source_and_port_range_check_interface_add_del (vat_main_t *vam)
1042 {
1043   unformat_input_t *input = vam->input;
1044   vl_api_ip_source_and_port_range_check_interface_add_del_t *mp;
1045   u32 sw_if_index = ~0;
1046   int vrf_set = 0;
1047   u32 tcp_out_vrf_id = ~0, udp_out_vrf_id = ~0;
1048   u32 tcp_in_vrf_id = ~0, udp_in_vrf_id = ~0;
1049   u8 is_add = 1;
1050   int ret;
1051
1052   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1053     {
1054       if (unformat (input, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
1055         ;
1056       else if (unformat (input, "sw_if_index %d", &sw_if_index))
1057         ;
1058       else if (unformat (input, "tcp-out-vrf %d", &tcp_out_vrf_id))
1059         vrf_set = 1;
1060       else if (unformat (input, "udp-out-vrf %d", &udp_out_vrf_id))
1061         vrf_set = 1;
1062       else if (unformat (input, "tcp-in-vrf %d", &tcp_in_vrf_id))
1063         vrf_set = 1;
1064       else if (unformat (input, "udp-in-vrf %d", &udp_in_vrf_id))
1065         vrf_set = 1;
1066       else if (unformat (input, "del"))
1067         is_add = 0;
1068       else
1069         break;
1070     }
1071
1072   if (sw_if_index == ~0)
1073     {
1074       errmsg ("Interface required but not specified");
1075       return -99;
1076     }
1077
1078   if (vrf_set == 0)
1079     {
1080       errmsg ("VRF ID required but not specified");
1081       return -99;
1082     }
1083
1084   if (tcp_out_vrf_id == 0 || udp_out_vrf_id == 0 || tcp_in_vrf_id == 0 ||
1085       udp_in_vrf_id == 0)
1086     {
1087       errmsg ("VRF ID should not be default. Should be distinct VRF for this "
1088               "purpose.");
1089       return -99;
1090     }
1091
1092   /* Construct the API message */
1093   M (IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, mp);
1094
1095   mp->sw_if_index = ntohl (sw_if_index);
1096   mp->is_add = is_add;
1097   mp->tcp_out_vrf_id = ntohl (tcp_out_vrf_id);
1098   mp->udp_out_vrf_id = ntohl (udp_out_vrf_id);
1099   mp->tcp_in_vrf_id = ntohl (tcp_in_vrf_id);
1100   mp->udp_in_vrf_id = ntohl (udp_in_vrf_id);
1101
1102   /* send it... */
1103   S (mp);
1104
1105   /* Wait for a reply... */
1106   W (ret);
1107   return ret;
1108 }
1109
1110 static void
1111 vl_api_ip_container_proxy_details_t_handler (
1112   vl_api_ip_container_proxy_details_t *mp)
1113 {
1114 }
1115
1116 static int
1117 api_ip_container_proxy_dump (vat_main_t *vam)
1118 {
1119   return -1;
1120 }
1121
1122 static int
1123 api_ip_dump (vat_main_t *vam)
1124 {
1125   vl_api_ip_dump_t *mp;
1126   vl_api_control_ping_t *mp_ping;
1127   unformat_input_t *in = vam->input;
1128   int ipv4_set = 0;
1129   int ipv6_set = 0;
1130   int is_ipv6;
1131   int i;
1132   int ret;
1133
1134   while (unformat_check_input (in) != UNFORMAT_END_OF_INPUT)
1135     {
1136       if (unformat (in, "ipv4"))
1137         ipv4_set = 1;
1138       else if (unformat (in, "ipv6"))
1139         ipv6_set = 1;
1140       else
1141         break;
1142     }
1143
1144   if (ipv4_set && ipv6_set)
1145     {
1146       errmsg ("ipv4 and ipv6 flags cannot be both set");
1147       return -99;
1148     }
1149
1150   if ((!ipv4_set) && (!ipv6_set))
1151     {
1152       errmsg ("no ipv4 nor ipv6 flag set");
1153       return -99;
1154     }
1155
1156   is_ipv6 = ipv6_set;
1157   vam->is_ipv6 = is_ipv6;
1158
1159   /* free old data */
1160   for (i = 0; i < vec_len (vam->ip_details_by_sw_if_index[is_ipv6]); i++)
1161     {
1162       vec_free (vam->ip_details_by_sw_if_index[is_ipv6][i].addr);
1163     }
1164   vec_free (vam->ip_details_by_sw_if_index[is_ipv6]);
1165
1166   M (IP_DUMP, mp);
1167   mp->is_ipv6 = ipv6_set;
1168   S (mp);
1169
1170   /* Use a control ping for synchronization */
1171   PING (&ip_test_main, mp_ping);
1172   S (mp_ping);
1173
1174   W (ret);
1175   return ret;
1176 }
1177
1178 static void
1179 vl_api_mfib_signal_details_t_handler (vl_api_mfib_signal_details_t *mp)
1180 {
1181 }
1182
1183 static void
1184 vl_api_ip_mroute_details_t_handler (vl_api_ip_mroute_details_t *mp)
1185 {
1186   vat_main_t *vam = ip_test_main.vat_main;
1187   vam->result_ready = 1;
1188 }
1189
1190 static int
1191 api_ip_mroute_dump (vat_main_t *vam)
1192 {
1193   unformat_input_t *input = vam->input;
1194   vl_api_control_ping_t *mp_ping;
1195   vl_api_ip_mroute_dump_t *mp;
1196   int ret, is_ip6;
1197   u32 table_id;
1198
1199   is_ip6 = 0;
1200   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1201     {
1202       if (unformat (input, "table_id %d", &table_id))
1203         ;
1204       else if (unformat (input, "ip6"))
1205         is_ip6 = 1;
1206       else if (unformat (input, "ip4"))
1207         is_ip6 = 0;
1208       else
1209         break;
1210     }
1211   if (table_id == ~0)
1212     {
1213       errmsg ("missing table id");
1214       return -99;
1215     }
1216
1217   M (IP_MROUTE_DUMP, mp);
1218   mp->table.table_id = table_id;
1219   mp->table.is_ip6 = is_ip6;
1220   S (mp);
1221
1222   /* Use a control ping for synchronization */
1223   PING (&ip_test_main, mp_ping);
1224   S (mp_ping);
1225
1226   W (ret);
1227   return ret;
1228 }
1229
1230 static int
1231 api_sw_interface_ip6_enable_disable (vat_main_t *vam)
1232 {
1233   unformat_input_t *i = vam->input;
1234   vl_api_sw_interface_ip6_enable_disable_t *mp;
1235   u32 sw_if_index;
1236   u8 sw_if_index_set = 0;
1237   u8 enable = 0;
1238   int ret;
1239
1240   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1241     {
1242       if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
1243         sw_if_index_set = 1;
1244       else if (unformat (i, "sw_if_index %d", &sw_if_index))
1245         sw_if_index_set = 1;
1246       else if (unformat (i, "enable"))
1247         enable = 1;
1248       else if (unformat (i, "disable"))
1249         enable = 0;
1250       else
1251         {
1252           clib_warning ("parse error '%U'", format_unformat_error, i);
1253           return -99;
1254         }
1255     }
1256
1257   if (sw_if_index_set == 0)
1258     {
1259       errmsg ("missing interface name or sw_if_index");
1260       return -99;
1261     }
1262
1263   M (SW_INTERFACE_IP6_ENABLE_DISABLE, mp);
1264
1265   mp->sw_if_index = ntohl (sw_if_index);
1266   mp->enable = enable;
1267
1268   S (mp);
1269   W (ret);
1270   return ret;
1271 }
1272
1273 static int
1274 api_set_ip_flow_hash_v2 (vat_main_t *vat)
1275 {
1276   return -1;
1277 }
1278
1279 static int
1280 api_set_ip_flow_hash_v3 (vat_main_t *vat)
1281 {
1282   return -1;
1283 }
1284
1285 static int
1286 api_ip_mroute_add_del (vat_main_t *vam)
1287 {
1288   unformat_input_t *i = vam->input;
1289   u8 path_set = 0, prefix_set = 0, is_add = 1;
1290   vl_api_ip_mroute_add_del_t *mp;
1291   mfib_entry_flags_t eflags = 0;
1292   vl_api_mfib_path_t path;
1293   vl_api_mprefix_t pfx = {};
1294   u32 vrf_id = 0;
1295   int ret;
1296
1297   /* Parse args required to build the message */
1298   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1299     {
1300       if (unformat (i, "%U", unformat_vl_api_mprefix, &pfx))
1301         {
1302           prefix_set = 1;
1303           pfx.grp_address_length = htons (pfx.grp_address_length);
1304         }
1305       else if (unformat (i, "del"))
1306         is_add = 0;
1307       else if (unformat (i, "add"))
1308         is_add = 1;
1309       else if (unformat (i, "vrf %d", &vrf_id))
1310         ;
1311       else if (unformat (i, "%U", unformat_mfib_itf_flags, &path.itf_flags))
1312         path.itf_flags = htonl (path.itf_flags);
1313       else if (unformat (i, "%U", unformat_mfib_entry_flags, &eflags))
1314         ;
1315       else if (unformat (i, "via %U", unformat_fib_path, vam, &path.path))
1316         path_set = 1;
1317       else
1318         {
1319           clib_warning ("parse error '%U'", format_unformat_error, i);
1320           return -99;
1321         }
1322     }
1323
1324   if (prefix_set == 0)
1325     {
1326       errmsg ("missing addresses\n");
1327       return -99;
1328     }
1329   if (path_set == 0)
1330     {
1331       errmsg ("missing path\n");
1332       return -99;
1333     }
1334
1335   /* Construct the API message */
1336   M (IP_MROUTE_ADD_DEL, mp);
1337
1338   mp->is_add = is_add;
1339   mp->is_multipath = 1;
1340
1341   clib_memcpy (&mp->route.prefix, &pfx, sizeof (pfx));
1342   mp->route.table_id = htonl (vrf_id);
1343   mp->route.n_paths = 1;
1344   mp->route.entry_flags = htonl (eflags);
1345
1346   clib_memcpy (&mp->route.paths, &path, sizeof (path));
1347
1348   /* send it... */
1349   S (mp);
1350   /* Wait for a reply... */
1351   W (ret);
1352   return ret;
1353 }
1354
1355 static void
1356 vl_api_ip_mroute_add_del_reply_t_handler (vl_api_ip_mroute_add_del_reply_t *mp)
1357 {
1358   vat_main_t *vam = ip_test_main.vat_main;
1359   vam->result_ready = 1;
1360 }
1361
1362 static int
1363 api_ip_mtable_dump (vat_main_t *vam)
1364 {
1365   vl_api_ip_mtable_dump_t *mp;
1366   vl_api_control_ping_t *mp_ping;
1367   int ret;
1368
1369   M (IP_MTABLE_DUMP, mp);
1370   S (mp);
1371
1372   /* Use a control ping for synchronization */
1373   PING (&ip_test_main, mp_ping);
1374   S (mp_ping);
1375
1376   W (ret);
1377   return ret;
1378 }
1379
1380 static void
1381 vl_api_ip_mtable_details_t_handler (vl_api_ip_mtable_details_t *mp)
1382 {
1383   vat_main_t *vam = ip_test_main.vat_main;
1384   vam->result_ready = 1;
1385 }
1386
1387 static int
1388 api_ip_table_replace_end (vat_main_t *vam)
1389 {
1390   unformat_input_t *i = vam->input;
1391   vl_api_ip_table_replace_end_t *mp;
1392   u32 table_id = 0;
1393   u8 is_ipv6 = 0;
1394
1395   int ret;
1396   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1397     {
1398       if (unformat (i, "table %d", &table_id))
1399         ;
1400       else if (unformat (i, "ipv6"))
1401         is_ipv6 = 1;
1402       else
1403         {
1404           clib_warning ("parse error '%U'", format_unformat_error, i);
1405           return -99;
1406         }
1407     }
1408
1409   M (IP_TABLE_REPLACE_END, mp);
1410
1411   mp->table.table_id = ntohl (table_id);
1412   mp->table.is_ip6 = is_ipv6;
1413
1414   S (mp);
1415   W (ret);
1416   return ret;
1417 }
1418
1419 static int
1420 api_ip_table_dump (vat_main_t *vam)
1421 {
1422   vl_api_ip_table_dump_t *mp;
1423   vl_api_control_ping_t *mp_ping;
1424   int ret;
1425
1426   M (IP_TABLE_DUMP, mp);
1427   S (mp);
1428
1429   /* Use a control ping for synchronization */
1430   PING (&ip_test_main, mp_ping);
1431   S (mp_ping);
1432
1433   W (ret);
1434   return ret;
1435 }
1436
1437 static void
1438 vl_api_ip_table_details_t_handler (vl_api_ip_table_details_t *mp)
1439 {
1440   vat_main_t *vam = ip_test_main.vat_main;
1441
1442   fformat (vam->ofp, "%s; table-id %d, prefix %U/%d", mp->table.name,
1443            ntohl (mp->table.table_id));
1444   vam->result_ready = 1;
1445 }
1446
1447 static int
1448 api_ip_path_mtu_get (vat_main_t *vat)
1449 {
1450   return -1;
1451 }
1452
1453 static int
1454 api_ip_route_v2_dump (vat_main_t *vat)
1455 {
1456   return -1;
1457 }
1458
1459 static void
1460 vl_api_ip_path_mtu_get_reply_t_handler (vl_api_ip_path_mtu_get_reply_t *mp)
1461 {
1462 }
1463
1464 static int
1465 api_ip_route_dump (vat_main_t *vam)
1466 {
1467   unformat_input_t *input = vam->input;
1468   vl_api_ip_route_dump_t *mp;
1469   vl_api_control_ping_t *mp_ping;
1470   u32 table_id;
1471   u8 is_ip6;
1472   int ret;
1473
1474   is_ip6 = 0;
1475   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1476     {
1477       if (unformat (input, "table_id %d", &table_id))
1478         ;
1479       else if (unformat (input, "ip6"))
1480         is_ip6 = 1;
1481       else if (unformat (input, "ip4"))
1482         is_ip6 = 0;
1483       else
1484         break;
1485     }
1486   if (table_id == ~0)
1487     {
1488       errmsg ("missing table id");
1489       return -99;
1490     }
1491
1492   M (IP_ROUTE_DUMP, mp);
1493
1494   mp->table.table_id = table_id;
1495   mp->table.is_ip6 = is_ip6;
1496
1497   S (mp);
1498
1499   /* Use a control ping for synchronization */
1500   PING (&ip_test_main, mp_ping);
1501   S (mp_ping);
1502
1503   W (ret);
1504   return ret;
1505 }
1506
1507 static void
1508 vl_api_ip_address_details_t_handler (vl_api_ip_address_details_t *mp)
1509 {
1510   vat_main_t *vam = ip_test_main.vat_main;
1511   static ip_address_details_t empty_ip_address_details = { { 0 } };
1512   ip_address_details_t *address = NULL;
1513   ip_details_t *current_ip_details = NULL;
1514   ip_details_t *details = NULL;
1515
1516   details = vam->ip_details_by_sw_if_index[vam->is_ipv6];
1517
1518   if (!details || vam->current_sw_if_index >= vec_len (details) ||
1519       !details[vam->current_sw_if_index].present)
1520     {
1521       errmsg ("ip address details arrived but not stored");
1522       errmsg ("ip_dump should be called first");
1523       return;
1524     }
1525
1526   current_ip_details = vec_elt_at_index (details, vam->current_sw_if_index);
1527
1528 #define addresses (current_ip_details->addr)
1529
1530   vec_validate_init_empty (addresses, vec_len (addresses),
1531                            empty_ip_address_details);
1532
1533   address = vec_elt_at_index (addresses, vec_len (addresses) - 1);
1534
1535   clib_memcpy (&address->ip, &mp->prefix.address.un, sizeof (address->ip));
1536   address->prefix_length = mp->prefix.len;
1537 #undef addresses
1538 }
1539
1540 static int
1541 api_ip_unnumbered_dump (vat_main_t *vam)
1542 {
1543   return -1;
1544 }
1545
1546 static void
1547 vl_api_ip_unnumbered_details_t_handler (vl_api_ip_unnumbered_details_t *mp)
1548 {
1549 }
1550
1551 static void
1552 vl_api_ip_details_t_handler (vl_api_ip_details_t *mp)
1553 {
1554   vat_main_t *vam = &vat_main;
1555   static ip_details_t empty_ip_details = { 0 };
1556   ip_details_t *ip = NULL;
1557   u32 sw_if_index = ~0;
1558
1559   sw_if_index = ntohl (mp->sw_if_index);
1560
1561   vec_validate_init_empty (vam->ip_details_by_sw_if_index[vam->is_ipv6],
1562                            sw_if_index, empty_ip_details);
1563
1564   ip = vec_elt_at_index (vam->ip_details_by_sw_if_index[vam->is_ipv6],
1565                          sw_if_index);
1566
1567   ip->present = 1;
1568 }
1569
1570 #include <vnet/ip/ip.api_test.c>
1571
1572 /*
1573  * fd.io coding-style-patch-verification: ON
1574  *
1575  * Local Variables:
1576  * eval: (c-set-style "gnu")
1577  * End:
1578  */