api: verify message size on receipt
[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 void
1018 vl_api_ip_reassembly_get_reply_t_handler (vl_api_ip_reassembly_get_reply_t *mp)
1019 {
1020 }
1021
1022 int
1023 api_ip_source_and_port_range_check_interface_add_del (vat_main_t *vam)
1024 {
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", api_unformat_sw_if_index, vam, &sw_if_index))
1037         ;
1038       else if (unformat (input, "sw_if_index %d", &sw_if_index))
1039         ;
1040       else if (unformat (input, "tcp-out-vrf %d", &tcp_out_vrf_id))
1041         vrf_set = 1;
1042       else if (unformat (input, "udp-out-vrf %d", &udp_out_vrf_id))
1043         vrf_set = 1;
1044       else if (unformat (input, "tcp-in-vrf %d", &tcp_in_vrf_id))
1045         vrf_set = 1;
1046       else if (unformat (input, "udp-in-vrf %d", &udp_in_vrf_id))
1047         vrf_set = 1;
1048       else if (unformat (input, "del"))
1049         is_add = 0;
1050       else
1051         break;
1052     }
1053
1054   if (sw_if_index == ~0)
1055     {
1056       errmsg ("Interface required but not specified");
1057       return -99;
1058     }
1059
1060   if (vrf_set == 0)
1061     {
1062       errmsg ("VRF ID required but not specified");
1063       return -99;
1064     }
1065
1066   if (tcp_out_vrf_id == 0 || udp_out_vrf_id == 0 || tcp_in_vrf_id == 0 ||
1067       udp_in_vrf_id == 0)
1068     {
1069       errmsg ("VRF ID should not be default. Should be distinct VRF for this "
1070               "purpose.");
1071       return -99;
1072     }
1073
1074   /* Construct the API message */
1075   M (IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, mp);
1076
1077   mp->sw_if_index = ntohl (sw_if_index);
1078   mp->is_add = is_add;
1079   mp->tcp_out_vrf_id = ntohl (tcp_out_vrf_id);
1080   mp->udp_out_vrf_id = ntohl (udp_out_vrf_id);
1081   mp->tcp_in_vrf_id = ntohl (tcp_in_vrf_id);
1082   mp->udp_in_vrf_id = ntohl (udp_in_vrf_id);
1083
1084   /* send it... */
1085   S (mp);
1086
1087   /* Wait for a reply... */
1088   W (ret);
1089   return ret;
1090 }
1091
1092 static void
1093 vl_api_ip_container_proxy_details_t_handler (
1094   vl_api_ip_container_proxy_details_t *mp)
1095 {
1096 }
1097
1098 static int
1099 api_ip_container_proxy_dump (vat_main_t *vam)
1100 {
1101   return -1;
1102 }
1103
1104 static int
1105 api_ip_dump (vat_main_t *vam)
1106 {
1107   vl_api_ip_dump_t *mp;
1108   vl_api_control_ping_t *mp_ping;
1109   unformat_input_t *in = vam->input;
1110   int ipv4_set = 0;
1111   int ipv6_set = 0;
1112   int is_ipv6;
1113   int i;
1114   int ret;
1115
1116   while (unformat_check_input (in) != UNFORMAT_END_OF_INPUT)
1117     {
1118       if (unformat (in, "ipv4"))
1119         ipv4_set = 1;
1120       else if (unformat (in, "ipv6"))
1121         ipv6_set = 1;
1122       else
1123         break;
1124     }
1125
1126   if (ipv4_set && ipv6_set)
1127     {
1128       errmsg ("ipv4 and ipv6 flags cannot be both set");
1129       return -99;
1130     }
1131
1132   if ((!ipv4_set) && (!ipv6_set))
1133     {
1134       errmsg ("no ipv4 nor ipv6 flag set");
1135       return -99;
1136     }
1137
1138   is_ipv6 = ipv6_set;
1139   vam->is_ipv6 = is_ipv6;
1140
1141   /* free old data */
1142   for (i = 0; i < vec_len (vam->ip_details_by_sw_if_index[is_ipv6]); i++)
1143     {
1144       vec_free (vam->ip_details_by_sw_if_index[is_ipv6][i].addr);
1145     }
1146   vec_free (vam->ip_details_by_sw_if_index[is_ipv6]);
1147
1148   M (IP_DUMP, mp);
1149   mp->is_ipv6 = ipv6_set;
1150   S (mp);
1151
1152   /* Use a control ping for synchronization */
1153   PING (&ip_test_main, mp_ping);
1154   S (mp_ping);
1155
1156   W (ret);
1157   return ret;
1158 }
1159
1160 static void
1161 vl_api_mfib_signal_details_t_handler (vl_api_mfib_signal_details_t *mp)
1162 {
1163 }
1164
1165 static void
1166 vl_api_ip_mroute_details_t_handler (vl_api_ip_mroute_details_t *mp)
1167 {
1168   vat_main_t *vam = ip_test_main.vat_main;
1169   vam->result_ready = 1;
1170 }
1171
1172 static int
1173 api_ip_mroute_dump (vat_main_t *vam)
1174 {
1175   unformat_input_t *input = vam->input;
1176   vl_api_control_ping_t *mp_ping;
1177   vl_api_ip_mroute_dump_t *mp;
1178   int ret, is_ip6;
1179   u32 table_id;
1180
1181   is_ip6 = 0;
1182   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1183     {
1184       if (unformat (input, "table_id %d", &table_id))
1185         ;
1186       else if (unformat (input, "ip6"))
1187         is_ip6 = 1;
1188       else if (unformat (input, "ip4"))
1189         is_ip6 = 0;
1190       else
1191         break;
1192     }
1193   if (table_id == ~0)
1194     {
1195       errmsg ("missing table id");
1196       return -99;
1197     }
1198
1199   M (IP_MROUTE_DUMP, mp);
1200   mp->table.table_id = table_id;
1201   mp->table.is_ip6 = is_ip6;
1202   S (mp);
1203
1204   /* Use a control ping for synchronization */
1205   PING (&ip_test_main, mp_ping);
1206   S (mp_ping);
1207
1208   W (ret);
1209   return ret;
1210 }
1211
1212 static int
1213 api_sw_interface_ip6_enable_disable (vat_main_t *vam)
1214 {
1215   unformat_input_t *i = vam->input;
1216   vl_api_sw_interface_ip6_enable_disable_t *mp;
1217   u32 sw_if_index;
1218   u8 sw_if_index_set = 0;
1219   u8 enable = 0;
1220   int ret;
1221
1222   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1223     {
1224       if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
1225         sw_if_index_set = 1;
1226       else if (unformat (i, "sw_if_index %d", &sw_if_index))
1227         sw_if_index_set = 1;
1228       else if (unformat (i, "enable"))
1229         enable = 1;
1230       else if (unformat (i, "disable"))
1231         enable = 0;
1232       else
1233         {
1234           clib_warning ("parse error '%U'", format_unformat_error, i);
1235           return -99;
1236         }
1237     }
1238
1239   if (sw_if_index_set == 0)
1240     {
1241       errmsg ("missing interface name or sw_if_index");
1242       return -99;
1243     }
1244
1245   M (SW_INTERFACE_IP6_ENABLE_DISABLE, mp);
1246
1247   mp->sw_if_index = ntohl (sw_if_index);
1248   mp->enable = enable;
1249
1250   S (mp);
1251   W (ret);
1252   return ret;
1253 }
1254
1255 static int
1256 api_set_ip_flow_hash_v2 (vat_main_t *vat)
1257 {
1258   return -1;
1259 }
1260
1261 static int
1262 api_ip_mroute_add_del (vat_main_t *vam)
1263 {
1264   unformat_input_t *i = vam->input;
1265   u8 path_set = 0, prefix_set = 0, is_add = 1;
1266   vl_api_ip_mroute_add_del_t *mp;
1267   mfib_entry_flags_t eflags = 0;
1268   vl_api_mfib_path_t path;
1269   vl_api_mprefix_t pfx = {};
1270   u32 vrf_id = 0;
1271   int ret;
1272
1273   /* Parse args required to build the message */
1274   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1275     {
1276       if (unformat (i, "%U", unformat_vl_api_mprefix, &pfx))
1277         {
1278           prefix_set = 1;
1279           pfx.grp_address_length = htons (pfx.grp_address_length);
1280         }
1281       else if (unformat (i, "del"))
1282         is_add = 0;
1283       else if (unformat (i, "add"))
1284         is_add = 1;
1285       else if (unformat (i, "vrf %d", &vrf_id))
1286         ;
1287       else if (unformat (i, "%U", unformat_mfib_itf_flags, &path.itf_flags))
1288         path.itf_flags = htonl (path.itf_flags);
1289       else if (unformat (i, "%U", unformat_mfib_entry_flags, &eflags))
1290         ;
1291       else if (unformat (i, "via %U", unformat_fib_path, vam, &path.path))
1292         path_set = 1;
1293       else
1294         {
1295           clib_warning ("parse error '%U'", format_unformat_error, i);
1296           return -99;
1297         }
1298     }
1299
1300   if (prefix_set == 0)
1301     {
1302       errmsg ("missing addresses\n");
1303       return -99;
1304     }
1305   if (path_set == 0)
1306     {
1307       errmsg ("missing path\n");
1308       return -99;
1309     }
1310
1311   /* Construct the API message */
1312   M (IP_MROUTE_ADD_DEL, mp);
1313
1314   mp->is_add = is_add;
1315   mp->is_multipath = 1;
1316
1317   clib_memcpy (&mp->route.prefix, &pfx, sizeof (pfx));
1318   mp->route.table_id = htonl (vrf_id);
1319   mp->route.n_paths = 1;
1320   mp->route.entry_flags = htonl (eflags);
1321
1322   clib_memcpy (&mp->route.paths, &path, sizeof (path));
1323
1324   /* send it... */
1325   S (mp);
1326   /* Wait for a reply... */
1327   W (ret);
1328   return ret;
1329 }
1330
1331 static void
1332 vl_api_ip_mroute_add_del_reply_t_handler (vl_api_ip_mroute_add_del_reply_t *mp)
1333 {
1334   vat_main_t *vam = ip_test_main.vat_main;
1335   vam->result_ready = 1;
1336 }
1337
1338 static int
1339 api_ip_mtable_dump (vat_main_t *vam)
1340 {
1341   vl_api_ip_mtable_dump_t *mp;
1342   vl_api_control_ping_t *mp_ping;
1343   int ret;
1344
1345   M (IP_MTABLE_DUMP, mp);
1346   S (mp);
1347
1348   /* Use a control ping for synchronization */
1349   PING (&ip_test_main, mp_ping);
1350   S (mp_ping);
1351
1352   W (ret);
1353   return ret;
1354 }
1355
1356 static void
1357 vl_api_ip_mtable_details_t_handler (vl_api_ip_mtable_details_t *mp)
1358 {
1359   vat_main_t *vam = ip_test_main.vat_main;
1360   vam->result_ready = 1;
1361 }
1362
1363 static int
1364 api_ip_table_replace_end (vat_main_t *vam)
1365 {
1366   unformat_input_t *i = vam->input;
1367   vl_api_ip_table_replace_end_t *mp;
1368   u32 table_id = 0;
1369   u8 is_ipv6 = 0;
1370
1371   int ret;
1372   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1373     {
1374       if (unformat (i, "table %d", &table_id))
1375         ;
1376       else if (unformat (i, "ipv6"))
1377         is_ipv6 = 1;
1378       else
1379         {
1380           clib_warning ("parse error '%U'", format_unformat_error, i);
1381           return -99;
1382         }
1383     }
1384
1385   M (IP_TABLE_REPLACE_END, mp);
1386
1387   mp->table.table_id = ntohl (table_id);
1388   mp->table.is_ip6 = is_ipv6;
1389
1390   S (mp);
1391   W (ret);
1392   return ret;
1393 }
1394
1395 static int
1396 api_ip_table_dump (vat_main_t *vam)
1397 {
1398   vl_api_ip_table_dump_t *mp;
1399   vl_api_control_ping_t *mp_ping;
1400   int ret;
1401
1402   M (IP_TABLE_DUMP, mp);
1403   S (mp);
1404
1405   /* Use a control ping for synchronization */
1406   PING (&ip_test_main, mp_ping);
1407   S (mp_ping);
1408
1409   W (ret);
1410   return ret;
1411 }
1412
1413 static void
1414 vl_api_ip_table_details_t_handler (vl_api_ip_table_details_t *mp)
1415 {
1416   vat_main_t *vam = ip_test_main.vat_main;
1417
1418   fformat (vam->ofp, "%s; table-id %d, prefix %U/%d", mp->table.name,
1419            ntohl (mp->table.table_id));
1420   vam->result_ready = 1;
1421 }
1422
1423 static int
1424 api_ip_path_mtu_get (vat_main_t *vat)
1425 {
1426   return -1;
1427 }
1428
1429 static int
1430 api_ip_route_v2_dump (vat_main_t *vat)
1431 {
1432   return -1;
1433 }
1434
1435 static void
1436 vl_api_ip_path_mtu_get_reply_t_handler (vl_api_ip_path_mtu_get_reply_t *mp)
1437 {
1438 }
1439
1440 static int
1441 api_ip_route_dump (vat_main_t *vam)
1442 {
1443   unformat_input_t *input = vam->input;
1444   vl_api_ip_route_dump_t *mp;
1445   vl_api_control_ping_t *mp_ping;
1446   u32 table_id;
1447   u8 is_ip6;
1448   int ret;
1449
1450   is_ip6 = 0;
1451   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1452     {
1453       if (unformat (input, "table_id %d", &table_id))
1454         ;
1455       else if (unformat (input, "ip6"))
1456         is_ip6 = 1;
1457       else if (unformat (input, "ip4"))
1458         is_ip6 = 0;
1459       else
1460         break;
1461     }
1462   if (table_id == ~0)
1463     {
1464       errmsg ("missing table id");
1465       return -99;
1466     }
1467
1468   M (IP_ROUTE_DUMP, mp);
1469
1470   mp->table.table_id = table_id;
1471   mp->table.is_ip6 = is_ip6;
1472
1473   S (mp);
1474
1475   /* Use a control ping for synchronization */
1476   PING (&ip_test_main, mp_ping);
1477   S (mp_ping);
1478
1479   W (ret);
1480   return ret;
1481 }
1482
1483 static void
1484 vl_api_ip_address_details_t_handler (vl_api_ip_address_details_t *mp)
1485 {
1486   vat_main_t *vam = ip_test_main.vat_main;
1487   static ip_address_details_t empty_ip_address_details = { { 0 } };
1488   ip_address_details_t *address = NULL;
1489   ip_details_t *current_ip_details = NULL;
1490   ip_details_t *details = NULL;
1491
1492   details = vam->ip_details_by_sw_if_index[vam->is_ipv6];
1493
1494   if (!details || vam->current_sw_if_index >= vec_len (details) ||
1495       !details[vam->current_sw_if_index].present)
1496     {
1497       errmsg ("ip address details arrived but not stored");
1498       errmsg ("ip_dump should be called first");
1499       return;
1500     }
1501
1502   current_ip_details = vec_elt_at_index (details, vam->current_sw_if_index);
1503
1504 #define addresses (current_ip_details->addr)
1505
1506   vec_validate_init_empty (addresses, vec_len (addresses),
1507                            empty_ip_address_details);
1508
1509   address = vec_elt_at_index (addresses, vec_len (addresses) - 1);
1510
1511   clib_memcpy (&address->ip, &mp->prefix.address.un, sizeof (address->ip));
1512   address->prefix_length = mp->prefix.len;
1513 #undef addresses
1514 }
1515
1516 static int
1517 api_ip_unnumbered_dump (vat_main_t *vam)
1518 {
1519   return -1;
1520 }
1521
1522 static void
1523 vl_api_ip_unnumbered_details_t_handler (vl_api_ip_unnumbered_details_t *mp)
1524 {
1525 }
1526
1527 static void
1528 vl_api_ip_details_t_handler (vl_api_ip_details_t *mp)
1529 {
1530   vat_main_t *vam = &vat_main;
1531   static ip_details_t empty_ip_details = { 0 };
1532   ip_details_t *ip = NULL;
1533   u32 sw_if_index = ~0;
1534
1535   sw_if_index = ntohl (mp->sw_if_index);
1536
1537   vec_validate_init_empty (vam->ip_details_by_sw_if_index[vam->is_ipv6],
1538                            sw_if_index, empty_ip_details);
1539
1540   ip = vec_elt_at_index (vam->ip_details_by_sw_if_index[vam->is_ipv6],
1541                          sw_if_index);
1542
1543   ip->present = 1;
1544 }
1545
1546 #include <vnet/ip/ip.api_test.c>
1547
1548 /*
1549  * fd.io coding-style-patch-verification: ON
1550  *
1551  * Local Variables:
1552  * eval: (c-set-style "gnu")
1553  * End:
1554  */