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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <plugins/gbp/gbp_bridge_domain.h>
17 #include <plugins/gbp/gbp_route_domain.h>
18 #include <plugins/gbp/gbp_endpoint.h>
19 #include <plugins/gbp/gbp_learn.h>
21 #include <vnet/dpo/dvr_dpo.h>
22 #include <vnet/fib/fib_table.h>
23 #include <vnet/l2/l2_input.h>
24 #include <vnet/l2/feat_bitmap.h>
25 #include <vnet/l2/l2_bvi.h>
26 #include <vnet/l2/l2_fib.h>
29 * Pool of GBP bridge_domains
31 gbp_bridge_domain_t *gbp_bridge_domain_pool;
34 * DB of bridge_domains
36 gbp_bridge_domain_db_t gbp_bridge_domain_db;
39 * Map of BD index to contract scope
41 gbp_scope_t *gbp_scope_by_bd_index;
46 vlib_log_class_t gb_logger;
48 #define GBP_BD_DBG(...) \
49 vlib_log_debug (gb_logger, __VA_ARGS__);
52 gbp_bridge_domain_index (const gbp_bridge_domain_t * gbd)
54 return (gbd - gbp_bridge_domain_pool);
58 gbp_bridge_domain_lock (index_t i)
60 gbp_bridge_domain_t *gb;
62 gb = gbp_bridge_domain_get (i);
67 gbp_bridge_domain_get_bd_id (index_t gbdi)
69 gbp_bridge_domain_t *gb;
71 gb = gbp_bridge_domain_get (gbdi);
73 return (gb->gb_bd_id);
77 gbp_bridge_domain_find (u32 bd_id)
81 p = hash_get (gbp_bridge_domain_db.gbd_by_bd_id, bd_id);
86 return (INDEX_INVALID);
90 gbp_bridge_domain_find_and_lock (u32 bd_id)
94 p = hash_get (gbp_bridge_domain_db.gbd_by_bd_id, bd_id);
98 gbp_bridge_domain_lock (p[0]);
101 return (INDEX_INVALID);
105 gbp_bridge_domain_db_add (gbp_bridge_domain_t * gb)
107 index_t gbi = gb - gbp_bridge_domain_pool;
109 hash_set (gbp_bridge_domain_db.gbd_by_bd_id, gb->gb_bd_id, gbi);
110 vec_validate_init_empty (gbp_bridge_domain_db.gbd_by_bd_index,
111 gb->gb_bd_index, INDEX_INVALID);
112 gbp_bridge_domain_db.gbd_by_bd_index[gb->gb_bd_index] = gbi;
116 gbp_bridge_domain_db_remove (gbp_bridge_domain_t * gb)
118 hash_unset (gbp_bridge_domain_db.gbd_by_bd_id, gb->gb_bd_id);
119 gbp_bridge_domain_db.gbd_by_bd_index[gb->gb_bd_index] = INDEX_INVALID;
123 format_gbp_bridge_domain_flags (u8 * s, va_list * args)
125 gbp_bridge_domain_flags_t gf = va_arg (*args, gbp_bridge_domain_flags_t);
129 if (gf & GBP_BD_FLAG_DO_NOT_LEARN)
130 s = format (s, "do-not-learn ");
131 if (gf & GBP_BD_FLAG_UU_FWD_DROP)
132 s = format (s, "uu-fwd-drop ");
133 if (gf & GBP_BD_FLAG_MCAST_DROP)
134 s = format (s, "mcast-drop ");
135 if (gf & GBP_BD_FLAG_UCAST_ARP)
136 s = format (s, "ucast-arp ");
140 s = format (s, "none");
146 format_gbp_bridge_domain_ptr (u8 * s, va_list * args)
148 gbp_bridge_domain_t *gb = va_arg (*args, gbp_bridge_domain_t *);
149 vnet_main_t *vnm = vnet_get_main ();
152 s = format (s, "[%d] bd:[%d,%d], bvi:%U uu-flood:%U flags:%U locks:%d",
153 gb - gbp_bridge_domain_pool,
156 format_vnet_sw_if_index_name, vnm, gb->gb_bvi_sw_if_index,
157 format_vnet_sw_if_index_name, vnm, gb->gb_uu_fwd_sw_if_index,
158 format_gbp_bridge_domain_flags, gb->gb_flags, gb->gb_locks);
160 s = format (s, "NULL");
166 format_gbp_bridge_domain (u8 * s, va_list * args)
168 index_t gbi = va_arg (*args, index_t);
171 format (s, "%U", format_gbp_bridge_domain_ptr,
172 gbp_bridge_domain_get (gbi));
178 gbp_bridge_domain_add_and_lock (u32 bd_id,
180 gbp_bridge_domain_flags_t flags,
182 u32 uu_fwd_sw_if_index,
183 u32 bm_flood_sw_if_index)
185 gbp_bridge_domain_t *gb;
188 gbi = gbp_bridge_domain_find (bd_id);
190 if (INDEX_INVALID == gbi)
192 gbp_route_domain_t *gr;
195 bd_index = bd_find_index (&bd_main, bd_id);
198 return (VNET_API_ERROR_BD_NOT_MODIFIABLE);
200 bd_flags_t bd_flags = L2_LEARN;
201 if (flags & GBP_BD_FLAG_UU_FWD_DROP)
202 bd_flags |= L2_UU_FLOOD;
203 if (flags & GBP_BD_FLAG_MCAST_DROP)
204 bd_flags |= L2_FLOOD;
206 pool_get (gbp_bridge_domain_pool, gb);
207 memset (gb, 0, sizeof (*gb));
209 gb->gb_bd_id = bd_id;
210 gb->gb_bd_index = bd_index;
211 gb->gb_uu_fwd_sw_if_index = uu_fwd_sw_if_index;
212 gb->gb_bvi_sw_if_index = bvi_sw_if_index;
213 gb->gb_bm_flood_sw_if_index = bm_flood_sw_if_index;
215 gb->gb_flags = flags;
216 gb->gb_rdi = gbp_route_domain_find_and_lock (rd_id);
219 * set the scope from the BD's RD's scope
221 gr = gbp_route_domain_get (gb->gb_rdi);
222 vec_validate (gbp_scope_by_bd_index, gb->gb_bd_index);
223 gbp_scope_by_bd_index[gb->gb_bd_index] = gr->grd_scope;
226 * Set the BVI and uu-flood interfaces into the BD
228 set_int_l2_mode (vlib_get_main (), vnet_get_main (),
229 MODE_L2_BRIDGE, gb->gb_bvi_sw_if_index,
230 bd_index, L2_BD_PORT_TYPE_BVI, 0, 0);
232 if ((!(flags & GBP_BD_FLAG_UU_FWD_DROP)
233 || (flags & GBP_BD_FLAG_UCAST_ARP))
234 && ~0 != gb->gb_uu_fwd_sw_if_index)
236 set_int_l2_mode (vlib_get_main (), vnet_get_main (),
237 MODE_L2_BRIDGE, gb->gb_uu_fwd_sw_if_index,
238 bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
240 if (!(flags & GBP_BD_FLAG_MCAST_DROP)
241 && ~0 != gb->gb_bm_flood_sw_if_index)
243 set_int_l2_mode (vlib_get_main (), vnet_get_main (),
244 MODE_L2_BRIDGE, gb->gb_bm_flood_sw_if_index,
245 bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
246 gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
250 * unset learning in the bridge + any flag(s) set above
252 bd_set_flags (vlib_get_main (), bd_index, bd_flags, 0);
254 if (flags & GBP_BD_FLAG_UCAST_ARP)
256 bd_flags = L2_ARP_UFWD;
257 bd_set_flags (vlib_get_main (), bd_index, bd_flags, 1);
261 * Add the BVI's MAC to the L2FIB
263 l2fib_add_entry (vnet_sw_interface_get_hw_address
264 (vnet_get_main (), gb->gb_bvi_sw_if_index),
265 gb->gb_bd_index, gb->gb_bvi_sw_if_index,
266 (L2FIB_ENTRY_RESULT_FLAG_STATIC |
267 L2FIB_ENTRY_RESULT_FLAG_BVI));
269 gbp_bridge_domain_db_add (gb);
273 gb = gbp_bridge_domain_get (gbi);
277 GBP_BD_DBG ("add: %U", format_gbp_bridge_domain_ptr, gb);
283 gbp_bridge_domain_unlock (index_t index)
285 gbp_bridge_domain_t *gb;
287 gb = gbp_bridge_domain_get (index);
291 if (0 == gb->gb_locks)
293 GBP_BD_DBG ("destroy: %U", format_gbp_bridge_domain_ptr, gb);
295 l2fib_del_entry (vnet_sw_interface_get_hw_address
296 (vnet_get_main (), gb->gb_bvi_sw_if_index),
297 gb->gb_bd_index, gb->gb_bvi_sw_if_index);
299 set_int_l2_mode (vlib_get_main (), vnet_get_main (),
300 MODE_L3, gb->gb_bvi_sw_if_index,
301 gb->gb_bd_index, L2_BD_PORT_TYPE_BVI, 0, 0);
302 if (~0 != gb->gb_uu_fwd_sw_if_index)
304 set_int_l2_mode (vlib_get_main (), vnet_get_main (),
305 MODE_L3, gb->gb_uu_fwd_sw_if_index,
306 gb->gb_bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
308 if (~0 != gb->gb_bm_flood_sw_if_index)
310 set_int_l2_mode (vlib_get_main (), vnet_get_main (),
311 MODE_L3, gb->gb_bm_flood_sw_if_index,
312 gb->gb_bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
313 gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
316 gbp_bridge_domain_db_remove (gb);
317 gbp_route_domain_unlock (gb->gb_rdi);
319 pool_put (gbp_bridge_domain_pool, gb);
324 gbp_bridge_domain_delete (u32 bd_id)
328 GBP_BD_DBG ("del: %d", bd_id);
329 gbi = gbp_bridge_domain_find (bd_id);
331 if (INDEX_INVALID != gbi)
333 GBP_BD_DBG ("del: %U", format_gbp_bridge_domain, gbi);
334 gbp_bridge_domain_unlock (gbi);
339 return (VNET_API_ERROR_NO_SUCH_ENTRY);
343 gbp_bridge_domain_walk (gbp_bridge_domain_cb_t cb, void *ctx)
345 gbp_bridge_domain_t *gbpe;
348 pool_foreach(gbpe, gbp_bridge_domain_pool,
356 static clib_error_t *
357 gbp_bridge_domain_cli (vlib_main_t * vm,
358 unformat_input_t * input, vlib_cli_command_t * cmd)
360 vnet_main_t *vnm = vnet_get_main ();
361 gbp_bridge_domain_flags_t flags;
362 u32 bm_flood_sw_if_index = ~0;
363 u32 uu_fwd_sw_if_index = ~0;
364 u32 bd_id = ~0, rd_id = ~0;
365 u32 bvi_sw_if_index = ~0;
368 flags = GBP_BD_FLAG_NONE;
370 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
372 if (unformat (input, "bvi %U", unformat_vnet_sw_interface,
373 vnm, &bvi_sw_if_index))
375 else if (unformat (input, "uu-fwd %U", unformat_vnet_sw_interface,
376 vnm, &uu_fwd_sw_if_index))
378 else if (unformat (input, "bm-flood %U", unformat_vnet_sw_interface,
379 vnm, &bm_flood_sw_if_index))
381 else if (unformat (input, "add"))
383 else if (unformat (input, "del"))
385 else if (unformat (input, "flags %d", &flags))
387 else if (unformat (input, "bd %d", &bd_id))
389 else if (unformat (input, "rd %d", &rd_id))
396 return clib_error_return (0, "BD-ID must be specified");
398 return clib_error_return (0, "RD-ID must be specified");
402 if (~0 == bvi_sw_if_index)
403 return clib_error_return (0, "interface must be specified");
405 gbp_bridge_domain_add_and_lock (bd_id, rd_id,
409 bm_flood_sw_if_index);
412 gbp_bridge_domain_delete (bd_id);
418 * Configure a GBP bridge-domain
421 * @cliexstart{gbp bridge-domain [del] bd <ID> bvi <interface> [uu-fwd <interface>] [bm-flood <interface>] [flags <flags>]}
425 VLIB_CLI_COMMAND (gbp_bridge_domain_cli_node, static) = {
426 .path = "gbp bridge-domain",
427 .short_help = "gbp bridge-domain [del] bd <ID> bvi <interface> [uu-fwd <interface>] [bm-flood <interface>] [flags <flags>]",
428 .function = gbp_bridge_domain_cli,
432 gbp_bridge_domain_show_one (gbp_bridge_domain_t *gb, void *ctx)
437 vlib_cli_output (vm, " %U", format_gbp_bridge_domain_ptr, gb);
442 static clib_error_t *
443 gbp_bridge_domain_show (vlib_main_t * vm,
444 unformat_input_t * input, vlib_cli_command_t * cmd)
446 vlib_cli_output (vm, "Bridge-Domains:");
447 gbp_bridge_domain_walk (gbp_bridge_domain_show_one, vm);
454 * Show Group Based Policy Bridge_Domains and derived information
457 * @cliexstart{show gbp bridge_domain}
461 VLIB_CLI_COMMAND (gbp_bridge_domain_show_node, static) = {
462 .path = "show gbp bridge-domain",
463 .short_help = "show gbp bridge-domain\n",
464 .function = gbp_bridge_domain_show,
468 static clib_error_t *
469 gbp_bridge_domain_init (vlib_main_t * vm)
471 gb_logger = vlib_log_register_class ("gbp", "bd");
476 VLIB_INIT_FUNCTION (gbp_bridge_domain_init);
479 * fd.io coding-style-patch-verification: ON
482 * eval: (c-set-style "gnu")