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