Punt Infra
[vpp.git] / src / plugins / gbp / gbp_vxlan.c
1 /*
2  * Copyright (c) 2018 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 <plugins/gbp/gbp_vxlan.h>
17 #include <plugins/gbp/gbp_itf.h>
18 #include <plugins/gbp/gbp_learn.h>
19 #include <plugins/gbp/gbp_bridge_domain.h>
20 #include <plugins/gbp/gbp_route_domain.h>
21
22 #include <vnet/vxlan-gbp/vxlan_gbp.h>
23 #include <vlibmemory/api.h>
24 #include <vnet/fib/fib_table.h>
25 #include <vlib/punt.h>
26
27 /**
28  * A reference to a VXLAN-GBP tunnel created as a child/dependent tunnel
29  * of the tempplate GBP-VXLAN tunnel
30  */
31 typedef struct vxlan_tunnel_ref_t_
32 {
33   u32 vxr_sw_if_index;
34   index_t vxr_itf;
35   u32 vxr_locks;
36   index_t vxr_parent;
37   gbp_vxlan_tunnel_layer_t vxr_layer;
38 } vxlan_tunnel_ref_t;
39
40 /**
41  * DB of added tunnels
42  */
43 uword *gv_db;
44
45 /**
46  * Logger
47  */
48 vlib_log_class_t gt_logger;
49
50 /**
51  * Pool of template tunnels
52  */
53 gbp_vxlan_tunnel_t *gbp_vxlan_tunnel_pool;
54
55 /**
56  * Pool of child tunnels
57  */
58 vxlan_tunnel_ref_t *vxlan_tunnel_ref_pool;
59
60 /**
61  * DB of template interfaces by SW interface index
62  */
63 index_t *gbp_vxlan_tunnel_db;
64
65 /**
66  * DB of child interfaces by SW interface index
67  */
68 index_t *vxlan_tunnel_ref_db;
69
70 /**
71  * handle registered with the ;unt infra
72  */
73 static vlib_punt_hdl_t punt_hdl;
74
75 static char *gbp_vxlan_tunnel_layer_strings[] = {
76 #define _(n,s) [GBP_VXLAN_TUN_##n] = s,
77   forecah_gbp_vxlan_tunnel_layer
78 #undef _
79 };
80
81 #define GBP_VXLAN_TUN_DBG(...)                          \
82     vlib_log_debug (gt_logger, __VA_ARGS__);
83
84
85
86 gbp_vxlan_tunnel_t *
87 gbp_vxlan_tunnel_get (index_t gti)
88 {
89   return (pool_elt_at_index (gbp_vxlan_tunnel_pool, gti));
90 }
91
92 static vxlan_tunnel_ref_t *
93 vxlan_tunnel_ref_get (index_t vxri)
94 {
95   return (pool_elt_at_index (vxlan_tunnel_ref_pool, vxri));
96 }
97
98 static u8 *
99 format_vxlan_tunnel_ref (u8 * s, va_list * args)
100 {
101   index_t vxri = va_arg (*args, u32);
102   vxlan_tunnel_ref_t *vxr;
103
104   vxr = vxlan_tunnel_ref_get (vxri);
105
106   s = format (s, "[%U locks:%d]", format_vnet_sw_if_index_name,
107               vnet_get_main (), vxr->vxr_sw_if_index, vxr->vxr_locks);
108
109   return (s);
110 }
111
112 static u32
113 gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
114                    const ip46_address_t * src, const ip46_address_t * dst)
115 {
116   vnet_vxlan_gbp_tunnel_add_del_args_t args = {
117     .is_add = 1,
118     .is_ip6 = !ip46_address_is_ip4 (src),
119     .vni = gt->gt_vni,
120     .src = *src,
121     .dst = *dst,
122     .instance = ~0,
123     .mode = (GBP_VXLAN_TUN_L2 == gt->gt_layer ?
124              VXLAN_GBP_TUNNEL_MODE_L2 : VXLAN_GBP_TUNNEL_MODE_L3),
125   };
126   vxlan_tunnel_ref_t *vxr;
127   u32 sw_if_index;
128   index_t vxri;
129   int rv;
130
131   sw_if_index = ~0;
132   rv = vnet_vxlan_gbp_tunnel_add_del (&args, &sw_if_index);
133
134   if (VNET_API_ERROR_TUNNEL_EXIST == rv)
135     {
136       vxri = vxlan_tunnel_ref_db[sw_if_index];
137
138       vxr = vxlan_tunnel_ref_get (vxri);
139       vxr->vxr_locks++;
140     }
141   else if (0 == rv)
142     {
143       ASSERT (~0 != sw_if_index);
144       GBP_VXLAN_TUN_DBG ("add-dep:%U %U %U %d", format_vnet_sw_if_index_name,
145                          vnet_get_main (), sw_if_index,
146                          format_ip46_address, src, IP46_TYPE_ANY,
147                          format_ip46_address, dst, IP46_TYPE_ANY, gt->gt_vni);
148
149       pool_get_zero (vxlan_tunnel_ref_pool, vxr);
150
151       vxri = (vxr - vxlan_tunnel_ref_pool);
152       vxr->vxr_parent = gt - gbp_vxlan_tunnel_pool;
153       vxr->vxr_sw_if_index = sw_if_index;
154       vxr->vxr_locks = 1;
155       vxr->vxr_layer = gt->gt_layer;
156
157       /*
158        * store the child both on the parent's list and the global DB
159        */
160       vec_add1 (gt->gt_tuns, vxri);
161
162       vec_validate_init_empty (vxlan_tunnel_ref_db,
163                                vxr->vxr_sw_if_index, INDEX_INVALID);
164       vxlan_tunnel_ref_db[vxr->vxr_sw_if_index] = vxri;
165
166       if (GBP_VXLAN_TUN_L2 == vxr->vxr_layer)
167         {
168           l2output_feat_masks_t ofeat;
169           l2input_feat_masks_t ifeat;
170           gbp_bridge_domain_t *gbd;
171
172           gbd = gbp_bridge_domain_get (gt->gt_gbd);
173           vxr->vxr_itf = gbp_itf_add_and_lock (vxr->vxr_sw_if_index,
174                                                gt->gt_bd_index);
175
176           ofeat = L2OUTPUT_FEAT_GBP_POLICY_MAC;
177           ifeat = L2INPUT_FEAT_NONE;
178
179           if (!(gbd->gb_flags & GBP_BD_FLAG_DO_NOT_LEARN))
180             ifeat |= L2INPUT_FEAT_GBP_LEARN;
181
182           gbp_itf_set_l2_output_feature (vxr->vxr_itf,
183                                          vxr->vxr_sw_if_index, ofeat);
184           gbp_itf_set_l2_input_feature (vxr->vxr_itf,
185                                         vxr->vxr_sw_if_index, ifeat);
186         }
187       else
188         {
189           const gbp_route_domain_t *grd;
190           fib_protocol_t fproto;
191
192           grd = gbp_route_domain_get (gt->gt_grd);
193
194           FOR_EACH_FIB_IP_PROTOCOL (fproto)
195             ip_table_bind (fproto, vxr->vxr_sw_if_index,
196                            grd->grd_table_id[fproto], 1);
197
198           gbp_learn_enable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
199         }
200     }
201
202   return (sw_if_index);
203 }
204
205 u32
206 vxlan_gbp_tunnel_get_parent (u32 sw_if_index)
207 {
208   ASSERT ((sw_if_index < vec_len (vxlan_tunnel_ref_db)) &&
209           (INDEX_INVALID != vxlan_tunnel_ref_db[sw_if_index]));
210
211   gbp_vxlan_tunnel_t *gt;
212   vxlan_tunnel_ref_t *vxr;
213
214   vxr = vxlan_tunnel_ref_get (vxlan_tunnel_ref_db[sw_if_index]);
215   gt = gbp_vxlan_tunnel_get (vxr->vxr_parent);
216
217   return (gt->gt_sw_if_index);
218 }
219
220 gbp_vxlan_tunnel_type_t
221 gbp_vxlan_tunnel_get_type (u32 sw_if_index)
222 {
223   if (sw_if_index < vec_len (vxlan_tunnel_ref_db) &&
224       INDEX_INVALID != vxlan_tunnel_ref_db[sw_if_index])
225     {
226       return (VXLAN_GBP_TUNNEL);
227     }
228   else if (sw_if_index < vec_len (gbp_vxlan_tunnel_db) &&
229            INDEX_INVALID != gbp_vxlan_tunnel_db[sw_if_index])
230     {
231       return (GBP_VXLAN_TEMPLATE_TUNNEL);
232     }
233
234   ASSERT (0);
235   return (GBP_VXLAN_TEMPLATE_TUNNEL);
236 }
237
238 u32
239 gbp_vxlan_tunnel_clone_and_lock (u32 sw_if_index,
240                                  const ip46_address_t * src,
241                                  const ip46_address_t * dst)
242 {
243   gbp_vxlan_tunnel_t *gt;
244   index_t gti;
245
246   gti = gbp_vxlan_tunnel_db[sw_if_index];
247
248   if (INDEX_INVALID == gti)
249     return (~0);
250
251   gt = pool_elt_at_index (gbp_vxlan_tunnel_pool, gti);
252
253   return (gdb_vxlan_dep_add (gt, src, dst));
254 }
255
256 static void
257 gdb_vxlan_dep_del (index_t vxri)
258 {
259   vxlan_tunnel_ref_t *vxr;
260   gbp_vxlan_tunnel_t *gt;
261   u32 pos;
262
263   vxr = vxlan_tunnel_ref_get (vxri);
264   gt = gbp_vxlan_tunnel_get (vxr->vxr_parent);
265
266   GBP_VXLAN_TUN_DBG ("del-dep:%U", format_vxlan_tunnel_ref, vxri);
267
268   vxlan_tunnel_ref_db[vxr->vxr_sw_if_index] = INDEX_INVALID;
269   pos = vec_search (gt->gt_tuns, vxri);
270
271   ASSERT (~0 != pos);
272   vec_del1 (gt->gt_tuns, pos);
273
274   if (GBP_VXLAN_TUN_L2 == vxr->vxr_layer)
275     {
276       gbp_itf_set_l2_output_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
277                                      L2OUTPUT_FEAT_NONE);
278       gbp_itf_set_l2_input_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
279                                     L2INPUT_FEAT_NONE);
280       gbp_itf_unlock (vxr->vxr_itf);
281     }
282   else
283     {
284       fib_protocol_t fproto;
285
286       FOR_EACH_FIB_IP_PROTOCOL (fproto)
287         ip_table_bind (fproto, vxr->vxr_sw_if_index, 0, 0);
288       gbp_learn_disable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
289     }
290
291   vnet_vxlan_gbp_tunnel_del (vxr->vxr_sw_if_index);
292
293   pool_put (vxlan_tunnel_ref_pool, vxr);
294 }
295
296 void
297 vxlan_gbp_tunnel_unlock (u32 sw_if_index)
298 {
299   vxlan_tunnel_ref_t *vxr;
300   index_t vxri;
301
302   vxri = vxlan_tunnel_ref_db[sw_if_index];
303
304   ASSERT (vxri != INDEX_INVALID);
305
306   vxr = vxlan_tunnel_ref_get (vxri);
307   vxr->vxr_locks--;
308
309   if (0 == vxr->vxr_locks)
310     {
311       gdb_vxlan_dep_del (vxri);
312     }
313 }
314
315 void
316 vxlan_gbp_tunnel_lock (u32 sw_if_index)
317 {
318   vxlan_tunnel_ref_t *vxr;
319   index_t vxri;
320
321   vxri = vxlan_tunnel_ref_db[sw_if_index];
322
323   ASSERT (vxri != INDEX_INVALID);
324
325   vxr = vxlan_tunnel_ref_get (vxri);
326   vxr->vxr_locks++;
327 }
328
329 void
330 gbp_vxlan_walk (gbp_vxlan_cb_t cb, void *ctx)
331 {
332   gbp_vxlan_tunnel_t *gt;
333
334   /* *INDENT-OFF* */
335   pool_foreach (gt, gbp_vxlan_tunnel_pool,
336     ({
337       if (WALK_CONTINUE != cb(gt, ctx))
338         break;
339     }));
340   /* *INDENT-ON* */
341 }
342
343 static walk_rc_t
344 gbp_vxlan_tunnel_show_one (gbp_vxlan_tunnel_t * gt, void *ctx)
345 {
346   vlib_cli_output (ctx, "%U", format_gbp_vxlan_tunnel,
347                    gt - gbp_vxlan_tunnel_pool);
348
349   return (WALK_CONTINUE);
350 }
351
352 static u8 *
353 format_gbp_vxlan_tunnel_name (u8 * s, va_list * args)
354 {
355   u32 dev_instance = va_arg (*args, u32);
356
357   return format (s, "gbp-vxlan-%d", dev_instance);
358 }
359
360 u8 *
361 format_gbp_vxlan_tunnel_layer (u8 * s, va_list * args)
362 {
363   gbp_vxlan_tunnel_layer_t gl = va_arg (*args, gbp_vxlan_tunnel_layer_t);
364   s = format (s, "%s", gbp_vxlan_tunnel_layer_strings[gl]);
365
366   return (s);
367 }
368
369 u8 *
370 format_gbp_vxlan_tunnel (u8 * s, va_list * args)
371 {
372   u32 dev_instance = va_arg (*args, u32);
373   CLIB_UNUSED (int verbose) = va_arg (*args, int);
374   gbp_vxlan_tunnel_t *gt = gbp_vxlan_tunnel_get (dev_instance);
375   index_t *vxri;
376
377   s = format (s, "GBP VXLAN tunnel: hw:%d sw:%d vni:%d %U",
378               gt->gt_hw_if_index, gt->gt_sw_if_index, gt->gt_vni,
379               format_gbp_vxlan_tunnel_layer, gt->gt_layer);
380   if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
381     s = format (s, " BD:%d bd-index:%d", gt->gt_bd_rd_id, gt->gt_bd_index);
382   else
383     s = format (s, " RD:%d fib-index:[%d,%d]",
384                 gt->gt_bd_rd_id,
385                 gt->gt_fib_index[FIB_PROTOCOL_IP4],
386                 gt->gt_fib_index[FIB_PROTOCOL_IP6]);
387
388   s = format (s, " children:[");
389   vec_foreach (vxri, gt->gt_tuns)
390   {
391     s = format (s, "%U, ", format_vxlan_tunnel_ref, *vxri);
392   }
393   s = format (s, "]");
394
395   return s;
396 }
397
398 typedef struct gbp_vxlan_tx_trace_t_
399 {
400   u32 vni;
401 } gbp_vxlan_tx_trace_t;
402
403 u8 *
404 format_gbp_vxlan_tx_trace (u8 * s, va_list * args)
405 {
406   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
407   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
408   gbp_vxlan_tx_trace_t *t = va_arg (*args, gbp_vxlan_tx_trace_t *);
409
410   s = format (s, "GBP-VXLAN: vni:%d", t->vni);
411
412   return (s);
413 }
414
415 clib_error_t *
416 gbp_vxlan_interface_admin_up_down (vnet_main_t * vnm,
417                                    u32 hw_if_index, u32 flags)
418 {
419   vnet_hw_interface_t *hi;
420   u32 ti;
421
422   hi = vnet_get_hw_interface (vnm, hw_if_index);
423
424   if (NULL == gbp_vxlan_tunnel_db ||
425       hi->sw_if_index >= vec_len (gbp_vxlan_tunnel_db))
426     return (NULL);
427
428   ti = gbp_vxlan_tunnel_db[hi->sw_if_index];
429
430   if (~0 == ti)
431     /* not one of ours */
432     return (NULL);
433
434   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
435     vnet_hw_interface_set_flags (vnm, hw_if_index,
436                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
437   else
438     vnet_hw_interface_set_flags (vnm, hw_if_index, 0);
439
440   return (NULL);
441 }
442
443 static uword
444 gbp_vxlan_interface_tx (vlib_main_t * vm,
445                         vlib_node_runtime_t * node, vlib_frame_t * frame)
446 {
447   clib_warning ("you shouldn't be here, leaking buffers...");
448   return frame->n_vectors;
449 }
450
451 /* *INDENT-OFF* */
452 VNET_DEVICE_CLASS (gbp_vxlan_device_class) = {
453   .name = "GBP VXLAN tunnel-template",
454   .format_device_name = format_gbp_vxlan_tunnel_name,
455   .format_device = format_gbp_vxlan_tunnel,
456   .format_tx_trace = format_gbp_vxlan_tx_trace,
457   .admin_up_down_function = gbp_vxlan_interface_admin_up_down,
458   .tx_function = gbp_vxlan_interface_tx,
459 };
460
461 VNET_HW_INTERFACE_CLASS (gbp_vxlan_hw_interface_class) = {
462   .name = "GBP-VXLAN",
463   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
464 };
465 /* *INDENT-ON* */
466
467 int
468 gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
469                       u32 bd_rd_id,
470                       const ip4_address_t * src, u32 * sw_if_indexp)
471 {
472   gbp_vxlan_tunnel_t *gt;
473   index_t gti;
474   uword *p;
475   int rv;
476
477   rv = 0;
478   p = hash_get (gv_db, vni);
479
480   GBP_VXLAN_TUN_DBG ("add: %d %d %d", vni, layer, bd_rd_id);
481
482   if (NULL == p)
483     {
484       vnet_sw_interface_t *si;
485       vnet_hw_interface_t *hi;
486       index_t gbi, grdi;
487       vnet_main_t *vnm;
488
489       gbi = grdi = INDEX_INVALID;
490
491       if (layer == GBP_VXLAN_TUN_L2)
492         {
493           gbi = gbp_bridge_domain_find_and_lock (bd_rd_id);
494
495           if (INDEX_INVALID == gbi)
496             {
497               return (VNET_API_ERROR_BD_NOT_MODIFIABLE);
498             }
499         }
500       else
501         {
502           grdi = gbp_route_domain_find_and_lock (bd_rd_id);
503
504           if (INDEX_INVALID == grdi)
505             {
506               return (VNET_API_ERROR_NO_SUCH_FIB);
507             }
508         }
509
510       vnm = vnet_get_main ();
511       pool_get (gbp_vxlan_tunnel_pool, gt);
512       gti = gt - gbp_vxlan_tunnel_pool;
513
514       gt->gt_vni = vni;
515       gt->gt_layer = layer;
516       gt->gt_bd_rd_id = bd_rd_id;
517       gt->gt_src.ip4.as_u32 = src->as_u32;
518       gt->gt_hw_if_index = vnet_register_interface (vnm,
519                                                     gbp_vxlan_device_class.index,
520                                                     gti,
521                                                     gbp_vxlan_hw_interface_class.index,
522                                                     gti);
523
524       hi = vnet_get_hw_interface (vnm, gt->gt_hw_if_index);
525
526       gt->gt_sw_if_index = hi->sw_if_index;
527
528       /* don't flood packets in a BD to these interfaces */
529       si = vnet_get_sw_interface (vnm, gt->gt_sw_if_index);
530       si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
531
532       if (layer == GBP_VXLAN_TUN_L2)
533         {
534           gbp_bridge_domain_t *gb;
535
536           gb = gbp_bridge_domain_get (gbi);
537
538           gt->gt_gbd = gbi;
539           gt->gt_bd_index = gb->gb_bd_index;
540           gb->gb_vni = gti;
541           /* set it up as a GBP interface */
542           gt->gt_itf = gbp_itf_add_and_lock (gt->gt_sw_if_index,
543                                              gt->gt_bd_index);
544           gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
545         }
546       else
547         {
548           gbp_route_domain_t *grd;
549           fib_protocol_t fproto;
550
551           grd = gbp_route_domain_get (grdi);
552
553           gt->gt_grd = grdi;
554           grd->grd_vni_sw_if_index = gt->gt_sw_if_index;
555
556           gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
557
558           ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
559           ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
560
561           FOR_EACH_FIB_IP_PROTOCOL (fproto)
562           {
563             gt->gt_fib_index[fproto] = grd->grd_fib_index[fproto];
564
565             ip_table_bind (fproto, gt->gt_sw_if_index,
566                            grd->grd_table_id[fproto], 1);
567           }
568         }
569
570       /*
571        * save the tunnel by VNI and by sw_if_index
572        */
573       hash_set (gv_db, vni, gti);
574
575       vec_validate_init_empty (gbp_vxlan_tunnel_db,
576                                gt->gt_sw_if_index, INDEX_INVALID);
577       gbp_vxlan_tunnel_db[gt->gt_sw_if_index] = gti;
578
579       if (sw_if_indexp)
580         *sw_if_indexp = gt->gt_sw_if_index;
581
582       vxlan_gbp_register_udp_ports ();
583     }
584   else
585     {
586       gti = p[0];
587       rv = VNET_API_ERROR_IF_ALREADY_EXISTS;
588     }
589
590   GBP_VXLAN_TUN_DBG ("add: %U", format_gbp_vxlan_tunnel, gti);
591
592   return (rv);
593 }
594
595 int
596 gbp_vxlan_tunnel_del (u32 vni)
597 {
598   gbp_vxlan_tunnel_t *gt;
599   uword *p;
600
601   p = hash_get (gv_db, vni);
602
603   if (NULL != p)
604     {
605       vnet_main_t *vnm;
606
607       vnm = vnet_get_main ();
608       gt = gbp_vxlan_tunnel_get (p[0]);
609
610       vxlan_gbp_unregister_udp_ports ();
611
612       GBP_VXLAN_TUN_DBG ("del: %U", format_gbp_vxlan_tunnel,
613                          gt - gbp_vxlan_tunnel_pool);
614
615       gbp_endpoint_flush (GBP_ENDPOINT_SRC_DP, gt->gt_sw_if_index);
616       ASSERT (0 == vec_len (gt->gt_tuns));
617       vec_free (gt->gt_tuns);
618
619       if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
620         {
621           gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
622           gbp_itf_unlock (gt->gt_itf);
623           gbp_bridge_domain_unlock (gt->gt_gbd);
624         }
625       else
626         {
627           fib_protocol_t fproto;
628
629           FOR_EACH_FIB_IP_PROTOCOL (fproto)
630             ip_table_bind (fproto, gt->gt_sw_if_index, 0, 0);
631
632           ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
633           ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
634
635           gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
636           gbp_route_domain_unlock (gt->gt_grd);
637         }
638
639       vnet_sw_interface_set_flags (vnm, gt->gt_sw_if_index, 0);
640       vnet_delete_hw_interface (vnm, gt->gt_hw_if_index);
641
642       hash_unset (gv_db, vni);
643       gbp_vxlan_tunnel_db[gt->gt_sw_if_index] = INDEX_INVALID;
644
645       pool_put (gbp_vxlan_tunnel_pool, gt);
646     }
647   else
648     return VNET_API_ERROR_NO_SUCH_ENTRY;
649
650   return (0);
651 }
652
653 static clib_error_t *
654 gbp_vxlan_show (vlib_main_t * vm,
655                 unformat_input_t * input, vlib_cli_command_t * cmd)
656 {
657   gbp_vxlan_walk (gbp_vxlan_tunnel_show_one, vm);
658
659   return (NULL);
660 }
661
662 /*?
663  * Show Group Based Policy VXLAN tunnels
664  *
665  * @cliexpar
666  * @cliexstart{show gbp vxlan}
667  * @cliexend
668  ?*/
669 /* *INDENT-OFF* */
670 VLIB_CLI_COMMAND (gbp_vxlan_show_node, static) = {
671   .path = "show gbp vxlan",
672   .short_help = "show gbp vxlan\n",
673   .function = gbp_vxlan_show,
674 };
675 /* *INDENT-ON* */
676
677 static clib_error_t *
678 gbp_vxlan_init (vlib_main_t * vm)
679 {
680   vxlan_gbp_main_t *vxm = &vxlan_gbp_main;
681   clib_error_t *error;
682
683   gt_logger = vlib_log_register_class ("gbp", "tun");
684
685   if ((error = vlib_call_init_function (vm, punt_init)))
686     return error;
687   if ((error = vlib_call_init_function (vm, vxlan_gbp_init)))
688     return error;
689
690   punt_hdl = vlib_punt_client_register ("gbp-vxlan");
691
692   vlib_punt_register (punt_hdl,
693                       vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP4],
694                       "gbp-vxlan4");
695
696   return (error);
697 }
698
699 VLIB_INIT_FUNCTION (gbp_vxlan_init);
700
701 /*
702  * fd.io coding-style-patch-verification: ON
703  *
704  * Local Variables:
705  * eval: (c-set-style "gnu")
706  * End:
707  */