LCOV - code coverage report
Current view: top level - vnet/ethernet - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 851 981 86.7 %
Date: 2023-10-26 01:39:38 Functions: 55 69 79.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * 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>
      43             : #include <vnet/ethernet/p2p_ethernet.h>
      44             : #include <vnet/devices/pipe/pipe.h>
      45             : #include <vppinfra/sparse_vec.h>
      46             : #include <vnet/l2/l2_bvi.h>
      47             : #include <vnet/classify/pcap_classify.h>
      48             : 
      49             : #define foreach_ethernet_input_next             \
      50             :   _ (PUNT, "error-punt")                      \
      51             :   _ (DROP, "error-drop")                      \
      52             :   _ (LLC, "llc-input")                                \
      53             :   _ (IP4_INPUT, "ip4-input")                  \
      54             :   _ (IP4_INPUT_NCS, "ip4-input-no-checksum")
      55             : 
      56             : typedef enum
      57             : {
      58             : #define _(s,n) ETHERNET_INPUT_NEXT_##s,
      59             :   foreach_ethernet_input_next
      60             : #undef _
      61             :     ETHERNET_INPUT_N_NEXT,
      62             : } ethernet_input_next_t;
      63             : 
      64             : typedef struct
      65             : {
      66             :   u8 packet_data[32];
      67             :   u16 frame_flags;
      68             :   ethernet_input_frame_t frame_data;
      69             : } ethernet_input_trace_t;
      70             : 
      71             : static u8 *
      72      355288 : format_ethernet_input_trace (u8 * s, va_list * va)
      73             : {
      74      355288 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
      75      355288 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
      76      355288 :   ethernet_input_trace_t *t = va_arg (*va, ethernet_input_trace_t *);
      77      355288 :   u32 indent = format_get_indent (s);
      78             : 
      79      355288 :   if (t->frame_flags)
      80             :     {
      81      353225 :       s = format (s, "frame: flags 0x%x", t->frame_flags);
      82      353225 :       if (t->frame_flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
      83      353225 :         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      353225 :       s = format (s, "\n%U", format_white_space, indent);
      86             :     }
      87      355288 :   s = format (s, "%U", format_ethernet_header, t->packet_data);
      88             : 
      89      355288 :   return s;
      90             : }
      91             : 
      92             : extern vlib_node_registration_t ethernet_input_node;
      93             : 
      94             : typedef enum
      95             : {
      96             :   ETHERNET_INPUT_VARIANT_ETHERNET,
      97             :   ETHERNET_INPUT_VARIANT_ETHERNET_TYPE,
      98             :   ETHERNET_INPUT_VARIANT_NOT_L2,
      99             : } ethernet_input_variant_t;
     100             : 
     101             : 
     102             : // Parse the ethernet header to extract vlan tags and innermost ethertype
     103             : static_always_inline void
     104      180486 : parse_header (ethernet_input_variant_t variant,
     105             :               vlib_buffer_t * b0,
     106             :               u16 * type,
     107             :               u16 * orig_type,
     108             :               u16 * outer_id, u16 * inner_id, u32 * match_flags)
     109             : {
     110             :   u8 vlan_count;
     111             : 
     112      180486 :   if (variant == ETHERNET_INPUT_VARIANT_ETHERNET
     113           0 :       || variant == ETHERNET_INPUT_VARIANT_NOT_L2)
     114      180486 :     {
     115             :       ethernet_header_t *e0;
     116             : 
     117      180486 :       e0 = vlib_buffer_get_current (b0);
     118             : 
     119      180486 :       vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
     120      180486 :       b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
     121             : 
     122      180486 :       vlib_buffer_advance (b0, sizeof (e0[0]));
     123             : 
     124      180486 :       *type = clib_net_to_host_u16 (e0->type);
     125             :     }
     126           0 :   else if (variant == ETHERNET_INPUT_VARIANT_ETHERNET_TYPE)
     127             :     {
     128             :       // here when prior node was LLC/SNAP processing
     129             :       u16 *e0;
     130             : 
     131           0 :       e0 = vlib_buffer_get_current (b0);
     132             : 
     133           0 :       vlib_buffer_advance (b0, sizeof (e0[0]));
     134             : 
     135           0 :       *type = clib_net_to_host_u16 (e0[0]);
     136             :     }
     137             : 
     138             :   // save for distinguishing between dot1q and dot1ad later
     139      180486 :   *orig_type = *type;
     140             : 
     141             :   // default the tags to 0 (used if there is no corresponding tag)
     142      180486 :   *outer_id = 0;
     143      180486 :   *inner_id = 0;
     144             : 
     145      180486 :   *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_0_TAG;
     146      180486 :   vlan_count = 0;
     147             : 
     148             :   // check for vlan encaps
     149      180486 :   if (ethernet_frame_is_tagged (*type))
     150             :     {
     151             :       ethernet_vlan_header_t *h0;
     152             :       u16 tag;
     153             : 
     154         514 :       *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_1_TAG;
     155             : 
     156         514 :       h0 = vlib_buffer_get_current (b0);
     157             : 
     158         514 :       tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
     159             : 
     160         514 :       *outer_id = tag & 0xfff;
     161         514 :       if (0 == *outer_id)
     162           0 :         *match_flags &= ~SUBINT_CONFIG_MATCH_1_TAG;
     163             : 
     164         514 :       *type = clib_net_to_host_u16 (h0->type);
     165             : 
     166         514 :       vlib_buffer_advance (b0, sizeof (h0[0]));
     167         514 :       vlan_count = 1;
     168             : 
     169         514 :       if (*type == ETHERNET_TYPE_VLAN)
     170             :         {
     171             :           // Double tagged packet
     172           0 :           *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_2_TAG;
     173             : 
     174           0 :           h0 = vlib_buffer_get_current (b0);
     175             : 
     176           0 :           tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
     177             : 
     178           0 :           *inner_id = tag & 0xfff;
     179             : 
     180           0 :           *type = clib_net_to_host_u16 (h0->type);
     181             : 
     182           0 :           vlib_buffer_advance (b0, sizeof (h0[0]));
     183           0 :           vlan_count = 2;
     184           0 :           if (*type == ETHERNET_TYPE_VLAN)
     185             :             {
     186             :               // More than double tagged packet
     187           0 :               *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG;
     188             : 
     189           0 :               vlib_buffer_advance (b0, sizeof (h0[0]));
     190           0 :               vlan_count = 3;   // "unknown" number, aka, 3-or-more
     191             :             }
     192             :         }
     193             :     }
     194      180486 :   ethernet_buffer_set_vlan_count (b0, vlan_count);
     195      180486 : }
     196             : 
     197             : static_always_inline void
     198             : ethernet_input_inline_dmac_check (vnet_hw_interface_t * hi,
     199             :                                   u64 * dmacs, u8 * dmacs_bad,
     200             :                                   u32 n_packets, ethernet_interface_t * ei,
     201             :                                   u8 have_sec_dmac);
     202             : 
     203             : // Determine the subinterface for this packet, given the result of the
     204             : // vlan table lookups and vlan header parsing. Check the most specific
     205             : // matches first.
     206             : static_always_inline void
     207      180486 : identify_subint (ethernet_main_t * em,
     208             :                  vnet_hw_interface_t * hi,
     209             :                  vlib_buffer_t * b0,
     210             :                  u32 match_flags,
     211             :                  main_intf_t * main_intf,
     212             :                  vlan_intf_t * vlan_intf,
     213             :                  qinq_intf_t * qinq_intf,
     214             :                  u32 * new_sw_if_index, u8 * error0, u32 * is_l2)
     215             : {
     216             :   u32 matched;
     217      180486 :   ethernet_interface_t *ei = ethernet_get_interface (em, hi->hw_if_index);
     218             : 
     219      180486 :   matched = eth_identify_subint (hi, match_flags, main_intf, vlan_intf,
     220             :                                  qinq_intf, new_sw_if_index, error0, is_l2);
     221             : 
     222      180486 :   if (matched)
     223             :     {
     224             :       // Perform L3 my-mac filter
     225             :       // A unicast packet arriving on an L3 interface must have a dmac
     226             :       // matching the interface mac. If interface has STATUS_L3 bit set
     227             :       // mac filter is already done.
     228      180486 :       if ((!*is_l2) && ei &&
     229       27838 :           (!(ei->flags & ETHERNET_INTERFACE_FLAG_STATUS_L3)))
     230             :         {
     231             :           u64 dmacs[2];
     232             :           u8 dmacs_bad[2];
     233             :           ethernet_header_t *e0;
     234             : 
     235       27838 :           e0 = (void *) (b0->data + vnet_buffer (b0)->l2_hdr_offset);
     236       27838 :           dmacs[0] = *(u64 *) e0;
     237             : 
     238       27838 :           if (vec_len (ei->secondary_addrs))
     239       27838 :             ethernet_input_inline_dmac_check (hi, dmacs, dmacs_bad,
     240             :                                               1 /* n_packets */, ei,
     241             :                                               1 /* have_sec_dmac */);
     242             :           else
     243           0 :             ethernet_input_inline_dmac_check (hi, dmacs, dmacs_bad,
     244             :                                               1 /* n_packets */, ei,
     245             :                                               0 /* have_sec_dmac */);
     246       27838 :           if (dmacs_bad[0])
     247           0 :             *error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
     248             :         }
     249             : 
     250             :       // Check for down subinterface
     251      180486 :       *error0 = (*new_sw_if_index) != ~0 ? (*error0) : ETHERNET_ERROR_DOWN;
     252             :     }
     253      180486 : }
     254             : 
     255             : static_always_inline void
     256     4493840 : determine_next_node (ethernet_main_t * em,
     257             :                      ethernet_input_variant_t variant,
     258             :                      u32 is_l20,
     259             :                      u32 type0, vlib_buffer_t * b0, u8 * error0, u8 * next0)
     260             : {
     261     4493840 :   vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
     262     4493840 :   b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
     263             : 
     264     4493840 :   if (PREDICT_FALSE (*error0 != ETHERNET_ERROR_NONE))
     265             :     {
     266             :       // some error occurred
     267          47 :       *next0 = ETHERNET_INPUT_NEXT_DROP;
     268             :     }
     269     4493790 :   else if (is_l20)
     270             :     {
     271             :       // record the L2 len and reset the buffer so the L2 header is preserved
     272      152648 :       u32 eth_start = vnet_buffer (b0)->l2_hdr_offset;
     273      152648 :       vnet_buffer (b0)->l2.l2_len = b0->current_data - eth_start;
     274      152648 :       *next0 = em->l2_next;
     275      152648 :       ASSERT (vnet_buffer (b0)->l2.l2_len ==
     276             :               ethernet_buffer_header_size (b0));
     277      152648 :       vlib_buffer_advance (b0, -(vnet_buffer (b0)->l2.l2_len));
     278             : 
     279             :       // check for common IP/MPLS ethertypes
     280             :     }
     281     4341140 :   else if (type0 == ETHERNET_TYPE_IP4)
     282             :     {
     283     2506580 :       *next0 = em->l3_next.input_next_ip4;
     284             :     }
     285     1834560 :   else if (type0 == ETHERNET_TYPE_IP6)
     286             :     {
     287     1834440 :       *next0 = em->l3_next.input_next_ip6;
     288             :     }
     289         122 :   else if (type0 == ETHERNET_TYPE_MPLS)
     290             :     {
     291           0 :       *next0 = em->l3_next.input_next_mpls;
     292             : 
     293             :     }
     294         122 :   else if (em->redirect_l3)
     295             :     {
     296             :       // L3 Redirect is on, the cached common next nodes will be
     297             :       // pointing to the redirect node, catch the uncommon types here
     298           0 :       *next0 = em->redirect_l3_next;
     299             :     }
     300             :   else
     301             :     {
     302             :       // uncommon ethertype, check table
     303             :       u32 i0;
     304         122 :       i0 = sparse_vec_index (em->l3_next.input_next_by_type, type0);
     305         122 :       *next0 = vec_elt (em->l3_next.input_next_by_type, i0);
     306         122 :       *error0 =
     307             :         i0 ==
     308             :         SPARSE_VEC_INVALID_INDEX ? ETHERNET_ERROR_UNKNOWN_TYPE : *error0;
     309             : 
     310             :       // The table is not populated with LLC values, so check that now.
     311             :       // If variant is variant_ethernet then we came from LLC processing. Don't
     312             :       // go back there; drop instead using by keeping the drop/bad table result.
     313         122 :       if ((type0 < 0x600) && (variant == ETHERNET_INPUT_VARIANT_ETHERNET))
     314             :         {
     315           0 :           *next0 = ETHERNET_INPUT_NEXT_LLC;
     316             :         }
     317             :     }
     318     4493840 : }
     319             : 
     320             : 
     321             : /* following vector code relies on following assumptions */
     322             : STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_data, 0);
     323             : STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, current_length, 2);
     324             : STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, flags, 4);
     325             : STATIC_ASSERT (STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l2_hdr_offset) ==
     326             :                STRUCT_OFFSET_OF (vnet_buffer_opaque_t, l3_hdr_offset) - 2,
     327             :                "l3_hdr_offset must follow l2_hdr_offset");
     328             : 
     329             : static_always_inline void
     330    14898400 : eth_input_adv_and_flags_x4 (vlib_buffer_t ** b, int is_l3)
     331             : {
     332    14898400 :   i16 adv = sizeof (ethernet_header_t);
     333    14898400 :   u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
     334             :     VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
     335             : 
     336             : #ifdef CLIB_HAVE_VEC256
     337             :   /* to reduce number of small loads/stores we are loading first 64 bits
     338             :      of each buffer metadata into 256-bit register so we can advance
     339             :      current_data, current_length and flags.
     340             :      Observed saving of this code is ~2 clocks per packet */
     341             :   u64x4 r, radv;
     342             : 
     343             :   /* vector if signed 16 bit integers used in signed vector add operation
     344             :      to advnce current_data and current_length */
     345    14898400 :   u32x8 flags4 = { 0, flags, 0, flags, 0, flags, 0, flags };
     346    14898400 :   i16x16 adv4 = {
     347             :     adv, -adv, 0, 0, adv, -adv, 0, 0,
     348             :     adv, -adv, 0, 0, adv, -adv, 0, 0
     349             :   };
     350             : 
     351             :   /* load 4 x 64 bits */
     352    14898400 :   r = u64x4_gather (b[0], b[1], b[2], b[3]);
     353             : 
     354             :   /* set flags */
     355    14898400 :   r |= (u64x4) flags4;
     356             : 
     357             :   /* advance buffer */
     358    14898400 :   radv = (u64x4) ((i16x16) r + adv4);
     359             : 
     360             :   /* write 4 x 64 bits */
     361    14898400 :   u64x4_scatter (is_l3 ? radv : r, b[0], b[1], b[2], b[3]);
     362             : 
     363             :   /* use old current_data as l2_hdr_offset and new current_data as
     364             :      l3_hdr_offset */
     365    14898400 :   r = (u64x4) u16x16_blend (r, radv << 16, 0xaa);
     366             : 
     367             :   /* store both l2_hdr_offset and l3_hdr_offset in single store operation */
     368    14898400 :   u32x8_scatter_one ((u32x8) r, 0, &vnet_buffer (b[0])->l2_hdr_offset);
     369    14898400 :   u32x8_scatter_one ((u32x8) r, 2, &vnet_buffer (b[1])->l2_hdr_offset);
     370    14898400 :   u32x8_scatter_one ((u32x8) r, 4, &vnet_buffer (b[2])->l2_hdr_offset);
     371    14898400 :   u32x8_scatter_one ((u32x8) r, 6, &vnet_buffer (b[3])->l2_hdr_offset);
     372             : 
     373    14898400 :   if (is_l3)
     374             :     {
     375     3318040 :       ASSERT (b[0]->current_data == vnet_buffer (b[0])->l3_hdr_offset);
     376     3318040 :       ASSERT (b[1]->current_data == vnet_buffer (b[1])->l3_hdr_offset);
     377     3318040 :       ASSERT (b[2]->current_data == vnet_buffer (b[2])->l3_hdr_offset);
     378     3318040 :       ASSERT (b[3]->current_data == vnet_buffer (b[3])->l3_hdr_offset);
     379             : 
     380     3318040 :       ASSERT (b[0]->current_data - vnet_buffer (b[0])->l2_hdr_offset == adv);
     381     3318040 :       ASSERT (b[1]->current_data - vnet_buffer (b[1])->l2_hdr_offset == adv);
     382     3318040 :       ASSERT (b[2]->current_data - vnet_buffer (b[2])->l2_hdr_offset == adv);
     383     3318040 :       ASSERT (b[3]->current_data - vnet_buffer (b[3])->l2_hdr_offset == adv);
     384             :     }
     385             :   else
     386             :     {
     387    11580400 :       ASSERT (b[0]->current_data == vnet_buffer (b[0])->l2_hdr_offset);
     388    11580400 :       ASSERT (b[1]->current_data == vnet_buffer (b[1])->l2_hdr_offset);
     389    11580400 :       ASSERT (b[2]->current_data == vnet_buffer (b[2])->l2_hdr_offset);
     390    11580400 :       ASSERT (b[3]->current_data == vnet_buffer (b[3])->l2_hdr_offset);
     391             : 
     392    11580400 :       ASSERT (b[0]->current_data - vnet_buffer (b[0])->l3_hdr_offset == -adv);
     393    11580400 :       ASSERT (b[1]->current_data - vnet_buffer (b[1])->l3_hdr_offset == -adv);
     394    11580400 :       ASSERT (b[2]->current_data - vnet_buffer (b[2])->l3_hdr_offset == -adv);
     395    11580400 :       ASSERT (b[3]->current_data - vnet_buffer (b[3])->l3_hdr_offset == -adv);
     396             :     }
     397             : 
     398             : #else
     399           0 :   vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
     400           0 :   vnet_buffer (b[1])->l2_hdr_offset = b[1]->current_data;
     401           0 :   vnet_buffer (b[2])->l2_hdr_offset = b[2]->current_data;
     402           0 :   vnet_buffer (b[3])->l2_hdr_offset = b[3]->current_data;
     403           0 :   vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
     404           0 :   vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data + adv;
     405           0 :   vnet_buffer (b[2])->l3_hdr_offset = b[2]->current_data + adv;
     406           0 :   vnet_buffer (b[3])->l3_hdr_offset = b[3]->current_data + adv;
     407             : 
     408           0 :   if (is_l3)
     409             :     {
     410           0 :       vlib_buffer_advance (b[0], adv);
     411           0 :       vlib_buffer_advance (b[1], adv);
     412           0 :       vlib_buffer_advance (b[2], adv);
     413           0 :       vlib_buffer_advance (b[3], adv);
     414             :     }
     415             : 
     416           0 :   b[0]->flags |= flags;
     417           0 :   b[1]->flags |= flags;
     418           0 :   b[2]->flags |= flags;
     419           0 :   b[3]->flags |= flags;
     420             : #endif
     421             : 
     422    14898400 :   if (!is_l3)
     423             :     {
     424    11580400 :       vnet_buffer (b[0])->l2.l2_len = adv;
     425    11580400 :       vnet_buffer (b[1])->l2.l2_len = adv;
     426    11580400 :       vnet_buffer (b[2])->l2.l2_len = adv;
     427    11580400 :       vnet_buffer (b[3])->l2.l2_len = adv;
     428             :     }
     429    14898400 : }
     430             : 
     431             : static_always_inline void
     432     1856300 : eth_input_adv_and_flags_x1 (vlib_buffer_t ** b, int is_l3)
     433             : {
     434     1856300 :   i16 adv = sizeof (ethernet_header_t);
     435     1856300 :   u32 flags = VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
     436             :     VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
     437             : 
     438     1856300 :   vnet_buffer (b[0])->l2_hdr_offset = b[0]->current_data;
     439     1856300 :   vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data + adv;
     440             : 
     441     1856300 :   if (is_l3)
     442      406462 :     vlib_buffer_advance (b[0], adv);
     443     1856300 :   b[0]->flags |= flags;
     444     1856300 :   if (!is_l3)
     445     1449840 :     vnet_buffer (b[0])->l2.l2_len = adv;
     446     1856300 : }
     447             : 
     448             : 
     449             : static_always_inline void
     450    61450000 : eth_input_get_etype_and_tags (vlib_buffer_t ** b, u16 * etype, u64 * tags,
     451             :                               u64 * dmacs, int offset, int dmac_check)
     452             : {
     453             :   ethernet_header_t *e;
     454    61450000 :   e = vlib_buffer_get_current (b[offset]);
     455             : #ifdef CLIB_HAVE_VEC128
     456    61450000 :   u64x2 r = u64x2_load_unaligned (((u8 *) & e->type) - 6);
     457    61450000 :   etype[offset] = ((u16x8) r)[3];
     458    61450000 :   tags[offset] = r[1];
     459             : #else
     460             :   etype[offset] = e->type;
     461             :   tags[offset] = *(u64 *) (e + 1);
     462             : #endif
     463             : 
     464    61450000 :   if (dmac_check)
     465    13678800 :     dmacs[offset] = *(u64 *) e;
     466    61450000 : }
     467             : 
     468             : static_always_inline u16
     469        2103 : eth_input_next_by_type (u16 etype)
     470             : {
     471        2103 :   ethernet_main_t *em = &ethernet_main;
     472             : 
     473        4198 :   return (etype < 0x600) ? ETHERNET_INPUT_NEXT_LLC :
     474        2095 :     vec_elt (em->l3_next.input_next_by_type,
     475             :              sparse_vec_index (em->l3_next.input_next_by_type, etype));
     476             : }
     477             : 
     478             : typedef struct
     479             : {
     480             :   u64 tag, mask;
     481             :   u32 sw_if_index;
     482             :   u16 type, len, next;
     483             :   i16 adv;
     484             :   u8 err, n_tags;
     485             :   u64 n_packets, n_bytes;
     486             : } eth_input_tag_lookup_t;
     487             : 
     488             : static_always_inline void
     489        4761 : eth_input_update_if_counters (vlib_main_t * vm, vnet_main_t * vnm,
     490             :                               eth_input_tag_lookup_t * l)
     491             : {
     492        4761 :   if (l->n_packets == 0 || l->sw_if_index == ~0)
     493        4514 :     return;
     494             : 
     495         247 :   if (l->adv > 0)
     496         158 :     l->n_bytes += l->n_packets * l->len;
     497             : 
     498         247 :   vlib_increment_combined_counter
     499             :     (vnm->interface_main.combined_sw_if_counters +
     500             :      VNET_INTERFACE_COUNTER_RX, vm->thread_index, l->sw_if_index,
     501             :      l->n_packets, l->n_bytes);
     502             : }
     503             : 
     504             : static_always_inline void
     505        4990 : eth_input_tag_lookup (vlib_main_t * vm, vnet_main_t * vnm,
     506             :                       vlib_node_runtime_t * node, vnet_hw_interface_t * hi,
     507             :                       u64 tag, u16 * next, vlib_buffer_t * b,
     508             :                       eth_input_tag_lookup_t * l, u8 dmac_bad, int is_dot1ad,
     509             :                       int main_is_l3, int check_dmac)
     510             : {
     511        4990 :   ethernet_main_t *em = &ethernet_main;
     512             : 
     513        4990 :   if ((tag ^ l->tag) & l->mask)
     514             :     {
     515         251 :       main_intf_t *mif = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
     516             :       vlan_intf_t *vif;
     517             :       qinq_intf_t *qif;
     518             :       vlan_table_t *vlan_table;
     519             :       qinq_table_t *qinq_table;
     520         251 :       u16 *t = (u16 *) & tag;
     521         251 :       u16 vlan1 = clib_net_to_host_u16 (t[0]) & 0xFFF;
     522         251 :       u16 vlan2 = clib_net_to_host_u16 (t[2]) & 0xFFF;
     523             :       u32 matched, is_l2, new_sw_if_index;
     524             : 
     525         251 :       vlan_table = vec_elt_at_index (em->vlan_pool, is_dot1ad ?
     526             :                                      mif->dot1ad_vlans : mif->dot1q_vlans);
     527         251 :       vif = &vlan_table->vlans[vlan1];
     528         251 :       qinq_table = vec_elt_at_index (em->qinq_pool, vif->qinqs);
     529         251 :       qif = &qinq_table->vlans[vlan2];
     530         251 :       l->err = ETHERNET_ERROR_NONE;
     531         251 :       l->type = clib_net_to_host_u16 (t[1]);
     532             : 
     533         251 :       if (l->type == ETHERNET_TYPE_VLAN)
     534             :         {
     535          53 :           l->type = clib_net_to_host_u16 (t[3]);
     536          53 :           l->n_tags = 2;
     537          53 :           matched = eth_identify_subint (hi, SUBINT_CONFIG_VALID |
     538             :                                          SUBINT_CONFIG_MATCH_2_TAG, mif, vif,
     539             :                                          qif, &new_sw_if_index, &l->err,
     540             :                                          &is_l2);
     541             :         }
     542             :       else
     543             :         {
     544         198 :           l->n_tags = 1;
     545         198 :           if (vlan1 == 0)
     546             :             {
     547           4 :               new_sw_if_index = hi->sw_if_index;
     548           4 :               l->err = ETHERNET_ERROR_NONE;
     549           4 :               matched = 1;
     550           4 :               is_l2 = main_is_l3 == 0;
     551             :             }
     552             :           else
     553         194 :             matched = eth_identify_subint (hi, SUBINT_CONFIG_VALID |
     554             :                                            SUBINT_CONFIG_MATCH_1_TAG, mif,
     555             :                                            vif, qif, &new_sw_if_index,
     556             :                                            &l->err, &is_l2);
     557             :         }
     558             : 
     559         251 :       if (l->sw_if_index != new_sw_if_index)
     560             :         {
     561         247 :           eth_input_update_if_counters (vm, vnm, l);
     562         247 :           l->n_packets = 0;
     563         247 :           l->n_bytes = 0;
     564         247 :           l->sw_if_index = new_sw_if_index;
     565             :         }
     566         251 :       l->tag = tag;
     567         502 :       l->mask = (l->n_tags == 2) ?
     568         251 :         clib_net_to_host_u64 (0xffffffffffffffff) :
     569         198 :         clib_net_to_host_u64 (0xffffffff00000000);
     570             : 
     571         251 :       if (matched && l->sw_if_index == ~0)
     572           0 :         l->err = ETHERNET_ERROR_DOWN;
     573             : 
     574         251 :       l->len = sizeof (ethernet_header_t) +
     575         251 :         l->n_tags * sizeof (ethernet_vlan_header_t);
     576         251 :       if (main_is_l3)
     577         387 :         l->adv = is_l2 ? -(int) sizeof (ethernet_header_t) :
     578         162 :           l->n_tags * sizeof (ethernet_vlan_header_t);
     579             :       else
     580          26 :         l->adv = is_l2 ? 0 : l->len;
     581             : 
     582         251 :       if (PREDICT_FALSE (l->err != ETHERNET_ERROR_NONE))
     583           4 :         l->next = ETHERNET_INPUT_NEXT_DROP;
     584         247 :       else if (is_l2)
     585          89 :         l->next = em->l2_next;
     586         158 :       else if (l->type == ETHERNET_TYPE_IP4)
     587          57 :         l->next = em->l3_next.input_next_ip4;
     588         101 :       else if (l->type == ETHERNET_TYPE_IP6)
     589          73 :         l->next = em->l3_next.input_next_ip6;
     590          28 :       else if (l->type == ETHERNET_TYPE_MPLS)
     591           0 :         l->next = em->l3_next.input_next_mpls;
     592          28 :       else if (em->redirect_l3)
     593           0 :         l->next = em->redirect_l3_next;
     594             :       else
     595             :         {
     596          28 :           l->next = eth_input_next_by_type (l->type);
     597          28 :           if (l->next == ETHERNET_INPUT_NEXT_PUNT)
     598           0 :             l->err = ETHERNET_ERROR_UNKNOWN_TYPE;
     599             :         }
     600             :     }
     601             : 
     602        4990 :   if (check_dmac && l->adv > 0 && dmac_bad)
     603             :     {
     604           0 :       l->err = ETHERNET_ERROR_L3_MAC_MISMATCH;
     605           0 :       next[0] = ETHERNET_INPUT_NEXT_PUNT;
     606             :     }
     607             :   else
     608        4990 :     next[0] = l->next;
     609             : 
     610        4990 :   vlib_buffer_advance (b, l->adv);
     611        4990 :   vnet_buffer (b)->l2.l2_len = l->len;
     612        4990 :   vnet_buffer (b)->l3_hdr_offset = vnet_buffer (b)->l2_hdr_offset + l->len;
     613             : 
     614        4990 :   if (l->err == ETHERNET_ERROR_NONE)
     615             :     {
     616        4954 :       vnet_buffer (b)->sw_if_index[VLIB_RX] = l->sw_if_index;
     617        4954 :       ethernet_buffer_set_vlan_count (b, l->n_tags);
     618             :     }
     619             :   else
     620          36 :     b->error = node->errors[l->err];
     621             : 
     622             :   /* update counters */
     623        4990 :   l->n_packets += 1;
     624        4990 :   l->n_bytes += vlib_buffer_length_in_chain (vm, b);
     625        4990 : }
     626             : 
     627             : #define DMAC_MASK clib_net_to_host_u64 (0xFFFFFFFFFFFF0000)
     628             : #define DMAC_IGBIT clib_net_to_host_u64 (0x0100000000000000)
     629             : 
     630             : #ifdef CLIB_HAVE_VEC256
     631             : static_always_inline u32
     632     3687420 : is_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
     633             : {
     634     3687420 :   u64x4 r0 = u64x4_load_unaligned (dmacs) & u64x4_splat (DMAC_MASK);
     635     3687420 :   r0 = (r0 != u64x4_splat (hwaddr)) & ((r0 & u64x4_splat (DMAC_IGBIT)) == 0);
     636     3687420 :   return u8x32_msb_mask ((u8x32) (r0));
     637             : }
     638             : #endif
     639             : 
     640             : static_always_inline u8
     641     4763310 : is_dmac_bad (u64 dmac, u64 hwaddr)
     642             : {
     643     4763310 :   u64 r0 = dmac & DMAC_MASK;
     644     4763310 :   return (r0 != hwaddr) && ((r0 & DMAC_IGBIT) == 0);
     645             : }
     646             : 
     647             : static_always_inline u8
     648         734 : is_sec_dmac_bad (u64 dmac, u64 hwaddr)
     649             : {
     650         734 :   return ((dmac & DMAC_MASK) != hwaddr);
     651             : }
     652             : 
     653             : #ifdef CLIB_HAVE_VEC256
     654             : static_always_inline u32
     655        5248 : is_sec_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
     656             : {
     657        5248 :   u64x4 r0 = u64x4_load_unaligned (dmacs) & u64x4_splat (DMAC_MASK);
     658        5248 :   r0 = (r0 != u64x4_splat (hwaddr));
     659        5248 :   return u8x32_msb_mask ((u8x32) (r0));
     660             : }
     661             : #endif
     662             : 
     663             : static_always_inline u8
     664         734 : eth_input_sec_dmac_check_x1 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
     665             : {
     666         734 :   dmac_bad[0] &= is_sec_dmac_bad (dmac[0], hwaddr);
     667         734 :   return dmac_bad[0];
     668             : }
     669             : 
     670             : static_always_inline u32
     671        5248 : eth_input_sec_dmac_check_x4 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
     672             : {
     673             : #ifdef CLIB_HAVE_VEC256
     674        5248 :   *(u32 *) (dmac_bad + 0) &= is_sec_dmac_bad_x4 (dmac + 0, hwaddr);
     675             : #else
     676           0 :   dmac_bad[0] &= is_sec_dmac_bad (dmac[0], hwaddr);
     677           0 :   dmac_bad[1] &= is_sec_dmac_bad (dmac[1], hwaddr);
     678           0 :   dmac_bad[2] &= is_sec_dmac_bad (dmac[2], hwaddr);
     679           0 :   dmac_bad[3] &= is_sec_dmac_bad (dmac[3], hwaddr);
     680             : #endif
     681        5248 :   return *(u32 *) dmac_bad;
     682             : }
     683             : 
     684             : /*
     685             :  * DMAC check for ethernet_input_inline()
     686             :  *
     687             :  * dmacs and dmacs_bad are arrays that are 2 elements long
     688             :  * n_packets should be 1 or 2 for ethernet_input_inline()
     689             :  */
     690             : static_always_inline void
     691     2381650 : ethernet_input_inline_dmac_check (vnet_hw_interface_t * hi,
     692             :                                   u64 * dmacs, u8 * dmacs_bad,
     693             :                                   u32 n_packets, ethernet_interface_t * ei,
     694             :                                   u8 have_sec_dmac)
     695             : {
     696     2381650 :   u64 hwaddr = ei->address.as_u64;
     697     2381650 :   u8 bad = 0;
     698             : 
     699     2381650 :   ASSERT (0 == ei->address.zero);
     700             : 
     701     2381650 :   dmacs_bad[0] = is_dmac_bad (dmacs[0], hwaddr);
     702     2381650 :   dmacs_bad[1] = ((n_packets > 1) & is_dmac_bad (dmacs[1], hwaddr));
     703             : 
     704     2381650 :   bad = dmacs_bad[0] | dmacs_bad[1];
     705             : 
     706     2381650 :   if (PREDICT_FALSE (bad && have_sec_dmac))
     707             :     {
     708             :       ethernet_interface_address_t *sec_addr;
     709             : 
     710           3 :       vec_foreach (sec_addr, ei->secondary_addrs)
     711             :       {
     712           2 :         ASSERT (0 == sec_addr->zero);
     713           2 :         hwaddr = sec_addr->as_u64;
     714             : 
     715           2 :         bad = (eth_input_sec_dmac_check_x1 (hwaddr, dmacs, dmacs_bad) |
     716           2 :                eth_input_sec_dmac_check_x1 (hwaddr, dmacs + 1,
     717             :                                             dmacs_bad + 1));
     718             : 
     719           2 :         if (!bad)
     720           0 :           return;
     721             :       }
     722             :     }
     723             : }
     724             : 
     725             : static_always_inline void
     726      283479 : eth_input_process_frame_dmac_check (vnet_hw_interface_t * hi,
     727             :                                     u64 * dmacs, u8 * dmacs_bad,
     728             :                                     u32 n_packets, ethernet_interface_t * ei,
     729             :                                     u8 have_sec_dmac)
     730             : {
     731      283479 :   u64 hwaddr = ei->address.as_u64;
     732      283479 :   u64 *dmac = dmacs;
     733      283479 :   u8 *dmac_bad = dmacs_bad;
     734      283479 :   u32 bad = 0;
     735      283479 :   i32 n_left = n_packets;
     736             : 
     737      283479 :   ASSERT (0 == ei->address.zero);
     738             : 
     739             : #ifdef CLIB_HAVE_VEC256
     740     2127190 :   while (n_left > 0)
     741             :     {
     742     1843710 :       bad |= *(u32 *) (dmac_bad + 0) = is_dmac_bad_x4 (dmac + 0, hwaddr);
     743     1843710 :       bad |= *(u32 *) (dmac_bad + 4) = is_dmac_bad_x4 (dmac + 4, hwaddr);
     744             : 
     745             :       /* next */
     746     1843710 :       dmac += 8;
     747     1843710 :       dmac_bad += 8;
     748     1843710 :       n_left -= 8;
     749             :     }
     750             : #else
     751           0 :   while (n_left > 0)
     752             :     {
     753           0 :       bad |= dmac_bad[0] = is_dmac_bad (dmac[0], hwaddr);
     754           0 :       bad |= dmac_bad[1] = is_dmac_bad (dmac[1], hwaddr);
     755           0 :       bad |= dmac_bad[2] = is_dmac_bad (dmac[2], hwaddr);
     756           0 :       bad |= dmac_bad[3] = is_dmac_bad (dmac[3], hwaddr);
     757             : 
     758             :       /* next */
     759           0 :       dmac += 4;
     760           0 :       dmac_bad += 4;
     761           0 :       n_left -= 4;
     762             :     }
     763             : #endif
     764             : 
     765      283479 :   if (have_sec_dmac && bad)
     766             :     {
     767             :       ethernet_interface_address_t *addr;
     768             : 
     769      178263 :       vec_foreach (addr, ei->secondary_addrs)
     770             :       {
     771      178142 :         u64 hwaddr = addr->as_u64;
     772      178142 :         i32 n_left = n_packets;
     773      178142 :         u64 *dmac = dmacs;
     774      178142 :         u8 *dmac_bad = dmacs_bad;
     775             : 
     776      178142 :         ASSERT (0 == addr->zero);
     777             : 
     778      178142 :         bad = 0;
     779             : 
     780     5317540 :         while (n_left > 0)
     781             :           {
     782     5139400 :             int adv = 0;
     783             :             int n_bad;
     784             : 
     785             :             /* skip any that have already matched */
     786     5139400 :             if (!dmac_bad[0])
     787             :               {
     788     5133660 :                 dmac += 1;
     789     5133660 :                 dmac_bad += 1;
     790     5133660 :                 n_left -= 1;
     791     5133660 :                 continue;
     792             :               }
     793             : 
     794        5732 :             n_bad = clib_min (4, n_left);
     795             : 
     796             :             /* If >= 4 left, compare 4 together */
     797        5732 :             if (n_bad == 4)
     798             :               {
     799        5248 :                 bad |= eth_input_sec_dmac_check_x4 (hwaddr, dmac, dmac_bad);
     800        5248 :                 adv = 4;
     801        5248 :                 n_bad = 0;
     802             :               }
     803             : 
     804             :             /* handle individually */
     805        6462 :             while (n_bad > 0)
     806             :               {
     807         730 :                 bad |= eth_input_sec_dmac_check_x1 (hwaddr, dmac + adv,
     808             :                                                     dmac_bad + adv);
     809         730 :                 adv += 1;
     810         730 :                 n_bad -= 1;
     811             :               }
     812             : 
     813        5732 :             dmac += adv;
     814        5732 :             dmac_bad += adv;
     815        5732 :             n_left -= adv;
     816             :           }
     817             : 
     818      178142 :         if (!bad)               /* can stop looping if everything matched */
     819      177602 :           break;
     820             :       }
     821             :     }
     822      283479 : }
     823             : 
     824             : /* process frame of buffers, store ethertype into array and update
     825             :    buffer metadata fields depending on interface being l2 or l3 assuming that
     826             :    packets are untagged. For tagged packets those fields are updated later.
     827             :    Optionally store Destionation MAC address and tag data into arrays
     828             :    for further processing */
     829             : 
     830             : STATIC_ASSERT (VLIB_FRAME_SIZE % 8 == 0,
     831             :                "VLIB_FRAME_SIZE must be power of 8");
     832             : static_always_inline void
     833     1265850 : eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
     834             :                          vnet_hw_interface_t * hi,
     835             :                          u32 * buffer_indices, u32 n_packets, int main_is_l3,
     836             :                          int ip4_cksum_ok, int dmac_check)
     837             : {
     838     1265850 :   ethernet_main_t *em = &ethernet_main;
     839             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     840     1265850 :   u16 etypes[VLIB_FRAME_SIZE], *etype = etypes;
     841     1265850 :   u64 dmacs[VLIB_FRAME_SIZE], *dmac = dmacs;
     842             :   u8 dmacs_bad[VLIB_FRAME_SIZE];
     843     1265850 :   u64 tags[VLIB_FRAME_SIZE], *tag = tags;
     844             :   u16 slowpath_indices[VLIB_FRAME_SIZE];
     845             :   u16 n_slowpath, i;
     846             :   u16 next_ip4, next_ip6, next_mpls, next_l2;
     847     1265850 :   u16 et_ip4 = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
     848     1265850 :   u16 et_ip6 = clib_host_to_net_u16 (ETHERNET_TYPE_IP6);
     849     1265850 :   u16 et_mpls = clib_host_to_net_u16 (ETHERNET_TYPE_MPLS);
     850     1265850 :   u16 et_vlan = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     851     1265850 :   u16 et_dot1ad = clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD);
     852     1265850 :   i32 n_left = n_packets;
     853             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
     854     1265850 :   vlib_buffer_t **b = bufs;
     855     1265850 :   ethernet_interface_t *ei = ethernet_get_interface (em, hi->hw_if_index);
     856             : 
     857     1265850 :   vlib_get_buffers (vm, buffer_indices, b, n_left);
     858             : 
     859    12048900 :   while (n_left >= 20)
     860             :     {
     861    10783000 :       vlib_buffer_t **ph = b + 16, **pd = b + 8;
     862             : 
     863    10783000 :       vlib_prefetch_buffer_header (ph[0], LOAD);
     864    10783000 :       vlib_prefetch_buffer_data (pd[0], LOAD);
     865    10783000 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
     866             : 
     867    10783000 :       vlib_prefetch_buffer_header (ph[1], LOAD);
     868    10783000 :       vlib_prefetch_buffer_data (pd[1], LOAD);
     869    10783000 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
     870             : 
     871    10783000 :       vlib_prefetch_buffer_header (ph[2], LOAD);
     872    10783000 :       vlib_prefetch_buffer_data (pd[2], LOAD);
     873    10783000 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
     874             : 
     875    10783000 :       vlib_prefetch_buffer_header (ph[3], LOAD);
     876    10783000 :       vlib_prefetch_buffer_data (pd[3], LOAD);
     877    10783000 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
     878             : 
     879    10783000 :       eth_input_adv_and_flags_x4 (b, main_is_l3);
     880             : 
     881             :       /* next */
     882    10783000 :       b += 4;
     883    10783000 :       n_left -= 4;
     884    10783000 :       etype += 4;
     885    10783000 :       tag += 4;
     886    10783000 :       dmac += 4;
     887             :     }
     888     5381250 :   while (n_left >= 4)
     889             :     {
     890     4115400 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
     891     4115400 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 1, dmac_check);
     892     4115400 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 2, dmac_check);
     893     4115400 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 3, dmac_check);
     894     4115400 :       eth_input_adv_and_flags_x4 (b, main_is_l3);
     895             : 
     896             :       /* next */
     897     4115400 :       b += 4;
     898     4115400 :       n_left -= 4;
     899     4115400 :       etype += 4;
     900     4115400 :       tag += 4;
     901     4115400 :       dmac += 4;
     902             :     }
     903     3122150 :   while (n_left)
     904             :     {
     905     1856300 :       eth_input_get_etype_and_tags (b, etype, tag, dmac, 0, dmac_check);
     906     1856300 :       eth_input_adv_and_flags_x1 (b, main_is_l3);
     907             : 
     908             :       /* next */
     909     1856300 :       b += 1;
     910     1856300 :       n_left -= 1;
     911     1856300 :       etype += 1;
     912     1856300 :       tag += 1;
     913     1856300 :       dmac += 1;
     914             :     }
     915             : 
     916     1265850 :   if (dmac_check)
     917             :     {
     918      283479 :       if (ei && vec_len (ei->secondary_addrs))
     919      282948 :         eth_input_process_frame_dmac_check (hi, dmacs, dmacs_bad, n_packets,
     920             :                                             ei, 1 /* have_sec_dmac */ );
     921             :       else
     922         531 :         eth_input_process_frame_dmac_check (hi, dmacs, dmacs_bad, n_packets,
     923             :                                             ei, 0 /* have_sec_dmac */ );
     924             :     }
     925             : 
     926     1265850 :   next_ip4 = em->l3_next.input_next_ip4;
     927     1265850 :   next_ip6 = em->l3_next.input_next_ip6;
     928     1265850 :   next_mpls = em->l3_next.input_next_mpls;
     929     1265850 :   next_l2 = em->l2_next;
     930             : 
     931     1265850 :   if (next_ip4 == ETHERNET_INPUT_NEXT_IP4_INPUT && ip4_cksum_ok)
     932           0 :     next_ip4 = ETHERNET_INPUT_NEXT_IP4_INPUT_NCS;
     933             : 
     934             : #ifdef CLIB_HAVE_VEC256
     935     1265850 :   u16x16 et16_ip4 = u16x16_splat (et_ip4);
     936     1265850 :   u16x16 et16_ip6 = u16x16_splat (et_ip6);
     937     1265850 :   u16x16 et16_mpls = u16x16_splat (et_mpls);
     938     1265850 :   u16x16 et16_vlan = u16x16_splat (et_vlan);
     939     1265850 :   u16x16 et16_dot1ad = u16x16_splat (et_dot1ad);
     940     1265850 :   u16x16 next16_ip4 = u16x16_splat (next_ip4);
     941     1265850 :   u16x16 next16_ip6 = u16x16_splat (next_ip6);
     942     1265850 :   u16x16 next16_mpls = u16x16_splat (next_mpls);
     943     1265850 :   u16x16 next16_l2 = u16x16_splat (next_l2);
     944     1265850 :   u16x16 zero = { 0 };
     945     1265850 :   u16x16 stairs = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
     946             : #endif
     947             : 
     948     1265850 :   etype = etypes;
     949     1265850 :   n_left = n_packets;
     950     1265850 :   next = nexts;
     951     1265850 :   n_slowpath = 0;
     952     1265850 :   i = 0;
     953             : 
     954             :   /* fastpath - in l3 mode hadles ip4, ip6 and mpls packets, other packets
     955             :      are considered as slowpath, in l2 mode all untagged packets are
     956             :      considered as fastpath */
     957    10930200 :   while (n_left > 0)
     958             :     {
     959             : #ifdef CLIB_HAVE_VEC256
     960     9664390 :       if (n_left >= 16)
     961             :         {
     962     3452380 :           u16x16 r = zero;
     963     3452380 :           u16x16 e16 = u16x16_load_unaligned (etype);
     964     3452380 :           if (main_is_l3)
     965             :             {
     966      779334 :               r += (e16 == et16_ip4) & next16_ip4;
     967      779334 :               r += (e16 == et16_ip6) & next16_ip6;
     968      779334 :               r += (e16 == et16_mpls) & next16_mpls;
     969             :             }
     970             :           else
     971     2673050 :             r = ((e16 != et16_vlan) & (e16 != et16_dot1ad)) & next16_l2;
     972     3452380 :           u16x16_store_unaligned (r, next);
     973             : 
     974     3452380 :           if (!u16x16_is_all_zero (r == zero))
     975             :             {
     976         291 :               if (u16x16_is_all_zero (r))
     977             :                 {
     978         291 :                   u16x16_store_unaligned (u16x16_splat (i) + stairs,
     979         291 :                                           slowpath_indices + n_slowpath);
     980         291 :                   n_slowpath += 16;
     981             :                 }
     982             :               else
     983             :                 {
     984           0 :                   for (int j = 0; j < 16; j++)
     985           0 :                     if (next[j] == 0)
     986           0 :                       slowpath_indices[n_slowpath++] = i + j;
     987             :                 }
     988             :             }
     989             : 
     990     3452380 :           etype += 16;
     991     3452380 :           next += 16;
     992     3452380 :           n_left -= 16;
     993     3452380 :           i += 16;
     994     3452380 :           continue;
     995             :         }
     996             : #endif
     997     6212010 :       if (main_is_l3 && etype[0] == et_ip4)
     998      645259 :         next[0] = next_ip4;
     999     5566750 :       else if (main_is_l3 && etype[0] == et_ip6)
    1000      561613 :         next[0] = next_ip6;
    1001     5005140 :       else if (main_is_l3 && etype[0] == et_mpls)
    1002         125 :         next[0] = next_mpls;
    1003     5005010 :       else if (main_is_l3 == 0 &&
    1004     5002640 :                etype[0] != et_vlan && etype[0] != et_dot1ad)
    1005     5002600 :         next[0] = next_l2;
    1006             :       else
    1007             :         {
    1008        2411 :           next[0] = 0;
    1009        2411 :           slowpath_indices[n_slowpath++] = i;
    1010             :         }
    1011             : 
    1012     6212010 :       etype += 1;
    1013     6212010 :       next += 1;
    1014     6212010 :       n_left -= 1;
    1015     6212010 :       i += 1;
    1016             :     }
    1017             : 
    1018     1265850 :   if (n_slowpath)
    1019             :     {
    1020        2257 :       vnet_main_t *vnm = vnet_get_main ();
    1021        2257 :       n_left = n_slowpath;
    1022        2257 :       u16 *si = slowpath_indices;
    1023        2257 :       u32 last_unknown_etype = ~0;
    1024        2257 :       u32 last_unknown_next = ~0;
    1025        2257 :       eth_input_tag_lookup_t dot1ad_lookup, dot1q_lookup = {
    1026             :         .mask = -1LL,
    1027        2257 :         .tag = tags[si[0]] ^ -1LL,
    1028             :         .sw_if_index = ~0
    1029             :       };
    1030             : 
    1031        2257 :       clib_memcpy_fast (&dot1ad_lookup, &dot1q_lookup, sizeof (dot1q_lookup));
    1032             : 
    1033        9324 :       while (n_left)
    1034             :         {
    1035        7067 :           i = si[0];
    1036        7067 :           u16 etype = etypes[i];
    1037             : 
    1038        7067 :           if (etype == et_vlan)
    1039             :             {
    1040        4304 :               vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
    1041        4304 :               eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
    1042        4304 :                                     &dot1q_lookup, dmacs_bad[i], 0,
    1043             :                                     main_is_l3, dmac_check);
    1044             : 
    1045             :             }
    1046        2763 :           else if (etype == et_dot1ad)
    1047             :             {
    1048         686 :               vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
    1049         686 :               eth_input_tag_lookup (vm, vnm, node, hi, tags[i], nexts + i, b,
    1050         686 :                                     &dot1ad_lookup, dmacs_bad[i], 1,
    1051             :                                     main_is_l3, dmac_check);
    1052             :             }
    1053             :           else
    1054             :             {
    1055             :               /* untagged packet with not well known etyertype */
    1056        2077 :               if (last_unknown_etype != etype)
    1057             :                 {
    1058        2075 :                   last_unknown_etype = etype;
    1059        2075 :                   etype = clib_host_to_net_u16 (etype);
    1060        2075 :                   last_unknown_next = eth_input_next_by_type (etype);
    1061             :                 }
    1062        2077 :               if (dmac_check && main_is_l3 && dmacs_bad[i])
    1063           4 :                 {
    1064           4 :                   vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
    1065           4 :                   b->error = node->errors[ETHERNET_ERROR_L3_MAC_MISMATCH];
    1066           4 :                   nexts[i] = ETHERNET_INPUT_NEXT_PUNT;
    1067             :                 }
    1068             :               else
    1069        2073 :                 nexts[i] = last_unknown_next;
    1070             :             }
    1071             : 
    1072             :           /* next */
    1073        7067 :           n_left--;
    1074        7067 :           si++;
    1075             :         }
    1076             : 
    1077        2257 :       eth_input_update_if_counters (vm, vnm, &dot1q_lookup);
    1078        2257 :       eth_input_update_if_counters (vm, vnm, &dot1ad_lookup);
    1079             :     }
    1080             : 
    1081     1265850 :   vlib_buffer_enqueue_to_next (vm, node, buffer_indices, nexts, n_packets);
    1082     1265850 : }
    1083             : 
    1084             : static_always_inline void
    1085     1265850 : eth_input_single_int (vlib_main_t * vm, vlib_node_runtime_t * node,
    1086             :                       vnet_hw_interface_t * hi, u32 * from, u32 n_pkts,
    1087             :                       int ip4_cksum_ok)
    1088             : {
    1089     1265850 :   ethernet_main_t *em = &ethernet_main;
    1090             :   ethernet_interface_t *ei;
    1091     1265850 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
    1092     1265850 :   main_intf_t *intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
    1093     1265850 :   subint_config_t *subint0 = &intf0->untagged_subint;
    1094             : 
    1095     1265850 :   int main_is_l3 = (subint0->flags & SUBINT_CONFIG_L2) == 0;
    1096     1265850 :   int int_is_l3 = ei->flags & ETHERNET_INTERFACE_FLAG_STATUS_L3;
    1097             : 
    1098     1265850 :   if (main_is_l3)
    1099             :     {
    1100      283463 :       if (int_is_l3 ||          /* DMAC filter already done by NIC */
    1101      283463 :           ((hi->l2_if_count != 0) && (hi->l3_if_count == 0)))
    1102             :         {                       /* All L2 usage - DMAC check not needed */
    1103          32 :           eth_input_process_frame (vm, node, hi, from, n_pkts,
    1104             :                                    /*is_l3 */ 1, ip4_cksum_ok, 0);
    1105             :         }
    1106             :       else
    1107             :         {                       /* DMAC check needed for L3 */
    1108      283431 :           eth_input_process_frame (vm, node, hi, from, n_pkts,
    1109             :                                    /*is_l3 */ 1, ip4_cksum_ok, 1);
    1110             :         }
    1111      283463 :       return;
    1112             :     }
    1113             :   else
    1114             :     {
    1115      982383 :       if (hi->l3_if_count == 0)
    1116             :         {                       /* All L2 usage - DMAC check not needed */
    1117      982336 :           eth_input_process_frame (vm, node, hi, from, n_pkts,
    1118             :                                    /*is_l3 */ 0, ip4_cksum_ok, 0);
    1119             :         }
    1120             :       else
    1121             :         {                       /* DMAC check needed for L3 */
    1122          47 :           eth_input_process_frame (vm, node, hi, from, n_pkts,
    1123             :                                    /*is_l3 */ 0, ip4_cksum_ok, 1);
    1124             :         }
    1125      982383 :       return;
    1126             :     }
    1127             : }
    1128             : 
    1129             : static_always_inline void
    1130     1874010 : ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
    1131             :                       vlib_frame_t * from_frame)
    1132             : {
    1133     1874010 :   vnet_main_t *vnm = vnet_get_main ();
    1134             :   u32 *from, n_left;
    1135     1874010 :   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    1136             :     {
    1137       15578 :       from = vlib_frame_vector_args (from_frame);
    1138       15578 :       n_left = from_frame->n_vectors;
    1139             : 
    1140      540146 :       while (n_left)
    1141             :         {
    1142             :           ethernet_input_trace_t *t0;
    1143      524570 :           vlib_buffer_t *b0 = vlib_get_buffer (vm, from[0]);
    1144             : 
    1145      524586 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
    1146             :             {
    1147      523534 :               t0 = vlib_add_trace (vm, node, b0,
    1148             :                                    sizeof (ethernet_input_trace_t));
    1149      523645 :               clib_memcpy_fast (t0->packet_data, b0->data + b0->current_data,
    1150             :                                 sizeof (t0->packet_data));
    1151      523560 :               t0->frame_flags = from_frame->flags;
    1152      523551 :               clib_memcpy_fast (&t0->frame_data,
    1153      523560 :                                 vlib_frame_scalar_args (from_frame),
    1154             :                                 sizeof (ethernet_input_frame_t));
    1155             :             }
    1156      524568 :           from += 1;
    1157      524568 :           n_left -= 1;
    1158             :         }
    1159             :     }
    1160             : 
    1161             :   /* rx pcap capture if enabled */
    1162     1874010 :   if (PREDICT_FALSE (vnm->pcap.pcap_rx_enable))
    1163             :     {
    1164             :       u32 bi0;
    1165           9 :       vnet_pcap_t *pp = &vnm->pcap;
    1166             : 
    1167           9 :       from = vlib_frame_vector_args (from_frame);
    1168           9 :       n_left = from_frame->n_vectors;
    1169         188 :       while (n_left > 0)
    1170             :         {
    1171             :           vlib_buffer_t *b0;
    1172         179 :           bi0 = from[0];
    1173         179 :           from++;
    1174         179 :           n_left--;
    1175         179 :           b0 = vlib_get_buffer (vm, bi0);
    1176         179 :           if (vnet_is_packet_pcaped (pp, b0, ~0))
    1177          87 :             pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
    1178             :         }
    1179             :     }
    1180     1874010 : }
    1181             : 
    1182             : static_always_inline void
    1183      608165 : ethernet_input_inline (vlib_main_t * vm,
    1184             :                        vlib_node_runtime_t * node,
    1185             :                        u32 * from, u32 n_packets,
    1186             :                        ethernet_input_variant_t variant)
    1187             : {
    1188      608165 :   vnet_main_t *vnm = vnet_get_main ();
    1189      608165 :   ethernet_main_t *em = &ethernet_main;
    1190             :   vlib_node_runtime_t *error_node;
    1191             :   u32 n_left_from, next_index, *to_next;
    1192             :   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
    1193      608165 :   u32 thread_index = vm->thread_index;
    1194      608165 :   u32 cached_sw_if_index = ~0;
    1195      608165 :   u32 cached_is_l2 = 0;         /* shut up gcc */
    1196      608165 :   vnet_hw_interface_t *hi = NULL;       /* used for main interface only */
    1197      608165 :   ethernet_interface_t *ei = NULL;
    1198             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
    1199      608165 :   vlib_buffer_t **b = bufs;
    1200             : 
    1201      608165 :   if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
    1202           0 :     error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
    1203             :   else
    1204      608165 :     error_node = node;
    1205             : 
    1206      608165 :   n_left_from = n_packets;
    1207             : 
    1208      608165 :   next_index = node->cached_next_index;
    1209      608165 :   stats_sw_if_index = node->runtime_data[0];
    1210      608165 :   stats_n_packets = stats_n_bytes = 0;
    1211      608165 :   vlib_get_buffers (vm, from, bufs, n_left_from);
    1212             : 
    1213     1216330 :   while (n_left_from > 0)
    1214             :     {
    1215             :       u32 n_left_to_next;
    1216             : 
    1217      608168 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1218             : 
    1219     6432840 :       while (n_left_from >= 4 && n_left_to_next >= 2)
    1220             :         {
    1221             :           u32 bi0, bi1;
    1222             :           vlib_buffer_t *b0, *b1;
    1223             :           u8 next0, next1, error0, error1;
    1224             :           u16 type0, orig_type0, type1, orig_type1;
    1225             :           u16 outer_id0, inner_id0, outer_id1, inner_id1;
    1226             :           u32 match_flags0, match_flags1;
    1227             :           u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1,
    1228             :             new_sw_if_index1, len1;
    1229             :           vnet_hw_interface_t *hi0, *hi1;
    1230             :           main_intf_t *main_intf0, *main_intf1;
    1231             :           vlan_intf_t *vlan_intf0, *vlan_intf1;
    1232             :           qinq_intf_t *qinq_intf0, *qinq_intf1;
    1233             :           u32 is_l20, is_l21;
    1234             :           ethernet_header_t *e0, *e1;
    1235             :           u64 dmacs[2];
    1236             :           u8 dmacs_bad[2];
    1237             : 
    1238             :           /* Prefetch next iteration. */
    1239             :           {
    1240     5824670 :             vlib_prefetch_buffer_header (b[2], STORE);
    1241     5824670 :             vlib_prefetch_buffer_header (b[3], STORE);
    1242             : 
    1243     5824670 :             CLIB_PREFETCH (b[2]->data, sizeof (ethernet_header_t), LOAD);
    1244     5824670 :             CLIB_PREFETCH (b[3]->data, sizeof (ethernet_header_t), LOAD);
    1245             :           }
    1246             : 
    1247     5824670 :           bi0 = from[0];
    1248     5824670 :           bi1 = from[1];
    1249     5824670 :           to_next[0] = bi0;
    1250     5824670 :           to_next[1] = bi1;
    1251     5824670 :           from += 2;
    1252     5824670 :           to_next += 2;
    1253     5824670 :           n_left_to_next -= 2;
    1254     5824670 :           n_left_from -= 2;
    1255             : 
    1256     5824670 :           b0 = b[0];
    1257     5824670 :           b1 = b[1];
    1258     5824670 :           b += 2;
    1259             : 
    1260     5824670 :           error0 = error1 = ETHERNET_ERROR_NONE;
    1261     5824670 :           e0 = vlib_buffer_get_current (b0);
    1262     5824670 :           type0 = clib_net_to_host_u16 (e0->type);
    1263     5824670 :           e1 = vlib_buffer_get_current (b1);
    1264     5824670 :           type1 = clib_net_to_host_u16 (e1->type);
    1265             : 
    1266             :           /* Set the L2 header offset for all packets */
    1267     5824670 :           vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
    1268     5824670 :           vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
    1269     5824670 :           b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
    1270     5824670 :           b1->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
    1271             : 
    1272             :           /* Speed-path for the untagged case */
    1273     5824670 :           if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
    1274             :                             && !ethernet_frame_is_any_tagged_x2 (type0,
    1275             :                                                                  type1)))
    1276             :             {
    1277             :               main_intf_t *intf0;
    1278             :               subint_config_t *subint0;
    1279             :               u32 sw_if_index0, sw_if_index1;
    1280             : 
    1281     5824420 :               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1282     5824420 :               sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
    1283     5824420 :               is_l20 = cached_is_l2;
    1284             : 
    1285             :               /* This is probably wholly unnecessary */
    1286     5824420 :               if (PREDICT_FALSE (sw_if_index0 != sw_if_index1))
    1287       89986 :                 goto slowpath;
    1288             : 
    1289             :               /* Now sw_if_index0 == sw_if_index1  */
    1290     5734430 :               if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
    1291             :                 {
    1292      508201 :                   cached_sw_if_index = sw_if_index0;
    1293      508201 :                   hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
    1294      508201 :                   ei = ethernet_get_interface (em, hi->hw_if_index);
    1295      508201 :                   intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
    1296      508201 :                   subint0 = &intf0->untagged_subint;
    1297      508201 :                   cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
    1298             :                 }
    1299             : 
    1300     5734430 :               if (PREDICT_TRUE (is_l20 != 0))
    1301             :                 {
    1302     3774900 :                   vnet_buffer (b0)->l3_hdr_offset =
    1303     3774900 :                     vnet_buffer (b0)->l2_hdr_offset +
    1304             :                     sizeof (ethernet_header_t);
    1305     3774900 :                   vnet_buffer (b1)->l3_hdr_offset =
    1306     3774900 :                     vnet_buffer (b1)->l2_hdr_offset +
    1307             :                     sizeof (ethernet_header_t);
    1308     3774900 :                   b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
    1309     3774900 :                   b1->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
    1310     3774900 :                   next0 = em->l2_next;
    1311     3774900 :                   vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
    1312     3774900 :                   next1 = em->l2_next;
    1313     3774900 :                   vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
    1314             :                 }
    1315             :               else
    1316             :                 {
    1317     1959530 :                   if (ei && (ei->flags & ETHERNET_INTERFACE_FLAG_STATUS_L3))
    1318           0 :                     goto skip_dmac_check01;
    1319             : 
    1320     1959530 :                   dmacs[0] = *(u64 *) e0;
    1321     1959530 :                   dmacs[1] = *(u64 *) e1;
    1322             : 
    1323     1959530 :                   if (ei && vec_len (ei->secondary_addrs))
    1324     1959510 :                     ethernet_input_inline_dmac_check (hi, dmacs,
    1325             :                                                       dmacs_bad,
    1326             :                                                       2 /* n_packets */ ,
    1327             :                                                       ei,
    1328             :                                                       1 /* have_sec_dmac */ );
    1329             :                   else
    1330          21 :                     ethernet_input_inline_dmac_check (hi, dmacs,
    1331             :                                                       dmacs_bad,
    1332             :                                                       2 /* n_packets */ ,
    1333             :                                                       ei,
    1334             :                                                       0 /* have_sec_dmac */ );
    1335             : 
    1336     1959530 :                   if (dmacs_bad[0])
    1337          21 :                     error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
    1338     1959530 :                   if (dmacs_bad[1])
    1339          21 :                     error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
    1340             : 
    1341     1959510 :                 skip_dmac_check01:
    1342     1959530 :                   vlib_buffer_advance (b0, sizeof (ethernet_header_t));
    1343     1959530 :                   determine_next_node (em, variant, 0, type0, b0,
    1344             :                                        &error0, &next0);
    1345     1959530 :                   vlib_buffer_advance (b1, sizeof (ethernet_header_t));
    1346     1959530 :                   determine_next_node (em, variant, 0, type1, b1,
    1347             :                                        &error1, &next1);
    1348             :                 }
    1349     5734430 :               goto ship_it01;
    1350             :             }
    1351             : 
    1352             :           /* Slow-path for the tagged case */
    1353         254 :         slowpath:
    1354       90240 :           parse_header (variant,
    1355             :                         b0,
    1356             :                         &type0,
    1357             :                         &orig_type0, &outer_id0, &inner_id0, &match_flags0);
    1358             : 
    1359       90240 :           parse_header (variant,
    1360             :                         b1,
    1361             :                         &type1,
    1362             :                         &orig_type1, &outer_id1, &inner_id1, &match_flags1);
    1363             : 
    1364       90240 :           old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1365       90240 :           old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
    1366             : 
    1367       90240 :           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);
    1375             : 
    1376       90240 :           eth_vlan_table_lookups (em,
    1377             :                                   vnm,
    1378             :                                   old_sw_if_index1,
    1379             :                                   orig_type1,
    1380             :                                   outer_id1,
    1381             :                                   inner_id1,
    1382             :                                   &hi1,
    1383             :                                   &main_intf1, &vlan_intf1, &qinq_intf1);
    1384             : 
    1385       90240 :           identify_subint (em,
    1386             :                            hi0,
    1387             :                            b0,
    1388             :                            match_flags0,
    1389             :                            main_intf0,
    1390             :                            vlan_intf0,
    1391             :                            qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
    1392             : 
    1393       90240 :           identify_subint (em,
    1394             :                            hi1,
    1395             :                            b1,
    1396             :                            match_flags1,
    1397             :                            main_intf1,
    1398             :                            vlan_intf1,
    1399             :                            qinq_intf1, &new_sw_if_index1, &error1, &is_l21);
    1400             : 
    1401             :           // Save RX sw_if_index for later nodes
    1402       90240 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] =
    1403       90240 :             error0 !=
    1404       90240 :             ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
    1405       90240 :           vnet_buffer (b1)->sw_if_index[VLIB_RX] =
    1406       90240 :             error1 !=
    1407       90240 :             ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
    1408             : 
    1409             :           // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
    1410       90240 :           if (((new_sw_if_index0 != ~0)
    1411       90240 :                && (new_sw_if_index0 != old_sw_if_index0))
    1412       89986 :               || ((new_sw_if_index1 != ~0)
    1413       89986 :                   && (new_sw_if_index1 != old_sw_if_index1)))
    1414             :             {
    1415             : 
    1416         254 :               len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
    1417         254 :                 - vnet_buffer (b0)->l2_hdr_offset;
    1418         254 :               len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
    1419         254 :                 - vnet_buffer (b1)->l2_hdr_offset;
    1420             : 
    1421         254 :               stats_n_packets += 2;
    1422         254 :               stats_n_bytes += len0 + len1;
    1423             : 
    1424         254 :               if (PREDICT_FALSE
    1425             :                   (!(new_sw_if_index0 == stats_sw_if_index
    1426             :                      && new_sw_if_index1 == stats_sw_if_index)))
    1427             :                 {
    1428           2 :                   stats_n_packets -= 2;
    1429           2 :                   stats_n_bytes -= len0 + len1;
    1430             : 
    1431           2 :                   if (new_sw_if_index0 != old_sw_if_index0
    1432           2 :                       && new_sw_if_index0 != ~0)
    1433           2 :                     vlib_increment_combined_counter (vnm->
    1434             :                                                      interface_main.combined_sw_if_counters
    1435             :                                                      +
    1436             :                                                      VNET_INTERFACE_COUNTER_RX,
    1437             :                                                      thread_index,
    1438             :                                                      new_sw_if_index0, 1,
    1439             :                                                      len0);
    1440           2 :                   if (new_sw_if_index1 != old_sw_if_index1
    1441           2 :                       && new_sw_if_index1 != ~0)
    1442           2 :                     vlib_increment_combined_counter (vnm->
    1443             :                                                      interface_main.combined_sw_if_counters
    1444             :                                                      +
    1445             :                                                      VNET_INTERFACE_COUNTER_RX,
    1446             :                                                      thread_index,
    1447             :                                                      new_sw_if_index1, 1,
    1448             :                                                      len1);
    1449             : 
    1450           2 :                   if (new_sw_if_index0 == new_sw_if_index1)
    1451             :                     {
    1452           2 :                       if (stats_n_packets > 0)
    1453             :                         {
    1454           0 :                           vlib_increment_combined_counter
    1455             :                             (vnm->interface_main.combined_sw_if_counters
    1456             :                              + VNET_INTERFACE_COUNTER_RX,
    1457             :                              thread_index,
    1458             :                              stats_sw_if_index,
    1459             :                              stats_n_packets, stats_n_bytes);
    1460           0 :                           stats_n_packets = stats_n_bytes = 0;
    1461             :                         }
    1462           2 :                       stats_sw_if_index = new_sw_if_index0;
    1463             :                     }
    1464             :                 }
    1465             :             }
    1466             : 
    1467       90240 :           if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
    1468           0 :             is_l20 = is_l21 = 0;
    1469             : 
    1470       90240 :           determine_next_node (em, variant, is_l20, type0, b0, &error0,
    1471             :                                &next0);
    1472       90240 :           determine_next_node (em, variant, is_l21, type1, b1, &error1,
    1473             :                                &next1);
    1474             : 
    1475     5824670 :         ship_it01:
    1476     5824670 :           b0->error = error_node->errors[error0];
    1477     5824670 :           b1->error = error_node->errors[error1];
    1478             : 
    1479             :           // verify speculative enqueue
    1480     5824670 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
    1481             :                                            n_left_to_next, bi0, bi1, next0,
    1482             :                                            next1);
    1483             :         }
    1484             : 
    1485     1741190 :       while (n_left_from > 0 && n_left_to_next > 0)
    1486             :         {
    1487             :           u32 bi0;
    1488             :           vlib_buffer_t *b0;
    1489             :           u8 error0, next0;
    1490             :           u16 type0, orig_type0;
    1491             :           u16 outer_id0, inner_id0;
    1492             :           u32 match_flags0;
    1493             :           u32 old_sw_if_index0, new_sw_if_index0, len0;
    1494             :           vnet_hw_interface_t *hi0;
    1495             :           main_intf_t *main_intf0;
    1496             :           vlan_intf_t *vlan_intf0;
    1497             :           qinq_intf_t *qinq_intf0;
    1498             :           ethernet_header_t *e0;
    1499             :           u32 is_l20;
    1500             :           u64 dmacs[2];
    1501             :           u8 dmacs_bad[2];
    1502             : 
    1503             :           // Prefetch next iteration
    1504     1133020 :           if (n_left_from > 1)
    1505             :             {
    1506      524860 :               vlib_prefetch_buffer_header (b[1], STORE);
    1507      524860 :               clib_prefetch_load (b[1]->data);
    1508             :             }
    1509             : 
    1510     1133020 :           bi0 = from[0];
    1511     1133020 :           to_next[0] = bi0;
    1512     1133020 :           from += 1;
    1513     1133020 :           to_next += 1;
    1514     1133020 :           n_left_from -= 1;
    1515     1133020 :           n_left_to_next -= 1;
    1516             : 
    1517     1133020 :           b0 = b[0];
    1518     1133020 :           b += 1;
    1519             : 
    1520     1133020 :           error0 = ETHERNET_ERROR_NONE;
    1521     1133020 :           e0 = vlib_buffer_get_current (b0);
    1522     1133020 :           type0 = clib_net_to_host_u16 (e0->type);
    1523             : 
    1524             :           /* Set the L2 header offset for all packets */
    1525     1133020 :           vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
    1526     1133020 :           b0->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID;
    1527             : 
    1528             :           /* Speed-path for the untagged case */
    1529     1133020 :           if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
    1530             :                             && !ethernet_frame_is_tagged (type0)))
    1531             :             {
    1532             :               main_intf_t *intf0;
    1533             :               subint_config_t *subint0;
    1534             :               u32 sw_if_index0;
    1535             : 
    1536     1133020 :               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1537     1133020 :               is_l20 = cached_is_l2;
    1538             : 
    1539     1133020 :               if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
    1540             :                 {
    1541      262803 :                   cached_sw_if_index = sw_if_index0;
    1542      262803 :                   hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
    1543      262803 :                   ei = ethernet_get_interface (em, hi->hw_if_index);
    1544      262803 :                   intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
    1545      262803 :                   subint0 = &intf0->untagged_subint;
    1546      262803 :                   cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
    1547             :                 }
    1548             : 
    1549             : 
    1550     1133020 :               if (PREDICT_TRUE (is_l20 != 0))
    1551             :                 {
    1552      738737 :                   vnet_buffer (b0)->l3_hdr_offset =
    1553      738737 :                     vnet_buffer (b0)->l2_hdr_offset +
    1554             :                     sizeof (ethernet_header_t);
    1555      738737 :                   b0->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
    1556      738737 :                   next0 = em->l2_next;
    1557      738737 :                   vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
    1558             :                 }
    1559             :               else
    1560             :                 {
    1561      394282 :                   if (ei && ei->flags & ETHERNET_INTERFACE_FLAG_STATUS_L3)
    1562           0 :                     goto skip_dmac_check0;
    1563             : 
    1564      394282 :                   dmacs[0] = *(u64 *) e0;
    1565             : 
    1566      394282 :                   if (ei)
    1567             :                     {
    1568      394282 :                       if (vec_len (ei->secondary_addrs))
    1569      394166 :                         ethernet_input_inline_dmac_check (
    1570             :                           hi, dmacs, dmacs_bad, 1 /* n_packets */, ei,
    1571             :                           1 /* have_sec_dmac */);
    1572             :                       else
    1573         116 :                         ethernet_input_inline_dmac_check (
    1574             :                           hi, dmacs, dmacs_bad, 1 /* n_packets */, ei,
    1575             :                           0 /* have_sec_dmac */);
    1576             : 
    1577      394282 :                       if (dmacs_bad[0])
    1578           5 :                         error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
    1579             :                     }
    1580             : 
    1581      394277 :                 skip_dmac_check0:
    1582      394282 :                   vlib_buffer_advance (b0, sizeof (ethernet_header_t));
    1583      394282 :                   determine_next_node (em, variant, 0, type0, b0,
    1584             :                                        &error0, &next0);
    1585             :                 }
    1586     1133020 :               goto ship_it0;
    1587             :             }
    1588             : 
    1589             :           /* Slow-path for the tagged case */
    1590           6 :           parse_header (variant,
    1591             :                         b0,
    1592             :                         &type0,
    1593             :                         &orig_type0, &outer_id0, &inner_id0, &match_flags0);
    1594             : 
    1595           6 :           old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1596             : 
    1597           6 :           eth_vlan_table_lookups (em,
    1598             :                                   vnm,
    1599             :                                   old_sw_if_index0,
    1600             :                                   orig_type0,
    1601             :                                   outer_id0,
    1602             :                                   inner_id0,
    1603             :                                   &hi0,
    1604             :                                   &main_intf0, &vlan_intf0, &qinq_intf0);
    1605             : 
    1606           6 :           identify_subint (em,
    1607             :                            hi0,
    1608             :                            b0,
    1609             :                            match_flags0,
    1610             :                            main_intf0,
    1611             :                            vlan_intf0,
    1612             :                            qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
    1613             : 
    1614             :           // Save RX sw_if_index for later nodes
    1615           6 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] =
    1616           6 :             error0 !=
    1617           6 :             ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
    1618             : 
    1619             :           // Increment subinterface stats
    1620             :           // Note that interface-level counters have already been incremented
    1621             :           // prior to calling this function. Thus only subinterface counters
    1622             :           // are incremented here.
    1623             :           //
    1624             :           // Interface level counters include packets received on the main
    1625             :           // interface and all subinterfaces. Subinterface level counters
    1626             :           // include only those packets received on that subinterface
    1627             :           // Increment stats if the subint is valid and it is not the main intf
    1628           6 :           if ((new_sw_if_index0 != ~0)
    1629           6 :               && (new_sw_if_index0 != old_sw_if_index0))
    1630             :             {
    1631             : 
    1632           6 :               len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
    1633           6 :                 - vnet_buffer (b0)->l2_hdr_offset;
    1634             : 
    1635           6 :               stats_n_packets += 1;
    1636           6 :               stats_n_bytes += len0;
    1637             : 
    1638             :               // Batch stat increments from the same subinterface so counters
    1639             :               // don't need to be incremented for every packet.
    1640           6 :               if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index))
    1641             :                 {
    1642           0 :                   stats_n_packets -= 1;
    1643           0 :                   stats_n_bytes -= len0;
    1644             : 
    1645           0 :                   if (new_sw_if_index0 != ~0)
    1646           0 :                     vlib_increment_combined_counter
    1647             :                       (vnm->interface_main.combined_sw_if_counters
    1648             :                        + VNET_INTERFACE_COUNTER_RX,
    1649             :                        thread_index, new_sw_if_index0, 1, len0);
    1650           0 :                   if (stats_n_packets > 0)
    1651             :                     {
    1652           0 :                       vlib_increment_combined_counter
    1653             :                         (vnm->interface_main.combined_sw_if_counters
    1654             :                          + VNET_INTERFACE_COUNTER_RX,
    1655             :                          thread_index,
    1656             :                          stats_sw_if_index, stats_n_packets, stats_n_bytes);
    1657           0 :                       stats_n_packets = stats_n_bytes = 0;
    1658             :                     }
    1659           0 :                   stats_sw_if_index = new_sw_if_index0;
    1660             :                 }
    1661             :             }
    1662             : 
    1663           6 :           if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
    1664           0 :             is_l20 = 0;
    1665             : 
    1666           6 :           determine_next_node (em, variant, is_l20, type0, b0, &error0,
    1667             :                                &next0);
    1668             : 
    1669     1133020 :         ship_it0:
    1670     1133020 :           b0->error = error_node->errors[error0];
    1671             : 
    1672             :           // verify speculative enqueue
    1673     1133020 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
    1674             :                                            to_next, n_left_to_next,
    1675             :                                            bi0, next0);
    1676             :         }
    1677             : 
    1678      608168 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1679             :     }
    1680             : 
    1681             :   // Increment any remaining batched stats
    1682      608165 :   if (stats_n_packets > 0)
    1683             :     {
    1684           4 :       vlib_increment_combined_counter
    1685             :         (vnm->interface_main.combined_sw_if_counters
    1686             :          + VNET_INTERFACE_COUNTER_RX,
    1687             :          thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
    1688           4 :       node->runtime_data[0] = stats_sw_if_index;
    1689             :     }
    1690      608165 : }
    1691             : 
    1692     1876310 : VLIB_NODE_FN (ethernet_input_node) (vlib_main_t * vm,
    1693             :                                     vlib_node_runtime_t * node,
    1694             :                                     vlib_frame_t * frame)
    1695             : {
    1696     1874010 :   vnet_main_t *vnm = vnet_get_main ();
    1697     1874010 :   u32 *from = vlib_frame_vector_args (frame);
    1698     1874010 :   u32 n_packets = frame->n_vectors;
    1699             : 
    1700     1874010 :   ethernet_input_trace (vm, node, frame);
    1701             : 
    1702     1874010 :   if (frame->flags & ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX)
    1703             :     {
    1704     1265850 :       ethernet_input_frame_t *ef = vlib_frame_scalar_args (frame);
    1705     1265850 :       int ip4_cksum_ok = (frame->flags & ETH_INPUT_FRAME_F_IP4_CKSUM_OK) != 0;
    1706     1265850 :       vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ef->hw_if_index);
    1707     1265850 :       eth_input_single_int (vm, node, hi, from, n_packets, ip4_cksum_ok);
    1708             :     }
    1709             :   else
    1710      608165 :     ethernet_input_inline (vm, node, from, n_packets,
    1711             :                            ETHERNET_INPUT_VARIANT_ETHERNET);
    1712     1874010 :   return n_packets;
    1713             : }
    1714             : 
    1715        2300 : VLIB_NODE_FN (ethernet_input_type_node) (vlib_main_t * vm,
    1716             :                                          vlib_node_runtime_t * node,
    1717             :                                          vlib_frame_t * from_frame)
    1718             : {
    1719           0 :   u32 *from = vlib_frame_vector_args (from_frame);
    1720           0 :   u32 n_packets = from_frame->n_vectors;
    1721           0 :   ethernet_input_trace (vm, node, from_frame);
    1722           0 :   ethernet_input_inline (vm, node, from, n_packets,
    1723             :                          ETHERNET_INPUT_VARIANT_ETHERNET_TYPE);
    1724           0 :   return n_packets;
    1725             : }
    1726             : 
    1727        2300 : VLIB_NODE_FN (ethernet_input_not_l2_node) (vlib_main_t * vm,
    1728             :                                            vlib_node_runtime_t * node,
    1729             :                                            vlib_frame_t * from_frame)
    1730             : {
    1731           0 :   u32 *from = vlib_frame_vector_args (from_frame);
    1732           0 :   u32 n_packets = from_frame->n_vectors;
    1733           0 :   ethernet_input_trace (vm, node, from_frame);
    1734           0 :   ethernet_input_inline (vm, node, from, n_packets,
    1735             :                          ETHERNET_INPUT_VARIANT_NOT_L2);
    1736           0 :   return n_packets;
    1737             : }
    1738             : 
    1739             : 
    1740             : // Return the subinterface config struct for the given sw_if_index
    1741             : // Also return via parameter the appropriate match flags for the
    1742             : // configured number of tags.
    1743             : // On error (unsupported or not ethernet) return 0.
    1744             : static subint_config_t *
    1745       28865 : ethernet_sw_interface_get_config (vnet_main_t * vnm,
    1746             :                                   u32 sw_if_index,
    1747             :                                   u32 * flags, u32 * unsupported)
    1748             : {
    1749       28865 :   ethernet_main_t *em = &ethernet_main;
    1750             :   vnet_hw_interface_t *hi;
    1751             :   vnet_sw_interface_t *si;
    1752             :   main_intf_t *main_intf;
    1753             :   vlan_table_t *vlan_table;
    1754             :   qinq_table_t *qinq_table;
    1755       28865 :   subint_config_t *subint = 0;
    1756             : 
    1757       28865 :   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1758             : 
    1759       28865 :   if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
    1760             :     {
    1761        3094 :       *unsupported = 0;
    1762        3094 :       goto done;                // non-ethernet interface
    1763             :     }
    1764             : 
    1765             :   // ensure there's an entry for the main intf (shouldn't really be necessary)
    1766       25771 :   vec_validate (em->main_intfs, hi->hw_if_index);
    1767       25771 :   main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
    1768             : 
    1769             :   // Locate the subint for the given ethernet config
    1770       25771 :   si = vnet_get_sw_interface (vnm, sw_if_index);
    1771             : 
    1772       25771 :   if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
    1773             :     {
    1774        2107 :       p2p_ethernet_main_t *p2pm = &p2p_main;
    1775             :       u32 p2pe_sw_if_index =
    1776        2107 :         p2p_ethernet_lookup (hi->hw_if_index, si->p2p.client_mac);
    1777        2107 :       if (p2pe_sw_if_index == ~0)
    1778             :         {
    1779        1023 :           pool_get (p2pm->p2p_subif_pool, subint);
    1780        1023 :           si->p2p.pool_index = subint - p2pm->p2p_subif_pool;
    1781             :         }
    1782             :       else
    1783        1084 :         subint = vec_elt_at_index (p2pm->p2p_subif_pool, si->p2p.pool_index);
    1784        2107 :       *flags = SUBINT_CONFIG_P2P;
    1785             :     }
    1786       23664 :   else if (si->type == VNET_SW_INTERFACE_TYPE_PIPE)
    1787             :     {
    1788             :       pipe_t *pipe;
    1789             : 
    1790          10 :       pipe = pipe_get (sw_if_index);
    1791          10 :       subint = &pipe->subint;
    1792          10 :       *flags = SUBINT_CONFIG_P2P;
    1793             :     }
    1794       23654 :   else if (si->sub.eth.flags.default_sub)
    1795             :     {
    1796           0 :       subint = &main_intf->default_subint;
    1797           0 :       *flags = SUBINT_CONFIG_MATCH_1_TAG |
    1798             :         SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
    1799             :     }
    1800       23654 :   else if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0))
    1801             :     {
    1802             :       // if no flags are set then this is a main interface
    1803             :       // so treat as untagged
    1804       23296 :       subint = &main_intf->untagged_subint;
    1805       23296 :       *flags = SUBINT_CONFIG_MATCH_0_TAG;
    1806             :     }
    1807             :   else
    1808             :     {
    1809             :       // one or two tags
    1810             :       // first get the vlan table
    1811         358 :       if (si->sub.eth.flags.dot1ad)
    1812             :         {
    1813          51 :           if (main_intf->dot1ad_vlans == 0)
    1814             :             {
    1815             :               // Allocate a vlan table from the pool
    1816          19 :               pool_get (em->vlan_pool, vlan_table);
    1817          19 :               main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
    1818             :             }
    1819             :           else
    1820             :             {
    1821             :               // Get ptr to existing vlan table
    1822          32 :               vlan_table =
    1823          32 :                 vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
    1824             :             }
    1825             :         }
    1826             :       else
    1827             :         {                       // dot1q
    1828         307 :           if (main_intf->dot1q_vlans == 0)
    1829             :             {
    1830             :               // Allocate a vlan table from the pool
    1831          34 :               pool_get (em->vlan_pool, vlan_table);
    1832          34 :               main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
    1833             :             }
    1834             :           else
    1835             :             {
    1836             :               // Get ptr to existing vlan table
    1837         273 :               vlan_table =
    1838         273 :                 vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
    1839             :             }
    1840             :         }
    1841             : 
    1842         358 :       if (si->sub.eth.flags.one_tag)
    1843             :         {
    1844         614 :           *flags = si->sub.eth.flags.exact_match ?
    1845         307 :             SUBINT_CONFIG_MATCH_1_TAG :
    1846             :             (SUBINT_CONFIG_MATCH_1_TAG |
    1847             :              SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
    1848             : 
    1849         307 :           if (si->sub.eth.flags.outer_vlan_id_any)
    1850             :             {
    1851             :               // not implemented yet
    1852           0 :               *unsupported = 1;
    1853           0 :               goto done;
    1854             :             }
    1855             :           else
    1856             :             {
    1857             :               // a single vlan, a common case
    1858         307 :               subint =
    1859         307 :                 &vlan_table->vlans[si->sub.eth.
    1860             :                                    outer_vlan_id].single_tag_subint;
    1861             :             }
    1862             : 
    1863             :         }
    1864             :       else
    1865             :         {
    1866             :           // Two tags
    1867         102 :           *flags = si->sub.eth.flags.exact_match ?
    1868          51 :             SUBINT_CONFIG_MATCH_2_TAG :
    1869             :             (SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
    1870             : 
    1871          51 :           if (si->sub.eth.flags.outer_vlan_id_any
    1872           0 :               && si->sub.eth.flags.inner_vlan_id_any)
    1873             :             {
    1874             :               // not implemented yet
    1875           0 :               *unsupported = 1;
    1876           0 :               goto done;
    1877             :             }
    1878             : 
    1879          51 :           if (si->sub.eth.flags.inner_vlan_id_any)
    1880             :             {
    1881             :               // a specific outer and "any" inner
    1882             :               // don't need a qinq table for this
    1883           0 :               subint =
    1884           0 :                 &vlan_table->vlans[si->sub.eth.
    1885             :                                    outer_vlan_id].inner_any_subint;
    1886           0 :               if (si->sub.eth.flags.exact_match)
    1887             :                 {
    1888           0 :                   *flags = SUBINT_CONFIG_MATCH_2_TAG;
    1889             :                 }
    1890             :               else
    1891             :                 {
    1892           0 :                   *flags = SUBINT_CONFIG_MATCH_2_TAG |
    1893             :                     SUBINT_CONFIG_MATCH_3_TAG;
    1894             :                 }
    1895             :             }
    1896             :           else
    1897             :             {
    1898             :               // a specific outer + specific innner vlan id, a common case
    1899             : 
    1900             :               // get the qinq table
    1901          51 :               if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0)
    1902             :                 {
    1903             :                   // Allocate a qinq table from the pool
    1904          19 :                   pool_get (em->qinq_pool, qinq_table);
    1905          19 :                   vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs =
    1906          19 :                     qinq_table - em->qinq_pool;
    1907             :                 }
    1908             :               else
    1909             :                 {
    1910             :                   // Get ptr to existing qinq table
    1911          32 :                   qinq_table =
    1912          32 :                     vec_elt_at_index (em->qinq_pool,
    1913             :                                       vlan_table->vlans[si->sub.
    1914             :                                                         eth.outer_vlan_id].
    1915             :                                       qinqs);
    1916             :                 }
    1917          51 :               subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
    1918             :             }
    1919             :         }
    1920             :     }
    1921             : 
    1922       28865 : done:
    1923       28865 :   return subint;
    1924             : }
    1925             : 
    1926             : static clib_error_t *
    1927       13514 : ethernet_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
    1928             : {
    1929             :   subint_config_t *subint;
    1930             :   u32 placeholder_flags;
    1931             :   u32 placeholder_unsup;
    1932       13514 :   clib_error_t *error = 0;
    1933             : 
    1934             :   // Find the config for this subinterface
    1935             :   subint =
    1936       13514 :     ethernet_sw_interface_get_config (vnm, sw_if_index, &placeholder_flags,
    1937             :                                       &placeholder_unsup);
    1938             : 
    1939       13514 :   if (subint == 0)
    1940             :     {
    1941             :       // not implemented yet or not ethernet
    1942        1214 :       goto done;
    1943             :     }
    1944             : 
    1945       12300 :   subint->sw_if_index =
    1946       12300 :     ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
    1947             : 
    1948       13514 : done:
    1949       13514 :   return error;
    1950             : }
    1951             : 
    1952        2881 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
    1953             : 
    1954             : 
    1955             : #ifndef CLIB_MARCH_VARIANT
    1956             : // Set the L2/L3 mode for the subinterface
    1957             : void
    1958        3553 : ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
    1959             : {
    1960             :   subint_config_t *subint;
    1961             :   u32 placeholder_flags;
    1962             :   u32 placeholder_unsup;
    1963             :   int is_port;
    1964        3553 :   vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
    1965             : 
    1966        3553 :   is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
    1967             : 
    1968             :   // Find the config for this subinterface
    1969             :   subint =
    1970        3553 :     ethernet_sw_interface_get_config (vnm, sw_if_index, &placeholder_flags,
    1971             :                                       &placeholder_unsup);
    1972             : 
    1973        3553 :   if (subint == 0)
    1974             :     {
    1975             :       // unimplemented or not ethernet
    1976         143 :       goto done;
    1977             :     }
    1978             : 
    1979             :   // Double check that the config we found is for our interface (or the interface is down)
    1980        3410 :   ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
    1981             : 
    1982        3410 :   if (l2)
    1983             :     {
    1984        1257 :       subint->flags |= SUBINT_CONFIG_L2;
    1985        1257 :       if (is_port)
    1986        1203 :         subint->flags |=
    1987             :           SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
    1988             :           | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
    1989             :     }
    1990             :   else
    1991             :     {
    1992        2153 :       subint->flags &= ~SUBINT_CONFIG_L2;
    1993        2153 :       if (is_port)
    1994        2117 :         subint->flags &=
    1995             :           ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
    1996             :             | SUBINT_CONFIG_MATCH_3_TAG);
    1997             :     }
    1998             : 
    1999          36 : done:
    2000        3553 :   return;
    2001             : }
    2002             : 
    2003             : /*
    2004             :  * Set the L2/L3 mode for the subinterface regardless of port
    2005             :  */
    2006             : void
    2007           0 : ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
    2008             :                                           u32 sw_if_index, u32 l2)
    2009             : {
    2010             :   subint_config_t *subint;
    2011             :   u32 placeholder_flags;
    2012             :   u32 placeholder_unsup;
    2013             : 
    2014             :   /* Find the config for this subinterface */
    2015             :   subint =
    2016           0 :     ethernet_sw_interface_get_config (vnm, sw_if_index, &placeholder_flags,
    2017             :                                       &placeholder_unsup);
    2018             : 
    2019           0 :   if (subint == 0)
    2020             :     {
    2021             :       /* unimplemented or not ethernet */
    2022           0 :       goto done;
    2023             :     }
    2024             : 
    2025             :   /*
    2026             :    * Double check that the config we found is for our interface (or the
    2027             :    * interface is down)
    2028             :    */
    2029           0 :   ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
    2030             : 
    2031           0 :   if (l2)
    2032             :     {
    2033           0 :       subint->flags |= SUBINT_CONFIG_L2;
    2034             :     }
    2035             :   else
    2036             :     {
    2037           0 :       subint->flags &= ~SUBINT_CONFIG_L2;
    2038             :     }
    2039             : 
    2040           0 : done:
    2041           0 :   return;
    2042             : }
    2043             : #endif
    2044             : 
    2045             : static clib_error_t *
    2046       11798 : ethernet_sw_interface_add_del (vnet_main_t * vnm,
    2047             :                                u32 sw_if_index, u32 is_create)
    2048             : {
    2049       11798 :   clib_error_t *error = 0;
    2050             :   subint_config_t *subint;
    2051             :   u32 match_flags;
    2052       11798 :   u32 unsupported = 0;
    2053             : 
    2054             :   // Find the config for this subinterface
    2055             :   subint =
    2056       11798 :     ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags,
    2057             :                                       &unsupported);
    2058             : 
    2059       11798 :   if (subint == 0)
    2060             :     {
    2061             :       // not implemented yet or not ethernet
    2062        1737 :       if (unsupported)
    2063             :         {
    2064             :           // this is the NYI case
    2065           0 :           error = clib_error_return (0, "not implemented yet");
    2066             :         }
    2067        1737 :       goto done;
    2068             :     }
    2069             : 
    2070       10061 :   if (!is_create)
    2071             :     {
    2072        3713 :       subint->flags = 0;
    2073        3713 :       return error;
    2074             :     }
    2075             : 
    2076             :   // Initialize the subint
    2077        6348 :   if (subint->flags & SUBINT_CONFIG_VALID)
    2078             :     {
    2079             :       // Error vlan already in use
    2080           0 :       error = clib_error_return (0, "vlan is already in use");
    2081             :     }
    2082             :   else
    2083             :     {
    2084             :       // Note that config is L3 by default
    2085        6348 :       subint->flags = SUBINT_CONFIG_VALID | match_flags;
    2086        6348 :       subint->sw_if_index = ~0;      // because interfaces are initially down
    2087             :     }
    2088             : 
    2089        8085 : done:
    2090        8085 :   return error;
    2091             : }
    2092             : 
    2093        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
    2094             : 
    2095             : static char *ethernet_error_strings[] = {
    2096             : #define ethernet_error(n,c,s) s,
    2097             : #include "error.def"
    2098             : #undef ethernet_error
    2099             : };
    2100             : 
    2101             : /* *INDENT-OFF* */
    2102      183788 : VLIB_REGISTER_NODE (ethernet_input_node) = {
    2103             :   .name = "ethernet-input",
    2104             :   /* Takes a vector of packets. */
    2105             :   .vector_size = sizeof (u32),
    2106             :   .scalar_size = sizeof (ethernet_input_frame_t),
    2107             :   .n_errors = ETHERNET_N_ERROR,
    2108             :   .error_strings = ethernet_error_strings,
    2109             :   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
    2110             :   .next_nodes = {
    2111             : #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
    2112             :     foreach_ethernet_input_next
    2113             : #undef _
    2114             :   },
    2115             :   .format_buffer = format_ethernet_header_with_length,
    2116             :   .format_trace = format_ethernet_input_trace,
    2117             :   .unformat_buffer = unformat_ethernet_header,
    2118             : };
    2119             : 
    2120      183788 : VLIB_REGISTER_NODE (ethernet_input_type_node) = {
    2121             :   .name = "ethernet-input-type",
    2122             :   /* Takes a vector of packets. */
    2123             :   .vector_size = sizeof (u32),
    2124             :   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
    2125             :   .next_nodes = {
    2126             : #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
    2127             :     foreach_ethernet_input_next
    2128             : #undef _
    2129             :   },
    2130             : };
    2131             : 
    2132      183788 : VLIB_REGISTER_NODE (ethernet_input_not_l2_node) = {
    2133             :   .name = "ethernet-input-not-l2",
    2134             :   /* Takes a vector of packets. */
    2135             :   .vector_size = sizeof (u32),
    2136             :   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
    2137             :   .next_nodes = {
    2138             : #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
    2139             :     foreach_ethernet_input_next
    2140             : #undef _
    2141             :   },
    2142             : };
    2143             : /* *INDENT-ON* */
    2144             : 
    2145             : #ifndef CLIB_MARCH_VARIANT
    2146             : void
    2147           0 : ethernet_set_rx_redirect (vnet_main_t * vnm,
    2148             :                           vnet_hw_interface_t * hi, u32 enable)
    2149             : {
    2150             :   // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
    2151             :   // don't go directly to ip4-input)
    2152           0 :   vnet_hw_interface_rx_redirect_to_node
    2153             :     (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
    2154           0 : }
    2155             : 
    2156             : 
    2157             : /*
    2158             :  * Initialization and registration for the next_by_ethernet structure
    2159             :  */
    2160             : 
    2161             : clib_error_t *
    2162        1150 : next_by_ethertype_init (next_by_ethertype_t * l3_next)
    2163             : {
    2164        1150 :   l3_next->input_next_by_type = sparse_vec_new
    2165             :     ( /* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
    2166             :      /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
    2167             : 
    2168        1150 :   vec_validate (l3_next->sparse_index_by_input_next_index,
    2169             :                 ETHERNET_INPUT_NEXT_DROP);
    2170        1150 :   vec_validate (l3_next->sparse_index_by_input_next_index,
    2171             :                 ETHERNET_INPUT_NEXT_PUNT);
    2172        1150 :   l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP] =
    2173             :     SPARSE_VEC_INVALID_INDEX;
    2174        1150 :   l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] =
    2175             :     SPARSE_VEC_INVALID_INDEX;
    2176             : 
    2177             :   /*
    2178             :    * Make sure we don't wipe out an ethernet registration by mistake
    2179             :    * Can happen if init function ordering constraints are missing.
    2180             :    */
    2181             :   if (CLIB_DEBUG > 0)
    2182             :     {
    2183        1150 :       ethernet_main_t *em = &ethernet_main;
    2184        1150 :       ASSERT (em->next_by_ethertype_register_called == 0);
    2185             :     }
    2186             : 
    2187        1150 :   return 0;
    2188             : }
    2189             : 
    2190             : // Add an ethertype -> next index mapping to the structure
    2191             : clib_error_t *
    2192       13812 : next_by_ethertype_register (next_by_ethertype_t * l3_next,
    2193             :                             u32 ethertype, u32 next_index)
    2194             : {
    2195             :   u32 i;
    2196             :   u16 *n;
    2197       13812 :   ethernet_main_t *em = &ethernet_main;
    2198             : 
    2199             :   if (CLIB_DEBUG > 0)
    2200             :     {
    2201       13812 :       ethernet_main_t *em = &ethernet_main;
    2202       13812 :       em->next_by_ethertype_register_called = 1;
    2203             :     }
    2204             : 
    2205             :   /* Setup ethernet type -> next index sparse vector mapping. */
    2206       13812 :   n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
    2207       13812 :   n[0] = next_index;
    2208             : 
    2209             :   /* Rebuild next index -> sparse index inverse mapping when sparse vector
    2210             :      is updated. */
    2211       13812 :   vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
    2212       76020 :   for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
    2213       62208 :     l3_next->
    2214       62208 :       sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
    2215             : 
    2216             :   // do not allow the cached next index's to be updated if L3
    2217             :   // redirect is enabled, as it will have overwritten them
    2218       13812 :   if (!em->redirect_l3)
    2219             :     {
    2220             :       // Cache common ethertypes directly
    2221       13812 :       if (ethertype == ETHERNET_TYPE_IP4)
    2222             :         {
    2223        1725 :           l3_next->input_next_ip4 = next_index;
    2224             :         }
    2225       12087 :       else if (ethertype == ETHERNET_TYPE_IP6)
    2226             :         {
    2227        1725 :           l3_next->input_next_ip6 = next_index;
    2228             :         }
    2229       10362 :       else if (ethertype == ETHERNET_TYPE_MPLS)
    2230             :         {
    2231        1725 :           l3_next->input_next_mpls = next_index;
    2232             :         }
    2233             :     }
    2234       13812 :   return 0;
    2235             : }
    2236             : 
    2237             : void
    2238        8680 : ethernet_setup_node (vlib_main_t *vm, u32 node_index)
    2239             : {
    2240        8680 :   vlib_node_t *n = vlib_get_node (vm, node_index);
    2241        8680 :   pg_node_t *pn = pg_get_node (node_index);
    2242             : 
    2243        8680 :   n->format_buffer = format_ethernet_header_with_length;
    2244        8680 :   n->unformat_buffer = unformat_ethernet_header;
    2245        8680 :   pn->unformat_edit = unformat_pg_ethernet_header;
    2246        8680 : }
    2247             : 
    2248             : void
    2249         575 : ethernet_input_init (vlib_main_t * vm, ethernet_main_t * em)
    2250             : {
    2251             :   __attribute__ ((unused)) vlan_table_t *invalid_vlan_table;
    2252             :   __attribute__ ((unused)) qinq_table_t *invalid_qinq_table;
    2253             : 
    2254         575 :   ethernet_setup_node (vm, ethernet_input_node.index);
    2255         575 :   ethernet_setup_node (vm, ethernet_input_type_node.index);
    2256         575 :   ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
    2257             : 
    2258         575 :   next_by_ethertype_init (&em->l3_next);
    2259             : 
    2260             :   // Initialize pools and vector for vlan parsing
    2261         575 :   vec_validate (em->main_intfs, 10); // 10 main interfaces
    2262         575 :   pool_alloc (em->vlan_pool, 10);
    2263         575 :   pool_alloc (em->qinq_pool, 1);
    2264             : 
    2265             :   // The first vlan pool will always be reserved for an invalid table
    2266         575 :   pool_get (em->vlan_pool, invalid_vlan_table);      // first id = 0
    2267             :   // The first qinq pool will always be reserved for an invalid table
    2268         575 :   pool_get (em->qinq_pool, invalid_qinq_table);      // first id = 0
    2269         575 : }
    2270             : 
    2271             : void
    2272        4604 : ethernet_register_input_type (vlib_main_t * vm,
    2273             :                               ethernet_type_t type, u32 node_index)
    2274             : {
    2275        4604 :   ethernet_main_t *em = &ethernet_main;
    2276             :   ethernet_type_info_t *ti;
    2277             :   u32 i;
    2278             : 
    2279             :   {
    2280        4604 :     clib_error_t *error = vlib_call_init_function (vm, ethernet_init);
    2281        4604 :     if (error)
    2282           0 :       clib_error_report (error);
    2283             :   }
    2284             : 
    2285        4604 :   ti = ethernet_get_type_info (em, type);
    2286        4604 :   if (ti == 0)
    2287             :     {
    2288           0 :       clib_warning ("type_info NULL for type %d", type);
    2289           0 :       return;
    2290             :     }
    2291        4604 :   ti->node_index = node_index;
    2292        9208 :   ti->next_index = vlib_node_add_next (vm,
    2293        4604 :                                        ethernet_input_node.index, node_index);
    2294        4604 :   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
    2295        4604 :   ASSERT (i == ti->next_index);
    2296             : 
    2297        4604 :   i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
    2298        4604 :   ASSERT (i == ti->next_index);
    2299             : 
    2300             :   // Add the L3 node for this ethertype to the next nodes structure
    2301        4604 :   next_by_ethertype_register (&em->l3_next, type, ti->next_index);
    2302             : 
    2303             :   // Call the registration functions for other nodes that want a mapping
    2304        4604 :   l2bvi_register_input_type (vm, type, node_index);
    2305             : }
    2306             : 
    2307             : void
    2308         575 : ethernet_register_l2_input (vlib_main_t * vm, u32 node_index)
    2309             : {
    2310         575 :   ethernet_main_t *em = &ethernet_main;
    2311             :   u32 i;
    2312             : 
    2313         575 :   em->l2_next =
    2314         575 :     vlib_node_add_next (vm, ethernet_input_node.index, node_index);
    2315             : 
    2316             :   /*
    2317             :    * Even if we never use these arcs, we have to align the next indices...
    2318             :    */
    2319         575 :   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
    2320             : 
    2321         575 :   ASSERT (i == em->l2_next);
    2322             : 
    2323         575 :   i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
    2324         575 :   ASSERT (i == em->l2_next);
    2325         575 : }
    2326             : 
    2327             : // Register a next node for L3 redirect, and enable L3 redirect
    2328             : void
    2329           0 : ethernet_register_l3_redirect (vlib_main_t * vm, u32 node_index)
    2330             : {
    2331           0 :   ethernet_main_t *em = &ethernet_main;
    2332             :   u32 i;
    2333             : 
    2334           0 :   em->redirect_l3 = 1;
    2335           0 :   em->redirect_l3_next = vlib_node_add_next (vm,
    2336           0 :                                              ethernet_input_node.index,
    2337             :                                              node_index);
    2338             :   /*
    2339             :    * Change the cached next nodes to the redirect node
    2340             :    */
    2341           0 :   em->l3_next.input_next_ip4 = em->redirect_l3_next;
    2342           0 :   em->l3_next.input_next_ip6 = em->redirect_l3_next;
    2343           0 :   em->l3_next.input_next_mpls = em->redirect_l3_next;
    2344             : 
    2345             :   /*
    2346             :    * Even if we never use these arcs, we have to align the next indices...
    2347             :    */
    2348           0 :   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
    2349             : 
    2350           0 :   ASSERT (i == em->redirect_l3_next);
    2351             : 
    2352           0 :   i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
    2353             : 
    2354           0 :   ASSERT (i == em->redirect_l3_next);
    2355           0 : }
    2356             : #endif
    2357             : 
    2358             : /*
    2359             :  * fd.io coding-style-patch-verification: ON
    2360             :  *
    2361             :  * Local Variables:
    2362             :  * eval: (c-set-style "gnu")
    2363             :  * End:
    2364             :  */

Generated by: LCOV version 1.14