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