2 * l2_bd.c : layer 2 bridge domain
4 * Copyright (c) 2013 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/ip/format.h>
23 #include <vnet/l2/l2_input.h>
24 #include <vnet/l2/feat_bitmap.h>
25 #include <vnet/l2/l2_bd.h>
26 #include <vnet/l2/l2_fib.h>
27 #include <vnet/l2/l2_vtr.h>
28 #include <vnet/ip/ip4_packet.h>
29 #include <vnet/ip/ip6_packet.h>
31 #include <vppinfra/error.h>
32 #include <vppinfra/hash.h>
33 #include <vppinfra/vec.h>
37 * @brief Ethernet Bridge Domain.
39 * Code in this file manages Layer 2 bridge domains.
46 Init bridge domain if not done already.
47 For feature bitmap, set all bits except ARP termination
50 bd_validate (l2_bridge_domain_t * bd_config)
52 if (!bd_is_valid (bd_config))
54 bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM;
55 bd_config->bvi_sw_if_index = ~0;
56 bd_config->members = 0;
57 bd_config->flood_count = 0;
58 bd_config->tun_master_count = 0;
59 bd_config->tun_normal_count = 0;
60 bd_config->mac_by_ip4 = 0;
61 bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t),
67 bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id)
75 while (hash_get (bdm->bd_index_by_bd_id, bd_id))
80 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
85 rv = clib_bitmap_first_clear (bdm->bd_index_bitmap);
87 /* mark this index busy */
88 bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, rv, 1);
90 hash_set (bdm->bd_index_by_bd_id, bd_id, rv);
92 vec_validate (l2input_main.bd_configs, rv);
93 l2input_main.bd_configs[rv].bd_id = bd_id;
99 bd_delete_bd_index (bd_main_t * bdm, u32 bd_id)
104 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
110 /* mark this index clear */
111 bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0);
112 hash_unset (bdm->bd_index_by_bd_id, bd_id);
114 l2input_main.bd_configs[bd_index].bd_id = ~0;
115 l2input_main.bd_configs[bd_index].feature_bitmap = 0;
121 update_flood_count (l2_bridge_domain_t * bd_config)
123 bd_config->flood_count = vec_len (bd_config->members) -
124 (bd_config->tun_master_count ? bd_config->tun_normal_count : 0);
128 bd_add_member (l2_bridge_domain_t * bd_config, l2_flood_member_t * member)
131 vnet_sw_interface_t *sw_if = vnet_get_sw_interface
132 (vnet_get_main (), member->sw_if_index);
135 * Add one element to the vector
136 * vector is ordered [ bvi, normal/tun_masters..., tun_normals... ]
137 * When flooding, the bvi interface (if present) must be the last member
138 * processed due to how BVI processing can change the packet. To enable
139 * this order, we make the bvi interface the first in the vector and
140 * flooding walks the vector in reverse.
142 switch (sw_if->flood_class)
144 case VNET_FLOOD_CLASS_TUNNEL_MASTER:
145 bd_config->tun_master_count++;
149 case VNET_FLOOD_CLASS_NORMAL:
150 ix = (member->flags & L2_FLOOD_MEMBER_BVI) ? 0 :
151 vec_len (bd_config->members) - bd_config->tun_normal_count;
153 case VNET_FLOOD_CLASS_TUNNEL_NORMAL:
154 ix = vec_len (bd_config->members);
155 bd_config->tun_normal_count++;
159 vec_insert_elts (bd_config->members, member, 1, ix);
160 update_flood_count (bd_config);
163 #define BD_REMOVE_ERROR_OK 0
164 #define BD_REMOVE_ERROR_NOT_FOUND 1
167 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index)
171 /* Find and delete the member */
172 vec_foreach_index (ix, bd_config->members)
174 l2_flood_member_t *m = vec_elt_at_index (bd_config->members, ix);
175 if (m->sw_if_index == sw_if_index)
177 vnet_sw_interface_t *sw_if = vnet_get_sw_interface
178 (vnet_get_main (), sw_if_index);
180 if (sw_if->flood_class != VNET_FLOOD_CLASS_NORMAL)
182 if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_MASTER)
183 bd_config->tun_master_count--;
184 else if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_NORMAL)
185 bd_config->tun_normal_count--;
187 vec_del1 (bd_config->members, ix);
188 update_flood_count (bd_config);
190 return BD_REMOVE_ERROR_OK;
194 return BD_REMOVE_ERROR_NOT_FOUND;
199 l2bd_init (vlib_main_t * vm)
201 bd_main_t *bdm = &bd_main;
203 bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword));
205 * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set
206 * to packet drop only. Thus, packets received from any L2 interface with
207 * uninitialized bd_index of 0 can be dropped safely.
209 bd_index = bd_find_or_add_bd_index (bdm, 0);
210 ASSERT (bd_index == 0);
211 l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP;
215 VLIB_INIT_FUNCTION (l2bd_init);
219 Set the learn/forward/flood flags for the bridge domain.
220 Return 0 if ok, non-zero if for an error.
223 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable)
226 l2_bridge_domain_t *bd_config;
227 u32 feature_bitmap = 0;
229 vec_validate (l2input_main.bd_configs, bd_index);
230 bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
232 bd_validate (bd_config);
234 if (flags & L2_LEARN)
236 feature_bitmap |= L2INPUT_FEAT_LEARN;
240 feature_bitmap |= L2INPUT_FEAT_FWD;
242 if (flags & L2_FLOOD)
244 feature_bitmap |= L2INPUT_FEAT_FLOOD;
246 if (flags & L2_UU_FLOOD)
248 feature_bitmap |= L2INPUT_FEAT_UU_FLOOD;
250 if (flags & L2_ARP_TERM)
252 feature_bitmap |= L2INPUT_FEAT_ARP_TERM;
257 bd_config->feature_bitmap |= feature_bitmap;
261 bd_config->feature_bitmap &= ~feature_bitmap;
268 Set bridge-domain learn enable/disable.
270 set bridge-domain learn <bd_id> [disable]
272 static clib_error_t *
273 bd_learn (vlib_main_t * vm,
274 unformat_input_t * input, vlib_cli_command_t * cmd)
276 bd_main_t *bdm = &bd_main;
277 clib_error_t *error = 0;
282 if (!unformat (input, "%d", &bd_id))
284 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
285 format_unformat_error, input);
289 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
292 return clib_error_return (0, "No such bridge domain %d", bd_id);
297 if (unformat (input, "disable"))
302 /* set the bridge domain flag */
303 if (bd_set_flags (vm, bd_index, L2_LEARN, enable))
306 clib_error_return (0, "bridge-domain id %d out of range", bd_index);
315 * Layer 2 learning can be enabled and disabled on each
316 * interface and on each bridge-domain. Use this command to
317 * manage bridge-domains. It is enabled by default.
320 * Example of how to enable learning (where 200 is the bridge-domain-id):
321 * @cliexcmd{set bridge-domain learn 200}
322 * Example of how to disable learning (where 200 is the bridge-domain-id):
323 * @cliexcmd{set bridge-domain learn 200 disable}
326 VLIB_CLI_COMMAND (bd_learn_cli, static) = {
327 .path = "set bridge-domain learn",
328 .short_help = "set bridge-domain learn <bridge-domain-id> [disable]",
329 .function = bd_learn,
334 Set bridge-domain forward enable/disable.
336 set bridge-domain forward <bd_index> [disable]
338 static clib_error_t *
339 bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
341 bd_main_t *bdm = &bd_main;
342 clib_error_t *error = 0;
347 if (!unformat (input, "%d", &bd_id))
349 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
350 format_unformat_error, input);
354 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
357 return clib_error_return (0, "No such bridge domain %d", bd_id);
362 if (unformat (input, "disable"))
367 /* set the bridge domain flag */
368 if (bd_set_flags (vm, bd_index, L2_FWD, enable))
371 clib_error_return (0, "bridge-domain id %d out of range", bd_index);
381 * Layer 2 unicast forwarding can be enabled and disabled on each
382 * interface and on each bridge-domain. Use this command to
383 * manage bridge-domains. It is enabled by default.
386 * Example of how to enable forwarding (where 200 is the bridge-domain-id):
387 * @cliexcmd{set bridge-domain forward 200}
388 * Example of how to disable forwarding (where 200 is the bridge-domain-id):
389 * @cliexcmd{set bridge-domain forward 200 disable}
392 VLIB_CLI_COMMAND (bd_fwd_cli, static) = {
393 .path = "set bridge-domain forward",
394 .short_help = "set bridge-domain forward <bridge-domain-id> [disable]",
400 Set bridge-domain flood enable/disable.
402 set bridge-domain flood <bd_index> [disable]
404 static clib_error_t *
405 bd_flood (vlib_main_t * vm,
406 unformat_input_t * input, vlib_cli_command_t * cmd)
408 bd_main_t *bdm = &bd_main;
409 clib_error_t *error = 0;
414 if (!unformat (input, "%d", &bd_id))
416 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
417 format_unformat_error, input);
421 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
424 return clib_error_return (0, "No such bridge domain %d", bd_id);
429 if (unformat (input, "disable"))
434 /* set the bridge domain flag */
435 if (bd_set_flags (vm, bd_index, L2_FLOOD, enable))
438 clib_error_return (0, "bridge-domain id %d out of range", bd_index);
447 * Layer 2 flooding can be enabled and disabled on each
448 * interface and on each bridge-domain. Use this command to
449 * manage bridge-domains. It is enabled by default.
452 * Example of how to enable flooding (where 200 is the bridge-domain-id):
453 * @cliexcmd{set bridge-domain flood 200}
454 * Example of how to disable flooding (where 200 is the bridge-domain-id):
455 * @cliexcmd{set bridge-domain flood 200 disable}
458 VLIB_CLI_COMMAND (bd_flood_cli, static) = {
459 .path = "set bridge-domain flood",
460 .short_help = "set bridge-domain flood <bridge-domain-id> [disable]",
461 .function = bd_flood,
466 Set bridge-domain unkown-unicast flood enable/disable.
468 set bridge-domain uu-flood <bd_index> [disable]
470 static clib_error_t *
471 bd_uu_flood (vlib_main_t * vm,
472 unformat_input_t * input, vlib_cli_command_t * cmd)
474 bd_main_t *bdm = &bd_main;
475 clib_error_t *error = 0;
480 if (!unformat (input, "%d", &bd_id))
482 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
483 format_unformat_error, input);
487 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
490 return clib_error_return (0, "No such bridge domain %d", bd_id);
495 if (unformat (input, "disable"))
500 /* set the bridge domain flag */
501 if (bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable))
504 clib_error_return (0, "bridge-domain id %d out of range", bd_index);
513 * Layer 2 unknown-unicast flooding can be enabled and disabled on each
514 * bridge-domain. It is enabled by default.
517 * Example of how to enable unknown-unicast flooding (where 200 is the
519 * @cliexcmd{set bridge-domain uu-flood 200}
520 * Example of how to disable unknown-unicast flooding (where 200 is the bridge-domain-id):
521 * @cliexcmd{set bridge-domain uu-flood 200 disable}
524 VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = {
525 .path = "set bridge-domain uu-flood",
526 .short_help = "set bridge-domain uu-flood <bridge-domain-id> [disable]",
527 .function = bd_uu_flood,
532 Set bridge-domain arp term enable/disable.
534 set bridge-domain arp term <bridge-domain-id> [disable]
536 static clib_error_t *
537 bd_arp_term (vlib_main_t * vm,
538 unformat_input_t * input, vlib_cli_command_t * cmd)
540 bd_main_t *bdm = &bd_main;
541 clib_error_t *error = 0;
546 if (!unformat (input, "%d", &bd_id))
548 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
549 format_unformat_error, input);
553 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
557 return clib_error_return (0, "No such bridge domain %d", bd_id);
560 if (unformat (input, "disable"))
563 /* set the bridge domain flag */
564 if (bd_set_flags (vm, bd_index, L2_ARP_TERM, enable))
567 clib_error_return (0, "bridge-domain id %d out of range", bd_index);
576 * Modify whether or not an existing bridge-domain should terminate and respond
577 * to ARP Requests. ARP Termination is disabled by default.
580 * Example of how to enable ARP termination (where 200 is the bridge-domain-id):
581 * @cliexcmd{set bridge-domain arp term 200}
582 * Example of how to disable ARP termination (where 200 is the bridge-domain-id):
583 * @cliexcmd{set bridge-domain arp term 200 disable}
586 VLIB_CLI_COMMAND (bd_arp_term_cli, static) = {
587 .path = "set bridge-domain arp term",
588 .short_help = "set bridge-domain arp term <bridge-domain-id> [disable]",
589 .function = bd_arp_term,
595 * Add/delete IP address to MAC address mapping.
597 * The clib hash implementation stores uword entries in the hash table.
598 * The hash table mac_by_ip4 is keyed via IP4 address and store the
599 * 6-byte MAC address directly in the hash table entry uword.
601 * @warning This only works for 64-bit processor with 8-byte uword;
602 * which means this code *WILL NOT WORK* for a 32-bit prcessor with
606 bd_add_del_ip_mac (u32 bd_index,
607 u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add)
609 l2input_main_t *l2im = &l2input_main;
610 l2_bridge_domain_t *bd_cfg = l2input_bd_config_from_index (l2im, bd_index);
611 u64 new_mac = *(u64 *) mac_addr;
613 u16 *mac16 = (u16 *) & new_mac;
615 ASSERT (sizeof (uword) == sizeof (u64)); /* make sure uword is 8 bytes */
617 mac16[3] = 0; /* Clear last 2 unsed bytes of the 8-byte MAC address */
620 ip6_address_t *ip6_addr_key;
622 old_mac = (u64 *) hash_get_mem (bd_cfg->mac_by_ip6, ip_addr);
626 { /* new entry - allocate and craete ip6 address key */
627 ip6_addr_key = clib_mem_alloc (sizeof (ip6_address_t));
628 clib_memcpy (ip6_addr_key, ip_addr, sizeof (ip6_address_t));
630 else if (*old_mac == new_mac)
631 { /* same mac entry already exist for ip6 address */
635 { /* updat mac for ip6 address */
636 hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr);
637 ip6_addr_key = (ip6_address_t *) hp->key;
639 hash_set_mem (bd_cfg->mac_by_ip6, ip6_addr_key, new_mac);
643 if (old_mac && (*old_mac == new_mac))
645 hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr);
646 ip6_addr_key = (ip6_address_t *) hp->key;
647 hash_unset_mem (bd_cfg->mac_by_ip6, ip_addr);
648 clib_mem_free (ip6_addr_key);
656 ip4_address_t ip4_addr = *(ip4_address_t *) ip_addr;
657 old_mac = (u64 *) hash_get (bd_cfg->mac_by_ip4, ip4_addr.as_u32);
660 if (old_mac && (*old_mac == new_mac))
661 return 0; /* mac entry already exist */
662 hash_set (bd_cfg->mac_by_ip4, ip4_addr.as_u32, new_mac);
666 if (old_mac && (*old_mac == new_mac))
667 hash_unset (bd_cfg->mac_by_ip4, ip4_addr.as_u32);
676 Set bridge-domain arp entry add/delete.
678 set bridge-domain arp entry <bridge-domain-id> <ip-addr> <mac-addr> [del]
680 static clib_error_t *
681 bd_arp_entry (vlib_main_t * vm,
682 unformat_input_t * input, vlib_cli_command_t * cmd)
684 bd_main_t *bdm = &bd_main;
685 clib_error_t *error = 0;
693 if (!unformat (input, "%d", &bd_id))
695 error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
696 format_unformat_error, input);
700 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
705 return clib_error_return (0, "No such bridge domain %d", bd_id);
707 if (unformat (input, "%U", unformat_ip4_address, ip_addr))
711 else if (unformat (input, "%U", unformat_ip6_address, ip_addr))
717 error = clib_error_return (0, "expecting IP address but got `%U'",
718 format_unformat_error, input);
722 if (!unformat (input, "%U", unformat_ethernet_address, mac_addr))
724 error = clib_error_return (0, "expecting MAC address but got `%U'",
725 format_unformat_error, input);
729 if (unformat (input, "del"))
734 /* set the bridge domain flagAdd IP-MAC entry into bridge domain */
735 if (bd_add_del_ip_mac (bd_index, ip_addr, mac_addr, is_ip6, is_add))
737 error = clib_error_return (0, "MAC %s for IP %U and MAC %U failed",
738 is_add ? "add" : "del",
740 format_ip4_address : format_ip6_address,
741 ip_addr, format_ethernet_address, mac_addr);
749 * Add an ARP entry to an existing bridge-domain.
752 * Example of how to add an ARP entry (where 200 is the bridge-domain-id):
753 * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a}
754 * Example of how to delete an ARP entry (where 200 is the bridge-domain-id):
755 * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a del}
758 VLIB_CLI_COMMAND (bd_arp_entry_cli, static) = {
759 .path = "set bridge-domain arp entry",
760 .short_help = "set bridge-domain arp entry <bridge-domain-id> <ip-addr> <mac-addr> [del]",
761 .function = bd_arp_entry,
766 format_vtr (u8 * s, va_list * args)
768 u32 vtr_op = va_arg (*args, u32);
769 u32 dot1q = va_arg (*args, u32);
770 u32 tag1 = va_arg (*args, u32);
771 u32 tag2 = va_arg (*args, u32);
774 case L2_VTR_DISABLED:
775 return format (s, "none");
777 return format (s, "push-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
779 return format (s, "push-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", tag1,
782 return format (s, "pop-1");
784 return format (s, "pop-2");
785 case L2_VTR_TRANSLATE_1_1:
786 return format (s, "trans-1-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
787 case L2_VTR_TRANSLATE_1_2:
788 return format (s, "trans-1-2 %s %d %d", dot1q ? "dot1q" : "dot1ad",
790 case L2_VTR_TRANSLATE_2_1:
791 return format (s, "trans-2-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
792 case L2_VTR_TRANSLATE_2_2:
793 return format (s, "trans-2-2 %s %d %d", dot1q ? "dot1q" : "dot1ad",
796 return format (s, "none");
801 Show bridge-domain state.
803 show bridge-domain [<bd_index>]
805 static clib_error_t *
806 bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
808 vnet_main_t *vnm = vnet_get_main ();
809 bd_main_t *bdm = &bd_main;
810 clib_error_t *error = 0;
812 l2_bridge_domain_t *bd_config;
822 end = vec_len (l2input_main.bd_configs);
824 if (unformat (input, "%d", &bd_id))
826 if (unformat (input, "detail"))
828 else if (unformat (input, "det"))
830 if (unformat (input, "int"))
832 if (unformat (input, "arp"))
835 p = hash_get (bdm->bd_index_by_bd_id, bd_id);
839 return clib_error_return (0, "No such bridge domain %d", bd_id);
841 vec_validate (l2input_main.bd_configs, bd_index);
842 bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
843 if (bd_is_valid (bd_config))
850 vlib_cli_output (vm, "bridge-domain %d not in use", bd_id);
855 /* Show all bridge-domains that have been initialized */
857 for (bd_index = start; bd_index < end; bd_index++)
859 bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
860 if (bd_is_valid (bd_config))
866 "%=5s %=7s %=10s %=10s %=10s %=10s %=10s %=14s",
867 "ID", "Index", "Learning", "U-Forwrd",
868 "UU-Flood", "Flooding", "ARP-Term",
873 "%=5d %=7d %=10s %=10s %=10s %=10s %=10s %=14U",
874 bd_config->bd_id, bd_index,
875 bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
877 bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on"
879 bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD ?
881 bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ?
883 bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ?
884 "on" : "off", format_vnet_sw_if_index_name_with_NA,
885 vnm, bd_config->bvi_sw_if_index);
889 /* Show all member interfaces */
891 vec_foreach_index (i, bd_config->members)
893 l2_flood_member_t *member =
894 vec_elt_at_index (bd_config->members, i);
895 u32 vtr_opr, dot1q, tag1, tag2;
898 vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=9s%=30s",
899 "Interface", "Index", "SHG", "BVI",
900 "TxFlood", "VLAN-Tag-Rewrite");
902 l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q,
904 vlib_cli_output (vm, "%=30U%=7d%=5d%=5s%=9s%=30U",
905 format_vnet_sw_if_index_name, vnm,
906 member->sw_if_index, member->sw_if_index,
908 member->flags & L2_FLOOD_MEMBER_BVI ? "*" :
909 "-", i < bd_config->flood_count ? "*" : "-",
910 format_vtr, vtr_opr, dot1q, tag1, tag2);
914 if ((detail || arp) &&
915 (bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM))
918 ip6_address_t *ip6_addr;
921 "\n IP4/IP6 to MAC table for ARP Termination");
924 hash_foreach (ip4_addr, mac_addr, bd_config->mac_by_ip4,
926 vlib_cli_output (vm, "%=40U => %=20U",
927 format_ip4_address, &ip4_addr,
928 format_ethernet_address, &mac_addr);
931 hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6,
933 vlib_cli_output (vm, "%=40U => %=20U",
934 format_ip6_address, ip6_addr,
935 format_ethernet_address, &mac_addr);
944 vlib_cli_output (vm, "no bridge-domains in use");
952 * Show a summary of all the bridge-domain instances or detailed view of a
953 * single bridge-domain. Bridge-domains are created by adding an interface
954 * to a bridge using the '<em>set interface l2 bridge</em>' command.
958 * Example of displaying all bridge-domains:
959 * @cliexstart{show bridge-domain}
960 * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
961 * 0 0 off off off off off local0
962 * 200 1 on on on on off N/A
965 * Example of displaying details of a single bridge-domains:
966 * @cliexstart{show bridge-domain 200 detail}
967 * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
968 * 200 1 on on on on off N/A
970 * Interface Index SHG BVI VLAN-Tag-Rewrite
971 * GigabitEthernet0/8/0.200 3 0 - none
972 * GigabitEthernet0/9/0.200 4 0 - none
977 VLIB_CLI_COMMAND (bd_show_cli, static) = {
978 .path = "show bridge-domain",
979 .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp]]",
985 * fd.io coding-style-patch-verification: ON
988 * eval: (c-set-style "gnu")