interface: Allow VLAN tag-rewrite on non-sub-interfaces too.
[vpp.git] / src / vnet / l2 / l2_bd.c
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
44 bd_main_t bd_main;
45
46 /**
47   Init bridge domain if not done already.
48   For feature bitmap, set all bits except ARP termination
49 */
50 void
51 bd_validate (l2_bridge_domain_t * bd_config)
52 {
53   if (bd_is_valid (bd_config))
54     return;
55   bd_config->feature_bitmap =
56     ~(L2INPUT_FEAT_ARP_TERM | L2INPUT_FEAT_UU_FWD | L2INPUT_FEAT_ARP_UFWD);
57   bd_config->bvi_sw_if_index = ~0;
58   bd_config->uu_fwd_sw_if_index = ~0;
59   bd_config->members = 0;
60   bd_config->flood_count = 0;
61   bd_config->tun_master_count = 0;
62   bd_config->tun_normal_count = 0;
63   bd_config->no_flood_count = 0;
64   bd_config->mac_by_ip4 = 0;
65   bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t),
66                                            sizeof (uword));
67 }
68
69 u32
70 bd_find_index (bd_main_t * bdm, u32 bd_id)
71 {
72   u32 *p = (u32 *) hash_get (bdm->bd_index_by_bd_id, bd_id);
73   if (!p)
74     return ~0;
75   return p[0];
76 }
77
78 u32
79 bd_add_bd_index (bd_main_t * bdm, u32 bd_id)
80 {
81   ASSERT (!hash_get (bdm->bd_index_by_bd_id, bd_id));
82   u32 rv = clib_bitmap_first_clear (bdm->bd_index_bitmap);
83
84   /* mark this index taken */
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
89   vec_validate (l2input_main.bd_configs, rv);
90   l2input_main.bd_configs[rv].bd_id = bd_id;
91
92   return rv;
93 }
94
95 static inline void
96 bd_free_ip_mac_tables (l2_bridge_domain_t * bd)
97 {
98   u64 mac_addr;
99   ip6_address_t *ip6_addr_key;
100
101   hash_free (bd->mac_by_ip4);
102   /* *INDENT-OFF* */
103   hash_foreach_mem (ip6_addr_key, mac_addr, bd->mac_by_ip6,
104   ({
105     clib_mem_free (ip6_addr_key); /* free memory used for ip6 addr key */
106   }));
107   /* *INDENT-ON* */
108   hash_free (bd->mac_by_ip6);
109 }
110
111 static int
112 bd_delete (bd_main_t * bdm, u32 bd_index)
113 {
114   l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index];
115   u32 bd_id = bd->bd_id;
116
117   /* flush non-static MACs in BD and removed bd_id from hash table */
118   l2fib_flush_bd_mac (vlib_get_main (), bd_index);
119   hash_unset (bdm->bd_index_by_bd_id, bd_id);
120
121   /* mark this index clear */
122   bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0);
123
124   /* clear BD config for reuse: bd_id to -1 and clear feature_bitmap */
125   bd->bd_id = ~0;
126   bd->feature_bitmap = 0;
127
128   /* free BD tag */
129   vec_free (bd->bd_tag);
130
131   /* free memory used by BD */
132   vec_free (bd->members);
133   bd_free_ip_mac_tables (bd);
134
135   return 0;
136 }
137
138 static void
139 update_flood_count (l2_bridge_domain_t * bd_config)
140 {
141   bd_config->flood_count = (vec_len (bd_config->members) -
142                             (bd_config->tun_master_count ?
143                              bd_config->tun_normal_count : 0));
144   bd_config->flood_count -= bd_config->no_flood_count;
145 }
146
147 void
148 bd_add_member (l2_bridge_domain_t * bd_config, l2_flood_member_t * member)
149 {
150   u32 ix = 0;
151   vnet_sw_interface_t *sw_if = vnet_get_sw_interface
152     (vnet_get_main (), member->sw_if_index);
153
154   /*
155    * Add one element to the vector
156    * vector is ordered [ bvi, normal/tun_masters..., tun_normals... no_flood]
157    * When flooding, the bvi interface (if present) must be the last member
158    * processed due to how BVI processing can change the packet. To enable
159    * this order, we make the bvi interface the first in the vector and
160    * flooding walks the vector in reverse. The flood-count determines where
161    * in the member list to start the walk from.
162    */
163   switch (sw_if->flood_class)
164     {
165     case VNET_FLOOD_CLASS_NO_FLOOD:
166       bd_config->no_flood_count++;
167       ix = vec_len (bd_config->members);
168       break;
169     case VNET_FLOOD_CLASS_BVI:
170       ix = 0;
171       break;
172     case VNET_FLOOD_CLASS_TUNNEL_MASTER:
173       bd_config->tun_master_count++;
174       /* Fall through */
175     case VNET_FLOOD_CLASS_NORMAL:
176       ix = (vec_len (bd_config->members) -
177             bd_config->tun_normal_count - bd_config->no_flood_count);
178       break;
179     case VNET_FLOOD_CLASS_TUNNEL_NORMAL:
180       ix = (vec_len (bd_config->members) - bd_config->no_flood_count);
181       bd_config->tun_normal_count++;
182       break;
183     }
184
185   vec_insert_elts (bd_config->members, member, 1, ix);
186   update_flood_count (bd_config);
187 }
188
189 #define BD_REMOVE_ERROR_OK        0
190 #define BD_REMOVE_ERROR_NOT_FOUND 1
191
192 u32
193 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index)
194 {
195   u32 ix;
196
197   /* Find and delete the member */
198   vec_foreach_index (ix, bd_config->members)
199   {
200     l2_flood_member_t *m = vec_elt_at_index (bd_config->members, ix);
201     if (m->sw_if_index == sw_if_index)
202       {
203         vnet_sw_interface_t *sw_if = vnet_get_sw_interface
204           (vnet_get_main (), sw_if_index);
205
206         if (sw_if->flood_class != VNET_FLOOD_CLASS_NORMAL)
207           {
208             if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_MASTER)
209               bd_config->tun_master_count--;
210             else if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_NORMAL)
211               bd_config->tun_normal_count--;
212             else if (sw_if->flood_class == VNET_FLOOD_CLASS_NO_FLOOD)
213               bd_config->no_flood_count--;
214           }
215         vec_delete (bd_config->members, 1, ix);
216         update_flood_count (bd_config);
217
218         return BD_REMOVE_ERROR_OK;
219       }
220   }
221
222   return BD_REMOVE_ERROR_NOT_FOUND;
223 }
224
225
226 clib_error_t *
227 l2bd_init (vlib_main_t * vm)
228 {
229   bd_main_t *bdm = &bd_main;
230   bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword));
231   /*
232    * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set
233    * to packet drop only. Thus, packets received from any L2 interface with
234    * uninitialized bd_index of 0 can be dropped safely.
235    */
236   u32 bd_index = bd_add_bd_index (bdm, 0);
237   ASSERT (bd_index == 0);
238   l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP;
239
240   bdm->vlib_main = vm;
241   return 0;
242 }
243
244 VLIB_INIT_FUNCTION (l2bd_init);
245
246
247 /**
248     Set the learn/forward/flood flags for the bridge domain.
249     Return 0 if ok, non-zero if for an error.
250 */
251 u32
252 bd_set_flags (vlib_main_t * vm, u32 bd_index, bd_flags_t flags, u32 enable)
253 {
254
255   l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);
256   bd_validate (bd_config);
257   u32 feature_bitmap = 0;
258
259   if (flags & L2_LEARN)
260     {
261       feature_bitmap |= L2INPUT_FEAT_LEARN;
262     }
263   if (flags & L2_FWD)
264     {
265       feature_bitmap |= L2INPUT_FEAT_FWD;
266     }
267   if (flags & L2_FLOOD)
268     {
269       feature_bitmap |= L2INPUT_FEAT_FLOOD;
270     }
271   if (flags & L2_UU_FLOOD)
272     {
273       feature_bitmap |= L2INPUT_FEAT_UU_FLOOD;
274     }
275   if (flags & L2_ARP_TERM)
276     {
277       feature_bitmap |= L2INPUT_FEAT_ARP_TERM;
278     }
279   if (flags & L2_ARP_UFWD)
280     {
281       feature_bitmap |= L2INPUT_FEAT_ARP_UFWD;
282     }
283
284   if (enable)
285     {
286       bd_config->feature_bitmap |= feature_bitmap;
287     }
288   else
289     {
290       bd_config->feature_bitmap &= ~feature_bitmap;
291     }
292
293   return bd_config->feature_bitmap;
294 }
295
296 /**
297     Set the mac age for the bridge domain.
298 */
299 void
300 bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age)
301 {
302   l2_bridge_domain_t *bd_config;
303   int enable = 0;
304
305   vec_validate (l2input_main.bd_configs, bd_index);
306   bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
307   bd_config->mac_age = age;
308
309   /* check if there is at least one bd with mac aging enabled */
310   vec_foreach (bd_config, l2input_main.bd_configs)
311     enable |= bd_config->bd_id != ~0 && bd_config->mac_age != 0;
312
313   vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index,
314                              enable ? L2_MAC_AGE_PROCESS_EVENT_START :
315                              L2_MAC_AGE_PROCESS_EVENT_STOP, 0);
316 }
317
318 /**
319     Set the tag for the bridge domain.
320 */
321
322 static void
323 bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag)
324 {
325   u8 *old;
326   l2_bridge_domain_t *bd_config;
327   vec_validate (l2input_main.bd_configs, bd_index);
328   bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
329
330   old = bd_config->bd_tag;
331
332   if (bd_tag[0])
333     {
334       bd_config->bd_tag = format (0, "%s%c", bd_tag, 0);
335     }
336   else
337     {
338       bd_config->bd_tag = NULL;
339     }
340
341   vec_free (old);
342 }
343
344 /**
345    Set bridge-domain learn enable/disable.
346    The CLI format is:
347    set bridge-domain learn <bd_id> [disable]
348 */
349 static clib_error_t *
350 bd_learn (vlib_main_t * vm,
351           unformat_input_t * input, vlib_cli_command_t * cmd)
352 {
353   bd_main_t *bdm = &bd_main;
354   clib_error_t *error = 0;
355   u32 bd_index, bd_id;
356   u32 enable;
357   uword *p;
358
359   if (!unformat (input, "%d", &bd_id))
360     {
361       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
362                                  format_unformat_error, input);
363       goto done;
364     }
365
366   if (bd_id == 0)
367     return clib_error_return (0,
368                               "No operations on the default bridge domain are supported");
369
370   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
371
372   if (p == 0)
373     return clib_error_return (0, "No such bridge domain %d", bd_id);
374
375   bd_index = p[0];
376
377   enable = 1;
378   if (unformat (input, "disable"))
379     {
380       enable = 0;
381     }
382
383   /* set the bridge domain flag */
384   bd_set_flags (vm, bd_index, L2_LEARN, enable);
385
386 done:
387   return error;
388 }
389
390 /*?
391  * Layer 2 learning can be enabled and disabled on each
392  * interface and on each bridge-domain. Use this command to
393  * manage bridge-domains. It is enabled by default.
394  *
395  * @cliexpar
396  * Example of how to enable learning (where 200 is the bridge-domain-id):
397  * @cliexcmd{set bridge-domain learn 200}
398  * Example of how to disable learning (where 200 is the bridge-domain-id):
399  * @cliexcmd{set bridge-domain learn 200 disable}
400 ?*/
401 /* *INDENT-OFF* */
402 VLIB_CLI_COMMAND (bd_learn_cli, static) = {
403   .path = "set bridge-domain learn",
404   .short_help = "set bridge-domain learn <bridge-domain-id> [disable]",
405   .function = bd_learn,
406 };
407 /* *INDENT-ON* */
408
409 /**
410     Set bridge-domain forward enable/disable.
411     The CLI format is:
412     set bridge-domain forward <bd_index> [disable]
413 */
414 static clib_error_t *
415 bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
416 {
417   bd_main_t *bdm = &bd_main;
418   clib_error_t *error = 0;
419   u32 bd_index, bd_id;
420   u32 enable;
421   uword *p;
422
423   if (!unformat (input, "%d", &bd_id))
424     {
425       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
426                                  format_unformat_error, input);
427       goto done;
428     }
429
430   if (bd_id == 0)
431     return clib_error_return (0,
432                               "No operations on the default bridge domain are supported");
433
434   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
435
436   if (p == 0)
437     return clib_error_return (0, "No such bridge domain %d", bd_id);
438
439   bd_index = p[0];
440
441   enable = 1;
442   if (unformat (input, "disable"))
443     {
444       enable = 0;
445     }
446
447   /* set the bridge domain flag */
448   bd_set_flags (vm, bd_index, L2_FWD, enable);
449
450 done:
451   return error;
452 }
453
454
455 /*?
456  * Layer 2 unicast forwarding can be enabled and disabled on each
457  * interface and on each bridge-domain. Use this command to
458  * manage bridge-domains. It is enabled by default.
459  *
460  * @cliexpar
461  * Example of how to enable forwarding (where 200 is the bridge-domain-id):
462  * @cliexcmd{set bridge-domain forward 200}
463  * Example of how to disable forwarding (where 200 is the bridge-domain-id):
464  * @cliexcmd{set bridge-domain forward 200 disable}
465 ?*/
466 /* *INDENT-OFF* */
467 VLIB_CLI_COMMAND (bd_fwd_cli, static) = {
468   .path = "set bridge-domain forward",
469   .short_help = "set bridge-domain forward <bridge-domain-id> [disable]",
470   .function = bd_fwd,
471 };
472 /* *INDENT-ON* */
473
474 /**
475     Set bridge-domain flood enable/disable.
476     The CLI format is:
477     set bridge-domain flood <bd_index> [disable]
478 */
479 static clib_error_t *
480 bd_flood (vlib_main_t * vm,
481           unformat_input_t * input, vlib_cli_command_t * cmd)
482 {
483   bd_main_t *bdm = &bd_main;
484   clib_error_t *error = 0;
485   u32 bd_index, bd_id;
486   u32 enable;
487   uword *p;
488
489   if (!unformat (input, "%d", &bd_id))
490     {
491       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
492                                  format_unformat_error, input);
493       goto done;
494     }
495
496   if (bd_id == 0)
497     return clib_error_return (0,
498                               "No operations on the default bridge domain are supported");
499
500   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
501
502   if (p == 0)
503     return clib_error_return (0, "No such bridge domain %d", bd_id);
504
505   bd_index = p[0];
506
507   enable = 1;
508   if (unformat (input, "disable"))
509     {
510       enable = 0;
511     }
512
513   /* set the bridge domain flag */
514   bd_set_flags (vm, bd_index, L2_FLOOD, enable);
515
516 done:
517   return error;
518 }
519
520 /*?
521  * Layer 2 flooding can be enabled and disabled on each
522  * interface and on each bridge-domain. Use this command to
523  * manage bridge-domains. It is enabled by default.
524  *
525  * @cliexpar
526  * Example of how to enable flooding (where 200 is the bridge-domain-id):
527  * @cliexcmd{set bridge-domain flood 200}
528  * Example of how to disable flooding (where 200 is the bridge-domain-id):
529  * @cliexcmd{set bridge-domain flood 200 disable}
530 ?*/
531 /* *INDENT-OFF* */
532 VLIB_CLI_COMMAND (bd_flood_cli, static) = {
533   .path = "set bridge-domain flood",
534   .short_help = "set bridge-domain flood <bridge-domain-id> [disable]",
535   .function = bd_flood,
536 };
537 /* *INDENT-ON* */
538
539 /**
540     Set bridge-domain unknown-unicast flood enable/disable.
541     The CLI format is:
542     set bridge-domain uu-flood <bd_index> [disable]
543 */
544 static clib_error_t *
545 bd_uu_flood (vlib_main_t * vm,
546              unformat_input_t * input, vlib_cli_command_t * cmd)
547 {
548   bd_main_t *bdm = &bd_main;
549   clib_error_t *error = 0;
550   u32 bd_index, bd_id;
551   u32 enable;
552   uword *p;
553
554   if (!unformat (input, "%d", &bd_id))
555     {
556       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
557                                  format_unformat_error, input);
558       goto done;
559     }
560
561   if (bd_id == 0)
562     return clib_error_return (0,
563                               "No operations on the default bridge domain are supported");
564
565   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
566
567   if (p == 0)
568     return clib_error_return (0, "No such bridge domain %d", bd_id);
569
570   bd_index = p[0];
571
572   enable = 1;
573   if (unformat (input, "disable"))
574     {
575       enable = 0;
576     }
577
578   /* set the bridge domain flag */
579   bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable);
580
581 done:
582   return error;
583 }
584
585 /*?
586  * Layer 2 unknown-unicast flooding can be enabled and disabled on each
587  * bridge-domain. It is enabled by default.
588  *
589  * @cliexpar
590  * Example of how to enable unknown-unicast flooding (where 200 is the
591  * bridge-domain-id):
592  * @cliexcmd{set bridge-domain uu-flood 200}
593  * Example of how to disable unknown-unicast flooding (where 200 is the bridge-domain-id):
594  * @cliexcmd{set bridge-domain uu-flood 200 disable}
595 ?*/
596 /* *INDENT-OFF* */
597 VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = {
598   .path = "set bridge-domain uu-flood",
599   .short_help = "set bridge-domain uu-flood <bridge-domain-id> [disable]",
600   .function = bd_uu_flood,
601 };
602 /* *INDENT-ON* */
603
604 /**
605     Set bridge-domain arp-unicast forward enable/disable.
606     The CLI format is:
607     set bridge-domain arp-ufwd <bd_index> [disable]
608 */
609 static clib_error_t *
610 bd_arp_ufwd (vlib_main_t * vm,
611              unformat_input_t * input, vlib_cli_command_t * cmd)
612 {
613   bd_main_t *bdm = &bd_main;
614   clib_error_t *error = 0;
615   u32 bd_index, bd_id;
616   u32 enable;
617   uword *p;
618
619   if (!unformat (input, "%d", &bd_id))
620     {
621       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
622                                  format_unformat_error, input);
623       goto done;
624     }
625
626   if (bd_id == 0)
627     return clib_error_return (0,
628                               "No operations on the default bridge domain are supported");
629
630   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
631
632   if (p == 0)
633     return clib_error_return (0, "No such bridge domain %d", bd_id);
634
635   bd_index = p[0];
636
637   enable = 1;
638   if (unformat (input, "disable"))
639     {
640       enable = 0;
641     }
642
643   /* set the bridge domain flag */
644   bd_set_flags (vm, bd_index, L2_ARP_UFWD, enable);
645
646 done:
647   return error;
648 }
649
650 /*?
651  * Layer 2 arp-unicast forwarding can be enabled and disabled on each
652  * bridge-domain. It is disabled by default.
653  *
654  * @cliexpar
655  * Example of how to enable arp-unicast forwarding (where 200 is the
656  * bridge-domain-id):
657  * @cliexcmd{set bridge-domain arp-ufwd 200}
658  * Example of how to disable arp-unicast forwarding (where 200 is the bridge-domain-id):
659  * @cliexcmd{set bridge-domain arp-ufwd 200 disable}
660 ?*/
661 /* *INDENT-OFF* */
662 VLIB_CLI_COMMAND (bd_arp_ufwd_cli, static) = {
663   .path = "set bridge-domain arp-ufwd",
664   .short_help = "set bridge-domain arp-ufwd <bridge-domain-id> [disable]",
665   .function = bd_arp_ufwd,
666 };
667 /* *INDENT-ON* */
668
669 /**
670     Set bridge-domain arp term enable/disable.
671     The CLI format is:
672     set bridge-domain arp term <bridge-domain-id> [disable]
673 */
674 static clib_error_t *
675 bd_arp_term (vlib_main_t * vm,
676              unformat_input_t * input, vlib_cli_command_t * cmd)
677 {
678   bd_main_t *bdm = &bd_main;
679   clib_error_t *error = 0;
680   u32 bd_index, bd_id;
681   u32 enable;
682   uword *p;
683
684   if (!unformat (input, "%d", &bd_id))
685     {
686       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
687                                  format_unformat_error, input);
688       goto done;
689     }
690
691   if (bd_id == 0)
692     return clib_error_return (0,
693                               "No operations on the default bridge domain are supported");
694
695   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
696   if (p)
697     bd_index = *p;
698   else
699     return clib_error_return (0, "No such bridge domain %d", bd_id);
700
701   enable = 1;
702   if (unformat (input, "disable"))
703     enable = 0;
704
705   /* set the bridge domain flag */
706   bd_set_flags (vm, bd_index, L2_ARP_TERM, enable);
707
708 done:
709   return error;
710 }
711
712 static clib_error_t *
713 bd_mac_age (vlib_main_t * vm,
714             unformat_input_t * input, vlib_cli_command_t * cmd)
715 {
716   bd_main_t *bdm = &bd_main;
717   clib_error_t *error = 0;
718   u32 bd_index, bd_id;
719   u32 age;
720   uword *p;
721
722   if (!unformat (input, "%d", &bd_id))
723     {
724       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
725                                  format_unformat_error, input);
726       goto done;
727     }
728
729   if (bd_id == 0)
730     return clib_error_return (0,
731                               "No operations on the default bridge domain are supported");
732
733   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
734
735   if (p == 0)
736     return clib_error_return (0, "No such bridge domain %d", bd_id);
737
738   bd_index = p[0];
739
740   if (!unformat (input, "%u", &age))
741     {
742       error =
743         clib_error_return (0, "expecting ageing time in minutes but got `%U'",
744                            format_unformat_error, input);
745       goto done;
746     }
747
748   /* set the bridge domain flag */
749   if (age > 255)
750     {
751       error =
752         clib_error_return (0, "mac aging time cannot be bigger than 255");
753       goto done;
754     }
755   bd_set_mac_age (vm, bd_index, (u8) age);
756
757 done:
758   return error;
759 }
760
761 /*?
762  * Layer 2 mac aging can be enabled and disabled on each
763  * bridge-domain. Use this command to set or disable mac aging
764  * on specific bridge-domains. It is disabled by default.
765  *
766  * @cliexpar
767  * Example of how to set mac aging (where 200 is the bridge-domain-id and
768  * 5 is aging time in minutes):
769  * @cliexcmd{set bridge-domain mac-age 200 5}
770  * Example of how to disable mac aging (where 200 is the bridge-domain-id):
771  * @cliexcmd{set bridge-domain flood 200 0}
772 ?*/
773 /* *INDENT-OFF* */
774 VLIB_CLI_COMMAND (bd_mac_age_cli, static) = {
775   .path = "set bridge-domain mac-age",
776   .short_help = "set bridge-domain mac-age <bridge-domain-id> <mins>",
777   .function = bd_mac_age,
778 };
779 /* *INDENT-ON* */
780
781 /*?
782  * Modify whether or not an existing bridge-domain should terminate and respond
783  * to ARP Requests. ARP Termination is disabled by default.
784  *
785  * @cliexpar
786  * Example of how to enable ARP termination (where 200 is the bridge-domain-id):
787  * @cliexcmd{set bridge-domain arp term 200}
788  * Example of how to disable ARP termination (where 200 is the bridge-domain-id):
789  * @cliexcmd{set bridge-domain arp term 200 disable}
790 ?*/
791 /* *INDENT-OFF* */
792 VLIB_CLI_COMMAND (bd_arp_term_cli, static) = {
793   .path = "set bridge-domain arp term",
794   .short_help = "set bridge-domain arp term <bridge-domain-id> [disable]",
795   .function = bd_arp_term,
796 };
797 /* *INDENT-ON* */
798
799
800 /**
801  * Add/delete IP address to MAC address mapping.
802  *
803  * The clib hash implementation stores uword entries in the hash table.
804  * The hash table mac_by_ip4 is keyed via IP4 address and store the
805  * 6-byte MAC address directly in the hash table entry uword.
806  *
807  * @warning This only works for 64-bit processor with 8-byte uword;
808  * which means this code *WILL NOT WORK* for a 32-bit processor with
809  * 4-byte uword.
810  */
811 u32
812 bd_add_del_ip_mac (u32 bd_index,
813                    ip46_type_t type,
814                    const ip46_address_t * ip,
815                    const mac_address_t * mac, u8 is_add)
816 {
817   l2_bridge_domain_t *bd_cfg = l2input_bd_config (bd_index);
818   u64 new_mac = mac_address_as_u64 (mac);
819   u64 *old_mac;
820
821   /* make sure uword is 8 bytes */
822   ASSERT (sizeof (uword) == sizeof (u64));
823   ASSERT (bd_is_valid (bd_cfg));
824
825   if (IP46_TYPE_IP6 == type)
826     {
827       ip6_address_t *ip6_addr_key;
828       hash_pair_t *hp;
829       old_mac = (u64 *) hash_get_mem (bd_cfg->mac_by_ip6, &ip->ip6);
830       if (is_add)
831         {
832           if (old_mac == NULL)
833             {
834               /* new entry - allocate and create ip6 address key */
835               ip6_addr_key = clib_mem_alloc (sizeof (ip6_address_t));
836               clib_memcpy (ip6_addr_key, &ip->ip6, sizeof (ip6_address_t));
837             }
838           else if (*old_mac == new_mac)
839             {
840               /* same mac entry already exist for ip6 address */
841               return 0;
842             }
843           else
844             {
845               /* update mac for ip6 address */
846               hp = hash_get_pair (bd_cfg->mac_by_ip6, &ip->ip6);
847               ip6_addr_key = (ip6_address_t *) hp->key;
848             }
849           hash_set_mem (bd_cfg->mac_by_ip6, ip6_addr_key, new_mac);
850         }
851       else
852         {
853           if (old_mac && (*old_mac == new_mac))
854             {
855               hp = hash_get_pair (bd_cfg->mac_by_ip6, &ip->ip6);
856               ip6_addr_key = (ip6_address_t *) hp->key;
857               hash_unset_mem (bd_cfg->mac_by_ip6, &ip->ip6);
858               clib_mem_free (ip6_addr_key);
859             }
860           else
861             return 1;
862         }
863     }
864   else
865     {
866       old_mac = (u64 *) hash_get (bd_cfg->mac_by_ip4, ip->ip4.as_u32);
867       if (is_add)
868         {
869           if (old_mac && (*old_mac == new_mac))
870             /* mac entry already exist */
871             return 0;
872           hash_set (bd_cfg->mac_by_ip4, ip->ip4.as_u32, new_mac);
873         }
874       else
875         {
876           if (old_mac && (*old_mac == new_mac))
877             hash_unset (bd_cfg->mac_by_ip4, ip->ip4.as_u32);
878           else
879             return 1;
880         }
881     }
882   return 0;
883 }
884
885 /**
886  * Flush IP address to MAC address mapping tables in a BD.
887  */
888 void
889 bd_flush_ip_mac (u32 bd_index)
890 {
891   l2_bridge_domain_t *bd = l2input_bd_config (bd_index);
892   ASSERT (bd_is_valid (bd));
893   bd_free_ip_mac_tables (bd);
894   bd->mac_by_ip4 = 0;
895   bd->mac_by_ip6 =
896     hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
897 }
898
899 /**
900     Set bridge-domain arp entry add/delete.
901     The CLI format is:
902     set bridge-domain arp entry <bridge-domain-id> <ip-addr> <mac-addr> [del]
903 */
904 static clib_error_t *
905 bd_arp_entry (vlib_main_t * vm,
906               unformat_input_t * input, vlib_cli_command_t * cmd)
907 {
908   ip46_address_t ip_addr = ip46_address_initializer;
909   ip46_type_t type = IP46_TYPE_IP4;
910   bd_main_t *bdm = &bd_main;
911   clib_error_t *error = 0;
912   u32 bd_index, bd_id;
913   mac_address_t mac;
914   u8 is_add = 1;
915   uword *p;
916
917   if (!unformat (input, "%d", &bd_id))
918     {
919       error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
920                                  format_unformat_error, input);
921       goto done;
922     }
923
924   if (bd_id == 0)
925     return clib_error_return (0,
926                               "No operations on the default bridge domain are supported");
927
928   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
929
930   if (p)
931     bd_index = *p;
932   else
933     return clib_error_return (0, "No such bridge domain %d", bd_id);
934
935   if (unformat (input, "%U", unformat_ip4_address, &ip_addr.ip4))
936     {
937       type = IP46_TYPE_IP4;
938     }
939   else if (unformat (input, "%U", unformat_ip6_address, &ip_addr.ip6))
940     {
941       type = IP46_TYPE_IP6;
942     }
943   else if (unformat (input, "del-all"))
944     {
945       bd_flush_ip_mac (bd_index);
946       goto done;
947     }
948   else
949     {
950       error = clib_error_return (0, "expecting IP address but got `%U'",
951                                  format_unformat_error, input);
952       goto done;
953     }
954
955   if (!unformat (input, "%U", unformat_mac_address_t, &mac))
956     {
957       error = clib_error_return (0, "expecting MAC address but got `%U'",
958                                  format_unformat_error, input);
959       goto done;
960     }
961
962   if (unformat (input, "del"))
963     {
964       is_add = 0;
965     }
966
967   /* set the bridge domain flagAdd IP-MAC entry into bridge domain */
968   if (bd_add_del_ip_mac (bd_index, type, &ip_addr, &mac, is_add))
969     {
970       error = clib_error_return (0, "MAC %s for IP %U and MAC %U failed",
971                                  is_add ? "add" : "del",
972                                  format_ip46_address, &ip_addr, IP46_TYPE_ANY,
973                                  format_mac_address_t, &mac);
974     }
975
976 done:
977   return error;
978 }
979
980 /*?
981  * Add an ARP entry to an existing bridge-domain.
982  *
983  * @cliexpar
984  * Example of how to add an ARP entry (where 200 is the bridge-domain-id):
985  * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a}
986  * Example of how to delete an ARP entry (where 200 is the bridge-domain-id):
987  * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a del}
988 ?*/
989 /* *INDENT-OFF* */
990 VLIB_CLI_COMMAND (bd_arp_entry_cli, static) = {
991   .path = "set bridge-domain arp entry",
992   .short_help = "set bridge-domain arp entry <bridge-domain-id> [<ip-addr> <mac-addr> [del] | del-all]",
993   .function = bd_arp_entry,
994 };
995 /* *INDENT-ON* */
996
997 static u8 *
998 format_uu_cfg (u8 * s, va_list * args)
999 {
1000   l2_bridge_domain_t *bd_config = va_arg (*args, l2_bridge_domain_t *);
1001
1002   if (bd_config->feature_bitmap & L2INPUT_FEAT_UU_FWD)
1003     return (format (s, "%U", format_vnet_sw_if_index_name_with_NA,
1004                     vnet_get_main (), bd_config->uu_fwd_sw_if_index));
1005   else if (bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD)
1006     return (format (s, "flood"));
1007   else
1008     return (format (s, "drop"));
1009 }
1010
1011 /**
1012    Show bridge-domain state.
1013    The CLI format is:
1014    show bridge-domain [<bd_index>]
1015 */
1016 static clib_error_t *
1017 bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1018 {
1019   vnet_main_t *vnm = vnet_get_main ();
1020   bd_main_t *bdm = &bd_main;
1021   clib_error_t *error = 0;
1022   u32 bd_index = ~0;
1023   l2_bridge_domain_t *bd_config;
1024   u32 start, end;
1025   u32 detail = 0;
1026   u32 intf = 0;
1027   u32 arp = 0;
1028   u32 bd_tag = 0;
1029   u32 bd_id = ~0;
1030   uword *p;
1031
1032   start = 1;
1033   end = vec_len (l2input_main.bd_configs);
1034
1035   if (unformat (input, "%d", &bd_id))
1036     {
1037       if (unformat (input, "detail"))
1038         detail = 1;
1039       else if (unformat (input, "det"))
1040         detail = 1;
1041       if (unformat (input, "int"))
1042         intf = 1;
1043       if (unformat (input, "arp"))
1044         arp = 1;
1045       if (unformat (input, "bd-tag"))
1046         bd_tag = 1;
1047
1048       if (bd_id == 0)
1049         return clib_error_return (0,
1050                                   "No operations on the default bridge domain are supported");
1051
1052       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1053       if (p)
1054         bd_index = *p;
1055       else
1056         return clib_error_return (0, "No such bridge domain %d", bd_id);
1057
1058       vec_validate (l2input_main.bd_configs, bd_index);
1059       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
1060       if (bd_is_valid (bd_config))
1061         {
1062           start = bd_index;
1063           end = start + 1;
1064         }
1065       else
1066         {
1067           vlib_cli_output (vm, "bridge-domain %d not in use", bd_id);
1068           goto done;
1069         }
1070     }
1071
1072   /* Show all bridge-domains that have been initialized */
1073   u32 printed = 0;
1074   u8 *as = 0;
1075   for (bd_index = start; bd_index < end; bd_index++)
1076     {
1077       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
1078       if (bd_is_valid (bd_config))
1079         {
1080           if (!printed)
1081             {
1082               printed = 1;
1083               vlib_cli_output (vm,
1084                                "%=8s %=7s %=4s %=9s %=9s %=9s %=11s %=9s %=9s %=9s %=11s",
1085                                "BD-ID", "Index", "BSN", "Age(min)",
1086                                "Learning", "U-Forwrd", "UU-Flood",
1087                                "Flooding", "ARP-Term", "arp-ufwd",
1088                                "BVI-Intf");
1089             }
1090
1091           if (bd_config->mac_age)
1092             as = format (as, "%d", bd_config->mac_age);
1093           else
1094             as = format (as, "off");
1095           vlib_cli_output (vm,
1096                            "%=8d %=7d %=4d %=9v %=9s %=9s %=11U %=9s %=9s %=9s %=11U",
1097                            bd_config->bd_id, bd_index, bd_config->seq_num, as,
1098                            bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
1099                            "on" : "off",
1100                            bd_config->feature_bitmap & L2INPUT_FEAT_FWD ?
1101                            "on" : "off",
1102                            format_uu_cfg, bd_config,
1103                            bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ?
1104                            "on" : "off",
1105                            bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ?
1106                            "on" : "off",
1107                            bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD ?
1108                            "on" : "off",
1109                            format_vnet_sw_if_index_name_with_NA,
1110                            vnm, bd_config->bvi_sw_if_index);
1111           vec_reset_length (as);
1112
1113           if (detail || intf)
1114             {
1115               /* Show all member interfaces */
1116               int i;
1117               vec_foreach_index (i, bd_config->members)
1118               {
1119                 l2_flood_member_t *member =
1120                   vec_elt_at_index (bd_config->members, i);
1121                 u8 swif_seq_num = *l2fib_swif_seq_num (member->sw_if_index);
1122                 u32 vtr_opr, dot1q, tag1, tag2;
1123                 if (i == 0)
1124                   {
1125                     vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=5s%=9s%=30s",
1126                                      "Interface", "If-idx", "ISN", "SHG",
1127                                      "BVI", "TxFlood", "VLAN-Tag-Rewrite");
1128                   }
1129                 l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q,
1130                            &tag1, &tag2);
1131                 vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30U",
1132                                  format_vnet_sw_if_index_name, vnm,
1133                                  member->sw_if_index, member->sw_if_index,
1134                                  swif_seq_num, member->shg,
1135                                  member->flags & L2_FLOOD_MEMBER_BVI ? "*" :
1136                                  "-", i < bd_config->flood_count ? "*" : "-",
1137                                  format_vtr, vtr_opr, dot1q, tag1, tag2);
1138               }
1139               if (~0 != bd_config->uu_fwd_sw_if_index)
1140                 vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30s",
1141                                  format_vnet_sw_if_index_name, vnm,
1142                                  bd_config->uu_fwd_sw_if_index,
1143                                  bd_config->uu_fwd_sw_if_index,
1144                                  0, 0, "uu", "-", "None");
1145
1146             }
1147
1148           if ((detail || arp) &&
1149               (bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM))
1150             {
1151               u32 ip4_addr;
1152               ip6_address_t *ip6_addr;
1153               u64 mac_addr;
1154               vlib_cli_output (vm,
1155                                "\n  IP4/IP6 to MAC table for ARP Termination");
1156
1157               /* *INDENT-OFF* */
1158               hash_foreach (ip4_addr, mac_addr, bd_config->mac_by_ip4,
1159               ({
1160                 vlib_cli_output (vm, "%=40U => %=20U",
1161                                  format_ip4_address, &ip4_addr,
1162                                  format_ethernet_address, &mac_addr);
1163               }));
1164
1165               hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6,
1166               ({
1167                 vlib_cli_output (vm, "%=40U => %=20U",
1168                                  format_ip6_address, ip6_addr,
1169                                  format_ethernet_address, &mac_addr);
1170               }));
1171               /* *INDENT-ON* */
1172             }
1173
1174           if ((detail || bd_tag) && (bd_config->bd_tag))
1175             {
1176               vlib_cli_output (vm, "\n  BD-Tag: %s", bd_config->bd_tag);
1177
1178             }
1179         }
1180     }
1181   vec_free (as);
1182
1183   if (!printed)
1184     {
1185       vlib_cli_output (vm, "no bridge-domains in use");
1186     }
1187
1188 done:
1189   return error;
1190 }
1191
1192 /*?
1193  * Show a summary of all the bridge-domain instances or detailed view of a
1194  * single bridge-domain. Bridge-domains are created by adding an interface
1195  * to a bridge using the '<em>set interface l2 bridge</em>' command.
1196  *
1197  * @cliexpar
1198  * @parblock
1199  * Example of displaying all bridge-domains:
1200  * @cliexstart{show bridge-domain}
1201  *  ID   Index   Learning   U-Forwrd   UU-Flood   Flooding   ARP-Term     BVI-Intf
1202  *  0      0        off        off        off        off        off        local0
1203  * 200     1        on         on         on         on         off          N/A
1204  * @cliexend
1205  *
1206  * Example of displaying details of a single bridge-domains:
1207  * @cliexstart{show bridge-domain 200 detail}
1208  *  ID   Index   Learning   U-Forwrd   UU-Flood   Flooding   ARP-Term     BVI-Intf
1209  * 200     1        on         on         on         on         off          N/A
1210  *
1211  *          Interface           Index  SHG  BVI        VLAN-Tag-Rewrite
1212  *  GigabitEthernet0/8/0.200      3     0    -               none
1213  *  GigabitEthernet0/9/0.200      4     0    -               none
1214  * @cliexend
1215  * @endparblock
1216 ?*/
1217 /* *INDENT-OFF* */
1218 VLIB_CLI_COMMAND (bd_show_cli, static) = {
1219   .path = "show bridge-domain",
1220   .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp|bd-tag]]",
1221   .function = bd_show,
1222 };
1223 /* *INDENT-ON* */
1224
1225 int
1226 bd_add_del (l2_bridge_domain_add_del_args_t * a)
1227 {
1228   bd_main_t *bdm = &bd_main;
1229   vlib_main_t *vm = bdm->vlib_main;
1230   int rv = 0;
1231
1232   u32 bd_index = bd_find_index (bdm, a->bd_id);
1233   if (a->is_add)
1234     {
1235       if (bd_index != ~0)
1236         return VNET_API_ERROR_BD_ALREADY_EXISTS;
1237       if (a->bd_id > L2_BD_ID_MAX)
1238         return VNET_API_ERROR_BD_ID_EXCEED_MAX;
1239       bd_index = bd_add_bd_index (bdm, a->bd_id);
1240
1241       bd_flags_t enable_flags = 0, disable_flags = 0;
1242       if (a->flood)
1243         enable_flags |= L2_FLOOD;
1244       else
1245         disable_flags |= L2_FLOOD;
1246
1247       if (a->uu_flood)
1248         enable_flags |= L2_UU_FLOOD;
1249       else
1250         disable_flags |= L2_UU_FLOOD;
1251
1252       if (a->forward)
1253         enable_flags |= L2_FWD;
1254       else
1255         disable_flags |= L2_FWD;
1256
1257       if (a->learn)
1258         enable_flags |= L2_LEARN;
1259       else
1260         disable_flags |= L2_LEARN;
1261
1262       if (a->arp_term)
1263         enable_flags |= L2_ARP_TERM;
1264       else
1265         disable_flags |= L2_ARP_TERM;
1266
1267       if (a->arp_ufwd)
1268         enable_flags |= L2_ARP_UFWD;
1269       else
1270         disable_flags |= L2_ARP_UFWD;
1271
1272       if (enable_flags)
1273         bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ );
1274
1275       if (disable_flags)
1276         bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ );
1277
1278       bd_set_mac_age (vm, bd_index, a->mac_age);
1279
1280       if (a->bd_tag)
1281         bd_set_bd_tag (vm, bd_index, a->bd_tag);
1282
1283     }
1284   else
1285     {
1286       if (bd_index == ~0)
1287         return VNET_API_ERROR_NO_SUCH_ENTRY;
1288       if (bd_index == 0)
1289         return VNET_API_ERROR_BD_NOT_MODIFIABLE;
1290       if (vec_len (l2input_main.bd_configs[bd_index].members))
1291         return VNET_API_ERROR_BD_IN_USE;
1292       rv = bd_delete (bdm, bd_index);
1293     }
1294
1295   return rv;
1296 }
1297
1298 /**
1299    Create or delete bridge-domain.
1300    The CLI format:
1301    create bridge-domain <bd_index> [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>]
1302                                         [arp-term <0|1>] [mac-age <nn>] [bd-tag <tag>] [del]
1303 */
1304
1305 static clib_error_t *
1306 bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input,
1307                        vlib_cli_command_t * cmd)
1308 {
1309   unformat_input_t _line_input, *line_input = &_line_input;
1310   clib_error_t *error = 0;
1311   u8 is_add = 1;
1312   u32 bd_id = ~0;
1313   u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term =
1314     0, arp_ufwd = 0;
1315   u32 mac_age = 0;
1316   u8 *bd_tag = NULL;
1317   l2_bridge_domain_add_del_args_t _a, *a = &_a;
1318   int rv;
1319
1320   /* Get a line of input. */
1321   if (!unformat_user (input, unformat_line_input, line_input))
1322     return 0;
1323
1324   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1325     {
1326       if (unformat (line_input, "%d", &bd_id))
1327         ;
1328       else if (unformat (line_input, "flood %d", &flood))
1329         ;
1330       else if (unformat (line_input, "uu-flood %d", &uu_flood))
1331         ;
1332       else if (unformat (line_input, "forward %d", &forward))
1333         ;
1334       else if (unformat (line_input, "learn %d", &learn))
1335         ;
1336       else if (unformat (line_input, "arp-term %d", &arp_term))
1337         ;
1338       else if (unformat (line_input, "arp-ufwd %d", &arp_ufwd))
1339         ;
1340       else if (unformat (line_input, "mac-age %d", &mac_age))
1341         ;
1342       else if (unformat (line_input, "bd-tag %s", &bd_tag))
1343         ;
1344       else if (unformat (line_input, "del"))
1345         {
1346           is_add = 0;
1347           flood = uu_flood = forward = learn = 0;
1348         }
1349       else
1350         break;
1351     }
1352
1353   if (bd_id == ~0)
1354     {
1355       error = clib_error_return (0, "bridge-domain-id not specified");
1356       goto done;
1357     }
1358
1359   if (bd_id == 0)
1360     {
1361       error = clib_error_return (0, "bridge domain 0 can not be modified");
1362       goto done;
1363     }
1364
1365   if (mac_age > 255)
1366     {
1367       error = clib_error_return (0, "mac age must be less than 256");
1368       goto done;
1369     }
1370   if ((bd_tag) && (strlen ((char *) bd_tag) > 63))
1371     {
1372       error = clib_error_return (0, "bd-tag cannot be longer than 63");
1373       goto done;
1374     }
1375
1376   clib_memset (a, 0, sizeof (*a));
1377   a->is_add = is_add;
1378   a->bd_id = bd_id;
1379   a->flood = (u8) flood;
1380   a->uu_flood = (u8) uu_flood;
1381   a->forward = (u8) forward;
1382   a->learn = (u8) learn;
1383   a->arp_term = (u8) arp_term;
1384   a->arp_ufwd = (u8) arp_ufwd;
1385   a->mac_age = (u8) mac_age;
1386   a->bd_tag = bd_tag;
1387
1388   rv = bd_add_del (a);
1389
1390   switch (rv)
1391     {
1392     case 0:
1393       if (is_add)
1394         vlib_cli_output (vm, "bridge-domain %d", bd_id);
1395       break;
1396     case VNET_API_ERROR_BD_IN_USE:
1397       error = clib_error_return (0, "bridge domain in use - remove members");
1398       goto done;
1399     case VNET_API_ERROR_NO_SUCH_ENTRY:
1400       error = clib_error_return (0, "bridge domain ID does not exist");
1401       goto done;
1402     case VNET_API_ERROR_BD_NOT_MODIFIABLE:
1403       error = clib_error_return (0, "bridge domain 0 can not be modified");
1404       goto done;
1405     case VNET_API_ERROR_BD_ID_EXCEED_MAX:
1406       error = clib_error_return (0, "bridge domain ID exceed 16M limit");
1407       goto done;
1408     default:
1409       error = clib_error_return (0, "bd_add_del returned %d", rv);
1410       goto done;
1411     }
1412
1413 done:
1414   vec_free (bd_tag);
1415   unformat_free (line_input);
1416
1417   return error;
1418 }
1419
1420
1421 /*?
1422  * Create/Delete bridge-domain instance
1423  *
1424  * @cliexpar
1425  * @parblock
1426  * Example of creating bridge-domain 1:
1427  * @cliexstart{create bridge-domain 1}
1428  * bridge-domain 1
1429  * @cliexend
1430  *
1431  * Example of creating bridge-domain 2 with enabling arp-term, mac-age 60:
1432  * @cliexstart{create bridge-domain 2 arp-term 1 mac-age 60}
1433  * bridge-domain 2
1434  *
1435  * vpp# show bridge-domain
1436  *   ID   Index   BSN  Age(min)  Learning  U-Forwrd  UU-Flood  Flooding  ARP-Term  BVI-Intf
1437  *   0      0      0     off       off       off       off       off       off      local0
1438  *   1      1      0     off        on        on       off        on       off       N/A
1439  *   2      2      0      60        on        on       off        on        on       N/A
1440  *
1441  * @cliexend
1442  *
1443  * Example of delete bridge-domain 1:
1444  * @cliexstart{create bridge-domain 1 del}
1445  * @cliexend
1446  * @endparblock
1447 ?*/
1448
1449 /* *INDENT-OFF* */
1450 VLIB_CLI_COMMAND (bd_create_cli, static) = {
1451   .path = "create bridge-domain",
1452   .short_help = "create bridge-domain <bridge-domain-id>"
1453                 " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]"
1454                 " [arp-ufwd <0|1>] [mac-age <nn>] [bd-tag <tag>] [del]",
1455   .function = bd_add_del_command_fn,
1456 };
1457 /* *INDENT-ON* */
1458
1459
1460
1461 /*
1462  * fd.io coding-style-patch-verification: ON
1463  *
1464  * Local Variables:
1465  * eval: (c-set-style "gnu")
1466  * End:
1467  */