NAT44: fix setting of flag SNAT_SESSION_FLAG_LOAD_BALANCING (VPP-1235)
[vpp.git] / src / plugins / nat / out2in.c
index f6d6a0a..a626bf5 100755 (executable)
@@ -133,6 +133,7 @@ typedef enum {
   SNAT_OUT2IN_NEXT_LOOKUP,
   SNAT_OUT2IN_NEXT_ICMP_ERROR,
   SNAT_OUT2IN_NEXT_REASS,
+  SNAT_OUT2IN_NEXT_IN2OUT,
   SNAT_OUT2IN_N_NEXT,
 } snat_out2in_next_t;
 
@@ -191,7 +192,7 @@ create_session_for_static_mapping (snat_main_t *sm,
   s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
   s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
   s->ext_host_port = udp0->src_port;
-  u->nstaticsessions++;
+  user_session_increment (sm, u, 1 /* static */);
   s->in2out = in2out;
   s->out2in = out2in;
   s->in2out.protocol = out2in.protocol;
@@ -311,6 +312,26 @@ icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
   return 0;
 }
 
+static int
+next_src_nat (snat_main_t * sm, ip4_header_t * ip, u32 proto, u16 src_port,
+              u32 thread_index)
+{
+  snat_session_key_t key;
+  clib_bihash_kv_8_8_t kv, value;
+
+  key.addr = ip->src_address;
+  key.port = src_port;
+  key.protocol = proto;
+  key.fib_index = sm->inside_fib_index;
+  kv.key = key.as_u64;
+
+  if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv,
+                               &value))
+    return 1;
+
+  return 0;
+}
+
 static void
 create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip)
 {
@@ -402,7 +423,7 @@ u32 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))
+      if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0))
         {
           if (!sm->forwarding_enabled)
             {
@@ -419,8 +440,13 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node,
             }
           else
             {
-              create_bypass_for_fwd(sm, ip0);
               dont_translate = 1;
+              if (next_src_nat(sm, ip0, key0.protocol, key0.port, thread_index))
+                {
+                  next0 = SNAT_OUT2IN_NEXT_IN2OUT;
+                  goto out;
+                }
+              create_bypass_for_fwd(sm, ip0);
               goto out;
             }
         }
@@ -536,7 +562,7 @@ u32 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))
+  if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 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))
@@ -618,6 +644,9 @@ static inline u32 icmp_out2in (snat_main_t *sm,
                          dst_address /* changed member */);
   ip0->checksum = ip_csum_fold (sum0);
 
+  if (icmp0->checksum == 0)
+    icmp0->checksum = 0xffff;
+
   if (!icmp_is_error_message (icmp0))
     {
       new_id0 = sm0.port;
@@ -804,7 +833,7 @@ snat_out2in_unknown_proto (snat_main_t *sm,
       s->in2out.addr.as_u32 = new_addr;
       s->in2out.fib_index = m->fib_index;
       s->in2out.port = s->out2in.port = ip->protocol;
-      u->nstaticsessions++;
+      user_session_increment (sm, u, 1 /* static */);
 
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
@@ -862,7 +891,7 @@ snat_out2in_lb (snat_main_t *sm,
   snat_user_t *u;
   u32 address_index;
   snat_session_key_t eh_key;
-  u8 twice_nat;
+  u8 twice_nat, lb;
 
   old_addr = ip->dst_address.as_u32;
 
@@ -891,7 +920,7 @@ snat_out2in_lb (snat_main_t *sm,
       e_key.port = udp->dst_port;
       e_key.protocol = proto;
       e_key.fib_index = rx_fib_index;
-      if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0, &twice_nat))
+      if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0, &twice_nat, &lb))
         return 0;
 
       u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index,
@@ -912,11 +941,12 @@ snat_out2in_lb (snat_main_t *sm,
       s->ext_host_addr.as_u32 = ip->src_address.as_u32;
       s->ext_host_port = udp->src_port;
       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
-      s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
+      if (lb)
+        s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
       s->outside_address_index = ~0;
       s->out2in = e_key;
       s->in2out = l_key;
-      u->nstaticsessions++;
+      user_session_increment (sm, u, 1 /* static */);
 
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
@@ -1135,7 +1165,7 @@ 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))
+              if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
                 {
                   if (!sm->forwarding_enabled)
                     {
@@ -1156,6 +1186,11 @@ snat_out2in_node_fn (vlib_main_t * vm,
                     }
                   else
                     {
+                      if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
+                        {
+                          next0 = SNAT_OUT2IN_NEXT_IN2OUT;
+                          goto trace0;
+                        }
                       create_bypass_for_fwd(sm, ip0);
                       goto trace0;
                     }
@@ -1306,7 +1341,7 @@ 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))
+              if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0, 0))
                 {
                   if (!sm->forwarding_enabled)
                     {
@@ -1327,6 +1362,11 @@ snat_out2in_node_fn (vlib_main_t * vm,
                     }
                   else
                     {
+                      if (next_src_nat(sm, ip1, proto1, udp1->src_port, thread_index))
+                        {
+                          next1 = SNAT_OUT2IN_NEXT_IN2OUT;
+                          goto trace1;
+                        }
                       create_bypass_for_fwd(sm, ip1);
                       goto trace1;
                     }
@@ -1513,7 +1553,7 @@ 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))
+              if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
                 {
                   if (!sm->forwarding_enabled)
                     {
@@ -1534,6 +1574,11 @@ snat_out2in_node_fn (vlib_main_t * vm,
                     }
                   else
                     {
+                      if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
+                        {
+                          next0 = SNAT_OUT2IN_NEXT_IN2OUT;
+                          goto trace00;
+                        }
                       create_bypass_for_fwd(sm, ip0);
                       goto trace00;
                     }
@@ -1661,6 +1706,7 @@ VLIB_REGISTER_NODE (snat_out2in_node) = {
     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
+    [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
   },
 };
 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
@@ -1760,7 +1806,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))
+                  if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
                     {
                       if (!sm->forwarding_enabled)
                         {
@@ -1781,6 +1827,11 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
                         }
                       else
                         {
+                          if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
+                            {
+                              next0 = SNAT_OUT2IN_NEXT_IN2OUT;
+                              goto trace0;
+                            }
                           create_bypass_for_fwd(sm, ip0);
                           goto trace0;
                         }
@@ -1952,6 +2003,7 @@ VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
+    [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
   },
 };
 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
@@ -2441,6 +2493,7 @@ VLIB_REGISTER_NODE (snat_det_out2in_node) = {
     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
+    [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
   },
 };
 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn);
@@ -2831,7 +2884,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))
+          if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
             {
               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace00;
@@ -2934,6 +2987,7 @@ VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
+    [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
   },
 };
 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);