2 * l2_input.c : layer 2 input packet processing
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vnet/pg/pg.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/ethernet/packet.h>
23 #include <vnet/ip/ip_packet.h>
24 #include <vnet/ip/ip4_packet.h>
25 #include <vnet/ip/ip6_packet.h>
26 #include <vnet/fib/fib_node.h>
27 #include <vnet/ethernet/arp_packet.h>
29 #include <vnet/l2/l2_input.h>
30 #include <vnet/l2/l2_output.h>
31 #include <vnet/l2/feat_bitmap.h>
32 #include <vnet/l2/l2_bvi.h>
33 #include <vnet/l2/l2_fib.h>
34 #include <vnet/l2/l2_bd.h>
36 #include <vppinfra/error.h>
37 #include <vppinfra/hash.h>
38 #include <vppinfra/cache.h>
42 * @brief Interface Input Mode (Layer 2 Cross-Connect or Bridge / Layer 3).
44 * This file contains the CLI Commands that modify the input mode of an
45 * interface. For interfaces in a Layer 2 cross-connect, all packets
46 * received on one interface will be transmitted to the other. For
47 * interfaces in a bridge-domain, packets will be forwarded to other
48 * interfaces in the same bridge-domain based on destination mac address.
49 * For interfaces in Layer 3 mode, the packets will be routed.
52 /* Feature graph node names */
53 static char *l2input_feat_names[] = {
54 #define _(sym,name) name,
60 l2input_get_feat_names (void)
62 return l2input_feat_names;
66 format_l2_input_features (u8 * s, va_list * args)
68 static char *display_names[] = {
69 #define _(sym,name) #sym,
73 u32 feature_bitmap = va_arg (*args, u32);
75 if (feature_bitmap == 0)
77 s = format (s, " none configured");
81 feature_bitmap &= ~L2INPUT_FEAT_DROP; /* Not a feature */
83 for (i = L2INPUT_N_FEAT; i >= 0; i--)
84 if (feature_bitmap & (1 << i))
85 s = format (s, "%10s (%s)\n", display_names[i], l2input_feat_names[i]);
91 /* per-pkt trace data */
98 /* packet trace format function */
100 format_l2input_trace (u8 * s, va_list * args)
102 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
103 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
104 l2input_trace_t *t = va_arg (*args, l2input_trace_t *);
106 s = format (s, "l2-input: sw_if_index %d dst %U src %U",
108 format_ethernet_address, t->dst,
109 format_ethernet_address, t->src);
113 l2input_main_t l2input_main;
115 #define foreach_l2input_error \
116 _(L2INPUT, "L2 input packets") \
117 _(DROP, "L2 input drops")
121 #define _(sym,str) L2INPUT_ERROR_##sym,
122 foreach_l2input_error
127 static char *l2input_error_strings[] = {
128 #define _(sym,string) string,
129 foreach_l2input_error
141 static_always_inline u32
142 l2_input_classiy_unicast (vlib_buffer_t * b, const ethernet_header_t * h0)
145 u8 *l3h0 = (u8 *) h0 + vnet_buffer (b)->l2.l2_len;
147 #define get_u16(addr) ( *((u16 *)(addr)) )
148 u16 ethertype = clib_net_to_host_u16 (get_u16 (l3h0 - 2));
149 u8 protocol = ((ip6_header_t *) l3h0)->protocol;
151 /* Disable bridge forwarding (flooding will execute instead if not xconnect) */
152 feat_mask &= ~(L2INPUT_FEAT_FWD |
153 L2INPUT_FEAT_UU_FLOOD | L2INPUT_FEAT_GBP_FWD);
155 /* Disable ARP-term for non-ARP and non-ICMP6 packet */
156 if (ethertype != ETHERNET_TYPE_ARP &&
157 (ethertype != ETHERNET_TYPE_IP6 || protocol != IP_PROTOCOL_ICMP6))
158 feat_mask &= ~(L2INPUT_FEAT_ARP_TERM);
161 * For packet from BVI - set SHG of ARP request or ICMPv6 neighbor
162 * solicitation packet from BVI to 0 so it can also flood to VXLAN
163 * tunnels or other ports with the same SHG as that of the BVI.
165 else if (PREDICT_FALSE (vnet_buffer (b)->sw_if_index[VLIB_TX] ==
168 if (ethertype == ETHERNET_TYPE_ARP)
170 ethernet_arp_header_t *arp0 = (ethernet_arp_header_t *) l3h0;
172 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request))
173 vnet_buffer (b)->l2.shg = 0;
175 else /* must be ICMPv6 */
177 ip6_header_t *iph0 = (ip6_header_t *) l3h0;
178 icmp6_neighbor_solicitation_or_advertisement_header_t *ndh0;
179 ndh0 = ip6_next_header (iph0);
180 if (ndh0->icmp.type == ICMP6_neighbor_solicitation)
181 vnet_buffer (b)->l2.shg = 0;
188 static_always_inline void
189 l2_input_classify_bridge (l2_bridge_domain_t * bd_config,
191 u32 sw_if_index, vlib_buffer_t * b, u32 * feat_mask)
193 /* save BD ID for next feature graph nodes */
194 vnet_buffer (b)->l2.bd_index = bd_index;
196 /* Save bridge domain and interface seq_num */
198 l2fib_seq_num_t sn = {
199 .swif = *l2fib_swif_seq_num(sw_if_index),
200 .bd = bd_config->seq_num,
203 vnet_buffer (b)->l2.l2fib_sn = sn.as_u16;;
204 vnet_buffer (b)->l2.bd_age = bd_config->mac_age;
207 * Process bridge domain feature enables.
208 * To perform learning/flooding/forwarding, the corresponding bit
209 * must be enabled in both the input interface config and in the
210 * bridge domain config. In the bd_bitmap, bits for features other
211 * than learning/flooding/forwarding should always be set.
213 *feat_mask = *feat_mask & bd_config->feature_bitmap;
216 static_always_inline void
217 classify_and_dispatch (l2input_main_t * msm,
219 u32 sw_if_index, vlib_buffer_t ** b, u16 * next)
222 * Load L2 input feature struct
223 * Load bridge domain struct
224 * Parse ethernet header to determine unicast/mcast/broadcast
226 * classify packet as IP/UDP/TCP, control, other
227 * mask feature bitmap
228 * go to first node in bitmap
229 * Later: optimize VTM
232 * set tx sw-if-handle
235 l2_input_config_t *config;
237 /* Get config for the input interface */
238 config = vec_elt_at_index (msm->configs, sw_if_index);
242 const ethernet_header_t *h0, *h1, *h2, *h3;
243 u32 fm0, fm1, fm2, fm3;
244 u32 fb0, fb1, fb2, fb3;
248 vlib_prefetch_buffer_header (b[0], LOAD);
249 vlib_prefetch_buffer_header (b[1], LOAD);
250 vlib_prefetch_buffer_header (b[2], LOAD);
251 vlib_prefetch_buffer_header (b[3], LOAD);
254 fm0 = fm1 = fm2 = fm3 = ~0;
255 h0 = vlib_buffer_get_current (b[0]);
256 h1 = vlib_buffer_get_current (b[1]);
257 h2 = vlib_buffer_get_current (b[2]);
258 h3 = vlib_buffer_get_current (b[3]);
260 /* Save split horizon group */
261 vnet_buffer (b[0])->l2.shg = config->shg;
262 vnet_buffer (b[1])->l2.shg = config->shg;
263 vnet_buffer (b[2])->l2.shg = config->shg;
264 vnet_buffer (b[3])->l2.shg = config->shg;
266 /* determine layer2 kind for stat and mask */
267 if (PREDICT_FALSE (ethernet_address_cast (h0->dst_address)))
269 fm0 = l2_input_classiy_unicast (b[0], h0);
273 if (PREDICT_FALSE (sw_if_index == L2INPUT_BVI))
274 vnet_buffer (b[0])->l2.shg = 0;
276 if (PREDICT_FALSE (ethernet_address_cast (h1->dst_address)))
278 fm1 = l2_input_classiy_unicast (b[1], h1);
282 if (PREDICT_FALSE (sw_if_index == L2INPUT_BVI))
283 vnet_buffer (b[1])->l2.shg = 0;
285 if (PREDICT_FALSE (ethernet_address_cast (h2->dst_address)))
287 fm2 = l2_input_classiy_unicast (b[2], h2);
291 if (PREDICT_FALSE (sw_if_index == L2INPUT_BVI))
292 vnet_buffer (b[1])->l2.shg = 0;
294 if (PREDICT_FALSE (ethernet_address_cast (h3->dst_address)))
296 fm3 = l2_input_classiy_unicast (b[3], h3);
300 if (PREDICT_FALSE (sw_if_index == L2INPUT_BVI))
301 vnet_buffer (b[1])->l2.shg = 0;
306 /* Do bridge-domain processing */
307 l2_bridge_domain_t *bd_config;
310 bd_index = config->bd_index;
311 bd_config = vec_elt_at_index (msm->bd_configs, bd_index);
313 l2_input_classify_bridge (bd_config, bd_index, sw_if_index,
315 l2_input_classify_bridge (bd_config, bd_index, sw_if_index,
317 l2_input_classify_bridge (bd_config, bd_index, sw_if_index,
319 l2_input_classify_bridge (bd_config, bd_index, sw_if_index,
322 else if (config->xconnect)
324 /* Set the output interface */
325 vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
326 config->output_sw_if_index;
327 vnet_buffer (b[1])->sw_if_index[VLIB_TX] =
328 config->output_sw_if_index;
329 vnet_buffer (b[2])->sw_if_index[VLIB_TX] =
330 config->output_sw_if_index;
331 vnet_buffer (b[3])->sw_if_index[VLIB_TX] =
332 config->output_sw_if_index;
336 fm0 = L2INPUT_FEAT_DROP;
337 fm1 = L2INPUT_FEAT_DROP;
338 fm2 = L2INPUT_FEAT_DROP;
339 fm3 = L2INPUT_FEAT_DROP;
342 /* mask out features from bitmap using packet type and bd config */
343 fb0 = config->feature_bitmap & fm0;
344 fb1 = config->feature_bitmap & fm1;
345 fb2 = config->feature_bitmap & fm2;
346 fb3 = config->feature_bitmap & fm3;
348 /* save for next feature graph nodes */
349 vnet_buffer (b[0])->l2.feature_bitmap = fb0;
350 vnet_buffer (b[1])->l2.feature_bitmap = fb1;
351 vnet_buffer (b[2])->l2.feature_bitmap = fb2;
352 vnet_buffer (b[3])->l2.feature_bitmap = fb3;
354 /* Determine the next node */
355 *next = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
358 *next = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
361 *next = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
364 *next = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
373 const ethernet_header_t *h0;
377 h0 = vlib_buffer_get_current (b[0]);
379 /* Save split horizon group */
380 vnet_buffer (b[0])->l2.shg = config->shg;
382 /* determine layer2 kind for stat and mask */
383 if (PREDICT_FALSE (ethernet_address_cast (h0->dst_address)))
385 fm0 = l2_input_classiy_unicast (b[0], h0);
390 * For packet from BVI - set SHG of unicast packet from BVI to 0 so it
391 * is not dropped on output to VXLAN tunnels or other ports with the
392 * same SHG as that of the BVI.
394 if (PREDICT_FALSE (sw_if_index == L2INPUT_BVI))
395 vnet_buffer (b[0])->l2.shg = 0;
400 /* Do bridge-domain processing */
401 u16 bd_index = config->bd_index;
402 l2_bridge_domain_t *bd_config =
403 vec_elt_at_index (msm->bd_configs, bd_index);
405 l2_input_classify_bridge (bd_config, bd_index, sw_if_index,
408 else if (config->xconnect)
410 /* Set the output interface */
411 vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
412 config->output_sw_if_index;
415 fm0 = L2INPUT_FEAT_DROP;
417 /* mask out features from bitmap using packet type and bd config */
418 fb0 = config->feature_bitmap & fm0;
420 /* save for next feature graph nodes */
421 vnet_buffer (b[0])->l2.feature_bitmap = fb0;
423 /* Determine the next node */
424 *next = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
433 static_always_inline uword
434 l2input_node_inline (vlib_main_t * vm,
435 vlib_node_runtime_t * node, vlib_frame_t * frame,
439 l2input_main_t *msm = &l2input_main;
440 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
441 u16 nexts[VLIB_FRAME_SIZE];
442 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
444 from = vlib_frame_vector_args (frame);
445 n_left = frame->n_vectors; /* number of packets to process */
446 vlib_get_buffers (vm, from, bufs, n_left);
448 sw_if_index = sw_if_indices;
450 /* extract data from buffer metadata */
453 /* Prefetch the buffer header for the N+2 loop iteration */
454 vlib_prefetch_buffer_header (b[4], LOAD);
455 vlib_prefetch_buffer_header (b[5], LOAD);
456 vlib_prefetch_buffer_header (b[6], LOAD);
457 vlib_prefetch_buffer_header (b[7], LOAD);
459 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
460 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
461 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
462 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
471 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
479 n_left = frame->n_vectors;
484 u16 off = frame->n_vectors - n_left;
487 sw_if_index = sw_if_indices + off;
490 count = clib_count_equal_u32 (sw_if_index, n_left);
493 classify_and_dispatch (msm, count, sw_if_index[0], b, next);
496 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
498 n_left = frame->n_vectors; /* number of packets to process */
503 if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
505 ethernet_header_t *h0 = vlib_buffer_get_current (b[0]);
507 vlib_add_trace (vm, node, b[0], sizeof (*t));
509 t->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
510 clib_memcpy (t->src, h0->src_address, 6);
511 clib_memcpy (t->dst, h0->dst_address, 6);
519 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
520 vlib_node_increment_counter (vm, l2input_node.index,
521 L2INPUT_ERROR_L2INPUT, frame->n_vectors);
523 return frame->n_vectors;
527 l2input_node_fn (vlib_main_t * vm,
528 vlib_node_runtime_t * node, vlib_frame_t * frame)
530 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
531 return l2input_node_inline (vm, node, frame, 1 /* do_trace */ );
532 return l2input_node_inline (vm, node, frame, 0 /* do_trace */ );
536 VLIB_REGISTER_NODE (l2input_node) = {
537 .function = l2input_node_fn,
539 .vector_size = sizeof (u32),
540 .format_trace = format_l2input_trace,
541 .format_buffer = format_ethernet_header_with_length,
542 .type = VLIB_NODE_TYPE_INTERNAL,
544 .n_errors = ARRAY_LEN(l2input_error_strings),
545 .error_strings = l2input_error_strings,
547 .n_next_nodes = L2INPUT_N_NEXT,
549 /* edit / add dispositions here */
551 [L2INPUT_NEXT_LEARN] = "l2-learn",
552 [L2INPUT_NEXT_FWD] = "l2-fwd",
553 [L2INPUT_NEXT_DROP] = "error-drop",
558 VLIB_NODE_FUNCTION_MULTIARCH (l2input_node, l2input_node_fn)
559 clib_error_t *l2input_init (vlib_main_t * vm)
561 l2input_main_t *mp = &l2input_main;
564 mp->vnet_main = vnet_get_main ();
566 /* Get packets RX'd from L2 interfaces */
567 ethernet_register_l2_input (vm, l2input_node.index);
569 /* Create the config vector */
570 vec_validate (mp->configs, 100);
571 /* create 100 sw interface entries and zero them */
573 /* Initialize the feature next-node indexes */
574 feat_bitmap_init_next_nodes (vm,
577 l2input_get_feat_names (),
578 mp->feat_next_node_index);
583 VLIB_INIT_FUNCTION (l2input_init);
586 /** Get a pointer to the config for the given interface. */
588 l2input_intf_config (u32 sw_if_index)
590 l2input_main_t *mp = &l2input_main;
592 vec_validate (mp->configs, sw_if_index);
593 return vec_elt_at_index (mp->configs, sw_if_index);
596 /** Enable (or disable) the feature in the bitmap for the given interface. */
598 l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable)
600 l2_input_config_t *config = l2input_intf_config (sw_if_index);
603 config->feature_bitmap |= feature_bitmap;
605 config->feature_bitmap &= ~feature_bitmap;
607 return config->feature_bitmap;
611 l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value)
613 l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);;
614 bd_validate (bd_config);
615 bd_config->feature_bitmap =
616 (bd_config->feature_bitmap & ~feat_mask) | feat_value;
617 return bd_config->feature_bitmap;
621 l2input_interface_mac_change (u32 sw_if_index,
622 const u8 * old_address, const u8 * new_address)
624 /* check if the sw_if_index passed is a BVI in a BD */
625 l2_input_config_t *intf_config;
627 intf_config = l2input_intf_config (sw_if_index);
629 if (intf_config->bridge && intf_config->bvi)
631 /* delete and re-add l2fib entry for the bvi interface */
632 l2fib_del_entry (old_address, intf_config->bd_index, sw_if_index);
633 l2fib_add_entry (new_address,
634 intf_config->bd_index,
636 L2FIB_ENTRY_RESULT_FLAG_BVI |
637 L2FIB_ENTRY_RESULT_FLAG_STATIC);
642 * Set the subinterface to run in l2 or l3 mode.
643 * For L3 mode, just the sw_if_index is specified.
644 * For bridged mode, the bd id and bvi flag are also specified.
645 * For xconnect mode, the peer sw_if_index is also specified.
646 * Return 0 if ok, or non-0 if there was an error.
650 set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */
651 u32 mode, /* One of L2 modes or back to L3 mode */
652 u32 sw_if_index, /* sw interface index */
653 u32 bd_index, /* for bridged interface */
654 u32 bvi, /* the bridged interface is the BVI */
655 u32 shg, /* the bridged interface split horizon group */
656 u32 xc_sw_if_index) /* peer interface for xconnect */
658 l2input_main_t *mp = &l2input_main;
659 l2output_main_t *l2om = &l2output_main;
660 vnet_main_t *vnm = vnet_get_main ();
661 vnet_hw_interface_t *hi;
662 l2_output_config_t *out_config;
663 l2_input_config_t *config;
664 l2_bridge_domain_t *bd_config;
665 i32 l2_if_adjust = 0;
666 vnet_device_class_t *dev_class;
668 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
669 config = l2input_intf_config (sw_if_index);
673 /* Interface is already in bridge mode. Undo the existing config. */
674 bd_config = vec_elt_at_index (mp->bd_configs, config->bd_index);
676 /* remove interface from flood vector */
677 bd_remove_member (bd_config, sw_if_index);
679 /* undo any BVI-related config */
680 if (bd_config->bvi_sw_if_index == sw_if_index)
682 vnet_sw_interface_t *si;
684 bd_config->bvi_sw_if_index = ~0;
687 /* delete the l2fib entry for the bvi interface */
688 l2fib_del_entry (hi->hw_address, config->bd_index, sw_if_index);
690 /* since this is a no longer BVI interface do not to flood to it */
691 si = vnet_get_sw_interface (vnm, sw_if_index);
692 si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
695 /* Clear MACs learned on the interface */
696 if ((config->feature_bitmap & L2INPUT_FEAT_LEARN) ||
697 (bd_config->feature_bitmap & L2INPUT_FEAT_LEARN))
698 l2fib_flush_int_mac (vm, sw_if_index);
702 else if (config->xconnect)
707 /* Make sure vector is big enough */
708 vec_validate_init_empty (l2om->output_node_index_vec, sw_if_index,
711 /* Initialize the l2-input configuration for the interface */
714 /* Set L2 config to BD index 0 so that if any packet accidentally
715 * came in on L2 path, it will be dropped in BD 0 */
716 config->xconnect = 0;
719 config->bd_index = 0;
720 config->feature_bitmap = L2INPUT_FEAT_DROP;
722 /* Clear L2 output config */
723 out_config = l2output_intf_config (sw_if_index);
724 memset (out_config, 0, sizeof (l2_output_config_t));
726 /* Make sure any L2-output packet to this interface now in L3 mode is
727 * dropped. This may happen if L2 FIB MAC entry is stale */
728 l2om->output_node_index_vec[sw_if_index] = L2OUTPUT_NEXT_BAD_INTF;
732 /* Add or update l2-output node next-arc and output_node_index_vec table
733 * for the interface */
734 l2output_create_output_node_mapping (vm, vnet_main, sw_if_index);
736 if (mode == MODE_L2_BRIDGE)
739 * Remove a check that the interface must be an Ethernet.
740 * Specifically so we can bridge to L3 tunnel interfaces.
742 * if (hi->hw_class_index != ethernet_hw_interface_class.index)
746 return MODE_ERROR_ETH; /* non-ethernet */
748 config->xconnect = 0;
750 config->bd_index = bd_index;
751 *l2fib_valid_swif_seq_num (sw_if_index) += 1;
754 * Enable forwarding, flooding, learning and ARP termination by default
755 * (note that ARP term is disabled on BD feature bitmap by default)
757 config->feature_bitmap |= L2INPUT_FEAT_FWD | L2INPUT_FEAT_UU_FLOOD |
758 L2INPUT_FEAT_FLOOD | L2INPUT_FEAT_LEARN | L2INPUT_FEAT_ARP_TERM;
760 /* Make sure last-chance drop is configured */
761 config->feature_bitmap |= L2INPUT_FEAT_DROP;
763 /* Make sure xconnect is disabled */
764 config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT;
766 /* Set up bridge domain */
767 bd_config = l2input_bd_config (bd_index);
768 bd_validate (bd_config);
770 /* TODO: think: add l2fib entry even for non-bvi interface? */
772 /* Do BVI interface initializations */
775 vnet_sw_interface_t *si;
777 /* ensure BD has no bvi interface (or replace that one with this??) */
778 if (bd_config->bvi_sw_if_index != ~0)
780 return MODE_ERROR_BVI_DEF; /* bd already has a bvi interface */
782 bd_config->bvi_sw_if_index = sw_if_index;
785 /* create the l2fib entry for the bvi interface */
786 l2fib_add_entry (hi->hw_address, bd_index, sw_if_index,
787 L2FIB_ENTRY_RESULT_FLAG_BVI |
788 L2FIB_ENTRY_RESULT_FLAG_STATIC);
790 /* Disable learning by default. no use since l2fib entry is static. */
791 config->feature_bitmap &= ~L2INPUT_FEAT_LEARN;
793 /* since this is a BVI interface we want to flood to it */
794 si = vnet_get_sw_interface (vnm, sw_if_index);
795 si->flood_class = VNET_FLOOD_CLASS_BVI;
798 /* Add interface to bridge-domain flood vector */
799 l2_flood_member_t member = {
800 .sw_if_index = sw_if_index,
801 .flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL,
804 bd_add_member (bd_config, &member);
807 else if (mode == MODE_L2_XC)
809 config->xconnect = 1;
811 config->output_sw_if_index = xc_sw_if_index;
813 /* Make sure last-chance drop is configured */
814 config->feature_bitmap |= L2INPUT_FEAT_DROP;
816 /* Make sure bridging features are disabled */
817 config->feature_bitmap &=
818 ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);
820 config->feature_bitmap |= L2INPUT_FEAT_XCONNECT;
821 shg = 0; /* not used in xconnect */
823 else if (mode == MODE_L2_CLASSIFY)
825 config->xconnect = 1;
827 config->output_sw_if_index = xc_sw_if_index;
829 /* Make sure last-chance drop is configured */
830 config->feature_bitmap |=
831 L2INPUT_FEAT_DROP | L2INPUT_FEAT_INPUT_CLASSIFY;
833 /* Make sure bridging features are disabled */
834 config->feature_bitmap &=
835 ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);
836 shg = 0; /* not used in xconnect */
838 /* Insure all packets go to ethernet-input */
839 ethernet_set_rx_redirect (vnet_main, hi, 1);
842 /* set up split-horizon group and set output feature bit */
844 out_config = l2output_intf_config (sw_if_index);
845 out_config->shg = shg;
846 out_config->feature_bitmap |= L2OUTPUT_FEAT_OUTPUT;
849 * Test: remove this when non-IP features can be configured.
850 * Enable a non-IP feature to test IP feature masking
851 * config->feature_bitmap |= L2INPUT_FEAT_CTRL_PKT;
857 /* Adjust count of L2 interfaces */
858 hi->l2_if_count += l2_if_adjust;
860 if (hi->hw_class_index == ethernet_hw_interface_class.index)
862 if ((hi->l2_if_count == 1) && (l2_if_adjust == 1))
864 /* Just added first L2 interface on this port */
866 /* Set promiscuous mode on the l2 interface */
867 ethernet_set_flags (vnet_main, hi->hw_if_index,
868 ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
870 /* ensure all packets go to ethernet-input */
871 ethernet_set_rx_redirect (vnet_main, hi, 1);
874 else if ((hi->l2_if_count == 0) && (l2_if_adjust == -1))
876 /* Just removed only L2 subinterface on this port */
878 /* Disable promiscuous mode on the l2 interface */
879 ethernet_set_flags (vnet_main, hi->hw_if_index, 0);
881 /* Allow ip packets to go directly to ip4-input etc */
882 ethernet_set_rx_redirect (vnet_main, hi, 0);
886 /* Set up the L2/L3 flag in the interface parsing tables */
887 ethernet_sw_interface_set_l2_mode (vnm, sw_if_index, (mode != MODE_L3));
889 dev_class = vnet_get_device_class (vnet_main, hi->dev_class_index);
890 if (dev_class->set_l2_mode_function)
892 dev_class->set_l2_mode_function (vnet_main, hi, l2_if_adjust);
899 * Set subinterface in bridging mode with a bridge-domain ID.
901 * set interface l2 bridge <interface> <bd> [bvi] [split-horizon-group]
903 static clib_error_t *
904 int_l2_bridge (vlib_main_t * vm,
905 unformat_input_t * input, vlib_cli_command_t * cmd)
907 vnet_main_t *vnm = vnet_get_main ();
908 clib_error_t *error = 0;
915 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
917 error = clib_error_return (0, "unknown interface `%U'",
918 format_unformat_error, input);
922 if (!unformat (input, "%d", &bd_id))
924 error = clib_error_return (0, "expected bridge domain ID `%U'",
925 format_unformat_error, input);
929 if (bd_id > L2_BD_ID_MAX)
931 error = clib_error_return (0, "bridge domain ID exceed 16M limit",
932 format_unformat_error, input);
935 bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
938 bvi = unformat (input, "bvi");
940 /* optional split horizon group */
942 (void) unformat (input, "%d", &shg);
944 /* set the interface mode */
946 set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE, sw_if_index, bd_index, bvi,
949 if (rc == MODE_ERROR_ETH)
951 error = clib_error_return (0, "bridged interface must be ethernet",
952 format_unformat_error, input);
954 else if (rc == MODE_ERROR_BVI_DEF)
957 clib_error_return (0, "bridge-domain already has a bvi interface",
958 format_unformat_error, input);
962 error = clib_error_return (0, "invalid configuration for interface",
963 format_unformat_error, input);
973 * Use this command put an interface into Layer 2 bridge domain. If a
974 * bridge-domain with the provided bridge-domain-id does not exist, it
975 * will be created. Interfaces in a bridge-domain forward packets to
976 * other interfaces in the same bridge-domain based on destination mac
977 * address. To remove an interface from a the Layer 2 bridge domain,
978 * put the interface in a different mode, for example Layer 3 mode.
980 * Optionally, an interface can be added to a Layer 2 bridge-domain as
981 * a Bridged Virtual Interface (bvi). Only one interface in a Layer 2
982 * bridge-domain can be a bvi.
984 * Optionally, a split-horizon group can also be specified. This defaults
985 * to 0 if not specified.
988 * Example of how to configure a Layer 2 bridge-domain with three
989 * interfaces (where 200 is the bridge-domain-id):
990 * @cliexcmd{set interface l2 bridge GigabitEthernet0/8/0.200 200}
991 * This interface is added a BVI interface:
992 * @cliexcmd{set interface l2 bridge GigabitEthernet0/9/0.200 200 bvi}
993 * This interface also has a split-horizon group of 1 specified:
994 * @cliexcmd{set interface l2 bridge GigabitEthernet0/a/0.200 200 1}
995 * Example of how to remove an interface from a Layer2 bridge-domain:
996 * @cliexcmd{set interface l3 GigabitEthernet0/a/0.200}
999 VLIB_CLI_COMMAND (int_l2_bridge_cli, static) = {
1000 .path = "set interface l2 bridge",
1001 .short_help = "set interface l2 bridge <interface> <bridge-domain-id> [bvi] [shg]",
1002 .function = int_l2_bridge,
1007 * Set subinterface in xconnect mode with another interface.
1008 * The CLI format is:
1009 * set interface l2 xconnect <interface> <peer interface>
1011 static clib_error_t *
1012 int_l2_xc (vlib_main_t * vm,
1013 unformat_input_t * input, vlib_cli_command_t * cmd)
1015 vnet_main_t *vnm = vnet_get_main ();
1016 clib_error_t *error = 0;
1020 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1022 error = clib_error_return (0, "unknown interface `%U'",
1023 format_unformat_error, input);
1028 (input, unformat_vnet_sw_interface, vnm, &xc_sw_if_index))
1030 error = clib_error_return (0, "unknown peer interface `%U'",
1031 format_unformat_error, input);
1035 /* set the interface mode */
1037 (vm, vnm, MODE_L2_XC, sw_if_index, 0, 0, 0, xc_sw_if_index))
1039 error = clib_error_return (0, "invalid configuration for interface",
1040 format_unformat_error, input);
1049 * Use this command put an interface into Layer 2 cross-connect mode.
1050 * Both interfaces must be in this mode for bi-directioal traffic. All
1051 * packets received on one interface will be transmitted to the other.
1052 * To remove the Layer 2 cross-connect, put the interface in a different
1053 * mode, for example Layer 3 mode.
1056 * Example of how to configure a Layer2 cross-connect between two interfaces:
1057 * @cliexcmd{set interface l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300}
1058 * @cliexcmd{set interface l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300}
1059 * Example of how to remove a Layer2 cross-connect:
1060 * @cliexcmd{set interface l3 GigabitEthernet0/8/0.300}
1061 * @cliexcmd{set interface l3 GigabitEthernet0/9/0.300}
1064 VLIB_CLI_COMMAND (int_l2_xc_cli, static) = {
1065 .path = "set interface l2 xconnect",
1066 .short_help = "set interface l2 xconnect <interface> <peer interface>",
1067 .function = int_l2_xc,
1072 * Set subinterface in L3 mode.
1073 * The CLI format is:
1074 * set interface l3 <interface>
1076 static clib_error_t *
1077 int_l3 (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1079 vnet_main_t *vnm = vnet_get_main ();
1080 clib_error_t *error = 0;
1083 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1085 error = clib_error_return (0, "unknown interface `%U'",
1086 format_unformat_error, input);
1090 /* set the interface mode */
1091 if (set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0, 0, 0, 0))
1093 error = clib_error_return (0, "invalid configuration for interface",
1094 format_unformat_error, input);
1103 * Modify the packet processing mode of the interface to Layer 3, which
1104 * implies packets will be routed. This is the default mode of an interface.
1105 * Use this command to remove an interface from a Layer 2 cross-connect or a
1109 * Example of how to set the mode of an interface to Layer 3:
1110 * @cliexcmd{set interface l3 GigabitEthernet0/8/0.200}
1113 VLIB_CLI_COMMAND (int_l3_cli, static) = {
1114 .path = "set interface l3",
1115 .short_help = "set interface l3 <interface>",
1121 * Show interface mode.
1122 * The CLI format is:
1123 * show mode [<if-name1> <if-name2> ...]
1125 static clib_error_t *
1126 show_int_mode (vlib_main_t * vm,
1127 unformat_input_t * input, vlib_cli_command_t * cmd)
1129 vnet_main_t *vnm = vnet_get_main ();
1130 clib_error_t *error = 0;
1133 vnet_interface_main_t *im = &vnm->interface_main;
1135 vnet_sw_interface_t *si, *sis = 0;
1136 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1140 /* See if user wants to show specific interface */
1142 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1144 si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
1145 vec_add1 (sis, si[0]);
1149 error = clib_error_return (0, "unknown input `%U'",
1150 format_unformat_error, input);
1155 if (vec_len (sis) == 0) /* Get all interfaces */
1157 /* Gather interfaces. */
1158 sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1161 pool_foreach (si, im->sw_interfaces, ({ vec_add1 (sis, si[0]); }));
1165 vec_foreach (si, sis)
1167 l2_input_config_t *config = l2input_intf_config (si->sw_if_index);
1172 bd_id = l2input_main.bd_configs[config->bd_index].bd_id;
1174 args = format (0, "bd_id %d%s%d", bd_id,
1175 config->bvi ? " bvi shg " : " shg ", config->shg);
1177 else if (config->xconnect)
1179 mode = "l2 xconnect";
1180 args = format (0, "%U",
1181 format_vnet_sw_if_index_name,
1182 vnm, config->output_sw_if_index);
1187 args = format (0, " ");
1189 vlib_cli_output (vm, "%s %U %v\n",
1191 format_vnet_sw_if_index_name,
1192 vnm, si->sw_if_index, args);
1203 * Show the packet processing mode (Layer2 xcross-onnect, Layer 2 bridge,
1204 * Layer 3 routed) of all interfaces and sub-interfaces, or limit the
1205 * output to just the provided list of interfaces and sub-interfaces.
1206 * The output shows the mode, the interface, and if the interface is
1207 * a member of a bridge, the bridge-domain-id and the split horizen group (shg).
1210 * Example of displaying the mode of all interfaces:
1211 * @cliexstart{show mode}
1213 * l3 GigabitEthernet0/8/0
1214 * l3 GigabitEthernet0/9/0
1215 * l3 GigabitEthernet0/a/0
1216 * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0
1217 * l2 bridge GigabitEthernet0/9/0.200 bd_id 200 shg 0
1218 * l2 bridge GigabitEthernet0/a/0.200 bd_id 200 shg 0
1219 * l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300
1220 * l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300
1222 * Example of displaying the mode of a seleted list of interfaces:
1223 * @cliexstart{show mode GigabitEthernet0/8/0 GigabitEthernet0/8/0.200}
1224 * l3 GigabitEthernet0/8/0
1225 * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0
1229 VLIB_CLI_COMMAND (show_l2_mode, static) = {
1230 .path = "show mode",
1231 .short_help = "show mode [<if-name1> <if-name2> ...]",
1232 .function = show_int_mode,
1236 #define foreach_l2_init_function \
1237 _(feat_bitmap_drop_init) \
1239 _(l2_input_classify_init) \
1242 _(l2_in_out_acl_init) \
1246 _(l2_efp_filter_init) \
1254 l2_init (vlib_main_t * vm)
1256 clib_error_t *error;
1259 if ((error = vlib_call_init_function (vm, a))) return error; } \
1261 foreach_l2_init_function;
1266 VLIB_INIT_FUNCTION (l2_init);
1269 * fd.io coding-style-patch-verification: ON
1272 * eval: (c-set-style "gnu")