misc: api move continued
[vpp.git] / src / vat / api_format.c
1 /*
2  *------------------------------------------------------------------
3  * api_format.c
4  *
5  * Copyright (c) 2014-2020 Cisco and/or its affiliates.
6  * 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>
21 #include <vlib/pci/pci.h>
22 #include <vpp/api/types.h>
23 #include <vppinfra/socket.h>
24 #include <vlibapi/api.h>
25 #include <vlibmemory/api.h>
26 #include <vnet/ip/ip.h>
27 #include <vnet/ip-neighbor/ip_neighbor.h>
28 #include <vnet/ip/ip_types_api.h>
29 #include <vnet/l2/l2_input.h>
30 #include <vnet/udp/udp_local.h>
31
32 #include <vpp/api/vpe_msg_enum.h>
33 #include <vnet/l2/l2_classify.h>
34 #include <vnet/l2/l2_vtr.h>
35 #include <vnet/classify/in_out_acl.h>
36 #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>
40 #include <inttypes.h>
41 #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>
47 #include <vnet/mfib/mfib_types.h>
48 #include <vnet/bonding/node.h>
49 #include <vnet/qos/qos_types.h>
50 #include <vnet/ethernet/ethernet_types_api.h>
51 #include <vnet/ip/ip_types_api.h>
52 #include "vat/json_format.h"
53 #include <vnet/ip/ip_types_api.h>
54 #include <vnet/ethernet/ethernet_types_api.h>
55
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 */
70 #if VPP_API_TEST_BUILTIN == 0
71 #define vl_print(handle, ...)
72 #else
73 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
74 #endif
75 #define vl_printfun
76 #include <vpp/api/vpe_all_api_h.h>
77 #undef vl_printfun
78
79 #define __plugin_msg_base 0
80 #include <vlibapi/vat_helper_macros.h>
81
82 void vl_api_set_elog_main (elog_main_t * m);
83 int vl_api_set_elog_trace_api_messages (int enable);
84
85 #if VPP_API_TEST_BUILTIN == 0
86 #include <netdb.h>
87
88 u32
89 vl (void *p)
90 {
91   return vec_len (p);
92 }
93
94 int
95 vat_socket_connect (vat_main_t * vam)
96 {
97   int rv;
98   api_main_t *am = vlibapi_get_main ();
99   vam->socket_client_main = &socket_client_main;
100   if ((rv = vl_socket_client_connect ((char *) vam->socket_name,
101                                       "vpp_api_test",
102                                       0 /* default socket rx, tx buffer */ )))
103     return rv;
104
105   /* vpp expects the client index in network order */
106   vam->my_client_index = htonl (socket_client_main.client_index);
107   am->my_client_index = vam->my_client_index;
108   return 0;
109 }
110 #else /* vpp built-in case, we don't do sockets... */
111 int
112 vat_socket_connect (vat_main_t * vam)
113 {
114   return 0;
115 }
116
117 int
118 vl_socket_client_read (int wait)
119 {
120   return -1;
121 };
122
123 int
124 vl_socket_client_write ()
125 {
126   return -1;
127 };
128
129 void *
130 vl_socket_client_msg_alloc (int nbytes)
131 {
132   return 0;
133 }
134 #endif
135
136
137 f64
138 vat_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
147 void
148 errmsg (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);
167     else
168       fformat (vam->ofp, "%s\n", (char *) s);
169     fflush (vam->ofp);
170   }
171 #endif
172
173   vec_free (s);
174 }
175
176 #if VPP_API_TEST_BUILTIN == 0
177 static uword
178 api_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
195 /* Parse an IP4 address %d.%d.%d.%d. */
196 uword
197 unformat_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
216 uword
217 unformat_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. */
238 uword
239 unformat_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
256 /* Parse an IP46 address. */
257 uword
258 unformat_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
276 /* Parse an IP6 address. */
277 uword
278 unformat_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
368 uword
369 unformat_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
382 u8 *
383 format_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
399 u8 *
400 format_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
416 #else /* VPP_API_TEST_BUILTIN == 1 */
417 static uword
418 api_unformat_sw_if_index (unformat_input_t * input, va_list * args)
419 {
420   vat_main_t *vam __clib_unused = va_arg (*args, vat_main_t *);
421   vnet_main_t *vnm = vnet_get_main ();
422   u32 *result = va_arg (*args, u32 *);
423
424   return unformat (input, "%U", unformat_vnet_sw_interface, vnm, result);
425 }
426
427 #endif /* VPP_API_TEST_BUILTIN */
428
429 #if (VPP_API_TEST_BUILTIN==0)
430
431 static const char *mfib_flag_names[] = MFIB_ENTRY_NAMES_SHORT;
432 static const char *mfib_flag_long_names[] = MFIB_ENTRY_NAMES_LONG;
433 static const char *mfib_itf_flag_long_names[] = MFIB_ITF_NAMES_LONG;
434 static const char *mfib_itf_flag_names[] = MFIB_ITF_NAMES_SHORT;
435
436 uword
437 unformat_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
457 uword
458 unformat_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
478 u8 *
479 format_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
485 u8 *
486 format_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. */
536 u8 *
537 format_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
561 u8 *
562 format_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
571 void
572 ip_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
581
582 static void vl_api_show_version_reply_t_handler
583   (vl_api_show_version_reply_t * mp)
584 {
585   vat_main_t *vam = &vat_main;
586   i32 retval = ntohl (mp->retval);
587
588   if (retval >= 0)
589     {
590       errmsg ("        program: %s", mp->program);
591       errmsg ("        version: %s", mp->version);
592       errmsg ("     build date: %s", mp->build_date);
593       errmsg ("build directory: %s", mp->build_directory);
594     }
595   vam->retval = retval;
596   vam->result_ready = 1;
597 }
598
599 static void vl_api_show_version_reply_t_handler_json
600   (vl_api_show_version_reply_t * mp)
601 {
602   vat_main_t *vam = &vat_main;
603   vat_json_node_t node;
604
605   vat_json_init_object (&node);
606   vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
607   vat_json_object_add_string_copy (&node, "program", mp->program);
608   vat_json_object_add_string_copy (&node, "version", mp->version);
609   vat_json_object_add_string_copy (&node, "build_date", mp->build_date);
610   vat_json_object_add_string_copy (&node, "build_directory",
611                                    mp->build_directory);
612
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
620 #define vl_api_bridge_domain_details_t_endian vl_noop_handler
621 #define vl_api_bridge_domain_details_t_print vl_noop_handler
622
623 static void vl_api_get_first_msg_id_reply_t_handler
624   (vl_api_get_first_msg_id_reply_t * mp)
625 {
626   vat_main_t *vam = &vat_main;
627   i32 retval = ntohl (mp->retval);
628
629   if (vam->async_mode)
630     {
631       vam->async_errors += (retval < 0);
632     }
633   else
634     {
635       vam->retval = retval;
636       vam->result_ready = 1;
637     }
638   if (retval >= 0)
639     {
640       errmsg ("first message id %d", ntohs (mp->first_msg_id));
641     }
642 }
643
644 static void vl_api_get_first_msg_id_reply_t_handler_json
645   (vl_api_get_first_msg_id_reply_t * mp)
646 {
647   vat_main_t *vam = &vat_main;
648   vat_json_node_t node;
649
650   vat_json_init_object (&node);
651   vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
652   vat_json_object_add_uint (&node, "first_msg_id",
653                             (uint) ntohs (mp->first_msg_id));
654
655   vat_json_print (vam->ofp, &node);
656   vat_json_free (&node);
657
658   vam->retval = ntohl (mp->retval);
659   vam->result_ready = 1;
660 }
661
662 /* Format hex dump. */
663 u8 *
664 format_hex_bytes (u8 * s, va_list * va)
665 {
666   u8 *bytes = va_arg (*va, u8 *);
667   int n_bytes = va_arg (*va, int);
668   uword i;
669
670   /* Print short or long form depending on byte count. */
671   uword short_form = n_bytes <= 32;
672   u32 indent = format_get_indent (s);
673
674   if (n_bytes == 0)
675     return s;
676
677   for (i = 0; i < n_bytes; i++)
678     {
679       if (!short_form && (i % 32) == 0)
680         s = format (s, "%08x: ", i);
681       s = format (s, "%02x", bytes[i]);
682       if (!short_form && ((i + 1) % 32) == 0 && (i + 1) < n_bytes)
683         s = format (s, "\n%U", format_white_space, indent);
684     }
685
686   return s;
687 }
688
689 /*
690  * Generate boilerplate reply handlers, which
691  * dig the return value out of the xxx_reply_t API message,
692  * stick it into vam->retval, and set vam->result_ready
693  *
694  * Could also do this by pointing N message decode slots at
695  * a single function, but that could break in subtle ways.
696  */
697
698 #define foreach_standard_reply_retval_handler
699
700 #define _(n)                                    \
701     static void vl_api_##n##_t_handler          \
702     (vl_api_##n##_t * mp)                       \
703     {                                           \
704         vat_main_t * vam = &vat_main;           \
705         i32 retval = ntohl(mp->retval);         \
706         if (vam->async_mode) {                  \
707             vam->async_errors += (retval < 0);  \
708         } else {                                \
709             vam->retval = retval;               \
710             vam->result_ready = 1;              \
711         }                                       \
712     }
713 foreach_standard_reply_retval_handler;
714 #undef _
715
716 #define _(n)                                    \
717     static void vl_api_##n##_t_handler_json     \
718     (vl_api_##n##_t * mp)                       \
719     {                                           \
720         vat_main_t * vam = &vat_main;           \
721         vat_json_node_t node;                   \
722         vat_json_init_object(&node);            \
723         vat_json_object_add_int(&node, "retval", ntohl(mp->retval));    \
724         vat_json_print(vam->ofp, &node);        \
725         vam->retval = ntohl(mp->retval);        \
726         vam->result_ready = 1;                  \
727     }
728 foreach_standard_reply_retval_handler;
729 #undef _
730
731 /*
732  * Table of message reply handlers, must include boilerplate handlers
733  * we just generated
734  */
735
736 #define foreach_vpe_api_reply_msg                                             \
737   _ (GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply)                          \
738   _ (SHOW_VERSION_REPLY, show_version_reply)                                  \
739
740 #define foreach_standalone_reply_msg                                    \
741
742 typedef struct
743 {
744   u8 *name;
745   u32 value;
746 } name_sort_t;
747
748 #define STR_VTR_OP_CASE(op)     \
749     case L2_VTR_ ## op:         \
750         return "" # op;
751
752 int
753 api_sw_interface_dump (vat_main_t *vam)
754 {
755   return 0;
756 }
757
758 uword
759 unformat_vlib_pci_addr (unformat_input_t *input, va_list *args)
760 {
761   vlib_pci_addr_t *addr = va_arg (*args, vlib_pci_addr_t *);
762   u32 x[4];
763
764   if (!unformat (input, "%x:%x:%x.%x", &x[0], &x[1], &x[2], &x[3]))
765     return 0;
766
767   addr->domain = x[0];
768   addr->bus = x[1];
769   addr->slot = x[2];
770   addr->function = x[3];
771
772   return 1;
773 }
774
775 uword
776 unformat_fib_path (unformat_input_t *input, va_list *args)
777 {
778   vat_main_t *vam = va_arg (*args, vat_main_t *);
779   vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t *);
780   u32 weight, preference;
781   mpls_label_t out_label;
782
783   clib_memset (path, 0, sizeof (*path));
784   path->weight = 1;
785   path->sw_if_index = ~0;
786   path->rpf_id = ~0;
787   path->n_labels = 0;
788
789   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
790     {
791       if (unformat (input, "%U %U", unformat_vl_api_ip4_address,
792                     &path->nh.address.ip4, api_unformat_sw_if_index, vam,
793                     &path->sw_if_index))
794         {
795           path->proto = FIB_API_PATH_NH_PROTO_IP4;
796         }
797       else if (unformat (input, "%U %U",
798                          unformat_vl_api_ip6_address,
799                          &path->nh.address.ip6,
800                          api_unformat_sw_if_index, vam, &path->sw_if_index))
801         {
802           path->proto = FIB_API_PATH_NH_PROTO_IP6;
803         }
804       else if (unformat (input, "weight %u", &weight))
805         {
806           path->weight = weight;
807         }
808       else if (unformat (input, "preference %u", &preference))
809         {
810           path->preference = preference;
811         }
812       else if (unformat (input, "%U next-hop-table %d",
813                          unformat_vl_api_ip4_address,
814                          &path->nh.address.ip4, &path->table_id))
815         {
816           path->proto = FIB_API_PATH_NH_PROTO_IP4;
817         }
818       else if (unformat (input, "%U next-hop-table %d",
819                          unformat_vl_api_ip6_address,
820                          &path->nh.address.ip6, &path->table_id))
821         {
822           path->proto = FIB_API_PATH_NH_PROTO_IP6;
823         }
824       else if (unformat (input, "%U",
825                          unformat_vl_api_ip4_address, &path->nh.address.ip4))
826         {
827           /*
828            * the recursive next-hops are by default in the default table
829            */
830           path->table_id = 0;
831           path->sw_if_index = ~0;
832           path->proto = FIB_API_PATH_NH_PROTO_IP4;
833         }
834       else if (unformat (input, "%U",
835                          unformat_vl_api_ip6_address, &path->nh.address.ip6))
836         {
837           /*
838            * the recursive next-hops are by default in the default table
839            */
840           path->table_id = 0;
841           path->sw_if_index = ~0;
842           path->proto = FIB_API_PATH_NH_PROTO_IP6;
843         }
844       else if (unformat (input, "resolve-via-host"))
845         {
846           path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_HOST;
847         }
848       else if (unformat (input, "resolve-via-attached"))
849         {
850           path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED;
851         }
852       else if (unformat (input, "ip4-lookup-in-table %d", &path->table_id))
853         {
854           path->type = FIB_API_PATH_TYPE_LOCAL;
855           path->sw_if_index = ~0;
856           path->proto = FIB_API_PATH_NH_PROTO_IP4;
857         }
858       else if (unformat (input, "ip6-lookup-in-table %d", &path->table_id))
859         {
860           path->type = FIB_API_PATH_TYPE_LOCAL;
861           path->sw_if_index = ~0;
862           path->proto = FIB_API_PATH_NH_PROTO_IP6;
863         }
864       else if (unformat (input, "sw_if_index %d", &path->sw_if_index))
865         ;
866       else if (unformat (input, "via-label %d", &path->nh.via_label))
867         {
868           path->proto = FIB_API_PATH_NH_PROTO_MPLS;
869           path->sw_if_index = ~0;
870         }
871       else if (unformat (input, "l2-input-on %d", &path->sw_if_index))
872         {
873           path->proto = FIB_API_PATH_NH_PROTO_ETHERNET;
874           path->type = FIB_API_PATH_TYPE_INTERFACE_RX;
875         }
876       else if (unformat (input, "local"))
877         {
878           path->type = FIB_API_PATH_TYPE_LOCAL;
879         }
880       else if (unformat (input, "out-labels"))
881         {
882           while (unformat (input, "%d", &out_label))
883             {
884               path->label_stack[path->n_labels].label = out_label;
885               path->label_stack[path->n_labels].is_uniform = 0;
886               path->label_stack[path->n_labels].ttl = 64;
887               path->n_labels++;
888             }
889         }
890       else if (unformat (input, "via"))
891         {
892           /* new path, back up and return */
893           unformat_put_input (input);
894           unformat_put_input (input);
895           unformat_put_input (input);
896           unformat_put_input (input);
897           break;
898         }
899       else
900         {
901           return (0);
902         }
903     }
904
905   path->proto = ntohl (path->proto);
906   path->type = ntohl (path->type);
907   path->flags = ntohl (path->flags);
908   path->table_id = ntohl (path->table_id);
909   path->sw_if_index = ntohl (path->sw_if_index);
910
911   return (1);
912 }
913
914 #define foreach_create_subif_bit                \
915 _(no_tags)                                      \
916 _(one_tag)                                      \
917 _(two_tags)                                     \
918 _(dot1ad)                                       \
919 _(exact_match)                                  \
920 _(default_sub)                                  \
921 _(outer_vlan_id_any)                            \
922 _(inner_vlan_id_any)
923
924 #define foreach_create_subif_flag               \
925 _(0, "no_tags")                                 \
926 _(1, "one_tag")                                 \
927 _(2, "two_tags")                                \
928 _(3, "dot1ad")                                  \
929 _(4, "exact_match")                             \
930 _(5, "default_sub")                             \
931 _(6, "outer_vlan_id_any")                       \
932 _(7, "inner_vlan_id_any")
933
934
935 #define foreach_tcp_proto_field                                               \
936   _ (src_port)                                                                \
937   _ (dst_port)
938
939 #define foreach_udp_proto_field                                               \
940   _ (src_port)                                                                \
941   _ (dst_port)
942
943 #define foreach_ip4_proto_field                                               \
944   _ (src_address)                                                             \
945   _ (dst_address)                                                             \
946   _ (tos)                                                                     \
947   _ (length)                                                                  \
948   _ (fragment_id)                                                             \
949   _ (ttl)                                                                     \
950   _ (protocol)                                                                \
951   _ (checksum)
952
953 typedef struct
954 {
955   u16 src_port, dst_port;
956 } tcpudp_header_t;
957
958 #if VPP_API_TEST_BUILTIN == 0
959 uword
960 unformat_tcp_mask (unformat_input_t *input, va_list *args)
961 {
962   u8 **maskp = va_arg (*args, u8 **);
963   u8 *mask = 0;
964   u8 found_something = 0;
965   tcp_header_t *tcp;
966
967 #define _(a) u8 a = 0;
968   foreach_tcp_proto_field;
969 #undef _
970
971   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
972     {
973       if (0)
974         ;
975 #define _(a) else if (unformat (input, #a)) a = 1;
976       foreach_tcp_proto_field
977 #undef _
978         else break;
979     }
980
981 #define _(a) found_something += a;
982   foreach_tcp_proto_field;
983 #undef _
984
985   if (found_something == 0)
986     return 0;
987
988   vec_validate (mask, sizeof (*tcp) - 1);
989
990   tcp = (tcp_header_t *) mask;
991
992 #define _(a)                                                                  \
993   if (a)                                                                      \
994     clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
995   foreach_tcp_proto_field;
996 #undef _
997
998   *maskp = mask;
999   return 1;
1000 }
1001
1002 uword
1003 unformat_udp_mask (unformat_input_t *input, va_list *args)
1004 {
1005   u8 **maskp = va_arg (*args, u8 **);
1006   u8 *mask = 0;
1007   u8 found_something = 0;
1008   udp_header_t *udp;
1009
1010 #define _(a) u8 a = 0;
1011   foreach_udp_proto_field;
1012 #undef _
1013
1014   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1015     {
1016       if (0)
1017         ;
1018 #define _(a) else if (unformat (input, #a)) a = 1;
1019       foreach_udp_proto_field
1020 #undef _
1021         else break;
1022     }
1023
1024 #define _(a) found_something += a;
1025   foreach_udp_proto_field;
1026 #undef _
1027
1028   if (found_something == 0)
1029     return 0;
1030
1031   vec_validate (mask, sizeof (*udp) - 1);
1032
1033   udp = (udp_header_t *) mask;
1034
1035 #define _(a)                                                                  \
1036   if (a)                                                                      \
1037     clib_memset (&udp->a, 0xff, sizeof (udp->a));
1038   foreach_udp_proto_field;
1039 #undef _
1040
1041   *maskp = mask;
1042   return 1;
1043 }
1044
1045 uword
1046 unformat_l4_mask (unformat_input_t *input, va_list *args)
1047 {
1048   u8 **maskp = va_arg (*args, u8 **);
1049   u16 src_port = 0, dst_port = 0;
1050   tcpudp_header_t *tcpudp;
1051
1052   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1053     {
1054       if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
1055         return 1;
1056       else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
1057         return 1;
1058       else if (unformat (input, "src_port"))
1059         src_port = 0xFFFF;
1060       else if (unformat (input, "dst_port"))
1061         dst_port = 0xFFFF;
1062       else
1063         return 0;
1064     }
1065
1066   if (!src_port && !dst_port)
1067     return 0;
1068
1069   u8 *mask = 0;
1070   vec_validate (mask, sizeof (tcpudp_header_t) - 1);
1071
1072   tcpudp = (tcpudp_header_t *) mask;
1073   tcpudp->src_port = src_port;
1074   tcpudp->dst_port = dst_port;
1075
1076   *maskp = mask;
1077
1078   return 1;
1079 }
1080
1081 uword
1082 unformat_ip4_mask (unformat_input_t * input, va_list * args)
1083 {
1084   u8 **maskp = va_arg (*args, u8 **);
1085   u8 *mask = 0;
1086   u8 found_something = 0;
1087   ip4_header_t *ip;
1088
1089 #define _(a) u8 a=0;
1090   foreach_ip4_proto_field;
1091 #undef _
1092   u8 version = 0;
1093   u8 hdr_length = 0;
1094
1095
1096   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1097     {
1098       if (unformat (input, "version"))
1099         version = 1;
1100       else if (unformat (input, "hdr_length"))
1101         hdr_length = 1;
1102       else if (unformat (input, "src"))
1103         src_address = 1;
1104       else if (unformat (input, "dst"))
1105         dst_address = 1;
1106       else if (unformat (input, "proto"))
1107         protocol = 1;
1108
1109 #define _(a) else if (unformat (input, #a)) a=1;
1110       foreach_ip4_proto_field
1111 #undef _
1112         else
1113         break;
1114     }
1115
1116 #define _(a) found_something += a;
1117   foreach_ip4_proto_field;
1118 #undef _
1119
1120   if (found_something == 0)
1121     return 0;
1122
1123   vec_validate (mask, sizeof (*ip) - 1);
1124
1125   ip = (ip4_header_t *) mask;
1126
1127 #define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
1128   foreach_ip4_proto_field;
1129 #undef _
1130
1131   ip->ip_version_and_header_length = 0;
1132
1133   if (version)
1134     ip->ip_version_and_header_length |= 0xF0;
1135
1136   if (hdr_length)
1137     ip->ip_version_and_header_length |= 0x0F;
1138
1139   *maskp = mask;
1140   return 1;
1141 }
1142
1143 #define foreach_ip6_proto_field                 \
1144 _(src_address)                                  \
1145 _(dst_address)                                  \
1146 _(payload_length)                               \
1147 _(hop_limit)                                    \
1148 _(protocol)
1149
1150 uword
1151 unformat_ip6_mask (unformat_input_t * input, va_list * args)
1152 {
1153   u8 **maskp = va_arg (*args, u8 **);
1154   u8 *mask = 0;
1155   u8 found_something = 0;
1156   ip6_header_t *ip;
1157   u32 ip_version_traffic_class_and_flow_label;
1158
1159 #define _(a) u8 a=0;
1160   foreach_ip6_proto_field;
1161 #undef _
1162   u8 version = 0;
1163   u8 traffic_class = 0;
1164   u8 flow_label = 0;
1165
1166   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1167     {
1168       if (unformat (input, "version"))
1169         version = 1;
1170       else if (unformat (input, "traffic-class"))
1171         traffic_class = 1;
1172       else if (unformat (input, "flow-label"))
1173         flow_label = 1;
1174       else if (unformat (input, "src"))
1175         src_address = 1;
1176       else if (unformat (input, "dst"))
1177         dst_address = 1;
1178       else if (unformat (input, "proto"))
1179         protocol = 1;
1180
1181 #define _(a) else if (unformat (input, #a)) a=1;
1182       foreach_ip6_proto_field
1183 #undef _
1184         else
1185         break;
1186     }
1187
1188 #define _(a) found_something += a;
1189   foreach_ip6_proto_field;
1190 #undef _
1191
1192   if (found_something == 0)
1193     return 0;
1194
1195   vec_validate (mask, sizeof (*ip) - 1);
1196
1197   ip = (ip6_header_t *) mask;
1198
1199 #define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
1200   foreach_ip6_proto_field;
1201 #undef _
1202
1203   ip_version_traffic_class_and_flow_label = 0;
1204
1205   if (version)
1206     ip_version_traffic_class_and_flow_label |= 0xF0000000;
1207
1208   if (traffic_class)
1209     ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1210
1211   if (flow_label)
1212     ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1213
1214   ip->ip_version_traffic_class_and_flow_label =
1215     clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1216
1217   *maskp = mask;
1218   return 1;
1219 }
1220
1221 uword
1222 unformat_l3_mask (unformat_input_t * input, va_list * args)
1223 {
1224   u8 **maskp = va_arg (*args, u8 **);
1225
1226   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1227     {
1228       if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1229         return 1;
1230       else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1231         return 1;
1232       else
1233         break;
1234     }
1235   return 0;
1236 }
1237
1238 uword
1239 unformat_l2_mask (unformat_input_t * input, va_list * args)
1240 {
1241   u8 **maskp = va_arg (*args, u8 **);
1242   u8 *mask = 0;
1243   u8 src = 0;
1244   u8 dst = 0;
1245   u8 proto = 0;
1246   u8 tag1 = 0;
1247   u8 tag2 = 0;
1248   u8 ignore_tag1 = 0;
1249   u8 ignore_tag2 = 0;
1250   u8 cos1 = 0;
1251   u8 cos2 = 0;
1252   u8 dot1q = 0;
1253   u8 dot1ad = 0;
1254   int len = 14;
1255
1256   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1257     {
1258       if (unformat (input, "src"))
1259         src = 1;
1260       else if (unformat (input, "dst"))
1261         dst = 1;
1262       else if (unformat (input, "proto"))
1263         proto = 1;
1264       else if (unformat (input, "tag1"))
1265         tag1 = 1;
1266       else if (unformat (input, "tag2"))
1267         tag2 = 1;
1268       else if (unformat (input, "ignore-tag1"))
1269         ignore_tag1 = 1;
1270       else if (unformat (input, "ignore-tag2"))
1271         ignore_tag2 = 1;
1272       else if (unformat (input, "cos1"))
1273         cos1 = 1;
1274       else if (unformat (input, "cos2"))
1275         cos2 = 1;
1276       else if (unformat (input, "dot1q"))
1277         dot1q = 1;
1278       else if (unformat (input, "dot1ad"))
1279         dot1ad = 1;
1280       else
1281         break;
1282     }
1283   if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
1284        ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1285     return 0;
1286
1287   if (tag1 || ignore_tag1 || cos1 || dot1q)
1288     len = 18;
1289   if (tag2 || ignore_tag2 || cos2 || dot1ad)
1290     len = 22;
1291
1292   vec_validate (mask, len - 1);
1293
1294   if (dst)
1295     clib_memset (mask, 0xff, 6);
1296
1297   if (src)
1298     clib_memset (mask + 6, 0xff, 6);
1299
1300   if (tag2 || dot1ad)
1301     {
1302       /* inner vlan tag */
1303       if (tag2)
1304         {
1305           mask[19] = 0xff;
1306           mask[18] = 0x0f;
1307         }
1308       if (cos2)
1309         mask[18] |= 0xe0;
1310       if (proto)
1311         mask[21] = mask[20] = 0xff;
1312       if (tag1)
1313         {
1314           mask[15] = 0xff;
1315           mask[14] = 0x0f;
1316         }
1317       if (cos1)
1318         mask[14] |= 0xe0;
1319       *maskp = mask;
1320       return 1;
1321     }
1322   if (tag1 | dot1q)
1323     {
1324       if (tag1)
1325         {
1326           mask[15] = 0xff;
1327           mask[14] = 0x0f;
1328         }
1329       if (cos1)
1330         mask[14] |= 0xe0;
1331       if (proto)
1332         mask[16] = mask[17] = 0xff;
1333
1334       *maskp = mask;
1335       return 1;
1336     }
1337   if (cos2)
1338     mask[18] |= 0xe0;
1339   if (cos1)
1340     mask[14] |= 0xe0;
1341   if (proto)
1342     mask[12] = mask[13] = 0xff;
1343
1344   *maskp = mask;
1345   return 1;
1346 }
1347
1348 uword
1349 unformat_classify_mask (unformat_input_t * input, va_list * args)
1350 {
1351   u8 **maskp = va_arg (*args, u8 **);
1352   u32 *skipp = va_arg (*args, u32 *);
1353   u32 *matchp = va_arg (*args, u32 *);
1354   u32 match;
1355   u8 *mask = 0;
1356   u8 *l2 = 0;
1357   u8 *l3 = 0;
1358   u8 *l4 = 0;
1359   int i;
1360
1361   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1362     {
1363       if (unformat (input, "hex %U", unformat_hex_string, &mask))
1364         ;
1365       else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1366         ;
1367       else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1368         ;
1369       else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1370         ;
1371       else
1372         break;
1373     }
1374
1375   if (l4 && !l3)
1376     {
1377       vec_free (mask);
1378       vec_free (l2);
1379       vec_free (l4);
1380       return 0;
1381     }
1382
1383   if (mask || l2 || l3 || l4)
1384     {
1385       if (l2 || l3 || l4)
1386         {
1387           /* "With a free Ethernet header in every package" */
1388           if (l2 == 0)
1389             vec_validate (l2, 13);
1390           mask = l2;
1391           if (vec_len (l3))
1392             {
1393               vec_append (mask, l3);
1394               vec_free (l3);
1395             }
1396           if (vec_len (l4))
1397             {
1398               vec_append (mask, l4);
1399               vec_free (l4);
1400             }
1401         }
1402
1403       /* Scan forward looking for the first significant mask octet */
1404       for (i = 0; i < vec_len (mask); i++)
1405         if (mask[i])
1406           break;
1407
1408       /* compute (skip, match) params */
1409       *skipp = i / sizeof (u32x4);
1410       vec_delete (mask, *skipp * sizeof (u32x4), 0);
1411
1412       /* Pad mask to an even multiple of the vector size */
1413       while (vec_len (mask) % sizeof (u32x4))
1414         vec_add1 (mask, 0);
1415
1416       match = vec_len (mask) / sizeof (u32x4);
1417
1418       for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1419         {
1420           u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1421           if (*tmp || *(tmp + 1))
1422             break;
1423           match--;
1424         }
1425       if (match == 0)
1426         clib_warning ("BUG: match 0");
1427
1428       _vec_len (mask) = match * sizeof (u32x4);
1429
1430       *matchp = match;
1431       *maskp = mask;
1432
1433       return 1;
1434     }
1435
1436   return 0;
1437 }
1438 #endif /* VPP_API_TEST_BUILTIN */
1439
1440 #define foreach_l2_next                         \
1441 _(drop, DROP)                                   \
1442 _(ethernet, ETHERNET_INPUT)                     \
1443 _(ip4, IP4_INPUT)                               \
1444 _(ip6, IP6_INPUT)
1445
1446 uword
1447 unformat_l2_next_index (unformat_input_t * input, va_list * args)
1448 {
1449   u32 *miss_next_indexp = va_arg (*args, u32 *);
1450   u32 next_index = 0;
1451   u32 tmp;
1452
1453 #define _(n,N) \
1454   if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1455   foreach_l2_next;
1456 #undef _
1457
1458   if (unformat (input, "%d", &tmp))
1459     {
1460       next_index = tmp;
1461       goto out;
1462     }
1463
1464   return 0;
1465
1466 out:
1467   *miss_next_indexp = next_index;
1468   return 1;
1469 }
1470
1471 #define foreach_ip_next                         \
1472 _(drop, DROP)                                   \
1473 _(local, LOCAL)                                 \
1474 _(rewrite, REWRITE)
1475
1476 uword
1477 api_unformat_ip_next_index (unformat_input_t * input, va_list * args)
1478 {
1479   u32 *miss_next_indexp = va_arg (*args, u32 *);
1480   u32 next_index = 0;
1481   u32 tmp;
1482
1483 #define _(n,N) \
1484   if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1485   foreach_ip_next;
1486 #undef _
1487
1488   if (unformat (input, "%d", &tmp))
1489     {
1490       next_index = tmp;
1491       goto out;
1492     }
1493
1494   return 0;
1495
1496 out:
1497   *miss_next_indexp = next_index;
1498   return 1;
1499 }
1500
1501 #define foreach_acl_next                        \
1502 _(deny, DENY)
1503
1504 uword
1505 api_unformat_acl_next_index (unformat_input_t * input, va_list * args)
1506 {
1507   u32 *miss_next_indexp = va_arg (*args, u32 *);
1508   u32 next_index = 0;
1509   u32 tmp;
1510
1511 #define _(n,N) \
1512   if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1513   foreach_acl_next;
1514 #undef _
1515
1516   if (unformat (input, "permit"))
1517     {
1518       next_index = ~0;
1519       goto out;
1520     }
1521   else if (unformat (input, "%d", &tmp))
1522     {
1523       next_index = tmp;
1524       goto out;
1525     }
1526
1527   return 0;
1528
1529 out:
1530   *miss_next_indexp = next_index;
1531   return 1;
1532 }
1533
1534 uword
1535 unformat_policer_precolor (unformat_input_t * input, va_list * args)
1536 {
1537   u32 *r = va_arg (*args, u32 *);
1538
1539   if (unformat (input, "conform-color"))
1540     *r = POLICE_CONFORM;
1541   else if (unformat (input, "exceed-color"))
1542     *r = POLICE_EXCEED;
1543   else
1544     return 0;
1545
1546   return 1;
1547 }
1548
1549 #if VPP_API_TEST_BUILTIN == 0
1550 uword
1551 unformat_l4_match (unformat_input_t * input, va_list * args)
1552 {
1553   u8 **matchp = va_arg (*args, u8 **);
1554
1555   u8 *proto_header = 0;
1556   int src_port = 0;
1557   int dst_port = 0;
1558
1559   tcpudp_header_t h;
1560
1561   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1562     {
1563       if (unformat (input, "src_port %d", &src_port))
1564         ;
1565       else if (unformat (input, "dst_port %d", &dst_port))
1566         ;
1567       else
1568         return 0;
1569     }
1570
1571   h.src_port = clib_host_to_net_u16 (src_port);
1572   h.dst_port = clib_host_to_net_u16 (dst_port);
1573   vec_validate (proto_header, sizeof (h) - 1);
1574   memcpy (proto_header, &h, sizeof (h));
1575
1576   *matchp = proto_header;
1577
1578   return 1;
1579 }
1580
1581 uword
1582 unformat_ip4_match (unformat_input_t * input, va_list * args)
1583 {
1584   u8 **matchp = va_arg (*args, u8 **);
1585   u8 *match = 0;
1586   ip4_header_t *ip;
1587   int version = 0;
1588   u32 version_val;
1589   int hdr_length = 0;
1590   u32 hdr_length_val;
1591   int src = 0, dst = 0;
1592   ip4_address_t src_val, dst_val;
1593   int proto = 0;
1594   u32 proto_val;
1595   int tos = 0;
1596   u32 tos_val;
1597   int length = 0;
1598   u32 length_val;
1599   int fragment_id = 0;
1600   u32 fragment_id_val;
1601   int ttl = 0;
1602   int ttl_val;
1603   int checksum = 0;
1604   u32 checksum_val;
1605
1606   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1607     {
1608       if (unformat (input, "version %d", &version_val))
1609         version = 1;
1610       else if (unformat (input, "hdr_length %d", &hdr_length_val))
1611         hdr_length = 1;
1612       else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
1613         src = 1;
1614       else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
1615         dst = 1;
1616       else if (unformat (input, "proto %d", &proto_val))
1617         proto = 1;
1618       else if (unformat (input, "tos %d", &tos_val))
1619         tos = 1;
1620       else if (unformat (input, "length %d", &length_val))
1621         length = 1;
1622       else if (unformat (input, "fragment_id %d", &fragment_id_val))
1623         fragment_id = 1;
1624       else if (unformat (input, "ttl %d", &ttl_val))
1625         ttl = 1;
1626       else if (unformat (input, "checksum %d", &checksum_val))
1627         checksum = 1;
1628       else
1629         break;
1630     }
1631
1632   if (version + hdr_length + src + dst + proto + tos + length + fragment_id
1633       + ttl + checksum == 0)
1634     return 0;
1635
1636   /*
1637    * Aligned because we use the real comparison functions
1638    */
1639   vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1640
1641   ip = (ip4_header_t *) match;
1642
1643   /* These are realistically matched in practice */
1644   if (src)
1645     ip->src_address.as_u32 = src_val.as_u32;
1646
1647   if (dst)
1648     ip->dst_address.as_u32 = dst_val.as_u32;
1649
1650   if (proto)
1651     ip->protocol = proto_val;
1652
1653
1654   /* These are not, but they're included for completeness */
1655   if (version)
1656     ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
1657
1658   if (hdr_length)
1659     ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
1660
1661   if (tos)
1662     ip->tos = tos_val;
1663
1664   if (length)
1665     ip->length = clib_host_to_net_u16 (length_val);
1666
1667   if (ttl)
1668     ip->ttl = ttl_val;
1669
1670   if (checksum)
1671     ip->checksum = clib_host_to_net_u16 (checksum_val);
1672
1673   *matchp = match;
1674   return 1;
1675 }
1676
1677 uword
1678 unformat_ip6_match (unformat_input_t * input, va_list * args)
1679 {
1680   u8 **matchp = va_arg (*args, u8 **);
1681   u8 *match = 0;
1682   ip6_header_t *ip;
1683   int version = 0;
1684   u32 version_val;
1685   u8 traffic_class = 0;
1686   u32 traffic_class_val = 0;
1687   u8 flow_label = 0;
1688   u8 flow_label_val;
1689   int src = 0, dst = 0;
1690   ip6_address_t src_val, dst_val;
1691   int proto = 0;
1692   u32 proto_val;
1693   int payload_length = 0;
1694   u32 payload_length_val;
1695   int hop_limit = 0;
1696   int hop_limit_val;
1697   u32 ip_version_traffic_class_and_flow_label;
1698
1699   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1700     {
1701       if (unformat (input, "version %d", &version_val))
1702         version = 1;
1703       else if (unformat (input, "traffic_class %d", &traffic_class_val))
1704         traffic_class = 1;
1705       else if (unformat (input, "flow_label %d", &flow_label_val))
1706         flow_label = 1;
1707       else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
1708         src = 1;
1709       else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
1710         dst = 1;
1711       else if (unformat (input, "proto %d", &proto_val))
1712         proto = 1;
1713       else if (unformat (input, "payload_length %d", &payload_length_val))
1714         payload_length = 1;
1715       else if (unformat (input, "hop_limit %d", &hop_limit_val))
1716         hop_limit = 1;
1717       else
1718         break;
1719     }
1720
1721   if (version + traffic_class + flow_label + src + dst + proto +
1722       payload_length + hop_limit == 0)
1723     return 0;
1724
1725   /*
1726    * Aligned because we use the real comparison functions
1727    */
1728   vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1729
1730   ip = (ip6_header_t *) match;
1731
1732   if (src)
1733     clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
1734
1735   if (dst)
1736     clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
1737
1738   if (proto)
1739     ip->protocol = proto_val;
1740
1741   ip_version_traffic_class_and_flow_label = 0;
1742
1743   if (version)
1744     ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
1745
1746   if (traffic_class)
1747     ip_version_traffic_class_and_flow_label |=
1748       (traffic_class_val & 0xFF) << 20;
1749
1750   if (flow_label)
1751     ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
1752
1753   ip->ip_version_traffic_class_and_flow_label =
1754     clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1755
1756   if (payload_length)
1757     ip->payload_length = clib_host_to_net_u16 (payload_length_val);
1758
1759   if (hop_limit)
1760     ip->hop_limit = hop_limit_val;
1761
1762   *matchp = match;
1763   return 1;
1764 }
1765
1766 uword
1767 unformat_l3_match (unformat_input_t * input, va_list * args)
1768 {
1769   u8 **matchp = va_arg (*args, u8 **);
1770
1771   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1772     {
1773       if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
1774         return 1;
1775       else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
1776         return 1;
1777       else
1778         break;
1779     }
1780   return 0;
1781 }
1782
1783 uword
1784 unformat_vlan_tag (unformat_input_t * input, va_list * args)
1785 {
1786   u8 *tagp = va_arg (*args, u8 *);
1787   u32 tag;
1788
1789   if (unformat (input, "%d", &tag))
1790     {
1791       tagp[0] = (tag >> 8) & 0x0F;
1792       tagp[1] = tag & 0xFF;
1793       return 1;
1794     }
1795
1796   return 0;
1797 }
1798
1799 uword
1800 unformat_l2_match (unformat_input_t * input, va_list * args)
1801 {
1802   u8 **matchp = va_arg (*args, u8 **);
1803   u8 *match = 0;
1804   u8 src = 0;
1805   u8 src_val[6];
1806   u8 dst = 0;
1807   u8 dst_val[6];
1808   u8 proto = 0;
1809   u16 proto_val;
1810   u8 tag1 = 0;
1811   u8 tag1_val[2];
1812   u8 tag2 = 0;
1813   u8 tag2_val[2];
1814   int len = 14;
1815   u8 ignore_tag1 = 0;
1816   u8 ignore_tag2 = 0;
1817   u8 cos1 = 0;
1818   u8 cos2 = 0;
1819   u32 cos1_val = 0;
1820   u32 cos2_val = 0;
1821
1822   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1823     {
1824       if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
1825         src = 1;
1826       else
1827         if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
1828         dst = 1;
1829       else if (unformat (input, "proto %U",
1830                          unformat_ethernet_type_host_byte_order, &proto_val))
1831         proto = 1;
1832       else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
1833         tag1 = 1;
1834       else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
1835         tag2 = 1;
1836       else if (unformat (input, "ignore-tag1"))
1837         ignore_tag1 = 1;
1838       else if (unformat (input, "ignore-tag2"))
1839         ignore_tag2 = 1;
1840       else if (unformat (input, "cos1 %d", &cos1_val))
1841         cos1 = 1;
1842       else if (unformat (input, "cos2 %d", &cos2_val))
1843         cos2 = 1;
1844       else
1845         break;
1846     }
1847   if ((src + dst + proto + tag1 + tag2 +
1848        ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1849     return 0;
1850
1851   if (tag1 || ignore_tag1 || cos1)
1852     len = 18;
1853   if (tag2 || ignore_tag2 || cos2)
1854     len = 22;
1855
1856   vec_validate_aligned (match, len - 1, sizeof (u32x4));
1857
1858   if (dst)
1859     clib_memcpy (match, dst_val, 6);
1860
1861   if (src)
1862     clib_memcpy (match + 6, src_val, 6);
1863
1864   if (tag2)
1865     {
1866       /* inner vlan tag */
1867       match[19] = tag2_val[1];
1868       match[18] = tag2_val[0];
1869       if (cos2)
1870         match[18] |= (cos2_val & 0x7) << 5;
1871       if (proto)
1872         {
1873           match[21] = proto_val & 0xff;
1874           match[20] = proto_val >> 8;
1875         }
1876       if (tag1)
1877         {
1878           match[15] = tag1_val[1];
1879           match[14] = tag1_val[0];
1880         }
1881       if (cos1)
1882         match[14] |= (cos1_val & 0x7) << 5;
1883       *matchp = match;
1884       return 1;
1885     }
1886   if (tag1)
1887     {
1888       match[15] = tag1_val[1];
1889       match[14] = tag1_val[0];
1890       if (proto)
1891         {
1892           match[17] = proto_val & 0xff;
1893           match[16] = proto_val >> 8;
1894         }
1895       if (cos1)
1896         match[14] |= (cos1_val & 0x7) << 5;
1897
1898       *matchp = match;
1899       return 1;
1900     }
1901   if (cos2)
1902     match[18] |= (cos2_val & 0x7) << 5;
1903   if (cos1)
1904     match[14] |= (cos1_val & 0x7) << 5;
1905   if (proto)
1906     {
1907       match[13] = proto_val & 0xff;
1908       match[12] = proto_val >> 8;
1909     }
1910
1911   *matchp = match;
1912   return 1;
1913 }
1914
1915 uword
1916 unformat_qos_source (unformat_input_t * input, va_list * args)
1917 {
1918   int *qs = va_arg (*args, int *);
1919
1920   if (unformat (input, "ip"))
1921     *qs = QOS_SOURCE_IP;
1922   else if (unformat (input, "mpls"))
1923     *qs = QOS_SOURCE_MPLS;
1924   else if (unformat (input, "ext"))
1925     *qs = QOS_SOURCE_EXT;
1926   else if (unformat (input, "vlan"))
1927     *qs = QOS_SOURCE_VLAN;
1928   else
1929     return 0;
1930
1931   return 1;
1932 }
1933 #endif
1934
1935 uword
1936 api_unformat_classify_match (unformat_input_t * input, va_list * args)
1937 {
1938   u8 **matchp = va_arg (*args, u8 **);
1939   u32 skip_n_vectors = va_arg (*args, u32);
1940   u32 match_n_vectors = va_arg (*args, u32);
1941
1942   u8 *match = 0;
1943   u8 *l2 = 0;
1944   u8 *l3 = 0;
1945   u8 *l4 = 0;
1946
1947   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1948     {
1949       if (unformat (input, "hex %U", unformat_hex_string, &match))
1950         ;
1951       else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
1952         ;
1953       else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
1954         ;
1955       else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
1956         ;
1957       else
1958         break;
1959     }
1960
1961   if (l4 && !l3)
1962     {
1963       vec_free (match);
1964       vec_free (l2);
1965       vec_free (l4);
1966       return 0;
1967     }
1968
1969   if (match || l2 || l3 || l4)
1970     {
1971       if (l2 || l3 || l4)
1972         {
1973           /* "Win a free Ethernet header in every packet" */
1974           if (l2 == 0)
1975             vec_validate_aligned (l2, 13, sizeof (u32x4));
1976           match = l2;
1977           if (vec_len (l3))
1978             {
1979               vec_append_aligned (match, l3, sizeof (u32x4));
1980               vec_free (l3);
1981             }
1982           if (vec_len (l4))
1983             {
1984               vec_append_aligned (match, l4, sizeof (u32x4));
1985               vec_free (l4);
1986             }
1987         }
1988
1989       /* Make sure the vector is big enough even if key is all 0's */
1990       vec_validate_aligned
1991         (match, ((match_n_vectors + skip_n_vectors) * sizeof (u32x4)) - 1,
1992          sizeof (u32x4));
1993
1994       /* Set size, include skipped vectors */
1995       _vec_len (match) = (match_n_vectors + skip_n_vectors) * sizeof (u32x4);
1996
1997       *matchp = match;
1998
1999       return 1;
2000     }
2001
2002   return 0;
2003 }
2004
2005 #define foreach_vtr_op                                                        \
2006   _ ("disable", L2_VTR_DISABLED)                                              \
2007   _ ("push-1", L2_VTR_PUSH_1)                                                 \
2008   _ ("push-2", L2_VTR_PUSH_2)                                                 \
2009   _ ("pop-1", L2_VTR_POP_1)                                                   \
2010   _ ("pop-2", L2_VTR_POP_2)                                                   \
2011   _ ("translate-1-1", L2_VTR_TRANSLATE_1_1)                                   \
2012   _ ("translate-1-2", L2_VTR_TRANSLATE_1_2)                                   \
2013   _ ("translate-2-1", L2_VTR_TRANSLATE_2_1)                                   \
2014   _ ("translate-2-2", L2_VTR_TRANSLATE_2_2)
2015
2016 static int
2017 api_show_version (vat_main_t *vam)
2018 {
2019   vl_api_show_version_t *mp;
2020   int ret;
2021
2022   M (SHOW_VERSION, mp);
2023
2024   S (mp);
2025   W (ret);
2026   return ret;
2027 }
2028
2029 static int
2030 api_get_first_msg_id (vat_main_t *vam)
2031 {
2032   vl_api_get_first_msg_id_t *mp;
2033   unformat_input_t *i = vam->input;
2034   u8 *name;
2035   u8 name_set = 0;
2036   int ret;
2037
2038   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2039     {
2040       if (unformat (i, "client %s", &name))
2041         name_set = 1;
2042       else
2043         break;
2044     }
2045
2046   if (name_set == 0)
2047     {
2048       errmsg ("missing client name");
2049       return -99;
2050     }
2051   vec_add1 (name, 0);
2052
2053   if (vec_len (name) > 63)
2054     {
2055       errmsg ("client name too long");
2056       return -99;
2057     }
2058
2059   M (GET_FIRST_MSG_ID, mp);
2060   clib_memcpy (mp->name, name, vec_len (name));
2061   S (mp);
2062   W (ret);
2063   return ret;
2064 }
2065
2066 #define foreach_pbb_vtr_op      \
2067 _("disable",  L2_VTR_DISABLED)  \
2068 _("pop",  L2_VTR_POP_2)         \
2069 _("push",  L2_VTR_PUSH_2)
2070
2071 static int
2072 api_sock_init_shm (vat_main_t * vam)
2073 {
2074 #if VPP_API_TEST_BUILTIN == 0
2075   unformat_input_t *i = vam->input;
2076   vl_api_shm_elem_config_t *config = 0;
2077   u64 size = 64 << 20;
2078   int rv;
2079
2080   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2081     {
2082       if (unformat (i, "size %U", unformat_memory_size, &size))
2083         ;
2084       else
2085         break;
2086     }
2087
2088   /*
2089    * Canned custom ring allocator config.
2090    * Should probably parse all of this
2091    */
2092   vec_validate (config, 6);
2093   config[0].type = VL_API_VLIB_RING;
2094   config[0].size = 256;
2095   config[0].count = 32;
2096
2097   config[1].type = VL_API_VLIB_RING;
2098   config[1].size = 1024;
2099   config[1].count = 16;
2100
2101   config[2].type = VL_API_VLIB_RING;
2102   config[2].size = 4096;
2103   config[2].count = 2;
2104
2105   config[3].type = VL_API_CLIENT_RING;
2106   config[3].size = 256;
2107   config[3].count = 32;
2108
2109   config[4].type = VL_API_CLIENT_RING;
2110   config[4].size = 1024;
2111   config[4].count = 16;
2112
2113   config[5].type = VL_API_CLIENT_RING;
2114   config[5].size = 4096;
2115   config[5].count = 2;
2116
2117   config[6].type = VL_API_QUEUE;
2118   config[6].count = 128;
2119   config[6].size = sizeof (uword);
2120
2121   rv = vl_socket_client_init_shm (config, 1 /* want_pthread */ );
2122   if (!rv)
2123     vam->client_index_invalid = 1;
2124   return rv;
2125 #else
2126   return -99;
2127 #endif
2128 }
2129
2130 static int
2131 q_or_quit (vat_main_t * vam)
2132 {
2133 #if VPP_API_TEST_BUILTIN == 0
2134   longjmp (vam->jump_buf, 1);
2135 #endif
2136   return 0;                     /* not so much */
2137 }
2138
2139 static int
2140 q (vat_main_t * vam)
2141 {
2142   return q_or_quit (vam);
2143 }
2144
2145 static int
2146 quit (vat_main_t * vam)
2147 {
2148   return q_or_quit (vam);
2149 }
2150
2151 static int
2152 comment (vat_main_t * vam)
2153 {
2154   return 0;
2155 }
2156
2157 static int
2158 elog_save (vat_main_t * vam)
2159 {
2160 #if VPP_API_TEST_BUILTIN == 0
2161   elog_main_t *em = &vam->elog_main;
2162   unformat_input_t *i = vam->input;
2163   char *file, *chroot_file;
2164   clib_error_t *error;
2165
2166   if (!unformat (i, "%s", &file))
2167     {
2168       errmsg ("expected file name, got `%U'", format_unformat_error, i);
2169       return 0;
2170     }
2171
2172   /* It's fairly hard to get "../oopsie" through unformat; just in case */
2173   if (strstr (file, "..") || index (file, '/'))
2174     {
2175       errmsg ("illegal characters in filename '%s'", file);
2176       return 0;
2177     }
2178
2179   chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
2180
2181   vec_free (file);
2182
2183   errmsg ("Saving %wd of %wd events to %s",
2184           elog_n_events_in_buffer (em),
2185           elog_buffer_capacity (em), chroot_file);
2186
2187   error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
2188   vec_free (chroot_file);
2189
2190   if (error)
2191     clib_error_report (error);
2192 #else
2193   errmsg ("Use the vpp event loger...");
2194 #endif
2195
2196   return 0;
2197 }
2198
2199 static int
2200 elog_setup (vat_main_t * vam)
2201 {
2202 #if VPP_API_TEST_BUILTIN == 0
2203   elog_main_t *em = &vam->elog_main;
2204   unformat_input_t *i = vam->input;
2205   u32 nevents = 128 << 10;
2206
2207   (void) unformat (i, "nevents %d", &nevents);
2208
2209   elog_init (em, nevents);
2210   vl_api_set_elog_main (em);
2211   vl_api_set_elog_trace_api_messages (1);
2212   errmsg ("Event logger initialized with %u events", nevents);
2213 #else
2214   errmsg ("Use the vpp event loger...");
2215 #endif
2216   return 0;
2217 }
2218
2219 static int
2220 elog_enable (vat_main_t * vam)
2221 {
2222 #if VPP_API_TEST_BUILTIN == 0
2223   elog_main_t *em = &vam->elog_main;
2224
2225   elog_enable_disable (em, 1 /* enable */ );
2226   vl_api_set_elog_trace_api_messages (1);
2227   errmsg ("Event logger enabled...");
2228 #else
2229   errmsg ("Use the vpp event loger...");
2230 #endif
2231   return 0;
2232 }
2233
2234 static int
2235 elog_disable (vat_main_t * vam)
2236 {
2237 #if VPP_API_TEST_BUILTIN == 0
2238   elog_main_t *em = &vam->elog_main;
2239
2240   elog_enable_disable (em, 0 /* enable */ );
2241   vl_api_set_elog_trace_api_messages (1);
2242   errmsg ("Event logger disabled...");
2243 #else
2244   errmsg ("Use the vpp event loger...");
2245 #endif
2246   return 0;
2247 }
2248
2249 static int
2250 statseg (vat_main_t * vam)
2251 {
2252   ssvm_private_t *ssvmp = &vam->stat_segment;
2253   ssvm_shared_header_t *shared_header = ssvmp->sh;
2254   vlib_counter_t **counters;
2255   u64 thread0_index1_packets;
2256   u64 thread0_index1_bytes;
2257   f64 vector_rate, input_rate;
2258   uword *p;
2259
2260   uword *counter_vector_by_name;
2261   if (vam->stat_segment_lockp == 0)
2262     {
2263       errmsg ("Stat segment not mapped...");
2264       return -99;
2265     }
2266
2267   /* look up "/if/rx for sw_if_index 1 as a test */
2268
2269   clib_spinlock_lock (vam->stat_segment_lockp);
2270
2271   counter_vector_by_name = (uword *) shared_header->opaque[1];
2272
2273   p = hash_get_mem (counter_vector_by_name, "/if/rx");
2274   if (p == 0)
2275     {
2276       clib_spinlock_unlock (vam->stat_segment_lockp);
2277       errmsg ("/if/tx not found?");
2278       return -99;
2279     }
2280
2281   /* Fish per-thread vector of combined counters from shared memory */
2282   counters = (vlib_counter_t **) p[0];
2283
2284   if (vec_len (counters[0]) < 2)
2285     {
2286       clib_spinlock_unlock (vam->stat_segment_lockp);
2287       errmsg ("/if/tx vector length %d", vec_len (counters[0]));
2288       return -99;
2289     }
2290
2291   /* Read thread 0 sw_if_index 1 counter */
2292   thread0_index1_packets = counters[0][1].packets;
2293   thread0_index1_bytes = counters[0][1].bytes;
2294
2295   p = hash_get_mem (counter_vector_by_name, "vector_rate");
2296   if (p == 0)
2297     {
2298       clib_spinlock_unlock (vam->stat_segment_lockp);
2299       errmsg ("vector_rate not found?");
2300       return -99;
2301     }
2302
2303   vector_rate = *(f64 *) (p[0]);
2304   p = hash_get_mem (counter_vector_by_name, "input_rate");
2305   if (p == 0)
2306     {
2307       clib_spinlock_unlock (vam->stat_segment_lockp);
2308       errmsg ("input_rate not found?");
2309       return -99;
2310     }
2311   input_rate = *(f64 *) (p[0]);
2312
2313   clib_spinlock_unlock (vam->stat_segment_lockp);
2314
2315   print (vam->ofp, "vector_rate %.2f input_rate %.2f",
2316          vector_rate, input_rate);
2317   print (vam->ofp, "thread 0 sw_if_index 1 rx pkts %lld, bytes %lld",
2318          thread0_index1_packets, thread0_index1_bytes);
2319
2320   return 0;
2321 }
2322
2323 static int
2324 cmd_cmp (void *a1, void *a2)
2325 {
2326   u8 **c1 = a1;
2327   u8 **c2 = a2;
2328
2329   return strcmp ((char *) (c1[0]), (char *) (c2[0]));
2330 }
2331
2332 static int
2333 help (vat_main_t * vam)
2334 {
2335   u8 **cmds = 0;
2336   u8 *name = 0;
2337   hash_pair_t *p;
2338   unformat_input_t *i = vam->input;
2339   int j;
2340
2341   if (unformat (i, "%s", &name))
2342     {
2343       uword *hs;
2344
2345       vec_add1 (name, 0);
2346
2347       hs = hash_get_mem (vam->help_by_name, name);
2348       if (hs)
2349         print (vam->ofp, "usage: %s %s", name, hs[0]);
2350       else
2351         print (vam->ofp, "No such msg / command '%s'", name);
2352       vec_free (name);
2353       return 0;
2354     }
2355
2356   print (vam->ofp, "Help is available for the following:");
2357
2358     /* *INDENT-OFF* */
2359     hash_foreach_pair (p, vam->function_by_name,
2360     ({
2361       vec_add1 (cmds, (u8 *)(p->key));
2362     }));
2363     /* *INDENT-ON* */
2364
2365   vec_sort_with_function (cmds, cmd_cmp);
2366
2367   for (j = 0; j < vec_len (cmds); j++)
2368     print (vam->ofp, "%s", cmds[j]);
2369
2370   vec_free (cmds);
2371   return 0;
2372 }
2373
2374 static int
2375 set (vat_main_t * vam)
2376 {
2377   u8 *name = 0, *value = 0;
2378   unformat_input_t *i = vam->input;
2379
2380   if (unformat (i, "%s", &name))
2381     {
2382       /* The input buffer is a vector, not a string. */
2383       value = vec_dup (i->buffer);
2384       vec_delete (value, i->index, 0);
2385       /* Almost certainly has a trailing newline */
2386       if (value[vec_len (value) - 1] == '\n')
2387         value[vec_len (value) - 1] = 0;
2388       /* Make sure it's a proper string, one way or the other */
2389       vec_add1 (value, 0);
2390       (void) clib_macro_set_value (&vam->macro_main,
2391                                    (char *) name, (char *) value);
2392     }
2393   else
2394     errmsg ("usage: set <name> <value>");
2395
2396   vec_free (name);
2397   vec_free (value);
2398   return 0;
2399 }
2400
2401 static int
2402 unset (vat_main_t * vam)
2403 {
2404   u8 *name = 0;
2405
2406   if (unformat (vam->input, "%s", &name))
2407     if (clib_macro_unset (&vam->macro_main, (char *) name) == 1)
2408       errmsg ("unset: %s wasn't set", name);
2409   vec_free (name);
2410   return 0;
2411 }
2412
2413 typedef struct
2414 {
2415   u8 *name;
2416   u8 *value;
2417 } macro_sort_t;
2418
2419
2420 static int
2421 macro_sort_cmp (void *a1, void *a2)
2422 {
2423   macro_sort_t *s1 = a1;
2424   macro_sort_t *s2 = a2;
2425
2426   return strcmp ((char *) (s1->name), (char *) (s2->name));
2427 }
2428
2429 static int
2430 dump_macro_table (vat_main_t * vam)
2431 {
2432   macro_sort_t *sort_me = 0, *sm;
2433   int i;
2434   hash_pair_t *p;
2435
2436     /* *INDENT-OFF* */
2437     hash_foreach_pair (p, vam->macro_main.the_value_table_hash,
2438     ({
2439       vec_add2 (sort_me, sm, 1);
2440       sm->name = (u8 *)(p->key);
2441       sm->value = (u8 *) (p->value[0]);
2442     }));
2443     /* *INDENT-ON* */
2444
2445   vec_sort_with_function (sort_me, macro_sort_cmp);
2446
2447   if (vec_len (sort_me))
2448     print (vam->ofp, "%-15s%s", "Name", "Value");
2449   else
2450     print (vam->ofp, "The macro table is empty...");
2451
2452   for (i = 0; i < vec_len (sort_me); i++)
2453     print (vam->ofp, "%-15s%s", sort_me[i].name, sort_me[i].value);
2454   return 0;
2455 }
2456
2457 static int
2458 value_sort_cmp (void *a1, void *a2)
2459 {
2460   name_sort_t *n1 = a1;
2461   name_sort_t *n2 = a2;
2462
2463   if (n1->value < n2->value)
2464     return -1;
2465   if (n1->value > n2->value)
2466     return 1;
2467   return 0;
2468 }
2469
2470
2471 static int
2472 dump_msg_api_table (vat_main_t * vam)
2473 {
2474   api_main_t *am = vlibapi_get_main ();
2475   name_sort_t *nses = 0, *ns;
2476   hash_pair_t *hp;
2477   int i;
2478
2479   /* *INDENT-OFF* */
2480   hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
2481   ({
2482     vec_add2 (nses, ns, 1);
2483     ns->name = (u8 *)(hp->key);
2484     ns->value = (u32) hp->value[0];
2485   }));
2486   /* *INDENT-ON* */
2487
2488   vec_sort_with_function (nses, value_sort_cmp);
2489
2490   for (i = 0; i < vec_len (nses); i++)
2491     print (vam->ofp, " [%d]: %s", nses[i].value, nses[i].name);
2492   vec_free (nses);
2493   return 0;
2494 }
2495
2496 static int
2497 get_msg_id (vat_main_t * vam)
2498 {
2499   u8 *name_and_crc;
2500   u32 message_index;
2501
2502   if (unformat (vam->input, "%s", &name_and_crc))
2503     {
2504       message_index = vl_msg_api_get_msg_index (name_and_crc);
2505       if (message_index == ~0)
2506         {
2507           print (vam->ofp, " '%s' not found", name_and_crc);
2508           return 0;
2509         }
2510       print (vam->ofp, " '%s' has message index %d",
2511              name_and_crc, message_index);
2512       return 0;
2513     }
2514   errmsg ("name_and_crc required...");
2515   return 0;
2516 }
2517
2518 static int
2519 search_node_table (vat_main_t * vam)
2520 {
2521   unformat_input_t *line_input = vam->input;
2522   u8 *node_to_find;
2523   int j;
2524   vlib_node_t *node, *next_node;
2525   uword *p;
2526
2527   if (vam->graph_node_index_by_name == 0)
2528     {
2529       print (vam->ofp, "Node table empty, issue get_node_graph...");
2530       return 0;
2531     }
2532
2533   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2534     {
2535       if (unformat (line_input, "%s", &node_to_find))
2536         {
2537           vec_add1 (node_to_find, 0);
2538           p = hash_get_mem (vam->graph_node_index_by_name, node_to_find);
2539           if (p == 0)
2540             {
2541               print (vam->ofp, "%s not found...", node_to_find);
2542               goto out;
2543             }
2544           node = vam->graph_nodes[0][p[0]];
2545           print (vam->ofp, "[%d] %s", p[0], node->name);
2546           for (j = 0; j < vec_len (node->next_nodes); j++)
2547             {
2548               if (node->next_nodes[j] != ~0)
2549                 {
2550                   next_node = vam->graph_nodes[0][node->next_nodes[j]];
2551                   print (vam->ofp, "  [%d] %s", j, next_node->name);
2552                 }
2553             }
2554         }
2555
2556       else
2557         {
2558           clib_warning ("parse error '%U'", format_unformat_error,
2559                         line_input);
2560           return -99;
2561         }
2562
2563     out:
2564       vec_free (node_to_find);
2565
2566     }
2567
2568   return 0;
2569 }
2570
2571
2572 static int
2573 script (vat_main_t * vam)
2574 {
2575 #if (VPP_API_TEST_BUILTIN==0)
2576   u8 *s = 0;
2577   char *save_current_file;
2578   unformat_input_t save_input;
2579   jmp_buf save_jump_buf;
2580   u32 save_line_number;
2581
2582   FILE *new_fp, *save_ifp;
2583
2584   if (unformat (vam->input, "%s", &s))
2585     {
2586       new_fp = fopen ((char *) s, "r");
2587       if (new_fp == 0)
2588         {
2589           errmsg ("Couldn't open script file %s", s);
2590           vec_free (s);
2591           return -99;
2592         }
2593     }
2594   else
2595     {
2596       errmsg ("Missing script name");
2597       return -99;
2598     }
2599
2600   clib_memcpy (&save_input, &vam->input, sizeof (save_input));
2601   clib_memcpy (&save_jump_buf, &vam->jump_buf, sizeof (save_jump_buf));
2602   save_ifp = vam->ifp;
2603   save_line_number = vam->input_line_number;
2604   save_current_file = (char *) vam->current_file;
2605
2606   vam->input_line_number = 0;
2607   vam->ifp = new_fp;
2608   vam->current_file = s;
2609   do_one_file (vam);
2610
2611   clib_memcpy (&vam->input, &save_input, sizeof (save_input));
2612   clib_memcpy (&vam->jump_buf, &save_jump_buf, sizeof (save_jump_buf));
2613   vam->ifp = save_ifp;
2614   vam->input_line_number = save_line_number;
2615   vam->current_file = (u8 *) save_current_file;
2616   vec_free (s);
2617
2618   return 0;
2619 #else
2620   clib_warning ("use the exec command...");
2621   return -99;
2622 #endif
2623 }
2624
2625 static int
2626 echo (vat_main_t * vam)
2627 {
2628   print (vam->ofp, "%v", vam->input->buffer);
2629   return 0;
2630 }
2631
2632 int exec (vat_main_t *vam) __attribute__ ((weak));
2633 int
2634 exec (vat_main_t *vam)
2635 {
2636   return -1;
2637 }
2638
2639 /* List of API message constructors, CLI names map to api_xxx */
2640 #define foreach_vpe_api_msg                                             \
2641 _(show_version, "")                                                     \
2642 _(get_first_msg_id, "client <name>")                                    \
2643 _(sock_init_shm, "size <nnn>")                                          \
2644 /* List of command functions, CLI names map directly to functions */
2645 #define foreach_cli_function                                    \
2646 _(comment, "usage: comment <ignore-rest-of-line>")              \
2647 _(dump_macro_table, "usage: dump_macro_table ")                 \
2648 _(dump_msg_api_table, "usage: dump_msg_api_table")              \
2649 _(elog_setup, "usage: elog_setup [nevents, default 128K]")      \
2650 _(elog_disable, "usage: elog_disable")                          \
2651 _(elog_enable, "usage: elog_enable")                            \
2652 _(elog_save, "usage: elog_save <filename>")                     \
2653 _(get_msg_id, "usage: get_msg_id name_and_crc")                 \
2654 _(echo, "usage: echo <message>")                                \
2655 _(help, "usage: help")                                          \
2656 _(q, "usage: quit")                                             \
2657 _(quit, "usage: quit")                                          \
2658 _(search_node_table, "usage: search_node_table <name>...")      \
2659 _(set, "usage: set <variable-name> <value>")                    \
2660 _(script, "usage: script <file-name>")                          \
2661 _(statseg, "usage: statseg")                                    \
2662 _(unset, "usage: unset <variable-name>")
2663
2664 #define _(N,n)                                  \
2665     static void vl_api_##n##_t_handler_uni      \
2666     (vl_api_##n##_t * mp)                       \
2667     {                                           \
2668         vat_main_t * vam = &vat_main;           \
2669         if (vam->json_output) {                 \
2670             vl_api_##n##_t_handler_json(mp);    \
2671         } else {                                \
2672             vl_api_##n##_t_handler(mp);         \
2673         }                                       \
2674     }
2675 foreach_vpe_api_reply_msg;
2676 #if VPP_API_TEST_BUILTIN == 0
2677 foreach_standalone_reply_msg;
2678 #endif
2679 #undef _
2680
2681 void
2682 vat_api_hookup (vat_main_t * vam)
2683 {
2684 #define _(N,n)                                                  \
2685     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
2686                            vl_api_##n##_t_handler_uni,          \
2687                            vl_noop_handler,                     \
2688                            vl_api_##n##_t_endian,               \
2689                            vl_api_##n##_t_print,                \
2690                            sizeof(vl_api_##n##_t), 1);
2691   foreach_vpe_api_reply_msg;
2692 #if VPP_API_TEST_BUILTIN == 0
2693   foreach_standalone_reply_msg;
2694 #endif
2695 #undef _
2696
2697 #if (VPP_API_TEST_BUILTIN==0)
2698   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
2699
2700   vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
2701
2702   vam->function_by_name = hash_create_string (0, sizeof (uword));
2703
2704   vam->help_by_name = hash_create_string (0, sizeof (uword));
2705 #endif
2706
2707   /* API messages we can send */
2708 #define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
2709   foreach_vpe_api_msg;
2710 #undef _
2711
2712   /* Help strings */
2713 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
2714   foreach_vpe_api_msg;
2715 #undef _
2716
2717   /* CLI functions */
2718 #define _(n,h) hash_set_mem (vam->function_by_name, #n, n);
2719   foreach_cli_function;
2720 #undef _
2721
2722   /* Help strings */
2723 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
2724   foreach_cli_function;
2725 #undef _
2726 }
2727
2728 #if VPP_API_TEST_BUILTIN
2729 static clib_error_t *
2730 vat_api_hookup_shim (vlib_main_t * vm)
2731 {
2732   vat_api_hookup (&vat_main);
2733   return 0;
2734 }
2735
2736 VLIB_API_INIT_FUNCTION (vat_api_hookup_shim);
2737 #endif
2738
2739 /*
2740  * fd.io coding-style-patch-verification: ON
2741  *
2742  * Local Variables:
2743  * eval: (c-set-style "gnu")
2744  * End:
2745  */