blob: 7cf78c6543511e6f9c241fecda8a9a15e840bebe [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>
47
48
49#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 {
227 if (!eth_mac_equal ((u8 *) e0, hi->hw_address))
228 {
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 +0100304typedef enum
305{
306 ETYPE_ID_UNKNOWN = 0,
307 ETYPE_ID_IP4,
308 ETYPE_ID_IP6,
309 ETYPE_ID_MPLS,
310 ETYPE_N_IDS,
311} etype_id_t;
312
313static_always_inline void
314eth_input_advance_and_flags (vlib_main_t * vm, u32 * from, u32 n_left,
315 i16 advance, u32 and_flags, u32 or_flags)
316{
317 vlib_buffer_t *b[8];
318 while (n_left >= 8)
319 {
320 vlib_get_buffers (vm, from, b, 8);
321 vlib_buffer_advance (b[0], advance);
322 vlib_buffer_advance (b[1], advance);
323 vlib_buffer_advance (b[2], advance);
324 vlib_buffer_advance (b[3], advance);
325 vlib_buffer_advance (b[4], advance);
326 vlib_buffer_advance (b[5], advance);
327 vlib_buffer_advance (b[6], advance);
328 vlib_buffer_advance (b[7], advance);
329 b[0]->flags = (b[0]->flags & and_flags) | or_flags;
330 b[1]->flags = (b[1]->flags & and_flags) | or_flags;
331 b[2]->flags = (b[2]->flags & and_flags) | or_flags;
332 b[3]->flags = (b[3]->flags & and_flags) | or_flags;
333 b[4]->flags = (b[4]->flags & and_flags) | or_flags;
334 b[5]->flags = (b[5]->flags & and_flags) | or_flags;
335 b[6]->flags = (b[6]->flags & and_flags) | or_flags;
336 b[7]->flags = (b[7]->flags & and_flags) | or_flags;
337
338 n_left -= 8;
339 from += 8;
340 }
341 while (n_left)
342 {
343 vlib_get_buffers (vm, from, b, 1);
344 vlib_buffer_advance (b[0], advance);
345 b[0]->flags = (b[0]->flags & and_flags) | or_flags;
346
347 n_left -= 1;
348 from += 1;
349 }
350}
351
352typedef struct
353{
354 u16 etypes[VLIB_FRAME_SIZE];
355 u32 bufs_by_etype[ETYPE_N_IDS][VLIB_FRAME_SIZE];
356 u16 n_bufs_by_etype[ETYPE_N_IDS];
357} eth_input_data_t;
358
359/* following vector code relies on following assumptions */
360STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_data, 0);
361STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_length, 2);
362STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, flags, 4);
363STATIC_ASSERT (STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l2_hdr_offset) ==
364 STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l3_hdr_offset) - 2,
365 "l3_hdr_offset must follow l2_hdr_offset");
366
367static_always_inline void
368eth_input_adv_and_flags_x4 (vlib_buffer_t ** b, i16 adv, u32 flags, int is_l3)
369{
370#ifdef CLIB_HAVE_VEC256
371 /* to reduce number of small loads/stores we are loading first 64 bits
372 of each buffer metadata into 256-bit register so we can advance
373 current_data, current_length and flags.
374 Observed saving of this code is ~2 clocks per packet */
375 u64x4 r, radv;
376
377 /* vector if signed 16 bit integers used in signed vector add operation
378 to advnce current_data and current_length */
379 u32x8 flags4 = { 0, flags, 0, flags, 0, flags, 0, flags };
380 i16x16 adv4 = {
381 adv, -adv, 0, 0, adv, -adv, 0, 0,
382 adv, -adv, 0, 0, adv, -adv, 0, 0
383 };
384
385 /* load 4 x 64 bits */
386 r = u64x4_gather (b[0], b[1], b[2], b[3]);
387
388 /* set flags */
389 r |= (u64x4) flags4;
390
391 /* advance buffer */
392 radv = (u64x4) ((i16x16) r + adv4);
393
394 /* write 4 x 64 bits */
395 u64x4_scatter (is_l3 ? radv : r, b[0], b[1], b[2], b[3]);
396
397 /* use old current_data as l2_hdr_offset and new current_data as
398 l3_hdr_offset */
399 r = (u64x4) u16x16_blend (r, radv << 16, 0xaa);
400
401 /* store both l2_hdr_offset and l3_hdr_offset in single store operation */
402 u32x8_scatter_one ((u32x8) r, 0, &vnet_buffer (b[0])->l2_hdr_offset);
403 u32x8_scatter_one ((u32x8) r, 2, &vnet_buffer (b[1])->l2_hdr_offset);
404 u32x8_scatter_one ((u32x8) r, 4, &vnet_buffer (b[2])->l2_hdr_offset);
405 u32x8_scatter_one ((u32x8) r, 6, &vnet_buffer (b[3])->l2_hdr_offset);
406
Damjan Marione9cebdf2018-11-21 00:47:42 +0100407 if (is_l3)
408 {
409 ASSERT (b[0]->current_data == vnet_buffer (b[0])->l3_hdr_offset);
410 ASSERT (b[1]->current_data == vnet_buffer (b[1])->l3_hdr_offset);
411 ASSERT (b[2]->current_data == vnet_buffer (b[2])->l3_hdr_offset);
412 ASSERT (b[3]->current_data == vnet_buffer (b[3])->l3_hdr_offset);
Damjan Marion650223c2018-11-14 16:55:53 +0100413
Damjan Marione9cebdf2018-11-21 00:47:42 +0100414 ASSERT (b[0]->current_data - vnet_buffer (b[0])->l2_hdr_offset == adv);
415 ASSERT (b[1]->current_data - vnet_buffer (b[1])->l2_hdr_offset == adv);
416 ASSERT (b[2]->current_data - vnet_buffer (b[2])->l2_hdr_offset == adv);
417 ASSERT (b[3]->current_data - vnet_buffer (b[3])->l2_hdr_offset == adv);
418 }
419 else
420 {
421 ASSERT (b[0]->current_data == vnet_buffer (b[0])->l2_hdr_offset);
422 ASSERT (b[1]->current_data == vnet_buffer (b[1])->l2_hdr_offset);
423 ASSERT (b[2]->current_data == vnet_buffer (b[2])->l2_hdr_offset);
424 ASSERT (b[3]->current_data == vnet_buffer (b[3])->l2_hdr_offset);
425
426 ASSERT (b[0]->current_data - vnet_buffer (b[0])->l3_hdr_offset == -adv);
427 ASSERT (b[1]->current_data - vnet_buffer (b[1])->l3_hdr_offset == -adv);
428 ASSERT (b[2]->current_data - vnet_buffer (b[2])->l3_hdr_offset == -adv);
429 ASSERT (b[3]->current_data - vnet_buffer (b[3])->l3_hdr_offset == -adv);
430 }
Damjan Marion650223c2018-11-14 16:55:53 +0100431
432#else
433 vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
434 vnet_buffer (b[1])->l2_hdr_offset = b[1]->current_data;
435 vnet_buffer (b[2])->l2_hdr_offset = b[2]->current_data;
436 vnet_buffer (b[3])->l2_hdr_offset = b[3]->current_data;
437 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
438 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data + adv;
439 vnet_buffer (b[2])->l3_hdr_offset = b[2]->current_data + adv;
440 vnet_buffer (b[3])->l3_hdr_offset = b[3]->current_data + adv;
441
442 if (is_l3)
443 {
444 vlib_buffer_advance (b[0], adv);
445 vlib_buffer_advance (b[1], adv);
446 vlib_buffer_advance (b[2], adv);
447 vlib_buffer_advance (b[3], adv);
448 }
449
450 b[0]->flags |= flags;
451 b[1]->flags |= flags;
452 b[2]->flags |= flags;
453 b[3]->flags |= flags;
454#endif
455
456 if (!is_l3)
457 {
458 vnet_buffer (b[0])->l2.l2_len = adv;
459 vnet_buffer (b[1])->l2.l2_len = adv;
460 vnet_buffer (b[2])->l2.l2_len = adv;
461 vnet_buffer (b[3])->l2.l2_len = adv;
462 }
463}
464
465static_always_inline void
466eth_input_adv_and_flags_x1 (vlib_buffer_t ** b, i16 adv, u32 flags, int is_l3)
467{
468 vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
469 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
470
471 if (is_l3)
472 vlib_buffer_advance (b[0], adv);
473 b[0]->flags |= flags;
474 if (!is_l3)
475 vnet_buffer (b[0])->l2.l2_len = adv;
476}
477
478static_always_inline void
479eth_input_process_frame (vlib_main_t * vm, u32 * from, u16 * etype,
480 u32 n_left, int is_l3)
481{
482 vlib_buffer_t *b[16];
483 ethernet_header_t *e;
484 int adv = sizeof (ethernet_header_t);
485
486 u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
487 VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
488
489 while (n_left >= 16)
490 {
491 vlib_buffer_t **ph = b + 12, **pd = b + 8;
492 vlib_get_buffers (vm, from, b, 4);
493 vlib_get_buffers (vm, from + 8, b + 8, 8);
494
495 vlib_prefetch_buffer_header (ph[0], LOAD);
496 vlib_prefetch_buffer_data (pd[0], LOAD);
497 e = vlib_buffer_get_current (b[0]);
498 etype[0] = e->type;
499
500 vlib_prefetch_buffer_header (ph[1], LOAD);
501 vlib_prefetch_buffer_data (pd[1], LOAD);
502 e = vlib_buffer_get_current (b[1]);
503 etype[1] = e->type;
504
505 vlib_prefetch_buffer_header (ph[2], LOAD);
506 vlib_prefetch_buffer_data (pd[2], LOAD);
507 e = vlib_buffer_get_current (b[2]);
508 etype[2] = e->type;
509
510 vlib_prefetch_buffer_header (ph[3], LOAD);
511 vlib_prefetch_buffer_data (pd[3], LOAD);
512 e = vlib_buffer_get_current (b[3]);
513 etype[3] = e->type;
514
515 eth_input_adv_and_flags_x4 (b, adv, flags, is_l3);
516
517 /* next */
518 n_left -= 4;
519 etype += 4;
520 from += 4;
521 }
522 while (n_left >= 4)
523 {
524 vlib_get_buffers (vm, from, b, 4);
525
526 e = vlib_buffer_get_current (b[0]);
527 etype[0] = e->type;
528
529 e = vlib_buffer_get_current (b[1]);
530 etype[1] = e->type;
531
532 e = vlib_buffer_get_current (b[2]);
533 etype[2] = e->type;
534
535 e = vlib_buffer_get_current (b[3]);
536 etype[3] = e->type;
537
538 eth_input_adv_and_flags_x4 (b, adv, flags, is_l3);
539
540 /* next */
541 n_left -= 4;
542 etype += 4;
543 from += 4;
544 }
545 while (n_left)
546 {
547 vlib_get_buffers (vm, from, b, 1);
548
549 e = vlib_buffer_get_current (b[0]);
550 etype[0] = e->type;
551
552 eth_input_adv_and_flags_x1 (b, adv, flags, is_l3);
553
554 /* next */
555 n_left -= 1;
556 etype += 1;
557 from += 1;
558 }
559}
560
561static_always_inline void
562eth_input_sort (vlib_main_t * vm, u32 * from, u32 n_packets,
563 eth_input_data_t * d)
564{
565 u16 *etype = d->etypes;
566 i32 n_left = n_packets;
567
568#if defined (CLIB_HAVE_VEC256)
569 u16x16 e16;
570 u16x16 et16_ip4 = u16x16_splat (clib_host_to_net_u16 (ETHERNET_TYPE_IP4));
571 u16x16 et16_ip6 = u16x16_splat (clib_host_to_net_u16 (ETHERNET_TYPE_IP6));
572 u16x16 et16_mpls = u16x16_splat (clib_host_to_net_u16 (ETHERNET_TYPE_MPLS));
573 u16x16 id16_ip4 = u16x16_splat (ETYPE_ID_IP4);
574 u16x16 id16_ip6 = u16x16_splat (ETYPE_ID_IP6);
575 u16x16 id16_mpls = u16x16_splat (ETYPE_ID_MPLS);
576
577 while (n_left > 0)
578 {
579 u16x16 r = { 0 };
580 e16 = u16x16_load_unaligned (etype);
581 r += (e16 == et16_ip4) & id16_ip4;
582 r += (e16 == et16_ip6) & id16_ip6;
583 r += (e16 == et16_mpls) & id16_mpls;
584 u16x16_store_unaligned (r, etype);
585 etype += 16;
586 n_left -= 16;
587 }
588#elif defined (CLIB_HAVE_VEC128)
589 u16x8 e8;
590 u16x8 et8_ip4 = u16x8_splat (clib_host_to_net_u16 (ETHERNET_TYPE_IP4));
591 u16x8 et8_ip6 = u16x8_splat (clib_host_to_net_u16 (ETHERNET_TYPE_IP6));
592 u16x8 et8_mpls = u16x8_splat (clib_host_to_net_u16 (ETHERNET_TYPE_MPLS));
593 u16x8 id8_ip4 = u16x8_splat (ETYPE_ID_IP4);
594 u16x8 id8_ip6 = u16x8_splat (ETYPE_ID_IP6);
595 u16x8 id8_mpls = u16x8_splat (ETYPE_ID_MPLS);
596
597 while (n_left > 0)
598 {
599 u16x8 r = { 0 };
600 e8 = u16x8_load_unaligned (etype);
601 r += (e8 == et8_ip4) & id8_ip4;
602 r += (e8 == et8_ip6) & id8_ip6;
603 r += (e8 == et8_mpls) & id8_mpls;
604 u16x8_store_unaligned (r, etype);
605 etype += 8;
606 n_left -= 8;
607 }
608#else
609 while (n_left)
610 {
611 if (etype[0] == ETHERNET_TYPE_IP4)
612 etype[0] = ETYPE_ID_IP4;
613 else if (etype[0] == ETHERNET_TYPE_IP6)
614 etype[0] = ETYPE_ID_IP6;
615 else if (etype[0] == ETHERNET_TYPE_MPLS)
616 etype[0] = ETYPE_ID_MPLS;
617 else
618 etype[0] = ETYPE_ID_UNKNOWN;
619
620 etype += 1;
621 n_left -= 1;
622 }
623#endif
624
625 etype = d->etypes;
626 n_left = n_packets;
627
628 clib_memset_u16 (d->n_bufs_by_etype, 0, ETYPE_N_IDS);
629 while (n_left)
630 {
631 u16 x, y;
632 x = etype[0];
633 y = d->n_bufs_by_etype[x];
634
635#ifdef CLIB_HAVE_VEC256
636 if (n_left >= 16 && u16x16_is_all_equal (u16x16_load_unaligned (etype),
637 etype[0]))
638 {
639 clib_memcpy_fast (&d->bufs_by_etype[x][y], from, 16 * sizeof (u32));
640 d->n_bufs_by_etype[x] += 16;
641
642 /* next */
643 n_left -= 16;
644 etype += 16;
645 from += 16;
646 continue;
647 }
648#endif
649#ifdef CLIB_HAVE_VEC128
650 if (n_left >= 8 && u16x8_is_all_equal (u16x8_load_unaligned (etype),
651 etype[0]))
652 {
653 clib_memcpy_fast (&d->bufs_by_etype[x][y], from, 8 * sizeof (u32));
654 d->n_bufs_by_etype[x] += 8;
655
656 /* next */
657 n_left -= 8;
658 etype += 8;
659 from += 8;
660 continue;
661 }
662#endif
663 d->bufs_by_etype[x][y] = from[0];
664 d->n_bufs_by_etype[x]++;
665
666 /* next */
667 n_left -= 1;
668 etype += 1;
669 from += 1;
670 }
671}
672
673static_always_inline void
674ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
675 vlib_frame_t * from_frame)
676{
677 u32 *from, n_left;
678 if ((node->flags & VLIB_NODE_FLAG_TRACE) == 0)
679 return;
680
681 from = vlib_frame_vector_args (from_frame);
682 n_left = from_frame->n_vectors;
683
684 while (n_left)
685 {
686 ethernet_input_trace_t *t0;
687 vlib_buffer_t *b0 = vlib_get_buffer (vm, from[0]);
688
689 if (b0->flags & VLIB_BUFFER_IS_TRACED)
690 {
691 t0 = vlib_add_trace (vm, node, b0, sizeof (ethernet_input_trace_t));
692 clib_memcpy_fast (t0->packet_data, b0->data + b0->current_data,
693 sizeof (t0->packet_data));
694 t0->frame_flags = from_frame->flags;
695 clib_memcpy_fast (&t0->frame_data,
696 vlib_frame_scalar_args (from_frame),
697 sizeof (ethernet_input_frame_t));
698 }
699 from += 1;
700 n_left -= 1;
701 }
702}
703
704static_always_inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705ethernet_input_inline (vlib_main_t * vm,
706 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +0100707 u32 * from, u32 n_packets,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708 ethernet_input_variant_t variant)
709{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700710 vnet_main_t *vnm = vnet_get_main ();
711 ethernet_main_t *em = &ethernet_main;
712 vlib_node_runtime_t *error_node;
Damjan Marion650223c2018-11-14 16:55:53 +0100713 u32 n_left_from, next_index, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714 u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
Damjan Marion067cd622018-07-11 12:47:43 +0200715 u32 thread_index = vm->thread_index;
Dave Barachcfba1e22016-11-16 10:23:50 -0500716 u32 cached_sw_if_index = ~0;
717 u32 cached_is_l2 = 0; /* shut up gcc */
John Lo1904c472017-03-10 17:15:22 -0500718 vnet_hw_interface_t *hi = NULL; /* used for main interface only */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
720 if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
721 error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
722 else
723 error_node = node;
724
Damjan Marion650223c2018-11-14 16:55:53 +0100725 n_left_from = n_packets;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726
727 next_index = node->cached_next_index;
728 stats_sw_if_index = node->runtime_data[0];
729 stats_n_packets = stats_n_bytes = 0;
730
731 while (n_left_from > 0)
732 {
733 u32 n_left_to_next;
734
735 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
736
737 while (n_left_from >= 4 && n_left_to_next >= 2)
738 {
739 u32 bi0, bi1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700740 vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741 u8 next0, next1, error0, error1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700742 u16 type0, orig_type0, type1, orig_type1;
743 u16 outer_id0, inner_id0, outer_id1, inner_id1;
744 u32 match_flags0, match_flags1;
745 u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1,
746 new_sw_if_index1, len1;
747 vnet_hw_interface_t *hi0, *hi1;
748 main_intf_t *main_intf0, *main_intf1;
749 vlan_intf_t *vlan_intf0, *vlan_intf1;
750 qinq_intf_t *qinq_intf0, *qinq_intf1;
751 u32 is_l20, is_l21;
Dave Barachcfba1e22016-11-16 10:23:50 -0500752 ethernet_header_t *e0, *e1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753
754 /* Prefetch next iteration. */
755 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700756 vlib_buffer_t *b2, *b3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757
758 b2 = vlib_get_buffer (vm, from[2]);
759 b3 = vlib_get_buffer (vm, from[3]);
760
761 vlib_prefetch_buffer_header (b2, STORE);
762 vlib_prefetch_buffer_header (b3, STORE);
763
764 CLIB_PREFETCH (b2->data, sizeof (ethernet_header_t), LOAD);
765 CLIB_PREFETCH (b3->data, sizeof (ethernet_header_t), LOAD);
766 }
767
768 bi0 = from[0];
769 bi1 = from[1];
770 to_next[0] = bi0;
771 to_next[1] = bi1;
772 from += 2;
773 to_next += 2;
774 n_left_to_next -= 2;
775 n_left_from -= 2;
776
777 b0 = vlib_get_buffer (vm, bi0);
778 b1 = vlib_get_buffer (vm, bi1);
779
780 error0 = error1 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -0500781 e0 = vlib_buffer_get_current (b0);
782 type0 = clib_net_to_host_u16 (e0->type);
783 e1 = vlib_buffer_get_current (b1);
784 type1 = clib_net_to_host_u16 (e1->type);
785
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +0200786 /* Set the L2 header offset for all packets */
787 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
788 vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
789 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
790 b1->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
791
John Locc532852016-12-14 15:42:45 -0500792 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -0500793 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
Damjan Marionc6969b52018-02-19 12:14:06 +0100794 && !ethernet_frame_is_any_tagged_x2 (type0,
795 type1)))
Dave Barachcfba1e22016-11-16 10:23:50 -0500796 {
797 main_intf_t *intf0;
798 subint_config_t *subint0;
799 u32 sw_if_index0, sw_if_index1;
800
801 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
802 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
803 is_l20 = cached_is_l2;
804
805 /* This is probably wholly unnecessary */
806 if (PREDICT_FALSE (sw_if_index0 != sw_if_index1))
807 goto slowpath;
808
John Lo1904c472017-03-10 17:15:22 -0500809 /* Now sw_if_index0 == sw_if_index1 */
Dave Barachcfba1e22016-11-16 10:23:50 -0500810 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
811 {
812 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -0500813 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
814 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -0500815 subint0 = &intf0->untagged_subint;
816 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
817 }
John Lo7714b302016-12-20 16:59:02 -0500818
Dave Barachcfba1e22016-11-16 10:23:50 -0500819 if (PREDICT_TRUE (is_l20 != 0))
820 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +0200821 vnet_buffer (b0)->l3_hdr_offset =
822 vnet_buffer (b0)->l2_hdr_offset +
823 sizeof (ethernet_header_t);
824 vnet_buffer (b1)->l3_hdr_offset =
825 vnet_buffer (b1)->l2_hdr_offset +
826 sizeof (ethernet_header_t);
827 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
828 b1->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -0500829 next0 = em->l2_next;
830 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -0500831 next1 = em->l2_next;
832 vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -0500833 }
John Locc532852016-12-14 15:42:45 -0500834 else
835 {
John Lo1904c472017-03-10 17:15:22 -0500836 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +0800837 (hi->hw_address != 0) &&
John Lo1904c472017-03-10 17:15:22 -0500838 !eth_mac_equal ((u8 *) e0, hi->hw_address))
839 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
840 if (!ethernet_address_cast (e1->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +0800841 (hi->hw_address != 0) &&
John Lo1904c472017-03-10 17:15:22 -0500842 !eth_mac_equal ((u8 *) e1, hi->hw_address))
843 error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
John Lob14826e2018-04-18 15:52:23 -0400844 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -0500845 determine_next_node (em, variant, 0, type0, b0,
846 &error0, &next0);
John Lob14826e2018-04-18 15:52:23 -0400847 vlib_buffer_advance (b1, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -0500848 determine_next_node (em, variant, 0, type1, b1,
849 &error1, &next1);
John Locc532852016-12-14 15:42:45 -0500850 }
851 goto ship_it01;
Dave Barachcfba1e22016-11-16 10:23:50 -0500852 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700853
John Locc532852016-12-14 15:42:45 -0500854 /* Slow-path for the tagged case */
855 slowpath:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700856 parse_header (variant,
857 b0,
858 &type0,
859 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700860
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700861 parse_header (variant,
862 b1,
863 &type1,
864 &orig_type1, &outer_id1, &inner_id1, &match_flags1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700866 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
867 old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700869 eth_vlan_table_lookups (em,
870 vnm,
871 old_sw_if_index0,
872 orig_type0,
873 outer_id0,
874 inner_id0,
875 &hi0,
876 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700877
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700878 eth_vlan_table_lookups (em,
879 vnm,
880 old_sw_if_index1,
881 orig_type1,
882 outer_id1,
883 inner_id1,
884 &hi1,
885 &main_intf1, &vlan_intf1, &qinq_intf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886
887 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700888 b0,
889 match_flags0,
890 main_intf0,
891 vlan_intf0,
892 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893
894 identify_subint (hi1,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700895 b1,
896 match_flags1,
897 main_intf1,
898 vlan_intf1,
899 qinq_intf1, &new_sw_if_index1, &error1, &is_l21);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700901 // Save RX sw_if_index for later nodes
902 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
903 error0 !=
904 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
905 vnet_buffer (b1)->sw_if_index[VLIB_RX] =
906 error1 !=
907 ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700909 // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
910 if (((new_sw_if_index0 != ~0)
911 && (new_sw_if_index0 != old_sw_if_index0))
912 || ((new_sw_if_index1 != ~0)
913 && (new_sw_if_index1 != old_sw_if_index1)))
914 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700916 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +0200917 - vnet_buffer (b0)->l2_hdr_offset;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700918 len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
Damjan Marion072401e2017-07-13 18:53:27 +0200919 - vnet_buffer (b1)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700921 stats_n_packets += 2;
922 stats_n_bytes += len0 + len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700923
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700924 if (PREDICT_FALSE
925 (!(new_sw_if_index0 == stats_sw_if_index
926 && new_sw_if_index1 == stats_sw_if_index)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700927 {
928 stats_n_packets -= 2;
929 stats_n_bytes -= len0 + len1;
930
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700931 if (new_sw_if_index0 != old_sw_if_index0
932 && new_sw_if_index0 != ~0)
933 vlib_increment_combined_counter (vnm->
934 interface_main.combined_sw_if_counters
935 +
936 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +0200937 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700938 new_sw_if_index0, 1,
939 len0);
940 if (new_sw_if_index1 != old_sw_if_index1
941 && new_sw_if_index1 != ~0)
942 vlib_increment_combined_counter (vnm->
943 interface_main.combined_sw_if_counters
944 +
945 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +0200946 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700947 new_sw_if_index1, 1,
948 len1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949
950 if (new_sw_if_index0 == new_sw_if_index1)
951 {
952 if (stats_n_packets > 0)
953 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700954 vlib_increment_combined_counter
955 (vnm->interface_main.combined_sw_if_counters
956 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +0200957 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700958 stats_sw_if_index,
959 stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960 stats_n_packets = stats_n_bytes = 0;
961 }
962 stats_sw_if_index = new_sw_if_index0;
963 }
964 }
965 }
966
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700967 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
968 is_l20 = is_l21 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700970 determine_next_node (em, variant, is_l20, type0, b0, &error0,
971 &next0);
972 determine_next_node (em, variant, is_l21, type1, b1, &error1,
973 &next1);
974
John Lo1904c472017-03-10 17:15:22 -0500975 ship_it01:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976 b0->error = error_node->errors[error0];
977 b1->error = error_node->errors[error1];
978
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700979 // verify speculative enqueue
980 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
981 n_left_to_next, bi0, bi1, next0,
982 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 }
984
985 while (n_left_from > 0 && n_left_to_next > 0)
986 {
987 u32 bi0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700988 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989 u8 error0, next0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700990 u16 type0, orig_type0;
991 u16 outer_id0, inner_id0;
992 u32 match_flags0;
993 u32 old_sw_if_index0, new_sw_if_index0, len0;
994 vnet_hw_interface_t *hi0;
995 main_intf_t *main_intf0;
996 vlan_intf_t *vlan_intf0;
997 qinq_intf_t *qinq_intf0;
Dave Barachcfba1e22016-11-16 10:23:50 -0500998 ethernet_header_t *e0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700999 u32 is_l20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001000
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001001 // Prefetch next iteration
1002 if (n_left_from > 1)
1003 {
1004 vlib_buffer_t *p2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001005
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001006 p2 = vlib_get_buffer (vm, from[1]);
1007 vlib_prefetch_buffer_header (p2, STORE);
1008 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
1009 }
1010
1011 bi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012 to_next[0] = bi0;
1013 from += 1;
1014 to_next += 1;
1015 n_left_from -= 1;
1016 n_left_to_next -= 1;
1017
1018 b0 = vlib_get_buffer (vm, bi0);
1019
1020 error0 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001021 e0 = vlib_buffer_get_current (b0);
1022 type0 = clib_net_to_host_u16 (e0->type);
1023
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001024 /* Set the L2 header offset for all packets */
1025 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1026 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1027
John Locc532852016-12-14 15:42:45 -05001028 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001029 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
1030 && !ethernet_frame_is_tagged (type0)))
1031 {
1032 main_intf_t *intf0;
1033 subint_config_t *subint0;
1034 u32 sw_if_index0;
1035
1036 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1037 is_l20 = cached_is_l2;
1038
1039 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1040 {
1041 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001042 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1043 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001044 subint0 = &intf0->untagged_subint;
1045 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1046 }
John Lo7714b302016-12-20 16:59:02 -05001047
John Lo7714b302016-12-20 16:59:02 -05001048
Dave Barachcfba1e22016-11-16 10:23:50 -05001049 if (PREDICT_TRUE (is_l20 != 0))
1050 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001051 vnet_buffer (b0)->l3_hdr_offset =
1052 vnet_buffer (b0)->l2_hdr_offset +
1053 sizeof (ethernet_header_t);
1054 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001055 next0 = em->l2_next;
1056 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001057 }
John Locc532852016-12-14 15:42:45 -05001058 else
1059 {
John Lo1904c472017-03-10 17:15:22 -05001060 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001061 (hi->hw_address != 0) &&
John Lo1904c472017-03-10 17:15:22 -05001062 !eth_mac_equal ((u8 *) e0, hi->hw_address))
1063 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
Andrew Yourtchenkoe78bca12018-10-10 16:15:55 +02001064 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001065 determine_next_node (em, variant, 0, type0, b0,
1066 &error0, &next0);
John Locc532852016-12-14 15:42:45 -05001067 }
1068 goto ship_it0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001069 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070
John Locc532852016-12-14 15:42:45 -05001071 /* Slow-path for the tagged case */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001072 parse_header (variant,
1073 b0,
1074 &type0,
1075 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001077 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001078
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001079 eth_vlan_table_lookups (em,
1080 vnm,
1081 old_sw_if_index0,
1082 orig_type0,
1083 outer_id0,
1084 inner_id0,
1085 &hi0,
1086 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001087
1088 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001089 b0,
1090 match_flags0,
1091 main_intf0,
1092 vlan_intf0,
1093 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001095 // Save RX sw_if_index for later nodes
1096 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1097 error0 !=
1098 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001100 // Increment subinterface stats
1101 // Note that interface-level counters have already been incremented
1102 // prior to calling this function. Thus only subinterface counters
1103 // are incremented here.
1104 //
Damjan Marion607de1a2016-08-16 22:53:54 +02001105 // Interface level counters include packets received on the main
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001106 // interface and all subinterfaces. Subinterface level counters
1107 // include only those packets received on that subinterface
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108 // Increment stats if the subint is valid and it is not the main intf
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001109 if ((new_sw_if_index0 != ~0)
1110 && (new_sw_if_index0 != old_sw_if_index0))
1111 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001113 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001114 - vnet_buffer (b0)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001116 stats_n_packets += 1;
1117 stats_n_bytes += len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001119 // Batch stat increments from the same subinterface so counters
Damjan Marion607de1a2016-08-16 22:53:54 +02001120 // don't need to be incremented for every packet.
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001121 if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index))
1122 {
1123 stats_n_packets -= 1;
1124 stats_n_bytes -= len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001126 if (new_sw_if_index0 != ~0)
1127 vlib_increment_combined_counter
1128 (vnm->interface_main.combined_sw_if_counters
1129 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001130 thread_index, new_sw_if_index0, 1, len0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001131 if (stats_n_packets > 0)
1132 {
1133 vlib_increment_combined_counter
1134 (vnm->interface_main.combined_sw_if_counters
1135 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001136 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001137 stats_sw_if_index, stats_n_packets, stats_n_bytes);
1138 stats_n_packets = stats_n_bytes = 0;
1139 }
1140 stats_sw_if_index = new_sw_if_index0;
1141 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001144 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1145 is_l20 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001147 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1148 &next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149
John Lo1904c472017-03-10 17:15:22 -05001150 ship_it0:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001151 b0->error = error_node->errors[error0];
1152
1153 // verify speculative enqueue
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1155 to_next, n_left_to_next,
1156 bi0, next0);
1157 }
1158
1159 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1160 }
1161
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001162 // Increment any remaining batched stats
1163 if (stats_n_packets > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001165 vlib_increment_combined_counter
1166 (vnm->interface_main.combined_sw_if_counters
1167 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001168 thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169 node->runtime_data[0] = stats_sw_if_index;
1170 }
Damjan Marion650223c2018-11-14 16:55:53 +01001171}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
Damjan Marion650223c2018-11-14 16:55:53 +01001173static_always_inline void
1174eth_input_enqueue_untagged (vlib_main_t * vm, vlib_node_runtime_t * node,
1175 eth_input_data_t * d, int ip4_cksum_ok, int is_l3)
1176{
1177 ethernet_main_t *em = &ethernet_main;
1178 etype_id_t id;
1179 u32 next_index;
1180
1181 id = ETYPE_ID_IP4;
1182 if (d->n_bufs_by_etype[id])
1183 {
1184 if (is_l3)
1185 {
1186 next_index = em->l3_next.input_next_ip4;
1187 if (next_index == ETHERNET_INPUT_NEXT_IP4_INPUT && ip4_cksum_ok)
1188 next_index = ETHERNET_INPUT_NEXT_IP4_INPUT_NCS;
1189 }
1190 else
1191 next_index = em->l2_next;
1192
1193 vlib_buffer_enqueue_to_single_next (vm, node, d->bufs_by_etype[id],
1194 next_index, d->n_bufs_by_etype[id]);
1195 }
1196
1197 id = ETYPE_ID_IP6;
1198 if (d->n_bufs_by_etype[id])
1199 {
1200 next_index = is_l3 ? em->l3_next.input_next_ip6 : em->l2_next;
1201 vlib_buffer_enqueue_to_single_next (vm, node, d->bufs_by_etype[id],
1202 next_index, d->n_bufs_by_etype[id]);
1203 }
1204
1205 id = ETYPE_ID_MPLS;
1206 if (d->n_bufs_by_etype[id])
1207 {
1208 next_index = is_l3 ? em->l3_next.input_next_mpls : em->l2_next;
1209 vlib_buffer_enqueue_to_single_next (vm, node, d->bufs_by_etype[id],
1210 next_index, d->n_bufs_by_etype[id]);
1211 }
1212
1213 id = ETYPE_ID_UNKNOWN;
1214 if (d->n_bufs_by_etype[id])
1215 {
1216 /* in case of l3 interfaces, we already advanced buffer so we need to
1217 roll back */
1218 if (is_l3)
1219 eth_input_advance_and_flags (vm, d->bufs_by_etype[id],
1220 d->n_bufs_by_etype[id],
1221 -(i16) sizeof (ethernet_header_t),
1222 ~VNET_BUFFER_F_L3_HDR_OFFSET_VALID, 0);
1223 ethernet_input_inline (vm, node, d->bufs_by_etype[id],
1224 d->n_bufs_by_etype[id],
1225 ETHERNET_INPUT_VARIANT_ETHERNET);
1226 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227}
1228
Damjan Marion5beecec2018-09-10 13:09:21 +02001229VLIB_NODE_FN (ethernet_input_node) (vlib_main_t * vm,
1230 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +01001231 vlib_frame_t * frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001232{
Damjan Marion650223c2018-11-14 16:55:53 +01001233 vnet_main_t *vnm = vnet_get_main ();
1234 ethernet_main_t *em = &ethernet_main;
1235 u32 *from = vlib_frame_vector_args (frame);
1236 u32 n_packets = frame->n_vectors;
1237
1238 ethernet_input_trace (vm, node, frame);
1239
1240 if (frame->flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
1241 {
1242 eth_input_data_t data, *d = &data;
1243 ethernet_input_frame_t *ef = vlib_frame_scalar_args (frame);
1244 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ef->hw_if_index);
1245 main_intf_t *intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
1246 subint_config_t *subint0 = &intf0->untagged_subint;
1247 int ip4_cksum_ok = (frame->flags & ETH_INPUT_FRAME_F_IP4_CKSUM_OK) != 0;
1248
1249 if (subint0->flags & SUBINT_CONFIG_L2)
1250 {
1251 /* untagged packets are treated as L2 */
1252 eth_input_process_frame (vm, from, d->etypes, n_packets, 0);
1253 eth_input_sort (vm, from, n_packets, d);
1254 eth_input_enqueue_untagged (vm, node, d, ip4_cksum_ok, 0);
1255 }
1256 else
1257 {
1258 ethernet_interface_t *ei;
1259 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
1260
1261 /* currently only slowpath deals with dmac check */
1262 if (ei->flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL)
1263 goto slowpath;
1264
1265 /* untagged packets are treated as L3 */
1266 eth_input_process_frame (vm, from, d->etypes, n_packets, 1);
1267 eth_input_sort (vm, from, n_packets, d);
1268 eth_input_enqueue_untagged (vm, node, d, ip4_cksum_ok, 1);
1269 }
1270 return n_packets;
1271 }
1272
1273slowpath:
1274 ethernet_input_inline (vm, node, from, n_packets,
1275 ETHERNET_INPUT_VARIANT_ETHERNET);
1276 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001277}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001278
Damjan Marion5beecec2018-09-10 13:09:21 +02001279VLIB_NODE_FN (ethernet_input_type_node) (vlib_main_t * vm,
1280 vlib_node_runtime_t * node,
1281 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001282{
Damjan Marion650223c2018-11-14 16:55:53 +01001283 u32 *from = vlib_frame_vector_args (from_frame);
1284 u32 n_packets = from_frame->n_vectors;
1285 ethernet_input_trace (vm, node, from_frame);
1286 ethernet_input_inline (vm, node, from, n_packets,
1287 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE);
1288 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001289}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
Damjan Marion5beecec2018-09-10 13:09:21 +02001291VLIB_NODE_FN (ethernet_input_not_l2_node) (vlib_main_t * vm,
1292 vlib_node_runtime_t * node,
1293 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001294{
Damjan Marion650223c2018-11-14 16:55:53 +01001295 u32 *from = vlib_frame_vector_args (from_frame);
1296 u32 n_packets = from_frame->n_vectors;
1297 ethernet_input_trace (vm, node, from_frame);
1298 ethernet_input_inline (vm, node, from, n_packets,
1299 ETHERNET_INPUT_VARIANT_NOT_L2);
1300 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001301}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302
1303
1304// Return the subinterface config struct for the given sw_if_index
1305// Also return via parameter the appropriate match flags for the
1306// configured number of tags.
1307// On error (unsupported or not ethernet) return 0.
1308static subint_config_t *
1309ethernet_sw_interface_get_config (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001310 u32 sw_if_index,
1311 u32 * flags, u32 * unsupported)
1312{
1313 ethernet_main_t *em = &ethernet_main;
1314 vnet_hw_interface_t *hi;
1315 vnet_sw_interface_t *si;
1316 main_intf_t *main_intf;
1317 vlan_table_t *vlan_table;
1318 qinq_table_t *qinq_table;
1319 subint_config_t *subint = 0;
1320
Ed Warnickecb9cada2015-12-08 15:45:58 -07001321 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1322
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001323 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
1324 {
1325 *unsupported = 0;
1326 goto done; // non-ethernet interface
1327 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328
1329 // ensure there's an entry for the main intf (shouldn't really be necessary)
1330 vec_validate (em->main_intfs, hi->hw_if_index);
1331 main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
1332
1333 // Locate the subint for the given ethernet config
1334 si = vnet_get_sw_interface (vnm, sw_if_index);
1335
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001336 if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
1337 {
1338 p2p_ethernet_main_t *p2pm = &p2p_main;
1339 u32 p2pe_sw_if_index =
1340 p2p_ethernet_lookup (hi->hw_if_index, si->p2p.client_mac);
1341 if (p2pe_sw_if_index == ~0)
1342 {
1343 pool_get (p2pm->p2p_subif_pool, subint);
1344 si->p2p.pool_index = subint - p2pm->p2p_subif_pool;
1345 }
1346 else
1347 subint = vec_elt_at_index (p2pm->p2p_subif_pool, si->p2p.pool_index);
1348 *flags = SUBINT_CONFIG_P2P;
1349 }
Neale Ranns17ff3c12018-07-04 10:24:24 -07001350 else if (si->type == VNET_SW_INTERFACE_TYPE_PIPE)
1351 {
1352 pipe_t *pipe;
1353
1354 pipe = pipe_get (sw_if_index);
1355 subint = &pipe->subint;
1356 *flags = SUBINT_CONFIG_P2P;
1357 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001358 else if (si->sub.eth.flags.default_sub)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001359 {
1360 subint = &main_intf->default_subint;
Mike Bly88076742018-09-24 10:13:06 -07001361 *flags = SUBINT_CONFIG_MATCH_1_TAG |
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001362 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1363 }
1364 else if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0))
1365 {
1366 // if no flags are set then this is a main interface
1367 // so treat as untagged
1368 subint = &main_intf->untagged_subint;
1369 *flags = SUBINT_CONFIG_MATCH_0_TAG;
1370 }
1371 else
1372 {
1373 // one or two tags
1374 // first get the vlan table
1375 if (si->sub.eth.flags.dot1ad)
1376 {
1377 if (main_intf->dot1ad_vlans == 0)
1378 {
1379 // Allocate a vlan table from the pool
1380 pool_get (em->vlan_pool, vlan_table);
1381 main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
1382 }
1383 else
1384 {
1385 // Get ptr to existing vlan table
1386 vlan_table =
1387 vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
1388 }
1389 }
1390 else
1391 { // dot1q
1392 if (main_intf->dot1q_vlans == 0)
1393 {
1394 // Allocate a vlan table from the pool
1395 pool_get (em->vlan_pool, vlan_table);
1396 main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
1397 }
1398 else
1399 {
1400 // Get ptr to existing vlan table
1401 vlan_table =
1402 vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
1403 }
1404 }
1405
1406 if (si->sub.eth.flags.one_tag)
1407 {
1408 *flags = si->sub.eth.flags.exact_match ?
1409 SUBINT_CONFIG_MATCH_1_TAG :
1410 (SUBINT_CONFIG_MATCH_1_TAG |
1411 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1412
1413 if (si->sub.eth.flags.outer_vlan_id_any)
1414 {
1415 // not implemented yet
1416 *unsupported = 1;
1417 goto done;
1418 }
1419 else
1420 {
1421 // a single vlan, a common case
1422 subint =
1423 &vlan_table->vlans[si->sub.eth.
1424 outer_vlan_id].single_tag_subint;
1425 }
1426
1427 }
1428 else
1429 {
1430 // Two tags
1431 *flags = si->sub.eth.flags.exact_match ?
1432 SUBINT_CONFIG_MATCH_2_TAG :
1433 (SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1434
1435 if (si->sub.eth.flags.outer_vlan_id_any
1436 && si->sub.eth.flags.inner_vlan_id_any)
1437 {
1438 // not implemented yet
1439 *unsupported = 1;
1440 goto done;
1441 }
1442
1443 if (si->sub.eth.flags.inner_vlan_id_any)
1444 {
1445 // a specific outer and "any" inner
1446 // don't need a qinq table for this
1447 subint =
1448 &vlan_table->vlans[si->sub.eth.
1449 outer_vlan_id].inner_any_subint;
1450 if (si->sub.eth.flags.exact_match)
1451 {
1452 *flags = SUBINT_CONFIG_MATCH_2_TAG;
1453 }
1454 else
1455 {
1456 *flags = SUBINT_CONFIG_MATCH_2_TAG |
1457 SUBINT_CONFIG_MATCH_3_TAG;
1458 }
1459 }
1460 else
1461 {
1462 // a specific outer + specifc innner vlan id, a common case
1463
1464 // get the qinq table
1465 if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0)
1466 {
1467 // Allocate a qinq table from the pool
1468 pool_get (em->qinq_pool, qinq_table);
1469 vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs =
1470 qinq_table - em->qinq_pool;
1471 }
1472 else
1473 {
1474 // Get ptr to existing qinq table
1475 qinq_table =
1476 vec_elt_at_index (em->qinq_pool,
1477 vlan_table->vlans[si->sub.
1478 eth.outer_vlan_id].
1479 qinqs);
1480 }
1481 subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
1482 }
1483 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001484 }
1485
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001486done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001487 return subint;
1488}
1489
Damjan Marion5beecec2018-09-10 13:09:21 +02001490static clib_error_t *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001491ethernet_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001493 subint_config_t *subint;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001494 u32 dummy_flags;
1495 u32 dummy_unsup;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001496 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001497
1498 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001499 subint =
1500 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1501 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001502
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001503 if (subint == 0)
1504 {
1505 // not implemented yet or not ethernet
1506 goto done;
1507 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001508
1509 subint->sw_if_index =
1510 ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
1511
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001512done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513 return error;
1514}
1515
1516VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
1517
1518
Damjan Marion5beecec2018-09-10 13:09:21 +02001519#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001520// Set the L2/L3 mode for the subinterface
1521void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001522ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001523{
1524 subint_config_t *subint;
1525 u32 dummy_flags;
1526 u32 dummy_unsup;
1527 int is_port;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001528 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529
1530 is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
1531
1532 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001533 subint =
1534 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1535 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001537 if (subint == 0)
1538 {
1539 // unimplemented or not ethernet
1540 goto done;
1541 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542
1543 // Double check that the config we found is for our interface (or the interface is down)
1544 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1545
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001546 if (l2)
1547 {
1548 subint->flags |= SUBINT_CONFIG_L2;
1549 if (is_port)
1550 subint->flags |=
1551 SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
1552 | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1553 }
1554 else
1555 {
1556 subint->flags &= ~SUBINT_CONFIG_L2;
1557 if (is_port)
1558 subint->flags &=
1559 ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
1560 | SUBINT_CONFIG_MATCH_3_TAG);
1561 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001563done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001564 return;
1565}
1566
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001567/*
1568 * Set the L2/L3 mode for the subinterface regardless of port
1569 */
1570void
1571ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001572 u32 sw_if_index, u32 l2)
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001573{
1574 subint_config_t *subint;
1575 u32 dummy_flags;
1576 u32 dummy_unsup;
1577
1578 /* Find the config for this subinterface */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001579 subint =
1580 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1581 &dummy_unsup);
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001582
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001583 if (subint == 0)
1584 {
1585 /* unimplemented or not ethernet */
1586 goto done;
1587 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001588
1589 /*
1590 * Double check that the config we found is for our interface (or the
1591 * interface is down)
1592 */
1593 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1594
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001595 if (l2)
1596 {
1597 subint->flags |= SUBINT_CONFIG_L2;
1598 }
1599 else
1600 {
1601 subint->flags &= ~SUBINT_CONFIG_L2;
1602 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001603
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001604done:
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001605 return;
1606}
Damjan Marion5beecec2018-09-10 13:09:21 +02001607#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608
1609static clib_error_t *
1610ethernet_sw_interface_add_del (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001611 u32 sw_if_index, u32 is_create)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001613 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001614 subint_config_t *subint;
1615 u32 match_flags;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001616 u32 unsupported = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617
1618 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001619 subint =
1620 ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags,
1621 &unsupported);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001622
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001623 if (subint == 0)
1624 {
1625 // not implemented yet or not ethernet
1626 if (unsupported)
1627 {
Damjan Marion607de1a2016-08-16 22:53:54 +02001628 // this is the NYI case
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001629 error = clib_error_return (0, "not implemented yet");
1630 }
1631 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001634 if (!is_create)
1635 {
1636 subint->flags = 0;
1637 return error;
1638 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001639
1640 // Initialize the subint
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001641 if (subint->flags & SUBINT_CONFIG_VALID)
1642 {
1643 // Error vlan already in use
1644 error = clib_error_return (0, "vlan is already in use");
1645 }
1646 else
1647 {
Neale Ranns17ff3c12018-07-04 10:24:24 -07001648 // Note that config is L3 by default
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001649 subint->flags = SUBINT_CONFIG_VALID | match_flags;
1650 subint->sw_if_index = ~0; // because interfaces are initially down
1651 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001652
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001653done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001654 return error;
1655}
1656
1657VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
1658
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001659static char *ethernet_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001660#define ethernet_error(n,c,s) s,
1661#include "error.def"
1662#undef ethernet_error
1663};
1664
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001665/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001666VLIB_REGISTER_NODE (ethernet_input_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001667 .name = "ethernet-input",
1668 /* Takes a vector of packets. */
1669 .vector_size = sizeof (u32),
Damjan Marion650223c2018-11-14 16:55:53 +01001670 .scalar_size = sizeof (ethernet_input_frame_t),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001671 .n_errors = ETHERNET_N_ERROR,
1672 .error_strings = ethernet_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001673 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1674 .next_nodes = {
1675#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1676 foreach_ethernet_input_next
1677#undef _
1678 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07001679 .format_buffer = format_ethernet_header_with_length,
1680 .format_trace = format_ethernet_input_trace,
1681 .unformat_buffer = unformat_ethernet_header,
1682};
1683
Damjan Marion5beecec2018-09-10 13:09:21 +02001684VLIB_REGISTER_NODE (ethernet_input_type_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685 .name = "ethernet-input-type",
1686 /* Takes a vector of packets. */
1687 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001688 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1689 .next_nodes = {
1690#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1691 foreach_ethernet_input_next
1692#undef _
1693 },
1694};
1695
Damjan Marion5beecec2018-09-10 13:09:21 +02001696VLIB_REGISTER_NODE (ethernet_input_not_l2_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001697 .name = "ethernet-input-not-l2",
1698 /* Takes a vector of packets. */
1699 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001700 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1701 .next_nodes = {
1702#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1703 foreach_ethernet_input_next
1704#undef _
1705 },
1706};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001707/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708
Damjan Marion5beecec2018-09-10 13:09:21 +02001709#ifndef CLIB_MARCH_VARIANT
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001710void
1711ethernet_set_rx_redirect (vnet_main_t * vnm,
1712 vnet_hw_interface_t * hi, u32 enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001713{
1714 // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
1715 // don't go directly to ip4-input)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001716 vnet_hw_interface_rx_redirect_to_node
1717 (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001718}
1719
1720
1721/*
1722 * Initialization and registration for the next_by_ethernet structure
1723 */
1724
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001725clib_error_t *
1726next_by_ethertype_init (next_by_ethertype_t * l3_next)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001727{
1728 l3_next->input_next_by_type = sparse_vec_new
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001729 ( /* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730 /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
1731
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001732 vec_validate (l3_next->sparse_index_by_input_next_index,
1733 ETHERNET_INPUT_NEXT_DROP);
1734 vec_validate (l3_next->sparse_index_by_input_next_index,
1735 ETHERNET_INPUT_NEXT_PUNT);
1736 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP] =
1737 SPARSE_VEC_INVALID_INDEX;
1738 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] =
1739 SPARSE_VEC_INVALID_INDEX;
1740
Damjan Marion607de1a2016-08-16 22:53:54 +02001741 /*
1742 * Make sure we don't wipe out an ethernet registration by mistake
Dave Barach1f49ed62016-02-24 11:29:06 -05001743 * Can happen if init function ordering constraints are missing.
1744 */
1745 if (CLIB_DEBUG > 0)
1746 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001747 ethernet_main_t *em = &ethernet_main;
1748 ASSERT (em->next_by_ethertype_register_called == 0);
Dave Barach1f49ed62016-02-24 11:29:06 -05001749 }
1750
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751 return 0;
1752}
1753
1754// Add an ethertype -> next index mapping to the structure
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001755clib_error_t *
1756next_by_ethertype_register (next_by_ethertype_t * l3_next,
1757 u32 ethertype, u32 next_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001758{
1759 u32 i;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001760 u16 *n;
1761 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762
Dave Barach1f49ed62016-02-24 11:29:06 -05001763 if (CLIB_DEBUG > 0)
1764 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001765 ethernet_main_t *em = &ethernet_main;
Dave Barach1f49ed62016-02-24 11:29:06 -05001766 em->next_by_ethertype_register_called = 1;
1767 }
1768
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769 /* Setup ethernet type -> next index sparse vector mapping. */
1770 n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
1771 n[0] = next_index;
1772
1773 /* Rebuild next index -> sparse index inverse mapping when sparse vector
1774 is updated. */
1775 vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
1776 for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001777 l3_next->
1778 sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001779
1780 // do not allow the cached next index's to be updated if L3
1781 // redirect is enabled, as it will have overwritten them
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001782 if (!em->redirect_l3)
1783 {
1784 // Cache common ethertypes directly
1785 if (ethertype == ETHERNET_TYPE_IP4)
1786 {
1787 l3_next->input_next_ip4 = next_index;
1788 }
1789 else if (ethertype == ETHERNET_TYPE_IP6)
1790 {
1791 l3_next->input_next_ip6 = next_index;
1792 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001793 else if (ethertype == ETHERNET_TYPE_MPLS)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001794 {
1795 l3_next->input_next_mpls = next_index;
1796 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001797 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798 return 0;
1799}
1800
1801
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001802static clib_error_t *
1803ethernet_input_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001805 ethernet_main_t *em = &ethernet_main;
1806 __attribute__ ((unused)) vlan_table_t *invalid_vlan_table;
1807 __attribute__ ((unused)) qinq_table_t *invalid_qinq_table;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001808
1809 ethernet_setup_node (vm, ethernet_input_node.index);
1810 ethernet_setup_node (vm, ethernet_input_type_node.index);
1811 ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
1812
1813 next_by_ethertype_init (&em->l3_next);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001814
Ed Warnickecb9cada2015-12-08 15:45:58 -07001815 // Initialize pools and vector for vlan parsing
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001816 vec_validate (em->main_intfs, 10); // 10 main interfaces
1817 pool_alloc (em->vlan_pool, 10);
1818 pool_alloc (em->qinq_pool, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819
1820 // The first vlan pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001821 pool_get (em->vlan_pool, invalid_vlan_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822 // The first qinq pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001823 pool_get (em->qinq_pool, invalid_qinq_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824
1825 return 0;
1826}
1827
1828VLIB_INIT_FUNCTION (ethernet_input_init);
1829
1830void
1831ethernet_register_input_type (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001832 ethernet_type_t type, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001834 ethernet_main_t *em = &ethernet_main;
1835 ethernet_type_info_t *ti;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836 u32 i;
1837
1838 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001839 clib_error_t *error = vlib_call_init_function (vm, ethernet_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001840 if (error)
1841 clib_error_report (error);
1842 }
1843
1844 ti = ethernet_get_type_info (em, type);
1845 ti->node_index = node_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001846 ti->next_index = vlib_node_add_next (vm,
1847 ethernet_input_node.index, node_index);
1848 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001849 ASSERT (i == ti->next_index);
1850
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001851 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852 ASSERT (i == ti->next_index);
1853
1854 // Add the L3 node for this ethertype to the next nodes structure
1855 next_by_ethertype_register (&em->l3_next, type, ti->next_index);
1856
1857 // Call the registration functions for other nodes that want a mapping
1858 l2bvi_register_input_type (vm, type, node_index);
1859}
1860
1861void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001862ethernet_register_l2_input (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001863{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001864 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865 u32 i;
1866
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001867 em->l2_next =
1868 vlib_node_add_next (vm, ethernet_input_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001869
Damjan Marion607de1a2016-08-16 22:53:54 +02001870 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871 * Even if we never use these arcs, we have to align the next indices...
1872 */
1873 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1874
1875 ASSERT (i == em->l2_next);
1876
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001877 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001878 ASSERT (i == em->l2_next);
1879}
1880
1881// Register a next node for L3 redirect, and enable L3 redirect
1882void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001883ethernet_register_l3_redirect (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001884{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001885 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886 u32 i;
1887
1888 em->redirect_l3 = 1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001889 em->redirect_l3_next = vlib_node_add_next (vm,
1890 ethernet_input_node.index,
1891 node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001892 /*
1893 * Change the cached next nodes to the redirect node
1894 */
1895 em->l3_next.input_next_ip4 = em->redirect_l3_next;
1896 em->l3_next.input_next_ip6 = em->redirect_l3_next;
1897 em->l3_next.input_next_mpls = em->redirect_l3_next;
1898
1899 /*
1900 * Even if we never use these arcs, we have to align the next indices...
1901 */
1902 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1903
1904 ASSERT (i == em->redirect_l3_next);
jerryianff82ed62016-12-05 17:13:00 +08001905
1906 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
1907
1908 ASSERT (i == em->redirect_l3_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909}
Damjan Marion5beecec2018-09-10 13:09:21 +02001910#endif
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001911
1912/*
1913 * fd.io coding-style-patch-verification: ON
1914 *
1915 * Local Variables:
1916 * eval: (c-set-style "gnu")
1917 * End:
1918 */