FD.io VPP  v16.12-rc0-308-g931be3a
Vector Packet Processing
l2_bd.c
Go to the documentation of this file.
1 /*
2  * l2_bd.c : layer 2 bridge domain
3  *
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:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vlib/cli.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>
30 
31 #include <vppinfra/error.h>
32 #include <vppinfra/hash.h>
33 #include <vppinfra/vec.h>
34 
35 /**
36  * @file
37  * @brief Ethernet Bridge Domain.
38  *
39  * Code in this file manages Layer 2 bridge domains.
40  *
41  */
42 
44 
45 /**
46  Init bridge domain if not done already.
47  For feature bitmap, set all bits except ARP termination
48 */
49 void
51 {
52  if (!bd_is_valid (bd_config))
53  {
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->mac_by_ip4 = 0;
58  bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t),
59  sizeof (uword));
60  }
61 }
62 
63 u32
65 {
66  uword *p;
67  u32 rv;
68 
69  if (bd_id == ~0)
70  {
71  bd_id = 0;
72  while (hash_get (bdm->bd_index_by_bd_id, bd_id))
73  bd_id++;
74  }
75  else
76  {
77  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
78  if (p)
79  return (p[0]);
80  }
81 
83 
84  /* mark this index busy */
85  bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, rv, 1);
86 
87  hash_set (bdm->bd_index_by_bd_id, bd_id, rv);
88 
90  l2input_main.bd_configs[rv].bd_id = bd_id;
91 
92  return rv;
93 }
94 
95 int
97 {
98  uword *p;
99  u32 bd_index;
100 
101  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
102  if (p == 0)
103  return -1;
104 
105  bd_index = p[0];
106 
107  /* mark this index clear */
108  bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0);
109  hash_unset (bdm->bd_index_by_bd_id, bd_id);
110 
111  l2input_main.bd_configs[bd_index].bd_id = ~0;
112  l2input_main.bd_configs[bd_index].feature_bitmap = 0;
113 
114  return 0;
115 }
116 
117 void
119 {
120  /*
121  * Add one element to the vector
122  *
123  * When flooding, the bvi interface (if present) must be the last member
124  * processed due to how BVI processing can change the packet. To enable
125  * this order, we make the bvi interface the first in the vector and
126  * flooding walks the vector in reverse.
127  */
128  if ((member->flags == L2_FLOOD_MEMBER_NORMAL) ||
129  (vec_len (bd_config->members) == 0))
130  {
131  vec_add1 (bd_config->members, *member);
132 
133  }
134  else
135  {
136  /* Move 0th element to the end */
137  vec_add1 (bd_config->members, bd_config->members[0]);
138  bd_config->members[0] = *member;
139  }
140 }
141 
142 
143 #define BD_REMOVE_ERROR_OK 0
144 #define BD_REMOVE_ERROR_NOT_FOUND 1
145 
146 u32
147 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index)
148 {
149  u32 ix;
150 
151  /* Find and delete the member */
152  vec_foreach_index (ix, bd_config->members)
153  {
154  if (vec_elt (bd_config->members, ix).sw_if_index == sw_if_index)
155  {
156  vec_del1 (bd_config->members, ix);
157  return BD_REMOVE_ERROR_OK;
158  }
159  }
160 
162 }
163 
164 
165 clib_error_t *
167 {
168  bd_main_t *bdm = &bd_main;
169  u32 bd_index;
170  bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword));
171  /*
172  * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set
173  * to packet drop only. Thus, packets received from any L2 interface with
174  * uninitialized bd_index of 0 can be dropped safely.
175  */
176  bd_index = bd_find_or_add_bd_index (bdm, 0);
177  ASSERT (bd_index == 0);
178  l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP;
179  return 0;
180 }
181 
183 
184 
185 /**
186  Set the learn/forward/flood flags for the bridge domain.
187  Return 0 if ok, non-zero if for an error.
188 */
189 u32
190 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable)
191 {
192 
193  l2_bridge_domain_t *bd_config;
194  u32 feature_bitmap = 0;
195 
197  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
198 
199  bd_validate (bd_config);
200 
201  if (flags & L2_LEARN)
202  {
203  feature_bitmap |= L2INPUT_FEAT_LEARN;
204  }
205  if (flags & L2_FWD)
206  {
207  feature_bitmap |= L2INPUT_FEAT_FWD;
208  }
209  if (flags & L2_FLOOD)
210  {
211  feature_bitmap |= L2INPUT_FEAT_FLOOD;
212  }
213  if (flags & L2_UU_FLOOD)
214  {
215  feature_bitmap |= L2INPUT_FEAT_UU_FLOOD;
216  }
217  if (flags & L2_ARP_TERM)
218  {
219  feature_bitmap |= L2INPUT_FEAT_ARP_TERM;
220  }
221 
222  if (enable)
223  {
224  bd_config->feature_bitmap |= feature_bitmap;
225  }
226  else
227  {
228  bd_config->feature_bitmap &= ~feature_bitmap;
229  }
230 
231  return 0;
232 }
233 
234 /**
235  Set bridge-domain learn enable/disable.
236  The CLI format is:
237  set bridge-domain learn <bd_id> [disable]
238 */
239 static clib_error_t *
241  unformat_input_t * input, vlib_cli_command_t * cmd)
242 {
243  bd_main_t *bdm = &bd_main;
244  clib_error_t *error = 0;
245  u32 bd_index, bd_id;
246  u32 enable;
247  uword *p;
248 
249  if (!unformat (input, "%d", &bd_id))
250  {
251  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
252  format_unformat_error, input);
253  goto done;
254  }
255 
256  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
257 
258  if (p == 0)
259  return clib_error_return (0, "No such bridge domain %d", bd_id);
260 
261  bd_index = p[0];
262 
263  enable = 1;
264  if (unformat (input, "disable"))
265  {
266  enable = 0;
267  }
268 
269  /* set the bridge domain flag */
270  if (bd_set_flags (vm, bd_index, L2_LEARN, enable))
271  {
272  error =
273  clib_error_return (0, "bridge-domain id %d out of range", bd_index);
274  goto done;
275  }
276 
277 done:
278  return error;
279 }
280 
281 /*?
282  * Layer 2 learning can be enabled and disabled on each
283  * interface and on each bridge-domain. Use this command to
284  * manage bridge-domains. It is enabled by default.
285  *
286  * @cliexpar
287  * Example of how to enable learning (where 200 is the bridge-domain-id):
288  * @cliexcmd{set bridge-domain learn 200}
289  * Example of how to disable learning (where 200 is the bridge-domain-id):
290  * @cliexcmd{set bridge-domain learn 200 disable}
291 ?*/
292 /* *INDENT-OFF* */
293 VLIB_CLI_COMMAND (bd_learn_cli, static) = {
294  .path = "set bridge-domain learn",
295  .short_help = "set bridge-domain learn <bridge-domain-id> [disable]",
296  .function = bd_learn,
297 };
298 /* *INDENT-ON* */
299 
300 /**
301  Set bridge-domain forward enable/disable.
302  The CLI format is:
303  set bridge-domain forward <bd_index> [disable]
304 */
305 static clib_error_t *
307 {
308  bd_main_t *bdm = &bd_main;
309  clib_error_t *error = 0;
310  u32 bd_index, bd_id;
311  u32 enable;
312  uword *p;
313 
314  if (!unformat (input, "%d", &bd_id))
315  {
316  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
317  format_unformat_error, input);
318  goto done;
319  }
320 
321  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
322 
323  if (p == 0)
324  return clib_error_return (0, "No such bridge domain %d", bd_id);
325 
326  bd_index = p[0];
327 
328  enable = 1;
329  if (unformat (input, "disable"))
330  {
331  enable = 0;
332  }
333 
334  /* set the bridge domain flag */
335  if (bd_set_flags (vm, bd_index, L2_FWD, enable))
336  {
337  error =
338  clib_error_return (0, "bridge-domain id %d out of range", bd_index);
339  goto done;
340  }
341 
342 done:
343  return error;
344 }
345 
346 
347 /*?
348  * Layer 2 unicast forwarding can be enabled and disabled on each
349  * interface and on each bridge-domain. Use this command to
350  * manage bridge-domains. It is enabled by default.
351  *
352  * @cliexpar
353  * Example of how to enable forwarding (where 200 is the bridge-domain-id):
354  * @cliexcmd{set bridge-domain forward 200}
355  * Example of how to disable forwarding (where 200 is the bridge-domain-id):
356  * @cliexcmd{set bridge-domain forward 200 disable}
357 ?*/
358 /* *INDENT-OFF* */
359 VLIB_CLI_COMMAND (bd_fwd_cli, static) = {
360  .path = "set bridge-domain forward",
361  .short_help = "set bridge-domain forward <bridge-domain-id> [disable]",
362  .function = bd_fwd,
363 };
364 /* *INDENT-ON* */
365 
366 /**
367  Set bridge-domain flood enable/disable.
368  The CLI format is:
369  set bridge-domain flood <bd_index> [disable]
370 */
371 static clib_error_t *
373  unformat_input_t * input, vlib_cli_command_t * cmd)
374 {
375  bd_main_t *bdm = &bd_main;
376  clib_error_t *error = 0;
377  u32 bd_index, bd_id;
378  u32 enable;
379  uword *p;
380 
381  if (!unformat (input, "%d", &bd_id))
382  {
383  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
384  format_unformat_error, input);
385  goto done;
386  }
387 
388  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
389 
390  if (p == 0)
391  return clib_error_return (0, "No such bridge domain %d", bd_id);
392 
393  bd_index = p[0];
394 
395  enable = 1;
396  if (unformat (input, "disable"))
397  {
398  enable = 0;
399  }
400 
401  /* set the bridge domain flag */
402  if (bd_set_flags (vm, bd_index, L2_FLOOD, enable))
403  {
404  error =
405  clib_error_return (0, "bridge-domain id %d out of range", bd_index);
406  goto done;
407  }
408 
409 done:
410  return error;
411 }
412 
413 /*?
414  * Layer 2 flooding can be enabled and disabled on each
415  * interface and on each bridge-domain. Use this command to
416  * manage bridge-domains. It is enabled by default.
417  *
418  * @cliexpar
419  * Example of how to enable flooding (where 200 is the bridge-domain-id):
420  * @cliexcmd{set bridge-domain flood 200}
421  * Example of how to disable flooding (where 200 is the bridge-domain-id):
422  * @cliexcmd{set bridge-domain flood 200 disable}
423 ?*/
424 /* *INDENT-OFF* */
425 VLIB_CLI_COMMAND (bd_flood_cli, static) = {
426  .path = "set bridge-domain flood",
427  .short_help = "set bridge-domain flood <bridge-domain-id> [disable]",
428  .function = bd_flood,
429 };
430 /* *INDENT-ON* */
431 
432 /**
433  Set bridge-domain unkown-unicast flood enable/disable.
434  The CLI format is:
435  set bridge-domain uu-flood <bd_index> [disable]
436 */
437 static clib_error_t *
439  unformat_input_t * input, vlib_cli_command_t * cmd)
440 {
441  bd_main_t *bdm = &bd_main;
442  clib_error_t *error = 0;
443  u32 bd_index, bd_id;
444  u32 enable;
445  uword *p;
446 
447  if (!unformat (input, "%d", &bd_id))
448  {
449  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
450  format_unformat_error, input);
451  goto done;
452  }
453 
454  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
455 
456  if (p == 0)
457  return clib_error_return (0, "No such bridge domain %d", bd_id);
458 
459  bd_index = p[0];
460 
461  enable = 1;
462  if (unformat (input, "disable"))
463  {
464  enable = 0;
465  }
466 
467  /* set the bridge domain flag */
468  if (bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable))
469  {
470  error =
471  clib_error_return (0, "bridge-domain id %d out of range", bd_index);
472  goto done;
473  }
474 
475 done:
476  return error;
477 }
478 
479 /*?
480  * Layer 2 unknown-unicast flooding can be enabled and disabled on each
481  * bridge-domain. It is enabled by default.
482  *
483  * @cliexpar
484  * Example of how to enable unknown-unicast flooding (where 200 is the
485  * bridge-domain-id):
486  * @cliexcmd{set bridge-domain uu-flood 200}
487  * Example of how to disable unknown-unicast flooding (where 200 is the bridge-domain-id):
488  * @cliexcmd{set bridge-domain uu-flood 200 disable}
489 ?*/
490 /* *INDENT-OFF* */
491 VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = {
492  .path = "set bridge-domain uu-flood",
493  .short_help = "set bridge-domain uu-flood <bridge-domain-id> [disable]",
494  .function = bd_uu_flood,
495 };
496 /* *INDENT-ON* */
497 
498 /**
499  Set bridge-domain arp term enable/disable.
500  The CLI format is:
501  set bridge-domain arp term <bridge-domain-id> [disable]
502 */
503 static clib_error_t *
505  unformat_input_t * input, vlib_cli_command_t * cmd)
506 {
507  bd_main_t *bdm = &bd_main;
508  clib_error_t *error = 0;
509  u32 bd_index, bd_id;
510  u32 enable;
511  uword *p;
512 
513  if (!unformat (input, "%d", &bd_id))
514  {
515  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
516  format_unformat_error, input);
517  goto done;
518  }
519 
520  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
521  if (p)
522  bd_index = *p;
523  else
524  return clib_error_return (0, "No such bridge domain %d", bd_id);
525 
526  enable = 1;
527  if (unformat (input, "disable"))
528  enable = 0;
529 
530  /* set the bridge domain flag */
531  if (bd_set_flags (vm, bd_index, L2_ARP_TERM, enable))
532  {
533  error =
534  clib_error_return (0, "bridge-domain id %d out of range", bd_index);
535  goto done;
536  }
537 
538 done:
539  return error;
540 }
541 
542 /*?
543  * Modify whether or not an existing bridge-domain should terminate and respond
544  * to ARP Requests. ARP Termination is disabled by default.
545  *
546  * @cliexpar
547  * Example of how to enable ARP termination (where 200 is the bridge-domain-id):
548  * @cliexcmd{set bridge-domain arp term 200}
549  * Example of how to disable ARP termination (where 200 is the bridge-domain-id):
550  * @cliexcmd{set bridge-domain arp term 200 disable}
551 ?*/
552 /* *INDENT-OFF* */
553 VLIB_CLI_COMMAND (bd_arp_term_cli, static) = {
554  .path = "set bridge-domain arp term",
555  .short_help = "set bridge-domain arp term <bridge-domain-id> [disable]",
556  .function = bd_arp_term,
557 };
558 /* *INDENT-ON* */
559 
560 
561 /**
562  * Add/delete IP address to MAC address mapping.
563  *
564  * The clib hash implementation stores uword entries in the hash table.
565  * The hash table mac_by_ip4 is keyed via IP4 address and store the
566  * 6-byte MAC address directly in the hash table entry uword.
567  *
568  * @warning This only works for 64-bit processor with 8-byte uword;
569  * which means this code *WILL NOT WORK* for a 32-bit prcessor with
570  * 4-byte uword.
571  */
572 u32
574  u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add)
575 {
576  l2input_main_t *l2im = &l2input_main;
577  l2_bridge_domain_t *bd_cfg = l2input_bd_config_from_index (l2im, bd_index);
578  u64 new_mac = *(u64 *) mac_addr;
579  u64 *old_mac;
580  u16 *mac16 = (u16 *) & new_mac;
581 
582  ASSERT (sizeof (uword) == sizeof (u64)); /* make sure uword is 8 bytes */
583 
584  mac16[3] = 0; /* Clear last 2 unsed bytes of the 8-byte MAC address */
585  if (is_ip6)
586  {
587  ip6_address_t *ip6_addr_key;
588  hash_pair_t *hp;
589  old_mac = (u64 *) hash_get_mem (bd_cfg->mac_by_ip6, ip_addr);
590  if (is_add)
591  {
592  if (old_mac == 0)
593  { /* new entry - allocate and craete ip6 address key */
594  ip6_addr_key = clib_mem_alloc (sizeof (ip6_address_t));
595  clib_memcpy (ip6_addr_key, ip_addr, sizeof (ip6_address_t));
596  }
597  else if (*old_mac == new_mac)
598  { /* same mac entry already exist for ip6 address */
599  return 0;
600  }
601  else
602  { /* updat mac for ip6 address */
603  hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr);
604  ip6_addr_key = (ip6_address_t *) hp->key;
605  }
606  hash_set_mem (bd_cfg->mac_by_ip6, ip6_addr_key, new_mac);
607  }
608  else
609  {
610  if (old_mac && (*old_mac == new_mac))
611  {
612  hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr);
613  ip6_addr_key = (ip6_address_t *) hp->key;
614  hash_unset_mem (bd_cfg->mac_by_ip6, ip_addr);
615  clib_mem_free (ip6_addr_key);
616  }
617  else
618  return 1;
619  }
620  }
621  else
622  {
623  ip4_address_t ip4_addr = *(ip4_address_t *) ip_addr;
624  old_mac = (u64 *) hash_get (bd_cfg->mac_by_ip4, ip4_addr.as_u32);
625  if (is_add)
626  {
627  if (old_mac && (*old_mac == new_mac))
628  return 0; /* mac entry already exist */
629  hash_set (bd_cfg->mac_by_ip4, ip4_addr.as_u32, new_mac);
630  }
631  else
632  {
633  if (old_mac && (*old_mac == new_mac))
634  hash_unset (bd_cfg->mac_by_ip4, ip4_addr.as_u32);
635  else
636  return 1;
637  }
638  }
639  return 0;
640 }
641 
642 /**
643  Set bridge-domain arp entry add/delete.
644  The CLI format is:
645  set bridge-domain arp entry <bridge-domain-id> <ip-addr> <mac-addr> [del]
646 */
647 static clib_error_t *
649  unformat_input_t * input, vlib_cli_command_t * cmd)
650 {
651  bd_main_t *bdm = &bd_main;
652  clib_error_t *error = 0;
653  u32 bd_index, bd_id;
654  u8 is_add = 1;
655  u8 is_ip6 = 0;
656  u8 ip_addr[16];
657  u8 mac_addr[6];
658  uword *p;
659 
660  if (!unformat (input, "%d", &bd_id))
661  {
662  error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
663  format_unformat_error, input);
664  goto done;
665  }
666 
667  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
668 
669  if (p)
670  bd_index = *p;
671  else
672  return clib_error_return (0, "No such bridge domain %d", bd_id);
673 
674  if (unformat (input, "%U", unformat_ip4_address, ip_addr))
675  {
676  is_ip6 = 0;
677  }
678  else if (unformat (input, "%U", unformat_ip6_address, ip_addr))
679  {
680  is_ip6 = 1;
681  }
682  else
683  {
684  error = clib_error_return (0, "expecting IP address but got `%U'",
685  format_unformat_error, input);
686  goto done;
687  }
688 
689  if (!unformat (input, "%U", unformat_ethernet_address, mac_addr))
690  {
691  error = clib_error_return (0, "expecting MAC address but got `%U'",
692  format_unformat_error, input);
693  goto done;
694  }
695 
696  if (unformat (input, "del"))
697  {
698  is_add = 0;
699  }
700 
701  /* set the bridge domain flagAdd IP-MAC entry into bridge domain */
702  if (bd_add_del_ip_mac (bd_index, ip_addr, mac_addr, is_ip6, is_add))
703  {
704  error = clib_error_return (0, "MAC %s for IP %U and MAC %U failed",
705  is_add ? "add" : "del",
706  is_ip6 ?
708  ip_addr, format_ethernet_address, mac_addr);
709  }
710 
711 done:
712  return error;
713 }
714 
715 /*?
716  * Add an ARP entry to an existing bridge-domain.
717  *
718  * @cliexpar
719  * Example of how to add an ARP entry (where 200 is the bridge-domain-id):
720  * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a}
721  * Example of how to delete an ARP entry (where 200 is the bridge-domain-id):
722  * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a del}
723 ?*/
724 /* *INDENT-OFF* */
725 VLIB_CLI_COMMAND (bd_arp_entry_cli, static) = {
726  .path = "set bridge-domain arp entry",
727  .short_help = "set bridge-domain arp entry <bridge-domain-id> <ip-addr> <mac-addr> [del]",
728  .function = bd_arp_entry,
729 };
730 /* *INDENT-ON* */
731 
732 u8 *
733 format_vtr (u8 * s, va_list * args)
734 {
735  u32 vtr_op = va_arg (*args, u32);
736  u32 dot1q = va_arg (*args, u32);
737  u32 tag1 = va_arg (*args, u32);
738  u32 tag2 = va_arg (*args, u32);
739  switch (vtr_op)
740  {
741  case L2_VTR_DISABLED:
742  return format (s, "none");
743  case L2_VTR_PUSH_1:
744  return format (s, "push-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
745  case L2_VTR_PUSH_2:
746  return format (s, "push-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", tag1,
747  tag2);
748  case L2_VTR_POP_1:
749  return format (s, "pop-1");
750  case L2_VTR_POP_2:
751  return format (s, "pop-2");
753  return format (s, "trans-1-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
755  return format (s, "trans-1-2 %s %d %d", dot1q ? "dot1q" : "dot1ad",
756  tag1, tag2);
758  return format (s, "trans-2-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
760  return format (s, "trans-2-2 %s %d %d", dot1q ? "dot1q" : "dot1ad",
761  tag1, tag2);
762  default:
763  return format (s, "none");
764  }
765 }
766 
767 /**
768  Show bridge-domain state.
769  The CLI format is:
770  show bridge-domain [<bd_index>]
771 */
772 static clib_error_t *
774 {
775  vnet_main_t *vnm = vnet_get_main ();
776  bd_main_t *bdm = &bd_main;
777  clib_error_t *error = 0;
778  u32 bd_index = ~0;
779  l2_bridge_domain_t *bd_config;
780  u32 start, end;
781  u32 printed;
782  u32 detail = 0;
783  u32 intf = 0;
784  u32 arp = 0;
785  u32 bd_id = ~0;
786  uword *p;
787 
788  start = 0;
790 
791  if (unformat (input, "%d", &bd_id))
792  {
793  if (unformat (input, "detail"))
794  detail = 1;
795  else if (unformat (input, "det"))
796  detail = 1;
797  if (unformat (input, "int"))
798  intf = 1;
799  if (unformat (input, "arp"))
800  arp = 1;
801 
802  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
803  if (p)
804  bd_index = *p;
805  else
806  return clib_error_return (0, "No such bridge domain %d", bd_id);
807 
809  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
810  if (bd_is_valid (bd_config))
811  {
812  start = bd_index;
813  end = start + 1;
814  }
815  else
816  {
817  vlib_cli_output (vm, "bridge-domain %d not in use", bd_id);
818  goto done;
819  }
820  }
821 
822  /* Show all bridge-domains that have been initialized */
823  printed = 0;
824  for (bd_index = start; bd_index < end; bd_index++)
825  {
826  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
827  if (bd_is_valid (bd_config))
828  {
829  if (!printed)
830  {
831  printed = 1;
832  vlib_cli_output (vm,
833  "%=5s %=7s %=10s %=10s %=10s %=10s %=10s %=14s",
834  "ID", "Index", "Learning", "U-Forwrd",
835  "UU-Flood", "Flooding", "ARP-Term",
836  "BVI-Intf");
837  }
838 
839  vlib_cli_output (vm,
840  "%=5d %=7d %=10s %=10s %=10s %=10s %=10s %=14U",
841  bd_config->bd_id, bd_index,
842  bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
843  "on" : "off",
844  bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on"
845  : "off",
846  bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD ?
847  "on" : "off",
848  bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ?
849  "on" : "off",
850  bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ?
852  vnm, bd_config->bvi_sw_if_index);
853 
854  if (detail || intf)
855  {
856  /* Show all member interfaces */
857 
858  l2_flood_member_t *member;
859  u32 header = 0;
860 
861  vec_foreach (member, bd_config->members)
862  {
863  u32 vtr_opr, dot1q, tag1, tag2;
864  if (!header)
865  {
866  header = 1;
867  vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=30s",
868  "Interface", "Index", "SHG", "BVI",
869  "VLAN-Tag-Rewrite");
870  }
871  l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q,
872  &tag1, &tag2);
873  vlib_cli_output (vm, "%=30U%=7d%=5d%=5s%=30U",
875  member->sw_if_index, member->sw_if_index,
876  member->shg,
877  member->flags & L2_FLOOD_MEMBER_BVI ? "*" :
878  "-", format_vtr, vtr_opr, dot1q, tag1, tag2);
879  }
880  }
881 
882  if ((detail || arp) &&
883  (bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM))
884  {
885  u32 ip4_addr;
886  ip6_address_t *ip6_addr;
887  u64 mac_addr;
888  vlib_cli_output (vm,
889  "\n IP4/IP6 to MAC table for ARP Termination");
890 
891  /* *INDENT-OFF* */
892  hash_foreach (ip4_addr, mac_addr, bd_config->mac_by_ip4,
893  ({
894  vlib_cli_output (vm, "%=40U => %=20U",
895  format_ip4_address, &ip4_addr,
896  format_ethernet_address, &mac_addr);
897  }));
898 
899  hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6,
900  ({
901  vlib_cli_output (vm, "%=40U => %=20U",
902  format_ip6_address, ip6_addr,
903  format_ethernet_address, &mac_addr);
904  }));
905  /* *INDENT-ON* */
906  }
907  }
908  }
909 
910  if (!printed)
911  {
912  vlib_cli_output (vm, "no bridge-domains in use");
913  }
914 
915 done:
916  return error;
917 }
918 
919 /*?
920  * Show a summary of all the bridge-domain instances or detailed view of a
921  * single bridge-domain. Bridge-domains are created by adding an interface
922  * to a bridge using the '<em>set interface l2 bridge</em>' command.
923  *
924  * @cliexpar
925  * @parblock
926  * Example of displaying all bridge-domains:
927  * @cliexstart{show bridge-domain}
928  * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
929  * 0 0 off off off off off local0
930  * 200 1 on on on on off N/A
931  * @cliexend
932  *
933  * Example of displaying details of a single bridge-domains:
934  * @cliexstart{show bridge-domain 200 detail}
935  * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
936  * 200 1 on on on on off N/A
937  *
938  * Interface Index SHG BVI VLAN-Tag-Rewrite
939  * GigabitEthernet0/8/0.200 3 0 - none
940  * GigabitEthernet0/9/0.200 4 0 - none
941  * @cliexend
942  * @endparblock
943 ?*/
944 /* *INDENT-OFF* */
945 VLIB_CLI_COMMAND (bd_show_cli, static) = {
946  .path = "show bridge-domain",
947  .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp]]",
948  .function = bd_show,
949 };
950 /* *INDENT-ON* */
951 
952 /*
953  * fd.io coding-style-patch-verification: ON
954  *
955  * Local Variables:
956  * eval: (c-set-style "gnu")
957  * End:
958  */
void bd_validate(l2_bridge_domain_t *bd_config)
Init bridge domain if not done already.
Definition: l2_bd.c:50
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
u32 bd_set_flags(vlib_main_t *vm, u32 bd_index, u32 flags, u32 enable)
Set the learn/forward/flood flags for the bridge domain.
Definition: l2_bd.c:190
#define vec_foreach_index(var, v)
Iterate over vector indices.
#define hash_set(h, key, value)
Definition: hash.h:254
#define L2_FLOOD_MEMBER_NORMAL
Definition: l2_bd.h:41
u8 * format_vnet_sw_if_index_name_with_NA(u8 *s, va_list *args)
Format sw_if_index.
Definition: l2_fib.c:59
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
#define hash_unset(h, key)
Definition: hash.h:260
format_function_t format_ip6_address
Definition: format.h:94
u32 bvi_sw_if_index
Definition: l2_bd.h:65
#define L2_FLOOD
Definition: l2_bd.h:98
#define L2_FWD
Definition: l2_bd.h:97
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
l2_flood_member_t * members
Definition: l2_bd.h:71
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
#define hash_set_mem(h, key, value)
Definition: hash.h:274
u32 bd_remove_member(l2_bridge_domain_t *bd_config, u32 sw_if_index)
Definition: l2_bd.c:147
#define L2_FLOOD_MEMBER_BVI
Definition: l2_bd.h:42
format_function_t format_ip4_address
Definition: format.h:78
format_function_t format_vnet_sw_if_index_name
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
int bd_delete_bd_index(bd_main_t *bdm, u32 bd_id)
Delete a bridge domain.
Definition: l2_bd.c:96
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
void bd_add_member(l2_bridge_domain_t *bd_config, l2_flood_member_t *member)
Definition: l2_bd.c:118
static clib_error_t * bd_fwd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set bridge-domain forward enable/disable.
Definition: l2_bd.c:306
#define hash_foreach(key_var, value_var, h, body)
Definition: hash.h:418
clib_error_t * l2bd_init(vlib_main_t *vm)
Definition: l2_bd.c:166
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define L2_UU_FLOOD
Definition: l2_bd.h:99
unsigned long u64
Definition: types.h:89
#define hash_get_pair(h, key)
Definition: hash.h:251
uword * bd_index_by_bd_id
Definition: l2_bd.h:27
unformat_function_t unformat_ip4_address
Definition: format.h:75
#define BD_REMOVE_ERROR_OK
Definition: l2_bd.c:143
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:637
#define hash_get(h, key)
Definition: hash.h:248
#define hash_unset_mem(h, key)
Definition: hash.h:280
static clib_error_t * bd_arp_entry(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set bridge-domain arp entry add/delete.
Definition: l2_bd.c:648
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:765
static clib_error_t * bd_flood(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set bridge-domain flood enable/disable.
Definition: l2_bd.c:372
uword * bd_index_bitmap
Definition: l2_bd.h:30
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
#define hash_foreach_mem(key_var, value_var, h, body)
Definition: hash.h:437
static u32 bd_is_valid(l2_bridge_domain_t *bd_config)
Definition: l2_bd.h:81
unformat_function_t unformat_ip6_address
Definition: format.h:93
#define BD_REMOVE_ERROR_NOT_FOUND
Definition: l2_bd.c:144
u32 bd_add_del_ip_mac(u32 bd_index, u8 *ip_addr, u8 *mac_addr, u8 is_ip6, u8 is_add)
Add/delete IP address to MAC address mapping.
Definition: l2_bd.c:573
static clib_error_t * bd_learn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set bridge-domain learn enable/disable.
Definition: l2_bd.c:240
#define clib_memcpy(a, b, c)
Definition: string.h:64
uword * mac_by_ip6
Definition: l2_bd.h:75
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
static clib_error_t * bd_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Show bridge-domain state.
Definition: l2_bd.c:773
#define hash_create(elts, value_bytes)
Definition: hash.h:658
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:245
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static_always_inline l2_bridge_domain_t * l2input_bd_config_from_index(l2input_main_t *l2im, u32 bd_index)
Definition: l2_input.h:81
static void clib_mem_free(void *p)
Definition: mem.h:176
static void * clib_mem_alloc(uword size)
Definition: mem.h:109
static clib_error_t * bd_arp_term(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set bridge-domain arp term enable/disable.
Definition: l2_bd.c:504
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
unsigned short u16
Definition: types.h:57
l2input_main_t l2input_main
Definition: l2_input.c:87
u32 bd_find_or_add_bd_index(bd_main_t *bdm, u32 bd_id)
Get or create a bridge domain.
Definition: l2_bd.c:64
u32 feature_bitmap
Definition: l2_bd.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define L2_ARP_TERM
Definition: l2_bd.h:100
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:69
static clib_error_t * bd_uu_flood(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set bridge-domain unkown-unicast flood enable/disable.
Definition: l2_bd.c:438
u8 * format_vtr(u8 *s, va_list *args)
Definition: l2_bd.c:733
#define hash_get_mem(h, key)
Definition: hash.h:268
u32 l2vtr_get(vlib_main_t *vlib_main, vnet_main_t *vnet_main, u32 sw_if_index, u32 *vtr_op, u32 *push_dot1q, u32 *vtr_tag1, u32 *vtr_tag2)
Get vtag tag rewrite on the given interface.
Definition: l2_vtr.c:350
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define vec_foreach(var, vec)
Vector iterator.
uword * mac_by_ip4
Definition: l2_bd.h:74
u32 sw_if_index
Definition: l2_bd.h:46
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
static uword clib_bitmap_first_clear(uword *ai)
Return the lowest numbered clear bit in a bitmap.
Definition: bitmap.h:424
u32 flags
Definition: vhost-user.h:75
bd_main_t bd_main
Definition: l2_bd.c:43
#define L2_LEARN
Definition: l2_bd.h:96
uword key
Definition: hash.h:161
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".