Line data Source code
1 : /*
2 : * l2_input.c : layer 2 input packet processing
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 <vnet/ethernet/ethernet.h>
21 : #include <vnet/ethernet/packet.h>
22 : #include <vnet/ip/ip_packet.h>
23 : #include <vnet/ip/ip4_packet.h>
24 : #include <vnet/ip/ip6_packet.h>
25 : #include <vnet/fib/fib_node.h>
26 : #include <vnet/ethernet/arp_packet.h>
27 : #include <vlib/cli.h>
28 : #include <vnet/l2/l2_input.h>
29 : #include <vnet/l2/l2_output.h>
30 : #include <vnet/l2/feat_bitmap.h>
31 : #include <vnet/l2/l2_bvi.h>
32 : #include <vnet/l2/l2_fib.h>
33 : #include <vnet/l2/l2_bd.h>
34 :
35 : #include <vppinfra/error.h>
36 : #include <vppinfra/hash.h>
37 : #include <vppinfra/cache.h>
38 :
39 : /**
40 : * @file
41 : * @brief Interface Input Mode (Layer 2 Cross-Connect or Bridge / Layer 3).
42 : *
43 : * This file contains the CLI Commands that modify the input mode of an
44 : * interface. For interfaces in a Layer 2 cross-connect, all packets
45 : * received on one interface will be transmitted to the other. For
46 : * interfaces in a bridge-domain, packets will be forwarded to other
47 : * interfaces in the same bridge-domain based on destination mac address.
48 : * For interfaces in Layer 3 mode, the packets will be routed.
49 : */
50 :
51 : /* Feature graph node names */
52 : static char *l2input_feat_names[] = {
53 : #define _(sym,name) name,
54 : foreach_l2input_feat
55 : #undef _
56 : };
57 :
58 : char **
59 9200 : l2input_get_feat_names (void)
60 : {
61 9200 : return l2input_feat_names;
62 : }
63 :
64 : u8 *
65 11466 : format_l2_input_feature_bitmap (u8 * s, va_list * args)
66 : {
67 : static char *display_names[] = {
68 : #define _(sym,name) #sym,
69 : foreach_l2input_feat
70 : #undef _
71 : };
72 11466 : u32 feature_bitmap = va_arg (*args, u32);
73 11466 : u32 verbose = va_arg (*args, u32);
74 :
75 11466 : if (feature_bitmap == 0)
76 : {
77 43 : s = format (s, " none configured");
78 43 : return s;
79 : }
80 :
81 11423 : feature_bitmap &= ~L2INPUT_FEAT_DROP; /* Not a feature */
82 : int i;
83 217037 : for (i = L2INPUT_N_FEAT - 1; i >= 0; i--)
84 : {
85 205614 : if (feature_bitmap & (1 << i))
86 : {
87 38481 : if (verbose)
88 3068 : s = format (s, "%17s (%s)\n",
89 : display_names[i], l2input_feat_names[i]);
90 : else
91 35413 : s = format (s, "%s ", l2input_feat_names[i]);
92 : }
93 : }
94 11423 : return s;
95 : }
96 :
97 : u8 *
98 3 : format_l2_input_features (u8 * s, va_list * args)
99 : {
100 3 : u32 sw_if_index = va_arg (*args, u32);
101 3 : u32 verbose = va_arg (*args, u32);
102 :
103 3 : l2_input_config_t *l2_input = l2input_intf_config (sw_if_index);
104 3 : u32 fb = l2_input->feature_bitmap;
105 :
106 : /* intf input features are masked by bridge domain */
107 3 : if (l2_input_is_bridge (l2_input))
108 0 : fb &= l2_input->bd_feature_bitmap;
109 :
110 : s =
111 3 : format (s, "\nl2-input:\n%U", format_l2_input_feature_bitmap, fb,
112 : verbose);
113 :
114 3 : return (s);
115 : }
116 :
117 : u8 *
118 4111 : format_l2_input (u8 * s, va_list * args)
119 : {
120 4111 : u32 sw_if_index = va_arg (*args, u32);
121 4111 : l2_input_config_t *l2_input = l2input_intf_config (sw_if_index);
122 :
123 : /* intf input features are masked by bridge domain */
124 4111 : if (l2_input_is_bridge (l2_input))
125 : {
126 310 : bd_main_t *bdm = &bd_main;
127 310 : u32 bd_id = l2input_main.bd_configs[l2_input->bd_index].bd_id;
128 :
129 620 : s = format (s, " L2 bridge bd-id %d idx %d shg %d %s",
130 310 : bd_id, bd_find_index (bdm, bd_id), l2_input->shg,
131 310 : l2_input_is_bvi (l2_input) ? "bvi" : " ");
132 : }
133 3801 : else if (l2_input_is_xconnect (l2_input))
134 0 : s = format (s, " L2 xconnect %U",
135 : format_vnet_sw_if_index_name, vnet_get_main (),
136 : l2_input->output_sw_if_index);
137 :
138 4111 : return (s);
139 : }
140 :
141 : clib_error_t *
142 575 : l2input_init (vlib_main_t * vm)
143 : {
144 575 : l2input_main_t *mp = &l2input_main;
145 :
146 575 : mp->vlib_main = vm;
147 575 : mp->vnet_main = vnet_get_main ();
148 :
149 : /* Get packets RX'd from L2 interfaces */
150 575 : ethernet_register_l2_input (vm, l2input_node.index);
151 :
152 : /* Initialize the feature next-node indexes */
153 575 : feat_bitmap_init_next_nodes (vm,
154 : l2input_node.index,
155 : L2INPUT_N_FEAT,
156 : l2input_get_feat_names (),
157 575 : mp->feat_next_node_index);
158 :
159 575 : return 0;
160 : }
161 :
162 19583 : VLIB_INIT_FUNCTION (l2input_init);
163 :
164 :
165 : /** Get a pointer to the config for the given interface. */
166 : l2_input_config_t *
167 31467 : l2input_intf_config (u32 sw_if_index)
168 : {
169 31467 : l2input_main_t *mp = &l2input_main;
170 :
171 31467 : vec_validate (mp->configs, sw_if_index);
172 31467 : return vec_elt_at_index (mp->configs, sw_if_index);
173 : }
174 :
175 : /** Enable (or disable) the feature in the bitmap for the given interface. */
176 : u32
177 1167 : l2input_intf_bitmap_enable (u32 sw_if_index,
178 : l2input_feat_masks_t feature_bitmap, u32 enable)
179 : {
180 1167 : l2_input_config_t *config = l2input_intf_config (sw_if_index);
181 :
182 1167 : if (enable)
183 775 : config->feature_bitmap |= feature_bitmap;
184 : else
185 392 : config->feature_bitmap &= ~feature_bitmap;
186 :
187 1167 : return config->feature_bitmap;
188 : }
189 :
190 : u32
191 0 : l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value)
192 : {
193 0 : l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);;
194 0 : bd_validate (bd_config);
195 0 : bd_config->feature_bitmap =
196 0 : (bd_config->feature_bitmap & ~feat_mask) | feat_value;
197 0 : return bd_config->feature_bitmap;
198 : }
199 :
200 : void
201 1 : l2input_interface_mac_change (u32 sw_if_index,
202 : const u8 * old_address, const u8 * new_address)
203 : {
204 : /* check if the sw_if_index passed is a BVI in a BD */
205 : l2_input_config_t *intf_config;
206 :
207 1 : intf_config = l2input_intf_config (sw_if_index);
208 :
209 1 : if (l2_input_is_bridge (intf_config) && l2_input_is_bvi (intf_config))
210 : {
211 : /* delete and re-add l2fib entry for the bvi interface */
212 1 : l2fib_del_entry (old_address, intf_config->bd_index, sw_if_index);
213 1 : l2fib_add_entry (new_address,
214 1 : intf_config->bd_index,
215 : sw_if_index,
216 : L2FIB_ENTRY_RESULT_FLAG_BVI |
217 : L2FIB_ENTRY_RESULT_FLAG_STATIC);
218 : }
219 1 : }
220 :
221 : walk_rc_t
222 8979 : l2input_recache (u32 bd_index, u32 sw_if_index)
223 : {
224 : l2_input_config_t *input;
225 : l2_bridge_domain_t *bd;
226 :
227 8979 : bd = bd_get (bd_index);
228 8979 : input = l2input_intf_config (sw_if_index);
229 :
230 8979 : input->bd_mac_age = bd->mac_age;
231 8979 : input->bd_seq_num = bd->seq_num;
232 8979 : input->bd_feature_bitmap = bd->feature_bitmap;
233 :
234 8979 : return (WALK_CONTINUE);
235 : }
236 :
237 : void
238 3288 : l2_input_seq_num_inc (u32 sw_if_index)
239 : {
240 : l2_input_config_t *input;
241 :
242 3288 : input = vec_elt_at_index (l2input_main.configs, sw_if_index);
243 :
244 3288 : input->seq_num++;
245 3288 : }
246 :
247 : /**
248 : * Set the subinterface to run in l2 or l3 mode.
249 : * For L3 mode, just the sw_if_index is specified.
250 : * For bridged mode, the bd id and bvi flag are also specified.
251 : * For xconnect mode, the peer sw_if_index is also specified.
252 : * Return 0 if ok, or non-0 if there was an error.
253 : */
254 :
255 : u32
256 3553 : set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */
257 : u32 mode, /* One of L2 modes or back to L3 mode */
258 : u32 sw_if_index, /* sw interface index */
259 : u32 bd_index, /* for bridged interface */
260 : l2_bd_port_type_t port_type, /* port_type */
261 : u32 shg, /* the bridged interface split horizon group */
262 : u32 xc_sw_if_index) /* peer interface for xconnect */
263 : {
264 3553 : l2output_main_t *l2om = &l2output_main;
265 3553 : vnet_main_t *vnm = vnet_get_main ();
266 : vnet_hw_interface_t *hi;
267 : l2_output_config_t *out_config;
268 : l2_input_config_t *config;
269 : l2_bridge_domain_t *bd_config;
270 3553 : i32 l2_if_adjust = 0;
271 : vnet_device_class_t *dev_class;
272 :
273 3553 : hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
274 3553 : config = l2input_intf_config (sw_if_index);
275 :
276 3553 : if (l2fib_main.mac_table_initialized == 0)
277 37 : l2fib_table_init ();
278 :
279 3553 : if (l2_input_is_bridge (config))
280 : {
281 : /* Interface is already in bridge mode. Undo the existing config. */
282 1136 : bd_config = bd_get (config->bd_index);
283 :
284 : /* remove interface from flood vector */
285 1136 : bd_remove_member (bd_config, sw_if_index);
286 :
287 : /* undo any BVI-related config */
288 1136 : if (bd_config->bvi_sw_if_index == sw_if_index)
289 : {
290 : vnet_sw_interface_t *si;
291 :
292 2 : bd_config->bvi_sw_if_index = ~0;
293 2 : config->flags &= ~L2_INPUT_FLAG_BVI;
294 :
295 : /* delete the l2fib entry for the bvi interface */
296 2 : l2fib_del_entry (hi->hw_address, config->bd_index, sw_if_index);
297 :
298 : /* since this is a no longer BVI interface do not to flood to it */
299 2 : si = vnet_get_sw_interface (vnm, sw_if_index);
300 2 : si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
301 : }
302 1136 : if (bd_config->uu_fwd_sw_if_index == sw_if_index)
303 : {
304 2 : bd_config->uu_fwd_sw_if_index = ~0;
305 2 : bd_config->feature_bitmap &= ~L2INPUT_FEAT_UU_FWD;
306 : }
307 :
308 : /* Clear MACs learned on the interface */
309 1136 : if ((config->feature_bitmap & L2INPUT_FEAT_LEARN) ||
310 2 : (bd_config->feature_bitmap & L2INPUT_FEAT_LEARN))
311 1136 : l2fib_flush_int_mac (vm, sw_if_index);
312 :
313 1136 : bd_input_walk (config->bd_index, l2input_recache, NULL);
314 1136 : l2_if_adjust--;
315 : }
316 2417 : else if (l2_input_is_xconnect (config))
317 : {
318 40 : l2_if_adjust--;
319 : }
320 :
321 : /* Make sure vector is big enough */
322 4595 : vec_validate_init_empty (l2om->output_node_index_vec, sw_if_index,
323 : L2OUTPUT_NEXT_DROP);
324 :
325 : /* Initialize the l2-input configuration for the interface */
326 3553 : if (mode == MODE_L3)
327 : {
328 : /* Set L2 config to BD index 0 so that if any packet accidentally
329 : * came in on L2 path, it will be dropped in BD 0 */
330 2249 : config->flags = L2_INPUT_FLAG_NONE;
331 2249 : config->shg = 0;
332 2249 : config->bd_index = 0;
333 2249 : config->feature_bitmap = L2INPUT_FEAT_DROP;
334 :
335 : /* Clear L2 output config */
336 2249 : out_config = l2output_intf_config (sw_if_index);
337 2249 : clib_memset (out_config, 0, sizeof (l2_output_config_t));
338 :
339 : /* Make sure any L2-output packet to this interface now in L3 mode is
340 : * dropped. This may happen if L2 FIB MAC entry is stale */
341 2249 : l2om->output_node_index_vec[sw_if_index] = L2OUTPUT_NEXT_BAD_INTF;
342 : }
343 : else
344 : {
345 : /* Add or update l2-output node next-arc and output_node_index_vec table
346 : * for the interface */
347 1304 : l2output_create_output_node_mapping (vm, vnet_main, sw_if_index);
348 :
349 1304 : if (mode == MODE_L2_BRIDGE)
350 : {
351 : u8 member_flags;
352 :
353 : /*
354 : * Remove a check that the interface must be an Ethernet.
355 : * Specifically so we can bridge to L3 tunnel interfaces.
356 : * Here's the check:
357 : * if (hi->hw_class_index != ethernet_hw_interface_class.index)
358 : *
359 : */
360 1256 : if (!hi)
361 0 : return MODE_ERROR_ETH; /* non-ethernet */
362 :
363 1256 : config->flags = L2_INPUT_FLAG_BRIDGE;
364 1256 : config->bd_index = bd_index;
365 1256 : l2_input_seq_num_inc (sw_if_index);
366 :
367 : /*
368 : * Enable forwarding, flooding, learning and ARP termination by default
369 : * (note that ARP term is disabled on BD feature bitmap by default)
370 : */
371 1256 : config->feature_bitmap |= (L2INPUT_FEAT_FWD |
372 : L2INPUT_FEAT_UU_FLOOD |
373 : L2INPUT_FEAT_UU_FWD |
374 : L2INPUT_FEAT_FLOOD |
375 : L2INPUT_FEAT_LEARN |
376 : L2INPUT_FEAT_ARP_UFWD |
377 : L2INPUT_FEAT_ARP_TERM);
378 :
379 : /* Make sure last-chance drop is configured */
380 1256 : config->feature_bitmap |= L2INPUT_FEAT_DROP;
381 :
382 : /* Make sure xconnect is disabled */
383 1256 : config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT;
384 :
385 : /* Set up bridge domain */
386 1256 : bd_config = l2input_bd_config (bd_index);
387 1256 : bd_validate (bd_config);
388 :
389 : /* TODO: think: add l2fib entry even for non-bvi interface? */
390 :
391 : /* Do BVI interface initializations */
392 1256 : if (L2_BD_PORT_TYPE_BVI == port_type)
393 : {
394 : vnet_sw_interface_t *si;
395 :
396 : /* ensure BD has no bvi interface (or replace that one with this??) */
397 11 : if (bd_config->bvi_sw_if_index != ~0)
398 : {
399 0 : return MODE_ERROR_BVI_DEF; /* bd already has a bvi interface */
400 : }
401 11 : bd_config->bvi_sw_if_index = sw_if_index;
402 11 : config->flags |= L2_INPUT_FLAG_BVI;
403 :
404 : /* create the l2fib entry for the bvi interface */
405 11 : l2fib_add_entry (hi->hw_address, bd_index, sw_if_index,
406 : L2FIB_ENTRY_RESULT_FLAG_BVI |
407 : L2FIB_ENTRY_RESULT_FLAG_STATIC);
408 :
409 : /* Disable learning by default. no use since l2fib entry is static. */
410 11 : config->feature_bitmap &= ~L2INPUT_FEAT_LEARN;
411 :
412 : /* since this is a BVI interface we want to flood to it */
413 11 : si = vnet_get_sw_interface (vnm, sw_if_index);
414 11 : si->flood_class = VNET_FLOOD_CLASS_BVI;
415 11 : member_flags = L2_FLOOD_MEMBER_BVI;
416 : }
417 1245 : else if (L2_BD_PORT_TYPE_UU_FWD == port_type)
418 : {
419 2 : bd_config->uu_fwd_sw_if_index = sw_if_index;
420 2 : bd_config->feature_bitmap |= L2INPUT_FEAT_UU_FWD;
421 : }
422 : else
423 : {
424 1243 : member_flags = L2_FLOOD_MEMBER_NORMAL;
425 : }
426 :
427 1256 : if (L2_BD_PORT_TYPE_NORMAL == port_type ||
428 : L2_BD_PORT_TYPE_BVI == port_type)
429 : {
430 : /* Add interface to bridge-domain flood vector */
431 1254 : l2_flood_member_t member = {
432 : .sw_if_index = sw_if_index,
433 : .flags = member_flags,
434 : .shg = shg,
435 : };
436 1254 : bd_add_member (bd_config, &member);
437 : }
438 : }
439 48 : else if (mode == MODE_L2_XC)
440 : {
441 48 : config->flags = L2_INPUT_FLAG_XCONNECT;
442 48 : config->output_sw_if_index = xc_sw_if_index;
443 :
444 : /* Make sure last-chance drop is configured */
445 48 : config->feature_bitmap |= L2INPUT_FEAT_DROP;
446 :
447 : /* Make sure bridging features are disabled */
448 48 : config->feature_bitmap &=
449 : ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);
450 :
451 48 : config->feature_bitmap |= L2INPUT_FEAT_XCONNECT;
452 48 : shg = 0; /* not used in xconnect */
453 : }
454 0 : else if (mode == MODE_L2_CLASSIFY)
455 : {
456 0 : config->flags = L2_INPUT_FLAG_XCONNECT;
457 0 : config->output_sw_if_index = xc_sw_if_index;
458 :
459 : /* Make sure last-chance drop is configured */
460 0 : config->feature_bitmap |=
461 : L2INPUT_FEAT_DROP | L2INPUT_FEAT_INPUT_CLASSIFY;
462 :
463 : /* Make sure bridging features are disabled */
464 0 : config->feature_bitmap &=
465 : ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);
466 0 : shg = 0; /* not used in xconnect */
467 : }
468 :
469 : /* set up split-horizon group and set output feature bit */
470 1304 : config->shg = shg;
471 1304 : out_config = l2output_intf_config (sw_if_index);
472 1304 : out_config->shg = shg;
473 1304 : out_config->feature_bitmap |= L2OUTPUT_FEAT_OUTPUT;
474 :
475 : /*
476 : * Test: remove this when non-IP features can be configured.
477 : * Enable a non-IP feature to test IP feature masking
478 : * config->feature_bitmap |= L2INPUT_FEAT_CTRL_PKT;
479 : */
480 :
481 1304 : l2_if_adjust++;
482 :
483 1304 : bd_input_walk (bd_index, l2input_recache, NULL);
484 : }
485 :
486 : /* Adjust count of L2 interfaces */
487 3553 : hi->l2_if_count += l2_if_adjust;
488 :
489 3553 : if (hi->hw_class_index == ethernet_hw_interface_class.index)
490 : {
491 3410 : if ((hi->l2_if_count == 1) && (l2_if_adjust == 1))
492 : {
493 : /* Just added first L2 interface on this port
494 : * Set promiscuous mode on the l2 interface */
495 1172 : ethernet_set_flags (vnet_main, hi->hw_if_index,
496 : ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
497 : }
498 2238 : else if ((hi->l2_if_count == 0) && (l2_if_adjust == -1))
499 : {
500 : /* Just removed only L2 subinterface on this port
501 : * Disable promiscuous mode on the l2 interface */
502 1096 : ethernet_set_flags (vnet_main, hi->hw_if_index,
503 : /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);
504 :
505 : }
506 : }
507 :
508 : /* Set up the L2/L3 flag in the interface parsing tables */
509 3553 : ethernet_sw_interface_set_l2_mode (vnm, sw_if_index, (mode != MODE_L3));
510 :
511 3553 : dev_class = vnet_get_device_class (vnet_main, hi->dev_class_index);
512 3553 : if (dev_class->set_l2_mode_function)
513 : {
514 0 : dev_class->set_l2_mode_function (vnet_main, hi, l2_if_adjust);
515 : }
516 :
517 3553 : return 0;
518 : }
519 :
520 : static clib_error_t *
521 11798 : l2_input_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
522 : {
523 11798 : if (!is_add)
524 : {
525 4251 : vlib_main_t *vm = vlib_get_main ();
526 : l2_input_config_t *config;
527 :
528 4251 : if (sw_if_index < vec_len (l2input_main.configs))
529 : {
530 4175 : config = vec_elt_at_index (l2input_main.configs, sw_if_index);
531 4175 : if (l2_input_is_xconnect (config))
532 3 : set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0,
533 : L2_BD_PORT_TYPE_NORMAL, 0, 0);
534 4175 : if (l2_input_is_xconnect (config) || l2_input_is_bridge (config))
535 897 : set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
536 : L2_BD_PORT_TYPE_NORMAL, 0, 0);
537 : }
538 : }
539 :
540 11798 : return (NULL);
541 : }
542 :
543 3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (l2_input_interface_add_del);
544 :
545 : /**
546 : * Set subinterface in bridging mode with a bridge-domain ID.
547 : * The CLI format is:
548 : * set interface l2 bridge <interface> <bd> [bvi] [split-horizon-group]
549 : */
550 : static clib_error_t *
551 0 : int_l2_bridge (vlib_main_t * vm,
552 : unformat_input_t * input, vlib_cli_command_t * cmd)
553 : {
554 0 : vnet_main_t *vnm = vnet_get_main ();
555 : l2_bd_port_type_t port_type;
556 0 : clib_error_t *error = 0;
557 : u32 bd_index, bd_id;
558 : u32 sw_if_index;
559 : u32 rc;
560 : u32 shg;
561 :
562 0 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
563 : {
564 0 : error = clib_error_return (0, "unknown interface `%U'",
565 : format_unformat_error, input);
566 0 : goto done;
567 : }
568 :
569 0 : if (!unformat (input, "%d", &bd_id))
570 : {
571 0 : error = clib_error_return (0, "expected bridge domain ID `%U'",
572 : format_unformat_error, input);
573 0 : goto done;
574 : }
575 :
576 0 : if (bd_id > L2_BD_ID_MAX)
577 : {
578 0 : error = clib_error_return (0, "bridge domain ID exceed 16M limit",
579 : format_unformat_error, input);
580 0 : goto done;
581 : }
582 0 : bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
583 :
584 : /* optional bvi */
585 0 : port_type = L2_BD_PORT_TYPE_NORMAL;
586 0 : if (unformat (input, "bvi"))
587 0 : port_type = L2_BD_PORT_TYPE_BVI;
588 0 : if (unformat (input, "uu-fwd"))
589 0 : port_type = L2_BD_PORT_TYPE_UU_FWD;
590 :
591 : /* optional split horizon group */
592 0 : shg = 0;
593 0 : (void) unformat (input, "%d", &shg);
594 :
595 : /* set the interface mode */
596 0 : if ((rc =
597 0 : set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE, sw_if_index, bd_index,
598 : port_type, shg, 0)))
599 : {
600 0 : if (rc == MODE_ERROR_ETH)
601 : {
602 0 : error = clib_error_return (0, "bridged interface must be ethernet",
603 : format_unformat_error, input);
604 : }
605 0 : else if (rc == MODE_ERROR_BVI_DEF)
606 : {
607 : error =
608 0 : clib_error_return (0, "bridge-domain already has a bvi interface",
609 : format_unformat_error, input);
610 : }
611 : else
612 : {
613 0 : error = clib_error_return (0, "invalid configuration for interface",
614 : format_unformat_error, input);
615 : }
616 0 : goto done;
617 : }
618 :
619 0 : done:
620 0 : return error;
621 : }
622 :
623 : /*?
624 : * Use this command put an interface into Layer 2 bridge domain. If a
625 : * bridge-domain with the provided bridge-domain-id does not exist, it
626 : * will be created. Interfaces in a bridge-domain forward packets to
627 : * other interfaces in the same bridge-domain based on destination mac
628 : * address. To remove an interface from a the Layer 2 bridge domain,
629 : * put the interface in a different mode, for example Layer 3 mode.
630 : *
631 : * Optionally, an interface can be added to a Layer 2 bridge-domain as
632 : * a Bridged Virtual Interface (bvi). Only one interface in a Layer 2
633 : * bridge-domain can be a bvi.
634 : *
635 : * Optionally, a split-horizon group can also be specified. This defaults
636 : * to 0 if not specified.
637 : *
638 : * @cliexpar
639 : * Example of how to configure a Layer 2 bridge-domain with three
640 : * interfaces (where 200 is the bridge-domain-id):
641 : * @cliexcmd{set interface l2 bridge GigabitEthernet0/8/0.200 200}
642 : * This interface is added a BVI interface:
643 : * @cliexcmd{set interface l2 bridge GigabitEthernet0/9/0.200 200 bvi}
644 : * This interface also has a split-horizon group of 1 specified:
645 : * @cliexcmd{set interface l2 bridge GigabitEthernet0/a/0.200 200 1}
646 : * Example of how to remove an interface from a Layer2 bridge-domain:
647 : * @cliexcmd{set interface l3 GigabitEthernet0/a/0.200}
648 : ?*/
649 : /* *INDENT-OFF* */
650 285289 : VLIB_CLI_COMMAND (int_l2_bridge_cli, static) = {
651 : .path = "set interface l2 bridge",
652 : .short_help = "set interface l2 bridge <interface> <bridge-domain-id> [bvi|uu-fwd] [shg]",
653 : .function = int_l2_bridge,
654 : };
655 : /* *INDENT-ON* */
656 :
657 : /**
658 : * Set subinterface in xconnect mode with another interface.
659 : * The CLI format is:
660 : * set interface l2 xconnect <interface> <peer interface>
661 : */
662 : static clib_error_t *
663 0 : int_l2_xc (vlib_main_t * vm,
664 : unformat_input_t * input, vlib_cli_command_t * cmd)
665 : {
666 0 : vnet_main_t *vnm = vnet_get_main ();
667 0 : clib_error_t *error = 0;
668 : u32 sw_if_index;
669 : u32 xc_sw_if_index;
670 :
671 0 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
672 : {
673 0 : error = clib_error_return (0, "unknown interface `%U'",
674 : format_unformat_error, input);
675 0 : goto done;
676 : }
677 :
678 0 : if (!unformat_user
679 : (input, unformat_vnet_sw_interface, vnm, &xc_sw_if_index))
680 : {
681 0 : error = clib_error_return (0, "unknown peer interface `%U'",
682 : format_unformat_error, input);
683 0 : goto done;
684 : }
685 :
686 : /* set the interface mode */
687 0 : if (set_int_l2_mode
688 : (vm, vnm, MODE_L2_XC, sw_if_index, 0, L2_BD_PORT_TYPE_NORMAL,
689 : 0, xc_sw_if_index))
690 : {
691 0 : error = clib_error_return (0, "invalid configuration for interface",
692 : format_unformat_error, input);
693 0 : goto done;
694 : }
695 :
696 0 : done:
697 0 : return error;
698 : }
699 :
700 : /*?
701 : * Use this command put an interface into Layer 2 cross-connect mode.
702 : * Both interfaces must be in this mode for bi-directional traffic. All
703 : * packets received on one interface will be transmitted to the other.
704 : * To remove the Layer 2 cross-connect, put the interface in a different
705 : * mode, for example Layer 3 mode.
706 : *
707 : * @cliexpar
708 : * Example of how to configure a Layer2 cross-connect between two interfaces:
709 : * @cliexcmd{set interface l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300}
710 : * @cliexcmd{set interface l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300}
711 : * Example of how to remove a Layer2 cross-connect:
712 : * @cliexcmd{set interface l3 GigabitEthernet0/8/0.300}
713 : * @cliexcmd{set interface l3 GigabitEthernet0/9/0.300}
714 : ?*/
715 : /* *INDENT-OFF* */
716 285289 : VLIB_CLI_COMMAND (int_l2_xc_cli, static) = {
717 : .path = "set interface l2 xconnect",
718 : .short_help = "set interface l2 xconnect <interface> <peer interface>",
719 : .function = int_l2_xc,
720 : };
721 : /* *INDENT-ON* */
722 :
723 : /**
724 : * Set subinterface in L3 mode.
725 : * The CLI format is:
726 : * set interface l3 <interface>
727 : */
728 : static clib_error_t *
729 0 : int_l3 (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
730 : {
731 0 : vnet_main_t *vnm = vnet_get_main ();
732 0 : clib_error_t *error = 0;
733 : u32 sw_if_index;
734 :
735 0 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
736 : {
737 0 : error = clib_error_return (0, "unknown interface `%U'",
738 : format_unformat_error, input);
739 0 : goto done;
740 : }
741 :
742 : /* set the interface mode */
743 0 : if (set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
744 : L2_BD_PORT_TYPE_NORMAL, 0, 0))
745 : {
746 0 : error = clib_error_return (0, "invalid configuration for interface",
747 : format_unformat_error, input);
748 0 : goto done;
749 : }
750 :
751 0 : done:
752 0 : return error;
753 : }
754 :
755 : /*?
756 : * Modify the packet processing mode of the interface to Layer 3, which
757 : * implies packets will be routed. This is the default mode of an interface.
758 : * Use this command to remove an interface from a Layer 2 cross-connect or a
759 : * Layer 2 bridge.
760 : *
761 : * @cliexpar
762 : * Example of how to set the mode of an interface to Layer 3:
763 : * @cliexcmd{set interface l3 GigabitEthernet0/8/0.200}
764 : ?*/
765 : /* *INDENT-OFF* */
766 285289 : VLIB_CLI_COMMAND (int_l3_cli, static) = {
767 : .path = "set interface l3",
768 : .short_help = "set interface l3 <interface>",
769 : .function = int_l3,
770 : };
771 : /* *INDENT-ON* */
772 :
773 : /**
774 : * Show interface mode.
775 : * The CLI format is:
776 : * show mode [<if-name1> <if-name2> ...]
777 : */
778 : static clib_error_t *
779 0 : show_int_mode (vlib_main_t * vm,
780 : unformat_input_t * input, vlib_cli_command_t * cmd)
781 : {
782 0 : vnet_main_t *vnm = vnet_get_main ();
783 0 : clib_error_t *error = 0;
784 : char *mode;
785 : u8 *args;
786 0 : vnet_interface_main_t *im = &vnm->interface_main;
787 :
788 0 : vnet_sw_interface_t *si, *sis = 0;
789 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
790 : {
791 : u32 sw_if_index;
792 :
793 : /* See if user wants to show specific interface */
794 0 : if (unformat
795 : (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
796 : {
797 0 : si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
798 0 : vec_add1 (sis, si[0]);
799 : }
800 : else
801 : {
802 0 : error = clib_error_return (0, "unknown input `%U'",
803 : format_unformat_error, input);
804 0 : goto done;
805 : }
806 : }
807 :
808 0 : if (vec_len (sis) == 0) /* Get all interfaces */
809 : {
810 : /* Gather interfaces. */
811 0 : sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
812 0 : vec_set_len (sis, 0);
813 : /* *INDENT-OFF* */
814 0 : pool_foreach (si, im->sw_interfaces) { vec_add1 (sis, si[0]); }
815 : /* *INDENT-ON* */
816 : }
817 :
818 0 : vec_foreach (si, sis)
819 : {
820 0 : l2_input_config_t *config = l2input_intf_config (si->sw_if_index);
821 0 : if (l2_input_is_bridge (config))
822 : {
823 : u32 bd_id;
824 0 : mode = "l2 bridge";
825 0 : bd_id = l2input_main.bd_configs[config->bd_index].bd_id;
826 :
827 0 : args = format (0, "bd_id %d%s shg %d", bd_id,
828 0 : l2_input_is_bvi (config) ? " bvi" : "", config->shg);
829 : }
830 0 : else if (l2_input_is_xconnect (config))
831 : {
832 0 : mode = "l2 xconnect";
833 0 : args = format (0, "%U",
834 : format_vnet_sw_if_index_name,
835 : vnm, config->output_sw_if_index);
836 : }
837 : else
838 : {
839 0 : mode = "l3";
840 0 : args = format (0, " ");
841 : }
842 0 : vlib_cli_output (vm, "%s %U %v\n",
843 : mode,
844 : format_vnet_sw_if_index_name,
845 : vnm, si->sw_if_index, args);
846 0 : vec_free (args);
847 : }
848 :
849 0 : done:
850 0 : vec_free (sis);
851 :
852 0 : return error;
853 : }
854 :
855 : /*?
856 : * Show the packet processing mode (Layer2 cross-connect, Layer 2 bridge,
857 : * Layer 3 routed) of all interfaces and sub-interfaces, or limit the
858 : * output to just the provided list of interfaces and sub-interfaces.
859 : * The output shows the mode, the interface, and if the interface is
860 : * a member of a bridge, the bridge-domain-id and the split horizon group (shg).
861 : *
862 : * @cliexpar
863 : * Example of displaying the mode of all interfaces:
864 : * @cliexstart{show mode}
865 : * l3 local0
866 : * l3 GigabitEthernet0/8/0
867 : * l3 GigabitEthernet0/9/0
868 : * l3 GigabitEthernet0/a/0
869 : * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0
870 : * l2 bridge GigabitEthernet0/9/0.200 bd_id 200 shg 0
871 : * l2 bridge GigabitEthernet0/a/0.200 bd_id 200 shg 0
872 : * l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300
873 : * l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300
874 : * @cliexend
875 : * Example of displaying the mode of a selected list of interfaces:
876 : * @cliexstart{show mode GigabitEthernet0/8/0 GigabitEthernet0/8/0.200}
877 : * l3 GigabitEthernet0/8/0
878 : * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0
879 : * @cliexend
880 : ?*/
881 : /* *INDENT-OFF* */
882 285289 : VLIB_CLI_COMMAND (show_l2_mode, static) = {
883 : .path = "show mode",
884 : .short_help = "show mode [<if-name1> <if-name2> ...]",
885 : .function = show_int_mode,
886 : };
887 : /* *INDENT-ON* */
888 :
889 : #define foreach_l2_init_function \
890 : _(feat_bitmap_drop_init) \
891 : _(l2fib_init) \
892 : _(l2_input_classify_init) \
893 : _(l2bd_init) \
894 : _(l2fwd_init) \
895 : _(l2_in_out_acl_init) \
896 : _(l2input_init) \
897 : _(l2_vtr_init) \
898 : _(l2_invtr_init) \
899 : _(l2_efp_filter_init) \
900 : _(l2learn_init) \
901 : _(l2flood_init) \
902 : _(l2output_init) \
903 : _(l2_patch_init) \
904 : _(l2_xcrw_init)
905 :
906 : clib_error_t *
907 575 : l2_init (vlib_main_t * vm)
908 : {
909 : clib_error_t *error;
910 :
911 : #define _(a) do { \
912 : if ((error = vlib_call_init_function (vm, a))) return error; } \
913 : while (0);
914 575 : foreach_l2_init_function;
915 : #undef _
916 575 : return 0;
917 : }
918 :
919 11519 : VLIB_INIT_FUNCTION (l2_init);
920 :
921 : /*
922 : * fd.io coding-style-patch-verification: ON
923 : *
924 : * Local Variables:
925 : * eval: (c-set-style "gnu")
926 : * End:
927 : */
|