207ef4d66010e5dc7ac1d58471f273b8bc55039b
[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_vtr (u8 * s, va_list * args)
999 {
1000   u32 vtr_op = va_arg (*args, u32);
1001   u32 dot1q = va_arg (*args, u32);
1002   u32 tag1 = va_arg (*args, u32);
1003   u32 tag2 = va_arg (*args, u32);
1004   switch (vtr_op)
1005     {
1006     case L2_VTR_DISABLED:
1007       return format (s, "none");
1008     case L2_VTR_PUSH_1:
1009       return format (s, "push-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
1010     case L2_VTR_PUSH_2:
1011       return format (s, "push-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", tag1,
1012                      tag2);
1013     case L2_VTR_POP_1:
1014       return format (s, "pop-1");
1015     case L2_VTR_POP_2:
1016       return format (s, "pop-2");
1017     case L2_VTR_TRANSLATE_1_1:
1018       return format (s, "trans-1-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
1019     case L2_VTR_TRANSLATE_1_2:
1020       return format (s, "trans-1-2 %s %d %d", dot1q ? "dot1q" : "dot1ad",
1021                      tag1, tag2);
1022     case L2_VTR_TRANSLATE_2_1:
1023       return format (s, "trans-2-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1);
1024     case L2_VTR_TRANSLATE_2_2:
1025       return format (s, "trans-2-2 %s %d %d", dot1q ? "dot1q" : "dot1ad",
1026                      tag1, tag2);
1027     default:
1028       return format (s, "none");
1029     }
1030 }
1031
1032 static u8 *
1033 format_uu_cfg (u8 * s, va_list * args)
1034 {
1035   l2_bridge_domain_t *bd_config = va_arg (*args, l2_bridge_domain_t *);
1036
1037   if (bd_config->feature_bitmap & L2INPUT_FEAT_UU_FWD)
1038     return (format (s, "%U", format_vnet_sw_if_index_name_with_NA,
1039                     vnet_get_main (), bd_config->uu_fwd_sw_if_index));
1040   else if (bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD)
1041     return (format (s, "flood"));
1042   else
1043     return (format (s, "drop"));
1044 }
1045
1046 /**
1047    Show bridge-domain state.
1048    The CLI format is:
1049    show bridge-domain [<bd_index>]
1050 */
1051 static clib_error_t *
1052 bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1053 {
1054   vnet_main_t *vnm = vnet_get_main ();
1055   bd_main_t *bdm = &bd_main;
1056   clib_error_t *error = 0;
1057   u32 bd_index = ~0;
1058   l2_bridge_domain_t *bd_config;
1059   u32 start, end;
1060   u32 detail = 0;
1061   u32 intf = 0;
1062   u32 arp = 0;
1063   u32 bd_tag = 0;
1064   u32 bd_id = ~0;
1065   uword *p;
1066
1067   start = 1;
1068   end = vec_len (l2input_main.bd_configs);
1069
1070   if (unformat (input, "%d", &bd_id))
1071     {
1072       if (unformat (input, "detail"))
1073         detail = 1;
1074       else if (unformat (input, "det"))
1075         detail = 1;
1076       if (unformat (input, "int"))
1077         intf = 1;
1078       if (unformat (input, "arp"))
1079         arp = 1;
1080       if (unformat (input, "bd-tag"))
1081         bd_tag = 1;
1082
1083       if (bd_id == 0)
1084         return clib_error_return (0,
1085                                   "No operations on the default bridge domain are supported");
1086
1087       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
1088       if (p)
1089         bd_index = *p;
1090       else
1091         return clib_error_return (0, "No such bridge domain %d", bd_id);
1092
1093       vec_validate (l2input_main.bd_configs, bd_index);
1094       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
1095       if (bd_is_valid (bd_config))
1096         {
1097           start = bd_index;
1098           end = start + 1;
1099         }
1100       else
1101         {
1102           vlib_cli_output (vm, "bridge-domain %d not in use", bd_id);
1103           goto done;
1104         }
1105     }
1106
1107   /* Show all bridge-domains that have been initialized */
1108   u32 printed = 0;
1109   u8 *as = 0;
1110   for (bd_index = start; bd_index < end; bd_index++)
1111     {
1112       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
1113       if (bd_is_valid (bd_config))
1114         {
1115           if (!printed)
1116             {
1117               printed = 1;
1118               vlib_cli_output (vm,
1119                                "%=8s %=7s %=4s %=9s %=9s %=9s %=11s %=9s %=9s %=9s %=11s",
1120                                "BD-ID", "Index", "BSN", "Age(min)",
1121                                "Learning", "U-Forwrd", "UU-Flood",
1122                                "Flooding", "ARP-Term", "arp-ufwd",
1123                                "BVI-Intf");
1124             }
1125
1126           if (bd_config->mac_age)
1127             as = format (as, "%d", bd_config->mac_age);
1128           else
1129             as = format (as, "off");
1130           vlib_cli_output (vm,
1131                            "%=8d %=7d %=4d %=9v %=9s %=9s %=11U %=9s %=9s %=9s %=11U",
1132                            bd_config->bd_id, bd_index, bd_config->seq_num, as,
1133                            bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
1134                            "on" : "off",
1135                            bd_config->feature_bitmap & L2INPUT_FEAT_FWD ?
1136                            "on" : "off",
1137                            format_uu_cfg, bd_config,
1138                            bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ?
1139                            "on" : "off",
1140                            bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ?
1141                            "on" : "off",
1142                            bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD ?
1143                            "on" : "off",
1144                            format_vnet_sw_if_index_name_with_NA,
1145                            vnm, bd_config->bvi_sw_if_index);
1146           vec_reset_length (as);
1147
1148           if (detail || intf)
1149             {
1150               /* Show all member interfaces */
1151               int i;
1152               vec_foreach_index (i, bd_config->members)
1153               {
1154                 l2_flood_member_t *member =
1155                   vec_elt_at_index (bd_config->members, i);
1156                 u8 swif_seq_num = *l2fib_swif_seq_num (member->sw_if_index);
1157                 u32 vtr_opr, dot1q, tag1, tag2;
1158                 if (i == 0)
1159                   {
1160                     vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=5s%=9s%=30s",
1161                                      "Interface", "If-idx", "ISN", "SHG",
1162                                      "BVI", "TxFlood", "VLAN-Tag-Rewrite");
1163                   }
1164                 l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q,
1165                            &tag1, &tag2);
1166                 vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30U",
1167                                  format_vnet_sw_if_index_name, vnm,
1168                                  member->sw_if_index, member->sw_if_index,
1169                                  swif_seq_num, member->shg,
1170                                  member->flags & L2_FLOOD_MEMBER_BVI ? "*" :
1171                                  "-", i < bd_config->flood_count ? "*" : "-",
1172                                  format_vtr, vtr_opr, dot1q, tag1, tag2);
1173               }
1174               if (~0 != bd_config->uu_fwd_sw_if_index)
1175                 vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30s",
1176                                  format_vnet_sw_if_index_name, vnm,
1177                                  bd_config->uu_fwd_sw_if_index,
1178                                  bd_config->uu_fwd_sw_if_index,
1179                                  0, 0, "uu", "-", "None");
1180
1181             }
1182
1183           if ((detail || arp) &&
1184               (bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM))
1185             {
1186               u32 ip4_addr;
1187               ip6_address_t *ip6_addr;
1188               u64 mac_addr;
1189               vlib_cli_output (vm,
1190                                "\n  IP4/IP6 to MAC table for ARP Termination");
1191
1192               /* *INDENT-OFF* */
1193               hash_foreach (ip4_addr, mac_addr, bd_config->mac_by_ip4,
1194               ({
1195                 vlib_cli_output (vm, "%=40U => %=20U",
1196                                  format_ip4_address, &ip4_addr,
1197                                  format_ethernet_address, &mac_addr);
1198               }));
1199
1200               hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6,
1201               ({
1202                 vlib_cli_output (vm, "%=40U => %=20U",
1203                                  format_ip6_address, ip6_addr,
1204                                  format_ethernet_address, &mac_addr);
1205               }));
1206               /* *INDENT-ON* */
1207             }
1208
1209           if ((detail || bd_tag) && (bd_config->bd_tag))
1210             {
1211               vlib_cli_output (vm, "\n  BD-Tag: %s", bd_config->bd_tag);
1212
1213             }
1214         }
1215     }
1216   vec_free (as);
1217
1218   if (!printed)
1219     {
1220       vlib_cli_output (vm, "no bridge-domains in use");
1221     }
1222
1223 done:
1224   return error;
1225 }
1226
1227 /*?
1228  * Show a summary of all the bridge-domain instances or detailed view of a
1229  * single bridge-domain. Bridge-domains are created by adding an interface
1230  * to a bridge using the '<em>set interface l2 bridge</em>' command.
1231  *
1232  * @cliexpar
1233  * @parblock
1234  * Example of displaying all bridge-domains:
1235  * @cliexstart{show bridge-domain}
1236  *  ID   Index   Learning   U-Forwrd   UU-Flood   Flooding   ARP-Term     BVI-Intf
1237  *  0      0        off        off        off        off        off        local0
1238  * 200     1        on         on         on         on         off          N/A
1239  * @cliexend
1240  *
1241  * Example of displaying details of a single bridge-domains:
1242  * @cliexstart{show bridge-domain 200 detail}
1243  *  ID   Index   Learning   U-Forwrd   UU-Flood   Flooding   ARP-Term     BVI-Intf
1244  * 200     1        on         on         on         on         off          N/A
1245  *
1246  *          Interface           Index  SHG  BVI        VLAN-Tag-Rewrite
1247  *  GigabitEthernet0/8/0.200      3     0    -               none
1248  *  GigabitEthernet0/9/0.200      4     0    -               none
1249  * @cliexend
1250  * @endparblock
1251 ?*/
1252 /* *INDENT-OFF* */
1253 VLIB_CLI_COMMAND (bd_show_cli, static) = {
1254   .path = "show bridge-domain",
1255   .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp|bd-tag]]",
1256   .function = bd_show,
1257 };
1258 /* *INDENT-ON* */
1259
1260 int
1261 bd_add_del (l2_bridge_domain_add_del_args_t * a)
1262 {
1263   bd_main_t *bdm = &bd_main;
1264   vlib_main_t *vm = bdm->vlib_main;
1265   int rv = 0;
1266
1267   u32 bd_index = bd_find_index (bdm, a->bd_id);
1268   if (a->is_add)
1269     {
1270       if (bd_index != ~0)
1271         return VNET_API_ERROR_BD_ALREADY_EXISTS;
1272       if (a->bd_id > L2_BD_ID_MAX)
1273         return VNET_API_ERROR_BD_ID_EXCEED_MAX;
1274       bd_index = bd_add_bd_index (bdm, a->bd_id);
1275
1276       bd_flags_t enable_flags = 0, disable_flags = 0;
1277       if (a->flood)
1278         enable_flags |= L2_FLOOD;
1279       else
1280         disable_flags |= L2_FLOOD;
1281
1282       if (a->uu_flood)
1283         enable_flags |= L2_UU_FLOOD;
1284       else
1285         disable_flags |= L2_UU_FLOOD;
1286
1287       if (a->forward)
1288         enable_flags |= L2_FWD;
1289       else
1290         disable_flags |= L2_FWD;
1291
1292       if (a->learn)
1293         enable_flags |= L2_LEARN;
1294       else
1295         disable_flags |= L2_LEARN;
1296
1297       if (a->arp_term)
1298         enable_flags |= L2_ARP_TERM;
1299       else
1300         disable_flags |= L2_ARP_TERM;
1301
1302       if (a->arp_ufwd)
1303         enable_flags |= L2_ARP_UFWD;
1304       else
1305         disable_flags |= L2_ARP_UFWD;
1306
1307       if (enable_flags)
1308         bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ );
1309
1310       if (disable_flags)
1311         bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ );
1312
1313       bd_set_mac_age (vm, bd_index, a->mac_age);
1314
1315       if (a->bd_tag)
1316         bd_set_bd_tag (vm, bd_index, a->bd_tag);
1317
1318     }
1319   else
1320     {
1321       if (bd_index == ~0)
1322         return VNET_API_ERROR_NO_SUCH_ENTRY;
1323       if (bd_index == 0)
1324         return VNET_API_ERROR_BD_NOT_MODIFIABLE;
1325       if (vec_len (l2input_main.bd_configs[bd_index].members))
1326         return VNET_API_ERROR_BD_IN_USE;
1327       rv = bd_delete (bdm, bd_index);
1328     }
1329
1330   return rv;
1331 }
1332
1333 /**
1334    Create or delete bridge-domain.
1335    The CLI format:
1336    create bridge-domain <bd_index> [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>]
1337                                         [arp-term <0|1>] [mac-age <nn>] [bd-tag <tag>] [del]
1338 */
1339
1340 static clib_error_t *
1341 bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input,
1342                        vlib_cli_command_t * cmd)
1343 {
1344   unformat_input_t _line_input, *line_input = &_line_input;
1345   clib_error_t *error = 0;
1346   u8 is_add = 1;
1347   u32 bd_id = ~0;
1348   u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term =
1349     0, arp_ufwd = 0;
1350   u32 mac_age = 0;
1351   u8 *bd_tag = NULL;
1352   l2_bridge_domain_add_del_args_t _a, *a = &_a;
1353   int rv;
1354
1355   /* Get a line of input. */
1356   if (!unformat_user (input, unformat_line_input, line_input))
1357     return 0;
1358
1359   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1360     {
1361       if (unformat (line_input, "%d", &bd_id))
1362         ;
1363       else if (unformat (line_input, "flood %d", &flood))
1364         ;
1365       else if (unformat (line_input, "uu-flood %d", &uu_flood))
1366         ;
1367       else if (unformat (line_input, "forward %d", &forward))
1368         ;
1369       else if (unformat (line_input, "learn %d", &learn))
1370         ;
1371       else if (unformat (line_input, "arp-term %d", &arp_term))
1372         ;
1373       else if (unformat (line_input, "arp-ufwd %d", &arp_ufwd))
1374         ;
1375       else if (unformat (line_input, "mac-age %d", &mac_age))
1376         ;
1377       else if (unformat (line_input, "bd-tag %s", &bd_tag))
1378         ;
1379       else if (unformat (line_input, "del"))
1380         {
1381           is_add = 0;
1382           flood = uu_flood = forward = learn = 0;
1383         }
1384       else
1385         break;
1386     }
1387
1388   if (bd_id == ~0)
1389     {
1390       error = clib_error_return (0, "bridge-domain-id not specified");
1391       goto done;
1392     }
1393
1394   if (bd_id == 0)
1395     {
1396       error = clib_error_return (0, "bridge domain 0 can not be modified");
1397       goto done;
1398     }
1399
1400   if (mac_age > 255)
1401     {
1402       error = clib_error_return (0, "mac age must be less than 256");
1403       goto done;
1404     }
1405   if ((bd_tag) && (strlen ((char *) bd_tag) > 63))
1406     {
1407       error = clib_error_return (0, "bd-tag cannot be longer than 63");
1408       goto done;
1409     }
1410
1411   clib_memset (a, 0, sizeof (*a));
1412   a->is_add = is_add;
1413   a->bd_id = bd_id;
1414   a->flood = (u8) flood;
1415   a->uu_flood = (u8) uu_flood;
1416   a->forward = (u8) forward;
1417   a->learn = (u8) learn;
1418   a->arp_term = (u8) arp_term;
1419   a->arp_ufwd = (u8) arp_ufwd;
1420   a->mac_age = (u8) mac_age;
1421   a->bd_tag = bd_tag;
1422
1423   rv = bd_add_del (a);
1424
1425   switch (rv)
1426     {
1427     case 0:
1428       if (is_add)
1429         vlib_cli_output (vm, "bridge-domain %d", bd_id);
1430       break;
1431     case VNET_API_ERROR_BD_IN_USE:
1432       error = clib_error_return (0, "bridge domain in use - remove members");
1433       goto done;
1434     case VNET_API_ERROR_NO_SUCH_ENTRY:
1435       error = clib_error_return (0, "bridge domain ID does not exist");
1436       goto done;
1437     case VNET_API_ERROR_BD_NOT_MODIFIABLE:
1438       error = clib_error_return (0, "bridge domain 0 can not be modified");
1439       goto done;
1440     case VNET_API_ERROR_BD_ID_EXCEED_MAX:
1441       error = clib_error_return (0, "bridge domain ID exceed 16M limit");
1442       goto done;
1443     default:
1444       error = clib_error_return (0, "bd_add_del returned %d", rv);
1445       goto done;
1446     }
1447
1448 done:
1449   vec_free (bd_tag);
1450   unformat_free (line_input);
1451
1452   return error;
1453 }
1454
1455
1456 /*?
1457  * Create/Delete bridge-domain instance
1458  *
1459  * @cliexpar
1460  * @parblock
1461  * Example of creating bridge-domain 1:
1462  * @cliexstart{create bridge-domain 1}
1463  * bridge-domain 1
1464  * @cliexend
1465  *
1466  * Example of creating bridge-domain 2 with enabling arp-term, mac-age 60:
1467  * @cliexstart{create bridge-domain 2 arp-term 1 mac-age 60}
1468  * bridge-domain 2
1469  *
1470  * vpp# show bridge-domain
1471  *   ID   Index   BSN  Age(min)  Learning  U-Forwrd  UU-Flood  Flooding  ARP-Term  BVI-Intf
1472  *   0      0      0     off       off       off       off       off       off      local0
1473  *   1      1      0     off        on        on       off        on       off       N/A
1474  *   2      2      0      60        on        on       off        on        on       N/A
1475  *
1476  * @cliexend
1477  *
1478  * Example of delete bridge-domain 1:
1479  * @cliexstart{create bridge-domain 1 del}
1480  * @cliexend
1481  * @endparblock
1482 ?*/
1483
1484 /* *INDENT-OFF* */
1485 VLIB_CLI_COMMAND (bd_create_cli, static) = {
1486   .path = "create bridge-domain",
1487   .short_help = "create bridge-domain <bridge-domain-id>"
1488                 " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]"
1489                 " [arp-ufwd <0|1>] [mac-age <nn>] [bd-tag <tag>] [del]",
1490   .function = bd_add_del_command_fn,
1491 };
1492 /* *INDENT-ON* */
1493
1494
1495
1496 /*
1497  * fd.io coding-style-patch-verification: ON
1498  *
1499  * Local Variables:
1500  * eval: (c-set-style "gnu")
1501  * End:
1502  */