summaryrefslogtreecommitdiffstats
path: root/src/plugins/lisp/lisp-gpe/lisp_gpe_test.c
blob: 2f1a4187551096a35cd78979dbfceaade5f14d0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
4
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.2" width="163mm" height="127mm" viewBox="0 0 16300 12700" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
 <defs class="ClipPathGroup">
  <clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
   <rect x="0" y="0" width="16300" height="12700"/>
  </clipPath>
  <clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
   <rect x="16" y="12" width="16268" height="12675"/>
  </clipPath>
 </defs>
 <defs>
  <font id="EmbeddedFont_1" horiz-adv-x="2048">
   <font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1852" descent="423"/>
   <missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
   <glyph unicode="x" horiz-adv-x="1006" d="M 801,0 L 510,444 217,0 23,0 408,556 41,1082 240,1082 510,661 778,1082 979,1082 612,558 1002,0 801,0 Z"/>
   <glyph unicode="w" horiz-adv-x="1509" d="M 1174,0 L 965,0 776,765 740,934 C 734,904 725,861 712,805 699,748 631,480 508,0 L 300,0 -3,1082 175,1082 358,347 C 363,331 377,265 401,149 L 418,223 644,1082 837,1082 1026,339 1072,149 1103,288 1308,1082 1484,1082 1174,0 Z"/>
   <glyph unicode="u" horiz-adv-x="874" d="M 314,1082 L 314,396 C 314,325 321,269 335,230 349,191 371,162 402,145 433,128 478,119 537,119 624,119 692,149 742,208 792,267 817,350 817,455 L 817,1082 997,1082 997,231 C 997,105 999,28 1003,0 L 833,0 C 832,3 832,12 831,27 830,42 830,59 829,78 828,97 826,132 825,185 L 822,185 C 781,110 733,58 679,27 624,-4 557,-20 476,-20 357,-20 271,10 216,69 161,128 133,225 133,361 L 133,1082 314,1082 Z"/>
   <glyph unicode="t" horiz-adv-x="531" d="M 554,8 C 495,-8 434,-16 372,-16 228,-16 156,66 156,229 L 156,951 31,951 31,1082 163,1082 216,1324 336,1324 336,1082 536,1082 536,951 336,951 336,268 C 336,216 345,180 362,159 379,138 408,127 450,127 474,127 509,132 554,141 L 554,8 Z"/>
   <glyph unicode="r" horiz-adv-x="530" d="M 142,0 L 142,830 C 142,906 140,990 136,1082 L 306,1082 C 311,959 314,886 314,861 L 318,861 C 347,954 380,1017 417,1051 454,1085 507,1102 575,1102 599,1102 623,1099 648,1092 L 648,927 C 624,934 592,937 552,937 477,937 420,905 381,841 342,776 322,684 322,564 L 322,0 142,0 Z"/>
   <glyph unicode="q" horiz-adv-x="927" d="M 484,-20 C 347,-20 246,26 182,119 118,212 86,351 86,536 86,913 219,1102 484,1102 566,1102 634,1088 687,1059 740,1030 785,981 821,914 L 823,914 C 823,934 824,969 827,1018 830,1067 832,1093 835,1096 L 1008,1096 C 1003,1057 1001,958 1001,801 L 1001,-425 821,-425 821,14 825,178 823,178 C 787,107 743,56 690,26 637,-5 569,-20 484,-20 Z M 821,554 C 821,695 798,799 752,867 706,935 633,969 532,969 441,969 375,935 335,867 295,799 275,691 275,542 275,391 295,282 336,217 376,152 441,119 530,119 632,119 706,155 752,228 798,301 821,409 821,554 Z"/>
   <glyph unicode="p" horiz-adv-x="953" d="M 1053,546 C 1053,169 920,-20 655,-20 488,-20 376,43 319,168 L 314,168 C 317,163 318,106 318,-2 L 318,-425 138,-425 138,861 C 138,972 136,1046 132,1082 L 306,1082 C 307,1079 308,1070 309,1054 310,1037 312,1012 314,978 315,944 316,921 316,908 L 320,908 C 352,975 394,1024 447,1055 500,1086 569,1101 655,1101 788,1101 888,1056 954,967 1020,878 1053,737 1053,546 Z M 864,542 C 864,693 844,800 803,865 762,930 698,962 609,962 538,962 482,947 442,917 401,887 371,840 350,777 329,713 318,630 318,528 318,386 341,281 386,214 431,147 505,113 607,113 696,113 762,146 803,212 844,277 864,387 864,542 Z"/>
   <glyph unicode="o" horiz-adv-x="980" d="M 1053,542 C 1053,353 1011,212 928,119 845,26 724,-20 565,-20 407,-20 288,28 207,125 126,221 86,360 86,542 86,915 248,1102 571,1102 736,1102 858,1057 936,966 1014,875 1053,733 1053,542 Z M 864,542 C 864,691 842,800 798,868 753,935 679,969 574,969 469,969 393,935 346,866 299,797 2
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vat/vat.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vppinfra/error.h>

#include <vnet/ip/ip_format_fns.h>
#include <vnet/ethernet/ethernet_format_fns.h>
#include <vnet/ethernet/mac_address.h>
#include <lisp/lisp-cp/lisp_types.h>

/* define message IDs */
#include <lisp/lisp-gpe/lisp_gpe.api_enum.h>
#include <lisp/lisp-gpe/lisp_gpe.api_types.h>
#include <vlibmemory/vlib.api_types.h>

typedef struct
{
  /* API message ID base */
  u16 msg_id_base;
  vat_main_t *vat_main;
  u32 ping_id;
} lisp_gpe_test_main_t;

lisp_gpe_test_main_t lisp_gpe_test_main;

#define __plugin_msg_base lisp_gpe_test_main.msg_id_base
#include <vlibapi/vat_helper_macros.h>

#define FINISH                                                                \
  vec_add1 (s, 0);                                                            \
  vlib_cli_output (handle, (char *) s);                                       \
  vec_free (s);                                                               \
  return handle;

#define LISP_PING(_lm, mp_ping)                                         \
  if (!(_lm)->ping_id)                                                  \
    (_lm)->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); \
  mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));          \
  mp_ping->_vl_msg_id = htons ((_lm)->ping_id);                         \
  mp_ping->client_index = vam->my_client_index;                         \
  fformat (vam->ofp, "Sending ping id=%d\n", (_lm)->ping_id);           \
  vam->result_ready = 0;                                                \

typedef struct
{
  u32 spi;
  u8 si;
} __attribute__ ((__packed__)) lisp_nsh_api_t;

static uword
unformat_nsh_address (unformat_input_t * input, va_list * args)
{
  lisp_nsh_api_t *nsh = va_arg (*args, lisp_nsh_api_t *);
  return unformat (input, "SPI:%d SI:%d", &nsh->spi, &nsh->si);
}

static u8 *
format_nsh_address_vat (u8 * s, va_list * args)
{
  nsh_t *a = va_arg (*args, nsh_t *);
  return format (s, "SPI:%d SI:%d", clib_net_to_host_u32 (a->spi), a->si);
}

static u8 *
format_lisp_flat_eid (u8 * s, va_list * args)
{
  vl_api_eid_t *eid = va_arg (*args, vl_api_eid_t *);

  switch (eid->type)
    {
    case EID_TYPE_API_PREFIX:
      if (eid->address.prefix.address.af)
	return format (s, "%U/%d", format_ip6_address,
		       eid->address.prefix.address.un.ip6,
		       eid->address.prefix.len);
      return format (s, "%U/%d", format_ip4_address,
		     eid->address.prefix.address.un.ip4,
		     eid->address.prefix.len);
    case EID_TYPE_API_MAC:
      return format (s, "%U", format_ethernet_address, eid->address.mac);
    case EID_TYPE_API_NSH:
      return format (s, "%U", format_nsh_address_vat, eid->address.nsh);
    }
  return 0;
}

static void vl_api_gpe_add_del_fwd_entry_reply_t_handler
  (vl_api_gpe_add_del_fwd_entry_reply_t * mp)
{
  vat_main_t *vam = &vat_main;
  i32 retval = ntohl (mp->retval);
  if (vam->async_mode)
    {
      vam->async_errors += (retval < 0);
    }
  else
    {
      vam->retval = retval;
      vam->result_ready = 1;
    }
}

static void
api_gpe_fwd_entry_net_to_host (vl_api_gpe_fwd_entry_t * e)
{
  e->dp_table = clib_net_to_host_u32 (e->dp_table);
  e->fwd_entry_index = clib_net_to_host_u32 (e->fwd_entry_index);
  e->vni = clib_net_to_host_u32 (e->vni);
}

static void
  gpe_fwd_entries_get_reply_t_net_to_host
  (vl_api_gpe_fwd_entries_get_reply_t * mp)
{
  u32 i;

  mp->count = clib_net_to_host_u32 (mp->count);
  for (i = 0; i < mp->count; i++)
    {
      api_gpe_fwd_entry_net_to_host (&mp->entries[i]);
    }
}

static u8 *
format_gpe_encap_mode (u8 * s, va_list * args)
{
  u32 mode = va_arg (*args, u32);

  switch (mode)
    {
    case 0:
      return format (s, "lisp");
    case 1:
      return format (s, "vxlan");
    }
  return 0;
}

static void
  vl_api_gpe_get_encap_mode_reply_t_handler
  (vl_api_gpe_get_encap_mode_reply_t * mp)
{
  vat_main_t *vam = &vat_main;

  print (vam->ofp, "gpe mode: %U", format_gpe_encap_mode, mp->encap_mode);
  vam->retval = ntohl (mp->retval);
  vam->result_ready = 1;
}

static void
  vl_api_gpe_fwd_entry_path_details_t_handler
  (vl_api_gpe_fwd_entry_path_details_t * mp)
{
  vat_main_t *vam = &vat_main;
  u8 *(*format_ip_address_fcn) (u8 *, va_list *) = 0;

  if (mp->lcl_loc.addr.af)
    format_ip_address_fcn = format_ip6_address;
  else
    format_ip_address_fcn = format_ip4_address;

  print (vam->ofp, "w:%d %30U %30U", mp->rmt_loc.weight,
	 format_ip_address_fcn, &mp->lcl_loc.addr.un,
	 format_ip_address_fcn, &mp->rmt_loc.addr.un);
}

static void
  vl_api_gpe_fwd_entries_get_reply_t_handler
  (vl_api_gpe_fwd_entries_get_reply_t * mp)
{
  vat_main_t *vam = &vat_main;
  u32 i;
  int retval = clib_net_to_host_u32 (mp->retval);
  vl_api_gpe_fwd_entry_t *e;

  if (retval)
    goto end;

  gpe_fwd_entries_get_reply_t_net_to_host (mp);

  for (i = 0; i < mp->count; i++)
    {
      e = &mp->entries[i];
      print (vam->ofp, "%10d %10d %U %40U", e->fwd_entry_index, e->dp_table,
	     format_lisp_flat_eid, e->leid, format_lisp_flat_eid, e->reid);
    }

end:
  vam->retval = retval;
  vam->result_ready = 1;
}

static void
  vl_api_gpe_native_fwd_rpaths_get_reply_t_handler
  (vl_api_gpe_native_fwd_rpaths_get_reply_t * mp)
{
  vat_main_t *vam = &vat_main;
  u32 i, n;
  int retval = clib_net_to_host_u32 (mp->retval);
  vl_api_gpe_native_fwd_rpath_t *r;

  if (retval)
    goto end;

  n = clib_net_to_host_u32 (mp->count);

  for (i = 0; i < n; i++)
    {
      r = &mp->entries[i];
      print (vam->ofp, "fib_index: %d sw_if_index %d nh %U",
	     clib_net_to_host_u32 (r->fib_index),
	     clib_net_to_host_u32 (r->nh_sw_if_index),
	     r->nh_addr.af ? format_ip6_address : format_ip4_address,
	     r->nh_addr.un);
    }

end:
  vam->retval = retval;
  vam->result_ready = 1;
}

static void
  vl_api_gpe_fwd_entry_vnis_get_reply_t_handler
  (vl_api_gpe_fwd_entry_vnis_get_reply_t * mp)
{
  vat_main_t *vam = &vat_main;
  u32 i, n;
  int retval = clib_net_to_host_u32 (mp->retval);

  if (retval)
    goto end;

  n = clib_net_to_host_u32 (mp->count);

  for (i = 0; i < n; i++)
    print (vam->ofp, "%d", clib_net_to_host_u32 (mp->vnis[i]));

end:
  vam->retval = retval;
  vam->result_ready = 1;
}


/* *INDENT-OFF* */
/** Used for parsing LISP eids */
typedef CLIB_PACKED(struct{
  union {
          ip46_address_t ip;
          mac_address_t mac;
          lisp_nsh_api_t nsh;
  } addr;
  u32 len;       /**< prefix length if IP */
  u8 type;      /**< type of eid */
}) lisp_eid_vat_t;
/* *INDENT-ON* */

static uword
unformat_lisp_eid_vat (unformat_input_t * input, va_list * args)
{
  lisp_eid_vat_t *a = va_arg (*args, lisp_eid_vat_t *);

  clib_memset (a, 0, sizeof (a[0]));

  if (unformat (input, "%U/%d", unformat_ip46_address, a->addr.ip, &a->len))
    {
      a->type = 0;		/* ip prefix type */
    }
  else if (unformat (input, "%U", unformat_ethernet_address, &a->addr.mac))
    {
      a->type = 1;		/* mac type */
    }
  else if (unformat (input, "%U", unformat_nsh_address, a->addr.nsh))
    {
      a->type = 2;		/* NSH type */
      a->addr.nsh.spi = clib_host_to_net_u32 (a->addr.nsh.spi);
    }
  else
    {
      return 0;
    }

  if (a->type == 0)
    {
      if (ip46_address_is_ip4 (&a->addr.ip))
	return a->len > 32 ? 1 : 0;
      else
	return a->len > 128 ? 1 : 0;
    }

  return 1;
}

static void
lisp_eid_put_vat (vl_api_eid_t * eid, const lisp_eid_vat_t * vat_eid)
{
  eid->type = vat_eid->type;
  switch (eid->type)
    {
    case EID_TYPE_API_PREFIX:
      if (ip46_address_is_ip4 (&vat_eid->addr.ip))
	{
	  clib_memcpy (&eid->address.prefix.address.un.ip4,
		       &vat_eid->addr.ip.ip4, 4);
	  eid->address.prefix.address.af = ADDRESS_IP4;
	  eid->address.prefix.len = vat_eid->len;
	}
      else
	{
	  clib_memcpy (&eid->address.prefix.address.un.ip6,
		       &vat_eid->addr.ip.ip6, 16);
	  eid->address.prefix.address.af = ADDRESS_IP6;
	  eid->address.prefix.len = vat_eid->len;
	}
      return;
    case EID_TYPE_API_MAC:
      clib_memcpy (&eid->address.mac, &vat_eid->addr.mac,
		   sizeof (eid->address.mac));
      return;
    case EID_TYPE_API_NSH:
      clib_memcpy (&eid->address.nsh, &vat_eid->addr.nsh,
		   sizeof (eid->address.nsh));
      return;
    default:
      ASSERT (0);
      return;
    }
}

static int
api_gpe_add_del_fwd_entry (vat_main_t * vam)
{
  u32 dp_table = 0, vni = 0;;
  unformat_input_t *input = vam->input;
  vl_api_gpe_add_del_fwd_entry_t *mp;
  u8 is_add = 1;
  lisp_eid_vat_t _rmt_eid, *rmt_eid = &_rmt_eid;
  lisp_eid_vat_t _lcl_eid, *lcl_eid = &_lcl_eid;
  u8 rmt_eid_set = 0, lcl_eid_set = 0;
  u32 action = ~0, w;
  ip4_address_t rmt_rloc4, lcl_rloc4;
  ip6_address_t rmt_rloc6, lcl_rloc6;
  vl_api_gpe_locator_t *rmt_locs = 0, *lcl_locs = 0, rloc, *curr_rloc = 0;
  int ret;

  clib_memset (&rloc, 0, sizeof (rloc));

  /* Parse args required to build the message */
  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (input, "del"))
	is_add = 0;
      else if (unformat (input, "add"))
	is_add = 1;
      else if (unformat (input, "reid %U", unformat_lisp_eid_vat, rmt_eid))
	{
	  rmt_eid_set = 1;
	}
      else if (unformat (input, "leid %U", unformat_lisp_eid_vat, lcl_eid))
	{
	  lcl_eid_set = 1;
	}
      else if (unformat (input, "vrf %d", &dp_table))
	;
      else if (unformat (input, "bd %d", &dp_table))
	;
      else if (unformat (input, "vni %d", &vni))
	;
      else if (unformat (input, "w %d", &w))
	{
	  if (!curr_rloc)
	    {
	      errmsg ("No RLOC configured for setting priority/weight!");
	      return -99;
	    }
	  curr_rloc->weight = w;
	}
      else if (unformat (input, "loc-pair %U %U", unformat_ip4_address,
			 &lcl_rloc4, unformat_ip4_address, &rmt_rloc4))
	{
	  rloc.addr.af = 0;
	  clib_memcpy (&rloc.addr.un.ip4, &lcl_rloc4, sizeof (lcl_rloc4));
	  rloc.weight = 0;
	  vec_add1 (lcl_locs, rloc);

	  clib_memcpy (&rloc.addr.un.ip4, &rmt_rloc4, sizeof (rmt_rloc4));
	  vec_add1 (rmt_locs, rloc);
	  /* weight saved in rmt loc */
	  curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1];
	}
      else if (unformat (input, "loc-pair %U %U", unformat_ip6_address,
			 &lcl_rloc6, unformat_ip6_address, &rmt_rloc6))
	{
	  rloc.addr.af = 1;
	  clib_memcpy (&rloc.addr.un.ip6, &lcl_rloc6, sizeof (lcl_rloc6));
	  rloc.weight = 0;
	  vec_add1 (lcl_locs, rloc);

	  clib_memcpy (&rloc.addr.un.ip6, &rmt_rloc6, sizeof (rmt_rloc6));
	  vec_add1 (rmt_locs, rloc);
	  /* weight saved in rmt loc */
	  curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1];
	}
      else if (unformat (input, "action %d", &action))
	{
	  ;
	}
      else
	{
	  clib_warning ("parse error '%U'", format_unformat_error, input);
	  return -99;
	}
    }

  if (!rmt_eid_set)
    {
      errmsg ("remote eid addresses not set");
      return -99;
    }

  if (lcl_eid_set && rmt_eid->type != lcl_eid->type)
    {
      errmsg ("eid types don't match");
      return -99;
    }

  if (0 == rmt_locs && (u32) ~ 0 == action)
    {
      errmsg ("action not set for negative mapping");
      return -99;
    }

  /* Construct the API message */
  M2 (GPE_ADD_DEL_FWD_ENTRY, mp,
      sizeof (vl_api_gpe_locator_t) * vec_len (rmt_locs) * 2);

  mp->is_add = is_add;
  lisp_eid_put_vat (&mp->rmt_eid, rmt_eid);
  lisp_eid_put_vat (&mp->lcl_eid, lcl_eid);
  mp->dp_table = clib_host_to_net_u32 (dp_table);
  mp->vni = clib_host_to_net_u32 (vni);
  mp->action = action;

  if (0 != rmt_locs && 0 != lcl_locs)
    {
      mp->loc_num = clib_host_to_net_u32 (vec_len (rmt_locs) * 2);
      clib_memcpy (mp->locs, lcl_locs,
		   (sizeof (vl_api_gpe_locator_t) * vec_len (lcl_locs)));

      u32 offset = sizeof (vl_api_gpe_locator_t) * vec_len (lcl_locs);
      clib_memcpy (((u8 *) mp->locs) + offset, rmt_locs,
		   (sizeof (vl_api_gpe_locator_t) * vec_len (rmt_locs)));
    }
  vec_free (lcl_locs);
  vec_free (rmt_locs);

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_enable_disable (vat_main_t * vam)
{
  unformat_input_t *input = vam->input;
  vl_api_gpe_enable_disable_t *mp;
  u8 is_set = 0;
  u8 is_enable = 1;
  int ret;

  /* Parse args required to build the message */
  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (input, "enable"))
	{
	  is_set = 1;
	  is_enable = 1;
	}
      else if (unformat (input, "disable"))
	{
	  is_set = 1;
	  is_enable = 0;
	}
      else
	break;
    }

  if (is_set == 0)
    {
      errmsg ("Value not set");
      return -99;
    }

  /* Construct the API message */
  M (GPE_ENABLE_DISABLE, mp);

  mp->is_enable = is_enable;

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

uword
unformat_gpe_encap_mode (unformat_input_t * input, va_list * args)
{
  u32 *mode = va_arg (*args, u32 *);

  if (unformat (input, "lisp"))
    *mode = 0;
  else if (unformat (input, "vxlan"))
    *mode = 1;
  else
    return 0;

  return 1;
}

static int
api_gpe_get_encap_mode (vat_main_t * vam)
{
  vl_api_gpe_get_encap_mode_t *mp;
  int ret;

  /* Construct the API message */
  M (GPE_GET_ENCAP_MODE, mp);

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_set_encap_mode (vat_main_t * vam)
{
  unformat_input_t *input = vam->input;
  vl_api_gpe_set_encap_mode_t *mp;
  int ret;
  u32 mode = 0;

  /* Parse args required to build the message */
  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (input, "%U", unformat_gpe_encap_mode, &mode))
	;
      else
	break;
    }

  /* Construct the API message */
  M (GPE_SET_ENCAP_MODE, mp);

  mp->is_vxlan = mode;

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_add_del_iface (vat_main_t * vam)
{
  unformat_input_t *input = vam->input;
  vl_api_gpe_add_del_iface_t *mp;
  u8 action_set = 0, is_add = 1, is_l2 = 0, dp_table_set = 0, vni_set = 0;
  u32 dp_table = 0, vni = 0;
  int ret;

  /* Parse args required to build the message */
  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (input, "up"))
	{
	  action_set = 1;
	  is_add = 1;
	}
      else if (unformat (input, "down"))
	{
	  action_set = 1;
	  is_add = 0;
	}
      else if (unformat (input, "table_id %d", &dp_table))
	{
	  dp_table_set = 1;
	}
      else if (unformat (input, "bd_id %d", &dp_table))
	{
	  dp_table_set = 1;
	  is_l2 = 1;
	}
      else if (unformat (input, "vni %d", &vni))
	{
	  vni_set = 1;
	}
      else
	break;
    }

  if (action_set == 0)
    {
      errmsg ("Action not set");
      return -99;
    }
  if (dp_table_set == 0 || vni_set == 0)
    {
      errmsg ("vni and dp_table must be set");
      return -99;
    }

  /* Construct the API message */
  M (GPE_ADD_DEL_IFACE, mp);

  mp->is_add = is_add;
  mp->dp_table = clib_host_to_net_u32 (dp_table);
  mp->is_l2 = is_l2;
  mp->vni = clib_host_to_net_u32 (vni);

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_fwd_entries_get (vat_main_t * vam)
{
  unformat_input_t *i = vam->input;
  vl_api_gpe_fwd_entries_get_t *mp;
  u8 vni_set = 0;
  u32 vni = ~0;
  int ret;

  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (i, "vni %d", &vni))
	{
	  vni_set = 1;
	}
      else
	{
	  errmsg ("parse error '%U'", format_unformat_error, i);
	  return -99;
	}
    }

  if (!vni_set)
    {
      errmsg ("vni not set!");
      return -99;
    }

  if (!vam->json_output)
    {
      print (vam->ofp, "%10s %10s %s %40s", "fwd_index", "dp_table",
	     "leid", "reid");
    }

  M (GPE_FWD_ENTRIES_GET, mp);
  mp->vni = clib_host_to_net_u32 (vni);

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_native_fwd_rpaths_get (vat_main_t * vam)
{
  unformat_input_t *i = vam->input;
  vl_api_gpe_native_fwd_rpaths_get_t *mp;
  int ret;
  u8 ip_family_set = 0, is_ip4 = 1;

  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (i, "ip4"))
	{
	  ip_family_set = 1;
	  is_ip4 = 1;
	}
      else if (unformat (i, "ip6"))
	{
	  ip_family_set = 1;
	  is_ip4 = 0;
	}
      else
	{
	  errmsg ("parse error '%U'", format_unformat_error, i);
	  return -99;
	}
    }

  if (!ip_family_set)
    {
      errmsg ("ip family not set!");
      return -99;
    }

  M (GPE_NATIVE_FWD_RPATHS_GET, mp);
  mp->is_ip4 = is_ip4;

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_fwd_entry_vnis_get (vat_main_t * vam)
{
  vl_api_gpe_fwd_entry_vnis_get_t *mp;
  int ret;

  if (!vam->json_output)
    {
      print (vam->ofp, "VNIs");
    }

  M (GPE_FWD_ENTRY_VNIS_GET, mp);

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_add_del_native_fwd_rpath (vat_main_t * vam)
{
  unformat_input_t *i = vam->input;
  vl_api_gpe_add_del_native_fwd_rpath_t *mp;
  int ret = 0;
  u8 is_add = 1, ip_set = 0, is_ip4 = 1;
  struct in_addr ip4;
  struct in6_addr ip6;
  u32 table_id = 0, nh_sw_if_index = ~0;

  clib_memset (&ip4, 0, sizeof (ip4));
  clib_memset (&ip6, 0, sizeof (ip6));

  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (i, "del"))
	is_add = 0;
      else if (unformat (i, "via %U %U", unformat_ip4_address, &ip4,
			 unformat_sw_if_index, vam, &nh_sw_if_index))
	{
	  ip_set = 1;
	  is_ip4 = 1;
	}
      else if (unformat (i, "via %U %U", unformat_ip6_address, &ip6,
			 unformat_sw_if_index, vam, &nh_sw_if_index))
	{
	  ip_set = 1;
	  is_ip4 = 0;
	}
      else if (unformat (i, "via %U", unformat_ip4_address, &ip4))
	{
	  ip_set = 1;
	  is_ip4 = 1;
	  nh_sw_if_index = ~0;
	}
      else if (unformat (i, "via %U", unformat_ip6_address, &ip6))
	{
	  ip_set = 1;
	  is_ip4 = 0;
	  nh_sw_if_index = ~0;
	}
      else if (unformat (i, "table %d", &table_id))
	;
      else
	{
	  errmsg ("parse error '%U'", format_unformat_error, i);
	  return -99;
	}
    }

  if (!ip_set)
    {
      errmsg ("nh addr not set!");
      return -99;
    }

  M (GPE_ADD_DEL_NATIVE_FWD_RPATH, mp);
  mp->is_add = is_add;
  mp->table_id = clib_host_to_net_u32 (table_id);
  mp->nh_sw_if_index = clib_host_to_net_u32 (nh_sw_if_index);
  mp->nh_addr.af = is_ip4 ? 0 : 1;
  if (is_ip4)
    clib_memcpy (mp->nh_addr.un.ip4, &ip4, sizeof (ip4));
  else
    clib_memcpy (mp->nh_addr.un.ip6, &ip6, sizeof (ip6));

  /* send it... */
  S (mp);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

static int
api_gpe_fwd_entry_path_dump (vat_main_t * vam)
{
  vl_api_gpe_fwd_entry_path_dump_t *mp;
  vl_api_control_ping_t *mp_ping;
  unformat_input_t *i = vam->input;
  u32 fwd_entry_index = ~0;
  int ret;

  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (i, "index %d", &fwd_entry_index))
	;
      else
	break;
    }

  if (~0 == fwd_entry_index)
    {
      errmsg ("no index specified!");
      return -99;
    }

  if (!vam->json_output)
    {
      print (vam->ofp, "first line");
    }

  M (GPE_FWD_ENTRY_PATH_DUMP, mp);

  /* send it... */
  S (mp);
  /* Use a control ping for synchronization */
  LISP_PING (&lisp_gpe_test_main, mp_ping);
  S (mp_ping);

  /* Wait for a reply... */
  W (ret);
  return ret;
}

#define vat_plugin_register vat_plugin_register_gpe
#include <lisp/lisp-gpe/lisp_gpe.api_test.c>

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */