2 * l2e_node.c : l2 emulation node
4 * Copyright (c) 2019 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.
17 #include <plugins/l2e/l2e.h>
18 #include <vnet/l2/l2_input.h>
19 #include <vnet/l2/feat_bitmap.h>
21 #define foreach_l2_emulation \
22 _(IP4, "Extract IPv4") \
23 _(IP6, "Extract IPv6")
27 #define _(sym,str) L2_EMULATION_ERROR_##sym,
31 } l2_emulation_error_t;
33 static char *l2_emulation_error_strings[] = {
34 #define _(sym,string) string,
41 #define _(sym,str) L2_EMULATION_NEXT_##sym,
45 } l2_emulation_next_t;
47 /* packet trace format function */
49 format_l2_emulation_trace (u8 * s, va_list * args)
51 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53 l2_emulation_trace_t *t = va_arg (*args, l2_emulation_trace_t *);
55 s = format (s, "l2-emulation: %s", (t->extracted ? "yes" : "no"));
60 VLIB_NODE_FN (l2_emulation_node) (vlib_main_t * vm,
61 vlib_node_runtime_t * node,
64 l2_emulation_main_t *em = &l2_emulation_main;
65 u32 n_left_from, *from, *to_next;
66 l2_emulation_next_t next_index;
71 n_left_from = frame->n_vectors;
72 from = vlib_frame_vector_args (frame);
74 while (n_left_from > 0)
78 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
79 while (n_left_from >= 4 && n_left_to_next >= 2)
81 vlib_buffer_t *b0, *b1;
82 u32 sw_if_index0, sw_if_index1;
83 u16 ether_type0, ether_type1;
84 u32 next0 = ~0, next1 = ~0;
89 bi0 = to_next[0] = from[0];
90 bi1 = to_next[1] = from[1];
97 b0 = vlib_get_buffer (vm, bi0);
98 b1 = vlib_get_buffer (vm, bi1);
99 l2_len0 = vnet_buffer (b0)->l2.l2_len;
100 l2_len1 = vnet_buffer (b1)->l2.l2_len;
102 h0 = vlib_buffer_get_current (b0);
103 h1 = vlib_buffer_get_current (b1);
105 ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
106 ether_type1 = clib_net_to_host_u16 (*(u16 *) (h1 + l2_len1 - 2));
107 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
108 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
111 * only extract unicast
113 if (PREDICT_TRUE (!(h0[0] & 0x1)))
117 case ETHERNET_TYPE_IP4:
118 ASSERT (em->l2_emulations[sw_if_index0].enabled);
120 next0 = L2_EMULATION_NEXT_IP4;
121 vlib_buffer_advance (b0, l2_len0);
123 case ETHERNET_TYPE_IP6:
124 ASSERT (em->l2_emulations[sw_if_index0].enabled);
126 next0 = L2_EMULATION_NEXT_IP6;
127 vlib_buffer_advance (b0, l2_len0);
132 if (PREDICT_TRUE (!(h1[0] & 0x1)))
136 case ETHERNET_TYPE_IP4:
137 ASSERT (em->l2_emulations[sw_if_index1].enabled);
139 next1 = L2_EMULATION_NEXT_IP4;
140 vlib_buffer_advance (b1, l2_len1);
142 case ETHERNET_TYPE_IP6:
143 ASSERT (em->l2_emulations[sw_if_index1].enabled);
145 next1 = L2_EMULATION_NEXT_IP6;
146 vlib_buffer_advance (b1, l2_len1);
151 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
152 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
154 l2_emulation_trace_t *t =
155 vlib_add_trace (vm, node, b0, sizeof (*t));
156 t->extracted = (next0 != ~0);
158 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
159 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
161 l2_emulation_trace_t *t =
162 vlib_add_trace (vm, node, b1, sizeof (*t));
163 t->extracted = (next1 != ~0);
166 /* Determine the next node and remove ourself from bitmap */
167 if (PREDICT_TRUE (next0 == ~0))
168 next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
169 L2INPUT_FEAT_L2_EMULATION);
171 /* Determine the next node and remove ourself from bitmap */
172 if (PREDICT_TRUE (next1 == ~0))
173 next1 = vnet_l2_feature_next (b1, em->l2_input_feat_next,
174 L2INPUT_FEAT_L2_EMULATION);
176 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
177 to_next, n_left_to_next,
178 bi0, bi1, next0, next1);
180 while (n_left_from > 0 && n_left_to_next > 0)
197 b0 = vlib_get_buffer (vm, bi0);
198 l2_len0 = vnet_buffer (b0)->l2.l2_len;
200 h0 = vlib_buffer_get_current (b0);
201 ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
202 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
205 * only extract unicast
207 if (PREDICT_TRUE (!(h0[0] & 0x1)))
211 case ETHERNET_TYPE_IP4:
212 ASSERT (em->l2_emulations[sw_if_index0].enabled);
214 next0 = L2_EMULATION_NEXT_IP4;
215 vlib_buffer_advance (b0, l2_len0);
217 case ETHERNET_TYPE_IP6:
218 ASSERT (em->l2_emulations[sw_if_index0].enabled);
220 next0 = L2_EMULATION_NEXT_IP6;
221 vlib_buffer_advance (b0, l2_len0);
227 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
228 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
230 l2_emulation_trace_t *t =
231 vlib_add_trace (vm, node, b0, sizeof (*t));
232 t->extracted = (next0 != ~0);
235 /* Determine the next node and remove ourself from bitmap */
236 if (PREDICT_TRUE (next0 == ~0))
237 next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
238 L2INPUT_FEAT_L2_EMULATION);
240 /* verify speculative enqueue, maybe switch current next frame */
241 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
242 to_next, n_left_to_next,
246 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
249 vlib_node_increment_counter (vm, node->node_index,
250 L2_EMULATION_ERROR_IP4, ip4_hits);
251 vlib_node_increment_counter (vm, node->node_index,
252 L2_EMULATION_ERROR_IP6, ip6_hits);
254 return frame->n_vectors;
258 VLIB_REGISTER_NODE (l2_emulation_node) = {
259 .name = "l2-emulation",
260 .vector_size = sizeof (u32),
261 .format_trace = format_l2_emulation_trace,
262 .type = VLIB_NODE_TYPE_INTERNAL,
264 .n_errors = ARRAY_LEN(l2_emulation_error_strings),
265 .error_strings = l2_emulation_error_strings,
267 .n_next_nodes = L2_EMULATION_N_NEXT,
269 /* edit / add dispositions here */
271 [L2_EMULATION_NEXT_IP4] = "ip4-input",
272 [L2_EMULATION_NEXT_IP6] = "ip6-input",
278 * fd.io coding-style-patch-verification: ON
281 * eval: (c-set-style "gnu")