Add special Twice-NAT feature (VPP-1221)
[vpp.git] / src / plugins / nat / in2out.c
index 8b565b1..786b6c6 100755 (executable)
@@ -239,7 +239,7 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node,
                               &value0))
     {
       /* or is static mappings */
-      if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
+      if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
         return 0;
     }
   else
@@ -310,6 +310,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
   u32 outside_fib_index;
   uword * p;
   udp_header_t * udp0 = ip4_next_header (ip0);
+  u8 is_sm = 0;
 
   if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
     {
@@ -337,7 +338,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
     }
 
   /* First try to match static mapping by local address and port */
-  if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0))
+  if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0, 0))
     {
       /* Try to create dynamic translation */
       if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index0,
@@ -349,12 +350,9 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
           b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
           return SNAT_IN2OUT_NEXT_DROP;
         }
-      u->nsessions++;
     }
   else
-    {
-      u->nstaticsessions++;
-    }
+    is_sm = 1;
 
   s = nat_session_alloc_or_recycle (sm, u, thread_index);
   if (!s)
@@ -363,8 +361,9 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
       return SNAT_IN2OUT_NEXT_DROP;
     }
 
-  if (address_index == ~0)
+  if (is_sm)
     s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
+  user_session_increment (sm, u, is_sm);
   s->outside_address_index = address_index;
   s->in2out = *key0;
   s->out2in = key1;
@@ -491,11 +490,14 @@ icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
 }
 
 static inline int
-nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip)
+nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
+                                      u32 thread_index)
 {
   nat_ed_ses_key_t key;
   clib_bihash_kv_16_8_t kv, value;
   udp_header_t *udp;
+  snat_session_t *s = 0;
+  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
 
   if (!sm->forwarding_enabled)
     return 0;
@@ -526,7 +528,19 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip)
   kv.key[1] = key.as_u64[1];
 
   if (!clib_bihash_search_16_8 (&sm->in2out_ed, &kv, &value))
-    return value.value == ~0ULL;
+    {
+      s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value);
+      if (is_fwd_bypass_session (s))
+        {
+          /* Per-user LRU list maintenance */
+          clib_dlist_remove (tsm->list_pool, s->per_user_index);
+          clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
+                              s->per_user_index);
+          return 1;
+        }
+      else
+        return 0;
+    }
 
   return 0;
 }
@@ -704,7 +718,7 @@ u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node,
     }
   key0.fib_index = rx_fib_index0;
 
-  if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only, 0))
+  if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only, 0, 0))
     {
       if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
           IP_PROTOCOL_ICMP, rx_fib_index0)))
@@ -903,7 +917,7 @@ snat_hairpinning (snat_main_t *sm,
   kv0.key = key0.as_u64;
 
   /* Check if destination is static mappings */
-  if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
+  if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
     {
       new_dst_addr0 = sm0.addr.as_u32;
       new_dst_port0 = sm0.port;
@@ -1004,7 +1018,7 @@ snat_icmp_hairpinning (snat_main_t *sm,
                                   &value0))
         {
           /* or static mappings */
-          if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
+          if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
             {
               new_dst_addr0 = sm0.addr.as_u32;
               vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
@@ -1259,6 +1273,7 @@ create_ses:
 
       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
+      s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
       s->outside_address_index = address_index;
       s->out2in.addr.as_u32 = new_addr;
       s->out2in.fib_index = sm->outside_fib_index;
@@ -1266,14 +1281,8 @@ create_ses:
       s->in2out.fib_index = rx_fib_index;
       s->in2out.port = s->out2in.port = ip->protocol;
       if (is_sm)
-        {
-          u->nstaticsessions++;
-          s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
-        }
-      else
-        {
-          u->nsessions++;
-        }
+       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
+      user_session_increment (sm, u, is_sm);
 
       /* Add to lookup tables */
       key.l_addr.as_u32 = old_addr;
@@ -1340,6 +1349,7 @@ snat_in2out_lb (snat_main_t *sm,
   u32 proto = ip_proto_to_snat_proto (ip->protocol);
   snat_session_key_t e_key, l_key;
   snat_user_t *u;
+  u8 lb;
 
   old_addr = ip->src_address.as_u32;
 
@@ -1354,9 +1364,9 @@ snat_in2out_lb (snat_main_t *sm,
 
   if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value))
     {
-      if (s_value.value == ~0ULL)
-        return 0;
       s = pool_elt_at_index (tsm->sessions, s_value.value);
+      if (is_fwd_bypass_session (s))
+        return 0;
     }
   else
     {
@@ -1371,7 +1381,7 @@ snat_in2out_lb (snat_main_t *sm,
       l_key.port = udp->src_port;
       l_key.protocol = proto;
       l_key.fib_index = rx_fib_index;
-      if (snat_static_mapping_match(sm, l_key, &e_key, 0, 0, 0))
+      if (snat_static_mapping_match(sm, l_key, &e_key, 0, 0, 0, &lb))
         return 0;
 
       u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
@@ -1391,12 +1401,14 @@ snat_in2out_lb (snat_main_t *sm,
 
       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
-      s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
+      if (lb)
+        s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
+      s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
       s->outside_address_index = ~0;
       s->in2out = l_key;
       s->out2in = e_key;
       s->out2in.protocol = l_key.protocol;
-      u->nstaticsessions++;
+      user_session_increment (sm, u, 1 /* static */);
 
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
@@ -1593,7 +1605,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
             {
               if (is_output_feature)
                 {
-                  if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0)))
+                  if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0, thread_index)))
                     goto trace00;
                 }
 
@@ -1785,7 +1797,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
             {
               if (is_output_feature)
                 {
-                  if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip1)))
+                  if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip1, thread_index)))
                     goto trace01;
                 }
 
@@ -2013,7 +2025,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
             {
                if (is_output_feature)
                 {
-                  if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0)))
+                  if (PREDICT_FALSE(nat_not_translate_output_feature_fwd(sm, ip0, thread_index)))
                     goto trace0;
                 }
 
@@ -2427,7 +2439,7 @@ nat44_reass_hairpinning (snat_main_t *sm,
   udp0 = ip4_next_header (ip0);
 
   /* Check if destination is static mappings */
-  if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0))
+  if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
     {
       new_dst_addr0 = sm0.addr.as_u32;
       new_dst_port0 = sm0.port;
@@ -4036,7 +4048,7 @@ snat_in2out_fast_static_map_fn (vlib_main_t * vm,
           key0.port = udp0->src_port;
           key0.fib_index = rx_fib_index0;
 
-          if (snat_static_mapping_match(sm, key0, &sm0, 0, 0, 0))
+          if (snat_static_mapping_match(sm, key0, &sm0, 0, 0, 0, 0))
             {
               b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
               next0= SNAT_IN2OUT_NEXT_DROP;