LCOV - code coverage report
Current view: top level - plugins/vxlan - decap.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 189 606 31.2 %
Date: 2023-10-26 01:39:38 Functions: 27 36 75.0 %

          Line data    Source code
       1             : /*
       2             :  * decap.c: vxlan tunnel decap packet processing
       3             :  *
       4             :  * Copyright (c) 2013 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vxlan/vxlan.h>
      20             : #include <vnet/udp/udp_local.h>
      21             : 
      22             : #ifndef CLIB_MARCH_VARIANT
      23             : __clib_export vlib_node_registration_t vxlan4_input_node;
      24             : __clib_export vlib_node_registration_t vxlan6_input_node;
      25             : #endif
      26             : 
      27             : typedef struct
      28             : {
      29             :   u32 next_index;
      30             :   u32 tunnel_index;
      31             :   u32 error;
      32             :   u32 vni;
      33             : } vxlan_rx_trace_t;
      34             : 
      35             : static u8 *
      36          84 : format_vxlan_rx_trace (u8 * s, va_list * args)
      37             : {
      38          84 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      39          84 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      40          84 :   vxlan_rx_trace_t *t = va_arg (*args, vxlan_rx_trace_t *);
      41             : 
      42          84 :   if (t->tunnel_index == ~0)
      43          40 :     return format (s, "VXLAN decap error - tunnel for vni %d does not exist",
      44             :                    t->vni);
      45          44 :   return format (s, "VXLAN decap from vxlan_tunnel%d vni %d next %d error %d",
      46             :                  t->tunnel_index, t->vni, t->next_index, t->error);
      47             : }
      48             : 
      49             : typedef vxlan4_tunnel_key_t last_tunnel_cache4;
      50             : 
      51             : static const vxlan_decap_info_t decap_not_found = {
      52             :   .sw_if_index = ~0,
      53             :   .next_index = VXLAN_INPUT_NEXT_DROP,
      54             :   .error = VXLAN_ERROR_NO_SUCH_TUNNEL
      55             : };
      56             : 
      57             : static const vxlan_decap_info_t decap_bad_flags = {
      58             :   .sw_if_index = ~0,
      59             :   .next_index = VXLAN_INPUT_NEXT_DROP,
      60             :   .error = VXLAN_ERROR_BAD_FLAGS
      61             : };
      62             : 
      63             : always_inline vxlan_decap_info_t
      64          42 : vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache,
      65             :                     u32 fib_index, ip4_header_t * ip4_0,
      66             :                     vxlan_header_t * vxlan0, u32 * stats_sw_if_index)
      67             : {
      68          42 :   if (PREDICT_FALSE (vxlan0->flags != VXLAN_FLAGS_I))
      69           0 :     return decap_bad_flags;
      70             : 
      71             :   /* Make sure VXLAN tunnel exist according to packet S/D IP, UDP port, VRF,
      72             :    * and VNI */
      73          42 :   u32 dst = ip4_0->dst_address.as_u32;
      74          42 :   u32 src = ip4_0->src_address.as_u32;
      75          42 :   udp_header_t *udp = ip4_next_header (ip4_0);
      76          42 :   vxlan4_tunnel_key_t key4 = {
      77          42 :     .key[0] = ((u64) dst << 32) | src,
      78          42 :     .key[1] = ((u64) udp->dst_port << 48) | ((u64) fib_index << 32) |
      79          42 :               vxlan0->vni_reserved,
      80             :   };
      81             : 
      82          42 :   if (PREDICT_TRUE
      83             :       (key4.key[0] == cache->key[0] && key4.key[1] == cache->key[1]))
      84             :     {
      85             :       /* cache hit */
      86           0 :       vxlan_decap_info_t di = {.as_u64 = cache->value };
      87           0 :       *stats_sw_if_index = di.sw_if_index;
      88           0 :       return di;
      89             :     }
      90             : 
      91          42 :   int rv = clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
      92          42 :   if (PREDICT_TRUE (rv == 0))
      93             :     {
      94           2 :       *cache = key4;
      95           2 :       vxlan_decap_info_t di = {.as_u64 = key4.value };
      96           2 :       *stats_sw_if_index = di.sw_if_index;
      97           2 :       return di;
      98             :     }
      99             : 
     100             :   /* try multicast */
     101          40 :   if (PREDICT_TRUE (!ip4_address_is_multicast (&ip4_0->dst_address)))
     102           0 :     return decap_not_found;
     103             : 
     104             :   /* search for mcast decap info by mcast address */
     105          40 :   key4.key[0] = dst;
     106          40 :   rv = clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
     107          40 :   if (rv != 0)
     108           0 :     return decap_not_found;
     109             : 
     110             :   /* search for unicast tunnel using the mcast tunnel local(src) ip */
     111          40 :   vxlan_decap_info_t mdi = {.as_u64 = key4.value };
     112          40 :   key4.key[0] = ((u64) mdi.local_ip.as_u32 << 32) | src;
     113          40 :   rv = clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
     114          40 :   if (PREDICT_FALSE (rv != 0))
     115          20 :     return decap_not_found;
     116             : 
     117             :   /* mcast traffic does not update the cache */
     118          20 :   *stats_sw_if_index = mdi.sw_if_index;
     119          20 :   vxlan_decap_info_t di = {.as_u64 = key4.value };
     120          20 :   return di;
     121             : }
     122             : 
     123             : typedef vxlan6_tunnel_key_t last_tunnel_cache6;
     124             : 
     125             : always_inline vxlan_decap_info_t
     126          42 : vxlan6_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache6 * cache,
     127             :                     u32 fib_index, ip6_header_t * ip6_0,
     128             :                     vxlan_header_t * vxlan0, u32 * stats_sw_if_index)
     129             : {
     130          42 :   if (PREDICT_FALSE (vxlan0->flags != VXLAN_FLAGS_I))
     131           0 :     return decap_bad_flags;
     132             : 
     133             :   /* Make sure VXLAN tunnel exist according to packet SIP, UDP port, VRF, and
     134             :    * VNI */
     135          42 :   udp_header_t *udp = ip6_next_header (ip6_0);
     136          42 :   vxlan6_tunnel_key_t key6 = {
     137          42 :     .key[0] = ip6_0->src_address.as_u64[0],
     138          42 :     .key[1] = ip6_0->src_address.as_u64[1],
     139          42 :     .key[2] = ((u64) udp->dst_port << 48) | ((u64) fib_index << 32) |
     140          42 :               vxlan0->vni_reserved,
     141             :   };
     142             : 
     143          42 :   if (PREDICT_FALSE
     144             :       (clib_bihash_key_compare_24_8 (key6.key, cache->key) == 0))
     145             :     {
     146             :       int rv =
     147          42 :         clib_bihash_search_inline_24_8 (&vxm->vxlan6_tunnel_by_key, &key6);
     148          42 :       if (PREDICT_FALSE (rv != 0))
     149          20 :         return decap_not_found;
     150             : 
     151          22 :       *cache = key6;
     152             :     }
     153          22 :   vxlan_tunnel_t *t0 = pool_elt_at_index (vxm->tunnels, cache->value);
     154             : 
     155             :   /* Validate VXLAN tunnel SIP against packet DIP */
     156          22 :   if (PREDICT_TRUE (ip6_address_is_equal (&ip6_0->dst_address, &t0->src.ip6)))
     157           2 :     *stats_sw_if_index = t0->sw_if_index;
     158             :   else
     159             :     {
     160             :       /* try multicast */
     161          20 :       if (PREDICT_TRUE (!ip6_address_is_multicast (&ip6_0->dst_address)))
     162           0 :         return decap_not_found;
     163             : 
     164             :       /* Make sure mcast VXLAN tunnel exist by packet DIP and VNI */
     165          20 :       key6.key[0] = ip6_0->dst_address.as_u64[0];
     166          20 :       key6.key[1] = ip6_0->dst_address.as_u64[1];
     167             :       int rv =
     168          20 :         clib_bihash_search_inline_24_8 (&vxm->vxlan6_tunnel_by_key, &key6);
     169          20 :       if (PREDICT_FALSE (rv != 0))
     170           0 :         return decap_not_found;
     171             : 
     172          20 :       vxlan_tunnel_t *mcast_t0 = pool_elt_at_index (vxm->tunnels, key6.value);
     173          20 :       *stats_sw_if_index = mcast_t0->sw_if_index;
     174             :     }
     175             : 
     176          22 :   vxlan_decap_info_t di = {
     177          22 :     .sw_if_index = t0->sw_if_index,
     178          22 :     .next_index = t0->decap_next_index,
     179             :   };
     180          22 :   return di;
     181             : }
     182             : 
     183             : always_inline uword
     184           8 : vxlan_input (vlib_main_t * vm,
     185             :              vlib_node_runtime_t * node,
     186             :              vlib_frame_t * from_frame, u32 is_ip4)
     187             : {
     188           8 :   vxlan_main_t *vxm = &vxlan_main;
     189           8 :   vnet_main_t *vnm = vxm->vnet_main;
     190           8 :   vnet_interface_main_t *im = &vnm->interface_main;
     191           8 :   vlib_combined_counter_main_t *rx_counter =
     192             :     im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
     193             :   last_tunnel_cache4 last4;
     194             :   last_tunnel_cache6 last6;
     195           8 :   u32 pkts_dropped = 0;
     196           8 :   u32 thread_index = vlib_get_thread_index ();
     197             : 
     198           8 :   if (is_ip4)
     199           4 :     clib_memset (&last4, 0xff, sizeof last4);
     200             :   else
     201           4 :     clib_memset (&last6, 0xff, sizeof last6);
     202             : 
     203           8 :   u32 *from = vlib_frame_vector_args (from_frame);
     204           8 :   u32 n_left_from = from_frame->n_vectors;
     205             : 
     206           8 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     207           8 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     208             : 
     209           8 :   u32 stats_if0 = ~0, stats_if1 = ~0;
     210           8 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
     211          44 :   while (n_left_from >= 4)
     212             :     {
     213             :       /* Prefetch next iteration. */
     214          36 :       vlib_prefetch_buffer_header (b[2], LOAD);
     215          36 :       vlib_prefetch_buffer_header (b[3], LOAD);
     216             : 
     217             :       /* udp leaves current_data pointing at the vxlan header */
     218          36 :       void *cur0 = vlib_buffer_get_current (b[0]);
     219          36 :       void *cur1 = vlib_buffer_get_current (b[1]);
     220          36 :       vxlan_header_t *vxlan0 = cur0;
     221          36 :       vxlan_header_t *vxlan1 = cur1;
     222             : 
     223             : 
     224             :       ip4_header_t *ip4_0, *ip4_1;
     225             :       ip6_header_t *ip6_0, *ip6_1;
     226          36 :       if (is_ip4)
     227             :         {
     228          18 :           ip4_0 = cur0 - sizeof (udp_header_t) - sizeof (ip4_header_t);
     229          18 :           ip4_1 = cur1 - sizeof (udp_header_t) - sizeof (ip4_header_t);
     230             :         }
     231             :       else
     232             :         {
     233          18 :           ip6_0 = cur0 - sizeof (udp_header_t) - sizeof (ip6_header_t);
     234          18 :           ip6_1 = cur1 - sizeof (udp_header_t) - sizeof (ip6_header_t);
     235             :         }
     236             : 
     237             :       /* pop vxlan */
     238          36 :       vlib_buffer_advance (b[0], sizeof *vxlan0);
     239          36 :       vlib_buffer_advance (b[1], sizeof *vxlan1);
     240             : 
     241          36 :       u32 fi0 = vlib_buffer_get_ip_fib_index (b[0], is_ip4);
     242          36 :       u32 fi1 = vlib_buffer_get_ip_fib_index (b[1], is_ip4);
     243             : 
     244          36 :       vxlan_decap_info_t di0 = is_ip4 ?
     245          18 :         vxlan4_find_tunnel (vxm, &last4, fi0, ip4_0, vxlan0, &stats_if0) :
     246          18 :         vxlan6_find_tunnel (vxm, &last6, fi0, ip6_0, vxlan0, &stats_if0);
     247          36 :       vxlan_decap_info_t di1 = is_ip4 ?
     248          18 :         vxlan4_find_tunnel (vxm, &last4, fi1, ip4_1, vxlan1, &stats_if1) :
     249          18 :         vxlan6_find_tunnel (vxm, &last6, fi1, ip6_1, vxlan1, &stats_if1);
     250             : 
     251             :       /* Prefetch next iteration. */
     252          36 :       clib_prefetch_load (b[2]->data);
     253          36 :       clib_prefetch_load (b[3]->data);
     254             : 
     255          36 :       u32 len0 = vlib_buffer_length_in_chain (vm, b[0]);
     256          36 :       u32 len1 = vlib_buffer_length_in_chain (vm, b[1]);
     257             : 
     258          36 :       next[0] = di0.next_index;
     259          36 :       next[1] = di1.next_index;
     260             : 
     261          36 :       u8 any_error = di0.error | di1.error;
     262          36 :       if (PREDICT_TRUE (any_error == 0))
     263             :         {
     264             :           /* Required to make the l2 tag push / pop code work on l2 subifs */
     265          20 :           vnet_update_l2_len (b[0]);
     266          20 :           vnet_update_l2_len (b[1]);
     267             :           /* Set packet input sw_if_index to unicast VXLAN tunnel for learning */
     268          20 :           vnet_buffer (b[0])->sw_if_index[VLIB_RX] = di0.sw_if_index;
     269          20 :           vnet_buffer (b[1])->sw_if_index[VLIB_RX] = di1.sw_if_index;
     270          20 :           vlib_increment_combined_counter (rx_counter, thread_index,
     271             :                                            stats_if0, 1, len0);
     272          20 :           vlib_increment_combined_counter (rx_counter, thread_index,
     273             :                                            stats_if1, 1, len1);
     274             :         }
     275             :       else
     276             :         {
     277          16 :           if (di0.error == 0)
     278             :             {
     279           0 :               vnet_update_l2_len (b[0]);
     280           0 :               vnet_buffer (b[0])->sw_if_index[VLIB_RX] = di0.sw_if_index;
     281           0 :               vlib_increment_combined_counter (rx_counter, thread_index,
     282             :                                                stats_if0, 1, len0);
     283             :             }
     284             :           else
     285             :             {
     286          16 :               b[0]->error = node->errors[di0.error];
     287          16 :               pkts_dropped++;
     288             :             }
     289             : 
     290          16 :           if (di1.error == 0)
     291             :             {
     292           0 :               vnet_update_l2_len (b[1]);
     293           0 :               vnet_buffer (b[1])->sw_if_index[VLIB_RX] = di1.sw_if_index;
     294           0 :               vlib_increment_combined_counter (rx_counter, thread_index,
     295             :                                                stats_if1, 1, len1);
     296             :             }
     297             :           else
     298             :             {
     299          16 :               b[1]->error = node->errors[di1.error];
     300          16 :               pkts_dropped++;
     301             :             }
     302             :         }
     303             : 
     304          36 :       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
     305             :         {
     306             :           vxlan_rx_trace_t *tr =
     307          36 :             vlib_add_trace (vm, node, b[0], sizeof (*tr));
     308          36 :           tr->next_index = next[0];
     309          36 :           tr->error = di0.error;
     310          72 :           tr->tunnel_index = di0.sw_if_index == ~0 ?
     311          36 :             ~0 : vxm->tunnel_index_by_sw_if_index[di0.sw_if_index];
     312          36 :           tr->vni = vnet_get_vni (vxlan0);
     313             :         }
     314          36 :       if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
     315             :         {
     316             :           vxlan_rx_trace_t *tr =
     317          36 :             vlib_add_trace (vm, node, b[1], sizeof (*tr));
     318          36 :           tr->next_index = next[1];
     319          36 :           tr->error = di1.error;
     320          72 :           tr->tunnel_index = di1.sw_if_index == ~0 ?
     321          36 :             ~0 : vxm->tunnel_index_by_sw_if_index[di1.sw_if_index];
     322          36 :           tr->vni = vnet_get_vni (vxlan1);
     323             :         }
     324          36 :       b += 2;
     325          36 :       next += 2;
     326          36 :       n_left_from -= 2;
     327             :     }
     328             : 
     329          20 :   while (n_left_from > 0)
     330             :     {
     331             :       /* udp leaves current_data pointing at the vxlan header */
     332          12 :       void *cur0 = vlib_buffer_get_current (b[0]);
     333          12 :       vxlan_header_t *vxlan0 = cur0;
     334             :       ip4_header_t *ip4_0;
     335             :       ip6_header_t *ip6_0;
     336          12 :       if (is_ip4)
     337           6 :         ip4_0 = cur0 - sizeof (udp_header_t) - sizeof (ip4_header_t);
     338             :       else
     339           6 :         ip6_0 = cur0 - sizeof (udp_header_t) - sizeof (ip6_header_t);
     340             : 
     341             :       /* pop (ip, udp, vxlan) */
     342          12 :       vlib_buffer_advance (b[0], sizeof (*vxlan0));
     343             : 
     344          12 :       u32 fi0 = vlib_buffer_get_ip_fib_index (b[0], is_ip4);
     345             : 
     346          12 :       vxlan_decap_info_t di0 = is_ip4 ?
     347           6 :         vxlan4_find_tunnel (vxm, &last4, fi0, ip4_0, vxlan0, &stats_if0) :
     348           6 :         vxlan6_find_tunnel (vxm, &last6, fi0, ip6_0, vxlan0, &stats_if0);
     349             : 
     350          12 :       uword len0 = vlib_buffer_length_in_chain (vm, b[0]);
     351             : 
     352          12 :       next[0] = di0.next_index;
     353             : 
     354             :       /* Validate VXLAN tunnel encap-fib index against packet */
     355          12 :       if (di0.error == 0)
     356             :         {
     357             :           /* Required to make the l2 tag push / pop code work on l2 subifs */
     358           4 :           vnet_update_l2_len (b[0]);
     359             : 
     360             :           /* Set packet input sw_if_index to unicast VXLAN tunnel for learning */
     361           4 :           vnet_buffer (b[0])->sw_if_index[VLIB_RX] = di0.sw_if_index;
     362             : 
     363           4 :           vlib_increment_combined_counter (rx_counter, thread_index,
     364             :                                            stats_if0, 1, len0);
     365             :         }
     366             :       else
     367             :         {
     368           8 :           b[0]->error = node->errors[di0.error];
     369           8 :           pkts_dropped++;
     370             :         }
     371             : 
     372          12 :       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
     373             :         {
     374             :           vxlan_rx_trace_t *tr
     375          12 :             = vlib_add_trace (vm, node, b[0], sizeof (*tr));
     376          12 :           tr->next_index = next[0];
     377          12 :           tr->error = di0.error;
     378          24 :           tr->tunnel_index = di0.sw_if_index == ~0 ?
     379          12 :             ~0 : vxm->tunnel_index_by_sw_if_index[di0.sw_if_index];
     380          12 :           tr->vni = vnet_get_vni (vxlan0);
     381             :         }
     382          12 :       b += 1;
     383          12 :       next += 1;
     384          12 :       n_left_from -= 1;
     385             :     }
     386           8 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors);
     387             :   /* Do we still need this now that tunnel tx stats is kept? */
     388           8 :   u32 node_idx = is_ip4 ? vxlan4_input_node.index : vxlan6_input_node.index;
     389           8 :   vlib_node_increment_counter (vm, node_idx, VXLAN_ERROR_DECAPSULATED,
     390           8 :                                from_frame->n_vectors - pkts_dropped);
     391             : 
     392           8 :   return from_frame->n_vectors;
     393             : }
     394             : 
     395         579 : VLIB_NODE_FN (vxlan4_input_node) (vlib_main_t * vm,
     396             :                                   vlib_node_runtime_t * node,
     397             :                                   vlib_frame_t * from_frame)
     398             : {
     399           4 :   return vxlan_input (vm, node, from_frame, /* is_ip4 */ 1);
     400             : }
     401             : 
     402         579 : VLIB_NODE_FN (vxlan6_input_node) (vlib_main_t * vm,
     403             :                                   vlib_node_runtime_t * node,
     404             :                                   vlib_frame_t * from_frame)
     405             : {
     406           4 :   return vxlan_input (vm, node, from_frame, /* is_ip4 */ 0);
     407             : }
     408             : 
     409             : static char *vxlan_error_strings[] = {
     410             : #define vxlan_error(n,s) s,
     411             : #include <vxlan/vxlan_error.def>
     412             : #undef vxlan_error
     413             : };
     414             : 
     415             : /* *INDENT-OFF* */
     416        9215 : VLIB_REGISTER_NODE (vxlan4_input_node) =
     417             : {
     418             :   .name = "vxlan4-input",
     419             :   .vector_size = sizeof (u32),
     420             :   .n_errors = VXLAN_N_ERROR,
     421             :   .error_strings = vxlan_error_strings,
     422             :   .n_next_nodes = VXLAN_INPUT_N_NEXT,
     423             :   .format_trace = format_vxlan_rx_trace,
     424             :   .next_nodes = {
     425             : #define _(s,n) [VXLAN_INPUT_NEXT_##s] = n,
     426             :     foreach_vxlan_input_next
     427             : #undef _
     428             :   },
     429             : };
     430             : 
     431        9215 : VLIB_REGISTER_NODE (vxlan6_input_node) =
     432             : {
     433             :   .name = "vxlan6-input",
     434             :   .vector_size = sizeof (u32),
     435             :   .n_errors = VXLAN_N_ERROR,
     436             :   .error_strings = vxlan_error_strings,
     437             :   .n_next_nodes = VXLAN_INPUT_N_NEXT,
     438             :   .next_nodes = {
     439             : #define _(s,n) [VXLAN_INPUT_NEXT_##s] = n,
     440             :     foreach_vxlan_input_next
     441             : #undef _
     442             :   },
     443             :   .format_trace = format_vxlan_rx_trace,
     444             : };
     445             : /* *INDENT-ON* */
     446             : 
     447             : typedef enum
     448             : {
     449             :   IP_VXLAN_BYPASS_NEXT_DROP,
     450             :   IP_VXLAN_BYPASS_NEXT_VXLAN,
     451             :   IP_VXLAN_BYPASS_N_NEXT,
     452             : } ip_vxlan_bypass_next_t;
     453             : 
     454             : always_inline uword
     455           0 : ip_vxlan_bypass_inline (vlib_main_t * vm,
     456             :                         vlib_node_runtime_t * node,
     457             :                         vlib_frame_t * frame, u32 is_ip4)
     458             : {
     459           0 :   vxlan_main_t *vxm = &vxlan_main;
     460             :   u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
     461             :   vlib_node_runtime_t *error_node =
     462           0 :     vlib_node_get_runtime (vm, ip4_input_node.index);
     463             :   vtep4_key_t last_vtep4;       /* last IPv4 address / fib index
     464             :                                    matching a local VTEP address */
     465             :   vtep6_key_t last_vtep6;       /* last IPv6 address / fib index
     466             :                                    matching a local VTEP address */
     467           0 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     468             : 
     469             :   last_tunnel_cache4 last4;
     470             :   last_tunnel_cache6 last6;
     471             : 
     472           0 :   from = vlib_frame_vector_args (frame);
     473           0 :   n_left_from = frame->n_vectors;
     474           0 :   next_index = node->cached_next_index;
     475             : 
     476           0 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     477             : 
     478           0 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     479           0 :     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
     480             : 
     481           0 :   if (is_ip4)
     482             :     {
     483           0 :       vtep4_key_init (&last_vtep4);
     484           0 :       clib_memset (&last4, 0xff, sizeof last4);
     485             :     }
     486             :   else
     487             :     {
     488           0 :       vtep6_key_init (&last_vtep6);
     489           0 :       clib_memset (&last6, 0xff, sizeof last6);
     490             :     }
     491             : 
     492           0 :   while (n_left_from > 0)
     493             :     {
     494           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     495             : 
     496           0 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     497             :         {
     498             :           vlib_buffer_t *b0, *b1;
     499             :           ip4_header_t *ip40, *ip41;
     500             :           ip6_header_t *ip60, *ip61;
     501             :           udp_header_t *udp0, *udp1;
     502             :           vxlan_header_t *vxlan0, *vxlan1;
     503             :           u32 bi0, ip_len0, udp_len0, flags0, next0;
     504             :           u32 bi1, ip_len1, udp_len1, flags1, next1;
     505             :           i32 len_diff0, len_diff1;
     506             :           u8 error0, good_udp0, proto0;
     507             :           u8 error1, good_udp1, proto1;
     508           0 :           u32 stats_if0 = ~0, stats_if1 = ~0;
     509             : 
     510             :           /* Prefetch next iteration. */
     511             :           {
     512           0 :             vlib_prefetch_buffer_header (b[2], LOAD);
     513           0 :             vlib_prefetch_buffer_header (b[3], LOAD);
     514             : 
     515           0 :             CLIB_PREFETCH (b[2]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
     516           0 :             CLIB_PREFETCH (b[3]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
     517             :           }
     518             : 
     519           0 :           bi0 = to_next[0] = from[0];
     520           0 :           bi1 = to_next[1] = from[1];
     521           0 :           from += 2;
     522           0 :           n_left_from -= 2;
     523           0 :           to_next += 2;
     524           0 :           n_left_to_next -= 2;
     525             : 
     526           0 :           b0 = b[0];
     527           0 :           b1 = b[1];
     528           0 :           b += 2;
     529           0 :           if (is_ip4)
     530             :             {
     531           0 :               ip40 = vlib_buffer_get_current (b0);
     532           0 :               ip41 = vlib_buffer_get_current (b1);
     533             :             }
     534             :           else
     535             :             {
     536           0 :               ip60 = vlib_buffer_get_current (b0);
     537           0 :               ip61 = vlib_buffer_get_current (b1);
     538             :             }
     539             : 
     540             :           /* Setup packet for next IP feature */
     541           0 :           vnet_feature_next (&next0, b0);
     542           0 :           vnet_feature_next (&next1, b1);
     543             : 
     544           0 :           if (is_ip4)
     545             :             {
     546             :               /* Treat IP frag packets as "experimental" protocol for now
     547             :                  until support of IP frag reassembly is implemented */
     548           0 :               proto0 = ip4_is_fragment (ip40) ? 0xfe : ip40->protocol;
     549           0 :               proto1 = ip4_is_fragment (ip41) ? 0xfe : ip41->protocol;
     550             :             }
     551             :           else
     552             :             {
     553           0 :               proto0 = ip60->protocol;
     554           0 :               proto1 = ip61->protocol;
     555             :             }
     556             : 
     557             :           /* Process packet 0 */
     558           0 :           if (proto0 != IP_PROTOCOL_UDP)
     559           0 :             goto exit0;         /* not UDP packet */
     560             : 
     561           0 :           if (is_ip4)
     562           0 :             udp0 = ip4_next_header (ip40);
     563             :           else
     564           0 :             udp0 = ip6_next_header (ip60);
     565             : 
     566           0 :           u32 fi0 = vlib_buffer_get_ip_fib_index (b0, is_ip4);
     567           0 :           vxlan0 = vlib_buffer_get_current (b0) + sizeof (udp_header_t) +
     568             :                    sizeof (ip4_header_t);
     569             : 
     570           0 :           vxlan_decap_info_t di0 =
     571             :             is_ip4 ?
     572           0 :               vxlan4_find_tunnel (vxm, &last4, fi0, ip40, vxlan0, &stats_if0) :
     573           0 :               vxlan6_find_tunnel (vxm, &last6, fi0, ip60, vxlan0, &stats_if0);
     574             : 
     575           0 :           if (PREDICT_FALSE (di0.sw_if_index == ~0))
     576           0 :             goto exit0; /* unknown interface */
     577             : 
     578             :           /* Validate DIP against VTEPs */
     579           0 :           if (is_ip4)
     580             :             {
     581             : #ifdef CLIB_HAVE_VEC512
     582             :               if (!vtep4_check_vector (&vxm->vtep_table, b0, ip40, &last_vtep4,
     583             :                                        &vxm->vtep4_u512))
     584             : #else
     585           0 :               if (!vtep4_check (&vxm->vtep_table, b0, ip40, &last_vtep4))
     586             : #endif
     587           0 :                 goto exit0;     /* no local VTEP for VXLAN packet */
     588             :             }
     589             :           else
     590             :             {
     591           0 :               if (!vtep6_check (&vxm->vtep_table, b0, ip60, &last_vtep6))
     592           0 :                 goto exit0;     /* no local VTEP for VXLAN packet */
     593             :             }
     594             : 
     595           0 :           flags0 = b0->flags;
     596           0 :           good_udp0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     597             : 
     598             :           /* Don't verify UDP checksum for packets with explicit zero checksum. */
     599           0 :           good_udp0 |= udp0->checksum == 0;
     600             : 
     601             :           /* Verify UDP length */
     602           0 :           if (is_ip4)
     603           0 :             ip_len0 = clib_net_to_host_u16 (ip40->length);
     604             :           else
     605           0 :             ip_len0 = clib_net_to_host_u16 (ip60->payload_length);
     606           0 :           udp_len0 = clib_net_to_host_u16 (udp0->length);
     607           0 :           len_diff0 = ip_len0 - udp_len0;
     608             : 
     609             :           /* Verify UDP checksum */
     610           0 :           if (PREDICT_FALSE (!good_udp0))
     611             :             {
     612           0 :               if (is_ip4)
     613           0 :                 flags0 = ip4_tcp_udp_validate_checksum (vm, b0);
     614             :               else
     615           0 :                 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, b0);
     616           0 :               good_udp0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     617             :             }
     618             : 
     619           0 :           if (is_ip4)
     620             :             {
     621           0 :               error0 = good_udp0 ? 0 : IP4_ERROR_UDP_CHECKSUM;
     622           0 :               error0 = (len_diff0 >= 0) ? error0 : IP4_ERROR_UDP_LENGTH;
     623             :             }
     624             :           else
     625             :             {
     626           0 :               error0 = good_udp0 ? 0 : IP6_ERROR_UDP_CHECKSUM;
     627           0 :               error0 = (len_diff0 >= 0) ? error0 : IP6_ERROR_UDP_LENGTH;
     628             :             }
     629             : 
     630           0 :           next0 = error0 ?
     631           0 :             IP_VXLAN_BYPASS_NEXT_DROP : IP_VXLAN_BYPASS_NEXT_VXLAN;
     632           0 :           b0->error = error0 ? error_node->errors[error0] : 0;
     633             : 
     634             :           /* vxlan-input node expect current at VXLAN header */
     635           0 :           if (is_ip4)
     636           0 :             vlib_buffer_advance (b0,
     637             :                                  sizeof (ip4_header_t) +
     638             :                                  sizeof (udp_header_t));
     639             :           else
     640           0 :             vlib_buffer_advance (b0,
     641             :                                  sizeof (ip6_header_t) +
     642             :                                  sizeof (udp_header_t));
     643             : 
     644           0 :         exit0:
     645             :           /* Process packet 1 */
     646           0 :           if (proto1 != IP_PROTOCOL_UDP)
     647           0 :             goto exit1;         /* not UDP packet */
     648             : 
     649           0 :           if (is_ip4)
     650           0 :             udp1 = ip4_next_header (ip41);
     651             :           else
     652           0 :             udp1 = ip6_next_header (ip61);
     653             : 
     654           0 :           u32 fi1 = vlib_buffer_get_ip_fib_index (b1, is_ip4);
     655           0 :           vxlan1 = vlib_buffer_get_current (b1) + sizeof (udp_header_t) +
     656             :                    sizeof (ip4_header_t);
     657             : 
     658           0 :           vxlan_decap_info_t di1 =
     659             :             is_ip4 ?
     660           0 :               vxlan4_find_tunnel (vxm, &last4, fi1, ip41, vxlan1, &stats_if1) :
     661           0 :               vxlan6_find_tunnel (vxm, &last6, fi1, ip61, vxlan1, &stats_if1);
     662             : 
     663           0 :           if (PREDICT_FALSE (di1.sw_if_index == ~0))
     664           0 :             goto exit1; /* unknown interface */
     665             : 
     666             :           /* Validate DIP against VTEPs */
     667           0 :           if (is_ip4)
     668             :             {
     669             : #ifdef CLIB_HAVE_VEC512
     670             :               if (!vtep4_check_vector (&vxm->vtep_table, b1, ip41, &last_vtep4,
     671             :                                        &vxm->vtep4_u512))
     672             : #else
     673           0 :               if (!vtep4_check (&vxm->vtep_table, b1, ip41, &last_vtep4))
     674             : #endif
     675           0 :                 goto exit1;     /* no local VTEP for VXLAN packet */
     676             :             }
     677             :           else
     678             :             {
     679           0 :               if (!vtep6_check (&vxm->vtep_table, b1, ip61, &last_vtep6))
     680           0 :                 goto exit1;     /* no local VTEP for VXLAN packet */
     681             :             }
     682             : 
     683           0 :           flags1 = b1->flags;
     684           0 :           good_udp1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     685             : 
     686             :           /* Don't verify UDP checksum for packets with explicit zero checksum. */
     687           0 :           good_udp1 |= udp1->checksum == 0;
     688             : 
     689             :           /* Verify UDP length */
     690           0 :           if (is_ip4)
     691           0 :             ip_len1 = clib_net_to_host_u16 (ip41->length);
     692             :           else
     693           0 :             ip_len1 = clib_net_to_host_u16 (ip61->payload_length);
     694           0 :           udp_len1 = clib_net_to_host_u16 (udp1->length);
     695           0 :           len_diff1 = ip_len1 - udp_len1;
     696             : 
     697             :           /* Verify UDP checksum */
     698           0 :           if (PREDICT_FALSE (!good_udp1))
     699             :             {
     700           0 :               if (is_ip4)
     701           0 :                 flags1 = ip4_tcp_udp_validate_checksum (vm, b1);
     702             :               else
     703           0 :                 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, b1);
     704           0 :               good_udp1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     705             :             }
     706             : 
     707           0 :           if (is_ip4)
     708             :             {
     709           0 :               error1 = good_udp1 ? 0 : IP4_ERROR_UDP_CHECKSUM;
     710           0 :               error1 = (len_diff1 >= 0) ? error1 : IP4_ERROR_UDP_LENGTH;
     711             :             }
     712             :           else
     713             :             {
     714           0 :               error1 = good_udp1 ? 0 : IP6_ERROR_UDP_CHECKSUM;
     715           0 :               error1 = (len_diff1 >= 0) ? error1 : IP6_ERROR_UDP_LENGTH;
     716             :             }
     717             : 
     718           0 :           next1 = error1 ?
     719           0 :             IP_VXLAN_BYPASS_NEXT_DROP : IP_VXLAN_BYPASS_NEXT_VXLAN;
     720           0 :           b1->error = error1 ? error_node->errors[error1] : 0;
     721             : 
     722             :           /* vxlan-input node expect current at VXLAN header */
     723           0 :           if (is_ip4)
     724           0 :             vlib_buffer_advance (b1,
     725             :                                  sizeof (ip4_header_t) +
     726             :                                  sizeof (udp_header_t));
     727             :           else
     728           0 :             vlib_buffer_advance (b1,
     729             :                                  sizeof (ip6_header_t) +
     730             :                                  sizeof (udp_header_t));
     731             : 
     732           0 :         exit1:
     733           0 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     734             :                                            to_next, n_left_to_next,
     735             :                                            bi0, bi1, next0, next1);
     736             :         }
     737             : 
     738           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     739             :         {
     740             :           vlib_buffer_t *b0;
     741             :           ip4_header_t *ip40;
     742             :           ip6_header_t *ip60;
     743             :           udp_header_t *udp0;
     744             :           vxlan_header_t *vxlan0;
     745             :           u32 bi0, ip_len0, udp_len0, flags0, next0;
     746             :           i32 len_diff0;
     747             :           u8 error0, good_udp0, proto0;
     748           0 :           u32 stats_if0 = ~0;
     749             : 
     750           0 :           bi0 = to_next[0] = from[0];
     751           0 :           from += 1;
     752           0 :           n_left_from -= 1;
     753           0 :           to_next += 1;
     754           0 :           n_left_to_next -= 1;
     755             : 
     756           0 :           b0 = b[0];
     757           0 :           b++;
     758           0 :           if (is_ip4)
     759           0 :             ip40 = vlib_buffer_get_current (b0);
     760             :           else
     761           0 :             ip60 = vlib_buffer_get_current (b0);
     762             : 
     763             :           /* Setup packet for next IP feature */
     764           0 :           vnet_feature_next (&next0, b0);
     765             : 
     766           0 :           if (is_ip4)
     767             :             /* Treat IP4 frag packets as "experimental" protocol for now
     768             :                until support of IP frag reassembly is implemented */
     769           0 :             proto0 = ip4_is_fragment (ip40) ? 0xfe : ip40->protocol;
     770             :           else
     771           0 :             proto0 = ip60->protocol;
     772             : 
     773           0 :           if (proto0 != IP_PROTOCOL_UDP)
     774           0 :             goto exit;          /* not UDP packet */
     775             : 
     776           0 :           if (is_ip4)
     777           0 :             udp0 = ip4_next_header (ip40);
     778             :           else
     779           0 :             udp0 = ip6_next_header (ip60);
     780             : 
     781           0 :           u32 fi0 = vlib_buffer_get_ip_fib_index (b0, is_ip4);
     782           0 :           vxlan0 = vlib_buffer_get_current (b0) + sizeof (udp_header_t) +
     783             :                    sizeof (ip4_header_t);
     784             : 
     785           0 :           vxlan_decap_info_t di0 =
     786             :             is_ip4 ?
     787           0 :               vxlan4_find_tunnel (vxm, &last4, fi0, ip40, vxlan0, &stats_if0) :
     788           0 :               vxlan6_find_tunnel (vxm, &last6, fi0, ip60, vxlan0, &stats_if0);
     789             : 
     790           0 :           if (PREDICT_FALSE (di0.sw_if_index == ~0))
     791           0 :             goto exit; /* unknown interface */
     792             : 
     793             :           /* Validate DIP against VTEPs */
     794           0 :           if (is_ip4)
     795             :             {
     796             : #ifdef CLIB_HAVE_VEC512
     797             :               if (!vtep4_check_vector (&vxm->vtep_table, b0, ip40, &last_vtep4,
     798             :                                        &vxm->vtep4_u512))
     799             : #else
     800           0 :               if (!vtep4_check (&vxm->vtep_table, b0, ip40, &last_vtep4))
     801             : #endif
     802           0 :                 goto exit;      /* no local VTEP for VXLAN packet */
     803             :             }
     804             :           else
     805             :             {
     806           0 :               if (!vtep6_check (&vxm->vtep_table, b0, ip60, &last_vtep6))
     807           0 :                 goto exit;      /* no local VTEP for VXLAN packet */
     808             :             }
     809             : 
     810           0 :           flags0 = b0->flags;
     811           0 :           good_udp0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     812             : 
     813             :           /* Don't verify UDP checksum for packets with explicit zero checksum. */
     814           0 :           good_udp0 |= udp0->checksum == 0;
     815             : 
     816             :           /* Verify UDP length */
     817           0 :           if (is_ip4)
     818           0 :             ip_len0 = clib_net_to_host_u16 (ip40->length);
     819             :           else
     820           0 :             ip_len0 = clib_net_to_host_u16 (ip60->payload_length);
     821           0 :           udp_len0 = clib_net_to_host_u16 (udp0->length);
     822           0 :           len_diff0 = ip_len0 - udp_len0;
     823             : 
     824             :           /* Verify UDP checksum */
     825           0 :           if (PREDICT_FALSE (!good_udp0))
     826             :             {
     827           0 :               if (is_ip4)
     828           0 :                 flags0 = ip4_tcp_udp_validate_checksum (vm, b0);
     829             :               else
     830           0 :                 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, b0);
     831           0 :               good_udp0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     832             :             }
     833             : 
     834           0 :           if (is_ip4)
     835             :             {
     836           0 :               error0 = good_udp0 ? 0 : IP4_ERROR_UDP_CHECKSUM;
     837           0 :               error0 = (len_diff0 >= 0) ? error0 : IP4_ERROR_UDP_LENGTH;
     838             :             }
     839             :           else
     840             :             {
     841           0 :               error0 = good_udp0 ? 0 : IP6_ERROR_UDP_CHECKSUM;
     842           0 :               error0 = (len_diff0 >= 0) ? error0 : IP6_ERROR_UDP_LENGTH;
     843             :             }
     844             : 
     845           0 :           next0 = error0 ?
     846           0 :             IP_VXLAN_BYPASS_NEXT_DROP : IP_VXLAN_BYPASS_NEXT_VXLAN;
     847           0 :           b0->error = error0 ? error_node->errors[error0] : 0;
     848             : 
     849             :           /* vxlan-input node expect current at VXLAN header */
     850           0 :           if (is_ip4)
     851           0 :             vlib_buffer_advance (b0,
     852             :                                  sizeof (ip4_header_t) +
     853             :                                  sizeof (udp_header_t));
     854             :           else
     855           0 :             vlib_buffer_advance (b0,
     856             :                                  sizeof (ip6_header_t) +
     857             :                                  sizeof (udp_header_t));
     858             : 
     859           0 :         exit:
     860           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     861             :                                            to_next, n_left_to_next,
     862             :                                            bi0, next0);
     863             :         }
     864             : 
     865           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     866             :     }
     867             : 
     868           0 :   return frame->n_vectors;
     869             : }
     870             : 
     871         575 : VLIB_NODE_FN (ip4_vxlan_bypass_node) (vlib_main_t * vm,
     872             :                                       vlib_node_runtime_t * node,
     873             :                                       vlib_frame_t * frame)
     874             : {
     875           0 :   return ip_vxlan_bypass_inline (vm, node, frame, /* is_ip4 */ 1);
     876             : }
     877             : 
     878             : /* *INDENT-OFF* */
     879        9215 : VLIB_REGISTER_NODE (ip4_vxlan_bypass_node) =
     880             : {
     881             :   .name = "ip4-vxlan-bypass",
     882             :   .vector_size = sizeof (u32),
     883             :   .n_next_nodes = IP_VXLAN_BYPASS_N_NEXT,
     884             :   .next_nodes = {
     885             :           [IP_VXLAN_BYPASS_NEXT_DROP] = "error-drop",
     886             :           [IP_VXLAN_BYPASS_NEXT_VXLAN] = "vxlan4-input",
     887             :   },
     888             :   .format_buffer = format_ip4_header,
     889             :   .format_trace = format_ip4_forward_next_trace,
     890             : };
     891             : 
     892             : /* *INDENT-ON* */
     893             : 
     894             : /* Dummy init function to get us linked in. */
     895             : static clib_error_t *
     896         575 : ip4_vxlan_bypass_init (vlib_main_t * vm)
     897             : {
     898         575 :   return 0;
     899             : }
     900             : 
     901        1151 : VLIB_INIT_FUNCTION (ip4_vxlan_bypass_init);
     902             : 
     903         575 : VLIB_NODE_FN (ip6_vxlan_bypass_node) (vlib_main_t * vm,
     904             :                                       vlib_node_runtime_t * node,
     905             :                                       vlib_frame_t * frame)
     906             : {
     907           0 :   return ip_vxlan_bypass_inline (vm, node, frame, /* is_ip4 */ 0);
     908             : }
     909             : 
     910             : /* *INDENT-OFF* */
     911        9215 : VLIB_REGISTER_NODE (ip6_vxlan_bypass_node) =
     912             : {
     913             :   .name = "ip6-vxlan-bypass",
     914             :   .vector_size = sizeof (u32),
     915             :   .n_next_nodes = IP_VXLAN_BYPASS_N_NEXT,
     916             :   .next_nodes = {
     917             :     [IP_VXLAN_BYPASS_NEXT_DROP] = "error-drop",
     918             :     [IP_VXLAN_BYPASS_NEXT_VXLAN] = "vxlan6-input",
     919             :   },
     920             :   .format_buffer = format_ip6_header,
     921             :   .format_trace = format_ip6_forward_next_trace,
     922             : };
     923             : 
     924             : /* *INDENT-ON* */
     925             : 
     926             : /* Dummy init function to get us linked in. */
     927             : static clib_error_t *
     928         575 : ip6_vxlan_bypass_init (vlib_main_t * vm)
     929             : {
     930         575 :   return 0;
     931             : }
     932             : 
     933        1727 : VLIB_INIT_FUNCTION (ip6_vxlan_bypass_init);
     934             : 
     935             : #define foreach_vxlan_flow_input_next        \
     936             : _(DROP, "error-drop")                           \
     937             : _(L2_INPUT, "l2-input")
     938             : 
     939             : typedef enum
     940             : {
     941             : #define _(s,n) VXLAN_FLOW_NEXT_##s,
     942             :   foreach_vxlan_flow_input_next
     943             : #undef _
     944             :     VXLAN_FLOW_N_NEXT,
     945             : } vxlan_flow_input_next_t;
     946             : 
     947             : #define foreach_vxlan_flow_error                                        \
     948             :   _(NONE, "no error")                                                 \
     949             :   _(IP_CHECKSUM_ERROR, "Rx ip checksum errors")                               \
     950             :   _(IP_HEADER_ERROR, "Rx ip header errors")                           \
     951             :   _(UDP_CHECKSUM_ERROR, "Rx udp checksum errors")                             \
     952             :   _(UDP_LENGTH_ERROR, "Rx udp length errors")
     953             : 
     954             : typedef enum
     955             : {
     956             : #define _(f,s) VXLAN_FLOW_ERROR_##f,
     957             :   foreach_vxlan_flow_error
     958             : #undef _
     959             :     VXLAN_FLOW_N_ERROR,
     960             : } vxlan_flow_error_t;
     961             : 
     962             : static char *vxlan_flow_error_strings[] = {
     963             : #define _(n,s) s,
     964             :   foreach_vxlan_flow_error
     965             : #undef _
     966             : };
     967             : 
     968             : 
     969             : static_always_inline u8
     970           0 : vxlan_validate_udp_csum (vlib_main_t * vm, vlib_buffer_t * b)
     971             : {
     972           0 :   u32 flags = b->flags;
     973             :   enum
     974             :   { offset =
     975             :       sizeof (ip4_header_t) + sizeof (udp_header_t) + sizeof (vxlan_header_t),
     976             :   };
     977             : 
     978             :   /* Verify UDP checksum */
     979           0 :   if ((flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED) == 0)
     980             :     {
     981           0 :       vlib_buffer_advance (b, -offset);
     982           0 :       flags = ip4_tcp_udp_validate_checksum (vm, b);
     983           0 :       vlib_buffer_advance (b, offset);
     984             :     }
     985             : 
     986           0 :   return (flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
     987             : }
     988             : 
     989             : static_always_inline u8
     990           0 : vxlan_check_udp_csum (vlib_main_t * vm, vlib_buffer_t * b)
     991             : {
     992           0 :   ip4_vxlan_header_t *hdr = vlib_buffer_get_current (b) - sizeof *hdr;
     993           0 :   udp_header_t *udp = &hdr->udp;
     994             :   /* Don't verify UDP checksum for packets with explicit zero checksum. */
     995           0 :   u8 good_csum = (b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0 ||
     996           0 :     udp->checksum == 0;
     997             : 
     998           0 :   return !good_csum;
     999             : }
    1000             : 
    1001             : static_always_inline u8
    1002           0 : vxlan_check_ip (vlib_buffer_t * b, u16 payload_len)
    1003             : {
    1004           0 :   ip4_vxlan_header_t *hdr = vlib_buffer_get_current (b) - sizeof *hdr;
    1005           0 :   u16 ip_len = clib_net_to_host_u16 (hdr->ip4.length);
    1006           0 :   u16 expected = payload_len + sizeof *hdr;
    1007           0 :   return ip_len > expected || hdr->ip4.ttl == 0
    1008           0 :     || hdr->ip4.ip_version_and_header_length != 0x45;
    1009             : }
    1010             : 
    1011             : static_always_inline u8
    1012           0 : vxlan_check_ip_udp_len (vlib_buffer_t * b)
    1013             : {
    1014           0 :   ip4_vxlan_header_t *hdr = vlib_buffer_get_current (b) - sizeof *hdr;
    1015           0 :   u16 ip_len = clib_net_to_host_u16 (hdr->ip4.length);
    1016           0 :   u16 udp_len = clib_net_to_host_u16 (hdr->udp.length);
    1017           0 :   return udp_len > ip_len;
    1018             : }
    1019             : 
    1020             : static_always_inline u8
    1021           0 : vxlan_err_code (u8 ip_err0, u8 udp_err0, u8 csum_err0)
    1022             : {
    1023           0 :   u8 error0 = VXLAN_FLOW_ERROR_NONE;
    1024           0 :   if (ip_err0)
    1025           0 :     error0 = VXLAN_FLOW_ERROR_IP_HEADER_ERROR;
    1026           0 :   if (udp_err0)
    1027           0 :     error0 = VXLAN_FLOW_ERROR_UDP_LENGTH_ERROR;
    1028           0 :   if (csum_err0)
    1029           0 :     error0 = VXLAN_FLOW_ERROR_UDP_CHECKSUM_ERROR;
    1030           0 :   return error0;
    1031             : }
    1032             : 
    1033         575 : VLIB_NODE_FN (vxlan4_flow_input_node) (vlib_main_t * vm,
    1034             :                                        vlib_node_runtime_t * node,
    1035             :                                        vlib_frame_t * f)
    1036             : {
    1037             :   enum
    1038             :   { payload_offset = sizeof (ip4_vxlan_header_t) };
    1039             : 
    1040           0 :   vxlan_main_t *vxm = &vxlan_main;
    1041           0 :   vnet_interface_main_t *im = &vnet_main.interface_main;
    1042           0 :   vlib_combined_counter_main_t *rx_counter[VXLAN_FLOW_N_NEXT] = {
    1043             :     [VXLAN_FLOW_NEXT_DROP] =
    1044           0 :       im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP,
    1045             :     [VXLAN_FLOW_NEXT_L2_INPUT] =
    1046           0 :       im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
    1047             :   };
    1048           0 :   u32 thread_index = vlib_get_thread_index ();
    1049             : 
    1050           0 :   u32 *from = vlib_frame_vector_args (f);
    1051           0 :   u32 n_left_from = f->n_vectors;
    1052           0 :   u32 next_index = VXLAN_FLOW_NEXT_L2_INPUT;
    1053             : 
    1054           0 :   while (n_left_from > 0)
    1055             :     {
    1056             :       u32 n_left_to_next, *to_next;
    1057             : 
    1058           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1059             : 
    1060           0 :       while (n_left_from > 3 && n_left_to_next > 3)
    1061             :         {
    1062           0 :           u32 bi0 = to_next[0] = from[0];
    1063           0 :           u32 bi1 = to_next[1] = from[1];
    1064           0 :           u32 bi2 = to_next[2] = from[2];
    1065           0 :           u32 bi3 = to_next[3] = from[3];
    1066           0 :           from += 4;
    1067           0 :           n_left_from -= 4;
    1068           0 :           to_next += 4;
    1069           0 :           n_left_to_next -= 4;
    1070             : 
    1071           0 :           vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
    1072           0 :           vlib_buffer_t *b1 = vlib_get_buffer (vm, bi1);
    1073           0 :           vlib_buffer_t *b2 = vlib_get_buffer (vm, bi2);
    1074           0 :           vlib_buffer_t *b3 = vlib_get_buffer (vm, bi3);
    1075             : 
    1076           0 :           vlib_buffer_advance (b0, payload_offset);
    1077           0 :           vlib_buffer_advance (b1, payload_offset);
    1078           0 :           vlib_buffer_advance (b2, payload_offset);
    1079           0 :           vlib_buffer_advance (b3, payload_offset);
    1080             : 
    1081           0 :           u16 len0 = vlib_buffer_length_in_chain (vm, b0);
    1082           0 :           u16 len1 = vlib_buffer_length_in_chain (vm, b1);
    1083           0 :           u16 len2 = vlib_buffer_length_in_chain (vm, b2);
    1084           0 :           u16 len3 = vlib_buffer_length_in_chain (vm, b3);
    1085             : 
    1086           0 :           u32 next0 = VXLAN_FLOW_NEXT_L2_INPUT, next1 =
    1087           0 :             VXLAN_FLOW_NEXT_L2_INPUT, next2 =
    1088           0 :             VXLAN_FLOW_NEXT_L2_INPUT, next3 = VXLAN_FLOW_NEXT_L2_INPUT;
    1089             : 
    1090           0 :           u8 ip_err0 = vxlan_check_ip (b0, len0);
    1091           0 :           u8 ip_err1 = vxlan_check_ip (b1, len1);
    1092           0 :           u8 ip_err2 = vxlan_check_ip (b2, len2);
    1093           0 :           u8 ip_err3 = vxlan_check_ip (b3, len3);
    1094           0 :           u8 ip_err = ip_err0 | ip_err1 | ip_err2 | ip_err3;
    1095             : 
    1096           0 :           u8 udp_err0 = vxlan_check_ip_udp_len (b0);
    1097           0 :           u8 udp_err1 = vxlan_check_ip_udp_len (b1);
    1098           0 :           u8 udp_err2 = vxlan_check_ip_udp_len (b2);
    1099           0 :           u8 udp_err3 = vxlan_check_ip_udp_len (b3);
    1100           0 :           u8 udp_err = udp_err0 | udp_err1 | udp_err2 | udp_err3;
    1101             : 
    1102           0 :           u8 csum_err0 = vxlan_check_udp_csum (vm, b0);
    1103           0 :           u8 csum_err1 = vxlan_check_udp_csum (vm, b1);
    1104           0 :           u8 csum_err2 = vxlan_check_udp_csum (vm, b2);
    1105           0 :           u8 csum_err3 = vxlan_check_udp_csum (vm, b3);
    1106           0 :           u8 csum_err = csum_err0 | csum_err1 | csum_err2 | csum_err3;
    1107             : 
    1108           0 :           if (PREDICT_FALSE (csum_err))
    1109             :             {
    1110           0 :               if (csum_err0)
    1111           0 :                 csum_err0 = !vxlan_validate_udp_csum (vm, b0);
    1112           0 :               if (csum_err1)
    1113           0 :                 csum_err1 = !vxlan_validate_udp_csum (vm, b1);
    1114           0 :               if (csum_err2)
    1115           0 :                 csum_err2 = !vxlan_validate_udp_csum (vm, b2);
    1116           0 :               if (csum_err3)
    1117           0 :                 csum_err3 = !vxlan_validate_udp_csum (vm, b3);
    1118           0 :               csum_err = csum_err0 | csum_err1 | csum_err2 | csum_err3;
    1119             :             }
    1120             : 
    1121           0 :           if (PREDICT_FALSE (ip_err || udp_err || csum_err))
    1122             :             {
    1123           0 :               if (ip_err0 || udp_err0 || csum_err0)
    1124             :                 {
    1125           0 :                   next0 = VXLAN_FLOW_NEXT_DROP;
    1126           0 :                   u8 error0 = vxlan_err_code (ip_err0, udp_err0, csum_err0);
    1127           0 :                   b0->error = node->errors[error0];
    1128             :                 }
    1129           0 :               if (ip_err1 || udp_err1 || csum_err1)
    1130             :                 {
    1131           0 :                   next1 = VXLAN_FLOW_NEXT_DROP;
    1132           0 :                   u8 error1 = vxlan_err_code (ip_err1, udp_err1, csum_err1);
    1133           0 :                   b1->error = node->errors[error1];
    1134             :                 }
    1135           0 :               if (ip_err2 || udp_err2 || csum_err2)
    1136             :                 {
    1137           0 :                   next2 = VXLAN_FLOW_NEXT_DROP;
    1138           0 :                   u8 error2 = vxlan_err_code (ip_err2, udp_err2, csum_err2);
    1139           0 :                   b2->error = node->errors[error2];
    1140             :                 }
    1141           0 :               if (ip_err3 || udp_err3 || csum_err3)
    1142             :                 {
    1143           0 :                   next3 = VXLAN_FLOW_NEXT_DROP;
    1144           0 :                   u8 error3 = vxlan_err_code (ip_err3, udp_err3, csum_err3);
    1145           0 :                   b3->error = node->errors[error3];
    1146             :                 }
    1147             :             }
    1148             : 
    1149           0 :           vnet_update_l2_len (b0);
    1150           0 :           vnet_update_l2_len (b1);
    1151           0 :           vnet_update_l2_len (b2);
    1152           0 :           vnet_update_l2_len (b3);
    1153             : 
    1154           0 :           ASSERT (b0->flow_id != 0);
    1155           0 :           ASSERT (b1->flow_id != 0);
    1156           0 :           ASSERT (b2->flow_id != 0);
    1157           0 :           ASSERT (b3->flow_id != 0);
    1158             : 
    1159           0 :           u32 t_index0 = b0->flow_id - vxm->flow_id_start;
    1160           0 :           u32 t_index1 = b1->flow_id - vxm->flow_id_start;
    1161           0 :           u32 t_index2 = b2->flow_id - vxm->flow_id_start;
    1162           0 :           u32 t_index3 = b3->flow_id - vxm->flow_id_start;
    1163             : 
    1164           0 :           vxlan_tunnel_t *t0 = &vxm->tunnels[t_index0];
    1165           0 :           vxlan_tunnel_t *t1 = &vxm->tunnels[t_index1];
    1166           0 :           vxlan_tunnel_t *t2 = &vxm->tunnels[t_index2];
    1167           0 :           vxlan_tunnel_t *t3 = &vxm->tunnels[t_index3];
    1168             : 
    1169             :           /* flow id consumed */
    1170           0 :           b0->flow_id = 0;
    1171           0 :           b1->flow_id = 0;
    1172           0 :           b2->flow_id = 0;
    1173           0 :           b3->flow_id = 0;
    1174             : 
    1175           0 :           u32 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX] =
    1176           0 :             t0->sw_if_index;
    1177           0 :           u32 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX] =
    1178           0 :             t1->sw_if_index;
    1179           0 :           u32 sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_RX] =
    1180           0 :             t2->sw_if_index;
    1181           0 :           u32 sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_RX] =
    1182           0 :             t3->sw_if_index;
    1183             : 
    1184           0 :           vlib_increment_combined_counter (rx_counter[next0], thread_index,
    1185             :                                            sw_if_index0, 1, len0);
    1186           0 :           vlib_increment_combined_counter (rx_counter[next1], thread_index,
    1187             :                                            sw_if_index1, 1, len1);
    1188           0 :           vlib_increment_combined_counter (rx_counter[next2], thread_index,
    1189             :                                            sw_if_index2, 1, len2);
    1190           0 :           vlib_increment_combined_counter (rx_counter[next3], thread_index,
    1191             :                                            sw_if_index3, 1, len3);
    1192             : 
    1193           0 :           u32 flags = b0->flags | b1->flags | b2->flags | b3->flags;
    1194             : 
    1195           0 :           if (PREDICT_FALSE (flags & VLIB_BUFFER_IS_TRACED))
    1196             :             {
    1197           0 :               if (b0->flags & VLIB_BUFFER_IS_TRACED)
    1198             :                 {
    1199             :                   vxlan_rx_trace_t *tr =
    1200           0 :                     vlib_add_trace (vm, node, b0, sizeof *tr);
    1201           0 :                   u8 error0 = vxlan_err_code (ip_err0, udp_err0, csum_err0);
    1202           0 :                   tr->next_index = next0;
    1203           0 :                   tr->error = error0;
    1204           0 :                   tr->tunnel_index = t_index0;
    1205           0 :                   tr->vni = t0->vni;
    1206             :                 }
    1207           0 :               if (b1->flags & VLIB_BUFFER_IS_TRACED)
    1208             :                 {
    1209             :                   vxlan_rx_trace_t *tr =
    1210           0 :                     vlib_add_trace (vm, node, b1, sizeof *tr);
    1211           0 :                   u8 error1 = vxlan_err_code (ip_err1, udp_err1, csum_err1);
    1212           0 :                   tr->next_index = next1;
    1213           0 :                   tr->error = error1;
    1214           0 :                   tr->tunnel_index = t_index1;
    1215           0 :                   tr->vni = t1->vni;
    1216             :                 }
    1217           0 :               if (b2->flags & VLIB_BUFFER_IS_TRACED)
    1218             :                 {
    1219             :                   vxlan_rx_trace_t *tr =
    1220           0 :                     vlib_add_trace (vm, node, b2, sizeof *tr);
    1221           0 :                   u8 error2 = vxlan_err_code (ip_err2, udp_err2, csum_err2);
    1222           0 :                   tr->next_index = next2;
    1223           0 :                   tr->error = error2;
    1224           0 :                   tr->tunnel_index = t_index2;
    1225           0 :                   tr->vni = t2->vni;
    1226             :                 }
    1227           0 :               if (b3->flags & VLIB_BUFFER_IS_TRACED)
    1228             :                 {
    1229             :                   vxlan_rx_trace_t *tr =
    1230           0 :                     vlib_add_trace (vm, node, b3, sizeof *tr);
    1231           0 :                   u8 error3 = vxlan_err_code (ip_err3, udp_err3, csum_err3);
    1232           0 :                   tr->next_index = next3;
    1233           0 :                   tr->error = error3;
    1234           0 :                   tr->tunnel_index = t_index3;
    1235           0 :                   tr->vni = t3->vni;
    1236             :                 }
    1237             :             }
    1238           0 :           vlib_validate_buffer_enqueue_x4
    1239             :             (vm, node, next_index, to_next, n_left_to_next,
    1240             :              bi0, bi1, bi2, bi3, next0, next1, next2, next3);
    1241             :         }
    1242           0 :       while (n_left_from > 0 && n_left_to_next > 0)
    1243             :         {
    1244           0 :           u32 bi0 = to_next[0] = from[0];
    1245           0 :           from++;
    1246           0 :           n_left_from--;
    1247           0 :           to_next++;
    1248           0 :           n_left_to_next--;
    1249             : 
    1250           0 :           vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
    1251           0 :           vlib_buffer_advance (b0, payload_offset);
    1252             : 
    1253           0 :           u16 len0 = vlib_buffer_length_in_chain (vm, b0);
    1254           0 :           u32 next0 = VXLAN_FLOW_NEXT_L2_INPUT;
    1255             : 
    1256           0 :           u8 ip_err0 = vxlan_check_ip (b0, len0);
    1257           0 :           u8 udp_err0 = vxlan_check_ip_udp_len (b0);
    1258           0 :           u8 csum_err0 = vxlan_check_udp_csum (vm, b0);
    1259             : 
    1260           0 :           if (csum_err0)
    1261           0 :             csum_err0 = !vxlan_validate_udp_csum (vm, b0);
    1262           0 :           if (ip_err0 || udp_err0 || csum_err0)
    1263             :             {
    1264           0 :               next0 = VXLAN_FLOW_NEXT_DROP;
    1265           0 :               u8 error0 = vxlan_err_code (ip_err0, udp_err0, csum_err0);
    1266           0 :               b0->error = node->errors[error0];
    1267             :             }
    1268             : 
    1269           0 :           vnet_update_l2_len (b0);
    1270             : 
    1271           0 :           ASSERT (b0->flow_id != 0);
    1272           0 :           u32 t_index0 = b0->flow_id - vxm->flow_id_start;
    1273           0 :           vxlan_tunnel_t *t0 = &vxm->tunnels[t_index0];
    1274           0 :           b0->flow_id = 0;
    1275             : 
    1276           0 :           u32 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX] =
    1277           0 :             t0->sw_if_index;
    1278           0 :           vlib_increment_combined_counter (rx_counter[next0], thread_index,
    1279             :                                            sw_if_index0, 1, len0);
    1280             : 
    1281           0 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1282             :             {
    1283             :               vxlan_rx_trace_t *tr =
    1284           0 :                 vlib_add_trace (vm, node, b0, sizeof *tr);
    1285           0 :               u8 error0 = vxlan_err_code (ip_err0, udp_err0, csum_err0);
    1286           0 :               tr->next_index = next0;
    1287           0 :               tr->error = error0;
    1288           0 :               tr->tunnel_index = t_index0;
    1289           0 :               tr->vni = t0->vni;
    1290             :             }
    1291           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
    1292             :                                            to_next, n_left_to_next,
    1293             :                                            bi0, next0);
    1294             :         }
    1295             : 
    1296           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1297             :     }
    1298             : 
    1299           0 :   return f->n_vectors;
    1300             : }
    1301             : 
    1302             : /* *INDENT-OFF* */
    1303             : #ifndef CLIB_MULTIARCH_VARIANT
    1304        9215 : VLIB_REGISTER_NODE (vxlan4_flow_input_node) = {
    1305             :   .name = "vxlan-flow-input",
    1306             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1307             :   .vector_size = sizeof (u32),
    1308             : 
    1309             :   .format_trace = format_vxlan_rx_trace,
    1310             : 
    1311             :   .n_errors = VXLAN_FLOW_N_ERROR,
    1312             :   .error_strings = vxlan_flow_error_strings,
    1313             : 
    1314             :   .n_next_nodes = VXLAN_FLOW_N_NEXT,
    1315             :   .next_nodes = {
    1316             : #define _(s,n) [VXLAN_FLOW_NEXT_##s] = n,
    1317             :     foreach_vxlan_flow_input_next
    1318             : #undef _
    1319             :   },
    1320             : };
    1321             : #endif
    1322             : /* *INDENT-ON* */
    1323             : 
    1324             : /*
    1325             :  * fd.io coding-style-patch-verification: ON
    1326             :  *
    1327             :  * Local Variables:
    1328             :  * eval: (c-set-style "gnu")
    1329             :  * End:
    1330             :  */

Generated by: LCOV version 1.14