LCOV - code coverage report
Current view: top level - plugins/gre - gre.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 309 360 85.8 %
Date: 2023-10-26 01:39:38 Functions: 44 54 81.5 %

          Line data    Source code
       1             : /*
       2             :  * gre.c: gre
       3             :  *
       4             :  * Copyright (c) 2012 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 <vnet/vnet.h>
      19             : #include <gre/gre.h>
      20             : #include <vnet/adj/adj_midchain.h>
      21             : #include <vnet/tunnel/tunnel_dp.h>
      22             : #include <vpp/app/version.h>
      23             : #include <vnet/plugin/plugin.h>
      24             : 
      25             : extern gre_main_t gre_main;
      26             : 
      27             : #ifndef CLIB_MARCH_VARIANT
      28             : gre_main_t gre_main;
      29             : 
      30             : typedef struct
      31             : {
      32             :   union
      33             :   {
      34             :     ip4_and_gre_header_t ip4_and_gre;
      35             :     u64 as_u64[3];
      36             :   };
      37             : } ip4_and_gre_union_t;
      38             : 
      39             : typedef struct
      40             : {
      41             :   union
      42             :   {
      43             :     ip6_and_gre_header_t ip6_and_gre;
      44             :     u64 as_u64[3];
      45             :   };
      46             : } ip6_and_gre_union_t;
      47             : #endif /* CLIB_MARCH_VARIANT */
      48             : 
      49             : /* Packet trace structure */
      50             : typedef struct
      51             : {
      52             :   /* Tunnel-id / index in tunnel vector */
      53             :   u32 tunnel_id;
      54             : 
      55             :   /* pkt length */
      56             :   u32 length;
      57             : 
      58             :   /* tunnel ip addresses */
      59             :   ip46_address_t src;
      60             :   ip46_address_t dst;
      61             : } gre_tx_trace_t;
      62             : 
      63             : extern u8 *format_gre_tx_trace (u8 *s, va_list *args);
      64             : 
      65             : #ifndef CLIB_MARCH_VARIANT
      66             : u8 *
      67        1699 : format_gre_tx_trace (u8 *s, va_list *args)
      68             : {
      69        1699 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      70        1699 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      71        1699 :   gre_tx_trace_t *t = va_arg (*args, gre_tx_trace_t *);
      72             : 
      73        1699 :   s = format (s, "GRE: tunnel %d len %d src %U dst %U", t->tunnel_id,
      74             :               t->length, format_ip46_address, &t->src, IP46_TYPE_ANY,
      75             :               format_ip46_address, &t->dst, IP46_TYPE_ANY);
      76        1699 :   return s;
      77             : }
      78             : 
      79             : u8 *
      80       16527 : format_gre_protocol (u8 *s, va_list *args)
      81             : {
      82       16527 :   gre_protocol_t p = va_arg (*args, u32);
      83       16527 :   gre_main_t *gm = &gre_main;
      84       16527 :   gre_protocol_info_t *pi = gre_get_protocol_info (gm, p);
      85             : 
      86       16527 :   if (pi)
      87       16524 :     s = format (s, "%s", pi->name);
      88             :   else
      89           3 :     s = format (s, "0x%04x", p);
      90             : 
      91       16527 :   return s;
      92             : }
      93             : 
      94             : u8 *
      95       16527 : format_gre_header_with_length (u8 *s, va_list *args)
      96             : {
      97       16527 :   gre_main_t *gm = &gre_main;
      98       16527 :   gre_header_t *h = va_arg (*args, gre_header_t *);
      99       16527 :   u32 max_header_bytes = va_arg (*args, u32);
     100       16527 :   gre_protocol_t p = clib_net_to_host_u16 (h->protocol);
     101             :   u32 indent, header_bytes;
     102             : 
     103       16527 :   header_bytes = sizeof (h[0]);
     104       16527 :   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
     105           0 :     return format (s, "gre header truncated");
     106             : 
     107       16527 :   indent = format_get_indent (s);
     108             : 
     109       16527 :   s = format (s, "GRE %U", format_gre_protocol, p);
     110             : 
     111       16527 :   if (max_header_bytes != 0 && header_bytes < max_header_bytes)
     112             :     {
     113           0 :       gre_protocol_info_t *pi = gre_get_protocol_info (gm, p);
     114           0 :       vlib_node_t *node = vlib_get_node (gm->vlib_main, pi->node_index);
     115           0 :       if (node->format_buffer)
     116             :         s =
     117           0 :           format (s, "\n%U%U", format_white_space, indent, node->format_buffer,
     118           0 :                   (void *) (h + 1), max_header_bytes - header_bytes);
     119             :     }
     120             : 
     121       16527 :   return s;
     122             : }
     123             : 
     124             : u8 *
     125       16527 : format_gre_header (u8 *s, va_list *args)
     126             : {
     127       16527 :   gre_header_t *h = va_arg (*args, gre_header_t *);
     128       16527 :   return format (s, "%U", format_gre_header_with_length, h, 0);
     129             : }
     130             : 
     131             : /* Returns gre protocol as an int in host byte order. */
     132             : uword
     133           0 : unformat_gre_protocol_host_byte_order (unformat_input_t *input, va_list *args)
     134             : {
     135           0 :   u16 *result = va_arg (*args, u16 *);
     136           0 :   gre_main_t *gm = &gre_main;
     137             :   int i;
     138             : 
     139             :   /* Named type. */
     140           0 :   if (unformat_user (input, unformat_vlib_number_by_name,
     141             :                      gm->protocol_info_by_name, &i))
     142             :     {
     143           0 :       gre_protocol_info_t *pi = vec_elt_at_index (gm->protocol_infos, i);
     144           0 :       *result = pi->protocol;
     145           0 :       return 1;
     146             :     }
     147             : 
     148           0 :   return 0;
     149             : }
     150             : 
     151             : uword
     152           0 : unformat_gre_protocol_net_byte_order (unformat_input_t *input, va_list *args)
     153             : {
     154           0 :   u16 *result = va_arg (*args, u16 *);
     155           0 :   if (!unformat_user (input, unformat_gre_protocol_host_byte_order, result))
     156           0 :     return 0;
     157           0 :   *result = clib_host_to_net_u16 ((u16) *result);
     158           0 :   return 1;
     159             : }
     160             : 
     161             : uword
     162           0 : unformat_gre_header (unformat_input_t *input, va_list *args)
     163             : {
     164           0 :   u8 **result = va_arg (*args, u8 **);
     165           0 :   gre_header_t _h, *h = &_h;
     166             :   u16 p;
     167             : 
     168           0 :   if (!unformat (input, "%U", unformat_gre_protocol_host_byte_order, &p))
     169           0 :     return 0;
     170             : 
     171           0 :   h->protocol = clib_host_to_net_u16 (p);
     172             : 
     173             :   /* Add header to result. */
     174             :   {
     175             :     void *p;
     176           0 :     u32 n_bytes = sizeof (h[0]);
     177             : 
     178           0 :     vec_add2 (*result, p, n_bytes);
     179           0 :     clib_memcpy (p, h, n_bytes);
     180             :   }
     181             : 
     182           0 :   return 1;
     183             : }
     184             : 
     185             : static int
     186         142 : gre_proto_from_vnet_link (vnet_link_t link)
     187             : {
     188         142 :   switch (link)
     189             :     {
     190          62 :     case VNET_LINK_IP4:
     191          62 :       return (GRE_PROTOCOL_ip4);
     192          64 :     case VNET_LINK_IP6:
     193          64 :       return (GRE_PROTOCOL_ip6);
     194           1 :     case VNET_LINK_MPLS:
     195           1 :       return (GRE_PROTOCOL_mpls_unicast);
     196          15 :     case VNET_LINK_ETHERNET:
     197          15 :       return (GRE_PROTOCOL_teb);
     198           0 :     case VNET_LINK_ARP:
     199           0 :       return (GRE_PROTOCOL_arp);
     200           0 :     case VNET_LINK_NSH:
     201           0 :       ASSERT (0);
     202           0 :       break;
     203             :     }
     204           0 :   ASSERT (0);
     205           0 :   return (GRE_PROTOCOL_ip4);
     206             : }
     207             : 
     208             : static u8 *
     209         143 : gre_build_rewrite (vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type,
     210             :                    const void *dst_address)
     211             : {
     212         143 :   gre_main_t *gm = &gre_main;
     213             :   const ip46_address_t *dst;
     214             :   ip4_and_gre_header_t *h4;
     215             :   ip6_and_gre_header_t *h6;
     216             :   gre_header_t *gre;
     217         143 :   u8 *rewrite = NULL;
     218             :   gre_tunnel_t *t;
     219             :   u32 ti;
     220             :   u8 is_ipv6;
     221             : 
     222         143 :   dst = dst_address;
     223         143 :   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
     224             : 
     225         143 :   if (~0 == ti)
     226             :     /* not one of ours */
     227           0 :     return (0);
     228             : 
     229         143 :   t = pool_elt_at_index (gm->tunnels, ti);
     230             : 
     231         143 :   is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
     232             : 
     233         143 :   if (!is_ipv6)
     234             :     {
     235          87 :       vec_validate (rewrite, sizeof (*h4) - 1);
     236          87 :       h4 = (ip4_and_gre_header_t *) rewrite;
     237          87 :       gre = &h4->gre;
     238          87 :       h4->ip4.ip_version_and_header_length = 0x45;
     239          87 :       h4->ip4.ttl = 254;
     240          87 :       h4->ip4.protocol = IP_PROTOCOL_GRE;
     241             :       /* fixup ip4 header length and checksum after-the-fact */
     242          87 :       h4->ip4.src_address.as_u32 = t->tunnel_src.ip4.as_u32;
     243          87 :       h4->ip4.dst_address.as_u32 = dst->ip4.as_u32;
     244          87 :       h4->ip4.checksum = ip4_header_checksum (&h4->ip4);
     245             :     }
     246             :   else
     247             :     {
     248          56 :       vec_validate (rewrite, sizeof (*h6) - 1);
     249          56 :       h6 = (ip6_and_gre_header_t *) rewrite;
     250          56 :       gre = &h6->gre;
     251          56 :       h6->ip6.ip_version_traffic_class_and_flow_label =
     252          56 :         clib_host_to_net_u32 (6 << 28);
     253          56 :       h6->ip6.hop_limit = 255;
     254          56 :       h6->ip6.protocol = IP_PROTOCOL_GRE;
     255             :       /* fixup ip6 header length and checksum after-the-fact */
     256          56 :       h6->ip6.src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
     257          56 :       h6->ip6.src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
     258          56 :       h6->ip6.dst_address.as_u64[0] = dst->ip6.as_u64[0];
     259          56 :       h6->ip6.dst_address.as_u64[1] = dst->ip6.as_u64[1];
     260             :     }
     261             : 
     262         143 :   if (PREDICT_FALSE (t->type == GRE_TUNNEL_TYPE_ERSPAN))
     263             :     {
     264           1 :       gre->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_erspan);
     265           1 :       gre->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_SEQUENCE);
     266             :     }
     267             :   else
     268         142 :     gre->protocol =
     269         142 :       clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type));
     270             : 
     271         143 :   return (rewrite);
     272             : }
     273             : 
     274             : static void
     275       13690 : gre44_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
     276             :              const void *data)
     277             : {
     278             :   tunnel_encap_decap_flags_t flags;
     279             :   ip4_and_gre_header_t *ip0;
     280             : 
     281       13690 :   ip0 = vlib_buffer_get_current (b0);
     282       13690 :   flags = pointer_to_uword (data);
     283             : 
     284             :   /* Fixup the checksum and len fields in the GRE tunnel encap
     285             :    * that was applied at the midchain node */
     286       13690 :   ip0->ip4.length =
     287       13690 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
     288       13690 :   tunnel_encap_fixup_4o4 (flags, (ip4_header_t *) (ip0 + 1), &ip0->ip4);
     289       13690 :   ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
     290       13690 : }
     291             : 
     292             : static void
     293         385 : gre64_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
     294             :              const void *data)
     295             : {
     296             :   tunnel_encap_decap_flags_t flags;
     297             :   ip4_and_gre_header_t *ip0;
     298             : 
     299         385 :   ip0 = vlib_buffer_get_current (b0);
     300         385 :   flags = pointer_to_uword (data);
     301             : 
     302             :   /* Fixup the checksum and len fields in the GRE tunnel encap
     303             :    * that was applied at the midchain node */
     304         385 :   ip0->ip4.length =
     305         385 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
     306         385 :   tunnel_encap_fixup_6o4 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip4);
     307         385 :   ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
     308         385 : }
     309             : 
     310             : static void
     311        2576 : grex4_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
     312             :              const void *data)
     313             : {
     314             :   ip4_header_t *ip0;
     315             : 
     316        2576 :   ip0 = vlib_buffer_get_current (b0);
     317             : 
     318             :   /* Fixup the checksum and len fields in the GRE tunnel encap
     319             :    * that was applied at the midchain node */
     320        2576 :   ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
     321        2576 :   ip0->checksum = ip4_header_checksum (ip0);
     322        2576 : }
     323             : 
     324             : static void
     325         257 : gre46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
     326             :              const void *data)
     327             : {
     328             :   tunnel_encap_decap_flags_t flags;
     329             :   ip6_and_gre_header_t *ip0;
     330             : 
     331         257 :   ip0 = vlib_buffer_get_current (b0);
     332         257 :   flags = pointer_to_uword (data);
     333             : 
     334             :   /* Fixup the payload length field in the GRE tunnel encap that was applied
     335             :    * at the midchain node */
     336         514 :   ip0->ip6.payload_length = clib_host_to_net_u16 (
     337         257 :     vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
     338         257 :   tunnel_encap_fixup_4o6 (flags, b0, (ip4_header_t *) (ip0 + 1), &ip0->ip6);
     339         257 : }
     340             : 
     341             : static void
     342        6407 : gre66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
     343             :              const void *data)
     344             : {
     345             :   tunnel_encap_decap_flags_t flags;
     346             :   ip6_and_gre_header_t *ip0;
     347             : 
     348        6407 :   ip0 = vlib_buffer_get_current (b0);
     349        6407 :   flags = pointer_to_uword (data);
     350             : 
     351             :   /* Fixup the payload length field in the GRE tunnel encap that was applied
     352             :    * at the midchain node */
     353       12814 :   ip0->ip6.payload_length = clib_host_to_net_u16 (
     354        6407 :     vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
     355        6407 :   tunnel_encap_fixup_6o6 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip6);
     356        6407 : }
     357             : 
     358             : static void
     359           0 : grex6_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
     360             :              const void *data)
     361             : {
     362             :   ip6_and_gre_header_t *ip0;
     363             : 
     364           0 :   ip0 = vlib_buffer_get_current (b0);
     365             : 
     366             :   /* Fixup the payload length field in the GRE tunnel encap that was applied
     367             :    * at the midchain node */
     368           0 :   ip0->ip6.payload_length = clib_host_to_net_u16 (
     369           0 :     vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
     370           0 : }
     371             : 
     372             : /**
     373             :  * return the appropriate fixup function given the overlay (link-type) and
     374             :  * underlay (fproto) combination
     375             :  */
     376             : static adj_midchain_fixup_t
     377         215 : gre_get_fixup (fib_protocol_t fproto, vnet_link_t lt)
     378             : {
     379         215 :   if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP6)
     380          64 :     return (gre66_fixup);
     381         151 :   if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP4)
     382           1 :     return (gre46_fixup);
     383         150 :   if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP6)
     384           9 :     return (gre64_fixup);
     385         141 :   if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP4)
     386         124 :     return (gre44_fixup);
     387          17 :   if (fproto == FIB_PROTOCOL_IP6)
     388           0 :     return (grex6_fixup);
     389          17 :   if (fproto == FIB_PROTOCOL_IP4)
     390          17 :     return (grex4_fixup);
     391             : 
     392           0 :   ASSERT (0);
     393           0 :   return (gre44_fixup);
     394             : }
     395             : 
     396             : void
     397          47 : gre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
     398             : {
     399          47 :   gre_main_t *gm = &gre_main;
     400             :   gre_tunnel_t *t;
     401             :   adj_flags_t af;
     402             :   u32 ti;
     403             : 
     404          47 :   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
     405          47 :   t = pool_elt_at_index (gm->tunnels, ti);
     406          47 :   af = ADJ_FLAG_NONE;
     407             : 
     408             :   /*
     409             :    * the user has not requested that the load-balancing be based on
     410             :    * a flow hash of the inner packet. so use the stacking to choose
     411             :    * a path.
     412             :    */
     413          47 :   if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
     414          47 :     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
     415             : 
     416          94 :   adj_nbr_midchain_update_rewrite (
     417          47 :     ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
     418          47 :     uword_to_pointer (t->flags, void *), af,
     419          47 :     gre_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai),
     420          47 :                        &t->tunnel_dst.fp_addr));
     421             : 
     422          47 :   gre_tunnel_stack (ai);
     423          47 : }
     424             : 
     425             : adj_walk_rc_t
     426          96 : mgre_mk_complete_walk (adj_index_t ai, void *data)
     427             : {
     428          96 :   mgre_walk_ctx_t *ctx = data;
     429             :   adj_flags_t af;
     430             : 
     431          96 :   af = ADJ_FLAG_NONE;
     432             : 
     433             :   /*
     434             :    * the user has not requested that the load-balancing be based on
     435             :    * a flow hash of the inner packet. so use the stacking to choose
     436             :    * a path.
     437             :    */
     438          96 :   if (!(ctx->t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
     439          96 :     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
     440             : 
     441         192 :   adj_nbr_midchain_update_rewrite (
     442          96 :     ai, gre_get_fixup (ctx->t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
     443          96 :     uword_to_pointer (ctx->t->flags, void *), af,
     444          96 :     gre_build_rewrite (vnet_get_main (), ctx->t->sw_if_index,
     445          96 :                        adj_get_link_type (ai),
     446          96 :                        &teib_entry_get_nh (ctx->ne)->fp_addr));
     447             : 
     448          96 :   teib_entry_adj_stack (ctx->ne, ai);
     449             : 
     450          96 :   return (ADJ_WALK_RC_CONTINUE);
     451             : }
     452             : 
     453             : adj_walk_rc_t
     454          50 : mgre_mk_incomplete_walk (adj_index_t ai, void *data)
     455             : {
     456          50 :   gre_tunnel_t *t = data;
     457             : 
     458          50 :   adj_nbr_midchain_update_rewrite (
     459          50 :     ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)), NULL,
     460             :     ADJ_FLAG_NONE, NULL);
     461             : 
     462          50 :   adj_midchain_delegate_unstack (ai);
     463             : 
     464          50 :   return (ADJ_WALK_RC_CONTINUE);
     465             : }
     466             : 
     467             : void
     468          45 : mgre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
     469             : {
     470          45 :   gre_main_t *gm = &gre_main;
     471             :   ip_adjacency_t *adj;
     472             :   teib_entry_t *ne;
     473             :   gre_tunnel_t *t;
     474             :   u32 ti;
     475             : 
     476          45 :   adj = adj_get (ai);
     477          45 :   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
     478          45 :   t = pool_elt_at_index (gm->tunnels, ti);
     479             : 
     480          45 :   ne = teib_entry_find_46 (sw_if_index, adj->ia_nh_proto,
     481          45 :                            &adj->sub_type.nbr.next_hop);
     482             : 
     483          45 :   if (NULL == ne)
     484             :     {
     485             :       // no TEIB entry to provide the next-hop
     486          22 :       adj_nbr_midchain_update_rewrite (
     487          22 :         ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
     488          22 :         uword_to_pointer (t->flags, void *), ADJ_FLAG_NONE, NULL);
     489          22 :       return;
     490             :     }
     491             : 
     492          23 :   mgre_walk_ctx_t ctx = { .t = t, .ne = ne };
     493          23 :   adj_nbr_walk_nh (sw_if_index, adj->ia_nh_proto, &adj->sub_type.nbr.next_hop,
     494             :                    mgre_mk_complete_walk, &ctx);
     495             : }
     496             : #endif /* CLIB_MARCH_VARIANT */
     497             : 
     498             : typedef enum
     499             : {
     500             :   GRE_ENCAP_NEXT_L2_MIDCHAIN,
     501             :   GRE_ENCAP_N_NEXT,
     502             : } gre_encap_next_t;
     503             : 
     504             : /**
     505             :  * @brief TX function. Only called for L2 payload including TEB or ERSPAN.
     506             :  *        L3 traffic uses the adj-midchains.
     507             :  */
     508             : static_always_inline u32
     509          28 : gre_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     510             :                   vlib_frame_t *frame, gre_tunnel_type_t type)
     511             : {
     512          28 :   gre_main_t *gm = &gre_main;
     513             :   u32 *from, n_left_from;
     514          28 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     515          28 :   u32 sw_if_index[2] = { ~0, ~0 };
     516          28 :   const gre_tunnel_t *gt[2] = { 0 };
     517          28 :   adj_index_t adj_index[2] = { ADJ_INDEX_INVALID, ADJ_INDEX_INVALID };
     518             : 
     519          28 :   from = vlib_frame_vector_args (frame);
     520          28 :   n_left_from = frame->n_vectors;
     521          28 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     522             : 
     523        1048 :   while (n_left_from >= 2)
     524             :     {
     525             : 
     526        1020 :       if (PREDICT_FALSE (sw_if_index[0] !=
     527             :                          vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
     528             :         {
     529             :           const vnet_hw_interface_t *hi;
     530          10 :           sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     531          10 :           hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
     532          10 :           gt[0] = &gm->tunnels[hi->dev_instance];
     533          10 :           adj_index[0] = gt[0]->l2_adj_index;
     534             :         }
     535        1020 :       if (PREDICT_FALSE (sw_if_index[1] !=
     536             :                          vnet_buffer (b[1])->sw_if_index[VLIB_TX]))
     537             :         {
     538             :           const vnet_hw_interface_t *hi;
     539          10 :           sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
     540          10 :           hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[1]);
     541          10 :           gt[1] = &gm->tunnels[hi->dev_instance];
     542          10 :           adj_index[1] = gt[1]->l2_adj_index;
     543             :         }
     544             : 
     545        1020 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
     546        1020 :       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = adj_index[1];
     547             : 
     548        1020 :       if (type == GRE_TUNNEL_TYPE_ERSPAN)
     549             :         {
     550             :           /* Encap GRE seq# and ERSPAN type II header */
     551             :           erspan_t2_t *h0;
     552             :           u32 seq_num;
     553             :           u64 hdr;
     554         128 :           vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
     555         128 :           h0 = vlib_buffer_get_current (b[0]);
     556         128 :           seq_num = clib_atomic_fetch_add (&gt[0]->gre_sn->seq_num, 1);
     557         128 :           hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
     558         128 :           h0->seq_num = clib_host_to_net_u32 (seq_num);
     559         128 :           h0->t2_u64 = hdr;
     560         128 :           h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
     561             :         }
     562        1020 :       if (type == GRE_TUNNEL_TYPE_ERSPAN)
     563             :         {
     564             :           /* Encap GRE seq# and ERSPAN type II header */
     565             :           erspan_t2_t *h0;
     566             :           u32 seq_num;
     567             :           u64 hdr;
     568         128 :           vlib_buffer_advance (b[1], -sizeof (erspan_t2_t));
     569         128 :           h0 = vlib_buffer_get_current (b[1]);
     570         128 :           seq_num = clib_atomic_fetch_add (&gt[1]->gre_sn->seq_num, 1);
     571         128 :           hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
     572         128 :           h0->seq_num = clib_host_to_net_u32 (seq_num);
     573         128 :           h0->t2_u64 = hdr;
     574         128 :           h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[1]->session_id);
     575             :         }
     576             : 
     577        1020 :       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
     578             :         {
     579        1020 :           gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
     580        1020 :           tr->tunnel_id = gt[0] - gm->tunnels;
     581        1020 :           tr->src = gt[0]->tunnel_src;
     582        1020 :           tr->dst = gt[0]->tunnel_dst.fp_addr;
     583        1020 :           tr->length = vlib_buffer_length_in_chain (vm, b[0]);
     584             :         }
     585        1020 :       if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
     586             :         {
     587        1020 :           gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[1], sizeof (*tr));
     588        1020 :           tr->tunnel_id = gt[1] - gm->tunnels;
     589        1020 :           tr->src = gt[1]->tunnel_src;
     590        1020 :           tr->dst = gt[1]->tunnel_dst.fp_addr;
     591        1020 :           tr->length = vlib_buffer_length_in_chain (vm, b[1]);
     592             :         }
     593             : 
     594        1020 :       b += 2;
     595        1020 :       n_left_from -= 2;
     596             :     }
     597             : 
     598          50 :   while (n_left_from >= 1)
     599             :     {
     600             : 
     601          22 :       if (PREDICT_FALSE (sw_if_index[0] !=
     602             :                          vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
     603             :         {
     604             :           const vnet_hw_interface_t *hi;
     605          18 :           sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     606          18 :           hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
     607          18 :           gt[0] = &gm->tunnels[hi->dev_instance];
     608          18 :           adj_index[0] = gt[0]->l2_adj_index;
     609             :         }
     610             : 
     611          22 :       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
     612             : 
     613          22 :       if (type == GRE_TUNNEL_TYPE_ERSPAN)
     614             :         {
     615             :           /* Encap GRE seq# and ERSPAN type II header */
     616             :           erspan_t2_t *h0;
     617             :           u32 seq_num;
     618             :           u64 hdr;
     619           1 :           ASSERT (gt[0]->type == GRE_TUNNEL_TYPE_ERSPAN);
     620           1 :           vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
     621           1 :           h0 = vlib_buffer_get_current (b[0]);
     622           1 :           seq_num = clib_atomic_fetch_add (&gt[0]->gre_sn->seq_num, 1);
     623           1 :           hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
     624           1 :           h0->seq_num = clib_host_to_net_u32 (seq_num);
     625           1 :           h0->t2_u64 = hdr;
     626           1 :           h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
     627             :         }
     628             : 
     629          22 :       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
     630             :         {
     631          22 :           gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
     632          22 :           tr->tunnel_id = gt[0] - gm->tunnels;
     633          22 :           tr->src = gt[0]->tunnel_src;
     634          22 :           tr->dst = gt[0]->tunnel_dst.fp_addr;
     635          22 :           tr->length = vlib_buffer_length_in_chain (vm, b[0]);
     636             :         }
     637             : 
     638          22 :       b += 1;
     639          22 :       n_left_from -= 1;
     640             :     }
     641             : 
     642          28 :   vlib_buffer_enqueue_to_single_next (
     643          28 :     vm, node, from, GRE_ENCAP_NEXT_L2_MIDCHAIN, frame->n_vectors);
     644             : 
     645          28 :   vlib_node_increment_counter (vm, node->node_index, GRE_ERROR_PKTS_ENCAP,
     646          28 :                                frame->n_vectors);
     647             : 
     648          28 :   return frame->n_vectors;
     649             : }
     650             : 
     651             : static char *gre_error_strings[] = {
     652             : #define gre_error(n, s) s,
     653             : #include "error.def"
     654             : #undef gre_error
     655             : };
     656             : 
     657        2326 : VLIB_NODE_FN (gre_teb_encap_node)
     658             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     659             : {
     660          26 :   return (gre_encap_inline (vm, node, frame, GRE_TUNNEL_TYPE_TEB));
     661             : }
     662             : 
     663        2302 : VLIB_NODE_FN (gre_erspan_encap_node)
     664             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     665             : {
     666           2 :   return (gre_encap_inline (vm, node, frame, GRE_TUNNEL_TYPE_ERSPAN));
     667             : }
     668             : 
     669             : /* *INDENT-OFF* */
     670      138284 : VLIB_REGISTER_NODE (gre_teb_encap_node) =
     671             : {
     672             :   .name = "gre-teb-encap",
     673             :   .vector_size = sizeof (u32),
     674             :   .format_trace = format_gre_tx_trace,
     675             :   .type = VLIB_NODE_TYPE_INTERNAL,
     676             :   .n_errors = GRE_N_ERROR,
     677             :   .error_strings = gre_error_strings,
     678             :   .n_next_nodes = GRE_ENCAP_N_NEXT,
     679             :   .next_nodes = {
     680             :     [GRE_ENCAP_NEXT_L2_MIDCHAIN] = "adj-l2-midchain",
     681             :   },
     682             : };
     683      138284 : VLIB_REGISTER_NODE (gre_erspan_encap_node) =
     684             : {
     685             :   .name = "gre-erspan-encap",
     686             :   .vector_size = sizeof (u32),
     687             :   .format_trace = format_gre_tx_trace,
     688             :   .type = VLIB_NODE_TYPE_INTERNAL,
     689             :   .n_errors = GRE_N_ERROR,
     690             :   .error_strings = gre_error_strings,
     691             :   .n_next_nodes = GRE_ENCAP_N_NEXT,
     692             :   .next_nodes = {
     693             :     [GRE_ENCAP_NEXT_L2_MIDCHAIN] = "adj-l2-midchain",
     694             :   },
     695             : };
     696             : /* *INDENT-ON* */
     697             : 
     698             : #ifndef CLIB_MARCH_VARIANT
     699             : static u8 *
     700         107 : format_gre_tunnel_name (u8 *s, va_list *args)
     701             : {
     702         107 :   u32 dev_instance = va_arg (*args, u32);
     703         107 :   gre_main_t *gm = &gre_main;
     704             :   gre_tunnel_t *t;
     705             : 
     706         107 :   if (dev_instance >= vec_len (gm->tunnels))
     707           0 :     return format (s, "<improperly-referenced>");
     708             : 
     709         107 :   t = pool_elt_at_index (gm->tunnels, dev_instance);
     710         107 :   return format (s, "gre%d", t->user_instance);
     711             : }
     712             : 
     713             : static u8 *
     714          60 : format_gre_device (u8 *s, va_list *args)
     715             : {
     716          60 :   u32 dev_instance = va_arg (*args, u32);
     717          60 :   CLIB_UNUSED (int verbose) = va_arg (*args, int);
     718             : 
     719          60 :   s = format (s, "GRE tunnel: id %d\n", dev_instance);
     720          60 :   return s;
     721             : }
     722             : 
     723             : static int
     724          54 : gre_tunnel_desc (u32 sw_if_index, ip46_address_t *src, ip46_address_t *dst,
     725             :                  u8 *is_l2)
     726             : {
     727          54 :   gre_main_t *gm = &gre_main;
     728             :   gre_tunnel_t *t;
     729             :   u32 ti;
     730             : 
     731          54 :   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
     732             : 
     733          54 :   if (~0 == ti)
     734             :     /* not one of ours */
     735           0 :     return -1;
     736             : 
     737          54 :   t = pool_elt_at_index (gm->tunnels, ti);
     738             : 
     739          54 :   *src = t->tunnel_src;
     740          54 :   *dst = t->tunnel_dst.fp_addr;
     741          54 :   *is_l2 = t->type == GRE_TUNNEL_TYPE_TEB;
     742             : 
     743          54 :   return (0);
     744             : }
     745             : 
     746             : /* *INDENT-OFF* */
     747        9215 : VNET_DEVICE_CLASS (gre_device_class) = {
     748             :   .name = "GRE tunnel device",
     749             :   .format_device_name = format_gre_tunnel_name,
     750             :   .format_device = format_gre_device,
     751             :   .format_tx_trace = format_gre_tx_trace,
     752             :   .admin_up_down_function = gre_interface_admin_up_down,
     753             :   .ip_tun_desc = gre_tunnel_desc,
     754             : #ifdef SOON
     755             :   .clear counter = 0;
     756             : #endif
     757             : }
     758             : ;
     759             : 
     760        5759 : VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
     761             :   .name = "GRE",
     762             :   .format_header = format_gre_header_with_length,
     763             :   .unformat_header = unformat_gre_header,
     764             :   .build_rewrite = gre_build_rewrite,
     765             :   .update_adjacency = gre_update_adj,
     766             :   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
     767             : };
     768             : 
     769        5759 : VNET_HW_INTERFACE_CLASS (mgre_hw_interface_class) = {
     770             :   .name = "mGRE",
     771             :   .format_header = format_gre_header_with_length,
     772             :   .unformat_header = unformat_gre_header,
     773             :   .build_rewrite = gre_build_rewrite,
     774             :   .update_adjacency = mgre_update_adj,
     775             :   .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
     776             : };
     777             : /* *INDENT-ON* */
     778             : #endif /* CLIB_MARCH_VARIANT */
     779             : 
     780             : static void
     781        4025 : add_protocol (gre_main_t *gm, gre_protocol_t protocol, char *protocol_name)
     782             : {
     783             :   gre_protocol_info_t *pi;
     784             :   u32 i;
     785             : 
     786        4025 :   vec_add2 (gm->protocol_infos, pi, 1);
     787        4025 :   i = pi - gm->protocol_infos;
     788             : 
     789        4025 :   pi->name = protocol_name;
     790        4025 :   pi->protocol = protocol;
     791        4025 :   pi->next_index = pi->node_index = ~0;
     792             : 
     793        4025 :   hash_set (gm->protocol_info_by_protocol, protocol, i);
     794        8050 :   hash_set_mem (gm->protocol_info_by_name, pi->name, i);
     795        4025 : }
     796             : 
     797             : static clib_error_t *
     798         575 : gre_init (vlib_main_t *vm)
     799             : {
     800         575 :   gre_main_t *gm = &gre_main;
     801             :   clib_error_t *error;
     802         575 :   ip_main_t *im = &ip_main;
     803             :   ip_protocol_info_t *pi;
     804             : 
     805         575 :   clib_memset (gm, 0, sizeof (gm[0]));
     806         575 :   gm->vlib_main = vm;
     807         575 :   gm->vnet_main = vnet_get_main ();
     808             : 
     809         575 :   if ((error = vlib_call_init_function (vm, ip_main_init)))
     810           0 :     return error;
     811             : 
     812         575 :   if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
     813           0 :     return error;
     814             : 
     815         575 :   if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
     816           0 :     return error;
     817             : 
     818             :   /* Set up the ip packet generator */
     819         575 :   pi = ip_get_protocol_info (im, IP_PROTOCOL_GRE);
     820         575 :   pi->format_header = format_gre_header;
     821         575 :   pi->unformat_pg_edit = unformat_pg_gre_header;
     822             : 
     823         575 :   gm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
     824         575 :   gm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
     825         575 :   gm->tunnel_by_key4 =
     826         575 :     hash_create_mem (0, sizeof (gre_tunnel_key4_t), sizeof (uword));
     827         575 :   gm->tunnel_by_key6 =
     828         575 :     hash_create_mem (0, sizeof (gre_tunnel_key6_t), sizeof (uword));
     829         575 :   gm->seq_num_by_key =
     830         575 :     hash_create_mem (0, sizeof (gre_sn_key_t), sizeof (uword));
     831             : 
     832             : #define _(n, s) add_protocol (gm, GRE_PROTOCOL_##s, #s);
     833         575 :   foreach_gre_protocol
     834             : #undef _
     835         575 :     return vlib_call_init_function (vm, gre_input_init);
     836             : }
     837             : 
     838        1151 : VLIB_INIT_FUNCTION (gre_init);
     839             : 
     840             : /*
     841             :  * fd.io coding-style-patch-verification: ON
     842             :  *
     843             :  * Local Variables:
     844             :  * eval: (c-set-style "gnu")
     845             :  * End:
     846             :  */

Generated by: LCOV version 1.14