GBP: redirect contracts
[vpp.git] / src / plugins / nat / out2in.c
index 985333f..9cace08 100755 (executable)
@@ -309,6 +309,7 @@ icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node,
   u8 is_addr_only;
   u32 next0 = ~0;
   int err;
+  u8 identity_nat;
 
   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
@@ -333,7 +334,7 @@ icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node,
       /* Try to match static mapping by external address and port,
          destination address and port in packet */
       if (snat_static_mapping_match
-         (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
+         (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, &identity_nat))
        {
          if (!sm->forwarding_enabled)
            {
@@ -364,6 +365,11 @@ icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node,
          goto out;
        }
 
+      if (PREDICT_FALSE (identity_nat))
+       {
+         dont_translate = 1;
+         goto out;
+       }
       /* Create session initiated by host from external network */
       s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
                                              node, thread_index,
@@ -443,7 +449,8 @@ icmp_match_out2in_fast (snat_main_t * sm, vlib_node_runtime_t * node,
     }
   key0.fib_index = rx_fib_index0;
 
-  if (snat_static_mapping_match (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
+  if (snat_static_mapping_match
+      (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, 0))
     {
       /* Don't NAT packet aimed at the intfc address */
       if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
@@ -508,9 +515,11 @@ icmp_out2in (snat_main_t * sm,
 
   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
     {
-      sum0 = ip_incremental_checksum (0, icmp0,
-                                     ntohs (ip0->length) -
-                                     ip4_header_bytes (ip0));
+      sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
+                                            (u8 *)
+                                            vlib_buffer_get_current (b0),
+                                            ntohs (ip0->length) -
+                                            ip4_header_bytes (ip0), 0);
       checksum0 = ~ip_csum_fold (sum0);
       if (checksum0 != 0 && checksum0 != 0xffff)
        {
@@ -701,6 +710,7 @@ snat_out2in_node_fn (vlib_main_t * vm,
          u32 proto0, proto1;
          snat_session_t *s0 = 0, *s1 = 0;
          clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
+         u8 identity_nat0, identity_nat1;
 
          /* Prefetch next iteration. */
          {
@@ -765,17 +775,17 @@ snat_out2in_node_fn (vlib_main_t * vm,
              goto trace0;
            }
 
-         if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
+         if (PREDICT_FALSE (ip4_is_fragment (ip0)))
            {
-             next0 = icmp_out2in_slow_path
-               (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-                next0, now, thread_index, &s0);
+             next0 = SNAT_OUT2IN_NEXT_REASS;
              goto trace0;
            }
 
-         if (PREDICT_FALSE (ip4_is_fragment (ip0)))
+         if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
            {
-             next0 = SNAT_OUT2IN_NEXT_REASS;
+             next0 = icmp_out2in_slow_path
+               (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
+                next0, now, thread_index, &s0);
              goto trace0;
            }
 
@@ -791,7 +801,8 @@ snat_out2in_node_fn (vlib_main_t * vm,
            {
              /* Try to match static mapping by external address and port,
                 destination address and port in packet */
-             if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+             if (snat_static_mapping_match
+                 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
                {
                  /*
                   * Send DHCP packets to the ipv4 stack, or we won't
@@ -815,6 +826,9 @@ snat_out2in_node_fn (vlib_main_t * vm,
                  goto trace0;
                }
 
+             if (PREDICT_FALSE (identity_nat0))
+               goto trace0;
+
              /* Create session initiated by host from external network */
              s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
                                                      thread_index, now);
@@ -922,17 +936,17 @@ snat_out2in_node_fn (vlib_main_t * vm,
              goto trace1;
            }
 
-         if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
+         if (PREDICT_FALSE (ip4_is_fragment (ip1)))
            {
-             next1 = icmp_out2in_slow_path
-               (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
-                next1, now, thread_index, &s1);
+             next1 = SNAT_OUT2IN_NEXT_REASS;
              goto trace1;
            }
 
-         if (PREDICT_FALSE (ip4_is_fragment (ip1)))
+         if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
            {
-             next1 = SNAT_OUT2IN_NEXT_REASS;
+             next1 = icmp_out2in_slow_path
+               (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
+                next1, now, thread_index, &s1);
              goto trace1;
            }
 
@@ -948,7 +962,8 @@ snat_out2in_node_fn (vlib_main_t * vm,
            {
              /* Try to match static mapping by external address and port,
                 destination address and port in packet */
-             if (snat_static_mapping_match (sm, key1, &sm1, 1, 0, 0, 0, 0))
+             if (snat_static_mapping_match
+                 (sm, key1, &sm1, 1, 0, 0, 0, 0, &identity_nat1))
                {
                  /*
                   * Send DHCP packets to the ipv4 stack, or we won't
@@ -972,6 +987,9 @@ snat_out2in_node_fn (vlib_main_t * vm,
                  goto trace1;
                }
 
+             if (PREDICT_FALSE (identity_nat1))
+               goto trace1;
+
              /* Create session initiated by host from external network */
              s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
                                                      thread_index, now);
@@ -1067,6 +1085,7 @@ snat_out2in_node_fn (vlib_main_t * vm,
          u32 proto0;
          snat_session_t *s0 = 0;
          clib_bihash_kv_8_8_t kv0, value0;
+         u8 identity_nat0;
 
          /* speculatively enqueue b0 to the current next frame */
          bi0 = from[0];
@@ -1115,17 +1134,17 @@ snat_out2in_node_fn (vlib_main_t * vm,
              goto trace00;
            }
 
-         if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
+         if (PREDICT_FALSE (ip4_is_fragment (ip0)))
            {
-             next0 = icmp_out2in_slow_path
-               (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-                next0, now, thread_index, &s0);
+             next0 = SNAT_OUT2IN_NEXT_REASS;
              goto trace00;
            }
 
-         if (PREDICT_FALSE (ip4_is_fragment (ip0)))
+         if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
            {
-             next0 = SNAT_OUT2IN_NEXT_REASS;
+             next0 = icmp_out2in_slow_path
+               (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
+                next0, now, thread_index, &s0);
              goto trace00;
            }
 
@@ -1141,7 +1160,8 @@ snat_out2in_node_fn (vlib_main_t * vm,
            {
              /* Try to match static mapping by external address and port,
                 destination address and port in packet */
-             if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+             if (snat_static_mapping_match
+                 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
                {
                  /*
                   * Send DHCP packets to the ipv4 stack, or we won't
@@ -1165,6 +1185,9 @@ snat_out2in_node_fn (vlib_main_t * vm,
                  goto trace00;
                }
 
+             if (PREDICT_FALSE (identity_nat0))
+               goto trace00;
+
              /* Create session initiated by host from external network */
              s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
                                                      thread_index, now);
@@ -1313,11 +1336,13 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
          nat_reass_ip4_t *reass0;
          udp_header_t *udp0;
          tcp_header_t *tcp0;
+         icmp46_header_t *icmp0;
          snat_session_key_t key0, sm0;
          clib_bihash_kv_8_8_t kv0, value0;
          snat_session_t *s0 = 0;
          u16 old_port0, new_port0;
          ip_csum_t sum0;
+         u8 identity_nat0;
 
          /* speculatively enqueue b0 to the current next frame */
          bi0 = from[0];
@@ -1345,6 +1370,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
          ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
          udp0 = ip4_next_header (ip0);
          tcp0 = (tcp_header_t *) udp0;
+         icmp0 = (icmp46_header_t *) udp0;
          proto0 = ip_proto_to_snat_proto (ip0->protocol);
 
          reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
@@ -1363,6 +1389,26 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
 
          if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
            {
+             if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
+               {
+                 next0 = icmp_out2in_slow_path
+                   (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
+                    next0, now, thread_index, &s0);
+
+                 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP))
+                   {
+                     if (s0)
+                       reass0->sess_index = s0 - per_thread_data->sessions;
+                     else
+                       reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
+                     reass0->thread_index = thread_index;
+                     nat_ip4_reass_get_frags (reass0,
+                                              &fragments_to_loopback);
+                   }
+
+                 goto trace0;
+               }
+
              key0.addr = ip0->dst_address;
              key0.port = udp0->dst_port;
              key0.protocol = proto0;
@@ -1375,7 +1421,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
                  /* Try to match static mapping by external address and port,
                     destination address and port in packet */
                  if (snat_static_mapping_match
-                     (sm, key0, &sm0, 1, 0, 0, 0, 0))
+                     (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
                    {
                      /*
                       * Send DHCP packets to the ipv4 stack, or we won't
@@ -1400,6 +1446,9 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
                      goto trace0;
                    }
 
+                 if (PREDICT_FALSE (identity_nat0))
+                   goto trace0;
+
                  /* Create session initiated by host from external network */
                  s0 =
                    create_session_for_static_mapping (sm, b0, sm0, key0,
@@ -1519,17 +1568,16 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
              u32 len = vec_len (fragments_to_loopback);
              if (len <= VLIB_FRAME_SIZE)
                {
-                 clib_memcpy (from, fragments_to_loopback,
-                              sizeof (u32) * len);
+                 clib_memcpy_fast (from, fragments_to_loopback,
+                                   sizeof (u32) * len);
                  n_left_from = len;
                  vec_reset_length (fragments_to_loopback);
                }
              else
                {
-                 clib_memcpy (from,
-                              fragments_to_loopback + (len -
-                                                       VLIB_FRAME_SIZE),
-                              sizeof (u32) * VLIB_FRAME_SIZE);
+                 clib_memcpy_fast (from, fragments_to_loopback +
+                                   (len - VLIB_FRAME_SIZE),
+                                   sizeof (u32) * VLIB_FRAME_SIZE);
                  n_left_from = VLIB_FRAME_SIZE;
                  _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
                }
@@ -1661,7 +1709,7 @@ snat_out2in_fast_node_fn (vlib_main_t * vm,
          key0.port = udp0->dst_port;
          key0.fib_index = rx_fib_index0;
 
-         if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+         if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
            {
              b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
              goto trace00;