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