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