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