ip: source address selection
[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_ip_punt_redirect_dump (vat_main_t *vat)
662 {
663   return -1;
664 }
665
666 static void
667 vl_api_ip_punt_redirect_details_t_handler (
668   vl_api_ip_punt_redirect_details_t *mp)
669 {
670 }
671
672 static int
673 api_ip_address_dump (vat_main_t *vam)
674 {
675   vnet_main_t *vnm = vnet_get_main ();
676   unformat_input_t *i = vam->input;
677   vl_api_ip_address_dump_t *mp;
678   vl_api_control_ping_t *mp_ping;
679   u32 sw_if_index = ~0;
680   u8 sw_if_index_set = 0;
681   u8 ipv4_set = 0;
682   u8 ipv6_set = 0;
683   int ret;
684
685   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
686     {
687       if (unformat (i, "sw_if_index %d", &sw_if_index))
688         sw_if_index_set = 1;
689       else if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
690                          &sw_if_index))
691         sw_if_index_set = 1;
692       else if (unformat (i, "ipv4"))
693         ipv4_set = 1;
694       else if (unformat (i, "ipv6"))
695         ipv6_set = 1;
696       else
697         break;
698     }
699
700   if (ipv4_set && ipv6_set)
701     {
702       errmsg ("ipv4 and ipv6 flags cannot be both set");
703       return -99;
704     }
705
706   if ((!ipv4_set) && (!ipv6_set))
707     {
708       errmsg ("no ipv4 nor ipv6 flag set");
709       return -99;
710     }
711
712   if (sw_if_index_set == 0)
713     {
714       errmsg ("missing interface name or sw_if_index");
715       return -99;
716     }
717
718   vam->current_sw_if_index = sw_if_index;
719   vam->is_ipv6 = ipv6_set;
720
721   M (IP_ADDRESS_DUMP, mp);
722   mp->sw_if_index = ntohl (sw_if_index);
723   mp->is_ipv6 = ipv6_set;
724   S (mp);
725
726   /* Use a control ping for synchronization */
727   PING (&ip_test_main, mp_ping);
728   S (mp_ping);
729
730   W (ret);
731   return ret;
732 }
733
734 static void
735 vl_api_sw_interface_ip6_get_link_local_address_reply_t_handler (
736   vl_api_sw_interface_ip6_get_link_local_address_reply_t *mp)
737 {
738 }
739
740 static int
741 api_sw_interface_ip6_set_link_local_address (vat_main_t *vam)
742 {
743   return -1;
744 }
745
746 static int
747 api_sw_interface_ip6_get_link_local_address (vat_main_t *vam)
748 {
749   return -1;
750 }
751
752 static int
753 api_ip_path_mtu_replace_end (vat_main_t *vam)
754 {
755   return -1;
756 }
757
758 static int
759 api_ioam_enable (vat_main_t *vam)
760 {
761   unformat_input_t *input = vam->input;
762   vl_api_ioam_enable_t *mp;
763   u32 id = 0;
764   int has_trace_option = 0;
765   int has_pot_option = 0;
766   int has_seqno_option = 0;
767   int has_analyse_option = 0;
768   int ret;
769
770   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
771     {
772       if (unformat (input, "trace"))
773         has_trace_option = 1;
774       else if (unformat (input, "pot"))
775         has_pot_option = 1;
776       else if (unformat (input, "seqno"))
777         has_seqno_option = 1;
778       else if (unformat (input, "analyse"))
779         has_analyse_option = 1;
780       else
781         break;
782     }
783   M (IOAM_ENABLE, mp);
784   mp->id = htons (id);
785   mp->seqno = has_seqno_option;
786   mp->analyse = has_analyse_option;
787   mp->pot_enable = has_pot_option;
788   mp->trace_enable = has_trace_option;
789
790   S (mp);
791   W (ret);
792   return ret;
793 }
794
795 static int
796 api_ip_reassembly_get (vat_main_t *vam)
797 {
798   return -1;
799 }
800
801 static int
802 api_ip_path_mtu_replace_begin (vat_main_t *vam)
803 {
804   return -1;
805 }
806
807 static int
808 api_ip_path_mtu_update (vat_main_t *vam)
809 {
810   return -1;
811 }
812
813 static int
814 api_ioam_disable (vat_main_t *vam)
815 {
816   vl_api_ioam_disable_t *mp;
817   int ret;
818
819   M (IOAM_DISABLE, mp);
820   S (mp);
821   W (ret);
822   return ret;
823 }
824
825 static int
826 api_ip_source_and_port_range_check_add_del (vat_main_t *vam)
827 {
828   unformat_input_t *input = vam->input;
829   vl_api_ip_source_and_port_range_check_add_del_t *mp;
830
831   u16 *low_ports = 0;
832   u16 *high_ports = 0;
833   u16 this_low;
834   u16 this_hi;
835   vl_api_prefix_t prefix;
836   u32 tmp, tmp2;
837   u8 prefix_set = 0;
838   u32 vrf_id = ~0;
839   u8 is_add = 1;
840   int ret;
841
842   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
843     {
844       if (unformat (input, "%U", unformat_vl_api_prefix, &prefix))
845         prefix_set = 1;
846       else if (unformat (input, "vrf %d", &vrf_id))
847         ;
848       else if (unformat (input, "del"))
849         is_add = 0;
850       else if (unformat (input, "port %d", &tmp))
851         {
852           if (tmp == 0 || tmp > 65535)
853             {
854               errmsg ("port %d out of range", tmp);
855               return -99;
856             }
857           this_low = tmp;
858           this_hi = this_low + 1;
859           vec_add1 (low_ports, this_low);
860           vec_add1 (high_ports, this_hi);
861         }
862       else if (unformat (input, "range %d - %d", &tmp, &tmp2))
863         {
864           if ((tmp > tmp2) || (tmp == 0) || (tmp2 > 65535))
865             {
866               errmsg ("incorrect range parameters");
867               return -99;
868             }
869           this_low = tmp;
870           /* Note: in debug CLI +1 is added to high before
871              passing to real fn that does "the work"
872              (ip_source_and_port_range_check_add_del).
873              This fn is a wrapper around the binary API fn a
874              control plane will call, which expects this increment
875              to have occurred. Hence letting the binary API control
876              plane fn do the increment for consistency between VAT
877              and other control planes.
878            */
879           this_hi = tmp2;
880           vec_add1 (low_ports, this_low);
881           vec_add1 (high_ports, this_hi);
882         }
883       else
884         break;
885     }
886
887   if (prefix_set == 0)
888     {
889       errmsg ("<address>/<mask> not specified");
890       return -99;
891     }
892
893   if (vrf_id == ~0)
894     {
895       errmsg ("VRF ID required, not specified");
896       return -99;
897     }
898
899   if (vrf_id == 0)
900     {
901       errmsg ("VRF ID should not be default. Should be distinct VRF for this "
902               "purpose.");
903       return -99;
904     }
905
906   if (vec_len (low_ports) == 0)
907     {
908       errmsg ("At least one port or port range required");
909       return -99;
910     }
911
912   M (IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, mp);
913
914   mp->is_add = is_add;
915
916   clib_memcpy (&mp->prefix, &prefix, sizeof (prefix));
917
918   mp->number_of_ranges = vec_len (low_ports);
919
920   clib_memcpy (mp->low_ports, low_ports, vec_len (low_ports));
921   vec_free (low_ports);
922
923   clib_memcpy (mp->high_ports, high_ports, vec_len (high_ports));
924   vec_free (high_ports);
925
926   mp->vrf_id = ntohl (vrf_id);
927
928   S (mp);
929   W (ret);
930   return ret;
931 }
932
933 static int
934 api_ip_reassembly_set (vat_main_t *vat)
935 {
936   return -1;
937 }
938
939 static int
940 api_ip_container_proxy_add_del (vat_main_t *vam)
941 {
942   vl_api_ip_container_proxy_add_del_t *mp;
943   unformat_input_t *i = vam->input;
944   u32 sw_if_index = ~0;
945   vl_api_prefix_t pfx = {};
946   u8 is_add = 1;
947   int ret;
948
949   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
950     {
951       if (unformat (i, "del"))
952         is_add = 0;
953       else if (unformat (i, "add"))
954         ;
955       if (unformat (i, "%U", unformat_vl_api_prefix, &pfx))
956         ;
957       else if (unformat (i, "sw_if_index %u", &sw_if_index))
958         ;
959       else
960         break;
961     }
962   if (sw_if_index == ~0 || pfx.len == 0)
963     {
964       errmsg ("address and sw_if_index must be set");
965       return -99;
966     }
967
968   M (IP_CONTAINER_PROXY_ADD_DEL, mp);
969
970   mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
971   mp->is_add = is_add;
972   clib_memcpy (&mp->pfx, &pfx, sizeof (pfx));
973
974   S (mp);
975   W (ret);
976   return ret;
977 }
978
979 static int
980 api_ip_reassembly_enable_disable (vat_main_t *vat)
981 {
982   return -1;
983 }
984
985 static void
986 vl_api_ip_reassembly_get_reply_t_handler (vl_api_ip_reassembly_get_reply_t *mp)
987 {
988 }
989
990 int
991 api_ip_source_and_port_range_check_interface_add_del (vat_main_t *vam)
992 {
993   vnet_main_t *vnm = vnet_get_main ();
994   unformat_input_t *input = vam->input;
995   vl_api_ip_source_and_port_range_check_interface_add_del_t *mp;
996   u32 sw_if_index = ~0;
997   int vrf_set = 0;
998   u32 tcp_out_vrf_id = ~0, udp_out_vrf_id = ~0;
999   u32 tcp_in_vrf_id = ~0, udp_in_vrf_id = ~0;
1000   u8 is_add = 1;
1001   int ret;
1002
1003   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1004     {
1005       if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
1006                     &sw_if_index))
1007         ;
1008       else if (unformat (input, "sw_if_index %d", &sw_if_index))
1009         ;
1010       else if (unformat (input, "tcp-out-vrf %d", &tcp_out_vrf_id))
1011         vrf_set = 1;
1012       else if (unformat (input, "udp-out-vrf %d", &udp_out_vrf_id))
1013         vrf_set = 1;
1014       else if (unformat (input, "tcp-in-vrf %d", &tcp_in_vrf_id))
1015         vrf_set = 1;
1016       else if (unformat (input, "udp-in-vrf %d", &udp_in_vrf_id))
1017         vrf_set = 1;
1018       else if (unformat (input, "del"))
1019         is_add = 0;
1020       else
1021         break;
1022     }
1023
1024   if (sw_if_index == ~0)
1025     {
1026       errmsg ("Interface required but not specified");
1027       return -99;
1028     }
1029
1030   if (vrf_set == 0)
1031     {
1032       errmsg ("VRF ID required but not specified");
1033       return -99;
1034     }
1035
1036   if (tcp_out_vrf_id == 0 || udp_out_vrf_id == 0 || tcp_in_vrf_id == 0 ||
1037       udp_in_vrf_id == 0)
1038     {
1039       errmsg ("VRF ID should not be default. Should be distinct VRF for this "
1040               "purpose.");
1041       return -99;
1042     }
1043
1044   /* Construct the API message */
1045   M (IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, mp);
1046
1047   mp->sw_if_index = ntohl (sw_if_index);
1048   mp->is_add = is_add;
1049   mp->tcp_out_vrf_id = ntohl (tcp_out_vrf_id);
1050   mp->udp_out_vrf_id = ntohl (udp_out_vrf_id);
1051   mp->tcp_in_vrf_id = ntohl (tcp_in_vrf_id);
1052   mp->udp_in_vrf_id = ntohl (udp_in_vrf_id);
1053
1054   /* send it... */
1055   S (mp);
1056
1057   /* Wait for a reply... */
1058   W (ret);
1059   return ret;
1060 }
1061
1062 static void
1063 vl_api_ip_container_proxy_details_t_handler (
1064   vl_api_ip_container_proxy_details_t *mp)
1065 {
1066 }
1067
1068 static int
1069 api_ip_container_proxy_dump (vat_main_t *vam)
1070 {
1071   return -1;
1072 }
1073
1074 static int
1075 api_ip_dump (vat_main_t *vam)
1076 {
1077   vl_api_ip_dump_t *mp;
1078   vl_api_control_ping_t *mp_ping;
1079   unformat_input_t *in = vam->input;
1080   int ipv4_set = 0;
1081   int ipv6_set = 0;
1082   int is_ipv6;
1083   int i;
1084   int ret;
1085
1086   while (unformat_check_input (in) != UNFORMAT_END_OF_INPUT)
1087     {
1088       if (unformat (in, "ipv4"))
1089         ipv4_set = 1;
1090       else if (unformat (in, "ipv6"))
1091         ipv6_set = 1;
1092       else
1093         break;
1094     }
1095
1096   if (ipv4_set && ipv6_set)
1097     {
1098       errmsg ("ipv4 and ipv6 flags cannot be both set");
1099       return -99;
1100     }
1101
1102   if ((!ipv4_set) && (!ipv6_set))
1103     {
1104       errmsg ("no ipv4 nor ipv6 flag set");
1105       return -99;
1106     }
1107
1108   is_ipv6 = ipv6_set;
1109   vam->is_ipv6 = is_ipv6;
1110
1111   /* free old data */
1112   for (i = 0; i < vec_len (vam->ip_details_by_sw_if_index[is_ipv6]); i++)
1113     {
1114       vec_free (vam->ip_details_by_sw_if_index[is_ipv6][i].addr);
1115     }
1116   vec_free (vam->ip_details_by_sw_if_index[is_ipv6]);
1117
1118   M (IP_DUMP, mp);
1119   mp->is_ipv6 = ipv6_set;
1120   S (mp);
1121
1122   /* Use a control ping for synchronization */
1123   PING (&ip_test_main, mp_ping);
1124   S (mp_ping);
1125
1126   W (ret);
1127   return ret;
1128 }
1129
1130 static void
1131 vl_api_mfib_signal_details_t_handler (vl_api_mfib_signal_details_t *mp)
1132 {
1133 }
1134
1135 static void
1136 vl_api_ip_mroute_details_t_handler (vl_api_ip_mroute_details_t *mp)
1137 {
1138   vat_main_t *vam = ip_test_main.vat_main;
1139   vam->result_ready = 1;
1140 }
1141
1142 static int
1143 api_ip_mroute_dump (vat_main_t *vam)
1144 {
1145   unformat_input_t *input = vam->input;
1146   vl_api_control_ping_t *mp_ping;
1147   vl_api_ip_mroute_dump_t *mp;
1148   int ret, is_ip6;
1149   u32 table_id;
1150
1151   is_ip6 = 0;
1152   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1153     {
1154       if (unformat (input, "table_id %d", &table_id))
1155         ;
1156       else if (unformat (input, "ip6"))
1157         is_ip6 = 1;
1158       else if (unformat (input, "ip4"))
1159         is_ip6 = 0;
1160       else
1161         break;
1162     }
1163   if (table_id == ~0)
1164     {
1165       errmsg ("missing table id");
1166       return -99;
1167     }
1168
1169   M (IP_MROUTE_DUMP, mp);
1170   mp->table.table_id = table_id;
1171   mp->table.is_ip6 = is_ip6;
1172   S (mp);
1173
1174   /* Use a control ping for synchronization */
1175   PING (&ip_test_main, mp_ping);
1176   S (mp_ping);
1177
1178   W (ret);
1179   return ret;
1180 }
1181
1182 static int
1183 api_sw_interface_ip6_enable_disable (vat_main_t *vam)
1184 {
1185   vnet_main_t *vnm = vnet_get_main ();
1186   unformat_input_t *i = vam->input;
1187   vl_api_sw_interface_ip6_enable_disable_t *mp;
1188   u32 sw_if_index;
1189   u8 sw_if_index_set = 0;
1190   u8 enable = 0;
1191   int ret;
1192
1193   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1194     {
1195       if (unformat (i, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1196         sw_if_index_set = 1;
1197       else if (unformat (i, "sw_if_index %d", &sw_if_index))
1198         sw_if_index_set = 1;
1199       else if (unformat (i, "enable"))
1200         enable = 1;
1201       else if (unformat (i, "disable"))
1202         enable = 0;
1203       else
1204         {
1205           clib_warning ("parse error '%U'", format_unformat_error, i);
1206           return -99;
1207         }
1208     }
1209
1210   if (sw_if_index_set == 0)
1211     {
1212       errmsg ("missing interface name or sw_if_index");
1213       return -99;
1214     }
1215
1216   M (SW_INTERFACE_IP6_ENABLE_DISABLE, mp);
1217
1218   mp->sw_if_index = ntohl (sw_if_index);
1219   mp->enable = enable;
1220
1221   S (mp);
1222   W (ret);
1223   return ret;
1224 }
1225
1226 static int
1227 api_set_ip_flow_hash_v2 (vat_main_t *vat)
1228 {
1229   return -1;
1230 }
1231
1232 static int
1233 api_ip_mroute_add_del (vat_main_t *vam)
1234 {
1235   unformat_input_t *i = vam->input;
1236   u8 path_set = 0, prefix_set = 0, is_add = 1;
1237   vl_api_ip_mroute_add_del_t *mp;
1238   mfib_entry_flags_t eflags = 0;
1239   vl_api_mfib_path_t path;
1240   vl_api_mprefix_t pfx = {};
1241   u32 vrf_id = 0;
1242   int ret;
1243
1244   /* Parse args required to build the message */
1245   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1246     {
1247       if (unformat (i, "%U", unformat_vl_api_mprefix, &pfx))
1248         {
1249           prefix_set = 1;
1250           pfx.grp_address_length = htons (pfx.grp_address_length);
1251         }
1252       else if (unformat (i, "del"))
1253         is_add = 0;
1254       else if (unformat (i, "add"))
1255         is_add = 1;
1256       else if (unformat (i, "vrf %d", &vrf_id))
1257         ;
1258       else if (unformat (i, "%U", unformat_mfib_itf_flags, &path.itf_flags))
1259         path.itf_flags = htonl (path.itf_flags);
1260       else if (unformat (i, "%U", unformat_mfib_entry_flags, &eflags))
1261         ;
1262       else if (unformat (i, "via %U", unformat_fib_path, vam, &path.path))
1263         path_set = 1;
1264       else
1265         {
1266           clib_warning ("parse error '%U'", format_unformat_error, i);
1267           return -99;
1268         }
1269     }
1270
1271   if (prefix_set == 0)
1272     {
1273       errmsg ("missing addresses\n");
1274       return -99;
1275     }
1276   if (path_set == 0)
1277     {
1278       errmsg ("missing path\n");
1279       return -99;
1280     }
1281
1282   /* Construct the API message */
1283   M (IP_MROUTE_ADD_DEL, mp);
1284
1285   mp->is_add = is_add;
1286   mp->is_multipath = 1;
1287
1288   clib_memcpy (&mp->route.prefix, &pfx, sizeof (pfx));
1289   mp->route.table_id = htonl (vrf_id);
1290   mp->route.n_paths = 1;
1291   mp->route.entry_flags = htonl (eflags);
1292
1293   clib_memcpy (&mp->route.paths, &path, sizeof (path));
1294
1295   /* send it... */
1296   S (mp);
1297   /* Wait for a reply... */
1298   W (ret);
1299   return ret;
1300 }
1301
1302 static void
1303 vl_api_ip_mroute_add_del_reply_t_handler (vl_api_ip_mroute_add_del_reply_t *mp)
1304 {
1305   vat_main_t *vam = ip_test_main.vat_main;
1306   vam->result_ready = 1;
1307 }
1308
1309 static int
1310 api_ip_mtable_dump (vat_main_t *vam)
1311 {
1312   vl_api_ip_mtable_dump_t *mp;
1313   vl_api_control_ping_t *mp_ping;
1314   int ret;
1315
1316   M (IP_MTABLE_DUMP, mp);
1317   S (mp);
1318
1319   /* Use a control ping for synchronization */
1320   PING (&ip_test_main, mp_ping);
1321   S (mp_ping);
1322
1323   W (ret);
1324   return ret;
1325 }
1326
1327 static void
1328 vl_api_ip_mtable_details_t_handler (vl_api_ip_mtable_details_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_table_replace_end (vat_main_t *vam)
1336 {
1337   unformat_input_t *i = vam->input;
1338   vl_api_ip_table_replace_end_t *mp;
1339   u32 table_id = 0;
1340   u8 is_ipv6 = 0;
1341
1342   int ret;
1343   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1344     {
1345       if (unformat (i, "table %d", &table_id))
1346         ;
1347       else if (unformat (i, "ipv6"))
1348         is_ipv6 = 1;
1349       else
1350         {
1351           clib_warning ("parse error '%U'", format_unformat_error, i);
1352           return -99;
1353         }
1354     }
1355
1356   M (IP_TABLE_REPLACE_END, mp);
1357
1358   mp->table.table_id = ntohl (table_id);
1359   mp->table.is_ip6 = is_ipv6;
1360
1361   S (mp);
1362   W (ret);
1363   return ret;
1364 }
1365
1366 static int
1367 api_ip_table_dump (vat_main_t *vam)
1368 {
1369   vl_api_ip_table_dump_t *mp;
1370   vl_api_control_ping_t *mp_ping;
1371   int ret;
1372
1373   M (IP_TABLE_DUMP, mp);
1374   S (mp);
1375
1376   /* Use a control ping for synchronization */
1377   PING (&ip_test_main, mp_ping);
1378   S (mp_ping);
1379
1380   W (ret);
1381   return ret;
1382 }
1383
1384 static void
1385 vl_api_ip_table_details_t_handler (vl_api_ip_table_details_t *mp)
1386 {
1387   vat_main_t *vam = ip_test_main.vat_main;
1388
1389   fformat (vam->ofp, "%s; table-id %d, prefix %U/%d", mp->table.name,
1390            ntohl (mp->table.table_id));
1391   vam->result_ready = 1;
1392 }
1393
1394 static int
1395 api_ip_path_mtu_get (vat_main_t *vat)
1396 {
1397   return -1;
1398 }
1399
1400 static int
1401 api_ip_route_v2_dump (vat_main_t *vat)
1402 {
1403   return -1;
1404 }
1405
1406 static void
1407 vl_api_ip_path_mtu_get_reply_t_handler (vl_api_ip_path_mtu_get_reply_t *mp)
1408 {
1409 }
1410
1411 static int
1412 api_ip_route_dump (vat_main_t *vam)
1413 {
1414   unformat_input_t *input = vam->input;
1415   vl_api_ip_route_dump_t *mp;
1416   vl_api_control_ping_t *mp_ping;
1417   u32 table_id;
1418   u8 is_ip6;
1419   int ret;
1420
1421   is_ip6 = 0;
1422   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1423     {
1424       if (unformat (input, "table_id %d", &table_id))
1425         ;
1426       else if (unformat (input, "ip6"))
1427         is_ip6 = 1;
1428       else if (unformat (input, "ip4"))
1429         is_ip6 = 0;
1430       else
1431         break;
1432     }
1433   if (table_id == ~0)
1434     {
1435       errmsg ("missing table id");
1436       return -99;
1437     }
1438
1439   M (IP_ROUTE_DUMP, mp);
1440
1441   mp->table.table_id = table_id;
1442   mp->table.is_ip6 = is_ip6;
1443
1444   S (mp);
1445
1446   /* Use a control ping for synchronization */
1447   PING (&ip_test_main, mp_ping);
1448   S (mp_ping);
1449
1450   W (ret);
1451   return ret;
1452 }
1453
1454 static void
1455 vl_api_ip_address_details_t_handler (vl_api_ip_address_details_t *mp)
1456 {
1457   vat_main_t *vam = ip_test_main.vat_main;
1458   static ip_address_details_t empty_ip_address_details = { { 0 } };
1459   ip_address_details_t *address = NULL;
1460   ip_details_t *current_ip_details = NULL;
1461   ip_details_t *details = NULL;
1462
1463   details = vam->ip_details_by_sw_if_index[vam->is_ipv6];
1464
1465   if (!details || vam->current_sw_if_index >= vec_len (details) ||
1466       !details[vam->current_sw_if_index].present)
1467     {
1468       errmsg ("ip address details arrived but not stored");
1469       errmsg ("ip_dump should be called first");
1470       return;
1471     }
1472
1473   current_ip_details = vec_elt_at_index (details, vam->current_sw_if_index);
1474
1475 #define addresses (current_ip_details->addr)
1476
1477   vec_validate_init_empty (addresses, vec_len (addresses),
1478                            empty_ip_address_details);
1479
1480   address = vec_elt_at_index (addresses, vec_len (addresses) - 1);
1481
1482   clib_memcpy (&address->ip, &mp->prefix.address.un, sizeof (address->ip));
1483   address->prefix_length = mp->prefix.len;
1484 #undef addresses
1485 }
1486
1487 static int
1488 api_ip_unnumbered_dump (vat_main_t *vam)
1489 {
1490   return -1;
1491 }
1492
1493 static void
1494 vl_api_ip_unnumbered_details_t_handler (vl_api_ip_unnumbered_details_t *mp)
1495 {
1496 }
1497
1498 static void
1499 vl_api_ip_details_t_handler (vl_api_ip_details_t *mp)
1500 {
1501   vat_main_t *vam = &vat_main;
1502   static ip_details_t empty_ip_details = { 0 };
1503   ip_details_t *ip = NULL;
1504   u32 sw_if_index = ~0;
1505
1506   sw_if_index = ntohl (mp->sw_if_index);
1507
1508   vec_validate_init_empty (vam->ip_details_by_sw_if_index[vam->is_ipv6],
1509                            sw_if_index, empty_ip_details);
1510
1511   ip = vec_elt_at_index (vam->ip_details_by_sw_if_index[vam->is_ipv6],
1512                          sw_if_index);
1513
1514   ip->present = 1;
1515 }
1516
1517 #include <vnet/ip/ip.api_test.c>
1518
1519 VAT_REGISTER_FEATURE_FUNCTION (vat_ip_plugin_register);
1520
1521 /*
1522  * fd.io coding-style-patch-verification: ON
1523  *
1524  * Local Variables:
1525  * eval: (c-set-style "gnu")
1526  * End:
1527  */