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