blob: ee14e40d88138c945f8e5714788f5a503a952857 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
Damjan Marion650223c2018-11-14 16:55:53 +01002 * Copyright (c) 2018 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ethernet_node.c: ethernet packet processing
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vlib/vlib.h>
41#include <vnet/pg/pg.h>
42#include <vnet/ethernet/ethernet.h>
Pavel Kotucek15ac81c2017-06-20 14:00:26 +020043#include <vnet/ethernet/p2p_ethernet.h>
Neale Ranns17ff3c12018-07-04 10:24:24 -070044#include <vnet/devices/pipe/pipe.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#include <vppinfra/sparse_vec.h>
46#include <vnet/l2/l2_bvi.h>
Dave Barach9137e542019-09-13 17:47:50 -040047#include <vnet/classify/trace_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Ed Warnickecb9cada2015-12-08 15:45:58 -070049#define foreach_ethernet_input_next \
50 _ (PUNT, "error-punt") \
51 _ (DROP, "error-drop") \
Damjan Marion650223c2018-11-14 16:55:53 +010052 _ (LLC, "llc-input") \
53 _ (IP4_INPUT, "ip4-input") \
54 _ (IP4_INPUT_NCS, "ip4-input-no-checksum")
Ed Warnickecb9cada2015-12-08 15:45:58 -070055
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070056typedef enum
57{
Ed Warnickecb9cada2015-12-08 15:45:58 -070058#define _(s,n) ETHERNET_INPUT_NEXT_##s,
59 foreach_ethernet_input_next
60#undef _
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070061 ETHERNET_INPUT_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -070062} ethernet_input_next_t;
63
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070064typedef struct
65{
Ed Warnickecb9cada2015-12-08 15:45:58 -070066 u8 packet_data[32];
Damjan Marion650223c2018-11-14 16:55:53 +010067 u16 frame_flags;
68 ethernet_input_frame_t frame_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -070069} ethernet_input_trace_t;
70
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070071static u8 *
72format_ethernet_input_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070073{
74 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
75 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070076 ethernet_input_trace_t *t = va_arg (*va, ethernet_input_trace_t *);
Damjan Marion650223c2018-11-14 16:55:53 +010077 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
Damjan Marion650223c2018-11-14 16:55:53 +010079 if (t->frame_flags)
80 {
81 s = format (s, "frame: flags 0x%x", t->frame_flags);
82 if (t->frame_flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
83 s = format (s, ", hw-if-index %u, sw-if-index %u",
84 t->frame_data.hw_if_index, t->frame_data.sw_if_index);
85 s = format (s, "\n%U", format_white_space, indent);
86 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 s = format (s, "%U", format_ethernet_header, t->packet_data);
88
89 return s;
90}
91
Damjan Marione849da22018-09-12 13:32:01 +020092extern vlib_node_registration_t ethernet_input_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -070093
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070094typedef enum
95{
Ed Warnickecb9cada2015-12-08 15:45:58 -070096 ETHERNET_INPUT_VARIANT_ETHERNET,
97 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE,
Ed Warnickecb9cada2015-12-08 15:45:58 -070098 ETHERNET_INPUT_VARIANT_NOT_L2,
99} ethernet_input_variant_t;
100
101
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102// Parse the ethernet header to extract vlan tags and innermost ethertype
103static_always_inline void
104parse_header (ethernet_input_variant_t variant,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700105 vlib_buffer_t * b0,
106 u16 * type,
107 u16 * orig_type,
108 u16 * outer_id, u16 * inner_id, u32 * match_flags)
109{
Chris Luke194ebc52016-04-25 14:26:55 -0400110 u8 vlan_count;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700112 if (variant == ETHERNET_INPUT_VARIANT_ETHERNET
113 || variant == ETHERNET_INPUT_VARIANT_NOT_L2)
114 {
115 ethernet_header_t *e0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700117 e0 = (void *) (b0->data + b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118
Damjan Marion072401e2017-07-13 18:53:27 +0200119 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
Steven35de3b32017-12-03 23:40:54 -0800120 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700122 vlib_buffer_advance (b0, sizeof (e0[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700124 *type = clib_net_to_host_u16 (e0->type);
125 }
126 else if (variant == ETHERNET_INPUT_VARIANT_ETHERNET_TYPE)
127 {
128 // here when prior node was LLC/SNAP processing
129 u16 *e0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700131 e0 = (void *) (b0->data + b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700133 vlib_buffer_advance (b0, sizeof (e0[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700135 *type = clib_net_to_host_u16 (e0[0]);
136 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137
138 // save for distinguishing between dot1q and dot1ad later
139 *orig_type = *type;
140
141 // default the tags to 0 (used if there is no corresponding tag)
142 *outer_id = 0;
143 *inner_id = 0;
144
145 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_0_TAG;
Chris Luke194ebc52016-04-25 14:26:55 -0400146 vlan_count = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147
148 // check for vlan encaps
Damjan Marionb94bdad2016-09-19 11:32:03 +0200149 if (ethernet_frame_is_tagged (*type))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700150 {
151 ethernet_vlan_header_t *h0;
152 u16 tag;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700154 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_1_TAG;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156 h0 = (void *) (b0->data + b0->current_data);
157
158 tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
159
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700160 *outer_id = tag & 0xfff;
Neale Ranns30d0fd42017-05-30 07:30:04 -0700161 if (0 == *outer_id)
162 *match_flags &= ~SUBINT_CONFIG_MATCH_1_TAG;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700164 *type = clib_net_to_host_u16 (h0->type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165
166 vlib_buffer_advance (b0, sizeof (h0[0]));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700167 vlan_count = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700169 if (*type == ETHERNET_TYPE_VLAN)
170 {
171 // Double tagged packet
172 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_2_TAG;
173
174 h0 = (void *) (b0->data + b0->current_data);
175
176 tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
177
178 *inner_id = tag & 0xfff;
179
180 *type = clib_net_to_host_u16 (h0->type);
181
182 vlib_buffer_advance (b0, sizeof (h0[0]));
183 vlan_count = 2;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700184 if (*type == ETHERNET_TYPE_VLAN)
185 {
186 // More than double tagged packet
187 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG;
Eyal Bari6f7ebf92017-06-13 12:09:37 +0300188
189 vlib_buffer_advance (b0, sizeof (h0[0]));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700190 vlan_count = 3; // "unknown" number, aka, 3-or-more
191 }
192 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700194 ethernet_buffer_set_vlan_count (b0, vlan_count);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195}
196
197// Determine the subinterface for this packet, given the result of the
198// vlan table lookups and vlan header parsing. Check the most specific
199// matches first.
200static_always_inline void
201identify_subint (vnet_hw_interface_t * hi,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700202 vlib_buffer_t * b0,
203 u32 match_flags,
204 main_intf_t * main_intf,
205 vlan_intf_t * vlan_intf,
206 qinq_intf_t * qinq_intf,
207 u32 * new_sw_if_index, u8 * error0, u32 * is_l2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208{
209 u32 matched;
210
Damjan Marionddf6e082018-11-26 16:05:07 +0100211 matched = eth_identify_subint (hi, match_flags, main_intf, vlan_intf,
212 qinq_intf, new_sw_if_index, error0, is_l2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700214 if (matched)
215 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700217 // Perform L3 my-mac filter
218 // A unicast packet arriving on an L3 interface must have a dmac matching the interface mac.
219 // This is required for promiscuous mode, else we will forward packets we aren't supposed to.
220 if (!(*is_l2))
221 {
222 ethernet_header_t *e0;
Damjan Marion072401e2017-07-13 18:53:27 +0200223 e0 = (void *) (b0->data + vnet_buffer (b0)->l2_hdr_offset);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700225 if (!(ethernet_address_cast (e0->dst_address)))
226 {
Neale Ranns37029302018-08-10 05:30:06 -0700227 if (!ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700228 {
229 *error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
230 }
231 }
232 }
233
234 // Check for down subinterface
235 *error0 = (*new_sw_if_index) != ~0 ? (*error0) : ETHERNET_ERROR_DOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237}
238
239static_always_inline void
240determine_next_node (ethernet_main_t * em,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700241 ethernet_input_variant_t variant,
242 u32 is_l20,
243 u32 type0, vlib_buffer_t * b0, u8 * error0, u8 * next0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244{
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +0200245 vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
246 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
247
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700248 if (PREDICT_FALSE (*error0 != ETHERNET_ERROR_NONE))
249 {
250 // some error occurred
251 *next0 = ETHERNET_INPUT_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700253 else if (is_l20)
254 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700255 // record the L2 len and reset the buffer so the L2 header is preserved
John Lob14826e2018-04-18 15:52:23 -0400256 u32 eth_start = vnet_buffer (b0)->l2_hdr_offset;
257 vnet_buffer (b0)->l2.l2_len = b0->current_data - eth_start;
258 *next0 = em->l2_next;
Eyal Bari6f7ebf92017-06-13 12:09:37 +0300259 ASSERT (vnet_buffer (b0)->l2.l2_len ==
260 ethernet_buffer_header_size (b0));
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +0200261 vlib_buffer_advance (b0, -(vnet_buffer (b0)->l2.l2_len));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700262
263 // check for common IP/MPLS ethertypes
264 }
265 else if (type0 == ETHERNET_TYPE_IP4)
266 {
267 *next0 = em->l3_next.input_next_ip4;
268 }
269 else if (type0 == ETHERNET_TYPE_IP6)
270 {
271 *next0 = em->l3_next.input_next_ip6;
272 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800273 else if (type0 == ETHERNET_TYPE_MPLS)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700274 {
275 *next0 = em->l3_next.input_next_mpls;
276
277 }
278 else if (em->redirect_l3)
279 {
280 // L3 Redirect is on, the cached common next nodes will be
281 // pointing to the redirect node, catch the uncommon types here
282 *next0 = em->redirect_l3_next;
283 }
284 else
285 {
286 // uncommon ethertype, check table
287 u32 i0;
288 i0 = sparse_vec_index (em->l3_next.input_next_by_type, type0);
289 *next0 = vec_elt (em->l3_next.input_next_by_type, i0);
290 *error0 =
291 i0 ==
292 SPARSE_VEC_INVALID_INDEX ? ETHERNET_ERROR_UNKNOWN_TYPE : *error0;
293
294 // The table is not populated with LLC values, so check that now.
Damjan Marion607de1a2016-08-16 22:53:54 +0200295 // If variant is variant_ethernet then we came from LLC processing. Don't
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700296 // go back there; drop instead using by keeping the drop/bad table result.
297 if ((type0 < 0x600) && (variant == ETHERNET_INPUT_VARIANT_ETHERNET))
298 {
299 *next0 = ETHERNET_INPUT_NEXT_LLC;
300 }
301 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302}
303
Damjan Marion650223c2018-11-14 16:55:53 +0100304
305/* following vector code relies on following assumptions */
306STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_data, 0);
307STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_length, 2);
308STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, flags, 4);
309STATIC_ASSERT (STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l2_hdr_offset) ==
310 STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l3_hdr_offset) - 2,
311 "l3_hdr_offset must follow l2_hdr_offset");
312
313static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100314eth_input_adv_and_flags_x4 (vlib_buffer_t ** b, int is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +0100315{
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100316 i16 adv = sizeof (ethernet_header_t);
317 u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
318 VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
319
Damjan Marion650223c2018-11-14 16:55:53 +0100320#ifdef CLIB_HAVE_VEC256
321 /* to reduce number of small loads/stores we are loading first 64 bits
322 of each buffer metadata into 256-bit register so we can advance
323 current_data, current_length and flags.
324 Observed saving of this code is ~2 clocks per packet */
325 u64x4 r, radv;
326
327 /* vector if signed 16 bit integers used in signed vector add operation
328 to advnce current_data and current_length */
329 u32x8 flags4 = { 0, flags, 0, flags, 0, flags, 0, flags };
330 i16x16 adv4 = {
331 adv, -adv, 0, 0, adv, -adv, 0, 0,
332 adv, -adv, 0, 0, adv, -adv, 0, 0
333 };
334
335 /* load 4 x 64 bits */
336 r = u64x4_gather (b[0], b[1], b[2], b[3]);
337
338 /* set flags */
339 r |= (u64x4) flags4;
340
341 /* advance buffer */
342 radv = (u64x4) ((i16x16) r + adv4);
343
344 /* write 4 x 64 bits */
345 u64x4_scatter (is_l3 ? radv : r, b[0], b[1], b[2], b[3]);
346
347 /* use old current_data as l2_hdr_offset and new current_data as
348 l3_hdr_offset */
349 r = (u64x4) u16x16_blend (r, radv << 16, 0xaa);
350
351 /* store both l2_hdr_offset and l3_hdr_offset in single store operation */
352 u32x8_scatter_one ((u32x8) r, 0, &vnet_buffer (b[0])->l2_hdr_offset);
353 u32x8_scatter_one ((u32x8) r, 2, &vnet_buffer (b[1])->l2_hdr_offset);
354 u32x8_scatter_one ((u32x8) r, 4, &vnet_buffer (b[2])->l2_hdr_offset);
355 u32x8_scatter_one ((u32x8) r, 6, &vnet_buffer (b[3])->l2_hdr_offset);
356
Damjan Marione9cebdf2018-11-21 00:47:42 +0100357 if (is_l3)
358 {
359 ASSERT (b[0]->current_data == vnet_buffer (b[0])->l3_hdr_offset);
360 ASSERT (b[1]->current_data == vnet_buffer (b[1])->l3_hdr_offset);
361 ASSERT (b[2]->current_data == vnet_buffer (b[2])->l3_hdr_offset);
362 ASSERT (b[3]->current_data == vnet_buffer (b[3])->l3_hdr_offset);
Damjan Marion650223c2018-11-14 16:55:53 +0100363
Damjan Marione9cebdf2018-11-21 00:47:42 +0100364 ASSERT (b[0]->current_data - vnet_buffer (b[0])->l2_hdr_offset == adv);
365 ASSERT (b[1]->current_data - vnet_buffer (b[1])->l2_hdr_offset == adv);
366 ASSERT (b[2]->current_data - vnet_buffer (b[2])->l2_hdr_offset == adv);
367 ASSERT (b[3]->current_data - vnet_buffer (b[3])->l2_hdr_offset == adv);
368 }
369 else
370 {
371 ASSERT (b[0]->current_data == vnet_buffer (b[0])->l2_hdr_offset);
372 ASSERT (b[1]->current_data == vnet_buffer (b[1])->l2_hdr_offset);
373 ASSERT (b[2]->current_data == vnet_buffer (b[2])->l2_hdr_offset);
374 ASSERT (b[3]->current_data == vnet_buffer (b[3])->l2_hdr_offset);
375
376 ASSERT (b[0]->current_data - vnet_buffer (b[0])->l3_hdr_offset == -adv);
377 ASSERT (b[1]->current_data - vnet_buffer (b[1])->l3_hdr_offset == -adv);
378 ASSERT (b[2]->current_data - vnet_buffer (b[2])->l3_hdr_offset == -adv);
379 ASSERT (b[3]->current_data - vnet_buffer (b[3])->l3_hdr_offset == -adv);
380 }
Damjan Marion650223c2018-11-14 16:55:53 +0100381
382#else
383 vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
384 vnet_buffer (b[1])->l2_hdr_offset = b[1]->current_data;
385 vnet_buffer (b[2])->l2_hdr_offset = b[2]->current_data;
386 vnet_buffer (b[3])->l2_hdr_offset = b[3]->current_data;
387 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
388 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data + adv;
389 vnet_buffer (b[2])->l3_hdr_offset = b[2]->current_data + adv;
390 vnet_buffer (b[3])->l3_hdr_offset = b[3]->current_data + adv;
391
392 if (is_l3)
393 {
394 vlib_buffer_advance (b[0], adv);
395 vlib_buffer_advance (b[1], adv);
396 vlib_buffer_advance (b[2], adv);
397 vlib_buffer_advance (b[3], adv);
398 }
399
400 b[0]->flags |= flags;
401 b[1]->flags |= flags;
402 b[2]->flags |= flags;
403 b[3]->flags |= flags;
404#endif
405
406 if (!is_l3)
407 {
408 vnet_buffer (b[0])->l2.l2_len = adv;
409 vnet_buffer (b[1])->l2.l2_len = adv;
410 vnet_buffer (b[2])->l2.l2_len = adv;
411 vnet_buffer (b[3])->l2.l2_len = adv;
412 }
413}
414
415static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100416eth_input_adv_and_flags_x1 (vlib_buffer_t ** b, int is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +0100417{
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100418 i16 adv = sizeof (ethernet_header_t);
419 u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
420 VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
421
Damjan Marion650223c2018-11-14 16:55:53 +0100422 vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
423 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
424
425 if (is_l3)
426 vlib_buffer_advance (b[0], adv);
427 b[0]->flags |= flags;
428 if (!is_l3)
429 vnet_buffer (b[0])->l2.l2_len = adv;
430}
431
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100432
Damjan Marion650223c2018-11-14 16:55:53 +0100433static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100434eth_input_get_etype_and_tags (vlib_buffer_t ** b, u16 * etype, u64 * tags,
435 u64 * dmacs, int offset, int dmac_check)
Damjan Marion650223c2018-11-14 16:55:53 +0100436{
Damjan Marion650223c2018-11-14 16:55:53 +0100437 ethernet_header_t *e;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100438 e = vlib_buffer_get_current (b[offset]);
439#ifdef CLIB_HAVE_VEC128
440 u64x2 r = u64x2_load_unaligned (((u8 *) & e->type) - 6);
441 etype[offset] = ((u16x8) r)[3];
442 tags[offset] = r[1];
443#else
444 etype[offset] = e->type;
445 tags[offset] = *(u64 *) (e + 1);
446#endif
Damjan Marion650223c2018-11-14 16:55:53 +0100447
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100448 if (dmac_check)
449 dmacs[offset] = *(u64 *) e;
450}
Damjan Marion650223c2018-11-14 16:55:53 +0100451
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100452static_always_inline u16
453eth_input_next_by_type (u16 etype)
454{
455 ethernet_main_t *em = &ethernet_main;
456
457 return (etype < 0x600) ? ETHERNET_INPUT_NEXT_LLC :
458 vec_elt (em->l3_next.input_next_by_type,
459 sparse_vec_index (em->l3_next.input_next_by_type, etype));
460}
461
462typedef struct
463{
464 u64 tag, mask;
465 u32 sw_if_index;
466 u16 type, len, next;
467 i16 adv;
468 u8 err, n_tags;
469 u64 n_packets, n_bytes;
470} eth_input_tag_lookup_t;
471
472static_always_inline void
473eth_input_update_if_counters (vlib_main_t * vm, vnet_main_t * vnm,
474 eth_input_tag_lookup_t * l)
475{
476 if (l->n_packets == 0 || l->sw_if_index == ~0)
477 return;
478
479 if (l->adv > 0)
480 l->n_bytes += l->n_packets * l->len;
481
482 vlib_increment_combined_counter
483 (vnm->interface_main.combined_sw_if_counters +
484 VNET_INTERFACE_COUNTER_RX, vm->thread_index, l->sw_if_index,
485 l->n_packets, l->n_bytes);
486}
487
488static_always_inline void
489eth_input_tag_lookup (vlib_main_t * vm, vnet_main_t * vnm,
490 vlib_node_runtime_t * node, vnet_hw_interface_t * hi,
491 u64 tag, u16 * next, vlib_buffer_t * b,
492 eth_input_tag_lookup_t * l, u8 dmac_bad, int is_dot1ad,
493 int main_is_l3, int check_dmac)
494{
495 ethernet_main_t *em = &ethernet_main;
496
497 if ((tag ^ l->tag) & l->mask)
Damjan Marion650223c2018-11-14 16:55:53 +0100498 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100499 main_intf_t *mif = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
500 vlan_intf_t *vif;
501 qinq_intf_t *qif;
502 vlan_table_t *vlan_table;
503 qinq_table_t *qinq_table;
504 u16 *t = (u16 *) & tag;
505 u16 vlan1 = clib_net_to_host_u16 (t[0]) & 0xFFF;
506 u16 vlan2 = clib_net_to_host_u16 (t[2]) & 0xFFF;
507 u32 matched, is_l2, new_sw_if_index;
508
509 vlan_table = vec_elt_at_index (em->vlan_pool, is_dot1ad ?
510 mif->dot1ad_vlans : mif->dot1q_vlans);
511 vif = &vlan_table->vlans[vlan1];
512 qinq_table = vec_elt_at_index (em->qinq_pool, vif->qinqs);
513 qif = &qinq_table->vlans[vlan2];
514 l->err = ETHERNET_ERROR_NONE;
515 l->type = clib_net_to_host_u16 (t[1]);
516
517 if (l->type == ETHERNET_TYPE_VLAN)
518 {
519 l->type = clib_net_to_host_u16 (t[3]);
520 l->n_tags = 2;
521 matched = eth_identify_subint (hi, SUBINT_CONFIG_VALID |
522 SUBINT_CONFIG_MATCH_2_TAG, mif, vif,
523 qif, &new_sw_if_index, &l->err,
524 &is_l2);
525 }
526 else
527 {
528 l->n_tags = 1;
529 if (vlan1 == 0)
530 {
531 new_sw_if_index = hi->sw_if_index;
532 l->err = ETHERNET_ERROR_NONE;
533 matched = 1;
534 is_l2 = main_is_l3 == 0;
535 }
536 else
537 matched = eth_identify_subint (hi, SUBINT_CONFIG_VALID |
538 SUBINT_CONFIG_MATCH_1_TAG, mif,
539 vif, qif, &new_sw_if_index,
540 &l->err, &is_l2);
541 }
542
543 if (l->sw_if_index != new_sw_if_index)
544 {
545 eth_input_update_if_counters (vm, vnm, l);
546 l->n_packets = 0;
547 l->n_bytes = 0;
548 l->sw_if_index = new_sw_if_index;
549 }
550 l->tag = tag;
551 l->mask = (l->n_tags == 2) ?
552 clib_net_to_host_u64 (0xffffffffffffffff) :
553 clib_net_to_host_u64 (0xffffffff00000000);
554
555 if (matched && l->sw_if_index == ~0)
556 l->err = ETHERNET_ERROR_DOWN;
557
558 l->len = sizeof (ethernet_header_t) +
559 l->n_tags * sizeof (ethernet_vlan_header_t);
560 if (main_is_l3)
561 l->adv = is_l2 ? -(int) sizeof (ethernet_header_t) :
562 l->n_tags * sizeof (ethernet_vlan_header_t);
563 else
564 l->adv = is_l2 ? 0 : l->len;
565
566 if (PREDICT_FALSE (l->err != ETHERNET_ERROR_NONE))
567 l->next = ETHERNET_INPUT_NEXT_DROP;
568 else if (is_l2)
569 l->next = em->l2_next;
570 else if (l->type == ETHERNET_TYPE_IP4)
571 l->next = em->l3_next.input_next_ip4;
572 else if (l->type == ETHERNET_TYPE_IP6)
573 l->next = em->l3_next.input_next_ip6;
574 else if (l->type == ETHERNET_TYPE_MPLS)
575 l->next = em->l3_next.input_next_mpls;
576 else if (em->redirect_l3)
577 l->next = em->redirect_l3_next;
578 else
579 {
580 l->next = eth_input_next_by_type (l->type);
581 if (l->next == ETHERNET_INPUT_NEXT_PUNT)
582 l->err = ETHERNET_ERROR_UNKNOWN_TYPE;
583 }
584 }
585
586 if (check_dmac && l->adv > 0 && dmac_bad)
587 {
588 l->err = ETHERNET_ERROR_L3_MAC_MISMATCH;
589 next[0] = ETHERNET_INPUT_NEXT_PUNT;
590 }
591 else
592 next[0] = l->next;
593
594 vlib_buffer_advance (b, l->adv);
595 vnet_buffer (b)->l2.l2_len = l->len;
596 vnet_buffer (b)->l3_hdr_offset = vnet_buffer (b)->l2_hdr_offset + l->len;
597
598 if (l->err == ETHERNET_ERROR_NONE)
599 {
600 vnet_buffer (b)->sw_if_index[VLIB_RX] = l->sw_if_index;
601 ethernet_buffer_set_vlan_count (b, l->n_tags);
602 }
603 else
604 b->error = node->errors[l->err];
605
606 /* update counters */
607 l->n_packets += 1;
608 l->n_bytes += vlib_buffer_length_in_chain (vm, b);
609}
610
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500611static_always_inline void
612eth_input_process_frame_dmac_check (vnet_hw_interface_t * hi,
613 u64 * dmacs, u8 * dmacs_bad,
614 u32 n_packets)
615{
616 u64 mask = clib_net_to_host_u64 (0xFFFFFFFFFFFF0000);
617 u64 igbit = clib_net_to_host_u64 (0x0100000000000000);
618 u64 hwaddr = (*(u64 *) hi->hw_address) & mask;
619 u64 *dmac = dmacs;
620 u8 *dmac_bad = dmacs_bad;
621
622 i32 n_left = n_packets;
623
624#ifdef CLIB_HAVE_VEC256
625 u64x4 igbit4 = u64x4_splat (igbit);
626 u64x4 mask4 = u64x4_splat (mask);
627 u64x4 hwaddr4 = u64x4_splat (hwaddr);
628 while (n_left > 0)
629 {
630 u64x4 r0, r1;
631 r0 = u64x4_load_unaligned (dmac + 0) & mask4;
632 r1 = u64x4_load_unaligned (dmac + 4) & mask4;
633
634 r0 = (r0 != hwaddr4) & ((r0 & igbit4) == 0);
635 r1 = (r1 != hwaddr4) & ((r1 & igbit4) == 0);
636
637 *(u32 *) (dmac_bad + 0) = u8x32_msb_mask ((u8x32) (r0));
638 *(u32 *) (dmac_bad + 4) = u8x32_msb_mask ((u8x32) (r1));
639
640 /* next */
641 dmac += 8;
642 dmac_bad += 8;
643 n_left -= 8;
644 }
645#else
646 while (n_left > 0)
647 {
648 u64 r0, r1, r2, r3;
649
650 r0 = dmac[0] & mask;
651 r1 = dmac[1] & mask;
652 r2 = dmac[2] & mask;
653 r3 = dmac[3] & mask;
654
655 r0 = (r0 != hwaddr) && ((r0 & igbit) == 0);
656 r1 = (r1 != hwaddr) && ((r1 & igbit) == 0);
657 r2 = (r2 != hwaddr) && ((r2 & igbit) == 0);
658 r3 = (r3 != hwaddr) && ((r3 & igbit) == 0);
659
660 dmac_bad[0] = r0;
661 dmac_bad[1] = r1;
662 dmac_bad[2] = r2;
663 dmac_bad[3] = r3;
664
665 /* next */
666 dmac += 4;
667 dmac_bad += 4;
668 n_left -= 4;
669 }
670#endif
671}
672
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100673/* process frame of buffers, store ethertype into array and update
674 buffer metadata fields depending on interface being l2 or l3 assuming that
675 packets are untagged. For tagged packets those fields are updated later.
676 Optionally store Destionation MAC address and tag data into arrays
677 for further processing */
678
679STATIC_ASSERT (VLIB_FRAME_SIZE % 8 == 0,
680 "VLIB_FRAME_SIZE must be power of 8");
681static_always_inline void
682eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
683 vnet_hw_interface_t * hi,
684 u32 * buffer_indices, u32 n_packets, int main_is_l3,
685 int ip4_cksum_ok, int dmac_check)
686{
687 ethernet_main_t *em = &ethernet_main;
688 u16 nexts[VLIB_FRAME_SIZE], *next;
689 u16 etypes[VLIB_FRAME_SIZE], *etype = etypes;
690 u64 dmacs[VLIB_FRAME_SIZE], *dmac = dmacs;
691 u8 dmacs_bad[VLIB_FRAME_SIZE];
692 u64 tags[VLIB_FRAME_SIZE], *tag = tags;
693 u16 slowpath_indices[VLIB_FRAME_SIZE];
694 u16 n_slowpath, i;
695 u16 next_ip4, next_ip6, next_mpls, next_l2;
696 u16 et_ip4 = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
697 u16 et_ip6 = clib_host_to_net_u16 (ETHERNET_TYPE_IP6);
698 u16 et_mpls = clib_host_to_net_u16 (ETHERNET_TYPE_MPLS);
699 u16 et_vlan = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
700 u16 et_dot1ad = clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD);
701 i32 n_left = n_packets;
702 vlib_buffer_t *b[20];
703 u32 *from;
704
705 from = buffer_indices;
706
707 while (n_left >= 20)
708 {
709 vlib_buffer_t **ph = b + 16, **pd = b + 8;
Damjan Marion650223c2018-11-14 16:55:53 +0100710 vlib_get_buffers (vm, from, b, 4);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100711 vlib_get_buffers (vm, from + 8, pd, 4);
712 vlib_get_buffers (vm, from + 16, ph, 4);
Damjan Marion650223c2018-11-14 16:55:53 +0100713
714 vlib_prefetch_buffer_header (ph[0], LOAD);
715 vlib_prefetch_buffer_data (pd[0], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100716 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100717
718 vlib_prefetch_buffer_header (ph[1], LOAD);
719 vlib_prefetch_buffer_data (pd[1], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100720 eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100721
722 vlib_prefetch_buffer_header (ph[2], LOAD);
723 vlib_prefetch_buffer_data (pd[2], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100724 eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100725
726 vlib_prefetch_buffer_header (ph[3], LOAD);
727 vlib_prefetch_buffer_data (pd[3], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100728 eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100729
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100730 eth_input_adv_and_flags_x4 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100731
732 /* next */
733 n_left -= 4;
734 etype += 4;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100735 tag += 4;
736 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100737 from += 4;
738 }
739 while (n_left >= 4)
740 {
741 vlib_get_buffers (vm, from, b, 4);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100742 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
743 eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
744 eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
745 eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
746 eth_input_adv_and_flags_x4 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100747
748 /* next */
749 n_left -= 4;
750 etype += 4;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100751 tag += 4;
752 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100753 from += 4;
754 }
755 while (n_left)
756 {
757 vlib_get_buffers (vm, from, b, 1);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100758 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
759 eth_input_adv_and_flags_x1 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100760
761 /* next */
762 n_left -= 1;
763 etype += 1;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100764 tag += 1;
765 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100766 from += 1;
767 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100768
769 if (dmac_check)
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500770 eth_input_process_frame_dmac_check (hi, dmacs, dmacs_bad, n_packets);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100771
772 next_ip4 = em->l3_next.input_next_ip4;
773 next_ip6 = em->l3_next.input_next_ip6;
774 next_mpls = em->l3_next.input_next_mpls;
775 next_l2 = em->l2_next;
776
777 if (next_ip4 == ETHERNET_INPUT_NEXT_IP4_INPUT && ip4_cksum_ok)
778 next_ip4 = ETHERNET_INPUT_NEXT_IP4_INPUT_NCS;
779
780#ifdef CLIB_HAVE_VEC256
781 u16x16 et16_ip4 = u16x16_splat (et_ip4);
782 u16x16 et16_ip6 = u16x16_splat (et_ip6);
783 u16x16 et16_mpls = u16x16_splat (et_mpls);
784 u16x16 et16_vlan = u16x16_splat (et_vlan);
785 u16x16 et16_dot1ad = u16x16_splat (et_dot1ad);
786 u16x16 next16_ip4 = u16x16_splat (next_ip4);
787 u16x16 next16_ip6 = u16x16_splat (next_ip6);
788 u16x16 next16_mpls = u16x16_splat (next_mpls);
789 u16x16 next16_l2 = u16x16_splat (next_l2);
790 u16x16 zero = { 0 };
791 u16x16 stairs = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
792#endif
793
794 etype = etypes;
795 n_left = n_packets;
796 next = nexts;
797 n_slowpath = 0;
798 i = 0;
799
800 /* fastpath - in l3 mode hadles ip4, ip6 and mpls packets, other packets
801 are considered as slowpath, in l2 mode all untagged packets are
802 considered as fastpath */
803 while (n_left > 0)
804 {
805#ifdef CLIB_HAVE_VEC256
806 if (n_left >= 16)
807 {
808 u16x16 r = zero;
809 u16x16 e16 = u16x16_load_unaligned (etype);
810 if (main_is_l3)
811 {
812 r += (e16 == et16_ip4) & next16_ip4;
813 r += (e16 == et16_ip6) & next16_ip6;
814 r += (e16 == et16_mpls) & next16_mpls;
815 }
816 else
817 r = ((e16 != et16_vlan) & (e16 != et16_dot1ad)) & next16_l2;
818 u16x16_store_unaligned (r, next);
819
820 if (!u16x16_is_all_zero (r == zero))
821 {
822 if (u16x16_is_all_zero (r))
823 {
824 u16x16_store_unaligned (u16x16_splat (i) + stairs,
825 slowpath_indices + n_slowpath);
826 n_slowpath += 16;
827 }
828 else
829 {
830 for (int j = 0; j < 16; j++)
831 if (next[j] == 0)
832 slowpath_indices[n_slowpath++] = i + j;
833 }
834 }
835
836 etype += 16;
837 next += 16;
838 n_left -= 16;
839 i += 16;
840 continue;
841 }
842#endif
843 if (main_is_l3 && etype[0] == et_ip4)
844 next[0] = next_ip4;
845 else if (main_is_l3 && etype[0] == et_ip6)
846 next[0] = next_ip6;
847 else if (main_is_l3 && etype[0] == et_mpls)
848 next[0] = next_mpls;
849 else if (main_is_l3 == 0 &&
850 etype[0] != et_vlan && etype[0] != et_dot1ad)
851 next[0] = next_l2;
852 else
853 {
854 next[0] = 0;
855 slowpath_indices[n_slowpath++] = i;
856 }
857
858 etype += 1;
859 next += 1;
860 n_left -= 1;
861 i += 1;
862 }
863
864 if (n_slowpath)
865 {
866 vnet_main_t *vnm = vnet_get_main ();
867 n_left = n_slowpath;
868 u16 *si = slowpath_indices;
869 u32 last_unknown_etype = ~0;
870 u32 last_unknown_next = ~0;
871 eth_input_tag_lookup_t dot1ad_lookup, dot1q_lookup = {
872 .mask = -1LL,
873 .tag = tags[si[0]] ^ -1LL,
874 .sw_if_index = ~0
875 };
876
877 clib_memcpy_fast (&dot1ad_lookup, &dot1q_lookup, sizeof (dot1q_lookup));
878
879 while (n_left)
880 {
881 i = si[0];
882 u16 etype = etypes[i];
883
884 if (etype == et_vlan)
885 {
886 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
887 eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
888 &dot1q_lookup, dmacs_bad[i], 0,
889 main_is_l3, dmac_check);
890
891 }
892 else if (etype == et_dot1ad)
893 {
894 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
895 eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
896 &dot1ad_lookup, dmacs_bad[i], 1,
897 main_is_l3, dmac_check);
898 }
899 else
900 {
901 /* untagged packet with not well known etyertype */
902 if (last_unknown_etype != etype)
903 {
904 last_unknown_etype = etype;
905 etype = clib_host_to_net_u16 (etype);
906 last_unknown_next = eth_input_next_by_type (etype);
907 }
908 if (dmac_check && main_is_l3 && dmacs_bad[i])
909 {
910 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
911 b->error = node->errors[ETHERNET_ERROR_L3_MAC_MISMATCH];
912 nexts[i] = ETHERNET_INPUT_NEXT_PUNT;
913 }
914 else
915 nexts[i] = last_unknown_next;
916 }
917
918 /* next */
919 n_left--;
920 si++;
921 }
922
923 eth_input_update_if_counters (vm, vnm, &dot1q_lookup);
924 eth_input_update_if_counters (vm, vnm, &dot1ad_lookup);
925 }
926
927 vlib_buffer_enqueue_to_next (vm, node, buffer_indices, nexts, n_packets);
Damjan Marion650223c2018-11-14 16:55:53 +0100928}
929
930static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100931eth_input_single_int (vlib_main_t * vm, vlib_node_runtime_t * node,
932 vnet_hw_interface_t * hi, u32 * from, u32 n_pkts,
933 int ip4_cksum_ok)
Damjan Marion650223c2018-11-14 16:55:53 +0100934{
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100935 ethernet_main_t *em = &ethernet_main;
936 ethernet_interface_t *ei;
937 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
938 main_intf_t *intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
939 subint_config_t *subint0 = &intf0->untagged_subint;
Damjan Marion650223c2018-11-14 16:55:53 +0100940
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100941 int main_is_l3 = (subint0->flags & SUBINT_CONFIG_L2) == 0;
942 int promisc = (ei->flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL) != 0;
Damjan Marion650223c2018-11-14 16:55:53 +0100943
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100944 if (main_is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +0100945 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100946 /* main interface is L3, we dont expect tagged packets and interface
947 is not in promisc node, so we dont't need to check DMAC */
948 int is_l3 = 1;
Damjan Marion650223c2018-11-14 16:55:53 +0100949
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100950 if (promisc == 0)
951 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
952 ip4_cksum_ok, 0);
Damjan Marion650223c2018-11-14 16:55:53 +0100953 else
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100954 /* subinterfaces and promisc mode so DMAC check is needed */
955 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
956 ip4_cksum_ok, 1);
957 return;
Damjan Marion650223c2018-11-14 16:55:53 +0100958 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100959 else
Damjan Marion650223c2018-11-14 16:55:53 +0100960 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100961 /* untagged packets are treated as L2 */
962 int is_l3 = 0;
963 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
964 ip4_cksum_ok, 1);
965 return;
Damjan Marion650223c2018-11-14 16:55:53 +0100966 }
967}
968
969static_always_inline void
970ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
971 vlib_frame_t * from_frame)
972{
973 u32 *from, n_left;
Benoît Ganne98477922019-04-10 14:21:11 +0200974 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
Damjan Marion650223c2018-11-14 16:55:53 +0100975 {
Dave Barach5ecd5a52019-02-25 15:27:28 -0500976 from = vlib_frame_vector_args (from_frame);
977 n_left = from_frame->n_vectors;
Damjan Marion650223c2018-11-14 16:55:53 +0100978
Dave Barach5ecd5a52019-02-25 15:27:28 -0500979 while (n_left)
Damjan Marion650223c2018-11-14 16:55:53 +0100980 {
Dave Barach5ecd5a52019-02-25 15:27:28 -0500981 ethernet_input_trace_t *t0;
982 vlib_buffer_t *b0 = vlib_get_buffer (vm, from[0]);
983
984 if (b0->flags & VLIB_BUFFER_IS_TRACED)
985 {
986 t0 = vlib_add_trace (vm, node, b0,
987 sizeof (ethernet_input_trace_t));
988 clib_memcpy_fast (t0->packet_data, b0->data + b0->current_data,
989 sizeof (t0->packet_data));
990 t0->frame_flags = from_frame->flags;
991 clib_memcpy_fast (&t0->frame_data,
992 vlib_frame_scalar_args (from_frame),
993 sizeof (ethernet_input_frame_t));
994 }
995 from += 1;
996 n_left -= 1;
Damjan Marion650223c2018-11-14 16:55:53 +0100997 }
Dave Barach5ecd5a52019-02-25 15:27:28 -0500998 }
999
1000 /* rx pcap capture if enabled */
Dave Barach33909772019-09-23 10:27:27 -04001001 if (PREDICT_FALSE (vlib_global_main.pcap.pcap_rx_enable))
Dave Barach5ecd5a52019-02-25 15:27:28 -05001002 {
1003 u32 bi0;
Dave Barach9137e542019-09-13 17:47:50 -04001004 vnet_main_t *vnm = vnet_get_main ();
Dave Barach33909772019-09-23 10:27:27 -04001005 vnet_pcap_t *pp = &vlib_global_main.pcap;
Dave Barach5ecd5a52019-02-25 15:27:28 -05001006
1007 from = vlib_frame_vector_args (from_frame);
1008 n_left = from_frame->n_vectors;
1009 while (n_left > 0)
1010 {
Dave Barach9137e542019-09-13 17:47:50 -04001011 int classify_filter_result;
Dave Barach5ecd5a52019-02-25 15:27:28 -05001012 vlib_buffer_t *b0;
1013 bi0 = from[0];
1014 from++;
Dave Barach9137e542019-09-13 17:47:50 -04001015 n_left--;
Dave Barach5ecd5a52019-02-25 15:27:28 -05001016 b0 = vlib_get_buffer (vm, bi0);
Dave Barach9137e542019-09-13 17:47:50 -04001017 if (vec_len (vnm->classify_filter_table_indices))
1018 {
1019 classify_filter_result =
1020 vnet_is_packet_traced_inline
1021 (b0, vnm->classify_filter_table_indices[0],
1022 0 /* full classify */ );
1023 if (classify_filter_result)
Dave Barach33909772019-09-23 10:27:27 -04001024 pcap_add_buffer (&pp->pcap_main, vm, bi0,
1025 pp->max_bytes_per_pkt);
Dave Barach9137e542019-09-13 17:47:50 -04001026 continue;
1027 }
Dave Barach5ecd5a52019-02-25 15:27:28 -05001028
Dave Barach33909772019-09-23 10:27:27 -04001029 if (pp->pcap_sw_if_index == 0 ||
1030 pp->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
Dave Barach5ecd5a52019-02-25 15:27:28 -05001031 {
Dave Barach33909772019-09-23 10:27:27 -04001032 pcap_add_buffer (&pp->pcap_main, vm, bi0,
1033 pp->max_bytes_per_pkt);
Dave Barach5ecd5a52019-02-25 15:27:28 -05001034 }
Dave Barach5ecd5a52019-02-25 15:27:28 -05001035 }
Damjan Marion650223c2018-11-14 16:55:53 +01001036 }
1037}
1038
1039static_always_inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040ethernet_input_inline (vlib_main_t * vm,
1041 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +01001042 u32 * from, u32 n_packets,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 ethernet_input_variant_t variant)
1044{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001045 vnet_main_t *vnm = vnet_get_main ();
1046 ethernet_main_t *em = &ethernet_main;
1047 vlib_node_runtime_t *error_node;
Damjan Marion650223c2018-11-14 16:55:53 +01001048 u32 n_left_from, next_index, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
Damjan Marion067cd622018-07-11 12:47:43 +02001050 u32 thread_index = vm->thread_index;
Dave Barachcfba1e22016-11-16 10:23:50 -05001051 u32 cached_sw_if_index = ~0;
1052 u32 cached_is_l2 = 0; /* shut up gcc */
John Lo1904c472017-03-10 17:15:22 -05001053 vnet_hw_interface_t *hi = NULL; /* used for main interface only */
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001054 vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
1055 vlib_buffer_t **b = bufs;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056
1057 if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
1058 error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
1059 else
1060 error_node = node;
1061
Damjan Marion650223c2018-11-14 16:55:53 +01001062 n_left_from = n_packets;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063
1064 next_index = node->cached_next_index;
1065 stats_sw_if_index = node->runtime_data[0];
1066 stats_n_packets = stats_n_bytes = 0;
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001067 vlib_get_buffers (vm, from, bufs, n_left_from);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068
1069 while (n_left_from > 0)
1070 {
1071 u32 n_left_to_next;
1072
1073 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1074
1075 while (n_left_from >= 4 && n_left_to_next >= 2)
1076 {
1077 u32 bi0, bi1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001078 vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079 u8 next0, next1, error0, error1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001080 u16 type0, orig_type0, type1, orig_type1;
1081 u16 outer_id0, inner_id0, outer_id1, inner_id1;
1082 u32 match_flags0, match_flags1;
1083 u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1,
1084 new_sw_if_index1, len1;
1085 vnet_hw_interface_t *hi0, *hi1;
1086 main_intf_t *main_intf0, *main_intf1;
1087 vlan_intf_t *vlan_intf0, *vlan_intf1;
1088 qinq_intf_t *qinq_intf0, *qinq_intf1;
1089 u32 is_l20, is_l21;
Dave Barachcfba1e22016-11-16 10:23:50 -05001090 ethernet_header_t *e0, *e1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091
1092 /* Prefetch next iteration. */
1093 {
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001094 vlib_prefetch_buffer_header (b[2], STORE);
1095 vlib_prefetch_buffer_header (b[3], STORE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001097 CLIB_PREFETCH (b[2]->data, sizeof (ethernet_header_t), LOAD);
1098 CLIB_PREFETCH (b[3]->data, sizeof (ethernet_header_t), LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099 }
1100
1101 bi0 = from[0];
1102 bi1 = from[1];
1103 to_next[0] = bi0;
1104 to_next[1] = bi1;
1105 from += 2;
1106 to_next += 2;
1107 n_left_to_next -= 2;
1108 n_left_from -= 2;
1109
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001110 b0 = b[0];
1111 b1 = b[1];
1112 b += 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113
1114 error0 = error1 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001115 e0 = vlib_buffer_get_current (b0);
1116 type0 = clib_net_to_host_u16 (e0->type);
1117 e1 = vlib_buffer_get_current (b1);
1118 type1 = clib_net_to_host_u16 (e1->type);
1119
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001120 /* Set the L2 header offset for all packets */
1121 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1122 vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
1123 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1124 b1->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1125
John Locc532852016-12-14 15:42:45 -05001126 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001127 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
Damjan Marionc6969b52018-02-19 12:14:06 +01001128 && !ethernet_frame_is_any_tagged_x2 (type0,
1129 type1)))
Dave Barachcfba1e22016-11-16 10:23:50 -05001130 {
1131 main_intf_t *intf0;
1132 subint_config_t *subint0;
1133 u32 sw_if_index0, sw_if_index1;
1134
1135 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1136 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1137 is_l20 = cached_is_l2;
1138
1139 /* This is probably wholly unnecessary */
1140 if (PREDICT_FALSE (sw_if_index0 != sw_if_index1))
1141 goto slowpath;
1142
John Lo1904c472017-03-10 17:15:22 -05001143 /* Now sw_if_index0 == sw_if_index1 */
Dave Barachcfba1e22016-11-16 10:23:50 -05001144 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1145 {
1146 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001147 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1148 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001149 subint0 = &intf0->untagged_subint;
1150 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1151 }
John Lo7714b302016-12-20 16:59:02 -05001152
Dave Barachcfba1e22016-11-16 10:23:50 -05001153 if (PREDICT_TRUE (is_l20 != 0))
1154 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001155 vnet_buffer (b0)->l3_hdr_offset =
1156 vnet_buffer (b0)->l2_hdr_offset +
1157 sizeof (ethernet_header_t);
1158 vnet_buffer (b1)->l3_hdr_offset =
1159 vnet_buffer (b1)->l2_hdr_offset +
1160 sizeof (ethernet_header_t);
1161 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
1162 b1->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001163 next0 = em->l2_next;
1164 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001165 next1 = em->l2_next;
1166 vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001167 }
John Locc532852016-12-14 15:42:45 -05001168 else
1169 {
John Lo1904c472017-03-10 17:15:22 -05001170 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001171 (hi->hw_address != 0) &&
Neale Ranns37029302018-08-10 05:30:06 -07001172 !ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
John Lo1904c472017-03-10 17:15:22 -05001173 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
1174 if (!ethernet_address_cast (e1->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001175 (hi->hw_address != 0) &&
Neale Ranns37029302018-08-10 05:30:06 -07001176 !ethernet_mac_address_equal ((u8 *) e1, hi->hw_address))
John Lo1904c472017-03-10 17:15:22 -05001177 error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
John Lob14826e2018-04-18 15:52:23 -04001178 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001179 determine_next_node (em, variant, 0, type0, b0,
1180 &error0, &next0);
John Lob14826e2018-04-18 15:52:23 -04001181 vlib_buffer_advance (b1, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001182 determine_next_node (em, variant, 0, type1, b1,
1183 &error1, &next1);
John Locc532852016-12-14 15:42:45 -05001184 }
1185 goto ship_it01;
Dave Barachcfba1e22016-11-16 10:23:50 -05001186 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187
John Locc532852016-12-14 15:42:45 -05001188 /* Slow-path for the tagged case */
1189 slowpath:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001190 parse_header (variant,
1191 b0,
1192 &type0,
1193 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001195 parse_header (variant,
1196 b1,
1197 &type1,
1198 &orig_type1, &outer_id1, &inner_id1, &match_flags1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001200 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1201 old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001203 eth_vlan_table_lookups (em,
1204 vnm,
1205 old_sw_if_index0,
1206 orig_type0,
1207 outer_id0,
1208 inner_id0,
1209 &hi0,
1210 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001212 eth_vlan_table_lookups (em,
1213 vnm,
1214 old_sw_if_index1,
1215 orig_type1,
1216 outer_id1,
1217 inner_id1,
1218 &hi1,
1219 &main_intf1, &vlan_intf1, &qinq_intf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001220
1221 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001222 b0,
1223 match_flags0,
1224 main_intf0,
1225 vlan_intf0,
1226 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227
1228 identify_subint (hi1,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001229 b1,
1230 match_flags1,
1231 main_intf1,
1232 vlan_intf1,
1233 qinq_intf1, &new_sw_if_index1, &error1, &is_l21);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001235 // Save RX sw_if_index for later nodes
1236 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1237 error0 !=
1238 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
1239 vnet_buffer (b1)->sw_if_index[VLIB_RX] =
1240 error1 !=
1241 ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001242
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001243 // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
1244 if (((new_sw_if_index0 != ~0)
1245 && (new_sw_if_index0 != old_sw_if_index0))
1246 || ((new_sw_if_index1 != ~0)
1247 && (new_sw_if_index1 != old_sw_if_index1)))
1248 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001250 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001251 - vnet_buffer (b0)->l2_hdr_offset;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001252 len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001253 - vnet_buffer (b1)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001255 stats_n_packets += 2;
1256 stats_n_bytes += len0 + len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001257
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001258 if (PREDICT_FALSE
1259 (!(new_sw_if_index0 == stats_sw_if_index
1260 && new_sw_if_index1 == stats_sw_if_index)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001261 {
1262 stats_n_packets -= 2;
1263 stats_n_bytes -= len0 + len1;
1264
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001265 if (new_sw_if_index0 != old_sw_if_index0
1266 && new_sw_if_index0 != ~0)
1267 vlib_increment_combined_counter (vnm->
1268 interface_main.combined_sw_if_counters
1269 +
1270 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001271 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001272 new_sw_if_index0, 1,
1273 len0);
1274 if (new_sw_if_index1 != old_sw_if_index1
1275 && new_sw_if_index1 != ~0)
1276 vlib_increment_combined_counter (vnm->
1277 interface_main.combined_sw_if_counters
1278 +
1279 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001280 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001281 new_sw_if_index1, 1,
1282 len1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283
1284 if (new_sw_if_index0 == new_sw_if_index1)
1285 {
1286 if (stats_n_packets > 0)
1287 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001288 vlib_increment_combined_counter
1289 (vnm->interface_main.combined_sw_if_counters
1290 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001291 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001292 stats_sw_if_index,
1293 stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294 stats_n_packets = stats_n_bytes = 0;
1295 }
1296 stats_sw_if_index = new_sw_if_index0;
1297 }
1298 }
1299 }
1300
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001301 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1302 is_l20 = is_l21 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001304 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1305 &next0);
1306 determine_next_node (em, variant, is_l21, type1, b1, &error1,
1307 &next1);
1308
John Lo1904c472017-03-10 17:15:22 -05001309 ship_it01:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001310 b0->error = error_node->errors[error0];
1311 b1->error = error_node->errors[error1];
1312
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001313 // verify speculative enqueue
1314 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1315 n_left_to_next, bi0, bi1, next0,
1316 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001317 }
1318
1319 while (n_left_from > 0 && n_left_to_next > 0)
1320 {
1321 u32 bi0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001322 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 u8 error0, next0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001324 u16 type0, orig_type0;
1325 u16 outer_id0, inner_id0;
1326 u32 match_flags0;
1327 u32 old_sw_if_index0, new_sw_if_index0, len0;
1328 vnet_hw_interface_t *hi0;
1329 main_intf_t *main_intf0;
1330 vlan_intf_t *vlan_intf0;
1331 qinq_intf_t *qinq_intf0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001332 ethernet_header_t *e0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001333 u32 is_l20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001334
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001335 // Prefetch next iteration
1336 if (n_left_from > 1)
1337 {
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001338 vlib_prefetch_buffer_header (b[1], STORE);
1339 CLIB_PREFETCH (b[1]->data, CLIB_CACHE_LINE_BYTES, LOAD);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001340 }
1341
1342 bi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343 to_next[0] = bi0;
1344 from += 1;
1345 to_next += 1;
1346 n_left_from -= 1;
1347 n_left_to_next -= 1;
1348
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001349 b0 = b[0];
1350 b += 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351
1352 error0 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001353 e0 = vlib_buffer_get_current (b0);
1354 type0 = clib_net_to_host_u16 (e0->type);
1355
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001356 /* Set the L2 header offset for all packets */
1357 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1358 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1359
John Locc532852016-12-14 15:42:45 -05001360 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001361 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
1362 && !ethernet_frame_is_tagged (type0)))
1363 {
1364 main_intf_t *intf0;
1365 subint_config_t *subint0;
1366 u32 sw_if_index0;
1367
1368 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1369 is_l20 = cached_is_l2;
1370
1371 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1372 {
1373 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001374 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1375 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001376 subint0 = &intf0->untagged_subint;
1377 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1378 }
John Lo7714b302016-12-20 16:59:02 -05001379
John Lo7714b302016-12-20 16:59:02 -05001380
Dave Barachcfba1e22016-11-16 10:23:50 -05001381 if (PREDICT_TRUE (is_l20 != 0))
1382 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001383 vnet_buffer (b0)->l3_hdr_offset =
1384 vnet_buffer (b0)->l2_hdr_offset +
1385 sizeof (ethernet_header_t);
1386 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001387 next0 = em->l2_next;
1388 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001389 }
John Locc532852016-12-14 15:42:45 -05001390 else
1391 {
John Lo1904c472017-03-10 17:15:22 -05001392 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001393 (hi->hw_address != 0) &&
Neale Ranns37029302018-08-10 05:30:06 -07001394 !ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
John Lo1904c472017-03-10 17:15:22 -05001395 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
Andrew Yourtchenkoe78bca12018-10-10 16:15:55 +02001396 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001397 determine_next_node (em, variant, 0, type0, b0,
1398 &error0, &next0);
John Locc532852016-12-14 15:42:45 -05001399 }
1400 goto ship_it0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001401 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001402
John Locc532852016-12-14 15:42:45 -05001403 /* Slow-path for the tagged case */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001404 parse_header (variant,
1405 b0,
1406 &type0,
1407 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001409 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001411 eth_vlan_table_lookups (em,
1412 vnm,
1413 old_sw_if_index0,
1414 orig_type0,
1415 outer_id0,
1416 inner_id0,
1417 &hi0,
1418 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419
1420 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001421 b0,
1422 match_flags0,
1423 main_intf0,
1424 vlan_intf0,
1425 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001427 // Save RX sw_if_index for later nodes
1428 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1429 error0 !=
1430 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001431
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001432 // Increment subinterface stats
1433 // Note that interface-level counters have already been incremented
1434 // prior to calling this function. Thus only subinterface counters
1435 // are incremented here.
1436 //
Damjan Marion607de1a2016-08-16 22:53:54 +02001437 // Interface level counters include packets received on the main
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001438 // interface and all subinterfaces. Subinterface level counters
1439 // include only those packets received on that subinterface
Ed Warnickecb9cada2015-12-08 15:45:58 -07001440 // Increment stats if the subint is valid and it is not the main intf
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001441 if ((new_sw_if_index0 != ~0)
1442 && (new_sw_if_index0 != old_sw_if_index0))
1443 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001444
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001445 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001446 - vnet_buffer (b0)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001447
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001448 stats_n_packets += 1;
1449 stats_n_bytes += len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001451 // Batch stat increments from the same subinterface so counters
Damjan Marion607de1a2016-08-16 22:53:54 +02001452 // don't need to be incremented for every packet.
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001453 if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index))
1454 {
1455 stats_n_packets -= 1;
1456 stats_n_bytes -= len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001457
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001458 if (new_sw_if_index0 != ~0)
1459 vlib_increment_combined_counter
1460 (vnm->interface_main.combined_sw_if_counters
1461 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001462 thread_index, new_sw_if_index0, 1, len0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001463 if (stats_n_packets > 0)
1464 {
1465 vlib_increment_combined_counter
1466 (vnm->interface_main.combined_sw_if_counters
1467 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001468 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001469 stats_sw_if_index, stats_n_packets, stats_n_bytes);
1470 stats_n_packets = stats_n_bytes = 0;
1471 }
1472 stats_sw_if_index = new_sw_if_index0;
1473 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001474 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001475
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001476 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1477 is_l20 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001478
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001479 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1480 &next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001481
John Lo1904c472017-03-10 17:15:22 -05001482 ship_it0:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001483 b0->error = error_node->errors[error0];
1484
1485 // verify speculative enqueue
Ed Warnickecb9cada2015-12-08 15:45:58 -07001486 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1487 to_next, n_left_to_next,
1488 bi0, next0);
1489 }
1490
1491 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1492 }
1493
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001494 // Increment any remaining batched stats
1495 if (stats_n_packets > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001496 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001497 vlib_increment_combined_counter
1498 (vnm->interface_main.combined_sw_if_counters
1499 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001500 thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001501 node->runtime_data[0] = stats_sw_if_index;
1502 }
Damjan Marion650223c2018-11-14 16:55:53 +01001503}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001504
Damjan Marion5beecec2018-09-10 13:09:21 +02001505VLIB_NODE_FN (ethernet_input_node) (vlib_main_t * vm,
1506 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +01001507 vlib_frame_t * frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001508{
Damjan Marion650223c2018-11-14 16:55:53 +01001509 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion650223c2018-11-14 16:55:53 +01001510 u32 *from = vlib_frame_vector_args (frame);
1511 u32 n_packets = frame->n_vectors;
1512
1513 ethernet_input_trace (vm, node, frame);
1514
1515 if (frame->flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
1516 {
Damjan Marion650223c2018-11-14 16:55:53 +01001517 ethernet_input_frame_t *ef = vlib_frame_scalar_args (frame);
Damjan Marion650223c2018-11-14 16:55:53 +01001518 int ip4_cksum_ok = (frame->flags & ETH_INPUT_FRAME_F_IP4_CKSUM_OK) != 0;
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001519 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ef->hw_if_index);
1520 eth_input_single_int (vm, node, hi, from, n_packets, ip4_cksum_ok);
Damjan Marion650223c2018-11-14 16:55:53 +01001521 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001522 else
1523 ethernet_input_inline (vm, node, from, n_packets,
1524 ETHERNET_INPUT_VARIANT_ETHERNET);
Damjan Marion650223c2018-11-14 16:55:53 +01001525 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001526}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527
Damjan Marion5beecec2018-09-10 13:09:21 +02001528VLIB_NODE_FN (ethernet_input_type_node) (vlib_main_t * vm,
1529 vlib_node_runtime_t * node,
1530 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001531{
Damjan Marion650223c2018-11-14 16:55:53 +01001532 u32 *from = vlib_frame_vector_args (from_frame);
1533 u32 n_packets = from_frame->n_vectors;
1534 ethernet_input_trace (vm, node, from_frame);
1535 ethernet_input_inline (vm, node, from, n_packets,
1536 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE);
1537 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001538}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539
Damjan Marion5beecec2018-09-10 13:09:21 +02001540VLIB_NODE_FN (ethernet_input_not_l2_node) (vlib_main_t * vm,
1541 vlib_node_runtime_t * node,
1542 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001543{
Damjan Marion650223c2018-11-14 16:55:53 +01001544 u32 *from = vlib_frame_vector_args (from_frame);
1545 u32 n_packets = from_frame->n_vectors;
1546 ethernet_input_trace (vm, node, from_frame);
1547 ethernet_input_inline (vm, node, from, n_packets,
1548 ETHERNET_INPUT_VARIANT_NOT_L2);
1549 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001550}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001551
1552
1553// Return the subinterface config struct for the given sw_if_index
1554// Also return via parameter the appropriate match flags for the
1555// configured number of tags.
1556// On error (unsupported or not ethernet) return 0.
1557static subint_config_t *
1558ethernet_sw_interface_get_config (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001559 u32 sw_if_index,
1560 u32 * flags, u32 * unsupported)
1561{
1562 ethernet_main_t *em = &ethernet_main;
1563 vnet_hw_interface_t *hi;
1564 vnet_sw_interface_t *si;
1565 main_intf_t *main_intf;
1566 vlan_table_t *vlan_table;
1567 qinq_table_t *qinq_table;
1568 subint_config_t *subint = 0;
1569
Ed Warnickecb9cada2015-12-08 15:45:58 -07001570 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1571
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001572 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
1573 {
1574 *unsupported = 0;
1575 goto done; // non-ethernet interface
1576 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001577
1578 // ensure there's an entry for the main intf (shouldn't really be necessary)
1579 vec_validate (em->main_intfs, hi->hw_if_index);
1580 main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
1581
1582 // Locate the subint for the given ethernet config
1583 si = vnet_get_sw_interface (vnm, sw_if_index);
1584
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001585 if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
1586 {
1587 p2p_ethernet_main_t *p2pm = &p2p_main;
1588 u32 p2pe_sw_if_index =
1589 p2p_ethernet_lookup (hi->hw_if_index, si->p2p.client_mac);
1590 if (p2pe_sw_if_index == ~0)
1591 {
1592 pool_get (p2pm->p2p_subif_pool, subint);
1593 si->p2p.pool_index = subint - p2pm->p2p_subif_pool;
1594 }
1595 else
1596 subint = vec_elt_at_index (p2pm->p2p_subif_pool, si->p2p.pool_index);
1597 *flags = SUBINT_CONFIG_P2P;
1598 }
Neale Ranns17ff3c12018-07-04 10:24:24 -07001599 else if (si->type == VNET_SW_INTERFACE_TYPE_PIPE)
1600 {
1601 pipe_t *pipe;
1602
1603 pipe = pipe_get (sw_if_index);
1604 subint = &pipe->subint;
1605 *flags = SUBINT_CONFIG_P2P;
1606 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001607 else if (si->sub.eth.flags.default_sub)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001608 {
1609 subint = &main_intf->default_subint;
Mike Bly88076742018-09-24 10:13:06 -07001610 *flags = SUBINT_CONFIG_MATCH_1_TAG |
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001611 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1612 }
1613 else if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0))
1614 {
1615 // if no flags are set then this is a main interface
1616 // so treat as untagged
1617 subint = &main_intf->untagged_subint;
1618 *flags = SUBINT_CONFIG_MATCH_0_TAG;
1619 }
1620 else
1621 {
1622 // one or two tags
1623 // first get the vlan table
1624 if (si->sub.eth.flags.dot1ad)
1625 {
1626 if (main_intf->dot1ad_vlans == 0)
1627 {
1628 // Allocate a vlan table from the pool
1629 pool_get (em->vlan_pool, vlan_table);
1630 main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
1631 }
1632 else
1633 {
1634 // Get ptr to existing vlan table
1635 vlan_table =
1636 vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
1637 }
1638 }
1639 else
1640 { // dot1q
1641 if (main_intf->dot1q_vlans == 0)
1642 {
1643 // Allocate a vlan table from the pool
1644 pool_get (em->vlan_pool, vlan_table);
1645 main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
1646 }
1647 else
1648 {
1649 // Get ptr to existing vlan table
1650 vlan_table =
1651 vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
1652 }
1653 }
1654
1655 if (si->sub.eth.flags.one_tag)
1656 {
1657 *flags = si->sub.eth.flags.exact_match ?
1658 SUBINT_CONFIG_MATCH_1_TAG :
1659 (SUBINT_CONFIG_MATCH_1_TAG |
1660 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1661
1662 if (si->sub.eth.flags.outer_vlan_id_any)
1663 {
1664 // not implemented yet
1665 *unsupported = 1;
1666 goto done;
1667 }
1668 else
1669 {
1670 // a single vlan, a common case
1671 subint =
1672 &vlan_table->vlans[si->sub.eth.
1673 outer_vlan_id].single_tag_subint;
1674 }
1675
1676 }
1677 else
1678 {
1679 // Two tags
1680 *flags = si->sub.eth.flags.exact_match ?
1681 SUBINT_CONFIG_MATCH_2_TAG :
1682 (SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1683
1684 if (si->sub.eth.flags.outer_vlan_id_any
1685 && si->sub.eth.flags.inner_vlan_id_any)
1686 {
1687 // not implemented yet
1688 *unsupported = 1;
1689 goto done;
1690 }
1691
1692 if (si->sub.eth.flags.inner_vlan_id_any)
1693 {
1694 // a specific outer and "any" inner
1695 // don't need a qinq table for this
1696 subint =
1697 &vlan_table->vlans[si->sub.eth.
1698 outer_vlan_id].inner_any_subint;
1699 if (si->sub.eth.flags.exact_match)
1700 {
1701 *flags = SUBINT_CONFIG_MATCH_2_TAG;
1702 }
1703 else
1704 {
1705 *flags = SUBINT_CONFIG_MATCH_2_TAG |
1706 SUBINT_CONFIG_MATCH_3_TAG;
1707 }
1708 }
1709 else
1710 {
1711 // a specific outer + specifc innner vlan id, a common case
1712
1713 // get the qinq table
1714 if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0)
1715 {
1716 // Allocate a qinq table from the pool
1717 pool_get (em->qinq_pool, qinq_table);
1718 vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs =
1719 qinq_table - em->qinq_pool;
1720 }
1721 else
1722 {
1723 // Get ptr to existing qinq table
1724 qinq_table =
1725 vec_elt_at_index (em->qinq_pool,
1726 vlan_table->vlans[si->sub.
1727 eth.outer_vlan_id].
1728 qinqs);
1729 }
1730 subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
1731 }
1732 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733 }
1734
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001735done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001736 return subint;
1737}
1738
Damjan Marion5beecec2018-09-10 13:09:21 +02001739static clib_error_t *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001740ethernet_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001741{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001742 subint_config_t *subint;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743 u32 dummy_flags;
1744 u32 dummy_unsup;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001745 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001746
1747 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001748 subint =
1749 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1750 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001752 if (subint == 0)
1753 {
1754 // not implemented yet or not ethernet
1755 goto done;
1756 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001757
1758 subint->sw_if_index =
1759 ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
1760
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001761done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762 return error;
1763}
1764
1765VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
1766
1767
Damjan Marion5beecec2018-09-10 13:09:21 +02001768#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769// Set the L2/L3 mode for the subinterface
1770void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001771ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772{
1773 subint_config_t *subint;
1774 u32 dummy_flags;
1775 u32 dummy_unsup;
1776 int is_port;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001777 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778
1779 is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
1780
1781 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001782 subint =
1783 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1784 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001785
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001786 if (subint == 0)
1787 {
1788 // unimplemented or not ethernet
1789 goto done;
1790 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001791
1792 // Double check that the config we found is for our interface (or the interface is down)
1793 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1794
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001795 if (l2)
1796 {
1797 subint->flags |= SUBINT_CONFIG_L2;
1798 if (is_port)
1799 subint->flags |=
1800 SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
1801 | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1802 }
1803 else
1804 {
1805 subint->flags &= ~SUBINT_CONFIG_L2;
1806 if (is_port)
1807 subint->flags &=
1808 ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
1809 | SUBINT_CONFIG_MATCH_3_TAG);
1810 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001812done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813 return;
1814}
1815
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001816/*
1817 * Set the L2/L3 mode for the subinterface regardless of port
1818 */
1819void
1820ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001821 u32 sw_if_index, u32 l2)
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001822{
1823 subint_config_t *subint;
1824 u32 dummy_flags;
1825 u32 dummy_unsup;
1826
1827 /* Find the config for this subinterface */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001828 subint =
1829 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1830 &dummy_unsup);
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001831
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001832 if (subint == 0)
1833 {
1834 /* unimplemented or not ethernet */
1835 goto done;
1836 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001837
1838 /*
1839 * Double check that the config we found is for our interface (or the
1840 * interface is down)
1841 */
1842 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1843
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001844 if (l2)
1845 {
1846 subint->flags |= SUBINT_CONFIG_L2;
1847 }
1848 else
1849 {
1850 subint->flags &= ~SUBINT_CONFIG_L2;
1851 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001852
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001853done:
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001854 return;
1855}
Damjan Marion5beecec2018-09-10 13:09:21 +02001856#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857
1858static clib_error_t *
1859ethernet_sw_interface_add_del (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001860 u32 sw_if_index, u32 is_create)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001862 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001863 subint_config_t *subint;
1864 u32 match_flags;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001865 u32 unsupported = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866
1867 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001868 subint =
1869 ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags,
1870 &unsupported);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001872 if (subint == 0)
1873 {
1874 // not implemented yet or not ethernet
1875 if (unsupported)
1876 {
Damjan Marion607de1a2016-08-16 22:53:54 +02001877 // this is the NYI case
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001878 error = clib_error_return (0, "not implemented yet");
1879 }
1880 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001881 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001883 if (!is_create)
1884 {
1885 subint->flags = 0;
1886 return error;
1887 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001888
1889 // Initialize the subint
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001890 if (subint->flags & SUBINT_CONFIG_VALID)
1891 {
1892 // Error vlan already in use
1893 error = clib_error_return (0, "vlan is already in use");
1894 }
1895 else
1896 {
Neale Ranns17ff3c12018-07-04 10:24:24 -07001897 // Note that config is L3 by default
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001898 subint->flags = SUBINT_CONFIG_VALID | match_flags;
1899 subint->sw_if_index = ~0; // because interfaces are initially down
1900 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001902done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001903 return error;
1904}
1905
1906VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
1907
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001908static char *ethernet_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909#define ethernet_error(n,c,s) s,
1910#include "error.def"
1911#undef ethernet_error
1912};
1913
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001914/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001915VLIB_REGISTER_NODE (ethernet_input_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001916 .name = "ethernet-input",
1917 /* Takes a vector of packets. */
1918 .vector_size = sizeof (u32),
Damjan Marion650223c2018-11-14 16:55:53 +01001919 .scalar_size = sizeof (ethernet_input_frame_t),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001920 .n_errors = ETHERNET_N_ERROR,
1921 .error_strings = ethernet_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001922 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1923 .next_nodes = {
1924#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1925 foreach_ethernet_input_next
1926#undef _
1927 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928 .format_buffer = format_ethernet_header_with_length,
1929 .format_trace = format_ethernet_input_trace,
1930 .unformat_buffer = unformat_ethernet_header,
1931};
1932
Damjan Marion5beecec2018-09-10 13:09:21 +02001933VLIB_REGISTER_NODE (ethernet_input_type_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001934 .name = "ethernet-input-type",
1935 /* Takes a vector of packets. */
1936 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001937 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1938 .next_nodes = {
1939#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1940 foreach_ethernet_input_next
1941#undef _
1942 },
1943};
1944
Damjan Marion5beecec2018-09-10 13:09:21 +02001945VLIB_REGISTER_NODE (ethernet_input_not_l2_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946 .name = "ethernet-input-not-l2",
1947 /* Takes a vector of packets. */
1948 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1950 .next_nodes = {
1951#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1952 foreach_ethernet_input_next
1953#undef _
1954 },
1955};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001956/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001957
Damjan Marion5beecec2018-09-10 13:09:21 +02001958#ifndef CLIB_MARCH_VARIANT
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001959void
1960ethernet_set_rx_redirect (vnet_main_t * vnm,
1961 vnet_hw_interface_t * hi, u32 enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962{
1963 // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
1964 // don't go directly to ip4-input)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001965 vnet_hw_interface_rx_redirect_to_node
1966 (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001967}
1968
1969
1970/*
1971 * Initialization and registration for the next_by_ethernet structure
1972 */
1973
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001974clib_error_t *
1975next_by_ethertype_init (next_by_ethertype_t * l3_next)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001976{
1977 l3_next->input_next_by_type = sparse_vec_new
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001978 ( /* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001979 /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
1980
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001981 vec_validate (l3_next->sparse_index_by_input_next_index,
1982 ETHERNET_INPUT_NEXT_DROP);
1983 vec_validate (l3_next->sparse_index_by_input_next_index,
1984 ETHERNET_INPUT_NEXT_PUNT);
1985 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP] =
1986 SPARSE_VEC_INVALID_INDEX;
1987 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] =
1988 SPARSE_VEC_INVALID_INDEX;
1989
Damjan Marion607de1a2016-08-16 22:53:54 +02001990 /*
1991 * Make sure we don't wipe out an ethernet registration by mistake
Dave Barach1f49ed62016-02-24 11:29:06 -05001992 * Can happen if init function ordering constraints are missing.
1993 */
1994 if (CLIB_DEBUG > 0)
1995 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001996 ethernet_main_t *em = &ethernet_main;
1997 ASSERT (em->next_by_ethertype_register_called == 0);
Dave Barach1f49ed62016-02-24 11:29:06 -05001998 }
1999
Ed Warnickecb9cada2015-12-08 15:45:58 -07002000 return 0;
2001}
2002
2003// Add an ethertype -> next index mapping to the structure
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002004clib_error_t *
2005next_by_ethertype_register (next_by_ethertype_t * l3_next,
2006 u32 ethertype, u32 next_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002007{
2008 u32 i;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002009 u16 *n;
2010 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011
Dave Barach1f49ed62016-02-24 11:29:06 -05002012 if (CLIB_DEBUG > 0)
2013 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002014 ethernet_main_t *em = &ethernet_main;
Dave Barach1f49ed62016-02-24 11:29:06 -05002015 em->next_by_ethertype_register_called = 1;
2016 }
2017
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 /* Setup ethernet type -> next index sparse vector mapping. */
2019 n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
2020 n[0] = next_index;
2021
2022 /* Rebuild next index -> sparse index inverse mapping when sparse vector
2023 is updated. */
2024 vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
2025 for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002026 l3_next->
2027 sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028
2029 // do not allow the cached next index's to be updated if L3
2030 // redirect is enabled, as it will have overwritten them
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002031 if (!em->redirect_l3)
2032 {
2033 // Cache common ethertypes directly
2034 if (ethertype == ETHERNET_TYPE_IP4)
2035 {
2036 l3_next->input_next_ip4 = next_index;
2037 }
2038 else if (ethertype == ETHERNET_TYPE_IP6)
2039 {
2040 l3_next->input_next_ip6 = next_index;
2041 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002042 else if (ethertype == ETHERNET_TYPE_MPLS)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002043 {
2044 l3_next->input_next_mpls = next_index;
2045 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047 return 0;
2048}
2049
Dave Barachf8d50682019-05-14 18:01:44 -04002050void
2051ethernet_input_init (vlib_main_t * vm, ethernet_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002052{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002053 __attribute__ ((unused)) vlan_table_t *invalid_vlan_table;
2054 __attribute__ ((unused)) qinq_table_t *invalid_qinq_table;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055
2056 ethernet_setup_node (vm, ethernet_input_node.index);
2057 ethernet_setup_node (vm, ethernet_input_type_node.index);
2058 ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
2059
2060 next_by_ethertype_init (&em->l3_next);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002061
Ed Warnickecb9cada2015-12-08 15:45:58 -07002062 // Initialize pools and vector for vlan parsing
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002063 vec_validate (em->main_intfs, 10); // 10 main interfaces
2064 pool_alloc (em->vlan_pool, 10);
2065 pool_alloc (em->qinq_pool, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002066
2067 // The first vlan pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002068 pool_get (em->vlan_pool, invalid_vlan_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069 // The first qinq pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002070 pool_get (em->qinq_pool, invalid_qinq_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002071}
2072
Ed Warnickecb9cada2015-12-08 15:45:58 -07002073void
2074ethernet_register_input_type (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002075 ethernet_type_t type, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002076{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002077 ethernet_main_t *em = &ethernet_main;
2078 ethernet_type_info_t *ti;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002079 u32 i;
2080
2081 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002082 clib_error_t *error = vlib_call_init_function (vm, ethernet_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002083 if (error)
2084 clib_error_report (error);
2085 }
2086
2087 ti = ethernet_get_type_info (em, type);
Dave Barach4bda2d92019-07-03 15:21:50 -04002088 if (ti == 0)
2089 {
2090 clib_warning ("type_info NULL for type %d", type);
2091 return;
2092 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002093 ti->node_index = node_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002094 ti->next_index = vlib_node_add_next (vm,
2095 ethernet_input_node.index, node_index);
2096 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097 ASSERT (i == ti->next_index);
2098
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002099 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002100 ASSERT (i == ti->next_index);
2101
2102 // Add the L3 node for this ethertype to the next nodes structure
2103 next_by_ethertype_register (&em->l3_next, type, ti->next_index);
2104
2105 // Call the registration functions for other nodes that want a mapping
2106 l2bvi_register_input_type (vm, type, node_index);
2107}
2108
2109void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002110ethernet_register_l2_input (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002111{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002112 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002113 u32 i;
2114
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002115 em->l2_next =
2116 vlib_node_add_next (vm, ethernet_input_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002117
Damjan Marion607de1a2016-08-16 22:53:54 +02002118 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002119 * Even if we never use these arcs, we have to align the next indices...
2120 */
2121 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
2122
2123 ASSERT (i == em->l2_next);
2124
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002125 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002126 ASSERT (i == em->l2_next);
2127}
2128
2129// Register a next node for L3 redirect, and enable L3 redirect
2130void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002131ethernet_register_l3_redirect (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002133 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002134 u32 i;
2135
2136 em->redirect_l3 = 1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002137 em->redirect_l3_next = vlib_node_add_next (vm,
2138 ethernet_input_node.index,
2139 node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002140 /*
2141 * Change the cached next nodes to the redirect node
2142 */
2143 em->l3_next.input_next_ip4 = em->redirect_l3_next;
2144 em->l3_next.input_next_ip6 = em->redirect_l3_next;
2145 em->l3_next.input_next_mpls = em->redirect_l3_next;
2146
2147 /*
2148 * Even if we never use these arcs, we have to align the next indices...
2149 */
2150 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
2151
2152 ASSERT (i == em->redirect_l3_next);
jerryianff82ed62016-12-05 17:13:00 +08002153
2154 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
2155
2156 ASSERT (i == em->redirect_l3_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002157}
Damjan Marion5beecec2018-09-10 13:09:21 +02002158#endif
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002159
2160/*
2161 * fd.io coding-style-patch-verification: ON
2162 *
2163 * Local Variables:
2164 * eval: (c-set-style "gnu")
2165 * End:
2166 */