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