blob: 9c9143dd4baf525dc517ff2b3dc419b4398707f8 [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 G Smithd459bf32019-09-04 15:01:04 -0500611#define DMAC_MASK clib_net_to_host_u64 (0xFFFFFFFFFFFF0000)
612#define DMAC_IGBIT clib_net_to_host_u64 (0x0100000000000000)
613
614#ifdef CLIB_HAVE_VEC256
615static_always_inline u32
616is_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
617{
618 u64x4 r0 = u64x4_load_unaligned (dmacs) & u64x4_splat (DMAC_MASK);
619 r0 = (r0 != u64x4_splat (hwaddr)) & ((r0 & u64x4_splat (DMAC_IGBIT)) == 0);
620 return u8x32_msb_mask ((u8x32) (r0));
621}
622#else
623static_always_inline u8
624is_dmac_bad (u64 dmac, u64 hwaddr)
625{
626 u64 r0 = dmac & DMAC_MASK;
627 return (r0 != hwaddr) && ((r0 & DMAC_IGBIT) == 0);
628}
629#endif
630
631static_always_inline u8
632is_sec_dmac_bad (u64 dmac, u64 hwaddr)
633{
634 return ((dmac & DMAC_MASK) != hwaddr);
635}
636
637#ifdef CLIB_HAVE_VEC256
638static_always_inline u32
639is_sec_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
640{
641 u64x4 r0 = u64x4_load_unaligned (dmacs) & u64x4_splat (DMAC_MASK);
642 r0 = (r0 != u64x4_splat (hwaddr));
643 return u8x32_msb_mask ((u8x32) (r0));
644}
645#endif
646
647static_always_inline u8
648eth_input_sec_dmac_check_x1 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
649{
650 dmac_bad[0] &= is_sec_dmac_bad (dmac[0], hwaddr);
651 return dmac_bad[0];
652}
653
654static_always_inline u32
655eth_input_sec_dmac_check_x4 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
656{
657#ifdef CLIB_HAVE_VEC256
658 *(u32 *) (dmac_bad + 0) &= is_sec_dmac_bad_x4 (dmac + 0, hwaddr);
659#else
660 dmac_bad[0] &= is_sec_dmac_bad (dmac[0], hwaddr);
661 dmac_bad[1] &= is_sec_dmac_bad (dmac[1], hwaddr);
662 dmac_bad[2] &= is_sec_dmac_bad (dmac[2], hwaddr);
663 dmac_bad[3] &= is_sec_dmac_bad (dmac[3], hwaddr);
664#endif
665 return *(u32 *) dmac_bad;
666}
667
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500668static_always_inline void
669eth_input_process_frame_dmac_check (vnet_hw_interface_t * hi,
670 u64 * dmacs, u8 * dmacs_bad,
Matthew G Smithd459bf32019-09-04 15:01:04 -0500671 u32 n_packets, ethernet_interface_t * ei,
672 u8 have_sec_dmac)
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500673{
Matthew G Smithd459bf32019-09-04 15:01:04 -0500674 u64 hwaddr = (*(u64 *) hi->hw_address) & DMAC_MASK;
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500675 u64 *dmac = dmacs;
676 u8 *dmac_bad = dmacs_bad;
Matthew G Smithd459bf32019-09-04 15:01:04 -0500677 u32 bad = 0;
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500678 i32 n_left = n_packets;
679
680#ifdef CLIB_HAVE_VEC256
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500681 while (n_left > 0)
682 {
Matthew G Smithd459bf32019-09-04 15:01:04 -0500683 bad |= *(u32 *) (dmac_bad + 0) = is_dmac_bad_x4 (dmac + 0, hwaddr);
684 bad |= *(u32 *) (dmac_bad + 4) = is_dmac_bad_x4 (dmac + 4, hwaddr);
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500685
686 /* next */
687 dmac += 8;
688 dmac_bad += 8;
689 n_left -= 8;
690 }
691#else
692 while (n_left > 0)
693 {
Matthew G Smithd459bf32019-09-04 15:01:04 -0500694 bad |= dmac_bad[0] = is_dmac_bad (dmac[0], hwaddr);
695 bad |= dmac_bad[1] = is_dmac_bad (dmac[1], hwaddr);
696 bad |= dmac_bad[2] = is_dmac_bad (dmac[2], hwaddr);
697 bad |= dmac_bad[3] = is_dmac_bad (dmac[3], hwaddr);
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500698
699 /* next */
700 dmac += 4;
701 dmac_bad += 4;
702 n_left -= 4;
703 }
704#endif
Matthew G Smithd459bf32019-09-04 15:01:04 -0500705
706 if (have_sec_dmac && bad)
707 {
708 mac_address_t *addr;
709
710 vec_foreach (addr, ei->secondary_addrs)
711 {
712 u64 hwaddr = ((u64 *) addr)[0] & DMAC_MASK;
713 i32 n_left = n_packets;
714 u64 *dmac = dmacs;
715 u8 *dmac_bad = dmacs_bad;
716
717 bad = 0;
718
719 while (n_left > 0)
720 {
721 int adv = 0;
722 int n_bad;
723
724 /* skip any that have already matched */
725 if (!dmac_bad[0])
726 {
727 dmac += 1;
728 dmac_bad += 1;
729 n_left -= 1;
730 continue;
731 }
732
733 n_bad = clib_min (4, n_left);
734
735 /* If >= 4 left, compare 4 together */
736 if (n_bad == 4)
737 {
738 bad |= eth_input_sec_dmac_check_x4 (hwaddr, dmac, dmac_bad);
739 adv = 4;
740 n_bad = 0;
741 }
742
743 /* handle individually */
744 while (n_bad > 0)
745 {
746 bad |= eth_input_sec_dmac_check_x1 (hwaddr, dmac + adv,
747 dmac_bad + adv);
748 adv += 1;
749 n_bad -= 1;
750 }
751
752 dmac += adv;
753 dmac_bad += adv;
754 n_left -= adv;
755 }
756
757 if (!bad) /* can stop looping if everything matched */
758 break;
759 }
760 }
Matthew Smithfa20d4c2019-07-12 11:48:24 -0500761}
762
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100763/* process frame of buffers, store ethertype into array and update
764 buffer metadata fields depending on interface being l2 or l3 assuming that
765 packets are untagged. For tagged packets those fields are updated later.
766 Optionally store Destionation MAC address and tag data into arrays
767 for further processing */
768
769STATIC_ASSERT (VLIB_FRAME_SIZE % 8 == 0,
770 "VLIB_FRAME_SIZE must be power of 8");
771static_always_inline void
772eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
773 vnet_hw_interface_t * hi,
774 u32 * buffer_indices, u32 n_packets, int main_is_l3,
775 int ip4_cksum_ok, int dmac_check)
776{
777 ethernet_main_t *em = &ethernet_main;
778 u16 nexts[VLIB_FRAME_SIZE], *next;
779 u16 etypes[VLIB_FRAME_SIZE], *etype = etypes;
780 u64 dmacs[VLIB_FRAME_SIZE], *dmac = dmacs;
781 u8 dmacs_bad[VLIB_FRAME_SIZE];
782 u64 tags[VLIB_FRAME_SIZE], *tag = tags;
783 u16 slowpath_indices[VLIB_FRAME_SIZE];
784 u16 n_slowpath, i;
785 u16 next_ip4, next_ip6, next_mpls, next_l2;
786 u16 et_ip4 = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
787 u16 et_ip6 = clib_host_to_net_u16 (ETHERNET_TYPE_IP6);
788 u16 et_mpls = clib_host_to_net_u16 (ETHERNET_TYPE_MPLS);
789 u16 et_vlan = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
790 u16 et_dot1ad = clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD);
791 i32 n_left = n_packets;
792 vlib_buffer_t *b[20];
793 u32 *from;
Matthew G Smithd459bf32019-09-04 15:01:04 -0500794 ethernet_interface_t *ei = ethernet_get_interface (em, hi->hw_if_index);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100795
796 from = buffer_indices;
797
798 while (n_left >= 20)
799 {
800 vlib_buffer_t **ph = b + 16, **pd = b + 8;
Damjan Marion650223c2018-11-14 16:55:53 +0100801 vlib_get_buffers (vm, from, b, 4);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100802 vlib_get_buffers (vm, from + 8, pd, 4);
803 vlib_get_buffers (vm, from + 16, ph, 4);
Damjan Marion650223c2018-11-14 16:55:53 +0100804
805 vlib_prefetch_buffer_header (ph[0], LOAD);
806 vlib_prefetch_buffer_data (pd[0], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100807 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100808
809 vlib_prefetch_buffer_header (ph[1], LOAD);
810 vlib_prefetch_buffer_data (pd[1], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100811 eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100812
813 vlib_prefetch_buffer_header (ph[2], LOAD);
814 vlib_prefetch_buffer_data (pd[2], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100815 eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100816
817 vlib_prefetch_buffer_header (ph[3], LOAD);
818 vlib_prefetch_buffer_data (pd[3], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100819 eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100820
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100821 eth_input_adv_and_flags_x4 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100822
823 /* next */
824 n_left -= 4;
825 etype += 4;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100826 tag += 4;
827 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100828 from += 4;
829 }
830 while (n_left >= 4)
831 {
832 vlib_get_buffers (vm, from, b, 4);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100833 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
834 eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
835 eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
836 eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
837 eth_input_adv_and_flags_x4 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100838
839 /* next */
840 n_left -= 4;
841 etype += 4;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100842 tag += 4;
843 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100844 from += 4;
845 }
846 while (n_left)
847 {
848 vlib_get_buffers (vm, from, b, 1);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100849 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
850 eth_input_adv_and_flags_x1 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100851
852 /* next */
853 n_left -= 1;
854 etype += 1;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100855 tag += 1;
856 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100857 from += 1;
858 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100859
860 if (dmac_check)
Matthew G Smithd459bf32019-09-04 15:01:04 -0500861 {
Matthew Smith49389382019-10-02 16:34:27 -0500862 if (ei && vec_len (ei->secondary_addrs))
Matthew G Smithd459bf32019-09-04 15:01:04 -0500863 eth_input_process_frame_dmac_check (hi, dmacs, dmacs_bad, n_packets,
864 ei, 1 /* have_sec_dmac */ );
865 else
866 eth_input_process_frame_dmac_check (hi, dmacs, dmacs_bad, n_packets,
867 ei, 0 /* have_sec_dmac */ );
868 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100869
870 next_ip4 = em->l3_next.input_next_ip4;
871 next_ip6 = em->l3_next.input_next_ip6;
872 next_mpls = em->l3_next.input_next_mpls;
873 next_l2 = em->l2_next;
874
875 if (next_ip4 == ETHERNET_INPUT_NEXT_IP4_INPUT && ip4_cksum_ok)
876 next_ip4 = ETHERNET_INPUT_NEXT_IP4_INPUT_NCS;
877
878#ifdef CLIB_HAVE_VEC256
879 u16x16 et16_ip4 = u16x16_splat (et_ip4);
880 u16x16 et16_ip6 = u16x16_splat (et_ip6);
881 u16x16 et16_mpls = u16x16_splat (et_mpls);
882 u16x16 et16_vlan = u16x16_splat (et_vlan);
883 u16x16 et16_dot1ad = u16x16_splat (et_dot1ad);
884 u16x16 next16_ip4 = u16x16_splat (next_ip4);
885 u16x16 next16_ip6 = u16x16_splat (next_ip6);
886 u16x16 next16_mpls = u16x16_splat (next_mpls);
887 u16x16 next16_l2 = u16x16_splat (next_l2);
888 u16x16 zero = { 0 };
889 u16x16 stairs = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
890#endif
891
892 etype = etypes;
893 n_left = n_packets;
894 next = nexts;
895 n_slowpath = 0;
896 i = 0;
897
898 /* fastpath - in l3 mode hadles ip4, ip6 and mpls packets, other packets
899 are considered as slowpath, in l2 mode all untagged packets are
900 considered as fastpath */
901 while (n_left > 0)
902 {
903#ifdef CLIB_HAVE_VEC256
904 if (n_left >= 16)
905 {
906 u16x16 r = zero;
907 u16x16 e16 = u16x16_load_unaligned (etype);
908 if (main_is_l3)
909 {
910 r += (e16 == et16_ip4) & next16_ip4;
911 r += (e16 == et16_ip6) & next16_ip6;
912 r += (e16 == et16_mpls) & next16_mpls;
913 }
914 else
915 r = ((e16 != et16_vlan) & (e16 != et16_dot1ad)) & next16_l2;
916 u16x16_store_unaligned (r, next);
917
918 if (!u16x16_is_all_zero (r == zero))
919 {
920 if (u16x16_is_all_zero (r))
921 {
922 u16x16_store_unaligned (u16x16_splat (i) + stairs,
923 slowpath_indices + n_slowpath);
924 n_slowpath += 16;
925 }
926 else
927 {
928 for (int j = 0; j < 16; j++)
929 if (next[j] == 0)
930 slowpath_indices[n_slowpath++] = i + j;
931 }
932 }
933
934 etype += 16;
935 next += 16;
936 n_left -= 16;
937 i += 16;
938 continue;
939 }
940#endif
941 if (main_is_l3 && etype[0] == et_ip4)
942 next[0] = next_ip4;
943 else if (main_is_l3 && etype[0] == et_ip6)
944 next[0] = next_ip6;
945 else if (main_is_l3 && etype[0] == et_mpls)
946 next[0] = next_mpls;
947 else if (main_is_l3 == 0 &&
948 etype[0] != et_vlan && etype[0] != et_dot1ad)
949 next[0] = next_l2;
950 else
951 {
952 next[0] = 0;
953 slowpath_indices[n_slowpath++] = i;
954 }
955
956 etype += 1;
957 next += 1;
958 n_left -= 1;
959 i += 1;
960 }
961
962 if (n_slowpath)
963 {
964 vnet_main_t *vnm = vnet_get_main ();
965 n_left = n_slowpath;
966 u16 *si = slowpath_indices;
967 u32 last_unknown_etype = ~0;
968 u32 last_unknown_next = ~0;
969 eth_input_tag_lookup_t dot1ad_lookup, dot1q_lookup = {
970 .mask = -1LL,
971 .tag = tags[si[0]] ^ -1LL,
972 .sw_if_index = ~0
973 };
974
975 clib_memcpy_fast (&dot1ad_lookup, &dot1q_lookup, sizeof (dot1q_lookup));
976
977 while (n_left)
978 {
979 i = si[0];
980 u16 etype = etypes[i];
981
982 if (etype == et_vlan)
983 {
984 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
985 eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
986 &dot1q_lookup, dmacs_bad[i], 0,
987 main_is_l3, dmac_check);
988
989 }
990 else if (etype == et_dot1ad)
991 {
992 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
993 eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
994 &dot1ad_lookup, dmacs_bad[i], 1,
995 main_is_l3, dmac_check);
996 }
997 else
998 {
999 /* untagged packet with not well known etyertype */
1000 if (last_unknown_etype != etype)
1001 {
1002 last_unknown_etype = etype;
1003 etype = clib_host_to_net_u16 (etype);
1004 last_unknown_next = eth_input_next_by_type (etype);
1005 }
1006 if (dmac_check && main_is_l3 && dmacs_bad[i])
1007 {
1008 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
1009 b->error = node->errors[ETHERNET_ERROR_L3_MAC_MISMATCH];
1010 nexts[i] = ETHERNET_INPUT_NEXT_PUNT;
1011 }
1012 else
1013 nexts[i] = last_unknown_next;
1014 }
1015
1016 /* next */
1017 n_left--;
1018 si++;
1019 }
1020
1021 eth_input_update_if_counters (vm, vnm, &dot1q_lookup);
1022 eth_input_update_if_counters (vm, vnm, &dot1ad_lookup);
1023 }
1024
1025 vlib_buffer_enqueue_to_next (vm, node, buffer_indices, nexts, n_packets);
Damjan Marion650223c2018-11-14 16:55:53 +01001026}
1027
1028static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001029eth_input_single_int (vlib_main_t * vm, vlib_node_runtime_t * node,
1030 vnet_hw_interface_t * hi, u32 * from, u32 n_pkts,
1031 int ip4_cksum_ok)
Damjan Marion650223c2018-11-14 16:55:53 +01001032{
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001033 ethernet_main_t *em = &ethernet_main;
1034 ethernet_interface_t *ei;
1035 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
1036 main_intf_t *intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
1037 subint_config_t *subint0 = &intf0->untagged_subint;
Damjan Marion650223c2018-11-14 16:55:53 +01001038
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001039 int main_is_l3 = (subint0->flags & SUBINT_CONFIG_L2) == 0;
1040 int promisc = (ei->flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL) != 0;
Damjan Marion650223c2018-11-14 16:55:53 +01001041
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001042 if (main_is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +01001043 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001044 /* main interface is L3, we dont expect tagged packets and interface
1045 is not in promisc node, so we dont't need to check DMAC */
1046 int is_l3 = 1;
Damjan Marion650223c2018-11-14 16:55:53 +01001047
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001048 if (promisc == 0)
1049 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
1050 ip4_cksum_ok, 0);
Damjan Marion650223c2018-11-14 16:55:53 +01001051 else
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001052 /* subinterfaces and promisc mode so DMAC check is needed */
1053 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
1054 ip4_cksum_ok, 1);
1055 return;
Damjan Marion650223c2018-11-14 16:55:53 +01001056 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001057 else
Damjan Marion650223c2018-11-14 16:55:53 +01001058 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001059 /* untagged packets are treated as L2 */
1060 int is_l3 = 0;
1061 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
1062 ip4_cksum_ok, 1);
1063 return;
Damjan Marion650223c2018-11-14 16:55:53 +01001064 }
1065}
1066
1067static_always_inline void
1068ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
1069 vlib_frame_t * from_frame)
1070{
1071 u32 *from, n_left;
Benoît Ganne98477922019-04-10 14:21:11 +02001072 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
Damjan Marion650223c2018-11-14 16:55:53 +01001073 {
Dave Barach5ecd5a52019-02-25 15:27:28 -05001074 from = vlib_frame_vector_args (from_frame);
1075 n_left = from_frame->n_vectors;
Damjan Marion650223c2018-11-14 16:55:53 +01001076
Dave Barach5ecd5a52019-02-25 15:27:28 -05001077 while (n_left)
Damjan Marion650223c2018-11-14 16:55:53 +01001078 {
Dave Barach5ecd5a52019-02-25 15:27:28 -05001079 ethernet_input_trace_t *t0;
1080 vlib_buffer_t *b0 = vlib_get_buffer (vm, from[0]);
1081
1082 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1083 {
1084 t0 = vlib_add_trace (vm, node, b0,
1085 sizeof (ethernet_input_trace_t));
1086 clib_memcpy_fast (t0->packet_data, b0->data + b0->current_data,
1087 sizeof (t0->packet_data));
1088 t0->frame_flags = from_frame->flags;
1089 clib_memcpy_fast (&t0->frame_data,
1090 vlib_frame_scalar_args (from_frame),
1091 sizeof (ethernet_input_frame_t));
1092 }
1093 from += 1;
1094 n_left -= 1;
Damjan Marion650223c2018-11-14 16:55:53 +01001095 }
Dave Barach5ecd5a52019-02-25 15:27:28 -05001096 }
1097
1098 /* rx pcap capture if enabled */
Dave Barach33909772019-09-23 10:27:27 -04001099 if (PREDICT_FALSE (vlib_global_main.pcap.pcap_rx_enable))
Dave Barach5ecd5a52019-02-25 15:27:28 -05001100 {
1101 u32 bi0;
Dave Barach33909772019-09-23 10:27:27 -04001102 vnet_pcap_t *pp = &vlib_global_main.pcap;
Dave Barach5ecd5a52019-02-25 15:27:28 -05001103
1104 from = vlib_frame_vector_args (from_frame);
1105 n_left = from_frame->n_vectors;
1106 while (n_left > 0)
1107 {
Dave Barach9137e542019-09-13 17:47:50 -04001108 int classify_filter_result;
Dave Barach5ecd5a52019-02-25 15:27:28 -05001109 vlib_buffer_t *b0;
1110 bi0 = from[0];
1111 from++;
Dave Barach9137e542019-09-13 17:47:50 -04001112 n_left--;
Dave Barach5ecd5a52019-02-25 15:27:28 -05001113 b0 = vlib_get_buffer (vm, bi0);
Dave Barachf5667c32019-09-25 11:27:46 -04001114 if (pp->filter_classify_table_index != ~0)
Dave Barach9137e542019-09-13 17:47:50 -04001115 {
1116 classify_filter_result =
1117 vnet_is_packet_traced_inline
Dave Barachf5667c32019-09-25 11:27:46 -04001118 (b0, pp->filter_classify_table_index, 0 /* full classify */ );
Dave Barach9137e542019-09-13 17:47:50 -04001119 if (classify_filter_result)
Dave Barach33909772019-09-23 10:27:27 -04001120 pcap_add_buffer (&pp->pcap_main, vm, bi0,
1121 pp->max_bytes_per_pkt);
Dave Barach9137e542019-09-13 17:47:50 -04001122 continue;
1123 }
Dave Barach5ecd5a52019-02-25 15:27:28 -05001124
Dave Barach33909772019-09-23 10:27:27 -04001125 if (pp->pcap_sw_if_index == 0 ||
1126 pp->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
Dave Barach5ecd5a52019-02-25 15:27:28 -05001127 {
Dave Barach33909772019-09-23 10:27:27 -04001128 pcap_add_buffer (&pp->pcap_main, vm, bi0,
1129 pp->max_bytes_per_pkt);
Dave Barach5ecd5a52019-02-25 15:27:28 -05001130 }
Dave Barach5ecd5a52019-02-25 15:27:28 -05001131 }
Damjan Marion650223c2018-11-14 16:55:53 +01001132 }
1133}
1134
1135static_always_inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136ethernet_input_inline (vlib_main_t * vm,
1137 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +01001138 u32 * from, u32 n_packets,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139 ethernet_input_variant_t variant)
1140{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001141 vnet_main_t *vnm = vnet_get_main ();
1142 ethernet_main_t *em = &ethernet_main;
1143 vlib_node_runtime_t *error_node;
Damjan Marion650223c2018-11-14 16:55:53 +01001144 u32 n_left_from, next_index, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
Damjan Marion067cd622018-07-11 12:47:43 +02001146 u32 thread_index = vm->thread_index;
Dave Barachcfba1e22016-11-16 10:23:50 -05001147 u32 cached_sw_if_index = ~0;
1148 u32 cached_is_l2 = 0; /* shut up gcc */
John Lo1904c472017-03-10 17:15:22 -05001149 vnet_hw_interface_t *hi = NULL; /* used for main interface only */
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001150 vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
1151 vlib_buffer_t **b = bufs;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152
1153 if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
1154 error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
1155 else
1156 error_node = node;
1157
Damjan Marion650223c2018-11-14 16:55:53 +01001158 n_left_from = n_packets;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001159
1160 next_index = node->cached_next_index;
1161 stats_sw_if_index = node->runtime_data[0];
1162 stats_n_packets = stats_n_bytes = 0;
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001163 vlib_get_buffers (vm, from, bufs, n_left_from);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164
1165 while (n_left_from > 0)
1166 {
1167 u32 n_left_to_next;
1168
1169 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1170
1171 while (n_left_from >= 4 && n_left_to_next >= 2)
1172 {
1173 u32 bi0, bi1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001174 vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175 u8 next0, next1, error0, error1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001176 u16 type0, orig_type0, type1, orig_type1;
1177 u16 outer_id0, inner_id0, outer_id1, inner_id1;
1178 u32 match_flags0, match_flags1;
1179 u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1,
1180 new_sw_if_index1, len1;
1181 vnet_hw_interface_t *hi0, *hi1;
1182 main_intf_t *main_intf0, *main_intf1;
1183 vlan_intf_t *vlan_intf0, *vlan_intf1;
1184 qinq_intf_t *qinq_intf0, *qinq_intf1;
1185 u32 is_l20, is_l21;
Dave Barachcfba1e22016-11-16 10:23:50 -05001186 ethernet_header_t *e0, *e1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187
1188 /* Prefetch next iteration. */
1189 {
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001190 vlib_prefetch_buffer_header (b[2], STORE);
1191 vlib_prefetch_buffer_header (b[3], STORE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001193 CLIB_PREFETCH (b[2]->data, sizeof (ethernet_header_t), LOAD);
1194 CLIB_PREFETCH (b[3]->data, sizeof (ethernet_header_t), LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195 }
1196
1197 bi0 = from[0];
1198 bi1 = from[1];
1199 to_next[0] = bi0;
1200 to_next[1] = bi1;
1201 from += 2;
1202 to_next += 2;
1203 n_left_to_next -= 2;
1204 n_left_from -= 2;
1205
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001206 b0 = b[0];
1207 b1 = b[1];
1208 b += 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209
1210 error0 = error1 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001211 e0 = vlib_buffer_get_current (b0);
1212 type0 = clib_net_to_host_u16 (e0->type);
1213 e1 = vlib_buffer_get_current (b1);
1214 type1 = clib_net_to_host_u16 (e1->type);
1215
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001216 /* Set the L2 header offset for all packets */
1217 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1218 vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
1219 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1220 b1->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1221
John Locc532852016-12-14 15:42:45 -05001222 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001223 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
Damjan Marionc6969b52018-02-19 12:14:06 +01001224 && !ethernet_frame_is_any_tagged_x2 (type0,
1225 type1)))
Dave Barachcfba1e22016-11-16 10:23:50 -05001226 {
1227 main_intf_t *intf0;
1228 subint_config_t *subint0;
1229 u32 sw_if_index0, sw_if_index1;
1230
1231 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1232 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1233 is_l20 = cached_is_l2;
1234
1235 /* This is probably wholly unnecessary */
1236 if (PREDICT_FALSE (sw_if_index0 != sw_if_index1))
1237 goto slowpath;
1238
John Lo1904c472017-03-10 17:15:22 -05001239 /* Now sw_if_index0 == sw_if_index1 */
Dave Barachcfba1e22016-11-16 10:23:50 -05001240 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1241 {
1242 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001243 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1244 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001245 subint0 = &intf0->untagged_subint;
1246 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1247 }
John Lo7714b302016-12-20 16:59:02 -05001248
Dave Barachcfba1e22016-11-16 10:23:50 -05001249 if (PREDICT_TRUE (is_l20 != 0))
1250 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001251 vnet_buffer (b0)->l3_hdr_offset =
1252 vnet_buffer (b0)->l2_hdr_offset +
1253 sizeof (ethernet_header_t);
1254 vnet_buffer (b1)->l3_hdr_offset =
1255 vnet_buffer (b1)->l2_hdr_offset +
1256 sizeof (ethernet_header_t);
1257 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
1258 b1->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001259 next0 = em->l2_next;
1260 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001261 next1 = em->l2_next;
1262 vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001263 }
John Locc532852016-12-14 15:42:45 -05001264 else
1265 {
John Lo1904c472017-03-10 17:15:22 -05001266 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001267 (hi->hw_address != 0) &&
Neale Ranns37029302018-08-10 05:30:06 -07001268 !ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
John Lo1904c472017-03-10 17:15:22 -05001269 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
1270 if (!ethernet_address_cast (e1->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001271 (hi->hw_address != 0) &&
Neale Ranns37029302018-08-10 05:30:06 -07001272 !ethernet_mac_address_equal ((u8 *) e1, hi->hw_address))
John Lo1904c472017-03-10 17:15:22 -05001273 error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
John Lob14826e2018-04-18 15:52:23 -04001274 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001275 determine_next_node (em, variant, 0, type0, b0,
1276 &error0, &next0);
John Lob14826e2018-04-18 15:52:23 -04001277 vlib_buffer_advance (b1, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001278 determine_next_node (em, variant, 0, type1, b1,
1279 &error1, &next1);
John Locc532852016-12-14 15:42:45 -05001280 }
1281 goto ship_it01;
Dave Barachcfba1e22016-11-16 10:23:50 -05001282 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283
John Locc532852016-12-14 15:42:45 -05001284 /* Slow-path for the tagged case */
1285 slowpath:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001286 parse_header (variant,
1287 b0,
1288 &type0,
1289 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001291 parse_header (variant,
1292 b1,
1293 &type1,
1294 &orig_type1, &outer_id1, &inner_id1, &match_flags1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001296 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1297 old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001299 eth_vlan_table_lookups (em,
1300 vnm,
1301 old_sw_if_index0,
1302 orig_type0,
1303 outer_id0,
1304 inner_id0,
1305 &hi0,
1306 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001308 eth_vlan_table_lookups (em,
1309 vnm,
1310 old_sw_if_index1,
1311 orig_type1,
1312 outer_id1,
1313 inner_id1,
1314 &hi1,
1315 &main_intf1, &vlan_intf1, &qinq_intf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316
1317 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001318 b0,
1319 match_flags0,
1320 main_intf0,
1321 vlan_intf0,
1322 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323
1324 identify_subint (hi1,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001325 b1,
1326 match_flags1,
1327 main_intf1,
1328 vlan_intf1,
1329 qinq_intf1, &new_sw_if_index1, &error1, &is_l21);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001330
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001331 // Save RX sw_if_index for later nodes
1332 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1333 error0 !=
1334 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
1335 vnet_buffer (b1)->sw_if_index[VLIB_RX] =
1336 error1 !=
1337 ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001339 // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
1340 if (((new_sw_if_index0 != ~0)
1341 && (new_sw_if_index0 != old_sw_if_index0))
1342 || ((new_sw_if_index1 != ~0)
1343 && (new_sw_if_index1 != old_sw_if_index1)))
1344 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001345
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001346 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001347 - vnet_buffer (b0)->l2_hdr_offset;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001348 len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001349 - vnet_buffer (b1)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001350
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001351 stats_n_packets += 2;
1352 stats_n_bytes += len0 + len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001354 if (PREDICT_FALSE
1355 (!(new_sw_if_index0 == stats_sw_if_index
1356 && new_sw_if_index1 == stats_sw_if_index)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357 {
1358 stats_n_packets -= 2;
1359 stats_n_bytes -= len0 + len1;
1360
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001361 if (new_sw_if_index0 != old_sw_if_index0
1362 && new_sw_if_index0 != ~0)
1363 vlib_increment_combined_counter (vnm->
1364 interface_main.combined_sw_if_counters
1365 +
1366 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001367 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001368 new_sw_if_index0, 1,
1369 len0);
1370 if (new_sw_if_index1 != old_sw_if_index1
1371 && new_sw_if_index1 != ~0)
1372 vlib_increment_combined_counter (vnm->
1373 interface_main.combined_sw_if_counters
1374 +
1375 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001376 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001377 new_sw_if_index1, 1,
1378 len1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001379
1380 if (new_sw_if_index0 == new_sw_if_index1)
1381 {
1382 if (stats_n_packets > 0)
1383 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001384 vlib_increment_combined_counter
1385 (vnm->interface_main.combined_sw_if_counters
1386 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001387 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001388 stats_sw_if_index,
1389 stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001390 stats_n_packets = stats_n_bytes = 0;
1391 }
1392 stats_sw_if_index = new_sw_if_index0;
1393 }
1394 }
1395 }
1396
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001397 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1398 is_l20 = is_l21 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001400 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1401 &next0);
1402 determine_next_node (em, variant, is_l21, type1, b1, &error1,
1403 &next1);
1404
John Lo1904c472017-03-10 17:15:22 -05001405 ship_it01:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001406 b0->error = error_node->errors[error0];
1407 b1->error = error_node->errors[error1];
1408
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001409 // verify speculative enqueue
1410 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1411 n_left_to_next, bi0, bi1, next0,
1412 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413 }
1414
1415 while (n_left_from > 0 && n_left_to_next > 0)
1416 {
1417 u32 bi0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001418 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419 u8 error0, next0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001420 u16 type0, orig_type0;
1421 u16 outer_id0, inner_id0;
1422 u32 match_flags0;
1423 u32 old_sw_if_index0, new_sw_if_index0, len0;
1424 vnet_hw_interface_t *hi0;
1425 main_intf_t *main_intf0;
1426 vlan_intf_t *vlan_intf0;
1427 qinq_intf_t *qinq_intf0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001428 ethernet_header_t *e0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001429 u32 is_l20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001431 // Prefetch next iteration
1432 if (n_left_from > 1)
1433 {
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001434 vlib_prefetch_buffer_header (b[1], STORE);
1435 CLIB_PREFETCH (b[1]->data, CLIB_CACHE_LINE_BYTES, LOAD);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001436 }
1437
1438 bi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001439 to_next[0] = bi0;
1440 from += 1;
1441 to_next += 1;
1442 n_left_from -= 1;
1443 n_left_to_next -= 1;
1444
Zhiyong Yangb3ca33f2019-04-24 04:13:27 -04001445 b0 = b[0];
1446 b += 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001447
1448 error0 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001449 e0 = vlib_buffer_get_current (b0);
1450 type0 = clib_net_to_host_u16 (e0->type);
1451
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001452 /* Set the L2 header offset for all packets */
1453 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1454 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1455
John Locc532852016-12-14 15:42:45 -05001456 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001457 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
1458 && !ethernet_frame_is_tagged (type0)))
1459 {
1460 main_intf_t *intf0;
1461 subint_config_t *subint0;
1462 u32 sw_if_index0;
1463
1464 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1465 is_l20 = cached_is_l2;
1466
1467 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1468 {
1469 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001470 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1471 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001472 subint0 = &intf0->untagged_subint;
1473 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1474 }
John Lo7714b302016-12-20 16:59:02 -05001475
John Lo7714b302016-12-20 16:59:02 -05001476
Dave Barachcfba1e22016-11-16 10:23:50 -05001477 if (PREDICT_TRUE (is_l20 != 0))
1478 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001479 vnet_buffer (b0)->l3_hdr_offset =
1480 vnet_buffer (b0)->l2_hdr_offset +
1481 sizeof (ethernet_header_t);
1482 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001483 next0 = em->l2_next;
1484 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001485 }
John Locc532852016-12-14 15:42:45 -05001486 else
1487 {
John Lo1904c472017-03-10 17:15:22 -05001488 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001489 (hi->hw_address != 0) &&
Neale Ranns37029302018-08-10 05:30:06 -07001490 !ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
John Lo1904c472017-03-10 17:15:22 -05001491 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
Andrew Yourtchenkoe78bca12018-10-10 16:15:55 +02001492 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001493 determine_next_node (em, variant, 0, type0, b0,
1494 &error0, &next0);
John Locc532852016-12-14 15:42:45 -05001495 }
1496 goto ship_it0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001497 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001498
John Locc532852016-12-14 15:42:45 -05001499 /* Slow-path for the tagged case */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001500 parse_header (variant,
1501 b0,
1502 &type0,
1503 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001504
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001505 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001507 eth_vlan_table_lookups (em,
1508 vnm,
1509 old_sw_if_index0,
1510 orig_type0,
1511 outer_id0,
1512 inner_id0,
1513 &hi0,
1514 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001515
1516 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001517 b0,
1518 match_flags0,
1519 main_intf0,
1520 vlan_intf0,
1521 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001522
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001523 // Save RX sw_if_index for later nodes
1524 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1525 error0 !=
1526 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001528 // Increment subinterface stats
1529 // Note that interface-level counters have already been incremented
1530 // prior to calling this function. Thus only subinterface counters
1531 // are incremented here.
1532 //
Damjan Marion607de1a2016-08-16 22:53:54 +02001533 // Interface level counters include packets received on the main
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001534 // interface and all subinterfaces. Subinterface level counters
1535 // include only those packets received on that subinterface
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536 // Increment stats if the subint is valid and it is not the main intf
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001537 if ((new_sw_if_index0 != ~0)
1538 && (new_sw_if_index0 != old_sw_if_index0))
1539 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001540
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001541 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001542 - vnet_buffer (b0)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001543
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001544 stats_n_packets += 1;
1545 stats_n_bytes += len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001546
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001547 // Batch stat increments from the same subinterface so counters
Damjan Marion607de1a2016-08-16 22:53:54 +02001548 // don't need to be incremented for every packet.
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001549 if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index))
1550 {
1551 stats_n_packets -= 1;
1552 stats_n_bytes -= len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001553
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001554 if (new_sw_if_index0 != ~0)
1555 vlib_increment_combined_counter
1556 (vnm->interface_main.combined_sw_if_counters
1557 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001558 thread_index, new_sw_if_index0, 1, len0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001559 if (stats_n_packets > 0)
1560 {
1561 vlib_increment_combined_counter
1562 (vnm->interface_main.combined_sw_if_counters
1563 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001564 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001565 stats_sw_if_index, stats_n_packets, stats_n_bytes);
1566 stats_n_packets = stats_n_bytes = 0;
1567 }
1568 stats_sw_if_index = new_sw_if_index0;
1569 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001570 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001571
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001572 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1573 is_l20 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001574
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001575 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1576 &next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001577
John Lo1904c472017-03-10 17:15:22 -05001578 ship_it0:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001579 b0->error = error_node->errors[error0];
1580
1581 // verify speculative enqueue
Ed Warnickecb9cada2015-12-08 15:45:58 -07001582 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1583 to_next, n_left_to_next,
1584 bi0, next0);
1585 }
1586
1587 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1588 }
1589
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001590 // Increment any remaining batched stats
1591 if (stats_n_packets > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001592 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001593 vlib_increment_combined_counter
1594 (vnm->interface_main.combined_sw_if_counters
1595 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001596 thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 node->runtime_data[0] = stats_sw_if_index;
1598 }
Damjan Marion650223c2018-11-14 16:55:53 +01001599}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600
Damjan Marion5beecec2018-09-10 13:09:21 +02001601VLIB_NODE_FN (ethernet_input_node) (vlib_main_t * vm,
1602 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +01001603 vlib_frame_t * frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001604{
Damjan Marion650223c2018-11-14 16:55:53 +01001605 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion650223c2018-11-14 16:55:53 +01001606 u32 *from = vlib_frame_vector_args (frame);
1607 u32 n_packets = frame->n_vectors;
1608
1609 ethernet_input_trace (vm, node, frame);
1610
1611 if (frame->flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
1612 {
Damjan Marion650223c2018-11-14 16:55:53 +01001613 ethernet_input_frame_t *ef = vlib_frame_scalar_args (frame);
Damjan Marion650223c2018-11-14 16:55:53 +01001614 int ip4_cksum_ok = (frame->flags & ETH_INPUT_FRAME_F_IP4_CKSUM_OK) != 0;
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001615 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ef->hw_if_index);
1616 eth_input_single_int (vm, node, hi, from, n_packets, ip4_cksum_ok);
Damjan Marion650223c2018-11-14 16:55:53 +01001617 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001618 else
1619 ethernet_input_inline (vm, node, from, n_packets,
1620 ETHERNET_INPUT_VARIANT_ETHERNET);
Damjan Marion650223c2018-11-14 16:55:53 +01001621 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001622}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001623
Damjan Marion5beecec2018-09-10 13:09:21 +02001624VLIB_NODE_FN (ethernet_input_type_node) (vlib_main_t * vm,
1625 vlib_node_runtime_t * node,
1626 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001627{
Damjan Marion650223c2018-11-14 16:55:53 +01001628 u32 *from = vlib_frame_vector_args (from_frame);
1629 u32 n_packets = from_frame->n_vectors;
1630 ethernet_input_trace (vm, node, from_frame);
1631 ethernet_input_inline (vm, node, from, n_packets,
1632 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE);
1633 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001634}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635
Damjan Marion5beecec2018-09-10 13:09:21 +02001636VLIB_NODE_FN (ethernet_input_not_l2_node) (vlib_main_t * vm,
1637 vlib_node_runtime_t * node,
1638 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001639{
Damjan Marion650223c2018-11-14 16:55:53 +01001640 u32 *from = vlib_frame_vector_args (from_frame);
1641 u32 n_packets = from_frame->n_vectors;
1642 ethernet_input_trace (vm, node, from_frame);
1643 ethernet_input_inline (vm, node, from, n_packets,
1644 ETHERNET_INPUT_VARIANT_NOT_L2);
1645 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001646}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001647
1648
1649// Return the subinterface config struct for the given sw_if_index
1650// Also return via parameter the appropriate match flags for the
1651// configured number of tags.
1652// On error (unsupported or not ethernet) return 0.
1653static subint_config_t *
1654ethernet_sw_interface_get_config (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001655 u32 sw_if_index,
1656 u32 * flags, u32 * unsupported)
1657{
1658 ethernet_main_t *em = &ethernet_main;
1659 vnet_hw_interface_t *hi;
1660 vnet_sw_interface_t *si;
1661 main_intf_t *main_intf;
1662 vlan_table_t *vlan_table;
1663 qinq_table_t *qinq_table;
1664 subint_config_t *subint = 0;
1665
Ed Warnickecb9cada2015-12-08 15:45:58 -07001666 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1667
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001668 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
1669 {
1670 *unsupported = 0;
1671 goto done; // non-ethernet interface
1672 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001673
1674 // ensure there's an entry for the main intf (shouldn't really be necessary)
1675 vec_validate (em->main_intfs, hi->hw_if_index);
1676 main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
1677
1678 // Locate the subint for the given ethernet config
1679 si = vnet_get_sw_interface (vnm, sw_if_index);
1680
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001681 if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
1682 {
1683 p2p_ethernet_main_t *p2pm = &p2p_main;
1684 u32 p2pe_sw_if_index =
1685 p2p_ethernet_lookup (hi->hw_if_index, si->p2p.client_mac);
1686 if (p2pe_sw_if_index == ~0)
1687 {
1688 pool_get (p2pm->p2p_subif_pool, subint);
1689 si->p2p.pool_index = subint - p2pm->p2p_subif_pool;
1690 }
1691 else
1692 subint = vec_elt_at_index (p2pm->p2p_subif_pool, si->p2p.pool_index);
1693 *flags = SUBINT_CONFIG_P2P;
1694 }
Neale Ranns17ff3c12018-07-04 10:24:24 -07001695 else if (si->type == VNET_SW_INTERFACE_TYPE_PIPE)
1696 {
1697 pipe_t *pipe;
1698
1699 pipe = pipe_get (sw_if_index);
1700 subint = &pipe->subint;
1701 *flags = SUBINT_CONFIG_P2P;
1702 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001703 else if (si->sub.eth.flags.default_sub)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001704 {
1705 subint = &main_intf->default_subint;
Mike Bly88076742018-09-24 10:13:06 -07001706 *flags = SUBINT_CONFIG_MATCH_1_TAG |
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001707 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1708 }
1709 else if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0))
1710 {
1711 // if no flags are set then this is a main interface
1712 // so treat as untagged
1713 subint = &main_intf->untagged_subint;
1714 *flags = SUBINT_CONFIG_MATCH_0_TAG;
1715 }
1716 else
1717 {
1718 // one or two tags
1719 // first get the vlan table
1720 if (si->sub.eth.flags.dot1ad)
1721 {
1722 if (main_intf->dot1ad_vlans == 0)
1723 {
1724 // Allocate a vlan table from the pool
1725 pool_get (em->vlan_pool, vlan_table);
1726 main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
1727 }
1728 else
1729 {
1730 // Get ptr to existing vlan table
1731 vlan_table =
1732 vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
1733 }
1734 }
1735 else
1736 { // dot1q
1737 if (main_intf->dot1q_vlans == 0)
1738 {
1739 // Allocate a vlan table from the pool
1740 pool_get (em->vlan_pool, vlan_table);
1741 main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
1742 }
1743 else
1744 {
1745 // Get ptr to existing vlan table
1746 vlan_table =
1747 vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
1748 }
1749 }
1750
1751 if (si->sub.eth.flags.one_tag)
1752 {
1753 *flags = si->sub.eth.flags.exact_match ?
1754 SUBINT_CONFIG_MATCH_1_TAG :
1755 (SUBINT_CONFIG_MATCH_1_TAG |
1756 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1757
1758 if (si->sub.eth.flags.outer_vlan_id_any)
1759 {
1760 // not implemented yet
1761 *unsupported = 1;
1762 goto done;
1763 }
1764 else
1765 {
1766 // a single vlan, a common case
1767 subint =
1768 &vlan_table->vlans[si->sub.eth.
1769 outer_vlan_id].single_tag_subint;
1770 }
1771
1772 }
1773 else
1774 {
1775 // Two tags
1776 *flags = si->sub.eth.flags.exact_match ?
1777 SUBINT_CONFIG_MATCH_2_TAG :
1778 (SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1779
1780 if (si->sub.eth.flags.outer_vlan_id_any
1781 && si->sub.eth.flags.inner_vlan_id_any)
1782 {
1783 // not implemented yet
1784 *unsupported = 1;
1785 goto done;
1786 }
1787
1788 if (si->sub.eth.flags.inner_vlan_id_any)
1789 {
1790 // a specific outer and "any" inner
1791 // don't need a qinq table for this
1792 subint =
1793 &vlan_table->vlans[si->sub.eth.
1794 outer_vlan_id].inner_any_subint;
1795 if (si->sub.eth.flags.exact_match)
1796 {
1797 *flags = SUBINT_CONFIG_MATCH_2_TAG;
1798 }
1799 else
1800 {
1801 *flags = SUBINT_CONFIG_MATCH_2_TAG |
1802 SUBINT_CONFIG_MATCH_3_TAG;
1803 }
1804 }
1805 else
1806 {
1807 // a specific outer + specifc innner vlan id, a common case
1808
1809 // get the qinq table
1810 if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0)
1811 {
1812 // Allocate a qinq table from the pool
1813 pool_get (em->qinq_pool, qinq_table);
1814 vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs =
1815 qinq_table - em->qinq_pool;
1816 }
1817 else
1818 {
1819 // Get ptr to existing qinq table
1820 qinq_table =
1821 vec_elt_at_index (em->qinq_pool,
1822 vlan_table->vlans[si->sub.
1823 eth.outer_vlan_id].
1824 qinqs);
1825 }
1826 subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
1827 }
1828 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829 }
1830
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001831done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001832 return subint;
1833}
1834
Damjan Marion5beecec2018-09-10 13:09:21 +02001835static clib_error_t *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001836ethernet_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001837{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001838 subint_config_t *subint;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001839 u32 dummy_flags;
1840 u32 dummy_unsup;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001841 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842
1843 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001844 subint =
1845 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1846 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001847
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001848 if (subint == 0)
1849 {
1850 // not implemented yet or not ethernet
1851 goto done;
1852 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001853
1854 subint->sw_if_index =
1855 ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
1856
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001857done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 return error;
1859}
1860
1861VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
1862
1863
Damjan Marion5beecec2018-09-10 13:09:21 +02001864#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865// Set the L2/L3 mode for the subinterface
1866void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001867ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868{
1869 subint_config_t *subint;
1870 u32 dummy_flags;
1871 u32 dummy_unsup;
1872 int is_port;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001873 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001874
1875 is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
1876
1877 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001878 subint =
1879 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1880 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001881
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001882 if (subint == 0)
1883 {
1884 // unimplemented or not ethernet
1885 goto done;
1886 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887
1888 // Double check that the config we found is for our interface (or the interface is down)
1889 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1890
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001891 if (l2)
1892 {
1893 subint->flags |= SUBINT_CONFIG_L2;
1894 if (is_port)
1895 subint->flags |=
1896 SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
1897 | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1898 }
1899 else
1900 {
1901 subint->flags &= ~SUBINT_CONFIG_L2;
1902 if (is_port)
1903 subint->flags &=
1904 ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
1905 | SUBINT_CONFIG_MATCH_3_TAG);
1906 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001908done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909 return;
1910}
1911
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001912/*
1913 * Set the L2/L3 mode for the subinterface regardless of port
1914 */
1915void
1916ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001917 u32 sw_if_index, u32 l2)
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001918{
1919 subint_config_t *subint;
1920 u32 dummy_flags;
1921 u32 dummy_unsup;
1922
1923 /* Find the config for this subinterface */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001924 subint =
1925 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1926 &dummy_unsup);
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001927
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001928 if (subint == 0)
1929 {
1930 /* unimplemented or not ethernet */
1931 goto done;
1932 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001933
1934 /*
1935 * Double check that the config we found is for our interface (or the
1936 * interface is down)
1937 */
1938 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1939
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001940 if (l2)
1941 {
1942 subint->flags |= SUBINT_CONFIG_L2;
1943 }
1944 else
1945 {
1946 subint->flags &= ~SUBINT_CONFIG_L2;
1947 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001948
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001949done:
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001950 return;
1951}
Damjan Marion5beecec2018-09-10 13:09:21 +02001952#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001953
1954static clib_error_t *
1955ethernet_sw_interface_add_del (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001956 u32 sw_if_index, u32 is_create)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001957{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001958 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001959 subint_config_t *subint;
1960 u32 match_flags;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001961 u32 unsupported = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962
1963 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001964 subint =
1965 ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags,
1966 &unsupported);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001967
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001968 if (subint == 0)
1969 {
1970 // not implemented yet or not ethernet
1971 if (unsupported)
1972 {
Damjan Marion607de1a2016-08-16 22:53:54 +02001973 // this is the NYI case
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001974 error = clib_error_return (0, "not implemented yet");
1975 }
1976 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001977 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001978
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001979 if (!is_create)
1980 {
1981 subint->flags = 0;
1982 return error;
1983 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001984
1985 // Initialize the subint
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001986 if (subint->flags & SUBINT_CONFIG_VALID)
1987 {
1988 // Error vlan already in use
1989 error = clib_error_return (0, "vlan is already in use");
1990 }
1991 else
1992 {
Neale Ranns17ff3c12018-07-04 10:24:24 -07001993 // Note that config is L3 by default
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001994 subint->flags = SUBINT_CONFIG_VALID | match_flags;
1995 subint->sw_if_index = ~0; // because interfaces are initially down
1996 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001997
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001998done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001999 return error;
2000}
2001
2002VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
2003
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002004static char *ethernet_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002005#define ethernet_error(n,c,s) s,
2006#include "error.def"
2007#undef ethernet_error
2008};
2009
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002010/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011VLIB_REGISTER_NODE (ethernet_input_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 .name = "ethernet-input",
2013 /* Takes a vector of packets. */
2014 .vector_size = sizeof (u32),
Damjan Marion650223c2018-11-14 16:55:53 +01002015 .scalar_size = sizeof (ethernet_input_frame_t),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016 .n_errors = ETHERNET_N_ERROR,
2017 .error_strings = ethernet_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
2019 .next_nodes = {
2020#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
2021 foreach_ethernet_input_next
2022#undef _
2023 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07002024 .format_buffer = format_ethernet_header_with_length,
2025 .format_trace = format_ethernet_input_trace,
2026 .unformat_buffer = unformat_ethernet_header,
2027};
2028
Damjan Marion5beecec2018-09-10 13:09:21 +02002029VLIB_REGISTER_NODE (ethernet_input_type_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002030 .name = "ethernet-input-type",
2031 /* Takes a vector of packets. */
2032 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002033 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
2034 .next_nodes = {
2035#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
2036 foreach_ethernet_input_next
2037#undef _
2038 },
2039};
2040
Damjan Marion5beecec2018-09-10 13:09:21 +02002041VLIB_REGISTER_NODE (ethernet_input_not_l2_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002042 .name = "ethernet-input-not-l2",
2043 /* Takes a vector of packets. */
2044 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002045 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
2046 .next_nodes = {
2047#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
2048 foreach_ethernet_input_next
2049#undef _
2050 },
2051};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002052/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002053
Damjan Marion5beecec2018-09-10 13:09:21 +02002054#ifndef CLIB_MARCH_VARIANT
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002055void
2056ethernet_set_rx_redirect (vnet_main_t * vnm,
2057 vnet_hw_interface_t * hi, u32 enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002058{
2059 // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
2060 // don't go directly to ip4-input)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002061 vnet_hw_interface_rx_redirect_to_node
2062 (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002063}
2064
2065
2066/*
2067 * Initialization and registration for the next_by_ethernet structure
2068 */
2069
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002070clib_error_t *
2071next_by_ethertype_init (next_by_ethertype_t * l3_next)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002072{
2073 l3_next->input_next_by_type = sparse_vec_new
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002074 ( /* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002075 /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
2076
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002077 vec_validate (l3_next->sparse_index_by_input_next_index,
2078 ETHERNET_INPUT_NEXT_DROP);
2079 vec_validate (l3_next->sparse_index_by_input_next_index,
2080 ETHERNET_INPUT_NEXT_PUNT);
2081 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP] =
2082 SPARSE_VEC_INVALID_INDEX;
2083 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] =
2084 SPARSE_VEC_INVALID_INDEX;
2085
Damjan Marion607de1a2016-08-16 22:53:54 +02002086 /*
2087 * Make sure we don't wipe out an ethernet registration by mistake
Dave Barach1f49ed62016-02-24 11:29:06 -05002088 * Can happen if init function ordering constraints are missing.
2089 */
2090 if (CLIB_DEBUG > 0)
2091 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002092 ethernet_main_t *em = &ethernet_main;
2093 ASSERT (em->next_by_ethertype_register_called == 0);
Dave Barach1f49ed62016-02-24 11:29:06 -05002094 }
2095
Ed Warnickecb9cada2015-12-08 15:45:58 -07002096 return 0;
2097}
2098
2099// Add an ethertype -> next index mapping to the structure
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002100clib_error_t *
2101next_by_ethertype_register (next_by_ethertype_t * l3_next,
2102 u32 ethertype, u32 next_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002103{
2104 u32 i;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002105 u16 *n;
2106 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002107
Dave Barach1f49ed62016-02-24 11:29:06 -05002108 if (CLIB_DEBUG > 0)
2109 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002110 ethernet_main_t *em = &ethernet_main;
Dave Barach1f49ed62016-02-24 11:29:06 -05002111 em->next_by_ethertype_register_called = 1;
2112 }
2113
Ed Warnickecb9cada2015-12-08 15:45:58 -07002114 /* Setup ethernet type -> next index sparse vector mapping. */
2115 n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
2116 n[0] = next_index;
2117
2118 /* Rebuild next index -> sparse index inverse mapping when sparse vector
2119 is updated. */
2120 vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
2121 for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002122 l3_next->
2123 sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002124
2125 // do not allow the cached next index's to be updated if L3
2126 // redirect is enabled, as it will have overwritten them
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002127 if (!em->redirect_l3)
2128 {
2129 // Cache common ethertypes directly
2130 if (ethertype == ETHERNET_TYPE_IP4)
2131 {
2132 l3_next->input_next_ip4 = next_index;
2133 }
2134 else if (ethertype == ETHERNET_TYPE_IP6)
2135 {
2136 l3_next->input_next_ip6 = next_index;
2137 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002138 else if (ethertype == ETHERNET_TYPE_MPLS)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002139 {
2140 l3_next->input_next_mpls = next_index;
2141 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002142 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002143 return 0;
2144}
2145
Dave Barachf8d50682019-05-14 18:01:44 -04002146void
2147ethernet_input_init (vlib_main_t * vm, ethernet_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002148{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002149 __attribute__ ((unused)) vlan_table_t *invalid_vlan_table;
2150 __attribute__ ((unused)) qinq_table_t *invalid_qinq_table;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002151
2152 ethernet_setup_node (vm, ethernet_input_node.index);
2153 ethernet_setup_node (vm, ethernet_input_type_node.index);
2154 ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
2155
2156 next_by_ethertype_init (&em->l3_next);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002157
Ed Warnickecb9cada2015-12-08 15:45:58 -07002158 // Initialize pools and vector for vlan parsing
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002159 vec_validate (em->main_intfs, 10); // 10 main interfaces
2160 pool_alloc (em->vlan_pool, 10);
2161 pool_alloc (em->qinq_pool, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002162
2163 // The first vlan pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002164 pool_get (em->vlan_pool, invalid_vlan_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165 // The first qinq pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002166 pool_get (em->qinq_pool, invalid_qinq_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002167}
2168
Ed Warnickecb9cada2015-12-08 15:45:58 -07002169void
2170ethernet_register_input_type (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002171 ethernet_type_t type, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002172{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002173 ethernet_main_t *em = &ethernet_main;
2174 ethernet_type_info_t *ti;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002175 u32 i;
2176
2177 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002178 clib_error_t *error = vlib_call_init_function (vm, ethernet_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002179 if (error)
2180 clib_error_report (error);
2181 }
2182
2183 ti = ethernet_get_type_info (em, type);
Dave Barach4bda2d92019-07-03 15:21:50 -04002184 if (ti == 0)
2185 {
2186 clib_warning ("type_info NULL for type %d", type);
2187 return;
2188 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002189 ti->node_index = node_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002190 ti->next_index = vlib_node_add_next (vm,
2191 ethernet_input_node.index, node_index);
2192 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193 ASSERT (i == ti->next_index);
2194
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002195 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002196 ASSERT (i == ti->next_index);
2197
2198 // Add the L3 node for this ethertype to the next nodes structure
2199 next_by_ethertype_register (&em->l3_next, type, ti->next_index);
2200
2201 // Call the registration functions for other nodes that want a mapping
2202 l2bvi_register_input_type (vm, type, node_index);
2203}
2204
2205void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002206ethernet_register_l2_input (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002207{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002208 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209 u32 i;
2210
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002211 em->l2_next =
2212 vlib_node_add_next (vm, ethernet_input_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002213
Damjan Marion607de1a2016-08-16 22:53:54 +02002214 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002215 * Even if we never use these arcs, we have to align the next indices...
2216 */
2217 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
2218
2219 ASSERT (i == em->l2_next);
2220
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002221 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222 ASSERT (i == em->l2_next);
2223}
2224
2225// Register a next node for L3 redirect, and enable L3 redirect
2226void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002227ethernet_register_l3_redirect (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002229 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002230 u32 i;
2231
2232 em->redirect_l3 = 1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002233 em->redirect_l3_next = vlib_node_add_next (vm,
2234 ethernet_input_node.index,
2235 node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236 /*
2237 * Change the cached next nodes to the redirect node
2238 */
2239 em->l3_next.input_next_ip4 = em->redirect_l3_next;
2240 em->l3_next.input_next_ip6 = em->redirect_l3_next;
2241 em->l3_next.input_next_mpls = em->redirect_l3_next;
2242
2243 /*
2244 * Even if we never use these arcs, we have to align the next indices...
2245 */
2246 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
2247
2248 ASSERT (i == em->redirect_l3_next);
jerryianff82ed62016-12-05 17:13:00 +08002249
2250 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
2251
2252 ASSERT (i == em->redirect_l3_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002253}
Damjan Marion5beecec2018-09-10 13:09:21 +02002254#endif
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002255
2256/*
2257 * fd.io coding-style-patch-verification: ON
2258 *
2259 * Local Variables:
2260 * eval: (c-set-style "gnu")
2261 * End:
2262 */