blob: 268b171a6afe69dfd2a1aa58f735b998a950794d [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
Ed Warnickecb9cada2015-12-08 15:45:58 -070048#define foreach_ethernet_input_next \
49 _ (PUNT, "error-punt") \
50 _ (DROP, "error-drop") \
Damjan Marion650223c2018-11-14 16:55:53 +010051 _ (LLC, "llc-input") \
52 _ (IP4_INPUT, "ip4-input") \
53 _ (IP4_INPUT_NCS, "ip4-input-no-checksum")
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070055typedef enum
56{
Ed Warnickecb9cada2015-12-08 15:45:58 -070057#define _(s,n) ETHERNET_INPUT_NEXT_##s,
58 foreach_ethernet_input_next
59#undef _
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070060 ETHERNET_INPUT_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -070061} ethernet_input_next_t;
62
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070063typedef struct
64{
Ed Warnickecb9cada2015-12-08 15:45:58 -070065 u8 packet_data[32];
Damjan Marion650223c2018-11-14 16:55:53 +010066 u16 frame_flags;
67 ethernet_input_frame_t frame_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -070068} ethernet_input_trace_t;
69
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070070static u8 *
71format_ethernet_input_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
73 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
74 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070075 ethernet_input_trace_t *t = va_arg (*va, ethernet_input_trace_t *);
Damjan Marion650223c2018-11-14 16:55:53 +010076 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
Damjan Marion650223c2018-11-14 16:55:53 +010078 if (t->frame_flags)
79 {
80 s = format (s, "frame: flags 0x%x", t->frame_flags);
81 if (t->frame_flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
82 s = format (s, ", hw-if-index %u, sw-if-index %u",
83 t->frame_data.hw_if_index, t->frame_data.sw_if_index);
84 s = format (s, "\n%U", format_white_space, indent);
85 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 s = format (s, "%U", format_ethernet_header, t->packet_data);
87
88 return s;
89}
90
Damjan Marione849da22018-09-12 13:32:01 +020091extern vlib_node_registration_t ethernet_input_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -070092
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070093typedef enum
94{
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 ETHERNET_INPUT_VARIANT_ETHERNET,
96 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE,
Ed Warnickecb9cada2015-12-08 15:45:58 -070097 ETHERNET_INPUT_VARIANT_NOT_L2,
98} ethernet_input_variant_t;
99
100
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101// Parse the ethernet header to extract vlan tags and innermost ethertype
102static_always_inline void
103parse_header (ethernet_input_variant_t variant,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700104 vlib_buffer_t * b0,
105 u16 * type,
106 u16 * orig_type,
107 u16 * outer_id, u16 * inner_id, u32 * match_flags)
108{
Chris Luke194ebc52016-04-25 14:26:55 -0400109 u8 vlan_count;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700111 if (variant == ETHERNET_INPUT_VARIANT_ETHERNET
112 || variant == ETHERNET_INPUT_VARIANT_NOT_L2)
113 {
114 ethernet_header_t *e0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700116 e0 = (void *) (b0->data + b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117
Damjan Marion072401e2017-07-13 18:53:27 +0200118 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
Steven35de3b32017-12-03 23:40:54 -0800119 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700121 vlib_buffer_advance (b0, sizeof (e0[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700123 *type = clib_net_to_host_u16 (e0->type);
124 }
125 else if (variant == ETHERNET_INPUT_VARIANT_ETHERNET_TYPE)
126 {
127 // here when prior node was LLC/SNAP processing
128 u16 *e0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700130 e0 = (void *) (b0->data + b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700132 vlib_buffer_advance (b0, sizeof (e0[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700134 *type = clib_net_to_host_u16 (e0[0]);
135 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
137 // save for distinguishing between dot1q and dot1ad later
138 *orig_type = *type;
139
140 // default the tags to 0 (used if there is no corresponding tag)
141 *outer_id = 0;
142 *inner_id = 0;
143
144 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_0_TAG;
Chris Luke194ebc52016-04-25 14:26:55 -0400145 vlan_count = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
147 // check for vlan encaps
Damjan Marionb94bdad2016-09-19 11:32:03 +0200148 if (ethernet_frame_is_tagged (*type))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700149 {
150 ethernet_vlan_header_t *h0;
151 u16 tag;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700153 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_1_TAG;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154
155 h0 = (void *) (b0->data + b0->current_data);
156
157 tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
158
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700159 *outer_id = tag & 0xfff;
Neale Ranns30d0fd42017-05-30 07:30:04 -0700160 if (0 == *outer_id)
161 *match_flags &= ~SUBINT_CONFIG_MATCH_1_TAG;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700163 *type = clib_net_to_host_u16 (h0->type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
165 vlib_buffer_advance (b0, sizeof (h0[0]));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700166 vlan_count = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700168 if (*type == ETHERNET_TYPE_VLAN)
169 {
170 // Double tagged packet
171 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_2_TAG;
172
173 h0 = (void *) (b0->data + b0->current_data);
174
175 tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
176
177 *inner_id = tag & 0xfff;
178
179 *type = clib_net_to_host_u16 (h0->type);
180
181 vlib_buffer_advance (b0, sizeof (h0[0]));
182 vlan_count = 2;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700183 if (*type == ETHERNET_TYPE_VLAN)
184 {
185 // More than double tagged packet
186 *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG;
Eyal Bari6f7ebf92017-06-13 12:09:37 +0300187
188 vlib_buffer_advance (b0, sizeof (h0[0]));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700189 vlan_count = 3; // "unknown" number, aka, 3-or-more
190 }
191 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700193 ethernet_buffer_set_vlan_count (b0, vlan_count);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194}
195
196// Determine the subinterface for this packet, given the result of the
197// vlan table lookups and vlan header parsing. Check the most specific
198// matches first.
199static_always_inline void
200identify_subint (vnet_hw_interface_t * hi,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700201 vlib_buffer_t * b0,
202 u32 match_flags,
203 main_intf_t * main_intf,
204 vlan_intf_t * vlan_intf,
205 qinq_intf_t * qinq_intf,
206 u32 * new_sw_if_index, u8 * error0, u32 * is_l2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207{
208 u32 matched;
209
Damjan Marionddf6e082018-11-26 16:05:07 +0100210 matched = eth_identify_subint (hi, match_flags, main_intf, vlan_intf,
211 qinq_intf, new_sw_if_index, error0, is_l2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700213 if (matched)
214 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700216 // Perform L3 my-mac filter
217 // A unicast packet arriving on an L3 interface must have a dmac matching the interface mac.
218 // This is required for promiscuous mode, else we will forward packets we aren't supposed to.
219 if (!(*is_l2))
220 {
221 ethernet_header_t *e0;
Damjan Marion072401e2017-07-13 18:53:27 +0200222 e0 = (void *) (b0->data + vnet_buffer (b0)->l2_hdr_offset);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700224 if (!(ethernet_address_cast (e0->dst_address)))
225 {
226 if (!eth_mac_equal ((u8 *) e0, hi->hw_address))
227 {
228 *error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
229 }
230 }
231 }
232
233 // Check for down subinterface
234 *error0 = (*new_sw_if_index) != ~0 ? (*error0) : ETHERNET_ERROR_DOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236}
237
238static_always_inline void
239determine_next_node (ethernet_main_t * em,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700240 ethernet_input_variant_t variant,
241 u32 is_l20,
242 u32 type0, vlib_buffer_t * b0, u8 * error0, u8 * next0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +0200244 vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
245 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
246
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700247 if (PREDICT_FALSE (*error0 != ETHERNET_ERROR_NONE))
248 {
249 // some error occurred
250 *next0 = ETHERNET_INPUT_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700252 else if (is_l20)
253 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700254 // record the L2 len and reset the buffer so the L2 header is preserved
John Lob14826e2018-04-18 15:52:23 -0400255 u32 eth_start = vnet_buffer (b0)->l2_hdr_offset;
256 vnet_buffer (b0)->l2.l2_len = b0->current_data - eth_start;
257 *next0 = em->l2_next;
Eyal Bari6f7ebf92017-06-13 12:09:37 +0300258 ASSERT (vnet_buffer (b0)->l2.l2_len ==
259 ethernet_buffer_header_size (b0));
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +0200260 vlib_buffer_advance (b0, -(vnet_buffer (b0)->l2.l2_len));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700261
262 // check for common IP/MPLS ethertypes
263 }
264 else if (type0 == ETHERNET_TYPE_IP4)
265 {
266 *next0 = em->l3_next.input_next_ip4;
267 }
268 else if (type0 == ETHERNET_TYPE_IP6)
269 {
270 *next0 = em->l3_next.input_next_ip6;
271 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800272 else if (type0 == ETHERNET_TYPE_MPLS)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700273 {
274 *next0 = em->l3_next.input_next_mpls;
275
276 }
277 else if (em->redirect_l3)
278 {
279 // L3 Redirect is on, the cached common next nodes will be
280 // pointing to the redirect node, catch the uncommon types here
281 *next0 = em->redirect_l3_next;
282 }
283 else
284 {
285 // uncommon ethertype, check table
286 u32 i0;
287 i0 = sparse_vec_index (em->l3_next.input_next_by_type, type0);
288 *next0 = vec_elt (em->l3_next.input_next_by_type, i0);
289 *error0 =
290 i0 ==
291 SPARSE_VEC_INVALID_INDEX ? ETHERNET_ERROR_UNKNOWN_TYPE : *error0;
292
293 // The table is not populated with LLC values, so check that now.
Damjan Marion607de1a2016-08-16 22:53:54 +0200294 // If variant is variant_ethernet then we came from LLC processing. Don't
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700295 // go back there; drop instead using by keeping the drop/bad table result.
296 if ((type0 < 0x600) && (variant == ETHERNET_INPUT_VARIANT_ETHERNET))
297 {
298 *next0 = ETHERNET_INPUT_NEXT_LLC;
299 }
300 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301}
302
Damjan Marion650223c2018-11-14 16:55:53 +0100303
304/* following vector code relies on following assumptions */
305STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_data, 0);
306STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_length, 2);
307STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, flags, 4);
308STATIC_ASSERT (STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l2_hdr_offset) ==
309 STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l3_hdr_offset) - 2,
310 "l3_hdr_offset must follow l2_hdr_offset");
311
312static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100313eth_input_adv_and_flags_x4 (vlib_buffer_t ** b, int is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +0100314{
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100315 i16 adv = sizeof (ethernet_header_t);
316 u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
317 VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
318
Damjan Marion650223c2018-11-14 16:55:53 +0100319#ifdef CLIB_HAVE_VEC256
320 /* to reduce number of small loads/stores we are loading first 64 bits
321 of each buffer metadata into 256-bit register so we can advance
322 current_data, current_length and flags.
323 Observed saving of this code is ~2 clocks per packet */
324 u64x4 r, radv;
325
326 /* vector if signed 16 bit integers used in signed vector add operation
327 to advnce current_data and current_length */
328 u32x8 flags4 = { 0, flags, 0, flags, 0, flags, 0, flags };
329 i16x16 adv4 = {
330 adv, -adv, 0, 0, adv, -adv, 0, 0,
331 adv, -adv, 0, 0, adv, -adv, 0, 0
332 };
333
334 /* load 4 x 64 bits */
335 r = u64x4_gather (b[0], b[1], b[2], b[3]);
336
337 /* set flags */
338 r |= (u64x4) flags4;
339
340 /* advance buffer */
341 radv = (u64x4) ((i16x16) r + adv4);
342
343 /* write 4 x 64 bits */
344 u64x4_scatter (is_l3 ? radv : r, b[0], b[1], b[2], b[3]);
345
346 /* use old current_data as l2_hdr_offset and new current_data as
347 l3_hdr_offset */
348 r = (u64x4) u16x16_blend (r, radv << 16, 0xaa);
349
350 /* store both l2_hdr_offset and l3_hdr_offset in single store operation */
351 u32x8_scatter_one ((u32x8) r, 0, &vnet_buffer (b[0])->l2_hdr_offset);
352 u32x8_scatter_one ((u32x8) r, 2, &vnet_buffer (b[1])->l2_hdr_offset);
353 u32x8_scatter_one ((u32x8) r, 4, &vnet_buffer (b[2])->l2_hdr_offset);
354 u32x8_scatter_one ((u32x8) r, 6, &vnet_buffer (b[3])->l2_hdr_offset);
355
Damjan Marione9cebdf2018-11-21 00:47:42 +0100356 if (is_l3)
357 {
358 ASSERT (b[0]->current_data == vnet_buffer (b[0])->l3_hdr_offset);
359 ASSERT (b[1]->current_data == vnet_buffer (b[1])->l3_hdr_offset);
360 ASSERT (b[2]->current_data == vnet_buffer (b[2])->l3_hdr_offset);
361 ASSERT (b[3]->current_data == vnet_buffer (b[3])->l3_hdr_offset);
Damjan Marion650223c2018-11-14 16:55:53 +0100362
Damjan Marione9cebdf2018-11-21 00:47:42 +0100363 ASSERT (b[0]->current_data - vnet_buffer (b[0])->l2_hdr_offset == adv);
364 ASSERT (b[1]->current_data - vnet_buffer (b[1])->l2_hdr_offset == adv);
365 ASSERT (b[2]->current_data - vnet_buffer (b[2])->l2_hdr_offset == adv);
366 ASSERT (b[3]->current_data - vnet_buffer (b[3])->l2_hdr_offset == adv);
367 }
368 else
369 {
370 ASSERT (b[0]->current_data == vnet_buffer (b[0])->l2_hdr_offset);
371 ASSERT (b[1]->current_data == vnet_buffer (b[1])->l2_hdr_offset);
372 ASSERT (b[2]->current_data == vnet_buffer (b[2])->l2_hdr_offset);
373 ASSERT (b[3]->current_data == vnet_buffer (b[3])->l2_hdr_offset);
374
375 ASSERT (b[0]->current_data - vnet_buffer (b[0])->l3_hdr_offset == -adv);
376 ASSERT (b[1]->current_data - vnet_buffer (b[1])->l3_hdr_offset == -adv);
377 ASSERT (b[2]->current_data - vnet_buffer (b[2])->l3_hdr_offset == -adv);
378 ASSERT (b[3]->current_data - vnet_buffer (b[3])->l3_hdr_offset == -adv);
379 }
Damjan Marion650223c2018-11-14 16:55:53 +0100380
381#else
382 vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
383 vnet_buffer (b[1])->l2_hdr_offset = b[1]->current_data;
384 vnet_buffer (b[2])->l2_hdr_offset = b[2]->current_data;
385 vnet_buffer (b[3])->l2_hdr_offset = b[3]->current_data;
386 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
387 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data + adv;
388 vnet_buffer (b[2])->l3_hdr_offset = b[2]->current_data + adv;
389 vnet_buffer (b[3])->l3_hdr_offset = b[3]->current_data + adv;
390
391 if (is_l3)
392 {
393 vlib_buffer_advance (b[0], adv);
394 vlib_buffer_advance (b[1], adv);
395 vlib_buffer_advance (b[2], adv);
396 vlib_buffer_advance (b[3], adv);
397 }
398
399 b[0]->flags |= flags;
400 b[1]->flags |= flags;
401 b[2]->flags |= flags;
402 b[3]->flags |= flags;
403#endif
404
405 if (!is_l3)
406 {
407 vnet_buffer (b[0])->l2.l2_len = adv;
408 vnet_buffer (b[1])->l2.l2_len = adv;
409 vnet_buffer (b[2])->l2.l2_len = adv;
410 vnet_buffer (b[3])->l2.l2_len = adv;
411 }
412}
413
414static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100415eth_input_adv_and_flags_x1 (vlib_buffer_t ** b, int is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +0100416{
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100417 i16 adv = sizeof (ethernet_header_t);
418 u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
419 VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
420
Damjan Marion650223c2018-11-14 16:55:53 +0100421 vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
422 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
423
424 if (is_l3)
425 vlib_buffer_advance (b[0], adv);
426 b[0]->flags |= flags;
427 if (!is_l3)
428 vnet_buffer (b[0])->l2.l2_len = adv;
429}
430
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100431
Damjan Marion650223c2018-11-14 16:55:53 +0100432static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100433eth_input_get_etype_and_tags (vlib_buffer_t ** b, u16 * etype, u64 * tags,
434 u64 * dmacs, int offset, int dmac_check)
Damjan Marion650223c2018-11-14 16:55:53 +0100435{
Damjan Marion650223c2018-11-14 16:55:53 +0100436 ethernet_header_t *e;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100437 e = vlib_buffer_get_current (b[offset]);
438#ifdef CLIB_HAVE_VEC128
439 u64x2 r = u64x2_load_unaligned (((u8 *) & e->type) - 6);
440 etype[offset] = ((u16x8) r)[3];
441 tags[offset] = r[1];
442#else
443 etype[offset] = e->type;
444 tags[offset] = *(u64 *) (e + 1);
445#endif
Damjan Marion650223c2018-11-14 16:55:53 +0100446
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100447 if (dmac_check)
448 dmacs[offset] = *(u64 *) e;
449}
Damjan Marion650223c2018-11-14 16:55:53 +0100450
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100451static_always_inline u16
452eth_input_next_by_type (u16 etype)
453{
454 ethernet_main_t *em = &ethernet_main;
455
456 return (etype < 0x600) ? ETHERNET_INPUT_NEXT_LLC :
457 vec_elt (em->l3_next.input_next_by_type,
458 sparse_vec_index (em->l3_next.input_next_by_type, etype));
459}
460
461typedef struct
462{
463 u64 tag, mask;
464 u32 sw_if_index;
465 u16 type, len, next;
466 i16 adv;
467 u8 err, n_tags;
468 u64 n_packets, n_bytes;
469} eth_input_tag_lookup_t;
470
471static_always_inline void
472eth_input_update_if_counters (vlib_main_t * vm, vnet_main_t * vnm,
473 eth_input_tag_lookup_t * l)
474{
475 if (l->n_packets == 0 || l->sw_if_index == ~0)
476 return;
477
478 if (l->adv > 0)
479 l->n_bytes += l->n_packets * l->len;
480
481 vlib_increment_combined_counter
482 (vnm->interface_main.combined_sw_if_counters +
483 VNET_INTERFACE_COUNTER_RX, vm->thread_index, l->sw_if_index,
484 l->n_packets, l->n_bytes);
485}
486
487static_always_inline void
488eth_input_tag_lookup (vlib_main_t * vm, vnet_main_t * vnm,
489 vlib_node_runtime_t * node, vnet_hw_interface_t * hi,
490 u64 tag, u16 * next, vlib_buffer_t * b,
491 eth_input_tag_lookup_t * l, u8 dmac_bad, int is_dot1ad,
492 int main_is_l3, int check_dmac)
493{
494 ethernet_main_t *em = &ethernet_main;
495
496 if ((tag ^ l->tag) & l->mask)
Damjan Marion650223c2018-11-14 16:55:53 +0100497 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100498 main_intf_t *mif = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
499 vlan_intf_t *vif;
500 qinq_intf_t *qif;
501 vlan_table_t *vlan_table;
502 qinq_table_t *qinq_table;
503 u16 *t = (u16 *) & tag;
504 u16 vlan1 = clib_net_to_host_u16 (t[0]) & 0xFFF;
505 u16 vlan2 = clib_net_to_host_u16 (t[2]) & 0xFFF;
506 u32 matched, is_l2, new_sw_if_index;
507
508 vlan_table = vec_elt_at_index (em->vlan_pool, is_dot1ad ?
509 mif->dot1ad_vlans : mif->dot1q_vlans);
510 vif = &vlan_table->vlans[vlan1];
511 qinq_table = vec_elt_at_index (em->qinq_pool, vif->qinqs);
512 qif = &qinq_table->vlans[vlan2];
513 l->err = ETHERNET_ERROR_NONE;
514 l->type = clib_net_to_host_u16 (t[1]);
515
516 if (l->type == ETHERNET_TYPE_VLAN)
517 {
518 l->type = clib_net_to_host_u16 (t[3]);
519 l->n_tags = 2;
520 matched = eth_identify_subint (hi, SUBINT_CONFIG_VALID |
521 SUBINT_CONFIG_MATCH_2_TAG, mif, vif,
522 qif, &new_sw_if_index, &l->err,
523 &is_l2);
524 }
525 else
526 {
527 l->n_tags = 1;
528 if (vlan1 == 0)
529 {
530 new_sw_if_index = hi->sw_if_index;
531 l->err = ETHERNET_ERROR_NONE;
532 matched = 1;
533 is_l2 = main_is_l3 == 0;
534 }
535 else
536 matched = eth_identify_subint (hi, SUBINT_CONFIG_VALID |
537 SUBINT_CONFIG_MATCH_1_TAG, mif,
538 vif, qif, &new_sw_if_index,
539 &l->err, &is_l2);
540 }
541
542 if (l->sw_if_index != new_sw_if_index)
543 {
544 eth_input_update_if_counters (vm, vnm, l);
545 l->n_packets = 0;
546 l->n_bytes = 0;
547 l->sw_if_index = new_sw_if_index;
548 }
549 l->tag = tag;
550 l->mask = (l->n_tags == 2) ?
551 clib_net_to_host_u64 (0xffffffffffffffff) :
552 clib_net_to_host_u64 (0xffffffff00000000);
553
554 if (matched && l->sw_if_index == ~0)
555 l->err = ETHERNET_ERROR_DOWN;
556
557 l->len = sizeof (ethernet_header_t) +
558 l->n_tags * sizeof (ethernet_vlan_header_t);
559 if (main_is_l3)
560 l->adv = is_l2 ? -(int) sizeof (ethernet_header_t) :
561 l->n_tags * sizeof (ethernet_vlan_header_t);
562 else
563 l->adv = is_l2 ? 0 : l->len;
564
565 if (PREDICT_FALSE (l->err != ETHERNET_ERROR_NONE))
566 l->next = ETHERNET_INPUT_NEXT_DROP;
567 else if (is_l2)
568 l->next = em->l2_next;
569 else if (l->type == ETHERNET_TYPE_IP4)
570 l->next = em->l3_next.input_next_ip4;
571 else if (l->type == ETHERNET_TYPE_IP6)
572 l->next = em->l3_next.input_next_ip6;
573 else if (l->type == ETHERNET_TYPE_MPLS)
574 l->next = em->l3_next.input_next_mpls;
575 else if (em->redirect_l3)
576 l->next = em->redirect_l3_next;
577 else
578 {
579 l->next = eth_input_next_by_type (l->type);
580 if (l->next == ETHERNET_INPUT_NEXT_PUNT)
581 l->err = ETHERNET_ERROR_UNKNOWN_TYPE;
582 }
583 }
584
585 if (check_dmac && l->adv > 0 && dmac_bad)
586 {
587 l->err = ETHERNET_ERROR_L3_MAC_MISMATCH;
588 next[0] = ETHERNET_INPUT_NEXT_PUNT;
589 }
590 else
591 next[0] = l->next;
592
593 vlib_buffer_advance (b, l->adv);
594 vnet_buffer (b)->l2.l2_len = l->len;
595 vnet_buffer (b)->l3_hdr_offset = vnet_buffer (b)->l2_hdr_offset + l->len;
596
597 if (l->err == ETHERNET_ERROR_NONE)
598 {
599 vnet_buffer (b)->sw_if_index[VLIB_RX] = l->sw_if_index;
600 ethernet_buffer_set_vlan_count (b, l->n_tags);
601 }
602 else
603 b->error = node->errors[l->err];
604
605 /* update counters */
606 l->n_packets += 1;
607 l->n_bytes += vlib_buffer_length_in_chain (vm, b);
608}
609
610/* process frame of buffers, store ethertype into array and update
611 buffer metadata fields depending on interface being l2 or l3 assuming that
612 packets are untagged. For tagged packets those fields are updated later.
613 Optionally store Destionation MAC address and tag data into arrays
614 for further processing */
615
616STATIC_ASSERT (VLIB_FRAME_SIZE % 8 == 0,
617 "VLIB_FRAME_SIZE must be power of 8");
618static_always_inline void
619eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
620 vnet_hw_interface_t * hi,
621 u32 * buffer_indices, u32 n_packets, int main_is_l3,
622 int ip4_cksum_ok, int dmac_check)
623{
624 ethernet_main_t *em = &ethernet_main;
625 u16 nexts[VLIB_FRAME_SIZE], *next;
626 u16 etypes[VLIB_FRAME_SIZE], *etype = etypes;
627 u64 dmacs[VLIB_FRAME_SIZE], *dmac = dmacs;
628 u8 dmacs_bad[VLIB_FRAME_SIZE];
629 u64 tags[VLIB_FRAME_SIZE], *tag = tags;
630 u16 slowpath_indices[VLIB_FRAME_SIZE];
631 u16 n_slowpath, i;
632 u16 next_ip4, next_ip6, next_mpls, next_l2;
633 u16 et_ip4 = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
634 u16 et_ip6 = clib_host_to_net_u16 (ETHERNET_TYPE_IP6);
635 u16 et_mpls = clib_host_to_net_u16 (ETHERNET_TYPE_MPLS);
636 u16 et_vlan = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
637 u16 et_dot1ad = clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD);
638 i32 n_left = n_packets;
639 vlib_buffer_t *b[20];
640 u32 *from;
641
642 from = buffer_indices;
643
644 while (n_left >= 20)
645 {
646 vlib_buffer_t **ph = b + 16, **pd = b + 8;
Damjan Marion650223c2018-11-14 16:55:53 +0100647 vlib_get_buffers (vm, from, b, 4);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100648 vlib_get_buffers (vm, from + 8, pd, 4);
649 vlib_get_buffers (vm, from + 16, ph, 4);
Damjan Marion650223c2018-11-14 16:55:53 +0100650
651 vlib_prefetch_buffer_header (ph[0], LOAD);
652 vlib_prefetch_buffer_data (pd[0], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100653 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100654
655 vlib_prefetch_buffer_header (ph[1], LOAD);
656 vlib_prefetch_buffer_data (pd[1], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100657 eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100658
659 vlib_prefetch_buffer_header (ph[2], LOAD);
660 vlib_prefetch_buffer_data (pd[2], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100661 eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100662
663 vlib_prefetch_buffer_header (ph[3], LOAD);
664 vlib_prefetch_buffer_data (pd[3], LOAD);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100665 eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
Damjan Marion650223c2018-11-14 16:55:53 +0100666
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100667 eth_input_adv_and_flags_x4 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100668
669 /* next */
670 n_left -= 4;
671 etype += 4;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100672 tag += 4;
673 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100674 from += 4;
675 }
676 while (n_left >= 4)
677 {
678 vlib_get_buffers (vm, from, b, 4);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100679 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
680 eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
681 eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
682 eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
683 eth_input_adv_and_flags_x4 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100684
685 /* next */
686 n_left -= 4;
687 etype += 4;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100688 tag += 4;
689 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100690 from += 4;
691 }
692 while (n_left)
693 {
694 vlib_get_buffers (vm, from, b, 1);
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100695 eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
696 eth_input_adv_and_flags_x1 (b, main_is_l3);
Damjan Marion650223c2018-11-14 16:55:53 +0100697
698 /* next */
699 n_left -= 1;
700 etype += 1;
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100701 tag += 1;
702 dmac += 4;
Damjan Marion650223c2018-11-14 16:55:53 +0100703 from += 1;
704 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100705
706 if (dmac_check)
707 {
708 u64 mask = clib_net_to_host_u64 (0xFFFFFFFFFFFF0000);
709 u64 igbit = clib_net_to_host_u64 (0x0100000000000000);
710 u64 hwaddr = (*(u64 *) hi->hw_address) & mask;
711 u64 *dmac = dmacs;
712 u8 *dmac_bad = dmacs_bad;
713
714 n_left = n_packets;
715
716#ifdef CLIB_HAVE_VEC256
717 u64x4 igbit4 = u64x4_splat (igbit);
718 u64x4 mask4 = u64x4_splat (mask);
719 u64x4 hwaddr4 = u64x4_splat (hwaddr);
720 while (n_left >= 0)
721 {
722 u64x4 r0, r1;
723 r0 = u64x4_load_unaligned (dmac + 0) & mask4;
724 r1 = u64x4_load_unaligned (dmac + 4) & mask4;
725
726 r0 = (r0 != hwaddr4) & ((r0 & igbit4) == 0);
727 r1 = (r1 != hwaddr4) & ((r1 & igbit4) == 0);
728
729 *(u32 *) (dmac_bad + 0) = u8x32_msb_mask ((u8x32) (r0));
730 *(u32 *) (dmac_bad + 4) = u8x32_msb_mask ((u8x32) (r1));
731
732 /* next */
733 dmac += 8;
734 dmac_bad += 8;
735 n_left -= 8;
736 }
737#else
738 while (n_left > 0)
739 {
740 u64 r0, r1, r2, r3;
741 r0 = dmac[0] & mask;
742 r1 = dmac[1] & mask;
743 r2 = dmac[2] & mask;
744 r3 = dmac[3] & mask;
745
746 r0 = (r0 != hwaddr) && ((r0 & igbit) == 0);
747 r1 = (r1 != hwaddr) && ((r1 & igbit) == 0);
748 r2 = (r2 != hwaddr) && ((r2 & igbit) == 0);
749 r3 = (r3 != hwaddr) && ((r3 & igbit) == 0);
750
751 dmac_bad[0] = r0;
752 dmac_bad[1] = r1;
753 dmac_bad[2] = r2;
754 dmac_bad[3] = r3;
755
756 /* next */
757 dmac += 4;
758 dmac_bad += 4;
759 n_left -= 4;
760 }
761#endif
762 }
763
764 next_ip4 = em->l3_next.input_next_ip4;
765 next_ip6 = em->l3_next.input_next_ip6;
766 next_mpls = em->l3_next.input_next_mpls;
767 next_l2 = em->l2_next;
768
769 if (next_ip4 == ETHERNET_INPUT_NEXT_IP4_INPUT && ip4_cksum_ok)
770 next_ip4 = ETHERNET_INPUT_NEXT_IP4_INPUT_NCS;
771
772#ifdef CLIB_HAVE_VEC256
773 u16x16 et16_ip4 = u16x16_splat (et_ip4);
774 u16x16 et16_ip6 = u16x16_splat (et_ip6);
775 u16x16 et16_mpls = u16x16_splat (et_mpls);
776 u16x16 et16_vlan = u16x16_splat (et_vlan);
777 u16x16 et16_dot1ad = u16x16_splat (et_dot1ad);
778 u16x16 next16_ip4 = u16x16_splat (next_ip4);
779 u16x16 next16_ip6 = u16x16_splat (next_ip6);
780 u16x16 next16_mpls = u16x16_splat (next_mpls);
781 u16x16 next16_l2 = u16x16_splat (next_l2);
782 u16x16 zero = { 0 };
783 u16x16 stairs = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
784#endif
785
786 etype = etypes;
787 n_left = n_packets;
788 next = nexts;
789 n_slowpath = 0;
790 i = 0;
791
792 /* fastpath - in l3 mode hadles ip4, ip6 and mpls packets, other packets
793 are considered as slowpath, in l2 mode all untagged packets are
794 considered as fastpath */
795 while (n_left > 0)
796 {
797#ifdef CLIB_HAVE_VEC256
798 if (n_left >= 16)
799 {
800 u16x16 r = zero;
801 u16x16 e16 = u16x16_load_unaligned (etype);
802 if (main_is_l3)
803 {
804 r += (e16 == et16_ip4) & next16_ip4;
805 r += (e16 == et16_ip6) & next16_ip6;
806 r += (e16 == et16_mpls) & next16_mpls;
807 }
808 else
809 r = ((e16 != et16_vlan) & (e16 != et16_dot1ad)) & next16_l2;
810 u16x16_store_unaligned (r, next);
811
812 if (!u16x16_is_all_zero (r == zero))
813 {
814 if (u16x16_is_all_zero (r))
815 {
816 u16x16_store_unaligned (u16x16_splat (i) + stairs,
817 slowpath_indices + n_slowpath);
818 n_slowpath += 16;
819 }
820 else
821 {
822 for (int j = 0; j < 16; j++)
823 if (next[j] == 0)
824 slowpath_indices[n_slowpath++] = i + j;
825 }
826 }
827
828 etype += 16;
829 next += 16;
830 n_left -= 16;
831 i += 16;
832 continue;
833 }
834#endif
835 if (main_is_l3 && etype[0] == et_ip4)
836 next[0] = next_ip4;
837 else if (main_is_l3 && etype[0] == et_ip6)
838 next[0] = next_ip6;
839 else if (main_is_l3 && etype[0] == et_mpls)
840 next[0] = next_mpls;
841 else if (main_is_l3 == 0 &&
842 etype[0] != et_vlan && etype[0] != et_dot1ad)
843 next[0] = next_l2;
844 else
845 {
846 next[0] = 0;
847 slowpath_indices[n_slowpath++] = i;
848 }
849
850 etype += 1;
851 next += 1;
852 n_left -= 1;
853 i += 1;
854 }
855
856 if (n_slowpath)
857 {
858 vnet_main_t *vnm = vnet_get_main ();
859 n_left = n_slowpath;
860 u16 *si = slowpath_indices;
861 u32 last_unknown_etype = ~0;
862 u32 last_unknown_next = ~0;
863 eth_input_tag_lookup_t dot1ad_lookup, dot1q_lookup = {
864 .mask = -1LL,
865 .tag = tags[si[0]] ^ -1LL,
866 .sw_if_index = ~0
867 };
868
869 clib_memcpy_fast (&dot1ad_lookup, &dot1q_lookup, sizeof (dot1q_lookup));
870
871 while (n_left)
872 {
873 i = si[0];
874 u16 etype = etypes[i];
875
876 if (etype == et_vlan)
877 {
878 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
879 eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
880 &dot1q_lookup, dmacs_bad[i], 0,
881 main_is_l3, dmac_check);
882
883 }
884 else if (etype == et_dot1ad)
885 {
886 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
887 eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
888 &dot1ad_lookup, dmacs_bad[i], 1,
889 main_is_l3, dmac_check);
890 }
891 else
892 {
893 /* untagged packet with not well known etyertype */
894 if (last_unknown_etype != etype)
895 {
896 last_unknown_etype = etype;
897 etype = clib_host_to_net_u16 (etype);
898 last_unknown_next = eth_input_next_by_type (etype);
899 }
900 if (dmac_check && main_is_l3 && dmacs_bad[i])
901 {
902 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
903 b->error = node->errors[ETHERNET_ERROR_L3_MAC_MISMATCH];
904 nexts[i] = ETHERNET_INPUT_NEXT_PUNT;
905 }
906 else
907 nexts[i] = last_unknown_next;
908 }
909
910 /* next */
911 n_left--;
912 si++;
913 }
914
915 eth_input_update_if_counters (vm, vnm, &dot1q_lookup);
916 eth_input_update_if_counters (vm, vnm, &dot1ad_lookup);
917 }
918
919 vlib_buffer_enqueue_to_next (vm, node, buffer_indices, nexts, n_packets);
Damjan Marion650223c2018-11-14 16:55:53 +0100920}
921
922static_always_inline void
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100923eth_input_single_int (vlib_main_t * vm, vlib_node_runtime_t * node,
924 vnet_hw_interface_t * hi, u32 * from, u32 n_pkts,
925 int ip4_cksum_ok)
Damjan Marion650223c2018-11-14 16:55:53 +0100926{
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100927 ethernet_main_t *em = &ethernet_main;
928 ethernet_interface_t *ei;
929 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
930 main_intf_t *intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
931 subint_config_t *subint0 = &intf0->untagged_subint;
Damjan Marion650223c2018-11-14 16:55:53 +0100932
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100933 int main_is_l3 = (subint0->flags & SUBINT_CONFIG_L2) == 0;
934 int promisc = (ei->flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL) != 0;
Damjan Marion650223c2018-11-14 16:55:53 +0100935
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100936 if (main_is_l3)
Damjan Marion650223c2018-11-14 16:55:53 +0100937 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100938 /* main interface is L3, we dont expect tagged packets and interface
939 is not in promisc node, so we dont't need to check DMAC */
940 int is_l3 = 1;
Damjan Marion650223c2018-11-14 16:55:53 +0100941
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100942 if (promisc == 0)
943 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
944 ip4_cksum_ok, 0);
Damjan Marion650223c2018-11-14 16:55:53 +0100945 else
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100946 /* subinterfaces and promisc mode so DMAC check is needed */
947 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
948 ip4_cksum_ok, 1);
949 return;
Damjan Marion650223c2018-11-14 16:55:53 +0100950 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100951 else
Damjan Marion650223c2018-11-14 16:55:53 +0100952 {
Damjan Marion8d6f34e2018-11-25 21:19:13 +0100953 /* untagged packets are treated as L2 */
954 int is_l3 = 0;
955 eth_input_process_frame (vm, node, hi, from, n_pkts, is_l3,
956 ip4_cksum_ok, 1);
957 return;
Damjan Marion650223c2018-11-14 16:55:53 +0100958 }
959}
960
961static_always_inline void
962ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
963 vlib_frame_t * from_frame)
964{
965 u32 *from, n_left;
966 if ((node->flags & VLIB_NODE_FLAG_TRACE) == 0)
967 return;
968
969 from = vlib_frame_vector_args (from_frame);
970 n_left = from_frame->n_vectors;
971
972 while (n_left)
973 {
974 ethernet_input_trace_t *t0;
975 vlib_buffer_t *b0 = vlib_get_buffer (vm, from[0]);
976
977 if (b0->flags & VLIB_BUFFER_IS_TRACED)
978 {
979 t0 = vlib_add_trace (vm, node, b0, sizeof (ethernet_input_trace_t));
980 clib_memcpy_fast (t0->packet_data, b0->data + b0->current_data,
981 sizeof (t0->packet_data));
982 t0->frame_flags = from_frame->flags;
983 clib_memcpy_fast (&t0->frame_data,
984 vlib_frame_scalar_args (from_frame),
985 sizeof (ethernet_input_frame_t));
986 }
987 from += 1;
988 n_left -= 1;
989 }
990}
991
992static_always_inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993ethernet_input_inline (vlib_main_t * vm,
994 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +0100995 u32 * from, u32 n_packets,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700996 ethernet_input_variant_t variant)
997{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700998 vnet_main_t *vnm = vnet_get_main ();
999 ethernet_main_t *em = &ethernet_main;
1000 vlib_node_runtime_t *error_node;
Damjan Marion650223c2018-11-14 16:55:53 +01001001 u32 n_left_from, next_index, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001002 u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
Damjan Marion067cd622018-07-11 12:47:43 +02001003 u32 thread_index = vm->thread_index;
Dave Barachcfba1e22016-11-16 10:23:50 -05001004 u32 cached_sw_if_index = ~0;
1005 u32 cached_is_l2 = 0; /* shut up gcc */
John Lo1904c472017-03-10 17:15:22 -05001006 vnet_hw_interface_t *hi = NULL; /* used for main interface only */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007
1008 if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
1009 error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
1010 else
1011 error_node = node;
1012
Damjan Marion650223c2018-11-14 16:55:53 +01001013 n_left_from = n_packets;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014
1015 next_index = node->cached_next_index;
1016 stats_sw_if_index = node->runtime_data[0];
1017 stats_n_packets = stats_n_bytes = 0;
1018
1019 while (n_left_from > 0)
1020 {
1021 u32 n_left_to_next;
1022
1023 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1024
1025 while (n_left_from >= 4 && n_left_to_next >= 2)
1026 {
1027 u32 bi0, bi1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001028 vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029 u8 next0, next1, error0, error1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001030 u16 type0, orig_type0, type1, orig_type1;
1031 u16 outer_id0, inner_id0, outer_id1, inner_id1;
1032 u32 match_flags0, match_flags1;
1033 u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1,
1034 new_sw_if_index1, len1;
1035 vnet_hw_interface_t *hi0, *hi1;
1036 main_intf_t *main_intf0, *main_intf1;
1037 vlan_intf_t *vlan_intf0, *vlan_intf1;
1038 qinq_intf_t *qinq_intf0, *qinq_intf1;
1039 u32 is_l20, is_l21;
Dave Barachcfba1e22016-11-16 10:23:50 -05001040 ethernet_header_t *e0, *e1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041
1042 /* Prefetch next iteration. */
1043 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001044 vlib_buffer_t *b2, *b3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045
1046 b2 = vlib_get_buffer (vm, from[2]);
1047 b3 = vlib_get_buffer (vm, from[3]);
1048
1049 vlib_prefetch_buffer_header (b2, STORE);
1050 vlib_prefetch_buffer_header (b3, STORE);
1051
1052 CLIB_PREFETCH (b2->data, sizeof (ethernet_header_t), LOAD);
1053 CLIB_PREFETCH (b3->data, sizeof (ethernet_header_t), LOAD);
1054 }
1055
1056 bi0 = from[0];
1057 bi1 = from[1];
1058 to_next[0] = bi0;
1059 to_next[1] = bi1;
1060 from += 2;
1061 to_next += 2;
1062 n_left_to_next -= 2;
1063 n_left_from -= 2;
1064
1065 b0 = vlib_get_buffer (vm, bi0);
1066 b1 = vlib_get_buffer (vm, bi1);
1067
1068 error0 = error1 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001069 e0 = vlib_buffer_get_current (b0);
1070 type0 = clib_net_to_host_u16 (e0->type);
1071 e1 = vlib_buffer_get_current (b1);
1072 type1 = clib_net_to_host_u16 (e1->type);
1073
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001074 /* Set the L2 header offset for all packets */
1075 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1076 vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
1077 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1078 b1->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1079
John Locc532852016-12-14 15:42:45 -05001080 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001081 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
Damjan Marionc6969b52018-02-19 12:14:06 +01001082 && !ethernet_frame_is_any_tagged_x2 (type0,
1083 type1)))
Dave Barachcfba1e22016-11-16 10:23:50 -05001084 {
1085 main_intf_t *intf0;
1086 subint_config_t *subint0;
1087 u32 sw_if_index0, sw_if_index1;
1088
1089 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1090 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1091 is_l20 = cached_is_l2;
1092
1093 /* This is probably wholly unnecessary */
1094 if (PREDICT_FALSE (sw_if_index0 != sw_if_index1))
1095 goto slowpath;
1096
John Lo1904c472017-03-10 17:15:22 -05001097 /* Now sw_if_index0 == sw_if_index1 */
Dave Barachcfba1e22016-11-16 10:23:50 -05001098 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1099 {
1100 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001101 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1102 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001103 subint0 = &intf0->untagged_subint;
1104 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1105 }
John Lo7714b302016-12-20 16:59:02 -05001106
Dave Barachcfba1e22016-11-16 10:23:50 -05001107 if (PREDICT_TRUE (is_l20 != 0))
1108 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001109 vnet_buffer (b0)->l3_hdr_offset =
1110 vnet_buffer (b0)->l2_hdr_offset +
1111 sizeof (ethernet_header_t);
1112 vnet_buffer (b1)->l3_hdr_offset =
1113 vnet_buffer (b1)->l2_hdr_offset +
1114 sizeof (ethernet_header_t);
1115 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
1116 b1->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001117 next0 = em->l2_next;
1118 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001119 next1 = em->l2_next;
1120 vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001121 }
John Locc532852016-12-14 15:42:45 -05001122 else
1123 {
John Lo1904c472017-03-10 17:15:22 -05001124 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001125 (hi->hw_address != 0) &&
John Lo1904c472017-03-10 17:15:22 -05001126 !eth_mac_equal ((u8 *) e0, hi->hw_address))
1127 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
1128 if (!ethernet_address_cast (e1->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001129 (hi->hw_address != 0) &&
John Lo1904c472017-03-10 17:15:22 -05001130 !eth_mac_equal ((u8 *) e1, hi->hw_address))
1131 error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
John Lob14826e2018-04-18 15:52:23 -04001132 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001133 determine_next_node (em, variant, 0, type0, b0,
1134 &error0, &next0);
John Lob14826e2018-04-18 15:52:23 -04001135 vlib_buffer_advance (b1, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001136 determine_next_node (em, variant, 0, type1, b1,
1137 &error1, &next1);
John Locc532852016-12-14 15:42:45 -05001138 }
1139 goto ship_it01;
Dave Barachcfba1e22016-11-16 10:23:50 -05001140 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
John Locc532852016-12-14 15:42:45 -05001142 /* Slow-path for the tagged case */
1143 slowpath:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001144 parse_header (variant,
1145 b0,
1146 &type0,
1147 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001149 parse_header (variant,
1150 b1,
1151 &type1,
1152 &orig_type1, &outer_id1, &inner_id1, &match_flags1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001154 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1155 old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001157 eth_vlan_table_lookups (em,
1158 vnm,
1159 old_sw_if_index0,
1160 orig_type0,
1161 outer_id0,
1162 inner_id0,
1163 &hi0,
1164 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001166 eth_vlan_table_lookups (em,
1167 vnm,
1168 old_sw_if_index1,
1169 orig_type1,
1170 outer_id1,
1171 inner_id1,
1172 &hi1,
1173 &main_intf1, &vlan_intf1, &qinq_intf1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
1175 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001176 b0,
1177 match_flags0,
1178 main_intf0,
1179 vlan_intf0,
1180 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
1182 identify_subint (hi1,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001183 b1,
1184 match_flags1,
1185 main_intf1,
1186 vlan_intf1,
1187 qinq_intf1, &new_sw_if_index1, &error1, &is_l21);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001189 // Save RX sw_if_index for later nodes
1190 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1191 error0 !=
1192 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
1193 vnet_buffer (b1)->sw_if_index[VLIB_RX] =
1194 error1 !=
1195 ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001196
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001197 // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
1198 if (((new_sw_if_index0 != ~0)
1199 && (new_sw_if_index0 != old_sw_if_index0))
1200 || ((new_sw_if_index1 != ~0)
1201 && (new_sw_if_index1 != old_sw_if_index1)))
1202 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001204 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001205 - vnet_buffer (b0)->l2_hdr_offset;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001206 len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001207 - vnet_buffer (b1)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001209 stats_n_packets += 2;
1210 stats_n_bytes += len0 + len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001212 if (PREDICT_FALSE
1213 (!(new_sw_if_index0 == stats_sw_if_index
1214 && new_sw_if_index1 == stats_sw_if_index)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215 {
1216 stats_n_packets -= 2;
1217 stats_n_bytes -= len0 + len1;
1218
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001219 if (new_sw_if_index0 != old_sw_if_index0
1220 && new_sw_if_index0 != ~0)
1221 vlib_increment_combined_counter (vnm->
1222 interface_main.combined_sw_if_counters
1223 +
1224 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001225 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001226 new_sw_if_index0, 1,
1227 len0);
1228 if (new_sw_if_index1 != old_sw_if_index1
1229 && new_sw_if_index1 != ~0)
1230 vlib_increment_combined_counter (vnm->
1231 interface_main.combined_sw_if_counters
1232 +
1233 VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001234 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001235 new_sw_if_index1, 1,
1236 len1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237
1238 if (new_sw_if_index0 == new_sw_if_index1)
1239 {
1240 if (stats_n_packets > 0)
1241 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001242 vlib_increment_combined_counter
1243 (vnm->interface_main.combined_sw_if_counters
1244 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001245 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001246 stats_sw_if_index,
1247 stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001248 stats_n_packets = stats_n_bytes = 0;
1249 }
1250 stats_sw_if_index = new_sw_if_index0;
1251 }
1252 }
1253 }
1254
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001255 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1256 is_l20 = is_l21 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001257
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001258 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1259 &next0);
1260 determine_next_node (em, variant, is_l21, type1, b1, &error1,
1261 &next1);
1262
John Lo1904c472017-03-10 17:15:22 -05001263 ship_it01:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001264 b0->error = error_node->errors[error0];
1265 b1->error = error_node->errors[error1];
1266
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001267 // verify speculative enqueue
1268 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1269 n_left_to_next, bi0, bi1, next0,
1270 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271 }
1272
1273 while (n_left_from > 0 && n_left_to_next > 0)
1274 {
1275 u32 bi0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001276 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277 u8 error0, next0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001278 u16 type0, orig_type0;
1279 u16 outer_id0, inner_id0;
1280 u32 match_flags0;
1281 u32 old_sw_if_index0, new_sw_if_index0, len0;
1282 vnet_hw_interface_t *hi0;
1283 main_intf_t *main_intf0;
1284 vlan_intf_t *vlan_intf0;
1285 qinq_intf_t *qinq_intf0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001286 ethernet_header_t *e0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001287 u32 is_l20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001288
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001289 // Prefetch next iteration
1290 if (n_left_from > 1)
1291 {
1292 vlib_buffer_t *p2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001294 p2 = vlib_get_buffer (vm, from[1]);
1295 vlib_prefetch_buffer_header (p2, STORE);
1296 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
1297 }
1298
1299 bi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001300 to_next[0] = bi0;
1301 from += 1;
1302 to_next += 1;
1303 n_left_from -= 1;
1304 n_left_to_next -= 1;
1305
1306 b0 = vlib_get_buffer (vm, bi0);
1307
1308 error0 = ETHERNET_ERROR_NONE;
Dave Barachcfba1e22016-11-16 10:23:50 -05001309 e0 = vlib_buffer_get_current (b0);
1310 type0 = clib_net_to_host_u16 (e0->type);
1311
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001312 /* Set the L2 header offset for all packets */
1313 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
1314 b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
1315
John Locc532852016-12-14 15:42:45 -05001316 /* Speed-path for the untagged case */
Dave Barachcfba1e22016-11-16 10:23:50 -05001317 if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
1318 && !ethernet_frame_is_tagged (type0)))
1319 {
1320 main_intf_t *intf0;
1321 subint_config_t *subint0;
1322 u32 sw_if_index0;
1323
1324 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1325 is_l20 = cached_is_l2;
1326
1327 if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
1328 {
1329 cached_sw_if_index = sw_if_index0;
John Lo1904c472017-03-10 17:15:22 -05001330 hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1331 intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Dave Barachcfba1e22016-11-16 10:23:50 -05001332 subint0 = &intf0->untagged_subint;
1333 cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
1334 }
John Lo7714b302016-12-20 16:59:02 -05001335
John Lo7714b302016-12-20 16:59:02 -05001336
Dave Barachcfba1e22016-11-16 10:23:50 -05001337 if (PREDICT_TRUE (is_l20 != 0))
1338 {
Andrew Yourtchenko20e6d362018-10-05 20:36:03 +02001339 vnet_buffer (b0)->l3_hdr_offset =
1340 vnet_buffer (b0)->l2_hdr_offset +
1341 sizeof (ethernet_header_t);
1342 b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
Dave Barachcfba1e22016-11-16 10:23:50 -05001343 next0 = em->l2_next;
1344 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
Dave Barachcfba1e22016-11-16 10:23:50 -05001345 }
John Locc532852016-12-14 15:42:45 -05001346 else
1347 {
John Lo1904c472017-03-10 17:15:22 -05001348 if (!ethernet_address_cast (e0->dst_address) &&
Hongjun Ni9e3e3612017-04-26 18:40:55 +08001349 (hi->hw_address != 0) &&
John Lo1904c472017-03-10 17:15:22 -05001350 !eth_mac_equal ((u8 *) e0, hi->hw_address))
1351 error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
Andrew Yourtchenkoe78bca12018-10-10 16:15:55 +02001352 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
John Locc532852016-12-14 15:42:45 -05001353 determine_next_node (em, variant, 0, type0, b0,
1354 &error0, &next0);
John Locc532852016-12-14 15:42:45 -05001355 }
1356 goto ship_it0;
Dave Barachcfba1e22016-11-16 10:23:50 -05001357 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001358
John Locc532852016-12-14 15:42:45 -05001359 /* Slow-path for the tagged case */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001360 parse_header (variant,
1361 b0,
1362 &type0,
1363 &orig_type0, &outer_id0, &inner_id0, &match_flags0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001365 old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001366
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001367 eth_vlan_table_lookups (em,
1368 vnm,
1369 old_sw_if_index0,
1370 orig_type0,
1371 outer_id0,
1372 inner_id0,
1373 &hi0,
1374 &main_intf0, &vlan_intf0, &qinq_intf0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001375
1376 identify_subint (hi0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001377 b0,
1378 match_flags0,
1379 main_intf0,
1380 vlan_intf0,
1381 qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001383 // Save RX sw_if_index for later nodes
1384 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1385 error0 !=
1386 ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001387
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001388 // Increment subinterface stats
1389 // Note that interface-level counters have already been incremented
1390 // prior to calling this function. Thus only subinterface counters
1391 // are incremented here.
1392 //
Damjan Marion607de1a2016-08-16 22:53:54 +02001393 // Interface level counters include packets received on the main
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001394 // interface and all subinterfaces. Subinterface level counters
1395 // include only those packets received on that subinterface
Ed Warnickecb9cada2015-12-08 15:45:58 -07001396 // Increment stats if the subint is valid and it is not the main intf
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001397 if ((new_sw_if_index0 != ~0)
1398 && (new_sw_if_index0 != old_sw_if_index0))
1399 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001401 len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
Damjan Marion072401e2017-07-13 18:53:27 +02001402 - vnet_buffer (b0)->l2_hdr_offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001404 stats_n_packets += 1;
1405 stats_n_bytes += len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001406
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001407 // Batch stat increments from the same subinterface so counters
Damjan Marion607de1a2016-08-16 22:53:54 +02001408 // don't need to be incremented for every packet.
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001409 if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index))
1410 {
1411 stats_n_packets -= 1;
1412 stats_n_bytes -= len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001414 if (new_sw_if_index0 != ~0)
1415 vlib_increment_combined_counter
1416 (vnm->interface_main.combined_sw_if_counters
1417 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001418 thread_index, new_sw_if_index0, 1, len0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001419 if (stats_n_packets > 0)
1420 {
1421 vlib_increment_combined_counter
1422 (vnm->interface_main.combined_sw_if_counters
1423 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001424 thread_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001425 stats_sw_if_index, stats_n_packets, stats_n_bytes);
1426 stats_n_packets = stats_n_bytes = 0;
1427 }
1428 stats_sw_if_index = new_sw_if_index0;
1429 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001431
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001432 if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
1433 is_l20 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001435 determine_next_node (em, variant, is_l20, type0, b0, &error0,
1436 &next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437
John Lo1904c472017-03-10 17:15:22 -05001438 ship_it0:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001439 b0->error = error_node->errors[error0];
1440
1441 // verify speculative enqueue
Ed Warnickecb9cada2015-12-08 15:45:58 -07001442 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1443 to_next, n_left_to_next,
1444 bi0, next0);
1445 }
1446
1447 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1448 }
1449
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001450 // Increment any remaining batched stats
1451 if (stats_n_packets > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001452 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001453 vlib_increment_combined_counter
1454 (vnm->interface_main.combined_sw_if_counters
1455 + VNET_INTERFACE_COUNTER_RX,
Damjan Marion586afd72017-04-05 19:18:20 +02001456 thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001457 node->runtime_data[0] = stats_sw_if_index;
1458 }
Damjan Marion650223c2018-11-14 16:55:53 +01001459}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001460
Damjan Marion5beecec2018-09-10 13:09:21 +02001461VLIB_NODE_FN (ethernet_input_node) (vlib_main_t * vm,
1462 vlib_node_runtime_t * node,
Damjan Marion650223c2018-11-14 16:55:53 +01001463 vlib_frame_t * frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001464{
Damjan Marion650223c2018-11-14 16:55:53 +01001465 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion650223c2018-11-14 16:55:53 +01001466 u32 *from = vlib_frame_vector_args (frame);
1467 u32 n_packets = frame->n_vectors;
1468
1469 ethernet_input_trace (vm, node, frame);
1470
1471 if (frame->flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
1472 {
Damjan Marion650223c2018-11-14 16:55:53 +01001473 ethernet_input_frame_t *ef = vlib_frame_scalar_args (frame);
Damjan Marion650223c2018-11-14 16:55:53 +01001474 int ip4_cksum_ok = (frame->flags & ETH_INPUT_FRAME_F_IP4_CKSUM_OK) != 0;
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001475 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ef->hw_if_index);
1476 eth_input_single_int (vm, node, hi, from, n_packets, ip4_cksum_ok);
Damjan Marion650223c2018-11-14 16:55:53 +01001477 }
Damjan Marion8d6f34e2018-11-25 21:19:13 +01001478 else
1479 ethernet_input_inline (vm, node, from, n_packets,
1480 ETHERNET_INPUT_VARIANT_ETHERNET);
Damjan Marion650223c2018-11-14 16:55:53 +01001481 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001482}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001483
Damjan Marion5beecec2018-09-10 13:09:21 +02001484VLIB_NODE_FN (ethernet_input_type_node) (vlib_main_t * vm,
1485 vlib_node_runtime_t * node,
1486 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001487{
Damjan Marion650223c2018-11-14 16:55:53 +01001488 u32 *from = vlib_frame_vector_args (from_frame);
1489 u32 n_packets = from_frame->n_vectors;
1490 ethernet_input_trace (vm, node, from_frame);
1491 ethernet_input_inline (vm, node, from, n_packets,
1492 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE);
1493 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001494}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001495
Damjan Marion5beecec2018-09-10 13:09:21 +02001496VLIB_NODE_FN (ethernet_input_not_l2_node) (vlib_main_t * vm,
1497 vlib_node_runtime_t * node,
1498 vlib_frame_t * from_frame)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001499{
Damjan Marion650223c2018-11-14 16:55:53 +01001500 u32 *from = vlib_frame_vector_args (from_frame);
1501 u32 n_packets = from_frame->n_vectors;
1502 ethernet_input_trace (vm, node, from_frame);
1503 ethernet_input_inline (vm, node, from, n_packets,
1504 ETHERNET_INPUT_VARIANT_NOT_L2);
1505 return n_packets;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001506}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001507
1508
1509// Return the subinterface config struct for the given sw_if_index
1510// Also return via parameter the appropriate match flags for the
1511// configured number of tags.
1512// On error (unsupported or not ethernet) return 0.
1513static subint_config_t *
1514ethernet_sw_interface_get_config (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001515 u32 sw_if_index,
1516 u32 * flags, u32 * unsupported)
1517{
1518 ethernet_main_t *em = &ethernet_main;
1519 vnet_hw_interface_t *hi;
1520 vnet_sw_interface_t *si;
1521 main_intf_t *main_intf;
1522 vlan_table_t *vlan_table;
1523 qinq_table_t *qinq_table;
1524 subint_config_t *subint = 0;
1525
Ed Warnickecb9cada2015-12-08 15:45:58 -07001526 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1527
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001528 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
1529 {
1530 *unsupported = 0;
1531 goto done; // non-ethernet interface
1532 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533
1534 // ensure there's an entry for the main intf (shouldn't really be necessary)
1535 vec_validate (em->main_intfs, hi->hw_if_index);
1536 main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
1537
1538 // Locate the subint for the given ethernet config
1539 si = vnet_get_sw_interface (vnm, sw_if_index);
1540
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001541 if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
1542 {
1543 p2p_ethernet_main_t *p2pm = &p2p_main;
1544 u32 p2pe_sw_if_index =
1545 p2p_ethernet_lookup (hi->hw_if_index, si->p2p.client_mac);
1546 if (p2pe_sw_if_index == ~0)
1547 {
1548 pool_get (p2pm->p2p_subif_pool, subint);
1549 si->p2p.pool_index = subint - p2pm->p2p_subif_pool;
1550 }
1551 else
1552 subint = vec_elt_at_index (p2pm->p2p_subif_pool, si->p2p.pool_index);
1553 *flags = SUBINT_CONFIG_P2P;
1554 }
Neale Ranns17ff3c12018-07-04 10:24:24 -07001555 else if (si->type == VNET_SW_INTERFACE_TYPE_PIPE)
1556 {
1557 pipe_t *pipe;
1558
1559 pipe = pipe_get (sw_if_index);
1560 subint = &pipe->subint;
1561 *flags = SUBINT_CONFIG_P2P;
1562 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001563 else if (si->sub.eth.flags.default_sub)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001564 {
1565 subint = &main_intf->default_subint;
Mike Bly88076742018-09-24 10:13:06 -07001566 *flags = SUBINT_CONFIG_MATCH_1_TAG |
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001567 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1568 }
1569 else if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0))
1570 {
1571 // if no flags are set then this is a main interface
1572 // so treat as untagged
1573 subint = &main_intf->untagged_subint;
1574 *flags = SUBINT_CONFIG_MATCH_0_TAG;
1575 }
1576 else
1577 {
1578 // one or two tags
1579 // first get the vlan table
1580 if (si->sub.eth.flags.dot1ad)
1581 {
1582 if (main_intf->dot1ad_vlans == 0)
1583 {
1584 // Allocate a vlan table from the pool
1585 pool_get (em->vlan_pool, vlan_table);
1586 main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
1587 }
1588 else
1589 {
1590 // Get ptr to existing vlan table
1591 vlan_table =
1592 vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
1593 }
1594 }
1595 else
1596 { // dot1q
1597 if (main_intf->dot1q_vlans == 0)
1598 {
1599 // Allocate a vlan table from the pool
1600 pool_get (em->vlan_pool, vlan_table);
1601 main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
1602 }
1603 else
1604 {
1605 // Get ptr to existing vlan table
1606 vlan_table =
1607 vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
1608 }
1609 }
1610
1611 if (si->sub.eth.flags.one_tag)
1612 {
1613 *flags = si->sub.eth.flags.exact_match ?
1614 SUBINT_CONFIG_MATCH_1_TAG :
1615 (SUBINT_CONFIG_MATCH_1_TAG |
1616 SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1617
1618 if (si->sub.eth.flags.outer_vlan_id_any)
1619 {
1620 // not implemented yet
1621 *unsupported = 1;
1622 goto done;
1623 }
1624 else
1625 {
1626 // a single vlan, a common case
1627 subint =
1628 &vlan_table->vlans[si->sub.eth.
1629 outer_vlan_id].single_tag_subint;
1630 }
1631
1632 }
1633 else
1634 {
1635 // Two tags
1636 *flags = si->sub.eth.flags.exact_match ?
1637 SUBINT_CONFIG_MATCH_2_TAG :
1638 (SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
1639
1640 if (si->sub.eth.flags.outer_vlan_id_any
1641 && si->sub.eth.flags.inner_vlan_id_any)
1642 {
1643 // not implemented yet
1644 *unsupported = 1;
1645 goto done;
1646 }
1647
1648 if (si->sub.eth.flags.inner_vlan_id_any)
1649 {
1650 // a specific outer and "any" inner
1651 // don't need a qinq table for this
1652 subint =
1653 &vlan_table->vlans[si->sub.eth.
1654 outer_vlan_id].inner_any_subint;
1655 if (si->sub.eth.flags.exact_match)
1656 {
1657 *flags = SUBINT_CONFIG_MATCH_2_TAG;
1658 }
1659 else
1660 {
1661 *flags = SUBINT_CONFIG_MATCH_2_TAG |
1662 SUBINT_CONFIG_MATCH_3_TAG;
1663 }
1664 }
1665 else
1666 {
1667 // a specific outer + specifc innner vlan id, a common case
1668
1669 // get the qinq table
1670 if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0)
1671 {
1672 // Allocate a qinq table from the pool
1673 pool_get (em->qinq_pool, qinq_table);
1674 vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs =
1675 qinq_table - em->qinq_pool;
1676 }
1677 else
1678 {
1679 // Get ptr to existing qinq table
1680 qinq_table =
1681 vec_elt_at_index (em->qinq_pool,
1682 vlan_table->vlans[si->sub.
1683 eth.outer_vlan_id].
1684 qinqs);
1685 }
1686 subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
1687 }
1688 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001689 }
1690
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001691done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001692 return subint;
1693}
1694
Damjan Marion5beecec2018-09-10 13:09:21 +02001695static clib_error_t *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001696ethernet_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001697{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001698 subint_config_t *subint;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001699 u32 dummy_flags;
1700 u32 dummy_unsup;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001701 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001702
1703 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001704 subint =
1705 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1706 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001707
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001708 if (subint == 0)
1709 {
1710 // not implemented yet or not ethernet
1711 goto done;
1712 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001713
1714 subint->sw_if_index =
1715 ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
1716
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001717done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001718 return error;
1719}
1720
1721VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
1722
1723
Damjan Marion5beecec2018-09-10 13:09:21 +02001724#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001725// Set the L2/L3 mode for the subinterface
1726void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001727ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728{
1729 subint_config_t *subint;
1730 u32 dummy_flags;
1731 u32 dummy_unsup;
1732 int is_port;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001733 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001734
1735 is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
1736
1737 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001738 subint =
1739 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1740 &dummy_unsup);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001741
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001742 if (subint == 0)
1743 {
1744 // unimplemented or not ethernet
1745 goto done;
1746 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001747
1748 // Double check that the config we found is for our interface (or the interface is down)
1749 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1750
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001751 if (l2)
1752 {
1753 subint->flags |= SUBINT_CONFIG_L2;
1754 if (is_port)
1755 subint->flags |=
1756 SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
1757 | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1758 }
1759 else
1760 {
1761 subint->flags &= ~SUBINT_CONFIG_L2;
1762 if (is_port)
1763 subint->flags &=
1764 ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
1765 | SUBINT_CONFIG_MATCH_3_TAG);
1766 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001767
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001768done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769 return;
1770}
1771
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001772/*
1773 * Set the L2/L3 mode for the subinterface regardless of port
1774 */
1775void
1776ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001777 u32 sw_if_index, u32 l2)
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001778{
1779 subint_config_t *subint;
1780 u32 dummy_flags;
1781 u32 dummy_unsup;
1782
1783 /* Find the config for this subinterface */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001784 subint =
1785 ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1786 &dummy_unsup);
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001787
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001788 if (subint == 0)
1789 {
1790 /* unimplemented or not ethernet */
1791 goto done;
1792 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001793
1794 /*
1795 * Double check that the config we found is for our interface (or the
1796 * interface is down)
1797 */
1798 ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1799
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001800 if (l2)
1801 {
1802 subint->flags |= SUBINT_CONFIG_L2;
1803 }
1804 else
1805 {
1806 subint->flags &= ~SUBINT_CONFIG_L2;
1807 }
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001808
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001809done:
Christian Dechamplain (cdechamp)07aecbb2016-04-05 10:40:38 -04001810 return;
1811}
Damjan Marion5beecec2018-09-10 13:09:21 +02001812#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813
1814static clib_error_t *
1815ethernet_sw_interface_add_del (vnet_main_t * vnm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001816 u32 sw_if_index, u32 is_create)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001817{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001818 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819 subint_config_t *subint;
1820 u32 match_flags;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001821 u32 unsupported = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822
1823 // Find the config for this subinterface
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001824 subint =
1825 ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags,
1826 &unsupported);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001827
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001828 if (subint == 0)
1829 {
1830 // not implemented yet or not ethernet
1831 if (unsupported)
1832 {
Damjan Marion607de1a2016-08-16 22:53:54 +02001833 // this is the NYI case
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001834 error = clib_error_return (0, "not implemented yet");
1835 }
1836 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001837 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001838
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001839 if (!is_create)
1840 {
1841 subint->flags = 0;
1842 return error;
1843 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001844
1845 // Initialize the subint
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001846 if (subint->flags & SUBINT_CONFIG_VALID)
1847 {
1848 // Error vlan already in use
1849 error = clib_error_return (0, "vlan is already in use");
1850 }
1851 else
1852 {
Neale Ranns17ff3c12018-07-04 10:24:24 -07001853 // Note that config is L3 by default
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001854 subint->flags = SUBINT_CONFIG_VALID | match_flags;
1855 subint->sw_if_index = ~0; // because interfaces are initially down
1856 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001858done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859 return error;
1860}
1861
1862VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
1863
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001864static char *ethernet_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865#define ethernet_error(n,c,s) s,
1866#include "error.def"
1867#undef ethernet_error
1868};
1869
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001870/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871VLIB_REGISTER_NODE (ethernet_input_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001872 .name = "ethernet-input",
1873 /* Takes a vector of packets. */
1874 .vector_size = sizeof (u32),
Damjan Marion650223c2018-11-14 16:55:53 +01001875 .scalar_size = sizeof (ethernet_input_frame_t),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001876 .n_errors = ETHERNET_N_ERROR,
1877 .error_strings = ethernet_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001878 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1879 .next_nodes = {
1880#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1881 foreach_ethernet_input_next
1882#undef _
1883 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07001884 .format_buffer = format_ethernet_header_with_length,
1885 .format_trace = format_ethernet_input_trace,
1886 .unformat_buffer = unformat_ethernet_header,
1887};
1888
Damjan Marion5beecec2018-09-10 13:09:21 +02001889VLIB_REGISTER_NODE (ethernet_input_type_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001890 .name = "ethernet-input-type",
1891 /* Takes a vector of packets. */
1892 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1894 .next_nodes = {
1895#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1896 foreach_ethernet_input_next
1897#undef _
1898 },
1899};
1900
Damjan Marion5beecec2018-09-10 13:09:21 +02001901VLIB_REGISTER_NODE (ethernet_input_not_l2_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902 .name = "ethernet-input-not-l2",
1903 /* Takes a vector of packets. */
1904 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905 .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1906 .next_nodes = {
1907#define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1908 foreach_ethernet_input_next
1909#undef _
1910 },
1911};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001912/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001913
Damjan Marion5beecec2018-09-10 13:09:21 +02001914#ifndef CLIB_MARCH_VARIANT
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001915void
1916ethernet_set_rx_redirect (vnet_main_t * vnm,
1917 vnet_hw_interface_t * hi, u32 enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001918{
1919 // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
1920 // don't go directly to ip4-input)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001921 vnet_hw_interface_rx_redirect_to_node
1922 (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001923}
1924
1925
1926/*
1927 * Initialization and registration for the next_by_ethernet structure
1928 */
1929
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001930clib_error_t *
1931next_by_ethertype_init (next_by_ethertype_t * l3_next)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001932{
1933 l3_next->input_next_by_type = sparse_vec_new
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001934 ( /* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001935 /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
1936
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001937 vec_validate (l3_next->sparse_index_by_input_next_index,
1938 ETHERNET_INPUT_NEXT_DROP);
1939 vec_validate (l3_next->sparse_index_by_input_next_index,
1940 ETHERNET_INPUT_NEXT_PUNT);
1941 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP] =
1942 SPARSE_VEC_INVALID_INDEX;
1943 l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] =
1944 SPARSE_VEC_INVALID_INDEX;
1945
Damjan Marion607de1a2016-08-16 22:53:54 +02001946 /*
1947 * Make sure we don't wipe out an ethernet registration by mistake
Dave Barach1f49ed62016-02-24 11:29:06 -05001948 * Can happen if init function ordering constraints are missing.
1949 */
1950 if (CLIB_DEBUG > 0)
1951 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001952 ethernet_main_t *em = &ethernet_main;
1953 ASSERT (em->next_by_ethertype_register_called == 0);
Dave Barach1f49ed62016-02-24 11:29:06 -05001954 }
1955
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956 return 0;
1957}
1958
1959// Add an ethertype -> next index mapping to the structure
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001960clib_error_t *
1961next_by_ethertype_register (next_by_ethertype_t * l3_next,
1962 u32 ethertype, u32 next_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963{
1964 u32 i;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001965 u16 *n;
1966 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001967
Dave Barach1f49ed62016-02-24 11:29:06 -05001968 if (CLIB_DEBUG > 0)
1969 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001970 ethernet_main_t *em = &ethernet_main;
Dave Barach1f49ed62016-02-24 11:29:06 -05001971 em->next_by_ethertype_register_called = 1;
1972 }
1973
Ed Warnickecb9cada2015-12-08 15:45:58 -07001974 /* Setup ethernet type -> next index sparse vector mapping. */
1975 n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
1976 n[0] = next_index;
1977
1978 /* Rebuild next index -> sparse index inverse mapping when sparse vector
1979 is updated. */
1980 vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
1981 for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001982 l3_next->
1983 sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001984
1985 // do not allow the cached next index's to be updated if L3
1986 // redirect is enabled, as it will have overwritten them
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001987 if (!em->redirect_l3)
1988 {
1989 // Cache common ethertypes directly
1990 if (ethertype == ETHERNET_TYPE_IP4)
1991 {
1992 l3_next->input_next_ip4 = next_index;
1993 }
1994 else if (ethertype == ETHERNET_TYPE_IP6)
1995 {
1996 l3_next->input_next_ip6 = next_index;
1997 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001998 else if (ethertype == ETHERNET_TYPE_MPLS)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001999 {
2000 l3_next->input_next_mpls = next_index;
2001 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002003 return 0;
2004}
2005
2006
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002007static clib_error_t *
2008ethernet_input_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002010 ethernet_main_t *em = &ethernet_main;
2011 __attribute__ ((unused)) vlan_table_t *invalid_vlan_table;
2012 __attribute__ ((unused)) qinq_table_t *invalid_qinq_table;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013
2014 ethernet_setup_node (vm, ethernet_input_node.index);
2015 ethernet_setup_node (vm, ethernet_input_type_node.index);
2016 ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
2017
2018 next_by_ethertype_init (&em->l3_next);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002019
Ed Warnickecb9cada2015-12-08 15:45:58 -07002020 // Initialize pools and vector for vlan parsing
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002021 vec_validate (em->main_intfs, 10); // 10 main interfaces
2022 pool_alloc (em->vlan_pool, 10);
2023 pool_alloc (em->qinq_pool, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002024
2025 // The first vlan pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002026 pool_get (em->vlan_pool, invalid_vlan_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027 // The first qinq pool will always be reserved for an invalid table
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002028 pool_get (em->qinq_pool, invalid_qinq_table); // first id = 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002029
2030 return 0;
2031}
2032
2033VLIB_INIT_FUNCTION (ethernet_input_init);
2034
2035void
2036ethernet_register_input_type (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002037 ethernet_type_t type, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002038{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002039 ethernet_main_t *em = &ethernet_main;
2040 ethernet_type_info_t *ti;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041 u32 i;
2042
2043 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002044 clib_error_t *error = vlib_call_init_function (vm, ethernet_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002045 if (error)
2046 clib_error_report (error);
2047 }
2048
2049 ti = ethernet_get_type_info (em, type);
2050 ti->node_index = node_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002051 ti->next_index = vlib_node_add_next (vm,
2052 ethernet_input_node.index, node_index);
2053 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054 ASSERT (i == ti->next_index);
2055
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002056 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002057 ASSERT (i == ti->next_index);
2058
2059 // Add the L3 node for this ethertype to the next nodes structure
2060 next_by_ethertype_register (&em->l3_next, type, ti->next_index);
2061
2062 // Call the registration functions for other nodes that want a mapping
2063 l2bvi_register_input_type (vm, type, node_index);
2064}
2065
2066void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002067ethernet_register_l2_input (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002068{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002069 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002070 u32 i;
2071
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002072 em->l2_next =
2073 vlib_node_add_next (vm, ethernet_input_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002074
Damjan Marion607de1a2016-08-16 22:53:54 +02002075 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002076 * Even if we never use these arcs, we have to align the next indices...
2077 */
2078 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
2079
2080 ASSERT (i == em->l2_next);
2081
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002082 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002083 ASSERT (i == em->l2_next);
2084}
2085
2086// Register a next node for L3 redirect, and enable L3 redirect
2087void
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002088ethernet_register_l3_redirect (vlib_main_t * vm, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002089{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002090 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002091 u32 i;
2092
2093 em->redirect_l3 = 1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002094 em->redirect_l3_next = vlib_node_add_next (vm,
2095 ethernet_input_node.index,
2096 node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097 /*
2098 * Change the cached next nodes to the redirect node
2099 */
2100 em->l3_next.input_next_ip4 = em->redirect_l3_next;
2101 em->l3_next.input_next_ip6 = em->redirect_l3_next;
2102 em->l3_next.input_next_mpls = em->redirect_l3_next;
2103
2104 /*
2105 * Even if we never use these arcs, we have to align the next indices...
2106 */
2107 i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
2108
2109 ASSERT (i == em->redirect_l3_next);
jerryianff82ed62016-12-05 17:13:00 +08002110
2111 i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
2112
2113 ASSERT (i == em->redirect_l3_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002114}
Damjan Marion5beecec2018-09-10 13:09:21 +02002115#endif
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002116
2117/*
2118 * fd.io coding-style-patch-verification: ON
2119 *
2120 * Local Variables:
2121 * eval: (c-set-style "gnu")
2122 * End:
2123 */