misc: api move continued
[vpp.git] / src / plugins / lisp / lisp-gpe / lisp_gpe_test.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vat/vat.h>
17 #include <vlibapi/api.h>
18 #include <vlibmemory/api.h>
19 #include <vppinfra/error.h>
20
21 #include <vnet/ip/ip_format_fns.h>
22 #include <vnet/ethernet/ethernet_format_fns.h>
23 #include <vnet/ethernet/mac_address.h>
24 #include <lisp/lisp-cp/lisp_types.h>
25
26 /* define message IDs */
27 #include <lisp/lisp-gpe/lisp_gpe.api_enum.h>
28 #include <lisp/lisp-gpe/lisp_gpe.api_types.h>
29 #include <vlibmemory/vlib.api_types.h>
30
31 typedef struct
32 {
33   /* API message ID base */
34   u16 msg_id_base;
35   vat_main_t *vat_main;
36   u32 ping_id;
37 } lisp_gpe_test_main_t;
38
39 lisp_gpe_test_main_t lisp_gpe_test_main;
40
41 #define __plugin_msg_base lisp_gpe_test_main.msg_id_base
42 #include <vlibapi/vat_helper_macros.h>
43
44 /* Macro to finish up custom dump fns */
45 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
46 #define FINISH                                  \
47     vec_add1 (s, 0);                            \
48     vl_print (handle, (char *)s);               \
49     vec_free (s);                               \
50     return handle;
51
52 #define LISP_PING(_lm, mp_ping)                                         \
53   if (!(_lm)->ping_id)                                                  \
54     (_lm)->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); \
55   mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));          \
56   mp_ping->_vl_msg_id = htons ((_lm)->ping_id);                         \
57   mp_ping->client_index = vam->my_client_index;                         \
58   fformat (vam->ofp, "Sending ping id=%d\n", (_lm)->ping_id);           \
59   vam->result_ready = 0;                                                \
60
61 typedef struct
62 {
63   u32 spi;
64   u8 si;
65 } __attribute__ ((__packed__)) lisp_nsh_api_t;
66
67 static uword
68 unformat_nsh_address (unformat_input_t * input, va_list * args)
69 {
70   lisp_nsh_api_t *nsh = va_arg (*args, lisp_nsh_api_t *);
71   return unformat (input, "SPI:%d SI:%d", &nsh->spi, &nsh->si);
72 }
73
74 static u8 *
75 format_nsh_address_vat (u8 * s, va_list * args)
76 {
77   nsh_t *a = va_arg (*args, nsh_t *);
78   return format (s, "SPI:%d SI:%d", clib_net_to_host_u32 (a->spi), a->si);
79 }
80
81 static u8 *
82 format_lisp_flat_eid (u8 * s, va_list * args)
83 {
84   vl_api_eid_t *eid = va_arg (*args, vl_api_eid_t *);
85
86   switch (eid->type)
87     {
88     case EID_TYPE_API_PREFIX:
89       if (eid->address.prefix.address.af)
90         return format (s, "%U/%d", format_ip6_address,
91                        eid->address.prefix.address.un.ip6,
92                        eid->address.prefix.len);
93       return format (s, "%U/%d", format_ip4_address,
94                      eid->address.prefix.address.un.ip4,
95                      eid->address.prefix.len);
96     case EID_TYPE_API_MAC:
97       return format (s, "%U", format_ethernet_address, eid->address.mac);
98     case EID_TYPE_API_NSH:
99       return format (s, "%U", format_nsh_address_vat, eid->address.nsh);
100     }
101   return 0;
102 }
103
104 static void vl_api_gpe_add_del_fwd_entry_reply_t_handler
105   (vl_api_gpe_add_del_fwd_entry_reply_t * mp)
106 {
107   vat_main_t *vam = &vat_main;
108   i32 retval = ntohl (mp->retval);
109   if (vam->async_mode)
110     {
111       vam->async_errors += (retval < 0);
112     }
113   else
114     {
115       vam->retval = retval;
116       vam->result_ready = 1;
117     }
118 }
119
120 static void
121 api_gpe_fwd_entry_net_to_host (vl_api_gpe_fwd_entry_t * e)
122 {
123   e->dp_table = clib_net_to_host_u32 (e->dp_table);
124   e->fwd_entry_index = clib_net_to_host_u32 (e->fwd_entry_index);
125   e->vni = clib_net_to_host_u32 (e->vni);
126 }
127
128 static void
129   gpe_fwd_entries_get_reply_t_net_to_host
130   (vl_api_gpe_fwd_entries_get_reply_t * mp)
131 {
132   u32 i;
133
134   mp->count = clib_net_to_host_u32 (mp->count);
135   for (i = 0; i < mp->count; i++)
136     {
137       api_gpe_fwd_entry_net_to_host (&mp->entries[i]);
138     }
139 }
140
141 static u8 *
142 format_gpe_encap_mode (u8 * s, va_list * args)
143 {
144   u32 mode = va_arg (*args, u32);
145
146   switch (mode)
147     {
148     case 0:
149       return format (s, "lisp");
150     case 1:
151       return format (s, "vxlan");
152     }
153   return 0;
154 }
155
156 static void
157   vl_api_gpe_get_encap_mode_reply_t_handler
158   (vl_api_gpe_get_encap_mode_reply_t * mp)
159 {
160   vat_main_t *vam = &vat_main;
161
162   print (vam->ofp, "gpe mode: %U", format_gpe_encap_mode, mp->encap_mode);
163   vam->retval = ntohl (mp->retval);
164   vam->result_ready = 1;
165 }
166
167 static void
168   vl_api_gpe_fwd_entry_path_details_t_handler
169   (vl_api_gpe_fwd_entry_path_details_t * mp)
170 {
171   vat_main_t *vam = &vat_main;
172   u8 *(*format_ip_address_fcn) (u8 *, va_list *) = 0;
173
174   if (mp->lcl_loc.addr.af)
175     format_ip_address_fcn = format_ip6_address;
176   else
177     format_ip_address_fcn = format_ip4_address;
178
179   print (vam->ofp, "w:%d %30U %30U", mp->rmt_loc.weight,
180          format_ip_address_fcn, &mp->lcl_loc.addr.un,
181          format_ip_address_fcn, &mp->rmt_loc.addr.un);
182 }
183
184 static void
185   vl_api_gpe_fwd_entries_get_reply_t_handler
186   (vl_api_gpe_fwd_entries_get_reply_t * mp)
187 {
188   vat_main_t *vam = &vat_main;
189   u32 i;
190   int retval = clib_net_to_host_u32 (mp->retval);
191   vl_api_gpe_fwd_entry_t *e;
192
193   if (retval)
194     goto end;
195
196   gpe_fwd_entries_get_reply_t_net_to_host (mp);
197
198   for (i = 0; i < mp->count; i++)
199     {
200       e = &mp->entries[i];
201       print (vam->ofp, "%10d %10d %U %40U", e->fwd_entry_index, e->dp_table,
202              format_lisp_flat_eid, e->leid, format_lisp_flat_eid, e->reid);
203     }
204
205 end:
206   vam->retval = retval;
207   vam->result_ready = 1;
208 }
209
210 static void
211   vl_api_gpe_native_fwd_rpaths_get_reply_t_handler
212   (vl_api_gpe_native_fwd_rpaths_get_reply_t * mp)
213 {
214   vat_main_t *vam = &vat_main;
215   u32 i, n;
216   int retval = clib_net_to_host_u32 (mp->retval);
217   vl_api_gpe_native_fwd_rpath_t *r;
218
219   if (retval)
220     goto end;
221
222   n = clib_net_to_host_u32 (mp->count);
223
224   for (i = 0; i < n; i++)
225     {
226       r = &mp->entries[i];
227       print (vam->ofp, "fib_index: %d sw_if_index %d nh %U",
228              clib_net_to_host_u32 (r->fib_index),
229              clib_net_to_host_u32 (r->nh_sw_if_index),
230              r->nh_addr.af ? format_ip6_address : format_ip4_address,
231              r->nh_addr.un);
232     }
233
234 end:
235   vam->retval = retval;
236   vam->result_ready = 1;
237 }
238
239 static void
240   vl_api_gpe_fwd_entry_vnis_get_reply_t_handler
241   (vl_api_gpe_fwd_entry_vnis_get_reply_t * mp)
242 {
243   vat_main_t *vam = &vat_main;
244   u32 i, n;
245   int retval = clib_net_to_host_u32 (mp->retval);
246
247   if (retval)
248     goto end;
249
250   n = clib_net_to_host_u32 (mp->count);
251
252   for (i = 0; i < n; i++)
253     print (vam->ofp, "%d", clib_net_to_host_u32 (mp->vnis[i]));
254
255 end:
256   vam->retval = retval;
257   vam->result_ready = 1;
258 }
259
260
261 /* *INDENT-OFF* */
262 /** Used for parsing LISP eids */
263 typedef CLIB_PACKED(struct{
264   union {
265           ip46_address_t ip;
266           mac_address_t mac;
267           lisp_nsh_api_t nsh;
268   } addr;
269   u32 len;       /**< prefix length if IP */
270   u8 type;      /**< type of eid */
271 }) lisp_eid_vat_t;
272 /* *INDENT-ON* */
273
274 static uword
275 unformat_lisp_eid_vat (unformat_input_t * input, va_list * args)
276 {
277   lisp_eid_vat_t *a = va_arg (*args, lisp_eid_vat_t *);
278
279   clib_memset (a, 0, sizeof (a[0]));
280
281   if (unformat (input, "%U/%d", unformat_ip46_address, a->addr.ip, &a->len))
282     {
283       a->type = 0;              /* ip prefix type */
284     }
285   else if (unformat (input, "%U", unformat_ethernet_address, &a->addr.mac))
286     {
287       a->type = 1;              /* mac type */
288     }
289   else if (unformat (input, "%U", unformat_nsh_address, a->addr.nsh))
290     {
291       a->type = 2;              /* NSH type */
292       a->addr.nsh.spi = clib_host_to_net_u32 (a->addr.nsh.spi);
293     }
294   else
295     {
296       return 0;
297     }
298
299   if (a->type == 0)
300     {
301       if (ip46_address_is_ip4 (&a->addr.ip))
302         return a->len > 32 ? 1 : 0;
303       else
304         return a->len > 128 ? 1 : 0;
305     }
306
307   return 1;
308 }
309
310 static void
311 lisp_eid_put_vat (vl_api_eid_t * eid, const lisp_eid_vat_t * vat_eid)
312 {
313   eid->type = vat_eid->type;
314   switch (eid->type)
315     {
316     case EID_TYPE_API_PREFIX:
317       if (ip46_address_is_ip4 (&vat_eid->addr.ip))
318         {
319           clib_memcpy (&eid->address.prefix.address.un.ip4,
320                        &vat_eid->addr.ip.ip4, 4);
321           eid->address.prefix.address.af = ADDRESS_IP4;
322           eid->address.prefix.len = vat_eid->len;
323         }
324       else
325         {
326           clib_memcpy (&eid->address.prefix.address.un.ip6,
327                        &vat_eid->addr.ip.ip6, 16);
328           eid->address.prefix.address.af = ADDRESS_IP6;
329           eid->address.prefix.len = vat_eid->len;
330         }
331       return;
332     case EID_TYPE_API_MAC:
333       clib_memcpy (&eid->address.mac, &vat_eid->addr.mac,
334                    sizeof (eid->address.mac));
335       return;
336     case EID_TYPE_API_NSH:
337       clib_memcpy (&eid->address.nsh, &vat_eid->addr.nsh,
338                    sizeof (eid->address.nsh));
339       return;
340     default:
341       ASSERT (0);
342       return;
343     }
344 }
345
346 static int
347 api_gpe_add_del_fwd_entry (vat_main_t * vam)
348 {
349   u32 dp_table = 0, vni = 0;;
350   unformat_input_t *input = vam->input;
351   vl_api_gpe_add_del_fwd_entry_t *mp;
352   u8 is_add = 1;
353   lisp_eid_vat_t _rmt_eid, *rmt_eid = &_rmt_eid;
354   lisp_eid_vat_t _lcl_eid, *lcl_eid = &_lcl_eid;
355   u8 rmt_eid_set = 0, lcl_eid_set = 0;
356   u32 action = ~0, w;
357   ip4_address_t rmt_rloc4, lcl_rloc4;
358   ip6_address_t rmt_rloc6, lcl_rloc6;
359   vl_api_gpe_locator_t *rmt_locs = 0, *lcl_locs = 0, rloc, *curr_rloc = 0;
360   int ret;
361
362   clib_memset (&rloc, 0, sizeof (rloc));
363
364   /* Parse args required to build the message */
365   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
366     {
367       if (unformat (input, "del"))
368         is_add = 0;
369       else if (unformat (input, "add"))
370         is_add = 1;
371       else if (unformat (input, "reid %U", unformat_lisp_eid_vat, rmt_eid))
372         {
373           rmt_eid_set = 1;
374         }
375       else if (unformat (input, "leid %U", unformat_lisp_eid_vat, lcl_eid))
376         {
377           lcl_eid_set = 1;
378         }
379       else if (unformat (input, "vrf %d", &dp_table))
380         ;
381       else if (unformat (input, "bd %d", &dp_table))
382         ;
383       else if (unformat (input, "vni %d", &vni))
384         ;
385       else if (unformat (input, "w %d", &w))
386         {
387           if (!curr_rloc)
388             {
389               errmsg ("No RLOC configured for setting priority/weight!");
390               return -99;
391             }
392           curr_rloc->weight = w;
393         }
394       else if (unformat (input, "loc-pair %U %U", unformat_ip4_address,
395                          &lcl_rloc4, unformat_ip4_address, &rmt_rloc4))
396         {
397           rloc.addr.af = 0;
398           clib_memcpy (&rloc.addr.un.ip4, &lcl_rloc4, sizeof (lcl_rloc4));
399           rloc.weight = 0;
400           vec_add1 (lcl_locs, rloc);
401
402           clib_memcpy (&rloc.addr.un.ip4, &rmt_rloc4, sizeof (rmt_rloc4));
403           vec_add1 (rmt_locs, rloc);
404           /* weight saved in rmt loc */
405           curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1];
406         }
407       else if (unformat (input, "loc-pair %U %U", unformat_ip6_address,
408                          &lcl_rloc6, unformat_ip6_address, &rmt_rloc6))
409         {
410           rloc.addr.af = 1;
411           clib_memcpy (&rloc.addr.un.ip6, &lcl_rloc6, sizeof (lcl_rloc6));
412           rloc.weight = 0;
413           vec_add1 (lcl_locs, rloc);
414
415           clib_memcpy (&rloc.addr.un.ip6, &rmt_rloc6, sizeof (rmt_rloc6));
416           vec_add1 (rmt_locs, rloc);
417           /* weight saved in rmt loc */
418           curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1];
419         }
420       else if (unformat (input, "action %d", &action))
421         {
422           ;
423         }
424       else
425         {
426           clib_warning ("parse error '%U'", format_unformat_error, input);
427           return -99;
428         }
429     }
430
431   if (!rmt_eid_set)
432     {
433       errmsg ("remote eid addresses not set");
434       return -99;
435     }
436
437   if (lcl_eid_set && rmt_eid->type != lcl_eid->type)
438     {
439       errmsg ("eid types don't match");
440       return -99;
441     }
442
443   if (0 == rmt_locs && (u32) ~ 0 == action)
444     {
445       errmsg ("action not set for negative mapping");
446       return -99;
447     }
448
449   /* Construct the API message */
450   M2 (GPE_ADD_DEL_FWD_ENTRY, mp,
451       sizeof (vl_api_gpe_locator_t) * vec_len (rmt_locs) * 2);
452
453   mp->is_add = is_add;
454   lisp_eid_put_vat (&mp->rmt_eid, rmt_eid);
455   lisp_eid_put_vat (&mp->lcl_eid, lcl_eid);
456   mp->dp_table = clib_host_to_net_u32 (dp_table);
457   mp->vni = clib_host_to_net_u32 (vni);
458   mp->action = action;
459
460   if (0 != rmt_locs && 0 != lcl_locs)
461     {
462       mp->loc_num = clib_host_to_net_u32 (vec_len (rmt_locs) * 2);
463       clib_memcpy (mp->locs, lcl_locs,
464                    (sizeof (vl_api_gpe_locator_t) * vec_len (lcl_locs)));
465
466       u32 offset = sizeof (vl_api_gpe_locator_t) * vec_len (lcl_locs);
467       clib_memcpy (((u8 *) mp->locs) + offset, rmt_locs,
468                    (sizeof (vl_api_gpe_locator_t) * vec_len (rmt_locs)));
469     }
470   vec_free (lcl_locs);
471   vec_free (rmt_locs);
472
473   /* send it... */
474   S (mp);
475
476   /* Wait for a reply... */
477   W (ret);
478   return ret;
479 }
480
481 static int
482 api_gpe_enable_disable (vat_main_t * vam)
483 {
484   unformat_input_t *input = vam->input;
485   vl_api_gpe_enable_disable_t *mp;
486   u8 is_set = 0;
487   u8 is_enable = 1;
488   int ret;
489
490   /* Parse args required to build the message */
491   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
492     {
493       if (unformat (input, "enable"))
494         {
495           is_set = 1;
496           is_enable = 1;
497         }
498       else if (unformat (input, "disable"))
499         {
500           is_set = 1;
501           is_enable = 0;
502         }
503       else
504         break;
505     }
506
507   if (is_set == 0)
508     {
509       errmsg ("Value not set");
510       return -99;
511     }
512
513   /* Construct the API message */
514   M (GPE_ENABLE_DISABLE, mp);
515
516   mp->is_enable = is_enable;
517
518   /* send it... */
519   S (mp);
520
521   /* Wait for a reply... */
522   W (ret);
523   return ret;
524 }
525
526 uword
527 unformat_gpe_encap_mode (unformat_input_t * input, va_list * args)
528 {
529   u32 *mode = va_arg (*args, u32 *);
530
531   if (unformat (input, "lisp"))
532     *mode = 0;
533   else if (unformat (input, "vxlan"))
534     *mode = 1;
535   else
536     return 0;
537
538   return 1;
539 }
540
541 static int
542 api_gpe_get_encap_mode (vat_main_t * vam)
543 {
544   vl_api_gpe_get_encap_mode_t *mp;
545   int ret;
546
547   /* Construct the API message */
548   M (GPE_GET_ENCAP_MODE, mp);
549
550   /* send it... */
551   S (mp);
552
553   /* Wait for a reply... */
554   W (ret);
555   return ret;
556 }
557
558 static int
559 api_gpe_set_encap_mode (vat_main_t * vam)
560 {
561   unformat_input_t *input = vam->input;
562   vl_api_gpe_set_encap_mode_t *mp;
563   int ret;
564   u32 mode = 0;
565
566   /* Parse args required to build the message */
567   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
568     {
569       if (unformat (input, "%U", unformat_gpe_encap_mode, &mode))
570         ;
571       else
572         break;
573     }
574
575   /* Construct the API message */
576   M (GPE_SET_ENCAP_MODE, mp);
577
578   mp->is_vxlan = mode;
579
580   /* send it... */
581   S (mp);
582
583   /* Wait for a reply... */
584   W (ret);
585   return ret;
586 }
587
588 static int
589 api_gpe_add_del_iface (vat_main_t * vam)
590 {
591   unformat_input_t *input = vam->input;
592   vl_api_gpe_add_del_iface_t *mp;
593   u8 action_set = 0, is_add = 1, is_l2 = 0, dp_table_set = 0, vni_set = 0;
594   u32 dp_table = 0, vni = 0;
595   int ret;
596
597   /* Parse args required to build the message */
598   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
599     {
600       if (unformat (input, "up"))
601         {
602           action_set = 1;
603           is_add = 1;
604         }
605       else if (unformat (input, "down"))
606         {
607           action_set = 1;
608           is_add = 0;
609         }
610       else if (unformat (input, "table_id %d", &dp_table))
611         {
612           dp_table_set = 1;
613         }
614       else if (unformat (input, "bd_id %d", &dp_table))
615         {
616           dp_table_set = 1;
617           is_l2 = 1;
618         }
619       else if (unformat (input, "vni %d", &vni))
620         {
621           vni_set = 1;
622         }
623       else
624         break;
625     }
626
627   if (action_set == 0)
628     {
629       errmsg ("Action not set");
630       return -99;
631     }
632   if (dp_table_set == 0 || vni_set == 0)
633     {
634       errmsg ("vni and dp_table must be set");
635       return -99;
636     }
637
638   /* Construct the API message */
639   M (GPE_ADD_DEL_IFACE, mp);
640
641   mp->is_add = is_add;
642   mp->dp_table = clib_host_to_net_u32 (dp_table);
643   mp->is_l2 = is_l2;
644   mp->vni = clib_host_to_net_u32 (vni);
645
646   /* send it... */
647   S (mp);
648
649   /* Wait for a reply... */
650   W (ret);
651   return ret;
652 }
653
654 static int
655 api_gpe_fwd_entries_get (vat_main_t * vam)
656 {
657   unformat_input_t *i = vam->input;
658   vl_api_gpe_fwd_entries_get_t *mp;
659   u8 vni_set = 0;
660   u32 vni = ~0;
661   int ret;
662
663   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
664     {
665       if (unformat (i, "vni %d", &vni))
666         {
667           vni_set = 1;
668         }
669       else
670         {
671           errmsg ("parse error '%U'", format_unformat_error, i);
672           return -99;
673         }
674     }
675
676   if (!vni_set)
677     {
678       errmsg ("vni not set!");
679       return -99;
680     }
681
682   if (!vam->json_output)
683     {
684       print (vam->ofp, "%10s %10s %s %40s", "fwd_index", "dp_table",
685              "leid", "reid");
686     }
687
688   M (GPE_FWD_ENTRIES_GET, mp);
689   mp->vni = clib_host_to_net_u32 (vni);
690
691   /* send it... */
692   S (mp);
693
694   /* Wait for a reply... */
695   W (ret);
696   return ret;
697 }
698
699 static int
700 api_gpe_native_fwd_rpaths_get (vat_main_t * vam)
701 {
702   unformat_input_t *i = vam->input;
703   vl_api_gpe_native_fwd_rpaths_get_t *mp;
704   int ret;
705   u8 ip_family_set = 0, is_ip4 = 1;
706
707   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
708     {
709       if (unformat (i, "ip4"))
710         {
711           ip_family_set = 1;
712           is_ip4 = 1;
713         }
714       else if (unformat (i, "ip6"))
715         {
716           ip_family_set = 1;
717           is_ip4 = 0;
718         }
719       else
720         {
721           errmsg ("parse error '%U'", format_unformat_error, i);
722           return -99;
723         }
724     }
725
726   if (!ip_family_set)
727     {
728       errmsg ("ip family not set!");
729       return -99;
730     }
731
732   M (GPE_NATIVE_FWD_RPATHS_GET, mp);
733   mp->is_ip4 = is_ip4;
734
735   /* send it... */
736   S (mp);
737
738   /* Wait for a reply... */
739   W (ret);
740   return ret;
741 }
742
743 static int
744 api_gpe_fwd_entry_vnis_get (vat_main_t * vam)
745 {
746   vl_api_gpe_fwd_entry_vnis_get_t *mp;
747   int ret;
748
749   if (!vam->json_output)
750     {
751       print (vam->ofp, "VNIs");
752     }
753
754   M (GPE_FWD_ENTRY_VNIS_GET, mp);
755
756   /* send it... */
757   S (mp);
758
759   /* Wait for a reply... */
760   W (ret);
761   return ret;
762 }
763
764 static int
765 api_gpe_add_del_native_fwd_rpath (vat_main_t * vam)
766 {
767   unformat_input_t *i = vam->input;
768   vl_api_gpe_add_del_native_fwd_rpath_t *mp;
769   int ret = 0;
770   u8 is_add = 1, ip_set = 0, is_ip4 = 1;
771   struct in_addr ip4;
772   struct in6_addr ip6;
773   u32 table_id = 0, nh_sw_if_index = ~0;
774
775   clib_memset (&ip4, 0, sizeof (ip4));
776   clib_memset (&ip6, 0, sizeof (ip6));
777
778   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
779     {
780       if (unformat (i, "del"))
781         is_add = 0;
782       else if (unformat (i, "via %U %U", unformat_ip4_address, &ip4,
783                          unformat_sw_if_index, vam, &nh_sw_if_index))
784         {
785           ip_set = 1;
786           is_ip4 = 1;
787         }
788       else if (unformat (i, "via %U %U", unformat_ip6_address, &ip6,
789                          unformat_sw_if_index, vam, &nh_sw_if_index))
790         {
791           ip_set = 1;
792           is_ip4 = 0;
793         }
794       else if (unformat (i, "via %U", unformat_ip4_address, &ip4))
795         {
796           ip_set = 1;
797           is_ip4 = 1;
798           nh_sw_if_index = ~0;
799         }
800       else if (unformat (i, "via %U", unformat_ip6_address, &ip6))
801         {
802           ip_set = 1;
803           is_ip4 = 0;
804           nh_sw_if_index = ~0;
805         }
806       else if (unformat (i, "table %d", &table_id))
807         ;
808       else
809         {
810           errmsg ("parse error '%U'", format_unformat_error, i);
811           return -99;
812         }
813     }
814
815   if (!ip_set)
816     {
817       errmsg ("nh addr not set!");
818       return -99;
819     }
820
821   M (GPE_ADD_DEL_NATIVE_FWD_RPATH, mp);
822   mp->is_add = is_add;
823   mp->table_id = clib_host_to_net_u32 (table_id);
824   mp->nh_sw_if_index = clib_host_to_net_u32 (nh_sw_if_index);
825   mp->nh_addr.af = is_ip4 ? 0 : 1;
826   if (is_ip4)
827     clib_memcpy (mp->nh_addr.un.ip4, &ip4, sizeof (ip4));
828   else
829     clib_memcpy (mp->nh_addr.un.ip6, &ip6, sizeof (ip6));
830
831   /* send it... */
832   S (mp);
833
834   /* Wait for a reply... */
835   W (ret);
836   return ret;
837 }
838
839 static int
840 api_gpe_fwd_entry_path_dump (vat_main_t * vam)
841 {
842   vl_api_gpe_fwd_entry_path_dump_t *mp;
843   vl_api_control_ping_t *mp_ping;
844   unformat_input_t *i = vam->input;
845   u32 fwd_entry_index = ~0;
846   int ret;
847
848   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
849     {
850       if (unformat (i, "index %d", &fwd_entry_index))
851         ;
852       else
853         break;
854     }
855
856   if (~0 == fwd_entry_index)
857     {
858       errmsg ("no index specified!");
859       return -99;
860     }
861
862   if (!vam->json_output)
863     {
864       print (vam->ofp, "first line");
865     }
866
867   M (GPE_FWD_ENTRY_PATH_DUMP, mp);
868
869   /* send it... */
870   S (mp);
871   /* Use a control ping for synchronization */
872   LISP_PING (&lisp_gpe_test_main, mp_ping);
873   S (mp_ping);
874
875   /* Wait for a reply... */
876   W (ret);
877   return ret;
878 }
879
880 #define vat_plugin_register vat_plugin_register_gpe
881 #include <lisp/lisp-gpe/lisp_gpe.api_test.c>
882
883 /*
884  * fd.io coding-style-patch-verification: ON
885  *
886  * Local Variables:
887  * eval: (c-set-style "gnu")
888  * End:
889  */