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