blob: 8c10b95b0c159b5d5d0ce7b97736860b6b833e5f [file] [log] [blame]
Damjan Marion7cd468a2016-12-19 23:05:39 +01001/*
2 *------------------------------------------------------------------
3 * api_format.c
4 *
Dave Barachac0326f2020-07-14 18:30:05 -04005 * Copyright (c) 2014-2020 Cisco and/or its affiliates.
Damjan Marion7cd468a2016-12-19 23:05:39 +01006 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
18 */
19
20#include <vat/vat.h>
jialv01082ebeb2019-09-10 00:23:55 +080021#include <vlib/pci/pci.h>
Neale Ranns86327be2018-11-02 09:14:01 -070022#include <vpp/api/types.h>
Dave Barach59b25652017-09-10 15:04:27 -040023#include <vppinfra/socket.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010024#include <vlibapi/api.h>
25#include <vlibmemory/api.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010026#include <vnet/ip/ip.h>
Neale Rannscbe25aa2019-09-30 10:53:31 +000027#include <vnet/ip-neighbor/ip_neighbor.h>
Neale Ranns37029302018-08-10 05:30:06 -070028#include <vnet/ip/ip_types_api.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010029#include <vnet/l2/l2_input.h>
Florin Corasb040f982020-10-20 14:59:43 -070030#include <vnet/udp/udp_local.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010031
32#include <vpp/api/vpe_msg_enum.h>
33#include <vnet/l2/l2_classify.h>
34#include <vnet/l2/l2_vtr.h>
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +010035#include <vnet/classify/in_out_acl.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010036#include <vnet/classify/policer_classify.h>
37#include <vnet/classify/flow_classify.h>
38#include <vnet/mpls/mpls.h>
39#include <vnet/ipsec/ipsec.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010040#include <inttypes.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010041#include <vnet/ip/ip6_hop_by_hop.h>
42#include <vnet/ip/ip_source_and_port_range_check.h>
43#include <vnet/policer/xlate.h>
44#include <vnet/span/span.h>
45#include <vnet/policer/policer.h>
46#include <vnet/policer/police.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000047#include <vnet/mfib/mfib_types.h>
Steven9cd2d7a2017-12-20 12:43:01 -080048#include <vnet/bonding/node.h>
Igor Mikhailov (imichail)582caa32018-04-26 21:33:02 -070049#include <vnet/qos/qos_types.h>
Neale Ranns37029302018-08-10 05:30:06 -070050#include <vnet/ethernet/ethernet_types_api.h>
51#include <vnet/ip/ip_types_api.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010052#include "vat/json_format.h"
Neale Ranns86327be2018-11-02 09:14:01 -070053#include <vnet/ip/ip_types_api.h>
54#include <vnet/ethernet/ethernet_types_api.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010055
56#include <inttypes.h>
57#include <sys/stat.h>
58
59#define vl_typedefs /* define message structures */
60#include <vpp/api/vpe_all_api_h.h>
61#undef vl_typedefs
62
63/* declare message handlers for each api */
64
65#define vl_endianfun /* define message structures */
66#include <vpp/api/vpe_all_api_h.h>
67#undef vl_endianfun
68
69/* instantiate all the print functions we know about */
Dave Barachf35a0722019-06-12 16:50:38 -040070#if VPP_API_TEST_BUILTIN == 0
Damjan Marion7cd468a2016-12-19 23:05:39 +010071#define vl_print(handle, ...)
Dave Barachf35a0722019-06-12 16:50:38 -040072#else
73#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
74#endif
Damjan Marion7cd468a2016-12-19 23:05:39 +010075#define vl_printfun
76#include <vpp/api/vpe_all_api_h.h>
77#undef vl_printfun
78
Dave Barach2d6b2d62017-01-25 16:32:08 -050079#define __plugin_msg_base 0
Dave Barachfe6bdfd2017-01-20 19:50:09 -050080#include <vlibapi/vat_helper_macros.h>
81
Dave Barachb09f4d02019-07-15 16:00:03 -040082void vl_api_set_elog_main (elog_main_t * m);
83int vl_api_set_elog_trace_api_messages (int enable);
84
Dave Barach59b25652017-09-10 15:04:27 -040085#if VPP_API_TEST_BUILTIN == 0
86#include <netdb.h>
87
88u32
89vl (void *p)
90{
91 return vec_len (p);
92}
93
94int
95vat_socket_connect (vat_main_t * vam)
96{
Florin Coras66a10032018-12-21 16:23:09 -080097 int rv;
Dave Barach69eeadc2020-04-14 09:52:26 -040098 api_main_t *am = vlibapi_get_main ();
Florin Coras90a63982017-12-19 04:50:01 -080099 vam->socket_client_main = &socket_client_main;
Florin Coras66a10032018-12-21 16:23:09 -0800100 if ((rv = vl_socket_client_connect ((char *) vam->socket_name,
101 "vpp_api_test",
102 0 /* default socket rx, tx buffer */ )))
103 return rv;
Dave Barach69eeadc2020-04-14 09:52:26 -0400104
Florin Coras66a10032018-12-21 16:23:09 -0800105 /* vpp expects the client index in network order */
106 vam->my_client_index = htonl (socket_client_main.client_index);
Dave Barach69eeadc2020-04-14 09:52:26 -0400107 am->my_client_index = vam->my_client_index;
Florin Coras66a10032018-12-21 16:23:09 -0800108 return 0;
Dave Barach59b25652017-09-10 15:04:27 -0400109}
110#else /* vpp built-in case, we don't do sockets... */
111int
112vat_socket_connect (vat_main_t * vam)
113{
114 return 0;
115}
116
Florin Coras90a63982017-12-19 04:50:01 -0800117int
118vl_socket_client_read (int wait)
Dave Barach59b25652017-09-10 15:04:27 -0400119{
Florin Coras90a63982017-12-19 04:50:01 -0800120 return -1;
Dave Barach59b25652017-09-10 15:04:27 -0400121};
Florin Coras90a63982017-12-19 04:50:01 -0800122
123int
124vl_socket_client_write ()
125{
126 return -1;
127};
128
129void *
130vl_socket_client_msg_alloc (int nbytes)
131{
132 return 0;
133}
Dave Barach59b25652017-09-10 15:04:27 -0400134#endif
135
136
Dave Barachfe6bdfd2017-01-20 19:50:09 -0500137f64
138vat_time_now (vat_main_t * vam)
139{
140#if VPP_API_TEST_BUILTIN
141 return vlib_time_now (vam->vlib_main);
142#else
143 return clib_time_now (&vam->clib_time);
144#endif
145}
146
147void
148errmsg (char *fmt, ...)
149{
150 vat_main_t *vam = &vat_main;
151 va_list va;
152 u8 *s;
153
154 va_start (va, fmt);
155 s = va_format (0, fmt, &va);
156 va_end (va);
157
158 vec_add1 (s, 0);
159
160#if VPP_API_TEST_BUILTIN
161 vlib_cli_output (vam->vlib_main, (char *) s);
162#else
163 {
164 if (vam->ifp != stdin)
165 fformat (vam->ofp, "%s(%d): \n", vam->current_file,
166 vam->input_line_number);
Dave Barachb09f4d02019-07-15 16:00:03 -0400167 else
168 fformat (vam->ofp, "%s\n", (char *) s);
Dave Barachfe6bdfd2017-01-20 19:50:09 -0500169 fflush (vam->ofp);
170 }
171#endif
172
173 vec_free (s);
174}
175
Dave Barach4a3f69c2017-02-22 12:44:56 -0500176#if VPP_API_TEST_BUILTIN == 0
Damjan Marion7cd468a2016-12-19 23:05:39 +0100177static uword
178api_unformat_sw_if_index (unformat_input_t * input, va_list * args)
179{
180 vat_main_t *vam = va_arg (*args, vat_main_t *);
181 u32 *result = va_arg (*args, u32 *);
182 u8 *if_name;
183 uword *p;
184
185 if (!unformat (input, "%s", &if_name))
186 return 0;
187
188 p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name);
189 if (p == 0)
190 return 0;
191 *result = p[0];
192 return 1;
193}
194
Damjan Marion7cd468a2016-12-19 23:05:39 +0100195/* Parse an IP4 address %d.%d.%d.%d. */
196uword
197unformat_ip4_address (unformat_input_t * input, va_list * args)
198{
199 u8 *result = va_arg (*args, u8 *);
200 unsigned a[4];
201
202 if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]))
203 return 0;
204
205 if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256)
206 return 0;
207
208 result[0] = a[0];
209 result[1] = a[1];
210 result[2] = a[2];
211 result[3] = a[3];
212
213 return 1;
214}
215
216uword
217unformat_ethernet_address (unformat_input_t * input, va_list * args)
218{
219 u8 *result = va_arg (*args, u8 *);
220 u32 i, a[6];
221
222 if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_",
223 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
224 return 0;
225
226 /* Check range. */
227 for (i = 0; i < 6; i++)
228 if (a[i] >= (1 << 8))
229 return 0;
230
231 for (i = 0; i < 6; i++)
232 result[i] = a[i];
233
234 return 1;
235}
236
237/* Returns ethernet type as an int in host byte order. */
238uword
239unformat_ethernet_type_host_byte_order (unformat_input_t * input,
240 va_list * args)
241{
242 u16 *result = va_arg (*args, u16 *);
243 int type;
244
245 /* Numeric type. */
246 if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type))
247 {
248 if (type >= (1 << 16))
249 return 0;
250 *result = type;
251 return 1;
252 }
253 return 0;
254}
255
Jakub Grajciar23a386b2020-02-26 11:01:43 +0100256/* Parse an IP46 address. */
257uword
258unformat_ip46_address (unformat_input_t * input, va_list * args)
259{
260 ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
261 ip46_type_t type = va_arg (*args, ip46_type_t);
262 if ((type != IP46_TYPE_IP6) &&
263 unformat (input, "%U", unformat_ip4_address, &ip46->ip4))
264 {
265 ip46_address_mask_ip4 (ip46);
266 return 1;
267 }
268 else if ((type != IP46_TYPE_IP4) &&
269 unformat (input, "%U", unformat_ip6_address, &ip46->ip6))
270 {
271 return 1;
272 }
273 return 0;
274}
275
Damjan Marion7cd468a2016-12-19 23:05:39 +0100276/* Parse an IP6 address. */
277uword
278unformat_ip6_address (unformat_input_t * input, va_list * args)
279{
280 ip6_address_t *result = va_arg (*args, ip6_address_t *);
281 u16 hex_quads[8];
282 uword hex_quad, n_hex_quads, hex_digit, n_hex_digits;
283 uword c, n_colon, double_colon_index;
284
285 n_hex_quads = hex_quad = n_hex_digits = n_colon = 0;
286 double_colon_index = ARRAY_LEN (hex_quads);
287 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
288 {
289 hex_digit = 16;
290 if (c >= '0' && c <= '9')
291 hex_digit = c - '0';
292 else if (c >= 'a' && c <= 'f')
293 hex_digit = c + 10 - 'a';
294 else if (c >= 'A' && c <= 'F')
295 hex_digit = c + 10 - 'A';
296 else if (c == ':' && n_colon < 2)
297 n_colon++;
298 else
299 {
300 unformat_put_input (input);
301 break;
302 }
303
304 /* Too many hex quads. */
305 if (n_hex_quads >= ARRAY_LEN (hex_quads))
306 return 0;
307
308 if (hex_digit < 16)
309 {
310 hex_quad = (hex_quad << 4) | hex_digit;
311
312 /* Hex quad must fit in 16 bits. */
313 if (n_hex_digits >= 4)
314 return 0;
315
316 n_colon = 0;
317 n_hex_digits++;
318 }
319
320 /* Save position of :: */
321 if (n_colon == 2)
322 {
323 /* More than one :: ? */
324 if (double_colon_index < ARRAY_LEN (hex_quads))
325 return 0;
326 double_colon_index = n_hex_quads;
327 }
328
329 if (n_colon > 0 && n_hex_digits > 0)
330 {
331 hex_quads[n_hex_quads++] = hex_quad;
332 hex_quad = 0;
333 n_hex_digits = 0;
334 }
335 }
336
337 if (n_hex_digits > 0)
338 hex_quads[n_hex_quads++] = hex_quad;
339
340 {
341 word i;
342
343 /* Expand :: to appropriate number of zero hex quads. */
344 if (double_colon_index < ARRAY_LEN (hex_quads))
345 {
346 word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads;
347
348 for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--)
349 hex_quads[n_zero + i] = hex_quads[i];
350
351 for (i = 0; i < n_zero; i++)
352 hex_quads[double_colon_index + i] = 0;
353
354 n_hex_quads = ARRAY_LEN (hex_quads);
355 }
356
357 /* Too few hex quads given. */
358 if (n_hex_quads < ARRAY_LEN (hex_quads))
359 return 0;
360
361 for (i = 0; i < ARRAY_LEN (hex_quads); i++)
362 result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]);
363
364 return 1;
365 }
366}
367
368uword
369unformat_ipsec_policy_action (unformat_input_t * input, va_list * args)
370{
371 u32 *r = va_arg (*args, u32 *);
372
373 if (0);
374#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_POLICY_ACTION_##f;
375 foreach_ipsec_policy_action
376#undef _
377 else
378 return 0;
379 return 1;
380}
381
Damjan Marion7cd468a2016-12-19 23:05:39 +0100382u8 *
383format_ipsec_crypto_alg (u8 * s, va_list * args)
384{
385 u32 i = va_arg (*args, u32);
386 u8 *t = 0;
387
388 switch (i)
389 {
390#define _(v,f,str) case IPSEC_CRYPTO_ALG_##f: t = (u8 *) str; break;
391 foreach_ipsec_crypto_alg
392#undef _
393 default:
394 return format (s, "unknown");
395 }
396 return format (s, "%s", t);
397}
398
Damjan Marion7cd468a2016-12-19 23:05:39 +0100399u8 *
400format_ipsec_integ_alg (u8 * s, va_list * args)
401{
402 u32 i = va_arg (*args, u32);
403 u8 *t = 0;
404
405 switch (i)
406 {
407#define _(v,f,str) case IPSEC_INTEG_ALG_##f: t = (u8 *) str; break;
408 foreach_ipsec_integ_alg
409#undef _
410 default:
411 return format (s, "unknown");
412 }
413 return format (s, "%s", t);
414}
415
Dave Barach4a3f69c2017-02-22 12:44:56 -0500416#else /* VPP_API_TEST_BUILTIN == 1 */
417static uword
418api_unformat_sw_if_index (unformat_input_t * input, va_list * args)
419{
Benoît Ganne49ee6842019-04-30 11:50:46 +0200420 vat_main_t *vam __clib_unused = va_arg (*args, vat_main_t *);
Dave Barach4a3f69c2017-02-22 12:44:56 -0500421 vnet_main_t *vnm = vnet_get_main ();
422 u32 *result = va_arg (*args, u32 *);
Dave Barach4a3f69c2017-02-22 12:44:56 -0500423
eyal bariaf86a482018-04-17 11:20:27 +0300424 return unformat (input, "%U", unformat_vnet_sw_interface, vnm, result);
Dave Barach4a3f69c2017-02-22 12:44:56 -0500425}
eyal bariaf86a482018-04-17 11:20:27 +0300426
Damjan Marion7cd468a2016-12-19 23:05:39 +0100427#endif /* VPP_API_TEST_BUILTIN */
428
Benoît Ganne49ee6842019-04-30 11:50:46 +0200429#if (VPP_API_TEST_BUILTIN==0)
430
Neale Ranns32e1c012016-11-22 17:07:28 +0000431static const char *mfib_flag_names[] = MFIB_ENTRY_NAMES_SHORT;
432static const char *mfib_flag_long_names[] = MFIB_ENTRY_NAMES_LONG;
433static const char *mfib_itf_flag_long_names[] = MFIB_ITF_NAMES_LONG;
434static const char *mfib_itf_flag_names[] = MFIB_ITF_NAMES_SHORT;
435
436uword
437unformat_mfib_itf_flags (unformat_input_t * input, va_list * args)
438{
439 mfib_itf_flags_t old, *iflags = va_arg (*args, mfib_itf_flags_t *);
440 mfib_itf_attribute_t attr;
441
442 old = *iflags;
443 FOR_EACH_MFIB_ITF_ATTRIBUTE (attr)
444 {
445 if (unformat (input, mfib_itf_flag_long_names[attr]))
446 *iflags |= (1 << attr);
447 }
448 FOR_EACH_MFIB_ITF_ATTRIBUTE (attr)
449 {
450 if (unformat (input, mfib_itf_flag_names[attr]))
451 *iflags |= (1 << attr);
452 }
453
454 return (old == *iflags ? 0 : 1);
455}
456
457uword
458unformat_mfib_entry_flags (unformat_input_t * input, va_list * args)
459{
460 mfib_entry_flags_t old, *eflags = va_arg (*args, mfib_entry_flags_t *);
461 mfib_entry_attribute_t attr;
462
463 old = *eflags;
464 FOR_EACH_MFIB_ATTRIBUTE (attr)
465 {
466 if (unformat (input, mfib_flag_long_names[attr]))
467 *eflags |= (1 << attr);
468 }
469 FOR_EACH_MFIB_ATTRIBUTE (attr)
470 {
471 if (unformat (input, mfib_flag_names[attr]))
472 *eflags |= (1 << attr);
473 }
474
475 return (old == *eflags ? 0 : 1);
476}
477
Damjan Marion7cd468a2016-12-19 23:05:39 +0100478u8 *
479format_ip4_address (u8 * s, va_list * args)
480{
481 u8 *a = va_arg (*args, u8 *);
482 return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
483}
484
485u8 *
486format_ip6_address (u8 * s, va_list * args)
487{
488 ip6_address_t *a = va_arg (*args, ip6_address_t *);
489 u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
490
491 i_max_n_zero = ARRAY_LEN (a->as_u16);
492 max_n_zeros = 0;
493 i_first_zero = i_max_n_zero;
494 n_zeros = 0;
495 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
496 {
497 u32 is_zero = a->as_u16[i] == 0;
498 if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
499 {
500 i_first_zero = i;
501 n_zeros = 0;
502 }
503 n_zeros += is_zero;
504 if ((!is_zero && n_zeros > max_n_zeros)
505 || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
506 {
507 i_max_n_zero = i_first_zero;
508 max_n_zeros = n_zeros;
509 i_first_zero = ARRAY_LEN (a->as_u16);
510 n_zeros = 0;
511 }
512 }
513
514 last_double_colon = 0;
515 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
516 {
517 if (i == i_max_n_zero && max_n_zeros > 1)
518 {
519 s = format (s, "::");
520 i += max_n_zeros - 1;
521 last_double_colon = 1;
522 }
523 else
524 {
525 s = format (s, "%s%x",
526 (last_double_colon || i == 0) ? "" : ":",
527 clib_net_to_host_u16 (a->as_u16[i]));
528 last_double_colon = 0;
529 }
530 }
531
532 return s;
533}
534
535/* Format an IP46 address. */
536u8 *
537format_ip46_address (u8 * s, va_list * args)
538{
539 ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
540 ip46_type_t type = va_arg (*args, ip46_type_t);
541 int is_ip4 = 1;
542
543 switch (type)
544 {
545 case IP46_TYPE_ANY:
546 is_ip4 = ip46_address_is_ip4 (ip46);
547 break;
548 case IP46_TYPE_IP4:
549 is_ip4 = 1;
550 break;
551 case IP46_TYPE_IP6:
552 is_ip4 = 0;
553 break;
554 }
555
556 return is_ip4 ?
557 format (s, "%U", format_ip4_address, &ip46->ip4) :
558 format (s, "%U", format_ip6_address, &ip46->ip6);
559}
560
561u8 *
562format_ethernet_address (u8 * s, va_list * args)
563{
564 u8 *a = va_arg (*args, u8 *);
565
566 return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
567 a[0], a[1], a[2], a[3], a[4], a[5]);
568}
569#endif
570
Jakub Grajciar23a386b2020-02-26 11:01:43 +0100571void
572ip_set (ip46_address_t * dst, void *src, u8 is_ip4)
573{
574 if (is_ip4)
575 dst->ip4.as_u32 = ((ip4_address_t *) src)->as_u32;
576 else
577 clib_memcpy_fast (&dst->ip6, (ip6_address_t *) src,
578 sizeof (ip6_address_t));
579}
580
Neale Ranns097fa662018-05-01 05:17:55 -0700581
Damjan Marion7cd468a2016-12-19 23:05:39 +0100582static void
583vl_api_cli_reply_t_handler (vl_api_cli_reply_t * mp)
584{
585 vat_main_t *vam = &vat_main;
586 i32 retval = ntohl (mp->retval);
587
588 vam->retval = retval;
Damjan Marion7bee80c2017-04-26 15:32:12 +0200589 vam->shmem_result = uword_to_pointer (mp->reply_in_shmem, u8 *);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100590 vam->result_ready = 1;
591}
592
593static void
594vl_api_cli_reply_t_handler_json (vl_api_cli_reply_t * mp)
595{
596 vat_main_t *vam = &vat_main;
597 vat_json_node_t node;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100598 void *oldheap;
599 u8 *reply;
600
601 vat_json_init_object (&node);
602 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
603 vat_json_object_add_uint (&node, "reply_in_shmem",
604 ntohl (mp->reply_in_shmem));
605 /* Toss the shared-memory original... */
Nathan Skrzypczak0aa40132019-11-25 16:29:38 +0100606 oldheap = vl_msg_push_heap ();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100607
Damjan Marion7bee80c2017-04-26 15:32:12 +0200608 reply = uword_to_pointer (mp->reply_in_shmem, u8 *);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100609 vec_free (reply);
610
Nathan Skrzypczak0aa40132019-11-25 16:29:38 +0100611 vl_msg_pop_heap (oldheap);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100612
613 vat_json_print (vam->ofp, &node);
614 vat_json_free (&node);
615
616 vam->retval = ntohl (mp->retval);
617 vam->result_ready = 1;
618}
619
620static void
621vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t * mp)
622{
623 vat_main_t *vam = &vat_main;
624 i32 retval = ntohl (mp->retval);
Dave Barach59b25652017-09-10 15:04:27 -0400625
626 vec_reset_length (vam->cmd_reply);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100627
628 vam->retval = retval;
Dave Barach59b25652017-09-10 15:04:27 -0400629 if (retval == 0)
Dave Barach77841402020-04-29 17:04:10 -0400630 vam->cmd_reply = vl_api_from_api_to_new_vec (mp, &mp->reply);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100631 vam->result_ready = 1;
632}
633
634static void
635vl_api_cli_inband_reply_t_handler_json (vl_api_cli_inband_reply_t * mp)
636{
637 vat_main_t *vam = &vat_main;
638 vat_json_node_t node;
Jakub Grajciar2dbee932020-02-07 11:30:26 +0100639 u8 *reply = 0; /* reply vector */
Damjan Marion7cd468a2016-12-19 23:05:39 +0100640
Dave Barach77841402020-04-29 17:04:10 -0400641 reply = vl_api_from_api_to_new_vec (mp, &mp->reply);
Dave Barach59b25652017-09-10 15:04:27 -0400642 vec_reset_length (vam->cmd_reply);
643
Damjan Marion7cd468a2016-12-19 23:05:39 +0100644 vat_json_init_object (&node);
645 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
Jakub Grajciar2dbee932020-02-07 11:30:26 +0100646 vat_json_object_add_string_copy (&node, "reply", reply);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100647
648 vat_json_print (vam->ofp, &node);
649 vat_json_free (&node);
Jakub Grajciar2dbee932020-02-07 11:30:26 +0100650 vec_free (reply);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100651
652 vam->retval = ntohl (mp->retval);
653 vam->result_ready = 1;
654}
655
Damjan Marion7cd468a2016-12-19 23:05:39 +0100656static void vl_api_get_node_index_reply_t_handler
657 (vl_api_get_node_index_reply_t * mp)
658{
659 vat_main_t *vam = &vat_main;
660 i32 retval = ntohl (mp->retval);
661 if (vam->async_mode)
662 {
663 vam->async_errors += (retval < 0);
664 }
665 else
666 {
667 vam->retval = retval;
668 if (retval == 0)
669 errmsg ("node index %d", ntohl (mp->node_index));
670 vam->result_ready = 1;
671 }
672}
673
674static void vl_api_get_node_index_reply_t_handler_json
675 (vl_api_get_node_index_reply_t * mp)
676{
677 vat_main_t *vam = &vat_main;
678 vat_json_node_t node;
679
680 vat_json_init_object (&node);
681 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
682 vat_json_object_add_uint (&node, "node_index", ntohl (mp->node_index));
683
684 vat_json_print (vam->ofp, &node);
685 vat_json_free (&node);
686
687 vam->retval = ntohl (mp->retval);
688 vam->result_ready = 1;
689}
690
691static void vl_api_get_next_index_reply_t_handler
692 (vl_api_get_next_index_reply_t * mp)
693{
694 vat_main_t *vam = &vat_main;
695 i32 retval = ntohl (mp->retval);
696 if (vam->async_mode)
697 {
698 vam->async_errors += (retval < 0);
699 }
700 else
701 {
702 vam->retval = retval;
703 if (retval == 0)
704 errmsg ("next node index %d", ntohl (mp->next_index));
705 vam->result_ready = 1;
706 }
707}
708
709static void vl_api_get_next_index_reply_t_handler_json
710 (vl_api_get_next_index_reply_t * mp)
711{
712 vat_main_t *vam = &vat_main;
713 vat_json_node_t node;
714
715 vat_json_init_object (&node);
716 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
717 vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index));
718
719 vat_json_print (vam->ofp, &node);
720 vat_json_free (&node);
721
722 vam->retval = ntohl (mp->retval);
723 vam->result_ready = 1;
724}
725
726static void vl_api_add_node_next_reply_t_handler
727 (vl_api_add_node_next_reply_t * mp)
728{
729 vat_main_t *vam = &vat_main;
730 i32 retval = ntohl (mp->retval);
731 if (vam->async_mode)
732 {
733 vam->async_errors += (retval < 0);
734 }
735 else
736 {
737 vam->retval = retval;
738 if (retval == 0)
739 errmsg ("next index %d", ntohl (mp->next_index));
740 vam->result_ready = 1;
741 }
742}
743
744static void vl_api_add_node_next_reply_t_handler_json
745 (vl_api_add_node_next_reply_t * mp)
746{
747 vat_main_t *vam = &vat_main;
748 vat_json_node_t node;
749
750 vat_json_init_object (&node);
751 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
752 vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index));
753
754 vat_json_print (vam->ofp, &node);
755 vat_json_free (&node);
756
757 vam->retval = ntohl (mp->retval);
758 vam->result_ready = 1;
759}
760
761static void vl_api_show_version_reply_t_handler
762 (vl_api_show_version_reply_t * mp)
763{
764 vat_main_t *vam = &vat_main;
765 i32 retval = ntohl (mp->retval);
766
767 if (retval >= 0)
768 {
Ole Troane5ff5a32019-08-23 22:55:18 +0200769 errmsg (" program: %s", mp->program);
770 errmsg (" version: %s", mp->version);
771 errmsg (" build date: %s", mp->build_date);
772 errmsg ("build directory: %s", mp->build_directory);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100773 }
774 vam->retval = retval;
775 vam->result_ready = 1;
776}
777
778static void vl_api_show_version_reply_t_handler_json
779 (vl_api_show_version_reply_t * mp)
780{
781 vat_main_t *vam = &vat_main;
782 vat_json_node_t node;
783
784 vat_json_init_object (&node);
785 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
Ole Troane5ff5a32019-08-23 22:55:18 +0200786 vat_json_object_add_string_copy (&node, "program", mp->program);
787 vat_json_object_add_string_copy (&node, "version", mp->version);
788 vat_json_object_add_string_copy (&node, "build_date", mp->build_date);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100789 vat_json_object_add_string_copy (&node, "build_directory",
Ole Troane5ff5a32019-08-23 22:55:18 +0200790 mp->build_directory);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100791
792 vat_json_print (vam->ofp, &node);
793 vat_json_free (&node);
794
795 vam->retval = ntohl (mp->retval);
796 vam->result_ready = 1;
797}
798
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200799static void vl_api_show_threads_reply_t_handler
800 (vl_api_show_threads_reply_t * mp)
801{
802 vat_main_t *vam = &vat_main;
803 i32 retval = ntohl (mp->retval);
804 int i, count = 0;
805
806 if (retval >= 0)
807 count = ntohl (mp->count);
808
809 for (i = 0; i < count; i++)
810 print (vam->ofp,
811 "\n%-2d %-11s %-11s %-5d %-6d %-4d %-6d",
812 ntohl (mp->thread_data[i].id), mp->thread_data[i].name,
813 mp->thread_data[i].type, ntohl (mp->thread_data[i].pid),
814 ntohl (mp->thread_data[i].cpu_id), ntohl (mp->thread_data[i].core),
815 ntohl (mp->thread_data[i].cpu_socket));
816
817 vam->retval = retval;
818 vam->result_ready = 1;
819}
820
821static void vl_api_show_threads_reply_t_handler_json
822 (vl_api_show_threads_reply_t * mp)
823{
824 vat_main_t *vam = &vat_main;
825 vat_json_node_t node;
826 vl_api_thread_data_t *td;
Mohsin Kazmi5df628b2018-10-01 17:41:08 +0200827 i32 retval = ntohl (mp->retval);
828 int i, count = 0;
829
830 if (retval >= 0)
831 count = ntohl (mp->count);
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200832
833 vat_json_init_object (&node);
Mohsin Kazmi5df628b2018-10-01 17:41:08 +0200834 vat_json_object_add_int (&node, "retval", retval);
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200835 vat_json_object_add_uint (&node, "count", count);
836
837 for (i = 0; i < count; i++)
838 {
839 td = &mp->thread_data[i];
840 vat_json_object_add_uint (&node, "id", ntohl (td->id));
841 vat_json_object_add_string_copy (&node, "name", td->name);
842 vat_json_object_add_string_copy (&node, "type", td->type);
843 vat_json_object_add_uint (&node, "pid", ntohl (td->pid));
844 vat_json_object_add_int (&node, "cpu_id", ntohl (td->cpu_id));
845 vat_json_object_add_int (&node, "core", ntohl (td->id));
846 vat_json_object_add_int (&node, "cpu_socket", ntohl (td->cpu_socket));
847 }
848
849 vat_json_print (vam->ofp, &node);
850 vat_json_free (&node);
851
Mohsin Kazmi5df628b2018-10-01 17:41:08 +0200852 vam->retval = retval;
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200853 vam->result_ready = 1;
854}
855
856static int
857api_show_threads (vat_main_t * vam)
858{
859 vl_api_show_threads_t *mp;
860 int ret;
861
862 print (vam->ofp,
863 "\n%-2s %-11s %-11s %-5s %-6s %-4s %-6s",
864 "ID", "Name", "Type", "LWP", "cpu_id", "Core", "Socket");
865
866 M (SHOW_THREADS, mp);
867
868 S (mp);
869 W (ret);
870 return ret;
871}
872
Ole Troan01384fe2017-05-12 11:55:35 +0200873#define vl_api_bridge_domain_details_t_endian vl_noop_handler
874#define vl_api_bridge_domain_details_t_print vl_noop_handler
875
Damjan Marion7cd468a2016-12-19 23:05:39 +0100876static void vl_api_control_ping_reply_t_handler
877 (vl_api_control_ping_reply_t * mp)
878{
879 vat_main_t *vam = &vat_main;
880 i32 retval = ntohl (mp->retval);
881 if (vam->async_mode)
882 {
883 vam->async_errors += (retval < 0);
884 }
885 else
886 {
887 vam->retval = retval;
888 vam->result_ready = 1;
889 }
Florin Coras90a63982017-12-19 04:50:01 -0800890 if (vam->socket_client_main)
891 vam->socket_client_main->control_pings_outstanding--;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100892}
893
894static void vl_api_control_ping_reply_t_handler_json
895 (vl_api_control_ping_reply_t * mp)
896{
897 vat_main_t *vam = &vat_main;
898 i32 retval = ntohl (mp->retval);
899
900 if (VAT_JSON_NONE != vam->json_tree.type)
901 {
902 vat_json_print (vam->ofp, &vam->json_tree);
903 vat_json_free (&vam->json_tree);
904 vam->json_tree.type = VAT_JSON_NONE;
905 }
906 else
907 {
908 /* just print [] */
909 vat_json_init_array (&vam->json_tree);
910 vat_json_print (vam->ofp, &vam->json_tree);
911 vam->json_tree.type = VAT_JSON_NONE;
912 }
913
914 vam->retval = retval;
915 vam->result_ready = 1;
916}
917
Damjan Marion7cd468a2016-12-19 23:05:39 +0100918
Damjan Marion7cd468a2016-12-19 23:05:39 +0100919static void vl_api_get_first_msg_id_reply_t_handler
920 (vl_api_get_first_msg_id_reply_t * mp)
921{
922 vat_main_t *vam = &vat_main;
923 i32 retval = ntohl (mp->retval);
924
925 if (vam->async_mode)
926 {
927 vam->async_errors += (retval < 0);
928 }
929 else
930 {
931 vam->retval = retval;
932 vam->result_ready = 1;
933 }
934 if (retval >= 0)
935 {
936 errmsg ("first message id %d", ntohs (mp->first_msg_id));
937 }
938}
939
940static void vl_api_get_first_msg_id_reply_t_handler_json
941 (vl_api_get_first_msg_id_reply_t * mp)
942{
943 vat_main_t *vam = &vat_main;
944 vat_json_node_t node;
945
946 vat_json_init_object (&node);
947 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
948 vat_json_object_add_uint (&node, "first_msg_id",
949 (uint) ntohs (mp->first_msg_id));
950
951 vat_json_print (vam->ofp, &node);
952 vat_json_free (&node);
953
954 vam->retval = ntohl (mp->retval);
955 vam->result_ready = 1;
956}
957
958static void vl_api_get_node_graph_reply_t_handler
959 (vl_api_get_node_graph_reply_t * mp)
960{
961 vat_main_t *vam = &vat_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100962 i32 retval = ntohl (mp->retval);
963 u8 *pvt_copy, *reply;
964 void *oldheap;
965 vlib_node_t *node;
966 int i;
967
968 if (vam->async_mode)
969 {
970 vam->async_errors += (retval < 0);
971 }
972 else
973 {
974 vam->retval = retval;
975 vam->result_ready = 1;
976 }
977
978 /* "Should never happen..." */
979 if (retval != 0)
980 return;
981
Damjan Marion7bee80c2017-04-26 15:32:12 +0200982 reply = uword_to_pointer (mp->reply_in_shmem, u8 *);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100983 pvt_copy = vec_dup (reply);
984
985 /* Toss the shared-memory original... */
Nathan Skrzypczak0aa40132019-11-25 16:29:38 +0100986 oldheap = vl_msg_push_heap ();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100987
988 vec_free (reply);
989
Nathan Skrzypczak0aa40132019-11-25 16:29:38 +0100990 vl_msg_pop_heap (oldheap);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100991
992 if (vam->graph_nodes)
993 {
994 hash_free (vam->graph_node_index_by_name);
995
Dave Barach1ddbc012018-06-13 09:26:05 -0400996 for (i = 0; i < vec_len (vam->graph_nodes[0]); i++)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100997 {
Dave Barach1ddbc012018-06-13 09:26:05 -0400998 node = vam->graph_nodes[0][i];
Damjan Marion7cd468a2016-12-19 23:05:39 +0100999 vec_free (node->name);
1000 vec_free (node->next_nodes);
1001 vec_free (node);
1002 }
Dave Barach1ddbc012018-06-13 09:26:05 -04001003 vec_free (vam->graph_nodes[0]);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001004 vec_free (vam->graph_nodes);
1005 }
1006
1007 vam->graph_node_index_by_name = hash_create_string (0, sizeof (uword));
1008 vam->graph_nodes = vlib_node_unserialize (pvt_copy);
1009 vec_free (pvt_copy);
1010
Dave Barach1ddbc012018-06-13 09:26:05 -04001011 for (i = 0; i < vec_len (vam->graph_nodes[0]); i++)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001012 {
Dave Barach1ddbc012018-06-13 09:26:05 -04001013 node = vam->graph_nodes[0][i];
Damjan Marion7cd468a2016-12-19 23:05:39 +01001014 hash_set_mem (vam->graph_node_index_by_name, node->name, i);
1015 }
1016}
1017
1018static void vl_api_get_node_graph_reply_t_handler_json
1019 (vl_api_get_node_graph_reply_t * mp)
1020{
1021 vat_main_t *vam = &vat_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001022 void *oldheap;
1023 vat_json_node_t node;
1024 u8 *reply;
1025
1026 /* $$$$ make this real? */
1027 vat_json_init_object (&node);
1028 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
1029 vat_json_object_add_uint (&node, "reply_in_shmem", mp->reply_in_shmem);
1030
Damjan Marion7bee80c2017-04-26 15:32:12 +02001031 reply = uword_to_pointer (mp->reply_in_shmem, u8 *);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001032
1033 /* Toss the shared-memory original... */
Nathan Skrzypczak0aa40132019-11-25 16:29:38 +01001034 oldheap = vl_msg_push_heap ();
Damjan Marion7cd468a2016-12-19 23:05:39 +01001035
1036 vec_free (reply);
1037
Nathan Skrzypczak0aa40132019-11-25 16:29:38 +01001038 vl_msg_pop_heap (oldheap);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001039
1040 vat_json_print (vam->ofp, &node);
1041 vat_json_free (&node);
1042
1043 vam->retval = ntohl (mp->retval);
1044 vam->result_ready = 1;
1045}
1046
Damjan Marion7cd468a2016-12-19 23:05:39 +01001047/* Format hex dump. */
1048u8 *
1049format_hex_bytes (u8 * s, va_list * va)
1050{
1051 u8 *bytes = va_arg (*va, u8 *);
1052 int n_bytes = va_arg (*va, int);
1053 uword i;
1054
1055 /* Print short or long form depending on byte count. */
1056 uword short_form = n_bytes <= 32;
Christophe Fontained3c008d2017-10-02 18:10:54 +02001057 u32 indent = format_get_indent (s);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001058
1059 if (n_bytes == 0)
1060 return s;
1061
1062 for (i = 0; i < n_bytes; i++)
1063 {
1064 if (!short_form && (i % 32) == 0)
1065 s = format (s, "%08x: ", i);
1066 s = format (s, "%02x", bytes[i]);
1067 if (!short_form && ((i + 1) % 32) == 0 && (i + 1) < n_bytes)
1068 s = format (s, "\n%U", format_white_space, indent);
1069 }
1070
1071 return s;
1072}
1073
Damjan Marion7cd468a2016-12-19 23:05:39 +01001074/*
1075 * Generate boilerplate reply handlers, which
1076 * dig the return value out of the xxx_reply_t API message,
1077 * stick it into vam->retval, and set vam->result_ready
1078 *
1079 * Could also do this by pointing N message decode slots at
1080 * a single function, but that could break in subtle ways.
1081 */
1082
Filip Tehlar0577ff12021-06-27 00:18:57 +00001083#define foreach_standard_reply_retval_handler _ (session_rule_add_del_reply)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001084
1085#define _(n) \
1086 static void vl_api_##n##_t_handler \
1087 (vl_api_##n##_t * mp) \
1088 { \
1089 vat_main_t * vam = &vat_main; \
1090 i32 retval = ntohl(mp->retval); \
1091 if (vam->async_mode) { \
1092 vam->async_errors += (retval < 0); \
1093 } else { \
1094 vam->retval = retval; \
1095 vam->result_ready = 1; \
1096 } \
1097 }
1098foreach_standard_reply_retval_handler;
1099#undef _
1100
1101#define _(n) \
1102 static void vl_api_##n##_t_handler_json \
1103 (vl_api_##n##_t * mp) \
1104 { \
1105 vat_main_t * vam = &vat_main; \
1106 vat_json_node_t node; \
1107 vat_json_init_object(&node); \
1108 vat_json_object_add_int(&node, "retval", ntohl(mp->retval)); \
1109 vat_json_print(vam->ofp, &node); \
1110 vam->retval = ntohl(mp->retval); \
1111 vam->result_ready = 1; \
1112 }
1113foreach_standard_reply_retval_handler;
1114#undef _
1115
1116/*
1117 * Table of message reply handlers, must include boilerplate handlers
1118 * we just generated
1119 */
1120
Filip Tehlar0577ff12021-06-27 00:18:57 +00001121#define foreach_vpe_api_reply_msg \
1122 _ (GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply) \
1123 _ (GET_NODE_GRAPH_REPLY, get_node_graph_reply) \
1124 _ (CONTROL_PING_REPLY, control_ping_reply) \
1125 _ (CLI_REPLY, cli_reply) \
1126 _ (CLI_INBAND_REPLY, cli_inband_reply) \
1127 _ (GET_NODE_INDEX_REPLY, get_node_index_reply) \
1128 _ (GET_NEXT_INDEX_REPLY, get_next_index_reply) \
1129 _ (ADD_NODE_NEXT_REPLY, add_node_next_reply) \
1130 _ (SHOW_VERSION_REPLY, show_version_reply) \
1131 _ (SHOW_THREADS_REPLY, show_threads_reply) \
1132 _ (APP_NAMESPACE_ADD_DEL_REPLY, app_namespace_add_del_reply) \
1133 _ (SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply) \
1134 _ (SESSION_RULES_DETAILS, session_rules_details)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001135
Dave Baracha1a093d2017-03-02 13:13:23 -05001136#define foreach_standalone_reply_msg \
Dave Baracha1a093d2017-03-02 13:13:23 -05001137
Damjan Marion7cd468a2016-12-19 23:05:39 +01001138typedef struct
1139{
1140 u8 *name;
1141 u32 value;
1142} name_sort_t;
1143
Damjan Marion7cd468a2016-12-19 23:05:39 +01001144#define STR_VTR_OP_CASE(op) \
1145 case L2_VTR_ ## op: \
1146 return "" # op;
1147
Damjan Marion7cd468a2016-12-19 23:05:39 +01001148/*
Dave Barach59b25652017-09-10 15:04:27 -04001149 * Pass CLI buffers directly in the CLI_INBAND API message,
1150 * instead of an additional shared memory area.
Damjan Marion7cd468a2016-12-19 23:05:39 +01001151 */
1152static int
1153exec_inband (vat_main_t * vam)
1154{
1155 vl_api_cli_inband_t *mp;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001156 unformat_input_t *i = vam->input;
Jon Loeliger56c7b012017-02-01 12:31:41 -06001157 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001158
1159 if (vec_len (i->buffer) == 0)
1160 return -1;
1161
1162 if (vam->exec_mode == 0 && unformat (i, "mode"))
1163 {
1164 vam->exec_mode = 1;
1165 return 0;
1166 }
1167 if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit")))
1168 {
1169 vam->exec_mode = 0;
1170 return 0;
1171 }
1172
1173 /*
1174 * In order for the CLI command to work, it
1175 * must be a vector ending in \n, not a C-string ending
1176 * in \n\0.
1177 */
Jakub Grajciar2dbee932020-02-07 11:30:26 +01001178 M2 (CLI_INBAND, mp, vec_len (vam->input->buffer));
1179 vl_api_vec_to_api_string (vam->input->buffer, &mp->cmd);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001180
Jon Loeliger7bc770c2017-01-31 14:03:33 -06001181 S (mp);
Dave Barach59b25652017-09-10 15:04:27 -04001182 W (ret);
1183 /* json responses may or may not include a useful reply... */
1184 if (vec_len (vam->cmd_reply))
Dave Barachcf5e8482017-10-17 11:48:29 -04001185 print (vam->ofp, "%v", (char *) (vam->cmd_reply));
Jon Loeliger56c7b012017-02-01 12:31:41 -06001186 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001187}
1188
Dave Barach59b25652017-09-10 15:04:27 -04001189int
Filip Tehlar0577ff12021-06-27 00:18:57 +00001190exec (vat_main_t *vam)
Dave Barach59b25652017-09-10 15:04:27 -04001191{
1192 return exec_inband (vam);
1193}
1194
Damjan Marion7cd468a2016-12-19 23:05:39 +01001195int
Filip Tehlar0577ff12021-06-27 00:18:57 +00001196api_sw_interface_dump (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001197{
Filip Tehlar0577ff12021-06-27 00:18:57 +00001198 return 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001199}
1200
Mohsin Kazmi03ae24b2019-01-18 11:50:00 +01001201uword
Filip Tehlar5a9d2a12021-06-22 21:20:29 +00001202unformat_vlib_pci_addr (unformat_input_t *input, va_list *args)
Mohsin Kazmi03ae24b2019-01-18 11:50:00 +01001203{
jialv01082ebeb2019-09-10 00:23:55 +08001204 vlib_pci_addr_t *addr = va_arg (*args, vlib_pci_addr_t *);
Mohsin Kazmi03ae24b2019-01-18 11:50:00 +01001205 u32 x[4];
1206
1207 if (!unformat (input, "%x:%x:%x.%x", &x[0], &x[1], &x[2], &x[3]))
1208 return 0;
1209
1210 addr->domain = x[0];
1211 addr->bus = x[1];
1212 addr->slot = x[2];
1213 addr->function = x[3];
1214
1215 return 1;
1216}
1217
Neale Ranns097fa662018-05-01 05:17:55 -07001218uword
Filip Tehlar5a9d2a12021-06-22 21:20:29 +00001219unformat_fib_path (unformat_input_t *input, va_list *args)
Neale Ranns097fa662018-05-01 05:17:55 -07001220{
1221 vat_main_t *vam = va_arg (*args, vat_main_t *);
1222 vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t *);
1223 u32 weight, preference;
1224 mpls_label_t out_label;
1225
1226 clib_memset (path, 0, sizeof (*path));
1227 path->weight = 1;
1228 path->sw_if_index = ~0;
1229 path->rpf_id = ~0;
1230 path->n_labels = 0;
1231
1232 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1233 {
Filip Tehlar5a9d2a12021-06-22 21:20:29 +00001234 if (unformat (input, "%U %U", unformat_vl_api_ip4_address,
1235 &path->nh.address.ip4, api_unformat_sw_if_index, vam,
1236 &path->sw_if_index))
Neale Ranns097fa662018-05-01 05:17:55 -07001237 {
1238 path->proto = FIB_API_PATH_NH_PROTO_IP4;
1239 }
1240 else if (unformat (input, "%U %U",
1241 unformat_vl_api_ip6_address,
1242 &path->nh.address.ip6,
1243 api_unformat_sw_if_index, vam, &path->sw_if_index))
1244 {
1245 path->proto = FIB_API_PATH_NH_PROTO_IP6;
1246 }
1247 else if (unformat (input, "weight %u", &weight))
1248 {
1249 path->weight = weight;
1250 }
1251 else if (unformat (input, "preference %u", &preference))
1252 {
1253 path->preference = preference;
1254 }
1255 else if (unformat (input, "%U next-hop-table %d",
1256 unformat_vl_api_ip4_address,
1257 &path->nh.address.ip4, &path->table_id))
1258 {
1259 path->proto = FIB_API_PATH_NH_PROTO_IP4;
1260 }
1261 else if (unformat (input, "%U next-hop-table %d",
1262 unformat_vl_api_ip6_address,
1263 &path->nh.address.ip6, &path->table_id))
1264 {
1265 path->proto = FIB_API_PATH_NH_PROTO_IP6;
1266 }
1267 else if (unformat (input, "%U",
1268 unformat_vl_api_ip4_address, &path->nh.address.ip4))
1269 {
1270 /*
1271 * the recursive next-hops are by default in the default table
1272 */
1273 path->table_id = 0;
1274 path->sw_if_index = ~0;
1275 path->proto = FIB_API_PATH_NH_PROTO_IP4;
1276 }
1277 else if (unformat (input, "%U",
1278 unformat_vl_api_ip6_address, &path->nh.address.ip6))
1279 {
1280 /*
1281 * the recursive next-hops are by default in the default table
1282 */
1283 path->table_id = 0;
1284 path->sw_if_index = ~0;
1285 path->proto = FIB_API_PATH_NH_PROTO_IP6;
1286 }
1287 else if (unformat (input, "resolve-via-host"))
1288 {
1289 path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_HOST;
1290 }
1291 else if (unformat (input, "resolve-via-attached"))
1292 {
1293 path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED;
1294 }
1295 else if (unformat (input, "ip4-lookup-in-table %d", &path->table_id))
1296 {
1297 path->type = FIB_API_PATH_TYPE_LOCAL;
1298 path->sw_if_index = ~0;
1299 path->proto = FIB_API_PATH_NH_PROTO_IP4;
1300 }
1301 else if (unformat (input, "ip6-lookup-in-table %d", &path->table_id))
1302 {
1303 path->type = FIB_API_PATH_TYPE_LOCAL;
1304 path->sw_if_index = ~0;
1305 path->proto = FIB_API_PATH_NH_PROTO_IP6;
1306 }
1307 else if (unformat (input, "sw_if_index %d", &path->sw_if_index))
1308 ;
1309 else if (unformat (input, "via-label %d", &path->nh.via_label))
1310 {
1311 path->proto = FIB_API_PATH_NH_PROTO_MPLS;
1312 path->sw_if_index = ~0;
1313 }
1314 else if (unformat (input, "l2-input-on %d", &path->sw_if_index))
1315 {
1316 path->proto = FIB_API_PATH_NH_PROTO_ETHERNET;
1317 path->type = FIB_API_PATH_TYPE_INTERFACE_RX;
1318 }
1319 else if (unformat (input, "local"))
1320 {
1321 path->type = FIB_API_PATH_TYPE_LOCAL;
1322 }
1323 else if (unformat (input, "out-labels"))
1324 {
1325 while (unformat (input, "%d", &out_label))
1326 {
1327 path->label_stack[path->n_labels].label = out_label;
1328 path->label_stack[path->n_labels].is_uniform = 0;
1329 path->label_stack[path->n_labels].ttl = 64;
1330 path->n_labels++;
1331 }
1332 }
1333 else if (unformat (input, "via"))
1334 {
1335 /* new path, back up and return */
1336 unformat_put_input (input);
1337 unformat_put_input (input);
1338 unformat_put_input (input);
1339 unformat_put_input (input);
1340 break;
1341 }
1342 else
1343 {
1344 return (0);
1345 }
1346 }
1347
1348 path->proto = ntohl (path->proto);
1349 path->type = ntohl (path->type);
1350 path->flags = ntohl (path->flags);
1351 path->table_id = ntohl (path->table_id);
1352 path->sw_if_index = ntohl (path->sw_if_index);
1353
1354 return (1);
1355}
1356
Damjan Marion7cd468a2016-12-19 23:05:39 +01001357#define foreach_create_subif_bit \
1358_(no_tags) \
1359_(one_tag) \
1360_(two_tags) \
1361_(dot1ad) \
1362_(exact_match) \
1363_(default_sub) \
1364_(outer_vlan_id_any) \
1365_(inner_vlan_id_any)
1366
Jakub Grajciar053204a2019-03-18 13:17:53 +01001367#define foreach_create_subif_flag \
1368_(0, "no_tags") \
1369_(1, "one_tag") \
1370_(2, "two_tags") \
1371_(3, "dot1ad") \
1372_(4, "exact_match") \
1373_(5, "default_sub") \
1374_(6, "outer_vlan_id_any") \
1375_(7, "inner_vlan_id_any")
1376
Pablo Camarillofb380952016-12-07 18:34:18 +01001377
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001378#define foreach_tcp_proto_field \
1379 _ (src_port) \
1380 _ (dst_port)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001381
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001382#define foreach_udp_proto_field \
1383 _ (src_port) \
1384 _ (dst_port)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001385
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001386#define foreach_ip4_proto_field \
1387 _ (src_address) \
1388 _ (dst_address) \
1389 _ (tos) \
1390 _ (length) \
1391 _ (fragment_id) \
1392 _ (ttl) \
1393 _ (protocol) \
1394 _ (checksum)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001395
Dave Barach4a3f69c2017-02-22 12:44:56 -05001396typedef struct
1397{
1398 u16 src_port, dst_port;
1399} tcpudp_header_t;
1400
1401#if VPP_API_TEST_BUILTIN == 0
Damjan Marion7cd468a2016-12-19 23:05:39 +01001402uword
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001403unformat_tcp_mask (unformat_input_t *input, va_list *args)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001404{
1405 u8 **maskp = va_arg (*args, u8 **);
1406 u8 *mask = 0;
1407 u8 found_something = 0;
1408 tcp_header_t *tcp;
1409
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001410#define _(a) u8 a = 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001411 foreach_tcp_proto_field;
1412#undef _
1413
1414 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1415 {
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001416 if (0)
1417 ;
1418#define _(a) else if (unformat (input, #a)) a = 1;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001419 foreach_tcp_proto_field
1420#undef _
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001421 else break;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001422 }
1423
1424#define _(a) found_something += a;
1425 foreach_tcp_proto_field;
1426#undef _
1427
1428 if (found_something == 0)
1429 return 0;
1430
1431 vec_validate (mask, sizeof (*tcp) - 1);
1432
1433 tcp = (tcp_header_t *) mask;
1434
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001435#define _(a) \
1436 if (a) \
1437 clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Damjan Marion7cd468a2016-12-19 23:05:39 +01001438 foreach_tcp_proto_field;
1439#undef _
1440
1441 *maskp = mask;
1442 return 1;
1443}
1444
1445uword
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001446unformat_udp_mask (unformat_input_t *input, va_list *args)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001447{
1448 u8 **maskp = va_arg (*args, u8 **);
1449 u8 *mask = 0;
1450 u8 found_something = 0;
1451 udp_header_t *udp;
1452
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001453#define _(a) u8 a = 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001454 foreach_udp_proto_field;
1455#undef _
1456
1457 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1458 {
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001459 if (0)
1460 ;
1461#define _(a) else if (unformat (input, #a)) a = 1;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001462 foreach_udp_proto_field
1463#undef _
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001464 else break;
Damjan Marion7cd468a2016-12-19 23:05:39 +01001465 }
1466
1467#define _(a) found_something += a;
1468 foreach_udp_proto_field;
1469#undef _
1470
1471 if (found_something == 0)
1472 return 0;
1473
1474 vec_validate (mask, sizeof (*udp) - 1);
1475
1476 udp = (udp_header_t *) mask;
1477
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001478#define _(a) \
1479 if (a) \
1480 clib_memset (&udp->a, 0xff, sizeof (udp->a));
Damjan Marion7cd468a2016-12-19 23:05:39 +01001481 foreach_udp_proto_field;
1482#undef _
1483
1484 *maskp = mask;
1485 return 1;
1486}
1487
Damjan Marion7cd468a2016-12-19 23:05:39 +01001488uword
Filip Tehlar5ff59a12021-06-23 14:38:38 +00001489unformat_l4_mask (unformat_input_t *input, va_list *args)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001490{
1491 u8 **maskp = va_arg (*args, u8 **);
1492 u16 src_port = 0, dst_port = 0;
1493 tcpudp_header_t *tcpudp;
1494
1495 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1496 {
1497 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
1498 return 1;
1499 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
1500 return 1;
1501 else if (unformat (input, "src_port"))
1502 src_port = 0xFFFF;
1503 else if (unformat (input, "dst_port"))
1504 dst_port = 0xFFFF;
1505 else
1506 return 0;
1507 }
1508
1509 if (!src_port && !dst_port)
1510 return 0;
1511
1512 u8 *mask = 0;
1513 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
1514
1515 tcpudp = (tcpudp_header_t *) mask;
1516 tcpudp->src_port = src_port;
1517 tcpudp->dst_port = dst_port;
1518
1519 *maskp = mask;
1520
1521 return 1;
1522}
1523
1524uword
1525unformat_ip4_mask (unformat_input_t * input, va_list * args)
1526{
1527 u8 **maskp = va_arg (*args, u8 **);
1528 u8 *mask = 0;
1529 u8 found_something = 0;
1530 ip4_header_t *ip;
1531
1532#define _(a) u8 a=0;
1533 foreach_ip4_proto_field;
1534#undef _
1535 u8 version = 0;
1536 u8 hdr_length = 0;
1537
1538
1539 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1540 {
1541 if (unformat (input, "version"))
1542 version = 1;
1543 else if (unformat (input, "hdr_length"))
1544 hdr_length = 1;
1545 else if (unformat (input, "src"))
1546 src_address = 1;
1547 else if (unformat (input, "dst"))
1548 dst_address = 1;
1549 else if (unformat (input, "proto"))
1550 protocol = 1;
1551
1552#define _(a) else if (unformat (input, #a)) a=1;
1553 foreach_ip4_proto_field
1554#undef _
1555 else
1556 break;
1557 }
1558
1559#define _(a) found_something += a;
1560 foreach_ip4_proto_field;
1561#undef _
1562
1563 if (found_something == 0)
1564 return 0;
1565
1566 vec_validate (mask, sizeof (*ip) - 1);
1567
1568 ip = (ip4_header_t *) mask;
1569
Dave Barachb7b92992018-10-17 10:38:51 -04001570#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Damjan Marion7cd468a2016-12-19 23:05:39 +01001571 foreach_ip4_proto_field;
1572#undef _
1573
1574 ip->ip_version_and_header_length = 0;
1575
1576 if (version)
1577 ip->ip_version_and_header_length |= 0xF0;
1578
1579 if (hdr_length)
1580 ip->ip_version_and_header_length |= 0x0F;
1581
1582 *maskp = mask;
1583 return 1;
1584}
1585
1586#define foreach_ip6_proto_field \
1587_(src_address) \
1588_(dst_address) \
1589_(payload_length) \
1590_(hop_limit) \
1591_(protocol)
1592
1593uword
1594unformat_ip6_mask (unformat_input_t * input, va_list * args)
1595{
1596 u8 **maskp = va_arg (*args, u8 **);
1597 u8 *mask = 0;
1598 u8 found_something = 0;
1599 ip6_header_t *ip;
1600 u32 ip_version_traffic_class_and_flow_label;
1601
1602#define _(a) u8 a=0;
1603 foreach_ip6_proto_field;
1604#undef _
1605 u8 version = 0;
1606 u8 traffic_class = 0;
1607 u8 flow_label = 0;
1608
1609 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1610 {
1611 if (unformat (input, "version"))
1612 version = 1;
1613 else if (unformat (input, "traffic-class"))
1614 traffic_class = 1;
1615 else if (unformat (input, "flow-label"))
1616 flow_label = 1;
1617 else if (unformat (input, "src"))
1618 src_address = 1;
1619 else if (unformat (input, "dst"))
1620 dst_address = 1;
1621 else if (unformat (input, "proto"))
1622 protocol = 1;
1623
1624#define _(a) else if (unformat (input, #a)) a=1;
1625 foreach_ip6_proto_field
1626#undef _
1627 else
1628 break;
1629 }
1630
1631#define _(a) found_something += a;
1632 foreach_ip6_proto_field;
1633#undef _
1634
1635 if (found_something == 0)
1636 return 0;
1637
1638 vec_validate (mask, sizeof (*ip) - 1);
1639
1640 ip = (ip6_header_t *) mask;
1641
Dave Barachb7b92992018-10-17 10:38:51 -04001642#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Damjan Marion7cd468a2016-12-19 23:05:39 +01001643 foreach_ip6_proto_field;
1644#undef _
1645
1646 ip_version_traffic_class_and_flow_label = 0;
1647
1648 if (version)
1649 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1650
1651 if (traffic_class)
1652 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1653
1654 if (flow_label)
1655 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1656
1657 ip->ip_version_traffic_class_and_flow_label =
1658 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1659
1660 *maskp = mask;
1661 return 1;
1662}
1663
1664uword
1665unformat_l3_mask (unformat_input_t * input, va_list * args)
1666{
1667 u8 **maskp = va_arg (*args, u8 **);
1668
1669 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1670 {
1671 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1672 return 1;
1673 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1674 return 1;
1675 else
1676 break;
1677 }
1678 return 0;
1679}
1680
1681uword
1682unformat_l2_mask (unformat_input_t * input, va_list * args)
1683{
1684 u8 **maskp = va_arg (*args, u8 **);
1685 u8 *mask = 0;
1686 u8 src = 0;
1687 u8 dst = 0;
1688 u8 proto = 0;
1689 u8 tag1 = 0;
1690 u8 tag2 = 0;
1691 u8 ignore_tag1 = 0;
1692 u8 ignore_tag2 = 0;
1693 u8 cos1 = 0;
1694 u8 cos2 = 0;
1695 u8 dot1q = 0;
1696 u8 dot1ad = 0;
1697 int len = 14;
1698
1699 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1700 {
1701 if (unformat (input, "src"))
1702 src = 1;
1703 else if (unformat (input, "dst"))
1704 dst = 1;
1705 else if (unformat (input, "proto"))
1706 proto = 1;
1707 else if (unformat (input, "tag1"))
1708 tag1 = 1;
1709 else if (unformat (input, "tag2"))
1710 tag2 = 1;
1711 else if (unformat (input, "ignore-tag1"))
1712 ignore_tag1 = 1;
1713 else if (unformat (input, "ignore-tag2"))
1714 ignore_tag2 = 1;
1715 else if (unformat (input, "cos1"))
1716 cos1 = 1;
1717 else if (unformat (input, "cos2"))
1718 cos2 = 1;
1719 else if (unformat (input, "dot1q"))
1720 dot1q = 1;
1721 else if (unformat (input, "dot1ad"))
1722 dot1ad = 1;
1723 else
1724 break;
1725 }
1726 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
1727 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1728 return 0;
1729
1730 if (tag1 || ignore_tag1 || cos1 || dot1q)
1731 len = 18;
1732 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1733 len = 22;
1734
1735 vec_validate (mask, len - 1);
1736
1737 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001738 clib_memset (mask, 0xff, 6);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001739
1740 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001741 clib_memset (mask + 6, 0xff, 6);
Damjan Marion7cd468a2016-12-19 23:05:39 +01001742
1743 if (tag2 || dot1ad)
1744 {
1745 /* inner vlan tag */
1746 if (tag2)
1747 {
1748 mask[19] = 0xff;
1749 mask[18] = 0x0f;
1750 }
1751 if (cos2)
1752 mask[18] |= 0xe0;
1753 if (proto)
1754 mask[21] = mask[20] = 0xff;
1755 if (tag1)
1756 {
1757 mask[15] = 0xff;
1758 mask[14] = 0x0f;
1759 }
1760 if (cos1)
1761 mask[14] |= 0xe0;
1762 *maskp = mask;
1763 return 1;
1764 }
1765 if (tag1 | dot1q)
1766 {
1767 if (tag1)
1768 {
1769 mask[15] = 0xff;
1770 mask[14] = 0x0f;
1771 }
1772 if (cos1)
1773 mask[14] |= 0xe0;
1774 if (proto)
1775 mask[16] = mask[17] = 0xff;
1776
1777 *maskp = mask;
1778 return 1;
1779 }
1780 if (cos2)
1781 mask[18] |= 0xe0;
1782 if (cos1)
1783 mask[14] |= 0xe0;
1784 if (proto)
1785 mask[12] = mask[13] = 0xff;
1786
1787 *maskp = mask;
1788 return 1;
1789}
1790
1791uword
1792unformat_classify_mask (unformat_input_t * input, va_list * args)
1793{
1794 u8 **maskp = va_arg (*args, u8 **);
1795 u32 *skipp = va_arg (*args, u32 *);
1796 u32 *matchp = va_arg (*args, u32 *);
1797 u32 match;
1798 u8 *mask = 0;
1799 u8 *l2 = 0;
1800 u8 *l3 = 0;
1801 u8 *l4 = 0;
1802 int i;
1803
1804 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1805 {
1806 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1807 ;
1808 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1809 ;
1810 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1811 ;
1812 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1813 ;
1814 else
1815 break;
1816 }
1817
1818 if (l4 && !l3)
1819 {
1820 vec_free (mask);
1821 vec_free (l2);
1822 vec_free (l4);
1823 return 0;
1824 }
1825
1826 if (mask || l2 || l3 || l4)
1827 {
1828 if (l2 || l3 || l4)
1829 {
1830 /* "With a free Ethernet header in every package" */
1831 if (l2 == 0)
1832 vec_validate (l2, 13);
1833 mask = l2;
1834 if (vec_len (l3))
1835 {
1836 vec_append (mask, l3);
1837 vec_free (l3);
1838 }
1839 if (vec_len (l4))
1840 {
1841 vec_append (mask, l4);
1842 vec_free (l4);
1843 }
1844 }
1845
1846 /* Scan forward looking for the first significant mask octet */
1847 for (i = 0; i < vec_len (mask); i++)
1848 if (mask[i])
1849 break;
1850
1851 /* compute (skip, match) params */
1852 *skipp = i / sizeof (u32x4);
1853 vec_delete (mask, *skipp * sizeof (u32x4), 0);
1854
1855 /* Pad mask to an even multiple of the vector size */
1856 while (vec_len (mask) % sizeof (u32x4))
1857 vec_add1 (mask, 0);
1858
1859 match = vec_len (mask) / sizeof (u32x4);
1860
1861 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1862 {
1863 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1864 if (*tmp || *(tmp + 1))
1865 break;
1866 match--;
1867 }
1868 if (match == 0)
1869 clib_warning ("BUG: match 0");
1870
1871 _vec_len (mask) = match * sizeof (u32x4);
1872
1873 *matchp = match;
1874 *maskp = mask;
1875
1876 return 1;
1877 }
1878
1879 return 0;
1880}
Dave Barach4a3f69c2017-02-22 12:44:56 -05001881#endif /* VPP_API_TEST_BUILTIN */
Damjan Marion7cd468a2016-12-19 23:05:39 +01001882
1883#define foreach_l2_next \
1884_(drop, DROP) \
1885_(ethernet, ETHERNET_INPUT) \
1886_(ip4, IP4_INPUT) \
1887_(ip6, IP6_INPUT)
1888
1889uword
1890unformat_l2_next_index (unformat_input_t * input, va_list * args)
1891{
1892 u32 *miss_next_indexp = va_arg (*args, u32 *);
1893 u32 next_index = 0;
1894 u32 tmp;
1895
1896#define _(n,N) \
1897 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1898 foreach_l2_next;
1899#undef _
1900
1901 if (unformat (input, "%d", &tmp))
1902 {
1903 next_index = tmp;
1904 goto out;
1905 }
1906
1907 return 0;
1908
1909out:
1910 *miss_next_indexp = next_index;
1911 return 1;
1912}
1913
1914#define foreach_ip_next \
1915_(drop, DROP) \
1916_(local, LOCAL) \
1917_(rewrite, REWRITE)
1918
1919uword
Dave Barach4a3f69c2017-02-22 12:44:56 -05001920api_unformat_ip_next_index (unformat_input_t * input, va_list * args)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001921{
1922 u32 *miss_next_indexp = va_arg (*args, u32 *);
1923 u32 next_index = 0;
1924 u32 tmp;
1925
1926#define _(n,N) \
1927 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1928 foreach_ip_next;
1929#undef _
1930
1931 if (unformat (input, "%d", &tmp))
1932 {
1933 next_index = tmp;
1934 goto out;
1935 }
1936
1937 return 0;
1938
1939out:
1940 *miss_next_indexp = next_index;
1941 return 1;
1942}
1943
1944#define foreach_acl_next \
1945_(deny, DENY)
1946
1947uword
Dave Barach4a3f69c2017-02-22 12:44:56 -05001948api_unformat_acl_next_index (unformat_input_t * input, va_list * args)
Damjan Marion7cd468a2016-12-19 23:05:39 +01001949{
1950 u32 *miss_next_indexp = va_arg (*args, u32 *);
1951 u32 next_index = 0;
1952 u32 tmp;
1953
1954#define _(n,N) \
1955 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1956 foreach_acl_next;
1957#undef _
1958
1959 if (unformat (input, "permit"))
1960 {
1961 next_index = ~0;
1962 goto out;
1963 }
1964 else if (unformat (input, "%d", &tmp))
1965 {
1966 next_index = tmp;
1967 goto out;
1968 }
1969
1970 return 0;
1971
1972out:
1973 *miss_next_indexp = next_index;
1974 return 1;
1975}
1976
1977uword
1978unformat_policer_precolor (unformat_input_t * input, va_list * args)
1979{
1980 u32 *r = va_arg (*args, u32 *);
1981
1982 if (unformat (input, "conform-color"))
1983 *r = POLICE_CONFORM;
1984 else if (unformat (input, "exceed-color"))
1985 *r = POLICE_EXCEED;
1986 else
1987 return 0;
1988
1989 return 1;
1990}
1991
Dave Barach4a3f69c2017-02-22 12:44:56 -05001992#if VPP_API_TEST_BUILTIN == 0
Damjan Marion7cd468a2016-12-19 23:05:39 +01001993uword
1994unformat_l4_match (unformat_input_t * input, va_list * args)
1995{
1996 u8 **matchp = va_arg (*args, u8 **);
1997
1998 u8 *proto_header = 0;
1999 int src_port = 0;
2000 int dst_port = 0;
2001
2002 tcpudp_header_t h;
2003
2004 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2005 {
2006 if (unformat (input, "src_port %d", &src_port))
2007 ;
2008 else if (unformat (input, "dst_port %d", &dst_port))
2009 ;
2010 else
2011 return 0;
2012 }
2013
2014 h.src_port = clib_host_to_net_u16 (src_port);
2015 h.dst_port = clib_host_to_net_u16 (dst_port);
2016 vec_validate (proto_header, sizeof (h) - 1);
2017 memcpy (proto_header, &h, sizeof (h));
2018
2019 *matchp = proto_header;
2020
2021 return 1;
2022}
2023
2024uword
2025unformat_ip4_match (unformat_input_t * input, va_list * args)
2026{
2027 u8 **matchp = va_arg (*args, u8 **);
2028 u8 *match = 0;
2029 ip4_header_t *ip;
2030 int version = 0;
2031 u32 version_val;
2032 int hdr_length = 0;
2033 u32 hdr_length_val;
2034 int src = 0, dst = 0;
2035 ip4_address_t src_val, dst_val;
2036 int proto = 0;
2037 u32 proto_val;
2038 int tos = 0;
2039 u32 tos_val;
2040 int length = 0;
2041 u32 length_val;
2042 int fragment_id = 0;
2043 u32 fragment_id_val;
2044 int ttl = 0;
2045 int ttl_val;
2046 int checksum = 0;
2047 u32 checksum_val;
2048
2049 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2050 {
2051 if (unformat (input, "version %d", &version_val))
2052 version = 1;
2053 else if (unformat (input, "hdr_length %d", &hdr_length_val))
2054 hdr_length = 1;
2055 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
2056 src = 1;
2057 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
2058 dst = 1;
2059 else if (unformat (input, "proto %d", &proto_val))
2060 proto = 1;
2061 else if (unformat (input, "tos %d", &tos_val))
2062 tos = 1;
2063 else if (unformat (input, "length %d", &length_val))
2064 length = 1;
2065 else if (unformat (input, "fragment_id %d", &fragment_id_val))
2066 fragment_id = 1;
2067 else if (unformat (input, "ttl %d", &ttl_val))
2068 ttl = 1;
2069 else if (unformat (input, "checksum %d", &checksum_val))
2070 checksum = 1;
2071 else
2072 break;
2073 }
2074
2075 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2076 + ttl + checksum == 0)
2077 return 0;
2078
2079 /*
2080 * Aligned because we use the real comparison functions
2081 */
2082 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2083
2084 ip = (ip4_header_t *) match;
2085
2086 /* These are realistically matched in practice */
2087 if (src)
2088 ip->src_address.as_u32 = src_val.as_u32;
2089
2090 if (dst)
2091 ip->dst_address.as_u32 = dst_val.as_u32;
2092
2093 if (proto)
2094 ip->protocol = proto_val;
2095
2096
2097 /* These are not, but they're included for completeness */
2098 if (version)
2099 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
2100
2101 if (hdr_length)
2102 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
2103
2104 if (tos)
2105 ip->tos = tos_val;
2106
2107 if (length)
2108 ip->length = clib_host_to_net_u16 (length_val);
2109
2110 if (ttl)
2111 ip->ttl = ttl_val;
2112
2113 if (checksum)
2114 ip->checksum = clib_host_to_net_u16 (checksum_val);
2115
2116 *matchp = match;
2117 return 1;
2118}
2119
2120uword
2121unformat_ip6_match (unformat_input_t * input, va_list * args)
2122{
2123 u8 **matchp = va_arg (*args, u8 **);
2124 u8 *match = 0;
2125 ip6_header_t *ip;
2126 int version = 0;
2127 u32 version_val;
2128 u8 traffic_class = 0;
2129 u32 traffic_class_val = 0;
2130 u8 flow_label = 0;
2131 u8 flow_label_val;
2132 int src = 0, dst = 0;
2133 ip6_address_t src_val, dst_val;
2134 int proto = 0;
2135 u32 proto_val;
2136 int payload_length = 0;
2137 u32 payload_length_val;
2138 int hop_limit = 0;
2139 int hop_limit_val;
2140 u32 ip_version_traffic_class_and_flow_label;
2141
2142 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2143 {
2144 if (unformat (input, "version %d", &version_val))
2145 version = 1;
2146 else if (unformat (input, "traffic_class %d", &traffic_class_val))
2147 traffic_class = 1;
2148 else if (unformat (input, "flow_label %d", &flow_label_val))
2149 flow_label = 1;
2150 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
2151 src = 1;
2152 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
2153 dst = 1;
2154 else if (unformat (input, "proto %d", &proto_val))
2155 proto = 1;
2156 else if (unformat (input, "payload_length %d", &payload_length_val))
2157 payload_length = 1;
2158 else if (unformat (input, "hop_limit %d", &hop_limit_val))
2159 hop_limit = 1;
2160 else
2161 break;
2162 }
2163
2164 if (version + traffic_class + flow_label + src + dst + proto +
2165 payload_length + hop_limit == 0)
2166 return 0;
2167
2168 /*
2169 * Aligned because we use the real comparison functions
2170 */
2171 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2172
2173 ip = (ip6_header_t *) match;
2174
2175 if (src)
2176 clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
2177
2178 if (dst)
2179 clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
2180
2181 if (proto)
2182 ip->protocol = proto_val;
2183
2184 ip_version_traffic_class_and_flow_label = 0;
2185
2186 if (version)
2187 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2188
2189 if (traffic_class)
2190 ip_version_traffic_class_and_flow_label |=
2191 (traffic_class_val & 0xFF) << 20;
2192
2193 if (flow_label)
2194 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
2195
2196 ip->ip_version_traffic_class_and_flow_label =
2197 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2198
2199 if (payload_length)
2200 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
2201
2202 if (hop_limit)
2203 ip->hop_limit = hop_limit_val;
2204
2205 *matchp = match;
2206 return 1;
2207}
2208
2209uword
2210unformat_l3_match (unformat_input_t * input, va_list * args)
2211{
2212 u8 **matchp = va_arg (*args, u8 **);
2213
2214 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2215 {
2216 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2217 return 1;
2218 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2219 return 1;
2220 else
2221 break;
2222 }
2223 return 0;
2224}
2225
2226uword
2227unformat_vlan_tag (unformat_input_t * input, va_list * args)
2228{
2229 u8 *tagp = va_arg (*args, u8 *);
2230 u32 tag;
2231
2232 if (unformat (input, "%d", &tag))
2233 {
2234 tagp[0] = (tag >> 8) & 0x0F;
2235 tagp[1] = tag & 0xFF;
2236 return 1;
2237 }
2238
2239 return 0;
2240}
2241
2242uword
2243unformat_l2_match (unformat_input_t * input, va_list * args)
2244{
2245 u8 **matchp = va_arg (*args, u8 **);
2246 u8 *match = 0;
2247 u8 src = 0;
2248 u8 src_val[6];
2249 u8 dst = 0;
2250 u8 dst_val[6];
2251 u8 proto = 0;
2252 u16 proto_val;
2253 u8 tag1 = 0;
2254 u8 tag1_val[2];
2255 u8 tag2 = 0;
2256 u8 tag2_val[2];
2257 int len = 14;
2258 u8 ignore_tag1 = 0;
2259 u8 ignore_tag2 = 0;
2260 u8 cos1 = 0;
2261 u8 cos2 = 0;
2262 u32 cos1_val = 0;
2263 u32 cos2_val = 0;
2264
2265 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2266 {
2267 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2268 src = 1;
2269 else
2270 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2271 dst = 1;
2272 else if (unformat (input, "proto %U",
2273 unformat_ethernet_type_host_byte_order, &proto_val))
2274 proto = 1;
2275 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2276 tag1 = 1;
2277 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2278 tag2 = 1;
2279 else if (unformat (input, "ignore-tag1"))
2280 ignore_tag1 = 1;
2281 else if (unformat (input, "ignore-tag2"))
2282 ignore_tag2 = 1;
2283 else if (unformat (input, "cos1 %d", &cos1_val))
2284 cos1 = 1;
2285 else if (unformat (input, "cos2 %d", &cos2_val))
2286 cos2 = 1;
2287 else
2288 break;
2289 }
2290 if ((src + dst + proto + tag1 + tag2 +
2291 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
2292 return 0;
2293
2294 if (tag1 || ignore_tag1 || cos1)
2295 len = 18;
2296 if (tag2 || ignore_tag2 || cos2)
2297 len = 22;
2298
2299 vec_validate_aligned (match, len - 1, sizeof (u32x4));
2300
2301 if (dst)
2302 clib_memcpy (match, dst_val, 6);
2303
2304 if (src)
2305 clib_memcpy (match + 6, src_val, 6);
2306
2307 if (tag2)
2308 {
2309 /* inner vlan tag */
2310 match[19] = tag2_val[1];
2311 match[18] = tag2_val[0];
2312 if (cos2)
2313 match[18] |= (cos2_val & 0x7) << 5;
2314 if (proto)
2315 {
2316 match[21] = proto_val & 0xff;
2317 match[20] = proto_val >> 8;
2318 }
2319 if (tag1)
2320 {
2321 match[15] = tag1_val[1];
2322 match[14] = tag1_val[0];
2323 }
2324 if (cos1)
2325 match[14] |= (cos1_val & 0x7) << 5;
2326 *matchp = match;
2327 return 1;
2328 }
2329 if (tag1)
2330 {
2331 match[15] = tag1_val[1];
2332 match[14] = tag1_val[0];
2333 if (proto)
2334 {
2335 match[17] = proto_val & 0xff;
2336 match[16] = proto_val >> 8;
2337 }
2338 if (cos1)
2339 match[14] |= (cos1_val & 0x7) << 5;
2340
2341 *matchp = match;
2342 return 1;
2343 }
2344 if (cos2)
2345 match[18] |= (cos2_val & 0x7) << 5;
2346 if (cos1)
2347 match[14] |= (cos1_val & 0x7) << 5;
2348 if (proto)
2349 {
2350 match[13] = proto_val & 0xff;
2351 match[12] = proto_val >> 8;
2352 }
2353
2354 *matchp = match;
2355 return 1;
2356}
Igor Mikhailov (imichail)582caa32018-04-26 21:33:02 -07002357
2358uword
2359unformat_qos_source (unformat_input_t * input, va_list * args)
2360{
2361 int *qs = va_arg (*args, int *);
2362
2363 if (unformat (input, "ip"))
2364 *qs = QOS_SOURCE_IP;
2365 else if (unformat (input, "mpls"))
2366 *qs = QOS_SOURCE_MPLS;
2367 else if (unformat (input, "ext"))
2368 *qs = QOS_SOURCE_EXT;
2369 else if (unformat (input, "vlan"))
2370 *qs = QOS_SOURCE_VLAN;
2371 else
2372 return 0;
2373
2374 return 1;
2375}
Dave Barach4a3f69c2017-02-22 12:44:56 -05002376#endif
Damjan Marion7cd468a2016-12-19 23:05:39 +01002377
2378uword
Dave Barach4a3f69c2017-02-22 12:44:56 -05002379api_unformat_classify_match (unformat_input_t * input, va_list * args)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002380{
2381 u8 **matchp = va_arg (*args, u8 **);
2382 u32 skip_n_vectors = va_arg (*args, u32);
2383 u32 match_n_vectors = va_arg (*args, u32);
2384
2385 u8 *match = 0;
2386 u8 *l2 = 0;
2387 u8 *l3 = 0;
2388 u8 *l4 = 0;
2389
2390 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2391 {
2392 if (unformat (input, "hex %U", unformat_hex_string, &match))
2393 ;
2394 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2395 ;
2396 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2397 ;
2398 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2399 ;
2400 else
2401 break;
2402 }
2403
2404 if (l4 && !l3)
2405 {
2406 vec_free (match);
2407 vec_free (l2);
2408 vec_free (l4);
2409 return 0;
2410 }
2411
2412 if (match || l2 || l3 || l4)
2413 {
2414 if (l2 || l3 || l4)
2415 {
2416 /* "Win a free Ethernet header in every packet" */
2417 if (l2 == 0)
2418 vec_validate_aligned (l2, 13, sizeof (u32x4));
2419 match = l2;
2420 if (vec_len (l3))
2421 {
2422 vec_append_aligned (match, l3, sizeof (u32x4));
2423 vec_free (l3);
2424 }
2425 if (vec_len (l4))
2426 {
2427 vec_append_aligned (match, l4, sizeof (u32x4));
2428 vec_free (l4);
2429 }
2430 }
2431
2432 /* Make sure the vector is big enough even if key is all 0's */
2433 vec_validate_aligned
2434 (match, ((match_n_vectors + skip_n_vectors) * sizeof (u32x4)) - 1,
2435 sizeof (u32x4));
2436
2437 /* Set size, include skipped vectors */
2438 _vec_len (match) = (match_n_vectors + skip_n_vectors) * sizeof (u32x4);
2439
2440 *matchp = match;
2441
2442 return 1;
2443 }
2444
2445 return 0;
2446}
2447
2448static int
Filip Tehlar5ff59a12021-06-23 14:38:38 +00002449api_get_node_index (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002450{
2451 unformat_input_t *i = vam->input;
2452 vl_api_get_node_index_t *mp;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002453 u8 *name = 0;
Jon Loeliger56c7b012017-02-01 12:31:41 -06002454 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002455
2456 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2457 {
2458 if (unformat (i, "node %s", &name))
2459 ;
2460 else
2461 break;
2462 }
2463 if (name == 0)
2464 {
2465 errmsg ("node name required");
2466 return -99;
2467 }
2468 if (vec_len (name) >= ARRAY_LEN (mp->node_name))
2469 {
2470 errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name));
2471 return -99;
2472 }
2473
Jon Loeliger8a2aea32017-01-31 13:19:40 -06002474 M (GET_NODE_INDEX, mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +01002475 clib_memcpy (mp->node_name, name, vec_len (name));
2476 vec_free (name);
2477
Jon Loeliger7bc770c2017-01-31 14:03:33 -06002478 S (mp);
Jon Loeliger56c7b012017-02-01 12:31:41 -06002479 W (ret);
2480 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002481}
2482
2483static int
Filip Tehlar5ff59a12021-06-23 14:38:38 +00002484api_get_next_index (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002485{
2486 unformat_input_t *i = vam->input;
2487 vl_api_get_next_index_t *mp;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002488 u8 *node_name = 0, *next_node_name = 0;
Jon Loeliger56c7b012017-02-01 12:31:41 -06002489 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002490
2491 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2492 {
2493 if (unformat (i, "node-name %s", &node_name))
2494 ;
2495 else if (unformat (i, "next-node-name %s", &next_node_name))
2496 break;
2497 }
2498
2499 if (node_name == 0)
2500 {
2501 errmsg ("node name required");
2502 return -99;
2503 }
2504 if (vec_len (node_name) >= ARRAY_LEN (mp->node_name))
2505 {
2506 errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name));
2507 return -99;
2508 }
2509
2510 if (next_node_name == 0)
2511 {
2512 errmsg ("next node name required");
2513 return -99;
2514 }
2515 if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name))
2516 {
2517 errmsg ("next node name too long, max %d", ARRAY_LEN (mp->next_name));
2518 return -99;
2519 }
2520
Jon Loeliger8a2aea32017-01-31 13:19:40 -06002521 M (GET_NEXT_INDEX, mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +01002522 clib_memcpy (mp->node_name, node_name, vec_len (node_name));
2523 clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name));
2524 vec_free (node_name);
2525 vec_free (next_node_name);
2526
Jon Loeliger7bc770c2017-01-31 14:03:33 -06002527 S (mp);
Jon Loeliger56c7b012017-02-01 12:31:41 -06002528 W (ret);
2529 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002530}
2531
2532static int
Filip Tehlar5ff59a12021-06-23 14:38:38 +00002533api_add_node_next (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002534{
2535 unformat_input_t *i = vam->input;
2536 vl_api_add_node_next_t *mp;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002537 u8 *name = 0;
2538 u8 *next = 0;
Jon Loeliger56c7b012017-02-01 12:31:41 -06002539 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002540
2541 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2542 {
2543 if (unformat (i, "node %s", &name))
2544 ;
2545 else if (unformat (i, "next %s", &next))
2546 ;
2547 else
2548 break;
2549 }
2550 if (name == 0)
2551 {
2552 errmsg ("node name required");
2553 return -99;
2554 }
2555 if (vec_len (name) >= ARRAY_LEN (mp->node_name))
2556 {
2557 errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name));
2558 return -99;
2559 }
2560 if (next == 0)
2561 {
2562 errmsg ("next node required");
2563 return -99;
2564 }
2565 if (vec_len (next) >= ARRAY_LEN (mp->next_name))
2566 {
2567 errmsg ("next name too long, max %d", ARRAY_LEN (mp->next_name));
2568 return -99;
2569 }
2570
Jon Loeliger8a2aea32017-01-31 13:19:40 -06002571 M (ADD_NODE_NEXT, mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +01002572 clib_memcpy (mp->node_name, name, vec_len (name));
2573 clib_memcpy (mp->next_name, next, vec_len (next));
2574 vec_free (name);
2575 vec_free (next);
2576
Jon Loeliger7bc770c2017-01-31 14:03:33 -06002577 S (mp);
Jon Loeliger56c7b012017-02-01 12:31:41 -06002578 W (ret);
2579 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002580}
2581
Filip Tehlar5ff59a12021-06-23 14:38:38 +00002582#define foreach_vtr_op \
2583 _ ("disable", L2_VTR_DISABLED) \
2584 _ ("push-1", L2_VTR_PUSH_1) \
2585 _ ("push-2", L2_VTR_PUSH_2) \
2586 _ ("pop-1", L2_VTR_POP_1) \
2587 _ ("pop-2", L2_VTR_POP_2) \
2588 _ ("translate-1-1", L2_VTR_TRANSLATE_1_1) \
2589 _ ("translate-1-2", L2_VTR_TRANSLATE_1_2) \
2590 _ ("translate-2-1", L2_VTR_TRANSLATE_2_1) \
2591 _ ("translate-2-2", L2_VTR_TRANSLATE_2_2)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002592
2593static int
Filip Tehlar4f348df2021-06-22 12:18:17 +00002594api_show_version (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002595{
2596 vl_api_show_version_t *mp;
Jon Loeliger56c7b012017-02-01 12:31:41 -06002597 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002598
Jon Loeliger8a2aea32017-01-31 13:19:40 -06002599 M (SHOW_VERSION, mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +01002600
Jon Loeliger7bc770c2017-01-31 14:03:33 -06002601 S (mp);
Jon Loeliger56c7b012017-02-01 12:31:41 -06002602 W (ret);
2603 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002604}
2605
Damjan Marion7cd468a2016-12-19 23:05:39 +01002606static int
Filip Tehlar5ff59a12021-06-23 14:38:38 +00002607api_get_first_msg_id (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002608{
2609 vl_api_get_first_msg_id_t *mp;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002610 unformat_input_t *i = vam->input;
2611 u8 *name;
2612 u8 name_set = 0;
Jon Loeliger56c7b012017-02-01 12:31:41 -06002613 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002614
2615 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2616 {
2617 if (unformat (i, "client %s", &name))
2618 name_set = 1;
2619 else
2620 break;
2621 }
2622
2623 if (name_set == 0)
2624 {
2625 errmsg ("missing client name");
2626 return -99;
2627 }
2628 vec_add1 (name, 0);
2629
2630 if (vec_len (name) > 63)
2631 {
2632 errmsg ("client name too long");
2633 return -99;
2634 }
2635
Jon Loeliger8a2aea32017-01-31 13:19:40 -06002636 M (GET_FIRST_MSG_ID, mp);
Ole Troan7adaa222019-08-27 15:05:27 +02002637 clib_memcpy (mp->name, name, vec_len (name));
Jon Loeliger7bc770c2017-01-31 14:03:33 -06002638 S (mp);
Jon Loeliger56c7b012017-02-01 12:31:41 -06002639 W (ret);
2640 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002641}
2642
2643static int
Filip Tehlar5ff59a12021-06-23 14:38:38 +00002644api_get_node_graph (vat_main_t *vam)
Damjan Marion7cd468a2016-12-19 23:05:39 +01002645{
2646 vl_api_get_node_graph_t *mp;
Jon Loeliger56c7b012017-02-01 12:31:41 -06002647 int ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002648
Jon Loeliger8a2aea32017-01-31 13:19:40 -06002649 M (GET_NODE_GRAPH, mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +01002650
2651 /* send it... */
Jon Loeliger7bc770c2017-01-31 14:03:33 -06002652 S (mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +01002653 /* Wait for the reply */
Jon Loeliger56c7b012017-02-01 12:31:41 -06002654 W (ret);
2655 return ret;
Damjan Marion7cd468a2016-12-19 23:05:39 +01002656}
2657
Damjan Marion7cd468a2016-12-19 23:05:39 +01002658#define foreach_pbb_vtr_op \
2659_("disable", L2_VTR_DISABLED) \
2660_("pop", L2_VTR_POP_2) \
2661_("push", L2_VTR_PUSH_2)
2662
Damjan Marion7cd468a2016-12-19 23:05:39 +01002663
Florin Coras6e8c6672017-11-10 09:03:54 -08002664static void vl_api_app_namespace_add_del_reply_t_handler
2665 (vl_api_app_namespace_add_del_reply_t * mp)
2666{
2667 vat_main_t *vam = &vat_main;
2668 i32 retval = ntohl (mp->retval);
2669 if (vam->async_mode)
2670 {
2671 vam->async_errors += (retval < 0);
2672 }
2673 else
2674 {
2675 vam->retval = retval;
2676 if (retval == 0)
2677 errmsg ("app ns index %d\n", ntohl (mp->appns_index));
2678 vam->result_ready = 1;
2679 }
2680}
2681
2682static void vl_api_app_namespace_add_del_reply_t_handler_json
2683 (vl_api_app_namespace_add_del_reply_t * mp)
2684{
2685 vat_main_t *vam = &vat_main;
2686 vat_json_node_t node;
2687
2688 vat_json_init_object (&node);
2689 vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
2690 vat_json_object_add_uint (&node, "appns_index", ntohl (mp->appns_index));
2691
2692 vat_json_print (vam->ofp, &node);
2693 vat_json_free (&node);
2694
2695 vam->retval = ntohl (mp->retval);
2696 vam->result_ready = 1;
2697}
2698
Dave Barach3bbcfab2017-08-15 19:03:44 -04002699static int
Florin Corascea194d2017-10-02 00:18:51 -07002700api_app_namespace_add_del (vat_main_t * vam)
2701{
2702 vl_api_app_namespace_add_del_t *mp;
2703 unformat_input_t *i = vam->input;
2704 u8 *ns_id = 0, secret_set = 0, sw_if_index_set = 0;
2705 u32 sw_if_index, ip4_fib_id, ip6_fib_id;
2706 u64 secret;
2707 int ret;
2708
2709 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2710 {
2711 if (unformat (i, "id %_%v%_", &ns_id))
2712 ;
2713 else if (unformat (i, "secret %lu", &secret))
2714 secret_set = 1;
2715 else if (unformat (i, "sw_if_index %d", &sw_if_index))
2716 sw_if_index_set = 1;
2717 else if (unformat (i, "ip4_fib_id %d", &ip4_fib_id))
2718 ;
2719 else if (unformat (i, "ip6_fib_id %d", &ip6_fib_id))
2720 ;
2721 else
2722 break;
2723 }
2724 if (!ns_id || !secret_set || !sw_if_index_set)
2725 {
2726 errmsg ("namespace id, secret and sw_if_index must be set");
2727 return -99;
2728 }
2729 if (vec_len (ns_id) > 64)
2730 {
2731 errmsg ("namespace id too long");
2732 return -99;
2733 }
2734 M (APP_NAMESPACE_ADD_DEL, mp);
2735
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002736 vl_api_vec_to_api_string (ns_id, &mp->namespace_id);
Florin Coras9a9adb22017-10-26 08:16:59 -07002737 mp->secret = clib_host_to_net_u64 (secret);
Florin Corascea194d2017-10-02 00:18:51 -07002738 mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
2739 mp->ip4_fib_id = clib_host_to_net_u32 (ip4_fib_id);
2740 mp->ip6_fib_id = clib_host_to_net_u32 (ip6_fib_id);
2741 vec_free (ns_id);
2742 S (mp);
2743 W (ret);
2744 return ret;
2745}
2746
2747static int
Florin Coras90a63982017-12-19 04:50:01 -08002748api_sock_init_shm (vat_main_t * vam)
2749{
2750#if VPP_API_TEST_BUILTIN == 0
2751 unformat_input_t *i = vam->input;
2752 vl_api_shm_elem_config_t *config = 0;
2753 u64 size = 64 << 20;
2754 int rv;
2755
2756 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2757 {
2758 if (unformat (i, "size %U", unformat_memory_size, &size))
2759 ;
2760 else
2761 break;
2762 }
2763
Dave Barach78958722018-05-10 16:44:27 -04002764 /*
2765 * Canned custom ring allocator config.
2766 * Should probably parse all of this
2767 */
2768 vec_validate (config, 6);
Florin Coras90a63982017-12-19 04:50:01 -08002769 config[0].type = VL_API_VLIB_RING;
Florin Coras90a63982017-12-19 04:50:01 -08002770 config[0].size = 256;
Dave Barach78958722018-05-10 16:44:27 -04002771 config[0].count = 32;
2772
2773 config[1].type = VL_API_VLIB_RING;
Florin Coras90a63982017-12-19 04:50:01 -08002774 config[1].size = 1024;
Dave Barach78958722018-05-10 16:44:27 -04002775 config[1].count = 16;
2776
2777 config[2].type = VL_API_VLIB_RING;
Florin Coras90a63982017-12-19 04:50:01 -08002778 config[2].size = 4096;
Dave Barach78958722018-05-10 16:44:27 -04002779 config[2].count = 2;
2780
2781 config[3].type = VL_API_CLIENT_RING;
2782 config[3].size = 256;
2783 config[3].count = 32;
2784
2785 config[4].type = VL_API_CLIENT_RING;
2786 config[4].size = 1024;
2787 config[4].count = 16;
2788
2789 config[5].type = VL_API_CLIENT_RING;
2790 config[5].size = 4096;
2791 config[5].count = 2;
2792
2793 config[6].type = VL_API_QUEUE;
2794 config[6].count = 128;
2795 config[6].size = sizeof (uword);
2796
Tomasz Kulasek97dcf5b2019-01-31 18:26:32 +01002797 rv = vl_socket_client_init_shm (config, 1 /* want_pthread */ );
Florin Coras90a63982017-12-19 04:50:01 -08002798 if (!rv)
2799 vam->client_index_invalid = 1;
2800 return rv;
2801#else
2802 return -99;
2803#endif
2804}
2805
Florin Coras6c36f532017-11-03 18:32:34 -07002806static void
2807vl_api_session_rules_details_t_handler (vl_api_session_rules_details_t * mp)
2808{
2809 vat_main_t *vam = &vat_main;
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002810 fib_prefix_t lcl, rmt;
Florin Coras6c36f532017-11-03 18:32:34 -07002811
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002812 ip_prefix_decode (&mp->lcl, &lcl);
2813 ip_prefix_decode (&mp->rmt, &rmt);
2814
2815 if (lcl.fp_proto == FIB_PROTOCOL_IP4)
Florin Coras6c36f532017-11-03 18:32:34 -07002816 {
Florin Corasc97a7392017-11-05 23:07:07 -08002817 print (vam->ofp,
2818 "appns %u tp %u scope %d %U/%d %d %U/%d %d action: %d tag: %s",
Steven85dbac02017-11-07 16:29:53 -08002819 clib_net_to_host_u32 (mp->appns_index), mp->transport_proto,
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002820 mp->scope, format_ip4_address, &lcl.fp_addr.ip4, lcl.fp_len,
Steven85dbac02017-11-07 16:29:53 -08002821 clib_net_to_host_u16 (mp->lcl_port), format_ip4_address,
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002822 &rmt.fp_addr.ip4, rmt.fp_len,
2823 clib_net_to_host_u16 (mp->rmt_port),
Steven85dbac02017-11-07 16:29:53 -08002824 clib_net_to_host_u32 (mp->action_index), mp->tag);
Florin Coras6c36f532017-11-03 18:32:34 -07002825 }
2826 else
2827 {
Florin Corasc97a7392017-11-05 23:07:07 -08002828 print (vam->ofp,
2829 "appns %u tp %u scope %d %U/%d %d %U/%d %d action: %d tag: %s",
Steven85dbac02017-11-07 16:29:53 -08002830 clib_net_to_host_u32 (mp->appns_index), mp->transport_proto,
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002831 mp->scope, format_ip6_address, &lcl.fp_addr.ip6, lcl.fp_len,
Steven85dbac02017-11-07 16:29:53 -08002832 clib_net_to_host_u16 (mp->lcl_port), format_ip6_address,
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002833 &rmt.fp_addr.ip6, rmt.fp_len,
2834 clib_net_to_host_u16 (mp->rmt_port),
Steven85dbac02017-11-07 16:29:53 -08002835 clib_net_to_host_u32 (mp->action_index), mp->tag);
Florin Coras6c36f532017-11-03 18:32:34 -07002836 }
2837}
2838
2839static void
2840vl_api_session_rules_details_t_handler_json (vl_api_session_rules_details_t *
2841 mp)
2842{
2843 vat_main_t *vam = &vat_main;
2844 vat_json_node_t *node = NULL;
2845 struct in6_addr ip6;
2846 struct in_addr ip4;
2847
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002848 fib_prefix_t lcl, rmt;
2849
2850 ip_prefix_decode (&mp->lcl, &lcl);
2851 ip_prefix_decode (&mp->rmt, &rmt);
2852
Florin Coras6c36f532017-11-03 18:32:34 -07002853 if (VAT_JSON_ARRAY != vam->json_tree.type)
2854 {
2855 ASSERT (VAT_JSON_NONE == vam->json_tree.type);
2856 vat_json_init_array (&vam->json_tree);
2857 }
2858 node = vat_json_array_add (&vam->json_tree);
2859 vat_json_init_object (node);
2860
Florin Coras6c36f532017-11-03 18:32:34 -07002861 vat_json_object_add_uint (node, "appns_index",
2862 clib_net_to_host_u32 (mp->appns_index));
2863 vat_json_object_add_uint (node, "transport_proto", mp->transport_proto);
2864 vat_json_object_add_uint (node, "scope", mp->scope);
2865 vat_json_object_add_uint (node, "action_index",
2866 clib_net_to_host_u32 (mp->action_index));
2867 vat_json_object_add_uint (node, "lcl_port",
2868 clib_net_to_host_u16 (mp->lcl_port));
2869 vat_json_object_add_uint (node, "rmt_port",
2870 clib_net_to_host_u16 (mp->rmt_port));
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002871 vat_json_object_add_uint (node, "lcl_plen", lcl.fp_len);
2872 vat_json_object_add_uint (node, "rmt_plen", rmt.fp_len);
Florin Corasc97a7392017-11-05 23:07:07 -08002873 vat_json_object_add_string_copy (node, "tag", mp->tag);
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002874 if (lcl.fp_proto == FIB_PROTOCOL_IP4)
Florin Coras6c36f532017-11-03 18:32:34 -07002875 {
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002876 clib_memcpy (&ip4, &lcl.fp_addr.ip4, sizeof (ip4));
Florin Coras6c36f532017-11-03 18:32:34 -07002877 vat_json_object_add_ip4 (node, "lcl_ip", ip4);
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002878 clib_memcpy (&ip4, &rmt.fp_addr.ip4, sizeof (ip4));
Florin Coras6c36f532017-11-03 18:32:34 -07002879 vat_json_object_add_ip4 (node, "rmt_ip", ip4);
2880 }
2881 else
2882 {
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002883 clib_memcpy (&ip6, &lcl.fp_addr.ip6, sizeof (ip6));
Florin Coras6c36f532017-11-03 18:32:34 -07002884 vat_json_object_add_ip6 (node, "lcl_ip", ip6);
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002885 clib_memcpy (&ip6, &rmt.fp_addr.ip6, sizeof (ip6));
Florin Coras6c36f532017-11-03 18:32:34 -07002886 vat_json_object_add_ip6 (node, "rmt_ip", ip6);
2887 }
2888}
2889
Florin Coras1c710452017-10-17 00:03:13 -07002890static int
2891api_session_rule_add_del (vat_main_t * vam)
2892{
2893 vl_api_session_rule_add_del_t *mp;
2894 unformat_input_t *i = vam->input;
2895 u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen, rmt_plen;
2896 u32 appns_index = 0, scope = 0;
2897 ip4_address_t lcl_ip4, rmt_ip4;
2898 ip6_address_t lcl_ip6, rmt_ip6;
2899 u8 is_ip4 = 1, conn_set = 0;
Florin Corasc97a7392017-11-05 23:07:07 -08002900 u8 is_add = 1, *tag = 0;
Florin Coras1c710452017-10-17 00:03:13 -07002901 int ret;
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002902 fib_prefix_t lcl, rmt;
Florin Coras1c710452017-10-17 00:03:13 -07002903
2904 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2905 {
2906 if (unformat (i, "del"))
2907 is_add = 0;
2908 else if (unformat (i, "add"))
2909 ;
2910 else if (unformat (i, "proto tcp"))
2911 proto = 0;
2912 else if (unformat (i, "proto udp"))
2913 proto = 1;
2914 else if (unformat (i, "appns %d", &appns_index))
2915 ;
2916 else if (unformat (i, "scope %d", &scope))
2917 ;
Florin Corasc97a7392017-11-05 23:07:07 -08002918 else if (unformat (i, "tag %_%v%_", &tag))
2919 ;
Florin Coras1c710452017-10-17 00:03:13 -07002920 else
2921 if (unformat
2922 (i, "%U/%d %d %U/%d %d", unformat_ip4_address, &lcl_ip4,
2923 &lcl_plen, &lcl_port, unformat_ip4_address, &rmt_ip4, &rmt_plen,
2924 &rmt_port))
2925 {
2926 is_ip4 = 1;
2927 conn_set = 1;
2928 }
2929 else
2930 if (unformat
2931 (i, "%U/%d %d %U/%d %d", unformat_ip6_address, &lcl_ip6,
2932 &lcl_plen, &lcl_port, unformat_ip6_address, &rmt_ip6, &rmt_plen,
2933 &rmt_port))
2934 {
2935 is_ip4 = 0;
2936 conn_set = 1;
2937 }
2938 else if (unformat (i, "action %d", &action))
2939 ;
2940 else
2941 break;
2942 }
2943 if (proto == ~0 || !conn_set || action == ~0)
2944 {
2945 errmsg ("transport proto, connection and action must be set");
2946 return -99;
2947 }
2948
2949 if (scope > 3)
2950 {
2951 errmsg ("scope should be 0-3");
2952 return -99;
2953 }
2954
2955 M (SESSION_RULE_ADD_DEL, mp);
2956
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002957 clib_memset (&lcl, 0, sizeof (lcl));
2958 clib_memset (&rmt, 0, sizeof (rmt));
2959 if (is_ip4)
2960 {
2961 ip_set (&lcl.fp_addr, &lcl_ip4, 1);
2962 ip_set (&rmt.fp_addr, &rmt_ip4, 1);
2963 lcl.fp_len = lcl_plen;
2964 rmt.fp_len = rmt_plen;
2965 }
2966 else
2967 {
2968 ip_set (&lcl.fp_addr, &lcl_ip6, 0);
2969 ip_set (&rmt.fp_addr, &rmt_ip6, 0);
2970 lcl.fp_len = lcl_plen;
2971 rmt.fp_len = rmt_plen;
2972 }
2973
2974
2975 ip_prefix_encode (&lcl, &mp->lcl);
2976 ip_prefix_encode (&rmt, &mp->rmt);
Florin Corasc97a7392017-11-05 23:07:07 -08002977 mp->lcl_port = clib_host_to_net_u16 ((u16) lcl_port);
2978 mp->rmt_port = clib_host_to_net_u16 ((u16) rmt_port);
Jakub Grajciarb4e5e502020-01-31 09:35:29 +01002979 mp->transport_proto =
2980 proto ? TRANSPORT_PROTO_API_UDP : TRANSPORT_PROTO_API_TCP;
Florin Coras1c710452017-10-17 00:03:13 -07002981 mp->action_index = clib_host_to_net_u32 (action);
2982 mp->appns_index = clib_host_to_net_u32 (appns_index);
2983 mp->scope = scope;
2984 mp->is_add = is_add;
Florin Corasc97a7392017-11-05 23:07:07 -08002985 if (tag)
2986 {
2987 clib_memcpy (mp->tag, tag, vec_len (tag));
2988 vec_free (tag);
2989 }
Florin Coras1c710452017-10-17 00:03:13 -07002990
2991 S (mp);
2992 W (ret);
2993 return ret;
2994}
Dave Barach65457162017-10-10 17:53:14 -04002995
2996static int
Florin Coras6c36f532017-11-03 18:32:34 -07002997api_session_rules_dump (vat_main_t * vam)
2998{
2999 vl_api_session_rules_dump_t *mp;
3000 vl_api_control_ping_t *mp_ping;
3001 int ret;
3002
3003 if (!vam->json_output)
3004 {
3005 print (vam->ofp, "%=20s", "Session Rules");
3006 }
3007
3008 M (SESSION_RULES_DUMP, mp);
3009 /* send it... */
3010 S (mp);
3011
3012 /* Use a control ping for synchronization */
3013 MPING (CONTROL_PING, mp_ping);
3014 S (mp_ping);
3015
3016 /* Wait for a reply... */
3017 W (ret);
3018 return ret;
3019}
3020
3021static int
Damjan Marion7cd468a2016-12-19 23:05:39 +01003022q_or_quit (vat_main_t * vam)
3023{
Dave Barachdef19da2017-02-22 17:29:20 -05003024#if VPP_API_TEST_BUILTIN == 0
Damjan Marion7cd468a2016-12-19 23:05:39 +01003025 longjmp (vam->jump_buf, 1);
Dave Barachdef19da2017-02-22 17:29:20 -05003026#endif
Damjan Marion7cd468a2016-12-19 23:05:39 +01003027 return 0; /* not so much */
3028}
3029
3030static int
3031q (vat_main_t * vam)
3032{
3033 return q_or_quit (vam);
3034}
3035
3036static int
3037quit (vat_main_t * vam)
3038{
3039 return q_or_quit (vam);
3040}
3041
3042static int
3043comment (vat_main_t * vam)
3044{
3045 return 0;
3046}
3047
3048static int
Dave Barachb09f4d02019-07-15 16:00:03 -04003049elog_save (vat_main_t * vam)
3050{
3051#if VPP_API_TEST_BUILTIN == 0
3052 elog_main_t *em = &vam->elog_main;
3053 unformat_input_t *i = vam->input;
3054 char *file, *chroot_file;
3055 clib_error_t *error;
3056
3057 if (!unformat (i, "%s", &file))
3058 {
3059 errmsg ("expected file name, got `%U'", format_unformat_error, i);
3060 return 0;
3061 }
3062
3063 /* It's fairly hard to get "../oopsie" through unformat; just in case */
3064 if (strstr (file, "..") || index (file, '/'))
3065 {
3066 errmsg ("illegal characters in filename '%s'", file);
3067 return 0;
3068 }
3069
3070 chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
3071
3072 vec_free (file);
3073
3074 errmsg ("Saving %wd of %wd events to %s",
3075 elog_n_events_in_buffer (em),
3076 elog_buffer_capacity (em), chroot_file);
3077
3078 error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
3079 vec_free (chroot_file);
3080
3081 if (error)
3082 clib_error_report (error);
3083#else
3084 errmsg ("Use the vpp event loger...");
3085#endif
3086
3087 return 0;
3088}
3089
3090static int
3091elog_setup (vat_main_t * vam)
3092{
3093#if VPP_API_TEST_BUILTIN == 0
3094 elog_main_t *em = &vam->elog_main;
3095 unformat_input_t *i = vam->input;
3096 u32 nevents = 128 << 10;
3097
3098 (void) unformat (i, "nevents %d", &nevents);
3099
3100 elog_init (em, nevents);
3101 vl_api_set_elog_main (em);
3102 vl_api_set_elog_trace_api_messages (1);
3103 errmsg ("Event logger initialized with %u events", nevents);
3104#else
3105 errmsg ("Use the vpp event loger...");
3106#endif
3107 return 0;
3108}
3109
3110static int
3111elog_enable (vat_main_t * vam)
3112{
3113#if VPP_API_TEST_BUILTIN == 0
3114 elog_main_t *em = &vam->elog_main;
3115
3116 elog_enable_disable (em, 1 /* enable */ );
3117 vl_api_set_elog_trace_api_messages (1);
3118 errmsg ("Event logger enabled...");
3119#else
3120 errmsg ("Use the vpp event loger...");
3121#endif
3122 return 0;
3123}
3124
3125static int
3126elog_disable (vat_main_t * vam)
3127{
3128#if VPP_API_TEST_BUILTIN == 0
3129 elog_main_t *em = &vam->elog_main;
3130
3131 elog_enable_disable (em, 0 /* enable */ );
3132 vl_api_set_elog_trace_api_messages (1);
3133 errmsg ("Event logger disabled...");
3134#else
3135 errmsg ("Use the vpp event loger...");
3136#endif
3137 return 0;
3138}
3139
3140static int
Dave Barach048a4e52018-06-01 18:52:25 -04003141statseg (vat_main_t * vam)
3142{
3143 ssvm_private_t *ssvmp = &vam->stat_segment;
3144 ssvm_shared_header_t *shared_header = ssvmp->sh;
3145 vlib_counter_t **counters;
3146 u64 thread0_index1_packets;
3147 u64 thread0_index1_bytes;
3148 f64 vector_rate, input_rate;
3149 uword *p;
3150
3151 uword *counter_vector_by_name;
3152 if (vam->stat_segment_lockp == 0)
3153 {
3154 errmsg ("Stat segment not mapped...");
3155 return -99;
3156 }
3157
3158 /* look up "/if/rx for sw_if_index 1 as a test */
3159
3160 clib_spinlock_lock (vam->stat_segment_lockp);
3161
3162 counter_vector_by_name = (uword *) shared_header->opaque[1];
3163
3164 p = hash_get_mem (counter_vector_by_name, "/if/rx");
3165 if (p == 0)
3166 {
3167 clib_spinlock_unlock (vam->stat_segment_lockp);
3168 errmsg ("/if/tx not found?");
3169 return -99;
3170 }
3171
3172 /* Fish per-thread vector of combined counters from shared memory */
3173 counters = (vlib_counter_t **) p[0];
3174
3175 if (vec_len (counters[0]) < 2)
3176 {
3177 clib_spinlock_unlock (vam->stat_segment_lockp);
3178 errmsg ("/if/tx vector length %d", vec_len (counters[0]));
3179 return -99;
3180 }
3181
3182 /* Read thread 0 sw_if_index 1 counter */
3183 thread0_index1_packets = counters[0][1].packets;
3184 thread0_index1_bytes = counters[0][1].bytes;
3185
3186 p = hash_get_mem (counter_vector_by_name, "vector_rate");
3187 if (p == 0)
3188 {
3189 clib_spinlock_unlock (vam->stat_segment_lockp);
3190 errmsg ("vector_rate not found?");
3191 return -99;
3192 }
3193
3194 vector_rate = *(f64 *) (p[0]);
3195 p = hash_get_mem (counter_vector_by_name, "input_rate");
3196 if (p == 0)
3197 {
3198 clib_spinlock_unlock (vam->stat_segment_lockp);
3199 errmsg ("input_rate not found?");
3200 return -99;
3201 }
3202 input_rate = *(f64 *) (p[0]);
3203
3204 clib_spinlock_unlock (vam->stat_segment_lockp);
3205
3206 print (vam->ofp, "vector_rate %.2f input_rate %.2f",
3207 vector_rate, input_rate);
3208 print (vam->ofp, "thread 0 sw_if_index 1 rx pkts %lld, bytes %lld",
3209 thread0_index1_packets, thread0_index1_bytes);
3210
3211 return 0;
3212}
3213
3214static int
Damjan Marion7cd468a2016-12-19 23:05:39 +01003215cmd_cmp (void *a1, void *a2)
3216{
3217 u8 **c1 = a1;
3218 u8 **c2 = a2;
3219
3220 return strcmp ((char *) (c1[0]), (char *) (c2[0]));
3221}
3222
3223static int
3224help (vat_main_t * vam)
3225{
3226 u8 **cmds = 0;
3227 u8 *name = 0;
3228 hash_pair_t *p;
3229 unformat_input_t *i = vam->input;
3230 int j;
3231
3232 if (unformat (i, "%s", &name))
3233 {
3234 uword *hs;
3235
3236 vec_add1 (name, 0);
3237
3238 hs = hash_get_mem (vam->help_by_name, name);
3239 if (hs)
3240 print (vam->ofp, "usage: %s %s", name, hs[0]);
3241 else
3242 print (vam->ofp, "No such msg / command '%s'", name);
3243 vec_free (name);
3244 return 0;
3245 }
3246
3247 print (vam->ofp, "Help is available for the following:");
3248
3249 /* *INDENT-OFF* */
3250 hash_foreach_pair (p, vam->function_by_name,
3251 ({
3252 vec_add1 (cmds, (u8 *)(p->key));
3253 }));
3254 /* *INDENT-ON* */
3255
3256 vec_sort_with_function (cmds, cmd_cmp);
3257
3258 for (j = 0; j < vec_len (cmds); j++)
3259 print (vam->ofp, "%s", cmds[j]);
3260
3261 vec_free (cmds);
3262 return 0;
3263}
3264
3265static int
3266set (vat_main_t * vam)
3267{
3268 u8 *name = 0, *value = 0;
3269 unformat_input_t *i = vam->input;
3270
3271 if (unformat (i, "%s", &name))
3272 {
3273 /* The input buffer is a vector, not a string. */
3274 value = vec_dup (i->buffer);
3275 vec_delete (value, i->index, 0);
3276 /* Almost certainly has a trailing newline */
3277 if (value[vec_len (value) - 1] == '\n')
3278 value[vec_len (value) - 1] = 0;
3279 /* Make sure it's a proper string, one way or the other */
3280 vec_add1 (value, 0);
3281 (void) clib_macro_set_value (&vam->macro_main,
3282 (char *) name, (char *) value);
3283 }
3284 else
3285 errmsg ("usage: set <name> <value>");
3286
3287 vec_free (name);
3288 vec_free (value);
3289 return 0;
3290}
3291
3292static int
3293unset (vat_main_t * vam)
3294{
3295 u8 *name = 0;
3296
3297 if (unformat (vam->input, "%s", &name))
3298 if (clib_macro_unset (&vam->macro_main, (char *) name) == 1)
3299 errmsg ("unset: %s wasn't set", name);
3300 vec_free (name);
3301 return 0;
3302}
3303
3304typedef struct
3305{
3306 u8 *name;
3307 u8 *value;
3308} macro_sort_t;
3309
3310
3311static int
3312macro_sort_cmp (void *a1, void *a2)
3313{
3314 macro_sort_t *s1 = a1;
3315 macro_sort_t *s2 = a2;
3316
3317 return strcmp ((char *) (s1->name), (char *) (s2->name));
3318}
3319
3320static int
3321dump_macro_table (vat_main_t * vam)
3322{
3323 macro_sort_t *sort_me = 0, *sm;
3324 int i;
3325 hash_pair_t *p;
3326
3327 /* *INDENT-OFF* */
3328 hash_foreach_pair (p, vam->macro_main.the_value_table_hash,
3329 ({
3330 vec_add2 (sort_me, sm, 1);
3331 sm->name = (u8 *)(p->key);
3332 sm->value = (u8 *) (p->value[0]);
3333 }));
3334 /* *INDENT-ON* */
3335
3336 vec_sort_with_function (sort_me, macro_sort_cmp);
3337
3338 if (vec_len (sort_me))
3339 print (vam->ofp, "%-15s%s", "Name", "Value");
3340 else
3341 print (vam->ofp, "The macro table is empty...");
3342
3343 for (i = 0; i < vec_len (sort_me); i++)
3344 print (vam->ofp, "%-15s%s", sort_me[i].name, sort_me[i].value);
3345 return 0;
3346}
3347
3348static int
Damjan Marion7cd468a2016-12-19 23:05:39 +01003349value_sort_cmp (void *a1, void *a2)
3350{
3351 name_sort_t *n1 = a1;
3352 name_sort_t *n2 = a2;
3353
3354 if (n1->value < n2->value)
3355 return -1;
3356 if (n1->value > n2->value)
3357 return 1;
3358 return 0;
3359}
3360
3361
3362static int
3363dump_msg_api_table (vat_main_t * vam)
3364{
Dave Barach39d69112019-11-27 11:42:13 -05003365 api_main_t *am = vlibapi_get_main ();
Damjan Marion7cd468a2016-12-19 23:05:39 +01003366 name_sort_t *nses = 0, *ns;
3367 hash_pair_t *hp;
3368 int i;
3369
3370 /* *INDENT-OFF* */
3371 hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
3372 ({
3373 vec_add2 (nses, ns, 1);
3374 ns->name = (u8 *)(hp->key);
3375 ns->value = (u32) hp->value[0];
3376 }));
3377 /* *INDENT-ON* */
3378
3379 vec_sort_with_function (nses, value_sort_cmp);
3380
3381 for (i = 0; i < vec_len (nses); i++)
3382 print (vam->ofp, " [%d]: %s", nses[i].value, nses[i].name);
3383 vec_free (nses);
3384 return 0;
3385}
3386
3387static int
3388get_msg_id (vat_main_t * vam)
3389{
3390 u8 *name_and_crc;
3391 u32 message_index;
3392
3393 if (unformat (vam->input, "%s", &name_and_crc))
3394 {
Florin Corase86a8ed2018-01-05 03:20:25 -08003395 message_index = vl_msg_api_get_msg_index (name_and_crc);
Damjan Marion7cd468a2016-12-19 23:05:39 +01003396 if (message_index == ~0)
3397 {
3398 print (vam->ofp, " '%s' not found", name_and_crc);
3399 return 0;
3400 }
3401 print (vam->ofp, " '%s' has message index %d",
3402 name_and_crc, message_index);
3403 return 0;
3404 }
3405 errmsg ("name_and_crc required...");
3406 return 0;
3407}
3408
3409static int
3410search_node_table (vat_main_t * vam)
3411{
3412 unformat_input_t *line_input = vam->input;
3413 u8 *node_to_find;
3414 int j;
3415 vlib_node_t *node, *next_node;
3416 uword *p;
3417
3418 if (vam->graph_node_index_by_name == 0)
3419 {
3420 print (vam->ofp, "Node table empty, issue get_node_graph...");
3421 return 0;
3422 }
3423
3424 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3425 {
3426 if (unformat (line_input, "%s", &node_to_find))
3427 {
3428 vec_add1 (node_to_find, 0);
3429 p = hash_get_mem (vam->graph_node_index_by_name, node_to_find);
3430 if (p == 0)
3431 {
3432 print (vam->ofp, "%s not found...", node_to_find);
3433 goto out;
3434 }
Dave Barach1ddbc012018-06-13 09:26:05 -04003435 node = vam->graph_nodes[0][p[0]];
Damjan Marion7cd468a2016-12-19 23:05:39 +01003436 print (vam->ofp, "[%d] %s", p[0], node->name);
3437 for (j = 0; j < vec_len (node->next_nodes); j++)
3438 {
3439 if (node->next_nodes[j] != ~0)
3440 {
Dave Barach1ddbc012018-06-13 09:26:05 -04003441 next_node = vam->graph_nodes[0][node->next_nodes[j]];
Damjan Marion7cd468a2016-12-19 23:05:39 +01003442 print (vam->ofp, " [%d] %s", j, next_node->name);
3443 }
3444 }
3445 }
3446
3447 else
3448 {
3449 clib_warning ("parse error '%U'", format_unformat_error,
3450 line_input);
3451 return -99;
3452 }
3453
3454 out:
3455 vec_free (node_to_find);
3456
3457 }
3458
3459 return 0;
3460}
3461
3462
3463static int
3464script (vat_main_t * vam)
3465{
3466#if (VPP_API_TEST_BUILTIN==0)
3467 u8 *s = 0;
3468 char *save_current_file;
3469 unformat_input_t save_input;
3470 jmp_buf save_jump_buf;
3471 u32 save_line_number;
3472
3473 FILE *new_fp, *save_ifp;
3474
3475 if (unformat (vam->input, "%s", &s))
3476 {
3477 new_fp = fopen ((char *) s, "r");
3478 if (new_fp == 0)
3479 {
3480 errmsg ("Couldn't open script file %s", s);
3481 vec_free (s);
3482 return -99;
3483 }
3484 }
3485 else
3486 {
3487 errmsg ("Missing script name");
3488 return -99;
3489 }
3490
3491 clib_memcpy (&save_input, &vam->input, sizeof (save_input));
3492 clib_memcpy (&save_jump_buf, &vam->jump_buf, sizeof (save_jump_buf));
3493 save_ifp = vam->ifp;
3494 save_line_number = vam->input_line_number;
3495 save_current_file = (char *) vam->current_file;
3496
3497 vam->input_line_number = 0;
3498 vam->ifp = new_fp;
3499 vam->current_file = s;
3500 do_one_file (vam);
3501
Sirshak Dasb0861822018-05-29 21:13:21 -05003502 clib_memcpy (&vam->input, &save_input, sizeof (save_input));
Damjan Marion7cd468a2016-12-19 23:05:39 +01003503 clib_memcpy (&vam->jump_buf, &save_jump_buf, sizeof (save_jump_buf));
3504 vam->ifp = save_ifp;
3505 vam->input_line_number = save_line_number;
3506 vam->current_file = (u8 *) save_current_file;
3507 vec_free (s);
3508
3509 return 0;
3510#else
3511 clib_warning ("use the exec command...");
3512 return -99;
3513#endif
3514}
3515
3516static int
3517echo (vat_main_t * vam)
3518{
3519 print (vam->ofp, "%v", vam->input->buffer);
3520 return 0;
3521}
3522
3523/* List of API message constructors, CLI names map to api_xxx */
3524#define foreach_vpe_api_msg \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003525_(get_node_index, "node <node-name") \
3526_(add_node_next, "node <node-name> next <next-node-name>") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003527_(show_version, "") \
Mohsin Kazmi5d64c782018-09-11 20:27:09 +02003528_(show_threads, "") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003529_(get_first_msg_id, "client <name>") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003530_(get_node_graph, " ") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003531_(get_next_index, "node-name <node-name> next-node-name <node-name>") \
Florin Coras90a63982017-12-19 04:50:01 -08003532_(sock_init_shm, "size <nnn>") \
Florin Corascea194d2017-10-02 00:18:51 -07003533_(app_namespace_add_del, "[add] id <ns-id> secret <nn> sw_if_index <nn>")\
Florin Coras1c710452017-10-17 00:03:13 -07003534_(session_rule_add_del, "[add|del] proto <tcp/udp> <lcl-ip>/<plen> " \
3535 "<lcl-port> <rmt-ip>/<plen> <rmt-port> action <nn>") \
Florin Coras6c36f532017-11-03 18:32:34 -07003536_(session_rules_dump, "") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003537
3538/* List of command functions, CLI names map directly to functions */
3539#define foreach_cli_function \
3540_(comment, "usage: comment <ignore-rest-of-line>") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003541_(dump_macro_table, "usage: dump_macro_table ") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003542_(dump_msg_api_table, "usage: dump_msg_api_table") \
Dave Barachb09f4d02019-07-15 16:00:03 -04003543_(elog_setup, "usage: elog_setup [nevents, default 128K]") \
3544_(elog_disable, "usage: elog_disable") \
3545_(elog_enable, "usage: elog_enable") \
3546_(elog_save, "usage: elog_save <filename>") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003547_(get_msg_id, "usage: get_msg_id name_and_crc") \
3548_(echo, "usage: echo <message>") \
3549_(exec, "usage: exec <vpe-debug-CLI-command>") \
3550_(exec_inband, "usage: exec_inband <vpe-debug-CLI-command>") \
3551_(help, "usage: help") \
3552_(q, "usage: quit") \
3553_(quit, "usage: quit") \
3554_(search_node_table, "usage: search_node_table <name>...") \
3555_(set, "usage: set <variable-name> <value>") \
3556_(script, "usage: script <file-name>") \
Neale Ranns097fa662018-05-01 05:17:55 -07003557_(statseg, "usage: statseg") \
Damjan Marion7cd468a2016-12-19 23:05:39 +01003558_(unset, "usage: unset <variable-name>")
Dave Barach048a4e52018-06-01 18:52:25 -04003559
Damjan Marion7cd468a2016-12-19 23:05:39 +01003560#define _(N,n) \
3561 static void vl_api_##n##_t_handler_uni \
3562 (vl_api_##n##_t * mp) \
3563 { \
3564 vat_main_t * vam = &vat_main; \
3565 if (vam->json_output) { \
3566 vl_api_##n##_t_handler_json(mp); \
3567 } else { \
3568 vl_api_##n##_t_handler(mp); \
3569 } \
3570 }
3571foreach_vpe_api_reply_msg;
Dave Baracha1a093d2017-03-02 13:13:23 -05003572#if VPP_API_TEST_BUILTIN == 0
3573foreach_standalone_reply_msg;
3574#endif
Damjan Marion7cd468a2016-12-19 23:05:39 +01003575#undef _
3576
3577void
3578vat_api_hookup (vat_main_t * vam)
3579{
3580#define _(N,n) \
3581 vl_msg_api_set_handlers(VL_API_##N, #n, \
3582 vl_api_##n##_t_handler_uni, \
3583 vl_noop_handler, \
3584 vl_api_##n##_t_endian, \
3585 vl_api_##n##_t_print, \
3586 sizeof(vl_api_##n##_t), 1);
3587 foreach_vpe_api_reply_msg;
Dave Baracha1a093d2017-03-02 13:13:23 -05003588#if VPP_API_TEST_BUILTIN == 0
3589 foreach_standalone_reply_msg;
3590#endif
Damjan Marion7cd468a2016-12-19 23:05:39 +01003591#undef _
3592
3593#if (VPP_API_TEST_BUILTIN==0)
3594 vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
Damjan Marion7cd468a2016-12-19 23:05:39 +01003595
3596 vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
3597
3598 vam->function_by_name = hash_create_string (0, sizeof (uword));
3599
3600 vam->help_by_name = hash_create_string (0, sizeof (uword));
Dave Barach45e4f362017-03-07 12:52:31 -05003601#endif
Damjan Marion7cd468a2016-12-19 23:05:39 +01003602
3603 /* API messages we can send */
3604#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
3605 foreach_vpe_api_msg;
3606#undef _
3607
3608 /* Help strings */
3609#define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
3610 foreach_vpe_api_msg;
3611#undef _
Damjan Marion7cd468a2016-12-19 23:05:39 +01003612
3613 /* CLI functions */
3614#define _(n,h) hash_set_mem (vam->function_by_name, #n, n);
3615 foreach_cli_function;
3616#undef _
3617
3618 /* Help strings */
3619#define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
3620 foreach_cli_function;
3621#undef _
3622}
3623
Dave Baracha1a093d2017-03-02 13:13:23 -05003624#if VPP_API_TEST_BUILTIN
3625static clib_error_t *
3626vat_api_hookup_shim (vlib_main_t * vm)
3627{
3628 vat_api_hookup (&vat_main);
3629 return 0;
3630}
3631
3632VLIB_API_INIT_FUNCTION (vat_api_hookup_shim);
3633#endif
3634
Damjan Marion7cd468a2016-12-19 23:05:39 +01003635/*
3636 * fd.io coding-style-patch-verification: ON
3637 *
3638 * Local Variables:
3639 * eval: (c-set-style "gnu")
3640 * End:
3641 */