ipsec: IPSec protection for multi-point tunnel interfaces
[vpp.git] / src / vnet / geneve / encap.c
index e9e7e5b..2859a9a 100644 (file)
@@ -43,25 +43,6 @@ typedef enum
   GENEVE_ENCAP_N_NEXT,
 } geneve_encap_next_t;
 
-typedef struct
-{
-  u32 tunnel_index;
-  u32 vni;
-} geneve_encap_trace_t;
-
-u8 *
-format_geneve_encap_trace (u8 * s, va_list * args)
-{
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  geneve_encap_trace_t *t = va_arg (*args, geneve_encap_trace_t *);
-
-  s = format (s, "GENEVE encap to geneve_tunnel%d vni %d",
-             t->tunnel_index, t->vni);
-  return s;
-}
-
-
 #define foreach_fixed_header4_offset            \
     _(0) _(1) _(2) _(3)
 
@@ -79,15 +60,17 @@ geneve_encap_inline (vlib_main_t * vm,
   vnet_interface_main_t *im = &vnm->interface_main;
   u32 pkts_encapsulated = 0;
   u16 old_l0 = 0, old_l1 = 0;
-  u32 thread_index = vlib_get_thread_index ();
+  u32 thread_index = vm->thread_index;
   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
-  u32 sw_if_index0 = 0, sw_if_index1 = 0;
+  u32 sw_if_index0 = ~0, sw_if_index1 = ~0;
   u32 next0 = 0, next1 = 0;
   vnet_hw_interface_t *hi0, *hi1;
   geneve_tunnel_t *t0 = NULL, *t1 = NULL;
+  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
 
   from = vlib_frame_vector_args (from_frame);
   n_left_from = from_frame->n_vectors;
+  vlib_get_buffers (vm, from, bufs, n_left_from);
 
   next_index = node->cached_next_index;
   stats_sw_if_index = node->runtime_data[0];
@@ -102,7 +85,6 @@ geneve_encap_inline (vlib_main_t * vm,
       while (n_left_from >= 4 && n_left_to_next >= 2)
        {
          u32 bi0, bi1;
-         vlib_buffer_t *b0, *b1;
          u32 flow_hash0, flow_hash1;
          u32 len0, len1;
          ip4_header_t *ip4_0, *ip4_1;
@@ -117,16 +99,13 @@ geneve_encap_inline (vlib_main_t * vm,
 
          /* Prefetch next iteration. */
          {
-           vlib_buffer_t *p2, *p3;
-
-           p2 = vlib_get_buffer (vm, from[2]);
-           p3 = vlib_get_buffer (vm, from[3]);
-
-           vlib_prefetch_buffer_header (p2, LOAD);
-           vlib_prefetch_buffer_header (p3, LOAD);
+           vlib_prefetch_buffer_header (b[2], LOAD);
+           vlib_prefetch_buffer_header (b[3], LOAD);
 
-           CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
-           CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+           CLIB_PREFETCH (b[2]->data - CLIB_CACHE_LINE_BYTES,
+                          2 * CLIB_CACHE_LINE_BYTES, LOAD);
+           CLIB_PREFETCH (b[3]->data - CLIB_CACHE_LINE_BYTES,
+                          2 * CLIB_CACHE_LINE_BYTES, LOAD);
          }
 
          bi0 = from[0];
@@ -138,43 +117,41 @@ geneve_encap_inline (vlib_main_t * vm,
          n_left_to_next -= 2;
          n_left_from -= 2;
 
-         b0 = vlib_get_buffer (vm, bi0);
-         b1 = vlib_get_buffer (vm, bi1);
+         flow_hash0 = vnet_l2_compute_flow_hash (b[0]);
+         flow_hash1 = vnet_l2_compute_flow_hash (b[1]);
 
-         flow_hash0 = vnet_l2_compute_flow_hash (b0);
-         flow_hash1 = vnet_l2_compute_flow_hash (b1);
 
          /* Get next node index and adj index from tunnel next_dpo */
-         if (sw_if_index0 != vnet_buffer (b0)->sw_if_index[VLIB_TX])
+         if (sw_if_index0 != vnet_buffer (b[0])->sw_if_index[VLIB_TX])
            {
-             sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+             sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
              hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
              t0 = &vxm->tunnels[hi0->dev_instance];
              /* Note: change to always set next0 if it may be set to drop */
              next0 = t0->next_dpo.dpoi_next_node;
            }
 
-         ASSERT (t0 != NULL);
+         ALWAYS_ASSERT (t0 != NULL);
 
-         vnet_buffer (b0)->ip.adj_index[VLIB_TX] = t0->next_dpo.dpoi_index;
+         vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = t0->next_dpo.dpoi_index;
 
          /* Get next node index and adj index from tunnel next_dpo */
-         if (sw_if_index1 != vnet_buffer (b1)->sw_if_index[VLIB_TX])
+         if (sw_if_index1 != vnet_buffer (b[1])->sw_if_index[VLIB_TX])
            {
-             sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
+             sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
              hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
              t1 = &vxm->tunnels[hi1->dev_instance];
              /* Note: change to always set next1 if it may be set to drop */
              next1 = t1->next_dpo.dpoi_next_node;
            }
 
-         ASSERT (t1 != NULL);
+         ALWAYS_ASSERT (t1 != NULL);
 
-         vnet_buffer (b1)->ip.adj_index[VLIB_TX] = t1->next_dpo.dpoi_index;
+         vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = t1->next_dpo.dpoi_index;
 
          /* Apply the rewrite string. $$$$ vnet_rewrite? */
-         vlib_buffer_advance (b0, -(word) _vec_len (t0->rewrite));
-         vlib_buffer_advance (b1, -(word) _vec_len (t1->rewrite));
+         vlib_buffer_advance (b[0], -(word) _vec_len (t0->rewrite));
+         vlib_buffer_advance (b[1], -(word) _vec_len (t1->rewrite));
 
          if (is_ip4)
            {
@@ -190,8 +167,8 @@ geneve_encap_inline (vlib_main_t * vm,
              ASSERT (vec_len (t0->rewrite) == ip4_geneve_header_total_len0);
              ASSERT (vec_len (t1->rewrite) == ip4_geneve_header_total_len1);
 
-             ip4_0 = vlib_buffer_get_current (b0);
-             ip4_1 = vlib_buffer_get_current (b1);
+             ip4_0 = vlib_buffer_get_current (b[0]);
+             ip4_1 = vlib_buffer_get_current (b[1]);
 
              /* Copy the fixed header */
              copy_dst0 = (u64 *) ip4_0;
@@ -216,14 +193,14 @@ geneve_encap_inline (vlib_main_t * vm,
              /* Fix the IP4 checksum and length */
              sum0 = ip4_0->checksum;
              new_l0 =          /* old_l0 always 0, see the rewrite setup */
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[0]));
              sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
                                     length /* changed member */ );
              ip4_0->checksum = ip_csum_fold (sum0);
              ip4_0->length = new_l0;
              sum1 = ip4_1->checksum;
              new_l1 =          /* old_l1 always 0, see the rewrite setup */
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[1]));
              sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
                                     length /* changed member */ );
              ip4_1->checksum = ip_csum_fold (sum1);
@@ -232,13 +209,13 @@ geneve_encap_inline (vlib_main_t * vm,
              /* Fix UDP length and set source port */
              udp0 = (udp_header_t *) (ip4_0 + 1);
              new_l0 =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[0]) -
                                      sizeof (*ip4_0));
              udp0->length = new_l0;
              udp0->src_port = flow_hash0;
              udp1 = (udp_header_t *) (ip4_1 + 1);
              new_l1 =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1) -
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[1]) -
                                      sizeof (*ip4_1));
              udp1->length = new_l1;
              udp1->src_port = flow_hash1;
@@ -259,8 +236,8 @@ geneve_encap_inline (vlib_main_t * vm,
              ASSERT (vec_len (t0->rewrite) == ip6_geneve_header_total_len0);
              ASSERT (vec_len (t1->rewrite) == ip6_geneve_header_total_len1);
 
-             ip6_0 = vlib_buffer_get_current (b0);
-             ip6_1 = vlib_buffer_get_current (b1);
+             ip6_0 = vlib_buffer_get_current (b[0]);
+             ip6_1 = vlib_buffer_get_current (b[1]);
 
              /* Copy the fixed header */
              copy_dst0 = (u64 *) ip6_0;
@@ -276,11 +253,11 @@ geneve_encap_inline (vlib_main_t * vm,
 #undef _
              /* Fix IP6 payload length */
              new_l0 =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[0])
                                      - sizeof (*ip6_0));
              ip6_0->payload_length = new_l0;
              new_l1 =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[1])
                                      - sizeof (*ip6_1));
              ip6_1->payload_length = new_l1;
 
@@ -293,13 +270,13 @@ geneve_encap_inline (vlib_main_t * vm,
              udp1->src_port = flow_hash1;
 
              /* IPv6 UDP checksum is mandatory */
-             udp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0,
+             udp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b[0],
                                                                  ip6_0,
                                                                  &bogus);
              ASSERT (bogus == 0);
              if (udp0->checksum == 0)
                udp0->checksum = 0xffff;
-             udp1->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b1,
+             udp1->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b[1],
                                                                  ip6_1,
                                                                  &bogus);
              ASSERT (bogus == 0);
@@ -308,11 +285,15 @@ geneve_encap_inline (vlib_main_t * vm,
            }
 
          pkts_encapsulated += 2;
-         len0 = vlib_buffer_length_in_chain (vm, b0);
-         len1 = vlib_buffer_length_in_chain (vm, b1);
+         len0 = vlib_buffer_length_in_chain (vm, b[0]);
+         len1 = vlib_buffer_length_in_chain (vm, b[1]);
          stats_n_packets += 2;
          stats_n_bytes += len0 + len1;
 
+         /* save inner packet flow_hash for load-balance node */
+         vnet_buffer (b[0])->ip.flow_hash = flow_hash0;
+         vnet_buffer (b[1])->ip.flow_hash = flow_hash1;
+
          /* Batch stats increment on the same geneve tunnel so counter is not
             incremented per packet. Note stats are still incremented for deleted
             and admin-down tunnel where packets are dropped. It is not worthwhile
@@ -344,21 +325,22 @@ geneve_encap_inline (vlib_main_t * vm,
                }
            }
 
-         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+         if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
            {
              geneve_encap_trace_t *tr =
-               vlib_add_trace (vm, node, b0, sizeof (*tr));
+               vlib_add_trace (vm, node, b[0], sizeof (*tr));
              tr->tunnel_index = t0 - vxm->tunnels;
              tr->vni = t0->vni;
            }
 
-         if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+         if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
            {
              geneve_encap_trace_t *tr =
-               vlib_add_trace (vm, node, b1, sizeof (*tr));
+               vlib_add_trace (vm, node, b[1], sizeof (*tr));
              tr->tunnel_index = t1 - vxm->tunnels;
              tr->vni = t1->vni;
            }
+         b += 2;
 
          vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
                                           to_next, n_left_to_next,
@@ -368,7 +350,6 @@ geneve_encap_inline (vlib_main_t * vm,
       while (n_left_from > 0 && n_left_to_next > 0)
        {
          u32 bi0;
-         vlib_buffer_t *b0;
          u32 flow_hash0;
          u32 len0;
          ip4_header_t *ip4_0;
@@ -386,23 +367,24 @@ geneve_encap_inline (vlib_main_t * vm,
          n_left_from -= 1;
          n_left_to_next -= 1;
 
-         b0 = vlib_get_buffer (vm, bi0);
-
-         flow_hash0 = vnet_l2_compute_flow_hash (b0);
+         flow_hash0 = vnet_l2_compute_flow_hash (b[0]);
 
          /* Get next node index and adj index from tunnel next_dpo */
-         if (sw_if_index0 != vnet_buffer (b0)->sw_if_index[VLIB_TX])
+         if (sw_if_index0 != vnet_buffer (b[0])->sw_if_index[VLIB_TX])
            {
-             sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+             sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
              hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
              t0 = &vxm->tunnels[hi0->dev_instance];
              /* Note: change to always set next0 if it may be set to drop */
              next0 = t0->next_dpo.dpoi_next_node;
            }
-         vnet_buffer (b0)->ip.adj_index[VLIB_TX] = t0->next_dpo.dpoi_index;
+
+         ALWAYS_ASSERT (t0 != NULL);
+
+         vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = t0->next_dpo.dpoi_index;
 
          /* Apply the rewrite string. $$$$ vnet_rewrite? */
-         vlib_buffer_advance (b0, -(word) _vec_len (t0->rewrite));
+         vlib_buffer_advance (b[0], -(word) _vec_len (t0->rewrite));
 
          if (is_ip4)
            {
@@ -415,7 +397,7 @@ geneve_encap_inline (vlib_main_t * vm,
 #endif
              ASSERT (vec_len (t0->rewrite) == ip4_geneve_header_total_len0);
 
-             ip4_0 = vlib_buffer_get_current (b0);
+             ip4_0 = vlib_buffer_get_current (b[0]);
 
              /* Copy the fixed header */
              copy_dst0 = (u64 *) ip4_0;
@@ -432,7 +414,7 @@ geneve_encap_inline (vlib_main_t * vm,
              /* Fix the IP4 checksum and length */
              sum0 = ip4_0->checksum;
              new_l0 =          /* old_l0 always 0, see the rewrite setup */
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[0]));
              sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
                                     length /* changed member */ );
              ip4_0->checksum = ip_csum_fold (sum0);
@@ -441,7 +423,7 @@ geneve_encap_inline (vlib_main_t * vm,
              /* Fix UDP length and set source port */
              udp0 = (udp_header_t *) (ip4_0 + 1);
              new_l0 =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[0]) -
                                      sizeof (*ip4_0));
              udp0->length = new_l0;
              udp0->src_port = flow_hash0;
@@ -460,7 +442,7 @@ geneve_encap_inline (vlib_main_t * vm,
 #endif
              ASSERT (vec_len (t0->rewrite) == ip6_geneve_header_total_len0);
 
-             ip6_0 = vlib_buffer_get_current (b0);
+             ip6_0 = vlib_buffer_get_current (b[0]);
              /* Copy the fixed header */
              copy_dst0 = (u64 *) ip6_0;
              copy_src0 = (u64 *) t0->rewrite;
@@ -470,7 +452,7 @@ geneve_encap_inline (vlib_main_t * vm,
 #undef _
              /* Fix IP6 payload length */
              new_l0 =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
+               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b[0])
                                      - sizeof (*ip6_0));
              ip6_0->payload_length = new_l0;
 
@@ -480,7 +462,7 @@ geneve_encap_inline (vlib_main_t * vm,
              udp0->src_port = flow_hash0;
 
              /* IPv6 UDP checksum is mandatory */
-             udp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0,
+             udp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b[0],
                                                                  ip6_0,
                                                                  &bogus);
              ASSERT (bogus == 0);
@@ -489,10 +471,13 @@ geneve_encap_inline (vlib_main_t * vm,
            }
 
          pkts_encapsulated++;
-         len0 = vlib_buffer_length_in_chain (vm, b0);
+         len0 = vlib_buffer_length_in_chain (vm, b[0]);
          stats_n_packets += 1;
          stats_n_bytes += len0;
 
+         /* save inner packet flow_hash for load-balance node */
+         vnet_buffer (b[0])->ip.flow_hash = flow_hash0;
+
          /* Batch stats increment on the same geneve tunnel so counter is not
             incremented per packet. Note stats are still incremented for deleted
             and admin-down tunnel where packets are dropped. It is not worthwhile
@@ -511,13 +496,15 @@ geneve_encap_inline (vlib_main_t * vm,
              stats_sw_if_index = sw_if_index0;
            }
 
-         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+         if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
            {
              geneve_encap_trace_t *tr =
-               vlib_add_trace (vm, node, b0, sizeof (*tr));
+               vlib_add_trace (vm, node, b[0], sizeof (*tr));
              tr->tunnel_index = t0 - vxm->tunnels;
              tr->vni = t0->vni;
            }
+         b += 1;
+
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                           to_next, n_left_to_next,
                                           bi0, next0);
@@ -543,23 +530,22 @@ geneve_encap_inline (vlib_main_t * vm,
   return from_frame->n_vectors;
 }
 
-static uword
-geneve4_encap (vlib_main_t * vm,
-              vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+VLIB_NODE_FN (geneve4_encap_node) (vlib_main_t * vm,
+                                  vlib_node_runtime_t * node,
+                                  vlib_frame_t * from_frame)
 {
   return geneve_encap_inline (vm, node, from_frame, /* is_ip4 */ 1);
 }
 
-static uword
-geneve6_encap (vlib_main_t * vm,
-              vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+VLIB_NODE_FN (geneve6_encap_node) (vlib_main_t * vm,
+                                  vlib_node_runtime_t * node,
+                                  vlib_frame_t * from_frame)
 {
   return geneve_encap_inline (vm, node, from_frame, /* is_ip4 */ 0);
 }
 
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (geneve4_encap_node) = {
-  .function = geneve4_encap,
   .name = "geneve4-encap",
   .vector_size = sizeof (u32),
   .format_trace = format_geneve_encap_trace,
@@ -572,10 +558,7 @@ VLIB_REGISTER_NODE (geneve4_encap_node) = {
   },
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (geneve4_encap_node, geneve4_encap)
-
 VLIB_REGISTER_NODE (geneve6_encap_node) = {
-  .function = geneve6_encap,
   .name = "geneve6-encap",
   .vector_size = sizeof (u32),
   .format_trace = format_geneve_encap_trace,
@@ -587,8 +570,6 @@ VLIB_REGISTER_NODE (geneve6_encap_node) = {
         [GENEVE_ENCAP_NEXT_DROP] = "error-drop",
   },
 };
-
-VLIB_NODE_FUNCTION_MULTIARCH (geneve6_encap_node, geneve6_encap)
 /* *INDENT-ON* */
 
 /*