GBP: custom-dump functions
[vpp.git] / src / plugins / gbp / gbp_bridge_domain.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_bridge_domain.h>
17 #include <plugins/gbp/gbp_endpoint.h>
18 #include <plugins/gbp/gbp_learn.h>
19
20 #include <vnet/dpo/dvr_dpo.h>
21 #include <vnet/fib/fib_table.h>
22 #include <vnet/l2/l2_input.h>
23 #include <vnet/l2/feat_bitmap.h>
24 #include <vnet/l2/l2_bvi.h>
25 #include <vnet/l2/l2_fib.h>
26
27 /**
28  * Pool of GBP bridge_domains
29  */
30 gbp_bridge_domain_t *gbp_bridge_domain_pool;
31
32 /**
33  * DB of bridge_domains
34  */
35 gbp_bridge_domain_db_t gbp_bridge_domain_db;
36
37 /**
38  * logger
39  */
40 vlib_log_class_t gb_logger;
41
42 #define GBP_BD_DBG(...)                           \
43     vlib_log_debug (gb_logger, __VA_ARGS__);
44
45 index_t
46 gbp_bridge_domain_index (const gbp_bridge_domain_t * gbd)
47 {
48   return (gbd - gbp_bridge_domain_pool);
49 }
50
51 static void
52 gbp_bridge_domain_lock (index_t i)
53 {
54   gbp_bridge_domain_t *gb;
55
56   gb = gbp_bridge_domain_get (i);
57   gb->gb_locks++;
58 }
59
60 u32
61 gbp_bridge_domain_get_bd_id (index_t gbdi)
62 {
63   gbp_bridge_domain_t *gb;
64
65   gb = gbp_bridge_domain_get (gbdi);
66
67   return (gb->gb_bd_id);
68 }
69
70 static index_t
71 gbp_bridge_domain_find (u32 bd_id)
72 {
73   uword *p;
74
75   p = hash_get (gbp_bridge_domain_db.gbd_by_bd_id, bd_id);
76
77   if (NULL != p)
78     return p[0];
79
80   return (INDEX_INVALID);
81 }
82
83 index_t
84 gbp_bridge_domain_find_and_lock (u32 bd_id)
85 {
86   uword *p;
87
88   p = hash_get (gbp_bridge_domain_db.gbd_by_bd_id, bd_id);
89
90   if (NULL != p)
91     {
92       gbp_bridge_domain_lock (p[0]);
93       return p[0];
94     }
95   return (INDEX_INVALID);
96 }
97
98 static void
99 gbp_bridge_domain_db_add (gbp_bridge_domain_t * gb)
100 {
101   index_t gbi = gb - gbp_bridge_domain_pool;
102
103   hash_set (gbp_bridge_domain_db.gbd_by_bd_id, gb->gb_bd_id, gbi);
104   vec_validate_init_empty (gbp_bridge_domain_db.gbd_by_bd_index,
105                            gb->gb_bd_index, INDEX_INVALID);
106   gbp_bridge_domain_db.gbd_by_bd_index[gb->gb_bd_index] = gbi;
107 }
108
109 static void
110 gbp_bridge_domain_db_remove (gbp_bridge_domain_t * gb)
111 {
112   hash_unset (gbp_bridge_domain_db.gbd_by_bd_id, gb->gb_bd_id);
113   gbp_bridge_domain_db.gbd_by_bd_index[gb->gb_bd_index] = INDEX_INVALID;
114 }
115
116 u8 *
117 format_gbp_bridge_domain_flags (u8 * s, va_list * args)
118 {
119   gbp_bridge_domain_flags_t gf = va_arg (*args, gbp_bridge_domain_flags_t);
120
121   if (gf)
122     {
123       if (gf & GBP_BD_FLAG_DO_NOT_LEARN)
124         s = format (s, "do-not-learn");
125     }
126   else
127     {
128       s = format (s, "none");
129     }
130   return (s);
131 }
132
133 static u8 *
134 format_gbp_bridge_domain_ptr (u8 * s, va_list * args)
135 {
136   gbp_bridge_domain_t *gb = va_arg (*args, gbp_bridge_domain_t *);
137   vnet_main_t *vnm = vnet_get_main ();
138
139   if (NULL != gb)
140     s = format (s, "[%d] bd:[%d,%d], bvi:%U uu-flood:%U flags:%U locks:%d",
141                 gb - gbp_bridge_domain_pool,
142                 gb->gb_bd_id,
143                 gb->gb_bd_index,
144                 format_vnet_sw_if_index_name, vnm, gb->gb_bvi_sw_if_index,
145                 format_vnet_sw_if_index_name, vnm, gb->gb_uu_fwd_sw_if_index,
146                 format_gbp_bridge_domain_flags, gb->gb_flags, gb->gb_locks);
147   else
148     s = format (s, "NULL");
149
150   return (s);
151 }
152
153 u8 *
154 format_gbp_bridge_domain (u8 * s, va_list * args)
155 {
156   index_t gbi = va_arg (*args, index_t);
157
158   s =
159     format (s, "%U", format_gbp_bridge_domain_ptr,
160             gbp_bridge_domain_get (gbi));
161
162   return (s);
163 }
164
165 int
166 gbp_bridge_domain_add_and_lock (u32 bd_id,
167                                 gbp_bridge_domain_flags_t flags,
168                                 u32 bvi_sw_if_index,
169                                 u32 uu_fwd_sw_if_index,
170                                 u32 bm_flood_sw_if_index)
171 {
172   gbp_bridge_domain_t *gb;
173   index_t gbi;
174
175   gbi = gbp_bridge_domain_find (bd_id);
176
177   if (INDEX_INVALID == gbi)
178     {
179       u32 bd_index;
180
181       bd_index = bd_find_index (&bd_main, bd_id);
182
183       if (~0 == bd_index)
184         return (VNET_API_ERROR_BD_NOT_MODIFIABLE);
185
186       /*
187        * unset learning in the bridge
188        */
189       bd_set_flags (vlib_get_main (), bd_index, L2_LEARN, 0);
190
191       pool_get (gbp_bridge_domain_pool, gb);
192       memset (gb, 0, sizeof (*gb));
193
194       gb->gb_bd_id = bd_id;
195       gb->gb_bd_index = bd_index;
196       gb->gb_uu_fwd_sw_if_index = uu_fwd_sw_if_index;
197       gb->gb_bvi_sw_if_index = bvi_sw_if_index;
198       gb->gb_bm_flood_sw_if_index = bm_flood_sw_if_index;
199       gb->gb_locks = 1;
200       gb->gb_flags = flags;
201
202       /*
203        * Set the BVI and uu-flood interfaces into the BD
204        */
205       set_int_l2_mode (vlib_get_main (), vnet_get_main (),
206                        MODE_L2_BRIDGE, gb->gb_bvi_sw_if_index,
207                        bd_index, L2_BD_PORT_TYPE_BVI, 0, 0);
208       if (~0 != gb->gb_uu_fwd_sw_if_index)
209         {
210           set_int_l2_mode (vlib_get_main (), vnet_get_main (),
211                            MODE_L2_BRIDGE, gb->gb_uu_fwd_sw_if_index,
212                            bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
213         }
214       if (~0 != gb->gb_bm_flood_sw_if_index)
215         {
216           set_int_l2_mode (vlib_get_main (), vnet_get_main (),
217                            MODE_L2_BRIDGE, gb->gb_bm_flood_sw_if_index,
218                            bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
219           gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
220         }
221
222       /*
223        * Add the BVI's MAC to the L2FIB
224        */
225       l2fib_add_entry (vnet_sw_interface_get_hw_address
226                        (vnet_get_main (), gb->gb_bvi_sw_if_index),
227                        gb->gb_bd_index, gb->gb_bvi_sw_if_index,
228                        (L2FIB_ENTRY_RESULT_FLAG_STATIC |
229                         L2FIB_ENTRY_RESULT_FLAG_BVI));
230
231       gbp_bridge_domain_db_add (gb);
232     }
233   else
234     {
235       gb = gbp_bridge_domain_get (gbi);
236       gb->gb_locks++;
237     }
238
239   GBP_BD_DBG ("add: %U", format_gbp_bridge_domain_ptr, gb);
240
241   return (0);
242 }
243
244 void
245 gbp_bridge_domain_unlock (index_t index)
246 {
247   gbp_bridge_domain_t *gb;
248
249   gb = gbp_bridge_domain_get (index);
250
251   gb->gb_locks--;
252
253   if (0 == gb->gb_locks)
254     {
255       GBP_BD_DBG ("destroy: %U", format_gbp_bridge_domain_ptr, gb);
256
257       l2fib_del_entry (vnet_sw_interface_get_hw_address
258                        (vnet_get_main (), gb->gb_bvi_sw_if_index),
259                        gb->gb_bd_index, gb->gb_bvi_sw_if_index);
260
261       set_int_l2_mode (vlib_get_main (), vnet_get_main (),
262                        MODE_L3, gb->gb_bvi_sw_if_index,
263                        gb->gb_bd_index, L2_BD_PORT_TYPE_BVI, 0, 0);
264       if (~0 != gb->gb_uu_fwd_sw_if_index)
265         {
266           set_int_l2_mode (vlib_get_main (), vnet_get_main (),
267                            MODE_L3, gb->gb_uu_fwd_sw_if_index,
268                            gb->gb_bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
269         }
270       if (~0 != gb->gb_bm_flood_sw_if_index)
271         {
272           set_int_l2_mode (vlib_get_main (), vnet_get_main (),
273                            MODE_L3, gb->gb_bm_flood_sw_if_index,
274                            gb->gb_bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
275           gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
276         }
277
278       gbp_bridge_domain_db_remove (gb);
279
280       pool_put (gbp_bridge_domain_pool, gb);
281     }
282 }
283
284 int
285 gbp_bridge_domain_delete (u32 bd_id)
286 {
287   index_t gbi;
288
289   GBP_BD_DBG ("del: %d", bd_id);
290   gbi = gbp_bridge_domain_find (bd_id);
291
292   if (INDEX_INVALID != gbi)
293     {
294       GBP_BD_DBG ("del: %U", format_gbp_bridge_domain, gbi);
295       gbp_bridge_domain_unlock (gbi);
296
297       return (0);
298     }
299
300   return (VNET_API_ERROR_NO_SUCH_ENTRY);
301 }
302
303 void
304 gbp_bridge_domain_walk (gbp_bridge_domain_cb_t cb, void *ctx)
305 {
306   gbp_bridge_domain_t *gbpe;
307
308   /* *INDENT-OFF* */
309   pool_foreach(gbpe, gbp_bridge_domain_pool,
310   {
311     if (!cb(gbpe, ctx))
312       break;
313   });
314   /* *INDENT-ON* */
315 }
316
317 static clib_error_t *
318 gbp_bridge_domain_cli (vlib_main_t * vm,
319                        unformat_input_t * input, vlib_cli_command_t * cmd)
320 {
321   vnet_main_t *vnm = vnet_get_main ();
322   gbp_bridge_domain_flags_t flags;
323   u32 bm_flood_sw_if_index = ~0;
324   u32 uu_fwd_sw_if_index = ~0;
325   u32 bvi_sw_if_index = ~0;
326   u32 bd_id = ~0;
327   u8 add = 1;
328
329   flags = GBP_BD_FLAG_NONE;
330
331   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
332     {
333       if (unformat (input, "bvi %U", unformat_vnet_sw_interface,
334                     vnm, &bvi_sw_if_index))
335         ;
336       else if (unformat (input, "uu-fwd %U", unformat_vnet_sw_interface,
337                          vnm, &uu_fwd_sw_if_index))
338         ;
339       else if (unformat (input, "bm-flood %U", unformat_vnet_sw_interface,
340                          vnm, &bm_flood_sw_if_index))
341         ;
342       else if (unformat (input, "add"))
343         add = 1;
344       else if (unformat (input, "del"))
345         add = 0;
346       else if (unformat (input, "flags &d", &flags))
347         add = 0;
348       else if (unformat (input, "bd %d", &bd_id))
349         ;
350       else
351         break;
352     }
353
354   if (~0 == bd_id)
355     return clib_error_return (0, "BD-ID must be specified");
356
357   if (add)
358     {
359       if (~0 == bvi_sw_if_index)
360         return clib_error_return (0, "interface must be specified");
361
362       gbp_bridge_domain_add_and_lock (bd_id, flags,
363                                       bvi_sw_if_index,
364                                       uu_fwd_sw_if_index,
365                                       bm_flood_sw_if_index);
366     }
367   else
368     gbp_bridge_domain_delete (bd_id);
369
370   return (NULL);
371 }
372
373 /*?
374  * Configure a GBP bridge-domain
375  *
376  * @cliexpar
377  * @cliexstart{set gbp bridge-domain [del] bd <ID> bvi <interface> uu-flood <interface>}
378  * @cliexend
379  ?*/
380 /* *INDENT-OFF* */
381 VLIB_CLI_COMMAND (gbp_bridge_domain_cli_node, static) = {
382   .path = "gbp bridge-domain",
383   .short_help = "gbp bridge-domain [del] bd <ID> bvi <interface> uu-flood <interface>",
384   .function = gbp_bridge_domain_cli,
385 };
386
387 static int
388 gbp_bridge_domain_show_one (gbp_bridge_domain_t *gb, void *ctx)
389 {
390   vlib_main_t *vm;
391
392   vm = ctx;
393   vlib_cli_output (vm, "  %U", format_gbp_bridge_domain_ptr, gb);
394
395   return (1);
396 }
397
398 static clib_error_t *
399 gbp_bridge_domain_show (vlib_main_t * vm,
400                    unformat_input_t * input, vlib_cli_command_t * cmd)
401 {
402   vlib_cli_output (vm, "Bridge-Domains:");
403   gbp_bridge_domain_walk (gbp_bridge_domain_show_one, vm);
404
405   return (NULL);
406 }
407
408
409 /*?
410  * Show Group Based Policy Bridge_Domains and derived information
411  *
412  * @cliexpar
413  * @cliexstart{show gbp bridge_domain}
414  * @cliexend
415  ?*/
416 /* *INDENT-OFF* */
417 VLIB_CLI_COMMAND (gbp_bridge_domain_show_node, static) = {
418   .path = "show gbp bridge-domain",
419   .short_help = "show gbp bridge-domain\n",
420   .function = gbp_bridge_domain_show,
421 };
422 /* *INDENT-ON* */
423
424 static clib_error_t *
425 gbp_bridge_domain_init (vlib_main_t * vm)
426 {
427   gb_logger = vlib_log_register_class ("gbp", "bd");
428
429   return (NULL);
430 }
431
432 VLIB_INIT_FUNCTION (gbp_bridge_domain_init);
433
434 /*
435  * fd.io coding-style-patch-verification: ON
436  *
437  * Local Variables:
438  * eval: (c-set-style "gnu")
439  * End:
440  */