nat: transitory timeout for TCP CLOSED state
[vpp.git] / src / plugins / nat / out2in_ed.c
index fbb7d06..6943614 100644 (file)
@@ -414,7 +414,8 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
     {
       tcp_header_t *tcp = ip4_next_header (ip);
       if (nat44_set_tcp_session_state_o2i
-         (sm, s, tcp->flags, tcp->ack_number, tcp->seq_number, thread_index))
+         (sm, now, s, tcp->flags, tcp->ack_number, tcp->seq_number,
+          thread_index))
        return;
     }
 
@@ -682,6 +683,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
   u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
     0, fragments = 0;
+  u32 tcp_closed_drops = 0;
 
   stats_node_index = sm->ed_out2in_node_index;
 
@@ -766,6 +768,23 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
            }
          s0 = pool_elt_at_index (tsm->sessions, value0.value);
 
+         if (s0->tcp_close_timestamp)
+           {
+             if (now >= s0->tcp_close_timestamp)
+               {
+                 // session is closed, go slow path
+                 next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
+               }
+             else
+               {
+                 // session in transitory timeout, drop
+                 b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TCP_CLOSED];
+                 ++tcp_closed_drops;
+                 next0 = NAT_NEXT_DROP;
+               }
+             goto trace0;
+           }
+
          // drop if session expired
          u64 sess_timeout_time;
          sess_timeout_time = s0->last_heard +
@@ -827,7 +846,8 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
                }
              tcp_packets++;
              if (nat44_set_tcp_session_state_o2i
-                 (sm, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
+                 (sm, now, s0,
+                  vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
                   vnet_buffer (b0)->ip.reass.tcp_ack_number,
                   vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index))
                goto trace0;
@@ -1029,7 +1049,20 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
                      vnet_buffer (b0)->ip.reass.l4_dst_port,
                      vnet_buffer (b0)->ip.reass.l4_src_port);
 
-         if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
+         s0 = NULL;
+         if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
+           {
+             s0 = pool_elt_at_index (tsm->sessions, value0.value);
+
+             if (s0->tcp_close_timestamp && now >= s0->tcp_close_timestamp)
+               {
+                 nat_free_session_data (sm, s0, thread_index, 0);
+                 nat44_delete_session (sm, s0, thread_index);
+                 s0 = NULL;
+               }
+           }
+
+         if (!s0)
            {
              /* Try to match static mapping by external address and port,
                 destination address and port in packet */
@@ -1108,10 +1141,6 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
                  goto trace0;
                }
            }
-         else
-           {
-             s0 = pool_elt_at_index (tsm->sessions, value0.value);
-           }
 
          old_addr0 = ip0->dst_address.as_u32;
          new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
@@ -1158,7 +1187,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
                }
              tcp_packets++;
              if (nat44_set_tcp_session_state_o2i
-                 (sm, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
+                 (sm, now, s0,
+                  vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
                   vnet_buffer (b0)->ip.reass.tcp_ack_number,
                   vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index))
                goto trace0;