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