interface: 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 _ (session_rule_add_del_reply)
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   _ (APP_NAMESPACE_ADD_DEL_REPLY, app_namespace_add_del_reply)                \
1133   _ (SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply)                  \
1134   _ (SESSION_RULES_DETAILS, session_rules_details)
1135
1136 #define foreach_standalone_reply_msg                                    \
1137
1138 typedef struct
1139 {
1140   u8 *name;
1141   u32 value;
1142 } name_sort_t;
1143
1144 #define STR_VTR_OP_CASE(op)     \
1145     case L2_VTR_ ## op:         \
1146         return "" # op;
1147
1148 /*
1149  * Pass CLI buffers directly in the CLI_INBAND API message,
1150  * instead of an additional shared memory area.
1151  */
1152 static int
1153 exec_inband (vat_main_t * vam)
1154 {
1155   vl_api_cli_inband_t *mp;
1156   unformat_input_t *i = vam->input;
1157   int ret;
1158
1159   if (vec_len (i->buffer) == 0)
1160     return -1;
1161
1162   if (vam->exec_mode == 0 && unformat (i, "mode"))
1163     {
1164       vam->exec_mode = 1;
1165       return 0;
1166     }
1167   if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit")))
1168     {
1169       vam->exec_mode = 0;
1170       return 0;
1171     }
1172
1173   /*
1174    * In order for the CLI command to work, it
1175    * must be a vector ending in \n, not a C-string ending
1176    * in \n\0.
1177    */
1178   M2 (CLI_INBAND, mp, vec_len (vam->input->buffer));
1179   vl_api_vec_to_api_string (vam->input->buffer, &mp->cmd);
1180
1181   S (mp);
1182   W (ret);
1183   /* json responses may or may not include a useful reply... */
1184   if (vec_len (vam->cmd_reply))
1185     print (vam->ofp, "%v", (char *) (vam->cmd_reply));
1186   return ret;
1187 }
1188
1189 int
1190 exec (vat_main_t *vam)
1191 {
1192   return exec_inband (vam);
1193 }
1194
1195 int
1196 api_sw_interface_dump (vat_main_t *vam)
1197 {
1198   return 0;
1199 }
1200
1201 uword
1202 unformat_vlib_pci_addr (unformat_input_t *input, va_list *args)
1203 {
1204   vlib_pci_addr_t *addr = va_arg (*args, vlib_pci_addr_t *);
1205   u32 x[4];
1206
1207   if (!unformat (input, "%x:%x:%x.%x", &x[0], &x[1], &x[2], &x[3]))
1208     return 0;
1209
1210   addr->domain = x[0];
1211   addr->bus = x[1];
1212   addr->slot = x[2];
1213   addr->function = x[3];
1214
1215   return 1;
1216 }
1217
1218 uword
1219 unformat_fib_path (unformat_input_t *input, va_list *args)
1220 {
1221   vat_main_t *vam = va_arg (*args, vat_main_t *);
1222   vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t *);
1223   u32 weight, preference;
1224   mpls_label_t out_label;
1225
1226   clib_memset (path, 0, sizeof (*path));
1227   path->weight = 1;
1228   path->sw_if_index = ~0;
1229   path->rpf_id = ~0;
1230   path->n_labels = 0;
1231
1232   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1233     {
1234       if (unformat (input, "%U %U", unformat_vl_api_ip4_address,
1235                     &path->nh.address.ip4, api_unformat_sw_if_index, vam,
1236                     &path->sw_if_index))
1237         {
1238           path->proto = FIB_API_PATH_NH_PROTO_IP4;
1239         }
1240       else if (unformat (input, "%U %U",
1241                          unformat_vl_api_ip6_address,
1242                          &path->nh.address.ip6,
1243                          api_unformat_sw_if_index, vam, &path->sw_if_index))
1244         {
1245           path->proto = FIB_API_PATH_NH_PROTO_IP6;
1246         }
1247       else if (unformat (input, "weight %u", &weight))
1248         {
1249           path->weight = weight;
1250         }
1251       else if (unformat (input, "preference %u", &preference))
1252         {
1253           path->preference = preference;
1254         }
1255       else if (unformat (input, "%U next-hop-table %d",
1256                          unformat_vl_api_ip4_address,
1257                          &path->nh.address.ip4, &path->table_id))
1258         {
1259           path->proto = FIB_API_PATH_NH_PROTO_IP4;
1260         }
1261       else if (unformat (input, "%U next-hop-table %d",
1262                          unformat_vl_api_ip6_address,
1263                          &path->nh.address.ip6, &path->table_id))
1264         {
1265           path->proto = FIB_API_PATH_NH_PROTO_IP6;
1266         }
1267       else if (unformat (input, "%U",
1268                          unformat_vl_api_ip4_address, &path->nh.address.ip4))
1269         {
1270           /*
1271            * the recursive next-hops are by default in the default table
1272            */
1273           path->table_id = 0;
1274           path->sw_if_index = ~0;
1275           path->proto = FIB_API_PATH_NH_PROTO_IP4;
1276         }
1277       else if (unformat (input, "%U",
1278                          unformat_vl_api_ip6_address, &path->nh.address.ip6))
1279         {
1280           /*
1281            * the recursive next-hops are by default in the default table
1282            */
1283           path->table_id = 0;
1284           path->sw_if_index = ~0;
1285           path->proto = FIB_API_PATH_NH_PROTO_IP6;
1286         }
1287       else if (unformat (input, "resolve-via-host"))
1288         {
1289           path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_HOST;
1290         }
1291       else if (unformat (input, "resolve-via-attached"))
1292         {
1293           path->flags |= FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED;
1294         }
1295       else if (unformat (input, "ip4-lookup-in-table %d", &path->table_id))
1296         {
1297           path->type = FIB_API_PATH_TYPE_LOCAL;
1298           path->sw_if_index = ~0;
1299           path->proto = FIB_API_PATH_NH_PROTO_IP4;
1300         }
1301       else if (unformat (input, "ip6-lookup-in-table %d", &path->table_id))
1302         {
1303           path->type = FIB_API_PATH_TYPE_LOCAL;
1304           path->sw_if_index = ~0;
1305           path->proto = FIB_API_PATH_NH_PROTO_IP6;
1306         }
1307       else if (unformat (input, "sw_if_index %d", &path->sw_if_index))
1308         ;
1309       else if (unformat (input, "via-label %d", &path->nh.via_label))
1310         {
1311           path->proto = FIB_API_PATH_NH_PROTO_MPLS;
1312           path->sw_if_index = ~0;
1313         }
1314       else if (unformat (input, "l2-input-on %d", &path->sw_if_index))
1315         {
1316           path->proto = FIB_API_PATH_NH_PROTO_ETHERNET;
1317           path->type = FIB_API_PATH_TYPE_INTERFACE_RX;
1318         }
1319       else if (unformat (input, "local"))
1320         {
1321           path->type = FIB_API_PATH_TYPE_LOCAL;
1322         }
1323       else if (unformat (input, "out-labels"))
1324         {
1325           while (unformat (input, "%d", &out_label))
1326             {
1327               path->label_stack[path->n_labels].label = out_label;
1328               path->label_stack[path->n_labels].is_uniform = 0;
1329               path->label_stack[path->n_labels].ttl = 64;
1330               path->n_labels++;
1331             }
1332         }
1333       else if (unformat (input, "via"))
1334         {
1335           /* new path, back up and return */
1336           unformat_put_input (input);
1337           unformat_put_input (input);
1338           unformat_put_input (input);
1339           unformat_put_input (input);
1340           break;
1341         }
1342       else
1343         {
1344           return (0);
1345         }
1346     }
1347
1348   path->proto = ntohl (path->proto);
1349   path->type = ntohl (path->type);
1350   path->flags = ntohl (path->flags);
1351   path->table_id = ntohl (path->table_id);
1352   path->sw_if_index = ntohl (path->sw_if_index);
1353
1354   return (1);
1355 }
1356
1357 #define foreach_create_subif_bit                \
1358 _(no_tags)                                      \
1359 _(one_tag)                                      \
1360 _(two_tags)                                     \
1361 _(dot1ad)                                       \
1362 _(exact_match)                                  \
1363 _(default_sub)                                  \
1364 _(outer_vlan_id_any)                            \
1365 _(inner_vlan_id_any)
1366
1367 #define foreach_create_subif_flag               \
1368 _(0, "no_tags")                                 \
1369 _(1, "one_tag")                                 \
1370 _(2, "two_tags")                                \
1371 _(3, "dot1ad")                                  \
1372 _(4, "exact_match")                             \
1373 _(5, "default_sub")                             \
1374 _(6, "outer_vlan_id_any")                       \
1375 _(7, "inner_vlan_id_any")
1376
1377
1378 #define foreach_tcp_proto_field                                               \
1379   _ (src_port)                                                                \
1380   _ (dst_port)
1381
1382 #define foreach_udp_proto_field                                               \
1383   _ (src_port)                                                                \
1384   _ (dst_port)
1385
1386 #define foreach_ip4_proto_field                                               \
1387   _ (src_address)                                                             \
1388   _ (dst_address)                                                             \
1389   _ (tos)                                                                     \
1390   _ (length)                                                                  \
1391   _ (fragment_id)                                                             \
1392   _ (ttl)                                                                     \
1393   _ (protocol)                                                                \
1394   _ (checksum)
1395
1396 typedef struct
1397 {
1398   u16 src_port, dst_port;
1399 } tcpudp_header_t;
1400
1401 #if VPP_API_TEST_BUILTIN == 0
1402 uword
1403 unformat_tcp_mask (unformat_input_t *input, va_list *args)
1404 {
1405   u8 **maskp = va_arg (*args, u8 **);
1406   u8 *mask = 0;
1407   u8 found_something = 0;
1408   tcp_header_t *tcp;
1409
1410 #define _(a) u8 a = 0;
1411   foreach_tcp_proto_field;
1412 #undef _
1413
1414   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1415     {
1416       if (0)
1417         ;
1418 #define _(a) else if (unformat (input, #a)) a = 1;
1419       foreach_tcp_proto_field
1420 #undef _
1421         else break;
1422     }
1423
1424 #define _(a) found_something += a;
1425   foreach_tcp_proto_field;
1426 #undef _
1427
1428   if (found_something == 0)
1429     return 0;
1430
1431   vec_validate (mask, sizeof (*tcp) - 1);
1432
1433   tcp = (tcp_header_t *) mask;
1434
1435 #define _(a)                                                                  \
1436   if (a)                                                                      \
1437     clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
1438   foreach_tcp_proto_field;
1439 #undef _
1440
1441   *maskp = mask;
1442   return 1;
1443 }
1444
1445 uword
1446 unformat_udp_mask (unformat_input_t *input, va_list *args)
1447 {
1448   u8 **maskp = va_arg (*args, u8 **);
1449   u8 *mask = 0;
1450   u8 found_something = 0;
1451   udp_header_t *udp;
1452
1453 #define _(a) u8 a = 0;
1454   foreach_udp_proto_field;
1455 #undef _
1456
1457   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1458     {
1459       if (0)
1460         ;
1461 #define _(a) else if (unformat (input, #a)) a = 1;
1462       foreach_udp_proto_field
1463 #undef _
1464         else break;
1465     }
1466
1467 #define _(a) found_something += a;
1468   foreach_udp_proto_field;
1469 #undef _
1470
1471   if (found_something == 0)
1472     return 0;
1473
1474   vec_validate (mask, sizeof (*udp) - 1);
1475
1476   udp = (udp_header_t *) mask;
1477
1478 #define _(a)                                                                  \
1479   if (a)                                                                      \
1480     clib_memset (&udp->a, 0xff, sizeof (udp->a));
1481   foreach_udp_proto_field;
1482 #undef _
1483
1484   *maskp = mask;
1485   return 1;
1486 }
1487
1488 uword
1489 unformat_l4_mask (unformat_input_t *input, va_list *args)
1490 {
1491   u8 **maskp = va_arg (*args, u8 **);
1492   u16 src_port = 0, dst_port = 0;
1493   tcpudp_header_t *tcpudp;
1494
1495   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1496     {
1497       if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
1498         return 1;
1499       else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
1500         return 1;
1501       else if (unformat (input, "src_port"))
1502         src_port = 0xFFFF;
1503       else if (unformat (input, "dst_port"))
1504         dst_port = 0xFFFF;
1505       else
1506         return 0;
1507     }
1508
1509   if (!src_port && !dst_port)
1510     return 0;
1511
1512   u8 *mask = 0;
1513   vec_validate (mask, sizeof (tcpudp_header_t) - 1);
1514
1515   tcpudp = (tcpudp_header_t *) mask;
1516   tcpudp->src_port = src_port;
1517   tcpudp->dst_port = dst_port;
1518
1519   *maskp = mask;
1520
1521   return 1;
1522 }
1523
1524 uword
1525 unformat_ip4_mask (unformat_input_t * input, va_list * args)
1526 {
1527   u8 **maskp = va_arg (*args, u8 **);
1528   u8 *mask = 0;
1529   u8 found_something = 0;
1530   ip4_header_t *ip;
1531
1532 #define _(a) u8 a=0;
1533   foreach_ip4_proto_field;
1534 #undef _
1535   u8 version = 0;
1536   u8 hdr_length = 0;
1537
1538
1539   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1540     {
1541       if (unformat (input, "version"))
1542         version = 1;
1543       else if (unformat (input, "hdr_length"))
1544         hdr_length = 1;
1545       else if (unformat (input, "src"))
1546         src_address = 1;
1547       else if (unformat (input, "dst"))
1548         dst_address = 1;
1549       else if (unformat (input, "proto"))
1550         protocol = 1;
1551
1552 #define _(a) else if (unformat (input, #a)) a=1;
1553       foreach_ip4_proto_field
1554 #undef _
1555         else
1556         break;
1557     }
1558
1559 #define _(a) found_something += a;
1560   foreach_ip4_proto_field;
1561 #undef _
1562
1563   if (found_something == 0)
1564     return 0;
1565
1566   vec_validate (mask, sizeof (*ip) - 1);
1567
1568   ip = (ip4_header_t *) mask;
1569
1570 #define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
1571   foreach_ip4_proto_field;
1572 #undef _
1573
1574   ip->ip_version_and_header_length = 0;
1575
1576   if (version)
1577     ip->ip_version_and_header_length |= 0xF0;
1578
1579   if (hdr_length)
1580     ip->ip_version_and_header_length |= 0x0F;
1581
1582   *maskp = mask;
1583   return 1;
1584 }
1585
1586 #define foreach_ip6_proto_field                 \
1587 _(src_address)                                  \
1588 _(dst_address)                                  \
1589 _(payload_length)                               \
1590 _(hop_limit)                                    \
1591 _(protocol)
1592
1593 uword
1594 unformat_ip6_mask (unformat_input_t * input, va_list * args)
1595 {
1596   u8 **maskp = va_arg (*args, u8 **);
1597   u8 *mask = 0;
1598   u8 found_something = 0;
1599   ip6_header_t *ip;
1600   u32 ip_version_traffic_class_and_flow_label;
1601
1602 #define _(a) u8 a=0;
1603   foreach_ip6_proto_field;
1604 #undef _
1605   u8 version = 0;
1606   u8 traffic_class = 0;
1607   u8 flow_label = 0;
1608
1609   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1610     {
1611       if (unformat (input, "version"))
1612         version = 1;
1613       else if (unformat (input, "traffic-class"))
1614         traffic_class = 1;
1615       else if (unformat (input, "flow-label"))
1616         flow_label = 1;
1617       else if (unformat (input, "src"))
1618         src_address = 1;
1619       else if (unformat (input, "dst"))
1620         dst_address = 1;
1621       else if (unformat (input, "proto"))
1622         protocol = 1;
1623
1624 #define _(a) else if (unformat (input, #a)) a=1;
1625       foreach_ip6_proto_field
1626 #undef _
1627         else
1628         break;
1629     }
1630
1631 #define _(a) found_something += a;
1632   foreach_ip6_proto_field;
1633 #undef _
1634
1635   if (found_something == 0)
1636     return 0;
1637
1638   vec_validate (mask, sizeof (*ip) - 1);
1639
1640   ip = (ip6_header_t *) mask;
1641
1642 #define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
1643   foreach_ip6_proto_field;
1644 #undef _
1645
1646   ip_version_traffic_class_and_flow_label = 0;
1647
1648   if (version)
1649     ip_version_traffic_class_and_flow_label |= 0xF0000000;
1650
1651   if (traffic_class)
1652     ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1653
1654   if (flow_label)
1655     ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1656
1657   ip->ip_version_traffic_class_and_flow_label =
1658     clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1659
1660   *maskp = mask;
1661   return 1;
1662 }
1663
1664 uword
1665 unformat_l3_mask (unformat_input_t * input, va_list * args)
1666 {
1667   u8 **maskp = va_arg (*args, u8 **);
1668
1669   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1670     {
1671       if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1672         return 1;
1673       else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1674         return 1;
1675       else
1676         break;
1677     }
1678   return 0;
1679 }
1680
1681 uword
1682 unformat_l2_mask (unformat_input_t * input, va_list * args)
1683 {
1684   u8 **maskp = va_arg (*args, u8 **);
1685   u8 *mask = 0;
1686   u8 src = 0;
1687   u8 dst = 0;
1688   u8 proto = 0;
1689   u8 tag1 = 0;
1690   u8 tag2 = 0;
1691   u8 ignore_tag1 = 0;
1692   u8 ignore_tag2 = 0;
1693   u8 cos1 = 0;
1694   u8 cos2 = 0;
1695   u8 dot1q = 0;
1696   u8 dot1ad = 0;
1697   int len = 14;
1698
1699   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1700     {
1701       if (unformat (input, "src"))
1702         src = 1;
1703       else if (unformat (input, "dst"))
1704         dst = 1;
1705       else if (unformat (input, "proto"))
1706         proto = 1;
1707       else if (unformat (input, "tag1"))
1708         tag1 = 1;
1709       else if (unformat (input, "tag2"))
1710         tag2 = 1;
1711       else if (unformat (input, "ignore-tag1"))
1712         ignore_tag1 = 1;
1713       else if (unformat (input, "ignore-tag2"))
1714         ignore_tag2 = 1;
1715       else if (unformat (input, "cos1"))
1716         cos1 = 1;
1717       else if (unformat (input, "cos2"))
1718         cos2 = 1;
1719       else if (unformat (input, "dot1q"))
1720         dot1q = 1;
1721       else if (unformat (input, "dot1ad"))
1722         dot1ad = 1;
1723       else
1724         break;
1725     }
1726   if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
1727        ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1728     return 0;
1729
1730   if (tag1 || ignore_tag1 || cos1 || dot1q)
1731     len = 18;
1732   if (tag2 || ignore_tag2 || cos2 || dot1ad)
1733     len = 22;
1734
1735   vec_validate (mask, len - 1);
1736
1737   if (dst)
1738     clib_memset (mask, 0xff, 6);
1739
1740   if (src)
1741     clib_memset (mask + 6, 0xff, 6);
1742
1743   if (tag2 || dot1ad)
1744     {
1745       /* inner vlan tag */
1746       if (tag2)
1747         {
1748           mask[19] = 0xff;
1749           mask[18] = 0x0f;
1750         }
1751       if (cos2)
1752         mask[18] |= 0xe0;
1753       if (proto)
1754         mask[21] = mask[20] = 0xff;
1755       if (tag1)
1756         {
1757           mask[15] = 0xff;
1758           mask[14] = 0x0f;
1759         }
1760       if (cos1)
1761         mask[14] |= 0xe0;
1762       *maskp = mask;
1763       return 1;
1764     }
1765   if (tag1 | dot1q)
1766     {
1767       if (tag1)
1768         {
1769           mask[15] = 0xff;
1770           mask[14] = 0x0f;
1771         }
1772       if (cos1)
1773         mask[14] |= 0xe0;
1774       if (proto)
1775         mask[16] = mask[17] = 0xff;
1776
1777       *maskp = mask;
1778       return 1;
1779     }
1780   if (cos2)
1781     mask[18] |= 0xe0;
1782   if (cos1)
1783     mask[14] |= 0xe0;
1784   if (proto)
1785     mask[12] = mask[13] = 0xff;
1786
1787   *maskp = mask;
1788   return 1;
1789 }
1790
1791 uword
1792 unformat_classify_mask (unformat_input_t * input, va_list * args)
1793 {
1794   u8 **maskp = va_arg (*args, u8 **);
1795   u32 *skipp = va_arg (*args, u32 *);
1796   u32 *matchp = va_arg (*args, u32 *);
1797   u32 match;
1798   u8 *mask = 0;
1799   u8 *l2 = 0;
1800   u8 *l3 = 0;
1801   u8 *l4 = 0;
1802   int i;
1803
1804   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1805     {
1806       if (unformat (input, "hex %U", unformat_hex_string, &mask))
1807         ;
1808       else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1809         ;
1810       else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1811         ;
1812       else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1813         ;
1814       else
1815         break;
1816     }
1817
1818   if (l4 && !l3)
1819     {
1820       vec_free (mask);
1821       vec_free (l2);
1822       vec_free (l4);
1823       return 0;
1824     }
1825
1826   if (mask || l2 || l3 || l4)
1827     {
1828       if (l2 || l3 || l4)
1829         {
1830           /* "With a free Ethernet header in every package" */
1831           if (l2 == 0)
1832             vec_validate (l2, 13);
1833           mask = l2;
1834           if (vec_len (l3))
1835             {
1836               vec_append (mask, l3);
1837               vec_free (l3);
1838             }
1839           if (vec_len (l4))
1840             {
1841               vec_append (mask, l4);
1842               vec_free (l4);
1843             }
1844         }
1845
1846       /* Scan forward looking for the first significant mask octet */
1847       for (i = 0; i < vec_len (mask); i++)
1848         if (mask[i])
1849           break;
1850
1851       /* compute (skip, match) params */
1852       *skipp = i / sizeof (u32x4);
1853       vec_delete (mask, *skipp * sizeof (u32x4), 0);
1854
1855       /* Pad mask to an even multiple of the vector size */
1856       while (vec_len (mask) % sizeof (u32x4))
1857         vec_add1 (mask, 0);
1858
1859       match = vec_len (mask) / sizeof (u32x4);
1860
1861       for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1862         {
1863           u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1864           if (*tmp || *(tmp + 1))
1865             break;
1866           match--;
1867         }
1868       if (match == 0)
1869         clib_warning ("BUG: match 0");
1870
1871       _vec_len (mask) = match * sizeof (u32x4);
1872
1873       *matchp = match;
1874       *maskp = mask;
1875
1876       return 1;
1877     }
1878
1879   return 0;
1880 }
1881 #endif /* VPP_API_TEST_BUILTIN */
1882
1883 #define foreach_l2_next                         \
1884 _(drop, DROP)                                   \
1885 _(ethernet, ETHERNET_INPUT)                     \
1886 _(ip4, IP4_INPUT)                               \
1887 _(ip6, IP6_INPUT)
1888
1889 uword
1890 unformat_l2_next_index (unformat_input_t * input, va_list * args)
1891 {
1892   u32 *miss_next_indexp = va_arg (*args, u32 *);
1893   u32 next_index = 0;
1894   u32 tmp;
1895
1896 #define _(n,N) \
1897   if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1898   foreach_l2_next;
1899 #undef _
1900
1901   if (unformat (input, "%d", &tmp))
1902     {
1903       next_index = tmp;
1904       goto out;
1905     }
1906
1907   return 0;
1908
1909 out:
1910   *miss_next_indexp = next_index;
1911   return 1;
1912 }
1913
1914 #define foreach_ip_next                         \
1915 _(drop, DROP)                                   \
1916 _(local, LOCAL)                                 \
1917 _(rewrite, REWRITE)
1918
1919 uword
1920 api_unformat_ip_next_index (unformat_input_t * input, va_list * args)
1921 {
1922   u32 *miss_next_indexp = va_arg (*args, u32 *);
1923   u32 next_index = 0;
1924   u32 tmp;
1925
1926 #define _(n,N) \
1927   if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1928   foreach_ip_next;
1929 #undef _
1930
1931   if (unformat (input, "%d", &tmp))
1932     {
1933       next_index = tmp;
1934       goto out;
1935     }
1936
1937   return 0;
1938
1939 out:
1940   *miss_next_indexp = next_index;
1941   return 1;
1942 }
1943
1944 #define foreach_acl_next                        \
1945 _(deny, DENY)
1946
1947 uword
1948 api_unformat_acl_next_index (unformat_input_t * input, va_list * args)
1949 {
1950   u32 *miss_next_indexp = va_arg (*args, u32 *);
1951   u32 next_index = 0;
1952   u32 tmp;
1953
1954 #define _(n,N) \
1955   if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1956   foreach_acl_next;
1957 #undef _
1958
1959   if (unformat (input, "permit"))
1960     {
1961       next_index = ~0;
1962       goto out;
1963     }
1964   else if (unformat (input, "%d", &tmp))
1965     {
1966       next_index = tmp;
1967       goto out;
1968     }
1969
1970   return 0;
1971
1972 out:
1973   *miss_next_indexp = next_index;
1974   return 1;
1975 }
1976
1977 uword
1978 unformat_policer_precolor (unformat_input_t * input, va_list * args)
1979 {
1980   u32 *r = va_arg (*args, u32 *);
1981
1982   if (unformat (input, "conform-color"))
1983     *r = POLICE_CONFORM;
1984   else if (unformat (input, "exceed-color"))
1985     *r = POLICE_EXCEED;
1986   else
1987     return 0;
1988
1989   return 1;
1990 }
1991
1992 #if VPP_API_TEST_BUILTIN == 0
1993 uword
1994 unformat_l4_match (unformat_input_t * input, va_list * args)
1995 {
1996   u8 **matchp = va_arg (*args, u8 **);
1997
1998   u8 *proto_header = 0;
1999   int src_port = 0;
2000   int dst_port = 0;
2001
2002   tcpudp_header_t h;
2003
2004   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2005     {
2006       if (unformat (input, "src_port %d", &src_port))
2007         ;
2008       else if (unformat (input, "dst_port %d", &dst_port))
2009         ;
2010       else
2011         return 0;
2012     }
2013
2014   h.src_port = clib_host_to_net_u16 (src_port);
2015   h.dst_port = clib_host_to_net_u16 (dst_port);
2016   vec_validate (proto_header, sizeof (h) - 1);
2017   memcpy (proto_header, &h, sizeof (h));
2018
2019   *matchp = proto_header;
2020
2021   return 1;
2022 }
2023
2024 uword
2025 unformat_ip4_match (unformat_input_t * input, va_list * args)
2026 {
2027   u8 **matchp = va_arg (*args, u8 **);
2028   u8 *match = 0;
2029   ip4_header_t *ip;
2030   int version = 0;
2031   u32 version_val;
2032   int hdr_length = 0;
2033   u32 hdr_length_val;
2034   int src = 0, dst = 0;
2035   ip4_address_t src_val, dst_val;
2036   int proto = 0;
2037   u32 proto_val;
2038   int tos = 0;
2039   u32 tos_val;
2040   int length = 0;
2041   u32 length_val;
2042   int fragment_id = 0;
2043   u32 fragment_id_val;
2044   int ttl = 0;
2045   int ttl_val;
2046   int checksum = 0;
2047   u32 checksum_val;
2048
2049   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2050     {
2051       if (unformat (input, "version %d", &version_val))
2052         version = 1;
2053       else if (unformat (input, "hdr_length %d", &hdr_length_val))
2054         hdr_length = 1;
2055       else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
2056         src = 1;
2057       else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
2058         dst = 1;
2059       else if (unformat (input, "proto %d", &proto_val))
2060         proto = 1;
2061       else if (unformat (input, "tos %d", &tos_val))
2062         tos = 1;
2063       else if (unformat (input, "length %d", &length_val))
2064         length = 1;
2065       else if (unformat (input, "fragment_id %d", &fragment_id_val))
2066         fragment_id = 1;
2067       else if (unformat (input, "ttl %d", &ttl_val))
2068         ttl = 1;
2069       else if (unformat (input, "checksum %d", &checksum_val))
2070         checksum = 1;
2071       else
2072         break;
2073     }
2074
2075   if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2076       + ttl + checksum == 0)
2077     return 0;
2078
2079   /*
2080    * Aligned because we use the real comparison functions
2081    */
2082   vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2083
2084   ip = (ip4_header_t *) match;
2085
2086   /* These are realistically matched in practice */
2087   if (src)
2088     ip->src_address.as_u32 = src_val.as_u32;
2089
2090   if (dst)
2091     ip->dst_address.as_u32 = dst_val.as_u32;
2092
2093   if (proto)
2094     ip->protocol = proto_val;
2095
2096
2097   /* These are not, but they're included for completeness */
2098   if (version)
2099     ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
2100
2101   if (hdr_length)
2102     ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
2103
2104   if (tos)
2105     ip->tos = tos_val;
2106
2107   if (length)
2108     ip->length = clib_host_to_net_u16 (length_val);
2109
2110   if (ttl)
2111     ip->ttl = ttl_val;
2112
2113   if (checksum)
2114     ip->checksum = clib_host_to_net_u16 (checksum_val);
2115
2116   *matchp = match;
2117   return 1;
2118 }
2119
2120 uword
2121 unformat_ip6_match (unformat_input_t * input, va_list * args)
2122 {
2123   u8 **matchp = va_arg (*args, u8 **);
2124   u8 *match = 0;
2125   ip6_header_t *ip;
2126   int version = 0;
2127   u32 version_val;
2128   u8 traffic_class = 0;
2129   u32 traffic_class_val = 0;
2130   u8 flow_label = 0;
2131   u8 flow_label_val;
2132   int src = 0, dst = 0;
2133   ip6_address_t src_val, dst_val;
2134   int proto = 0;
2135   u32 proto_val;
2136   int payload_length = 0;
2137   u32 payload_length_val;
2138   int hop_limit = 0;
2139   int hop_limit_val;
2140   u32 ip_version_traffic_class_and_flow_label;
2141
2142   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2143     {
2144       if (unformat (input, "version %d", &version_val))
2145         version = 1;
2146       else if (unformat (input, "traffic_class %d", &traffic_class_val))
2147         traffic_class = 1;
2148       else if (unformat (input, "flow_label %d", &flow_label_val))
2149         flow_label = 1;
2150       else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
2151         src = 1;
2152       else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
2153         dst = 1;
2154       else if (unformat (input, "proto %d", &proto_val))
2155         proto = 1;
2156       else if (unformat (input, "payload_length %d", &payload_length_val))
2157         payload_length = 1;
2158       else if (unformat (input, "hop_limit %d", &hop_limit_val))
2159         hop_limit = 1;
2160       else
2161         break;
2162     }
2163
2164   if (version + traffic_class + flow_label + src + dst + proto +
2165       payload_length + hop_limit == 0)
2166     return 0;
2167
2168   /*
2169    * Aligned because we use the real comparison functions
2170    */
2171   vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2172
2173   ip = (ip6_header_t *) match;
2174
2175   if (src)
2176     clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
2177
2178   if (dst)
2179     clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
2180
2181   if (proto)
2182     ip->protocol = proto_val;
2183
2184   ip_version_traffic_class_and_flow_label = 0;
2185
2186   if (version)
2187     ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2188
2189   if (traffic_class)
2190     ip_version_traffic_class_and_flow_label |=
2191       (traffic_class_val & 0xFF) << 20;
2192
2193   if (flow_label)
2194     ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
2195
2196   ip->ip_version_traffic_class_and_flow_label =
2197     clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2198
2199   if (payload_length)
2200     ip->payload_length = clib_host_to_net_u16 (payload_length_val);
2201
2202   if (hop_limit)
2203     ip->hop_limit = hop_limit_val;
2204
2205   *matchp = match;
2206   return 1;
2207 }
2208
2209 uword
2210 unformat_l3_match (unformat_input_t * input, va_list * args)
2211 {
2212   u8 **matchp = va_arg (*args, u8 **);
2213
2214   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2215     {
2216       if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2217         return 1;
2218       else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2219         return 1;
2220       else
2221         break;
2222     }
2223   return 0;
2224 }
2225
2226 uword
2227 unformat_vlan_tag (unformat_input_t * input, va_list * args)
2228 {
2229   u8 *tagp = va_arg (*args, u8 *);
2230   u32 tag;
2231
2232   if (unformat (input, "%d", &tag))
2233     {
2234       tagp[0] = (tag >> 8) & 0x0F;
2235       tagp[1] = tag & 0xFF;
2236       return 1;
2237     }
2238
2239   return 0;
2240 }
2241
2242 uword
2243 unformat_l2_match (unformat_input_t * input, va_list * args)
2244 {
2245   u8 **matchp = va_arg (*args, u8 **);
2246   u8 *match = 0;
2247   u8 src = 0;
2248   u8 src_val[6];
2249   u8 dst = 0;
2250   u8 dst_val[6];
2251   u8 proto = 0;
2252   u16 proto_val;
2253   u8 tag1 = 0;
2254   u8 tag1_val[2];
2255   u8 tag2 = 0;
2256   u8 tag2_val[2];
2257   int len = 14;
2258   u8 ignore_tag1 = 0;
2259   u8 ignore_tag2 = 0;
2260   u8 cos1 = 0;
2261   u8 cos2 = 0;
2262   u32 cos1_val = 0;
2263   u32 cos2_val = 0;
2264
2265   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2266     {
2267       if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2268         src = 1;
2269       else
2270         if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2271         dst = 1;
2272       else if (unformat (input, "proto %U",
2273                          unformat_ethernet_type_host_byte_order, &proto_val))
2274         proto = 1;
2275       else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2276         tag1 = 1;
2277       else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2278         tag2 = 1;
2279       else if (unformat (input, "ignore-tag1"))
2280         ignore_tag1 = 1;
2281       else if (unformat (input, "ignore-tag2"))
2282         ignore_tag2 = 1;
2283       else if (unformat (input, "cos1 %d", &cos1_val))
2284         cos1 = 1;
2285       else if (unformat (input, "cos2 %d", &cos2_val))
2286         cos2 = 1;
2287       else
2288         break;
2289     }
2290   if ((src + dst + proto + tag1 + tag2 +
2291        ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
2292     return 0;
2293
2294   if (tag1 || ignore_tag1 || cos1)
2295     len = 18;
2296   if (tag2 || ignore_tag2 || cos2)
2297     len = 22;
2298
2299   vec_validate_aligned (match, len - 1, sizeof (u32x4));
2300
2301   if (dst)
2302     clib_memcpy (match, dst_val, 6);
2303
2304   if (src)
2305     clib_memcpy (match + 6, src_val, 6);
2306
2307   if (tag2)
2308     {
2309       /* inner vlan tag */
2310       match[19] = tag2_val[1];
2311       match[18] = tag2_val[0];
2312       if (cos2)
2313         match[18] |= (cos2_val & 0x7) << 5;
2314       if (proto)
2315         {
2316           match[21] = proto_val & 0xff;
2317           match[20] = proto_val >> 8;
2318         }
2319       if (tag1)
2320         {
2321           match[15] = tag1_val[1];
2322           match[14] = tag1_val[0];
2323         }
2324       if (cos1)
2325         match[14] |= (cos1_val & 0x7) << 5;
2326       *matchp = match;
2327       return 1;
2328     }
2329   if (tag1)
2330     {
2331       match[15] = tag1_val[1];
2332       match[14] = tag1_val[0];
2333       if (proto)
2334         {
2335           match[17] = proto_val & 0xff;
2336           match[16] = proto_val >> 8;
2337         }
2338       if (cos1)
2339         match[14] |= (cos1_val & 0x7) << 5;
2340
2341       *matchp = match;
2342       return 1;
2343     }
2344   if (cos2)
2345     match[18] |= (cos2_val & 0x7) << 5;
2346   if (cos1)
2347     match[14] |= (cos1_val & 0x7) << 5;
2348   if (proto)
2349     {
2350       match[13] = proto_val & 0xff;
2351       match[12] = proto_val >> 8;
2352     }
2353
2354   *matchp = match;
2355   return 1;
2356 }
2357
2358 uword
2359 unformat_qos_source (unformat_input_t * input, va_list * args)
2360 {
2361   int *qs = va_arg (*args, int *);
2362
2363   if (unformat (input, "ip"))
2364     *qs = QOS_SOURCE_IP;
2365   else if (unformat (input, "mpls"))
2366     *qs = QOS_SOURCE_MPLS;
2367   else if (unformat (input, "ext"))
2368     *qs = QOS_SOURCE_EXT;
2369   else if (unformat (input, "vlan"))
2370     *qs = QOS_SOURCE_VLAN;
2371   else
2372     return 0;
2373
2374   return 1;
2375 }
2376 #endif
2377
2378 uword
2379 api_unformat_classify_match (unformat_input_t * input, va_list * args)
2380 {
2381   u8 **matchp = va_arg (*args, u8 **);
2382   u32 skip_n_vectors = va_arg (*args, u32);
2383   u32 match_n_vectors = va_arg (*args, u32);
2384
2385   u8 *match = 0;
2386   u8 *l2 = 0;
2387   u8 *l3 = 0;
2388   u8 *l4 = 0;
2389
2390   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2391     {
2392       if (unformat (input, "hex %U", unformat_hex_string, &match))
2393         ;
2394       else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2395         ;
2396       else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2397         ;
2398       else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2399         ;
2400       else
2401         break;
2402     }
2403
2404   if (l4 && !l3)
2405     {
2406       vec_free (match);
2407       vec_free (l2);
2408       vec_free (l4);
2409       return 0;
2410     }
2411
2412   if (match || l2 || l3 || l4)
2413     {
2414       if (l2 || l3 || l4)
2415         {
2416           /* "Win a free Ethernet header in every packet" */
2417           if (l2 == 0)
2418             vec_validate_aligned (l2, 13, sizeof (u32x4));
2419           match = l2;
2420           if (vec_len (l3))
2421             {
2422               vec_append_aligned (match, l3, sizeof (u32x4));
2423               vec_free (l3);
2424             }
2425           if (vec_len (l4))
2426             {
2427               vec_append_aligned (match, l4, sizeof (u32x4));
2428               vec_free (l4);
2429             }
2430         }
2431
2432       /* Make sure the vector is big enough even if key is all 0's */
2433       vec_validate_aligned
2434         (match, ((match_n_vectors + skip_n_vectors) * sizeof (u32x4)) - 1,
2435          sizeof (u32x4));
2436
2437       /* Set size, include skipped vectors */
2438       _vec_len (match) = (match_n_vectors + skip_n_vectors) * sizeof (u32x4);
2439
2440       *matchp = match;
2441
2442       return 1;
2443     }
2444
2445   return 0;
2446 }
2447
2448 static int
2449 api_get_node_index (vat_main_t *vam)
2450 {
2451   unformat_input_t *i = vam->input;
2452   vl_api_get_node_index_t *mp;
2453   u8 *name = 0;
2454   int ret;
2455
2456   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2457     {
2458       if (unformat (i, "node %s", &name))
2459         ;
2460       else
2461         break;
2462     }
2463   if (name == 0)
2464     {
2465       errmsg ("node name required");
2466       return -99;
2467     }
2468   if (vec_len (name) >= ARRAY_LEN (mp->node_name))
2469     {
2470       errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name));
2471       return -99;
2472     }
2473
2474   M (GET_NODE_INDEX, mp);
2475   clib_memcpy (mp->node_name, name, vec_len (name));
2476   vec_free (name);
2477
2478   S (mp);
2479   W (ret);
2480   return ret;
2481 }
2482
2483 static int
2484 api_get_next_index (vat_main_t *vam)
2485 {
2486   unformat_input_t *i = vam->input;
2487   vl_api_get_next_index_t *mp;
2488   u8 *node_name = 0, *next_node_name = 0;
2489   int ret;
2490
2491   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2492     {
2493       if (unformat (i, "node-name %s", &node_name))
2494         ;
2495       else if (unformat (i, "next-node-name %s", &next_node_name))
2496         break;
2497     }
2498
2499   if (node_name == 0)
2500     {
2501       errmsg ("node name required");
2502       return -99;
2503     }
2504   if (vec_len (node_name) >= ARRAY_LEN (mp->node_name))
2505     {
2506       errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name));
2507       return -99;
2508     }
2509
2510   if (next_node_name == 0)
2511     {
2512       errmsg ("next node name required");
2513       return -99;
2514     }
2515   if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name))
2516     {
2517       errmsg ("next node name too long, max %d", ARRAY_LEN (mp->next_name));
2518       return -99;
2519     }
2520
2521   M (GET_NEXT_INDEX, mp);
2522   clib_memcpy (mp->node_name, node_name, vec_len (node_name));
2523   clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name));
2524   vec_free (node_name);
2525   vec_free (next_node_name);
2526
2527   S (mp);
2528   W (ret);
2529   return ret;
2530 }
2531
2532 static int
2533 api_add_node_next (vat_main_t *vam)
2534 {
2535   unformat_input_t *i = vam->input;
2536   vl_api_add_node_next_t *mp;
2537   u8 *name = 0;
2538   u8 *next = 0;
2539   int ret;
2540
2541   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2542     {
2543       if (unformat (i, "node %s", &name))
2544         ;
2545       else if (unformat (i, "next %s", &next))
2546         ;
2547       else
2548         break;
2549     }
2550   if (name == 0)
2551     {
2552       errmsg ("node name required");
2553       return -99;
2554     }
2555   if (vec_len (name) >= ARRAY_LEN (mp->node_name))
2556     {
2557       errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name));
2558       return -99;
2559     }
2560   if (next == 0)
2561     {
2562       errmsg ("next node required");
2563       return -99;
2564     }
2565   if (vec_len (next) >= ARRAY_LEN (mp->next_name))
2566     {
2567       errmsg ("next name too long, max %d", ARRAY_LEN (mp->next_name));
2568       return -99;
2569     }
2570
2571   M (ADD_NODE_NEXT, mp);
2572   clib_memcpy (mp->node_name, name, vec_len (name));
2573   clib_memcpy (mp->next_name, next, vec_len (next));
2574   vec_free (name);
2575   vec_free (next);
2576
2577   S (mp);
2578   W (ret);
2579   return ret;
2580 }
2581
2582 #define foreach_vtr_op                                                        \
2583   _ ("disable", L2_VTR_DISABLED)                                              \
2584   _ ("push-1", L2_VTR_PUSH_1)                                                 \
2585   _ ("push-2", L2_VTR_PUSH_2)                                                 \
2586   _ ("pop-1", L2_VTR_POP_1)                                                   \
2587   _ ("pop-2", L2_VTR_POP_2)                                                   \
2588   _ ("translate-1-1", L2_VTR_TRANSLATE_1_1)                                   \
2589   _ ("translate-1-2", L2_VTR_TRANSLATE_1_2)                                   \
2590   _ ("translate-2-1", L2_VTR_TRANSLATE_2_1)                                   \
2591   _ ("translate-2-2", L2_VTR_TRANSLATE_2_2)
2592
2593 static int
2594 api_show_version (vat_main_t *vam)
2595 {
2596   vl_api_show_version_t *mp;
2597   int ret;
2598
2599   M (SHOW_VERSION, mp);
2600
2601   S (mp);
2602   W (ret);
2603   return ret;
2604 }
2605
2606 static int
2607 api_get_first_msg_id (vat_main_t *vam)
2608 {
2609   vl_api_get_first_msg_id_t *mp;
2610   unformat_input_t *i = vam->input;
2611   u8 *name;
2612   u8 name_set = 0;
2613   int ret;
2614
2615   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2616     {
2617       if (unformat (i, "client %s", &name))
2618         name_set = 1;
2619       else
2620         break;
2621     }
2622
2623   if (name_set == 0)
2624     {
2625       errmsg ("missing client name");
2626       return -99;
2627     }
2628   vec_add1 (name, 0);
2629
2630   if (vec_len (name) > 63)
2631     {
2632       errmsg ("client name too long");
2633       return -99;
2634     }
2635
2636   M (GET_FIRST_MSG_ID, mp);
2637   clib_memcpy (mp->name, name, vec_len (name));
2638   S (mp);
2639   W (ret);
2640   return ret;
2641 }
2642
2643 static int
2644 api_get_node_graph (vat_main_t *vam)
2645 {
2646   vl_api_get_node_graph_t *mp;
2647   int ret;
2648
2649   M (GET_NODE_GRAPH, mp);
2650
2651   /* send it... */
2652   S (mp);
2653   /* Wait for the reply */
2654   W (ret);
2655   return ret;
2656 }
2657
2658 #define foreach_pbb_vtr_op      \
2659 _("disable",  L2_VTR_DISABLED)  \
2660 _("pop",  L2_VTR_POP_2)         \
2661 _("push",  L2_VTR_PUSH_2)
2662
2663
2664 static void vl_api_app_namespace_add_del_reply_t_handler
2665   (vl_api_app_namespace_add_del_reply_t * mp)
2666 {
2667   vat_main_t *vam = &vat_main;
2668   i32 retval = ntohl (mp->retval);
2669   if (vam->async_mode)
2670     {
2671       vam->async_errors += (retval < 0);
2672     }
2673   else
2674     {
2675       vam->retval = retval;
2676       if (retval == 0)
2677         errmsg ("app ns index %d\n", ntohl (mp->appns_index));
2678       vam->result_ready = 1;
2679     }
2680 }
2681
2682 static void vl_api_app_namespace_add_del_reply_t_handler_json
2683   (vl_api_app_namespace_add_del_reply_t * mp)
2684 {
2685   vat_main_t *vam = &vat_main;
2686   vat_json_node_t node;
2687
2688   vat_json_init_object (&node);
2689   vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
2690   vat_json_object_add_uint (&node, "appns_index", ntohl (mp->appns_index));
2691
2692   vat_json_print (vam->ofp, &node);
2693   vat_json_free (&node);
2694
2695   vam->retval = ntohl (mp->retval);
2696   vam->result_ready = 1;
2697 }
2698
2699 static int
2700 api_app_namespace_add_del (vat_main_t * vam)
2701 {
2702   vl_api_app_namespace_add_del_t *mp;
2703   unformat_input_t *i = vam->input;
2704   u8 *ns_id = 0, secret_set = 0, sw_if_index_set = 0;
2705   u32 sw_if_index, ip4_fib_id, ip6_fib_id;
2706   u64 secret;
2707   int ret;
2708
2709   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2710     {
2711       if (unformat (i, "id %_%v%_", &ns_id))
2712         ;
2713       else if (unformat (i, "secret %lu", &secret))
2714         secret_set = 1;
2715       else if (unformat (i, "sw_if_index %d", &sw_if_index))
2716         sw_if_index_set = 1;
2717       else if (unformat (i, "ip4_fib_id %d", &ip4_fib_id))
2718         ;
2719       else if (unformat (i, "ip6_fib_id %d", &ip6_fib_id))
2720         ;
2721       else
2722         break;
2723     }
2724   if (!ns_id || !secret_set || !sw_if_index_set)
2725     {
2726       errmsg ("namespace id, secret and sw_if_index must be set");
2727       return -99;
2728     }
2729   if (vec_len (ns_id) > 64)
2730     {
2731       errmsg ("namespace id too long");
2732       return -99;
2733     }
2734   M (APP_NAMESPACE_ADD_DEL, mp);
2735
2736   vl_api_vec_to_api_string (ns_id, &mp->namespace_id);
2737   mp->secret = clib_host_to_net_u64 (secret);
2738   mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
2739   mp->ip4_fib_id = clib_host_to_net_u32 (ip4_fib_id);
2740   mp->ip6_fib_id = clib_host_to_net_u32 (ip6_fib_id);
2741   vec_free (ns_id);
2742   S (mp);
2743   W (ret);
2744   return ret;
2745 }
2746
2747 static int
2748 api_sock_init_shm (vat_main_t * vam)
2749 {
2750 #if VPP_API_TEST_BUILTIN == 0
2751   unformat_input_t *i = vam->input;
2752   vl_api_shm_elem_config_t *config = 0;
2753   u64 size = 64 << 20;
2754   int rv;
2755
2756   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2757     {
2758       if (unformat (i, "size %U", unformat_memory_size, &size))
2759         ;
2760       else
2761         break;
2762     }
2763
2764   /*
2765    * Canned custom ring allocator config.
2766    * Should probably parse all of this
2767    */
2768   vec_validate (config, 6);
2769   config[0].type = VL_API_VLIB_RING;
2770   config[0].size = 256;
2771   config[0].count = 32;
2772
2773   config[1].type = VL_API_VLIB_RING;
2774   config[1].size = 1024;
2775   config[1].count = 16;
2776
2777   config[2].type = VL_API_VLIB_RING;
2778   config[2].size = 4096;
2779   config[2].count = 2;
2780
2781   config[3].type = VL_API_CLIENT_RING;
2782   config[3].size = 256;
2783   config[3].count = 32;
2784
2785   config[4].type = VL_API_CLIENT_RING;
2786   config[4].size = 1024;
2787   config[4].count = 16;
2788
2789   config[5].type = VL_API_CLIENT_RING;
2790   config[5].size = 4096;
2791   config[5].count = 2;
2792
2793   config[6].type = VL_API_QUEUE;
2794   config[6].count = 128;
2795   config[6].size = sizeof (uword);
2796
2797   rv = vl_socket_client_init_shm (config, 1 /* want_pthread */ );
2798   if (!rv)
2799     vam->client_index_invalid = 1;
2800   return rv;
2801 #else
2802   return -99;
2803 #endif
2804 }
2805
2806 static void
2807 vl_api_session_rules_details_t_handler (vl_api_session_rules_details_t * mp)
2808 {
2809   vat_main_t *vam = &vat_main;
2810   fib_prefix_t lcl, rmt;
2811
2812   ip_prefix_decode (&mp->lcl, &lcl);
2813   ip_prefix_decode (&mp->rmt, &rmt);
2814
2815   if (lcl.fp_proto == FIB_PROTOCOL_IP4)
2816     {
2817       print (vam->ofp,
2818              "appns %u tp %u scope %d %U/%d %d %U/%d %d action: %d tag: %s",
2819              clib_net_to_host_u32 (mp->appns_index), mp->transport_proto,
2820              mp->scope, format_ip4_address, &lcl.fp_addr.ip4, lcl.fp_len,
2821              clib_net_to_host_u16 (mp->lcl_port), format_ip4_address,
2822              &rmt.fp_addr.ip4, rmt.fp_len,
2823              clib_net_to_host_u16 (mp->rmt_port),
2824              clib_net_to_host_u32 (mp->action_index), mp->tag);
2825     }
2826   else
2827     {
2828       print (vam->ofp,
2829              "appns %u tp %u scope %d %U/%d %d %U/%d %d action: %d tag: %s",
2830              clib_net_to_host_u32 (mp->appns_index), mp->transport_proto,
2831              mp->scope, format_ip6_address, &lcl.fp_addr.ip6, lcl.fp_len,
2832              clib_net_to_host_u16 (mp->lcl_port), format_ip6_address,
2833              &rmt.fp_addr.ip6, rmt.fp_len,
2834              clib_net_to_host_u16 (mp->rmt_port),
2835              clib_net_to_host_u32 (mp->action_index), mp->tag);
2836     }
2837 }
2838
2839 static void
2840 vl_api_session_rules_details_t_handler_json (vl_api_session_rules_details_t *
2841                                              mp)
2842 {
2843   vat_main_t *vam = &vat_main;
2844   vat_json_node_t *node = NULL;
2845   struct in6_addr ip6;
2846   struct in_addr ip4;
2847
2848   fib_prefix_t lcl, rmt;
2849
2850   ip_prefix_decode (&mp->lcl, &lcl);
2851   ip_prefix_decode (&mp->rmt, &rmt);
2852
2853   if (VAT_JSON_ARRAY != vam->json_tree.type)
2854     {
2855       ASSERT (VAT_JSON_NONE == vam->json_tree.type);
2856       vat_json_init_array (&vam->json_tree);
2857     }
2858   node = vat_json_array_add (&vam->json_tree);
2859   vat_json_init_object (node);
2860
2861   vat_json_object_add_uint (node, "appns_index",
2862                             clib_net_to_host_u32 (mp->appns_index));
2863   vat_json_object_add_uint (node, "transport_proto", mp->transport_proto);
2864   vat_json_object_add_uint (node, "scope", mp->scope);
2865   vat_json_object_add_uint (node, "action_index",
2866                             clib_net_to_host_u32 (mp->action_index));
2867   vat_json_object_add_uint (node, "lcl_port",
2868                             clib_net_to_host_u16 (mp->lcl_port));
2869   vat_json_object_add_uint (node, "rmt_port",
2870                             clib_net_to_host_u16 (mp->rmt_port));
2871   vat_json_object_add_uint (node, "lcl_plen", lcl.fp_len);
2872   vat_json_object_add_uint (node, "rmt_plen", rmt.fp_len);
2873   vat_json_object_add_string_copy (node, "tag", mp->tag);
2874   if (lcl.fp_proto == FIB_PROTOCOL_IP4)
2875     {
2876       clib_memcpy (&ip4, &lcl.fp_addr.ip4, sizeof (ip4));
2877       vat_json_object_add_ip4 (node, "lcl_ip", ip4);
2878       clib_memcpy (&ip4, &rmt.fp_addr.ip4, sizeof (ip4));
2879       vat_json_object_add_ip4 (node, "rmt_ip", ip4);
2880     }
2881   else
2882     {
2883       clib_memcpy (&ip6, &lcl.fp_addr.ip6, sizeof (ip6));
2884       vat_json_object_add_ip6 (node, "lcl_ip", ip6);
2885       clib_memcpy (&ip6, &rmt.fp_addr.ip6, sizeof (ip6));
2886       vat_json_object_add_ip6 (node, "rmt_ip", ip6);
2887     }
2888 }
2889
2890 static int
2891 api_session_rule_add_del (vat_main_t * vam)
2892 {
2893   vl_api_session_rule_add_del_t *mp;
2894   unformat_input_t *i = vam->input;
2895   u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen, rmt_plen;
2896   u32 appns_index = 0, scope = 0;
2897   ip4_address_t lcl_ip4, rmt_ip4;
2898   ip6_address_t lcl_ip6, rmt_ip6;
2899   u8 is_ip4 = 1, conn_set = 0;
2900   u8 is_add = 1, *tag = 0;
2901   int ret;
2902   fib_prefix_t lcl, rmt;
2903
2904   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
2905     {
2906       if (unformat (i, "del"))
2907         is_add = 0;
2908       else if (unformat (i, "add"))
2909         ;
2910       else if (unformat (i, "proto tcp"))
2911         proto = 0;
2912       else if (unformat (i, "proto udp"))
2913         proto = 1;
2914       else if (unformat (i, "appns %d", &appns_index))
2915         ;
2916       else if (unformat (i, "scope %d", &scope))
2917         ;
2918       else if (unformat (i, "tag %_%v%_", &tag))
2919         ;
2920       else
2921         if (unformat
2922             (i, "%U/%d %d %U/%d %d", unformat_ip4_address, &lcl_ip4,
2923              &lcl_plen, &lcl_port, unformat_ip4_address, &rmt_ip4, &rmt_plen,
2924              &rmt_port))
2925         {
2926           is_ip4 = 1;
2927           conn_set = 1;
2928         }
2929       else
2930         if (unformat
2931             (i, "%U/%d %d %U/%d %d", unformat_ip6_address, &lcl_ip6,
2932              &lcl_plen, &lcl_port, unformat_ip6_address, &rmt_ip6, &rmt_plen,
2933              &rmt_port))
2934         {
2935           is_ip4 = 0;
2936           conn_set = 1;
2937         }
2938       else if (unformat (i, "action %d", &action))
2939         ;
2940       else
2941         break;
2942     }
2943   if (proto == ~0 || !conn_set || action == ~0)
2944     {
2945       errmsg ("transport proto, connection and action must be set");
2946       return -99;
2947     }
2948
2949   if (scope > 3)
2950     {
2951       errmsg ("scope should be 0-3");
2952       return -99;
2953     }
2954
2955   M (SESSION_RULE_ADD_DEL, mp);
2956
2957   clib_memset (&lcl, 0, sizeof (lcl));
2958   clib_memset (&rmt, 0, sizeof (rmt));
2959   if (is_ip4)
2960     {
2961       ip_set (&lcl.fp_addr, &lcl_ip4, 1);
2962       ip_set (&rmt.fp_addr, &rmt_ip4, 1);
2963       lcl.fp_len = lcl_plen;
2964       rmt.fp_len = rmt_plen;
2965     }
2966   else
2967     {
2968       ip_set (&lcl.fp_addr, &lcl_ip6, 0);
2969       ip_set (&rmt.fp_addr, &rmt_ip6, 0);
2970       lcl.fp_len = lcl_plen;
2971       rmt.fp_len = rmt_plen;
2972     }
2973
2974
2975   ip_prefix_encode (&lcl, &mp->lcl);
2976   ip_prefix_encode (&rmt, &mp->rmt);
2977   mp->lcl_port = clib_host_to_net_u16 ((u16) lcl_port);
2978   mp->rmt_port = clib_host_to_net_u16 ((u16) rmt_port);
2979   mp->transport_proto =
2980     proto ? TRANSPORT_PROTO_API_UDP : TRANSPORT_PROTO_API_TCP;
2981   mp->action_index = clib_host_to_net_u32 (action);
2982   mp->appns_index = clib_host_to_net_u32 (appns_index);
2983   mp->scope = scope;
2984   mp->is_add = is_add;
2985   if (tag)
2986     {
2987       clib_memcpy (mp->tag, tag, vec_len (tag));
2988       vec_free (tag);
2989     }
2990
2991   S (mp);
2992   W (ret);
2993   return ret;
2994 }
2995
2996 static int
2997 api_session_rules_dump (vat_main_t * vam)
2998 {
2999   vl_api_session_rules_dump_t *mp;
3000   vl_api_control_ping_t *mp_ping;
3001   int ret;
3002
3003   if (!vam->json_output)
3004     {
3005       print (vam->ofp, "%=20s", "Session Rules");
3006     }
3007
3008   M (SESSION_RULES_DUMP, mp);
3009   /* send it... */
3010   S (mp);
3011
3012   /* Use a control ping for synchronization */
3013   MPING (CONTROL_PING, mp_ping);
3014   S (mp_ping);
3015
3016   /* Wait for a reply... */
3017   W (ret);
3018   return ret;
3019 }
3020
3021 static int
3022 q_or_quit (vat_main_t * vam)
3023 {
3024 #if VPP_API_TEST_BUILTIN == 0
3025   longjmp (vam->jump_buf, 1);
3026 #endif
3027   return 0;                     /* not so much */
3028 }
3029
3030 static int
3031 q (vat_main_t * vam)
3032 {
3033   return q_or_quit (vam);
3034 }
3035
3036 static int
3037 quit (vat_main_t * vam)
3038 {
3039   return q_or_quit (vam);
3040 }
3041
3042 static int
3043 comment (vat_main_t * vam)
3044 {
3045   return 0;
3046 }
3047
3048 static int
3049 elog_save (vat_main_t * vam)
3050 {
3051 #if VPP_API_TEST_BUILTIN == 0
3052   elog_main_t *em = &vam->elog_main;
3053   unformat_input_t *i = vam->input;
3054   char *file, *chroot_file;
3055   clib_error_t *error;
3056
3057   if (!unformat (i, "%s", &file))
3058     {
3059       errmsg ("expected file name, got `%U'", format_unformat_error, i);
3060       return 0;
3061     }
3062
3063   /* It's fairly hard to get "../oopsie" through unformat; just in case */
3064   if (strstr (file, "..") || index (file, '/'))
3065     {
3066       errmsg ("illegal characters in filename '%s'", file);
3067       return 0;
3068     }
3069
3070   chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
3071
3072   vec_free (file);
3073
3074   errmsg ("Saving %wd of %wd events to %s",
3075           elog_n_events_in_buffer (em),
3076           elog_buffer_capacity (em), chroot_file);
3077
3078   error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
3079   vec_free (chroot_file);
3080
3081   if (error)
3082     clib_error_report (error);
3083 #else
3084   errmsg ("Use the vpp event loger...");
3085 #endif
3086
3087   return 0;
3088 }
3089
3090 static int
3091 elog_setup (vat_main_t * vam)
3092 {
3093 #if VPP_API_TEST_BUILTIN == 0
3094   elog_main_t *em = &vam->elog_main;
3095   unformat_input_t *i = vam->input;
3096   u32 nevents = 128 << 10;
3097
3098   (void) unformat (i, "nevents %d", &nevents);
3099
3100   elog_init (em, nevents);
3101   vl_api_set_elog_main (em);
3102   vl_api_set_elog_trace_api_messages (1);
3103   errmsg ("Event logger initialized with %u events", nevents);
3104 #else
3105   errmsg ("Use the vpp event loger...");
3106 #endif
3107   return 0;
3108 }
3109
3110 static int
3111 elog_enable (vat_main_t * vam)
3112 {
3113 #if VPP_API_TEST_BUILTIN == 0
3114   elog_main_t *em = &vam->elog_main;
3115
3116   elog_enable_disable (em, 1 /* enable */ );
3117   vl_api_set_elog_trace_api_messages (1);
3118   errmsg ("Event logger enabled...");
3119 #else
3120   errmsg ("Use the vpp event loger...");
3121 #endif
3122   return 0;
3123 }
3124
3125 static int
3126 elog_disable (vat_main_t * vam)
3127 {
3128 #if VPP_API_TEST_BUILTIN == 0
3129   elog_main_t *em = &vam->elog_main;
3130
3131   elog_enable_disable (em, 0 /* enable */ );
3132   vl_api_set_elog_trace_api_messages (1);
3133   errmsg ("Event logger disabled...");
3134 #else
3135   errmsg ("Use the vpp event loger...");
3136 #endif
3137   return 0;
3138 }
3139
3140 static int
3141 statseg (vat_main_t * vam)
3142 {
3143   ssvm_private_t *ssvmp = &vam->stat_segment;
3144   ssvm_shared_header_t *shared_header = ssvmp->sh;
3145   vlib_counter_t **counters;
3146   u64 thread0_index1_packets;
3147   u64 thread0_index1_bytes;
3148   f64 vector_rate, input_rate;
3149   uword *p;
3150
3151   uword *counter_vector_by_name;
3152   if (vam->stat_segment_lockp == 0)
3153     {
3154       errmsg ("Stat segment not mapped...");
3155       return -99;
3156     }
3157
3158   /* look up "/if/rx for sw_if_index 1 as a test */
3159
3160   clib_spinlock_lock (vam->stat_segment_lockp);
3161
3162   counter_vector_by_name = (uword *) shared_header->opaque[1];
3163
3164   p = hash_get_mem (counter_vector_by_name, "/if/rx");
3165   if (p == 0)
3166     {
3167       clib_spinlock_unlock (vam->stat_segment_lockp);
3168       errmsg ("/if/tx not found?");
3169       return -99;
3170     }
3171
3172   /* Fish per-thread vector of combined counters from shared memory */
3173   counters = (vlib_counter_t **) p[0];
3174
3175   if (vec_len (counters[0]) < 2)
3176     {
3177       clib_spinlock_unlock (vam->stat_segment_lockp);
3178       errmsg ("/if/tx vector length %d", vec_len (counters[0]));
3179       return -99;
3180     }
3181
3182   /* Read thread 0 sw_if_index 1 counter */
3183   thread0_index1_packets = counters[0][1].packets;
3184   thread0_index1_bytes = counters[0][1].bytes;
3185
3186   p = hash_get_mem (counter_vector_by_name, "vector_rate");
3187   if (p == 0)
3188     {
3189       clib_spinlock_unlock (vam->stat_segment_lockp);
3190       errmsg ("vector_rate not found?");
3191       return -99;
3192     }
3193
3194   vector_rate = *(f64 *) (p[0]);
3195   p = hash_get_mem (counter_vector_by_name, "input_rate");
3196   if (p == 0)
3197     {
3198       clib_spinlock_unlock (vam->stat_segment_lockp);
3199       errmsg ("input_rate not found?");
3200       return -99;
3201     }
3202   input_rate = *(f64 *) (p[0]);
3203
3204   clib_spinlock_unlock (vam->stat_segment_lockp);
3205
3206   print (vam->ofp, "vector_rate %.2f input_rate %.2f",
3207          vector_rate, input_rate);
3208   print (vam->ofp, "thread 0 sw_if_index 1 rx pkts %lld, bytes %lld",
3209          thread0_index1_packets, thread0_index1_bytes);
3210
3211   return 0;
3212 }
3213
3214 static int
3215 cmd_cmp (void *a1, void *a2)
3216 {
3217   u8 **c1 = a1;
3218   u8 **c2 = a2;
3219
3220   return strcmp ((char *) (c1[0]), (char *) (c2[0]));
3221 }
3222
3223 static int
3224 help (vat_main_t * vam)
3225 {
3226   u8 **cmds = 0;
3227   u8 *name = 0;
3228   hash_pair_t *p;
3229   unformat_input_t *i = vam->input;
3230   int j;
3231
3232   if (unformat (i, "%s", &name))
3233     {
3234       uword *hs;
3235
3236       vec_add1 (name, 0);
3237
3238       hs = hash_get_mem (vam->help_by_name, name);
3239       if (hs)
3240         print (vam->ofp, "usage: %s %s", name, hs[0]);
3241       else
3242         print (vam->ofp, "No such msg / command '%s'", name);
3243       vec_free (name);
3244       return 0;
3245     }
3246
3247   print (vam->ofp, "Help is available for the following:");
3248
3249     /* *INDENT-OFF* */
3250     hash_foreach_pair (p, vam->function_by_name,
3251     ({
3252       vec_add1 (cmds, (u8 *)(p->key));
3253     }));
3254     /* *INDENT-ON* */
3255
3256   vec_sort_with_function (cmds, cmd_cmp);
3257
3258   for (j = 0; j < vec_len (cmds); j++)
3259     print (vam->ofp, "%s", cmds[j]);
3260
3261   vec_free (cmds);
3262   return 0;
3263 }
3264
3265 static int
3266 set (vat_main_t * vam)
3267 {
3268   u8 *name = 0, *value = 0;
3269   unformat_input_t *i = vam->input;
3270
3271   if (unformat (i, "%s", &name))
3272     {
3273       /* The input buffer is a vector, not a string. */
3274       value = vec_dup (i->buffer);
3275       vec_delete (value, i->index, 0);
3276       /* Almost certainly has a trailing newline */
3277       if (value[vec_len (value) - 1] == '\n')
3278         value[vec_len (value) - 1] = 0;
3279       /* Make sure it's a proper string, one way or the other */
3280       vec_add1 (value, 0);
3281       (void) clib_macro_set_value (&vam->macro_main,
3282                                    (char *) name, (char *) value);
3283     }
3284   else
3285     errmsg ("usage: set <name> <value>");
3286
3287   vec_free (name);
3288   vec_free (value);
3289   return 0;
3290 }
3291
3292 static int
3293 unset (vat_main_t * vam)
3294 {
3295   u8 *name = 0;
3296
3297   if (unformat (vam->input, "%s", &name))
3298     if (clib_macro_unset (&vam->macro_main, (char *) name) == 1)
3299       errmsg ("unset: %s wasn't set", name);
3300   vec_free (name);
3301   return 0;
3302 }
3303
3304 typedef struct
3305 {
3306   u8 *name;
3307   u8 *value;
3308 } macro_sort_t;
3309
3310
3311 static int
3312 macro_sort_cmp (void *a1, void *a2)
3313 {
3314   macro_sort_t *s1 = a1;
3315   macro_sort_t *s2 = a2;
3316
3317   return strcmp ((char *) (s1->name), (char *) (s2->name));
3318 }
3319
3320 static int
3321 dump_macro_table (vat_main_t * vam)
3322 {
3323   macro_sort_t *sort_me = 0, *sm;
3324   int i;
3325   hash_pair_t *p;
3326
3327     /* *INDENT-OFF* */
3328     hash_foreach_pair (p, vam->macro_main.the_value_table_hash,
3329     ({
3330       vec_add2 (sort_me, sm, 1);
3331       sm->name = (u8 *)(p->key);
3332       sm->value = (u8 *) (p->value[0]);
3333     }));
3334     /* *INDENT-ON* */
3335
3336   vec_sort_with_function (sort_me, macro_sort_cmp);
3337
3338   if (vec_len (sort_me))
3339     print (vam->ofp, "%-15s%s", "Name", "Value");
3340   else
3341     print (vam->ofp, "The macro table is empty...");
3342
3343   for (i = 0; i < vec_len (sort_me); i++)
3344     print (vam->ofp, "%-15s%s", sort_me[i].name, sort_me[i].value);
3345   return 0;
3346 }
3347
3348 static int
3349 value_sort_cmp (void *a1, void *a2)
3350 {
3351   name_sort_t *n1 = a1;
3352   name_sort_t *n2 = a2;
3353
3354   if (n1->value < n2->value)
3355     return -1;
3356   if (n1->value > n2->value)
3357     return 1;
3358   return 0;
3359 }
3360
3361
3362 static int
3363 dump_msg_api_table (vat_main_t * vam)
3364 {
3365   api_main_t *am = vlibapi_get_main ();
3366   name_sort_t *nses = 0, *ns;
3367   hash_pair_t *hp;
3368   int i;
3369
3370   /* *INDENT-OFF* */
3371   hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
3372   ({
3373     vec_add2 (nses, ns, 1);
3374     ns->name = (u8 *)(hp->key);
3375     ns->value = (u32) hp->value[0];
3376   }));
3377   /* *INDENT-ON* */
3378
3379   vec_sort_with_function (nses, value_sort_cmp);
3380
3381   for (i = 0; i < vec_len (nses); i++)
3382     print (vam->ofp, " [%d]: %s", nses[i].value, nses[i].name);
3383   vec_free (nses);
3384   return 0;
3385 }
3386
3387 static int
3388 get_msg_id (vat_main_t * vam)
3389 {
3390   u8 *name_and_crc;
3391   u32 message_index;
3392
3393   if (unformat (vam->input, "%s", &name_and_crc))
3394     {
3395       message_index = vl_msg_api_get_msg_index (name_and_crc);
3396       if (message_index == ~0)
3397         {
3398           print (vam->ofp, " '%s' not found", name_and_crc);
3399           return 0;
3400         }
3401       print (vam->ofp, " '%s' has message index %d",
3402              name_and_crc, message_index);
3403       return 0;
3404     }
3405   errmsg ("name_and_crc required...");
3406   return 0;
3407 }
3408
3409 static int
3410 search_node_table (vat_main_t * vam)
3411 {
3412   unformat_input_t *line_input = vam->input;
3413   u8 *node_to_find;
3414   int j;
3415   vlib_node_t *node, *next_node;
3416   uword *p;
3417
3418   if (vam->graph_node_index_by_name == 0)
3419     {
3420       print (vam->ofp, "Node table empty, issue get_node_graph...");
3421       return 0;
3422     }
3423
3424   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3425     {
3426       if (unformat (line_input, "%s", &node_to_find))
3427         {
3428           vec_add1 (node_to_find, 0);
3429           p = hash_get_mem (vam->graph_node_index_by_name, node_to_find);
3430           if (p == 0)
3431             {
3432               print (vam->ofp, "%s not found...", node_to_find);
3433               goto out;
3434             }
3435           node = vam->graph_nodes[0][p[0]];
3436           print (vam->ofp, "[%d] %s", p[0], node->name);
3437           for (j = 0; j < vec_len (node->next_nodes); j++)
3438             {
3439               if (node->next_nodes[j] != ~0)
3440                 {
3441                   next_node = vam->graph_nodes[0][node->next_nodes[j]];
3442                   print (vam->ofp, "  [%d] %s", j, next_node->name);
3443                 }
3444             }
3445         }
3446
3447       else
3448         {
3449           clib_warning ("parse error '%U'", format_unformat_error,
3450                         line_input);
3451           return -99;
3452         }
3453
3454     out:
3455       vec_free (node_to_find);
3456
3457     }
3458
3459   return 0;
3460 }
3461
3462
3463 static int
3464 script (vat_main_t * vam)
3465 {
3466 #if (VPP_API_TEST_BUILTIN==0)
3467   u8 *s = 0;
3468   char *save_current_file;
3469   unformat_input_t save_input;
3470   jmp_buf save_jump_buf;
3471   u32 save_line_number;
3472
3473   FILE *new_fp, *save_ifp;
3474
3475   if (unformat (vam->input, "%s", &s))
3476     {
3477       new_fp = fopen ((char *) s, "r");
3478       if (new_fp == 0)
3479         {
3480           errmsg ("Couldn't open script file %s", s);
3481           vec_free (s);
3482           return -99;
3483         }
3484     }
3485   else
3486     {
3487       errmsg ("Missing script name");
3488       return -99;
3489     }
3490
3491   clib_memcpy (&save_input, &vam->input, sizeof (save_input));
3492   clib_memcpy (&save_jump_buf, &vam->jump_buf, sizeof (save_jump_buf));
3493   save_ifp = vam->ifp;
3494   save_line_number = vam->input_line_number;
3495   save_current_file = (char *) vam->current_file;
3496
3497   vam->input_line_number = 0;
3498   vam->ifp = new_fp;
3499   vam->current_file = s;
3500   do_one_file (vam);
3501
3502   clib_memcpy (&vam->input, &save_input, sizeof (save_input));
3503   clib_memcpy (&vam->jump_buf, &save_jump_buf, sizeof (save_jump_buf));
3504   vam->ifp = save_ifp;
3505   vam->input_line_number = save_line_number;
3506   vam->current_file = (u8 *) save_current_file;
3507   vec_free (s);
3508
3509   return 0;
3510 #else
3511   clib_warning ("use the exec command...");
3512   return -99;
3513 #endif
3514 }
3515
3516 static int
3517 echo (vat_main_t * vam)
3518 {
3519   print (vam->ofp, "%v", vam->input->buffer);
3520   return 0;
3521 }
3522
3523 /* List of API message constructors, CLI names map to api_xxx */
3524 #define foreach_vpe_api_msg                                             \
3525 _(get_node_index, "node <node-name")                                    \
3526 _(add_node_next, "node <node-name> next <next-node-name>")              \
3527 _(show_version, "")                                                     \
3528 _(show_threads, "")                                                     \
3529 _(get_first_msg_id, "client <name>")                                    \
3530 _(get_node_graph, " ")                                                  \
3531 _(get_next_index, "node-name <node-name> next-node-name <node-name>")   \
3532 _(sock_init_shm, "size <nnn>")                                          \
3533 _(app_namespace_add_del, "[add] id <ns-id> secret <nn> sw_if_index <nn>")\
3534 _(session_rule_add_del, "[add|del] proto <tcp/udp> <lcl-ip>/<plen> "    \
3535   "<lcl-port> <rmt-ip>/<plen> <rmt-port> action <nn>")                  \
3536 _(session_rules_dump, "")                                               \
3537
3538 /* List of command functions, CLI names map directly to functions */
3539 #define foreach_cli_function                                    \
3540 _(comment, "usage: comment <ignore-rest-of-line>")              \
3541 _(dump_macro_table, "usage: dump_macro_table ")                 \
3542 _(dump_msg_api_table, "usage: dump_msg_api_table")              \
3543 _(elog_setup, "usage: elog_setup [nevents, default 128K]")      \
3544 _(elog_disable, "usage: elog_disable")                          \
3545 _(elog_enable, "usage: elog_enable")                            \
3546 _(elog_save, "usage: elog_save <filename>")                     \
3547 _(get_msg_id, "usage: get_msg_id name_and_crc")                 \
3548 _(echo, "usage: echo <message>")                                \
3549 _(exec, "usage: exec <vpe-debug-CLI-command>")                  \
3550 _(exec_inband, "usage: exec_inband <vpe-debug-CLI-command>")    \
3551 _(help, "usage: help")                                          \
3552 _(q, "usage: quit")                                             \
3553 _(quit, "usage: quit")                                          \
3554 _(search_node_table, "usage: search_node_table <name>...")      \
3555 _(set, "usage: set <variable-name> <value>")                    \
3556 _(script, "usage: script <file-name>")                          \
3557 _(statseg, "usage: statseg")                                    \
3558 _(unset, "usage: unset <variable-name>")
3559
3560 #define _(N,n)                                  \
3561     static void vl_api_##n##_t_handler_uni      \
3562     (vl_api_##n##_t * mp)                       \
3563     {                                           \
3564         vat_main_t * vam = &vat_main;           \
3565         if (vam->json_output) {                 \
3566             vl_api_##n##_t_handler_json(mp);    \
3567         } else {                                \
3568             vl_api_##n##_t_handler(mp);         \
3569         }                                       \
3570     }
3571 foreach_vpe_api_reply_msg;
3572 #if VPP_API_TEST_BUILTIN == 0
3573 foreach_standalone_reply_msg;
3574 #endif
3575 #undef _
3576
3577 void
3578 vat_api_hookup (vat_main_t * vam)
3579 {
3580 #define _(N,n)                                                  \
3581     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
3582                            vl_api_##n##_t_handler_uni,          \
3583                            vl_noop_handler,                     \
3584                            vl_api_##n##_t_endian,               \
3585                            vl_api_##n##_t_print,                \
3586                            sizeof(vl_api_##n##_t), 1);
3587   foreach_vpe_api_reply_msg;
3588 #if VPP_API_TEST_BUILTIN == 0
3589   foreach_standalone_reply_msg;
3590 #endif
3591 #undef _
3592
3593 #if (VPP_API_TEST_BUILTIN==0)
3594   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
3595
3596   vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
3597
3598   vam->function_by_name = hash_create_string (0, sizeof (uword));
3599
3600   vam->help_by_name = hash_create_string (0, sizeof (uword));
3601 #endif
3602
3603   /* API messages we can send */
3604 #define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
3605   foreach_vpe_api_msg;
3606 #undef _
3607
3608   /* Help strings */
3609 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
3610   foreach_vpe_api_msg;
3611 #undef _
3612
3613   /* CLI functions */
3614 #define _(n,h) hash_set_mem (vam->function_by_name, #n, n);
3615   foreach_cli_function;
3616 #undef _
3617
3618   /* Help strings */
3619 #define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
3620   foreach_cli_function;
3621 #undef _
3622 }
3623
3624 #if VPP_API_TEST_BUILTIN
3625 static clib_error_t *
3626 vat_api_hookup_shim (vlib_main_t * vm)
3627 {
3628   vat_api_hookup (&vat_main);
3629   return 0;
3630 }
3631
3632 VLIB_API_INIT_FUNCTION (vat_api_hookup_shim);
3633 #endif
3634
3635 /*
3636  * fd.io coding-style-patch-verification: ON
3637  *
3638  * Local Variables:
3639  * eval: (c-set-style "gnu")
3640  * End:
3641  */