GBP: redirect contracts
[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
26 /**
27  * A reference to a VXLAN-GBP tunnel created as a child/dependent tunnel
28  * of the tempplate GBP-VXLAN tunnel
29  */
30 typedef struct vxlan_tunnel_ref_t_
31 {
32   u32 vxr_sw_if_index;
33   index_t vxr_itf;
34   u32 vxr_locks;
35   index_t vxr_parent;
36   gbp_vxlan_tunnel_layer_t vxr_layer;
37 } vxlan_tunnel_ref_t;
38
39 /**
40  * DB of added tunnels
41  */
42 uword *gv_db;
43
44 /**
45  * Logger
46  */
47 vlib_log_class_t gt_logger;
48
49 /**
50  * Pool of template tunnels
51  */
52 gbp_vxlan_tunnel_t *gbp_vxlan_tunnel_pool;
53
54 /**
55  * Pool of child tunnels
56  */
57 vxlan_tunnel_ref_t *vxlan_tunnel_ref_pool;
58
59 /**
60  * DB of template interfaces by SW interface index
61  */
62 index_t *gbp_vxlan_tunnel_db;
63
64 /**
65  * DB of child interfaces by SW interface index
66  */
67 index_t *vxlan_tunnel_ref_db;
68
69
70 static char *gbp_vxlan_tunnel_layer_strings[] = {
71 #define _(n,s) [GBP_VXLAN_TUN_##n] = s,
72   forecah_gbp_vxlan_tunnel_layer
73 #undef _
74 };
75
76 #define GBP_VXLAN_TUN_DBG(...)                          \
77     vlib_log_debug (gt_logger, __VA_ARGS__);
78
79
80
81 always_inline gbp_vxlan_tunnel_t *
82 gbp_vxlan_tunnel_get (index_t gti)
83 {
84   return (pool_elt_at_index (gbp_vxlan_tunnel_pool, gti));
85 }
86
87 static vxlan_tunnel_ref_t *
88 vxlan_tunnel_ref_get (index_t vxri)
89 {
90   return (pool_elt_at_index (vxlan_tunnel_ref_pool, vxri));
91 }
92
93 static u8 *
94 format_vxlan_tunnel_ref (u8 * s, va_list * args)
95 {
96   index_t vxri = va_arg (*args, u32);
97   vxlan_tunnel_ref_t *vxr;
98
99   vxr = vxlan_tunnel_ref_get (vxri);
100
101   s = format (s, "[%U locks:%d]", format_vnet_sw_if_index_name,
102               vnet_get_main (), vxr->vxr_sw_if_index, vxr->vxr_locks);
103
104   return (s);
105 }
106
107 static u32
108 gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
109                    u32 vni,
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 = 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, 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           vxr->vxr_itf = gbp_itf_add_and_lock (vxr->vxr_sw_if_index,
165                                                gt->gt_bd_index);
166
167           gbp_itf_set_l2_output_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
168                                          L2OUTPUT_FEAT_GBP_POLICY_MAC);
169           gbp_itf_set_l2_input_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
170                                         L2INPUT_FEAT_GBP_LEARN);
171         }
172       else
173         {
174           const gbp_route_domain_t *grd;
175           fib_protocol_t fproto;
176
177           grd = gbp_route_domain_get (gt->gt_grd);
178
179           FOR_EACH_FIB_IP_PROTOCOL (fproto)
180             ip_table_bind (fproto, vxr->vxr_sw_if_index,
181                            grd->grd_table_id[fproto], 1);
182
183           gbp_learn_enable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
184         }
185     }
186
187   return (sw_if_index);
188 }
189
190 u32
191 vxlan_gbp_tunnel_get_parent (u32 sw_if_index)
192 {
193   ASSERT ((sw_if_index < vec_len (vxlan_tunnel_ref_db)) &&
194           (INDEX_INVALID != vxlan_tunnel_ref_db[sw_if_index]));
195
196   gbp_vxlan_tunnel_t *gt;
197   vxlan_tunnel_ref_t *vxr;
198
199   vxr = vxlan_tunnel_ref_get (vxlan_tunnel_ref_db[sw_if_index]);
200   gt = gbp_vxlan_tunnel_get (vxr->vxr_parent);
201
202   return (gt->gt_sw_if_index);
203 }
204
205 gbp_vxlan_tunnel_type_t
206 gbp_vxlan_tunnel_get_type (u32 sw_if_index)
207 {
208   if (sw_if_index < vec_len (vxlan_tunnel_ref_db) &&
209       INDEX_INVALID != vxlan_tunnel_ref_db[sw_if_index])
210     {
211       return (VXLAN_GBP_TUNNEL);
212     }
213   else if (sw_if_index < vec_len (gbp_vxlan_tunnel_db) &&
214            INDEX_INVALID != gbp_vxlan_tunnel_db[sw_if_index])
215     {
216       return (GBP_VXLAN_TEMPLATE_TUNNEL);
217     }
218
219   ASSERT (0);
220   return (GBP_VXLAN_TEMPLATE_TUNNEL);
221 }
222
223 u32
224 gbp_vxlan_tunnel_clone_and_lock (u32 sw_if_index,
225                                  const ip46_address_t * src,
226                                  const ip46_address_t * dst)
227 {
228   gbp_vxlan_tunnel_t *gt;
229   index_t gti;
230
231   gti = gbp_vxlan_tunnel_db[sw_if_index];
232
233   if (INDEX_INVALID == gti)
234     return (~0);
235
236   gt = pool_elt_at_index (gbp_vxlan_tunnel_pool, gti);
237
238   return (gdb_vxlan_dep_add (gt, gt->gt_vni, src, dst));
239 }
240
241 static void
242 gdb_vxlan_dep_del (index_t vxri)
243 {
244   vxlan_tunnel_ref_t *vxr;
245   gbp_vxlan_tunnel_t *gt;
246   u32 pos;
247
248   vxr = vxlan_tunnel_ref_get (vxri);
249   gt = gbp_vxlan_tunnel_get (vxr->vxr_parent);
250
251   GBP_VXLAN_TUN_DBG ("del-dep:%U", format_vxlan_tunnel_ref, vxri);
252
253   vxlan_tunnel_ref_db[vxr->vxr_sw_if_index] = INDEX_INVALID;
254   pos = vec_search (gt->gt_tuns, vxri);
255
256   ASSERT (~0 != pos);
257   vec_del1 (gt->gt_tuns, pos);
258
259   if (GBP_VXLAN_TUN_L2 == vxr->vxr_layer)
260     {
261       gbp_itf_set_l2_output_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
262                                      L2OUTPUT_FEAT_NONE);
263       gbp_itf_set_l2_input_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
264                                     L2INPUT_FEAT_NONE);
265       gbp_itf_unlock (vxr->vxr_itf);
266     }
267   else
268     {
269       fib_protocol_t fproto;
270
271       FOR_EACH_FIB_IP_PROTOCOL (fproto)
272         ip_table_bind (fproto, vxr->vxr_sw_if_index, 0, 0);
273     }
274
275   vnet_vxlan_gbp_tunnel_del (vxr->vxr_sw_if_index);
276
277   pool_put (vxlan_tunnel_ref_pool, vxr);
278 }
279
280 void
281 vxlan_gbp_tunnel_unlock (u32 sw_if_index)
282 {
283   vxlan_tunnel_ref_t *vxr;
284   index_t vxri;
285
286   vxri = vxlan_tunnel_ref_db[sw_if_index];
287
288   ASSERT (vxri != INDEX_INVALID);
289
290   vxr = vxlan_tunnel_ref_get (vxri);
291   vxr->vxr_locks--;
292
293   if (0 == vxr->vxr_locks)
294     {
295       gdb_vxlan_dep_del (vxri);
296     }
297 }
298
299 void
300 vxlan_gbp_tunnel_lock (u32 sw_if_index)
301 {
302   vxlan_tunnel_ref_t *vxr;
303   index_t vxri;
304
305   vxri = vxlan_tunnel_ref_db[sw_if_index];
306
307   ASSERT (vxri != INDEX_INVALID);
308
309   vxr = vxlan_tunnel_ref_get (vxri);
310   vxr->vxr_locks++;
311 }
312
313 #define foreach_gbp_vxlan_input_next         \
314   _(DROP, "error-drop")                      \
315   _(L2_INPUT, "l2-input")                    \
316   _(IP4_INPUT, "ip4-input")                  \
317   _(IP6_INPUT, "ip6-input")
318
319 typedef enum
320 {
321 #define _(s,n) GBP_VXLAN_INPUT_NEXT_##s,
322   foreach_gbp_vxlan_input_next
323 #undef _
324     GBP_VXLAN_INPUT_N_NEXT,
325 } gbp_vxlan_input_next_t;
326
327 #define foreach_gbp_vxlan_error              \
328   _(DECAPPED, "decapped")                    \
329   _(LEARNED, "learned")
330
331 typedef enum
332 {
333 #define _(s,n) GBP_VXLAN_ERROR_##s,
334   foreach_gbp_vxlan_error
335 #undef _
336     GBP_VXLAN_N_ERROR,
337 } gbp_vxlan_input_error_t;
338
339 static char *gbp_vxlan_error_strings[] = {
340 #define _(n,s) s,
341   foreach_gbp_vxlan_error
342 #undef _
343 };
344
345 typedef struct gbp_vxlan_trace_t_
346 {
347   u8 dropped;
348   u32 vni;
349   u32 sw_if_index;
350   u16 sclass;
351   u8 flags;
352 } gbp_vxlan_trace_t;
353
354
355 static uword
356 gbp_vxlan_decap (vlib_main_t * vm,
357                  vlib_node_runtime_t * node,
358                  vlib_frame_t * from_frame, u8 is_ip4)
359 {
360   u32 n_left_to_next, n_left_from, next_index, *to_next, *from;
361
362   next_index = 0;
363   from = vlib_frame_vector_args (from_frame);
364   n_left_from = from_frame->n_vectors;
365
366   while (n_left_from > 0)
367     {
368
369       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
370
371       while (n_left_from > 0 && n_left_to_next > 0)
372         {
373           vxlan_gbp_header_t *vxlan_gbp0;
374           gbp_vxlan_input_next_t next0;
375           gbp_vxlan_tunnel_t *gt0;
376           vlib_buffer_t *b0;
377           u32 bi0, vni0;
378           uword *p;
379
380           bi0 = to_next[0] = from[0];
381           from += 1;
382           to_next += 1;
383           n_left_from -= 1;
384           n_left_to_next -= 1;
385           next0 = GBP_VXLAN_INPUT_NEXT_DROP;
386
387           b0 = vlib_get_buffer (vm, bi0);
388           vxlan_gbp0 =
389             vlib_buffer_get_current (b0) - sizeof (vxlan_gbp_header_t);
390
391           vni0 = vxlan_gbp_get_vni (vxlan_gbp0);
392           p = hash_get (gv_db, vni0);
393
394           if (PREDICT_FALSE (NULL == p))
395             {
396               gt0 = NULL;
397               next0 = GBP_VXLAN_INPUT_NEXT_DROP;
398             }
399           else
400             {
401               gt0 = gbp_vxlan_tunnel_get (p[0]);
402
403               vnet_buffer (b0)->sw_if_index[VLIB_RX] = gt0->gt_sw_if_index;
404
405               if (GBP_VXLAN_TUN_L2 == gt0->gt_layer)
406                 /*
407                  * An L2 layer tunnel goes into the BD
408                  */
409                 next0 = GBP_VXLAN_INPUT_NEXT_L2_INPUT;
410               else
411                 {
412                   /*
413                    * An L3 layer tunnel needs to strip the L2 header
414                    * an inject into the RD
415                    */
416                   ethernet_header_t *e0;
417                   u16 type0;
418
419                   e0 = vlib_buffer_get_current (b0);
420                   type0 = clib_net_to_host_u16 (e0->type);
421                   switch (type0)
422                     {
423                     case ETHERNET_TYPE_IP4:
424                       next0 = GBP_VXLAN_INPUT_NEXT_IP4_INPUT;
425                       break;
426                     case ETHERNET_TYPE_IP6:
427                       next0 = GBP_VXLAN_INPUT_NEXT_IP6_INPUT;
428                       break;
429                     default:
430                       goto trace;
431                     }
432                   vlib_buffer_advance (b0, sizeof (*e0));
433                 }
434             }
435
436         trace:
437           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
438             {
439               gbp_vxlan_trace_t *tr;
440
441               tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
442               tr->dropped = (next0 == GBP_VXLAN_INPUT_NEXT_DROP);
443               tr->vni = vni0;
444               tr->sw_if_index = (gt0 ? gt0->gt_sw_if_index : ~0);
445               tr->flags = vxlan_gbp_get_gpflags (vxlan_gbp0);
446               tr->sclass = vxlan_gbp_get_sclass (vxlan_gbp0);
447             }
448
449           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
450                                            to_next, n_left_to_next,
451                                            bi0, next0);
452         }
453
454       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
455     }
456
457   return from_frame->n_vectors;
458 }
459
460 static u8 *
461 format_gbp_vxlan_rx_trace (u8 * s, va_list * args)
462 {
463   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
464   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
465   gbp_vxlan_trace_t *t = va_arg (*args, gbp_vxlan_trace_t *);
466
467   s = format (s, "vni:%d dropped:%d rx:%d sclass:%d flags:%U",
468               t->vni, t->dropped, t->sw_if_index,
469               t->sclass, format_vxlan_gbp_header_gpflags, t->flags);
470
471   return (s);
472 }
473
474 static uword
475 gbp_vxlan4_decap (vlib_main_t * vm,
476                   vlib_node_runtime_t * node, vlib_frame_t * from_frame)
477 {
478   return gbp_vxlan_decap (vm, node, from_frame, 1);
479 }
480
481 /* *INDENT-OFF* */
482 VLIB_REGISTER_NODE (gbp_vxlan4_input_node) =
483 {
484   .function = gbp_vxlan4_decap,
485   .name = "gbp-vxlan4",
486   .vector_size = sizeof (u32),
487   .n_errors = GBP_VXLAN_N_ERROR,
488   .error_strings = gbp_vxlan_error_strings,
489   .n_next_nodes = GBP_VXLAN_INPUT_N_NEXT,
490   .format_trace = format_gbp_vxlan_rx_trace,
491   .next_nodes = {
492 #define _(s,n) [GBP_VXLAN_INPUT_NEXT_##s] = n,
493     foreach_gbp_vxlan_input_next
494 #undef _
495   },
496 };
497 VLIB_NODE_FUNCTION_MULTIARCH (gbp_vxlan4_input_node, gbp_vxlan4_decap)
498
499 /* *INDENT-ON* */
500
501 void
502 gbp_vxlan_walk (gbp_vxlan_cb_t cb, void *ctx)
503 {
504   gbp_vxlan_tunnel_t *gt;
505
506   /* *INDENT-OFF* */
507   pool_foreach (gt, gbp_vxlan_tunnel_pool,
508     ({
509       if (WALK_CONTINUE != cb(gt, ctx))
510         break;
511     }));
512   /* *INDENT-ON* */
513 }
514
515 static walk_rc_t
516 gbp_vxlan_tunnel_show_one (gbp_vxlan_tunnel_t * gt, void *ctx)
517 {
518   vlib_cli_output (ctx, "%U", format_gbp_vxlan_tunnel,
519                    gt - gbp_vxlan_tunnel_pool);
520
521   return (WALK_CONTINUE);
522 }
523
524 static u8 *
525 format_gbp_vxlan_tunnel_name (u8 * s, va_list * args)
526 {
527   u32 dev_instance = va_arg (*args, u32);
528
529   return format (s, "gbp-vxlan-%d", dev_instance);
530 }
531
532 u8 *
533 format_gbp_vxlan_tunnel_layer (u8 * s, va_list * args)
534 {
535   gbp_vxlan_tunnel_layer_t gl = va_arg (*args, gbp_vxlan_tunnel_layer_t);
536   s = format (s, "%s", gbp_vxlan_tunnel_layer_strings[gl]);
537
538   return (s);
539 }
540
541 u8 *
542 format_gbp_vxlan_tunnel (u8 * s, va_list * args)
543 {
544   u32 dev_instance = va_arg (*args, u32);
545   CLIB_UNUSED (int verbose) = va_arg (*args, int);
546   gbp_vxlan_tunnel_t *gt = gbp_vxlan_tunnel_get (dev_instance);
547   index_t *vxri;
548
549   s = format (s, "GBP VXLAN tunnel: hw:%d sw:%d vni:%d %U",
550               gt->gt_hw_if_index, gt->gt_sw_if_index, gt->gt_vni,
551               format_gbp_vxlan_tunnel_layer, gt->gt_layer);
552   if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
553     s = format (s, " BD:%d bd-index:%d", gt->gt_bd_rd_id, gt->gt_bd_index);
554   else
555     s = format (s, " RD:%d fib-index:[%d,%d]",
556                 gt->gt_bd_rd_id,
557                 gt->gt_fib_index[FIB_PROTOCOL_IP4],
558                 gt->gt_fib_index[FIB_PROTOCOL_IP6]);
559
560   s = format (s, " children:[");
561   vec_foreach (vxri, gt->gt_tuns)
562   {
563     s = format (s, "%U, ", format_vxlan_tunnel_ref, *vxri);
564   }
565   s = format (s, "]");
566
567   return s;
568 }
569
570 typedef struct gbp_vxlan_tx_trace_t_
571 {
572   u32 vni;
573 } gbp_vxlan_tx_trace_t;
574
575 u8 *
576 format_gbp_vxlan_tx_trace (u8 * s, va_list * args)
577 {
578   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
579   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
580   gbp_vxlan_tx_trace_t *t = va_arg (*args, gbp_vxlan_tx_trace_t *);
581
582   s = format (s, "GBP-VXLAN: vni:%d", t->vni);
583
584   return (s);
585 }
586
587 clib_error_t *
588 gbp_vxlan_interface_admin_up_down (vnet_main_t * vnm,
589                                    u32 hw_if_index, u32 flags)
590 {
591   vnet_hw_interface_t *hi;
592   u32 ti;
593
594   hi = vnet_get_hw_interface (vnm, hw_if_index);
595
596   if (NULL == gbp_vxlan_tunnel_db ||
597       hi->sw_if_index >= vec_len (gbp_vxlan_tunnel_db))
598     return (NULL);
599
600   ti = gbp_vxlan_tunnel_db[hi->sw_if_index];
601
602   if (~0 == ti)
603     /* not one of ours */
604     return (NULL);
605
606   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
607     vnet_hw_interface_set_flags (vnm, hw_if_index,
608                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
609   else
610     vnet_hw_interface_set_flags (vnm, hw_if_index, 0);
611
612   return (NULL);
613 }
614
615 static uword
616 gbp_vxlan_interface_tx (vlib_main_t * vm,
617                         vlib_node_runtime_t * node, vlib_frame_t * frame)
618 {
619   clib_warning ("you shouldn't be here, leaking buffers...");
620   return frame->n_vectors;
621 }
622
623 /* *INDENT-OFF* */
624 VNET_DEVICE_CLASS (gbp_vxlan_device_class) = {
625   .name = "GBP VXLAN tunnel-template",
626   .format_device_name = format_gbp_vxlan_tunnel_name,
627   .format_device = format_gbp_vxlan_tunnel,
628   .format_tx_trace = format_gbp_vxlan_tx_trace,
629   .admin_up_down_function = gbp_vxlan_interface_admin_up_down,
630   .tx_function = gbp_vxlan_interface_tx,
631 };
632
633 VNET_HW_INTERFACE_CLASS (gbp_vxlan_hw_interface_class) = {
634   .name = "GBP-VXLAN",
635   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
636 };
637 /* *INDENT-ON* */
638
639 int
640 gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
641                       u32 bd_rd_id, u32 * sw_if_indexp)
642 {
643   gbp_vxlan_tunnel_t *gt;
644   index_t gti;
645   uword *p;
646   int rv;
647
648   rv = 0;
649   p = hash_get (gv_db, vni);
650
651   GBP_VXLAN_TUN_DBG ("add: %d %d %d", vni, layer, bd_rd_id);
652
653   if (NULL == p)
654     {
655       vnet_sw_interface_t *si;
656       vnet_hw_interface_t *hi;
657       index_t gbi, grdi;
658       vnet_main_t *vnm;
659
660       gbi = grdi = INDEX_INVALID;
661
662       if (layer == GBP_VXLAN_TUN_L2)
663         {
664           gbi = gbp_bridge_domain_find_and_lock (bd_rd_id);
665
666           if (INDEX_INVALID == gbi)
667             {
668               return (VNET_API_ERROR_BD_NOT_MODIFIABLE);
669             }
670         }
671       else
672         {
673           grdi = gbp_route_domain_find_and_lock (bd_rd_id);
674
675           if (INDEX_INVALID == grdi)
676             {
677               return (VNET_API_ERROR_NO_SUCH_FIB);
678             }
679         }
680
681       vnm = vnet_get_main ();
682       pool_get (gbp_vxlan_tunnel_pool, gt);
683       gti = gt - gbp_vxlan_tunnel_pool;
684
685       gt->gt_vni = vni;
686       gt->gt_layer = layer;
687       gt->gt_bd_rd_id = bd_rd_id;
688       gt->gt_hw_if_index = vnet_register_interface (vnm,
689                                                     gbp_vxlan_device_class.index,
690                                                     gti,
691                                                     gbp_vxlan_hw_interface_class.index,
692                                                     gti);
693
694       hi = vnet_get_hw_interface (vnm, gt->gt_hw_if_index);
695
696       gt->gt_sw_if_index = hi->sw_if_index;
697
698       /* don't flood packets in a BD to these interfaces */
699       si = vnet_get_sw_interface (vnm, gt->gt_sw_if_index);
700       si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
701
702       if (layer == GBP_VXLAN_TUN_L2)
703         {
704           gbp_bridge_domain_t *gb;
705
706           gb = gbp_bridge_domain_get (gbi);
707
708           gt->gt_gbd = gbi;
709           gt->gt_bd_index = gb->gb_bd_id;
710           gb->gb_vni_sw_if_index = gt->gt_sw_if_index;
711           /* set it up as a GBP interface */
712           gt->gt_itf = gbp_itf_add_and_lock (gt->gt_sw_if_index,
713                                              gt->gt_bd_index);
714           gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
715         }
716       else
717         {
718           gbp_route_domain_t *grd;
719           fib_protocol_t fproto;
720
721           grd = gbp_route_domain_get (grdi);
722
723           gt->gt_grd = grdi;
724           grd->grd_vni_sw_if_index = gt->gt_sw_if_index;
725
726           gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
727
728           ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
729           ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
730
731           FOR_EACH_FIB_IP_PROTOCOL (fproto)
732           {
733             gt->gt_fib_index[fproto] = grd->grd_fib_index[fproto];
734
735             ip_table_bind (fproto, gt->gt_sw_if_index,
736                            grd->grd_table_id[fproto], 1);
737           }
738         }
739
740       /*
741        * save the tunnel by VNI and by sw_if_index
742        */
743       hash_set (gv_db, vni, gti);
744
745       vec_validate (gbp_vxlan_tunnel_db, gt->gt_sw_if_index);
746       gbp_vxlan_tunnel_db[gt->gt_sw_if_index] = gti;
747
748       if (sw_if_indexp)
749         *sw_if_indexp = gt->gt_sw_if_index;
750
751       vxlan_gbp_register_udp_ports ();
752     }
753   else
754     {
755       gti = p[0];
756       rv = VNET_API_ERROR_IF_ALREADY_EXISTS;
757     }
758
759   GBP_VXLAN_TUN_DBG ("add: %U", format_gbp_vxlan_tunnel, gti);
760
761   return (rv);
762 }
763
764 int
765 gbp_vxlan_tunnel_del (u32 vni)
766 {
767   gbp_vxlan_tunnel_t *gt;
768   uword *p;
769
770   p = hash_get (gv_db, vni);
771
772   if (NULL != p)
773     {
774       vnet_main_t *vnm;
775
776       vnm = vnet_get_main ();
777       gt = gbp_vxlan_tunnel_get (p[0]);
778
779       vxlan_gbp_unregister_udp_ports ();
780
781       GBP_VXLAN_TUN_DBG ("del: %U", format_gbp_vxlan_tunnel,
782                          gt - gbp_vxlan_tunnel_pool);
783
784       gbp_endpoint_flush (GBP_ENDPOINT_SRC_DP, gt->gt_sw_if_index);
785       ASSERT (0 == vec_len (gt->gt_tuns));
786       vec_free (gt->gt_tuns);
787
788       if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
789         {
790           gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
791           gbp_itf_unlock (gt->gt_itf);
792           gbp_bridge_domain_unlock (gt->gt_gbd);
793         }
794       else
795         {
796           fib_protocol_t fproto;
797
798           FOR_EACH_FIB_IP_PROTOCOL (fproto)
799             ip_table_bind (fproto, gt->gt_sw_if_index, 0, 0);
800
801           ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
802           ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
803
804           gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
805           gbp_route_domain_unlock (gt->gt_grd);
806         }
807
808       vnet_sw_interface_set_flags (vnm, gt->gt_sw_if_index, 0);
809       vnet_delete_hw_interface (vnm, gt->gt_hw_if_index);
810
811       hash_unset (gv_db, vni);
812       gbp_vxlan_tunnel_db[gt->gt_sw_if_index] = INDEX_INVALID;
813
814       pool_put (gbp_vxlan_tunnel_pool, gt);
815     }
816   else
817     return VNET_API_ERROR_NO_SUCH_ENTRY;
818
819   return (0);
820 }
821
822 static clib_error_t *
823 gbp_vxlan_show (vlib_main_t * vm,
824                 unformat_input_t * input, vlib_cli_command_t * cmd)
825 {
826   gbp_vxlan_walk (gbp_vxlan_tunnel_show_one, vm);
827
828   return (NULL);
829 }
830
831 /*?
832  * Show Group Based Policy VXLAN tunnels
833  *
834  * @cliexpar
835  * @cliexstart{show gbp vxlan}
836  * @cliexend
837  ?*/
838 /* *INDENT-OFF* */
839 VLIB_CLI_COMMAND (gbp_vxlan_show_node, static) = {
840   .path = "show gbp vxlan",
841   .short_help = "show gbp vxlan\n",
842   .function = gbp_vxlan_show,
843 };
844 /* *INDENT-ON* */
845
846 static clib_error_t *
847 gbp_vxlan_init (vlib_main_t * vm)
848 {
849   u32 slot4;
850
851   /*
852    * insert ourselves into the VXLAN-GBP arc to collect the no-tunnel
853    * packets.
854    */
855   slot4 = vlib_node_add_next_with_slot (vm,
856                                         vxlan4_gbp_input_node.index,
857                                         gbp_vxlan4_input_node.index,
858                                         VXLAN_GBP_INPUT_NEXT_NO_TUNNEL);
859   ASSERT (slot4 == VXLAN_GBP_INPUT_NEXT_NO_TUNNEL);
860
861   /* slot6 = vlib_node_add_next_with_slot (vm, */
862   /*                                    vxlan6_gbp_input_node.index, */
863   /*                                    gbp_vxlan6_input_node.index, */
864   /*                                    VXLAN_GBP_INPUT_NEXT_NO_TUNNEL); */
865   /* ASSERT (slot6 == VXLAN_GBP_INPUT_NEXT_NO_TUNNEL); */
866
867   gt_logger = vlib_log_register_class ("gbp", "tun");
868
869   return (NULL);
870 }
871
872 VLIB_INIT_FUNCTION (gbp_vxlan_init);
873
874 /*
875  * fd.io coding-style-patch-verification: ON
876  *
877  * Local Variables:
878  * eval: (c-set-style "gnu")
879  * End:
880  */