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