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