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