NAT44: nat44_del_session and nat44_user_session_details API update (VPP-1271) 69/12569/4
authorMatus Fabian <matfabia@cisco.com>
Mon, 14 May 2018 13:20:28 +0000 (06:20 -0700)
committerMatus Fabian <matfabia@cisco.com>
Thu, 17 May 2018 08:06:17 +0000 (01:06 -0700)
Change-Id: I484d79000c1bbd87ff83847cf567bf3414a719d3
Signed-off-by: Matus Fabian <matfabia@cisco.com>
src/plugins/nat/in2out.c
src/plugins/nat/nat.api
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44_cli.c
src/plugins/nat/nat_api.c
src/plugins/nat/out2in.c
test/test_nat.py
test/vpp_papi_provider.py

index 4a0d265..1659ed0 100755 (executable)
@@ -498,6 +498,7 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
   udp_header_t *udp;
   snat_session_t *s = 0;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  f64 now = vlib_time_now (sm->vlib_main);
 
   if (!sm->forwarding_enabled)
     return 0;
@@ -535,13 +536,16 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
           if (ip->protocol == IP_PROTOCOL_TCP)
             {
               tcp_header_t *tcp = ip4_next_header(ip);
-              if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+              if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
                 return 1;
             }
           /* 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);
+          /* Accounting */
+          s->last_heard = now;
+          s->total_pkts++;
           return 1;
         }
       else
@@ -1378,7 +1382,7 @@ snat_in2out_lb (snat_main_t *sm,
         {
           if (ip->protocol == IP_PROTOCOL_TCP)
             {
-              if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+              if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
                 return 0;
             }
           /* Per-user LRU list maintenance */
@@ -1477,7 +1481,7 @@ snat_in2out_lb (snat_main_t *sm,
           ip->dst_address.as_u32 = s->ext_host_addr.as_u32;
         }
       tcp->checksum = ip_csum_fold(sum);
-      if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+      if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
         return s;
     }
   else
@@ -1734,8 +1738,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                                      ip4_header_t /* cheat */,
                                      length /* changed member */);
               tcp0->checksum = ip_csum_fold(sum0);
-              if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
-                goto trace00;
             }
           else
             {
@@ -1928,8 +1930,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                                      ip4_header_t /* cheat */,
                                      length /* changed member */);
               tcp1->checksum = ip_csum_fold(sum1);
-              if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index))
-                goto trace01;
             }
           else
             {
@@ -2159,8 +2159,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                                      ip4_header_t /* cheat */,
                                      length /* changed member */);
               tcp0->checksum = ip_csum_fold(sum0);
-              if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
-                goto trace0;
             }
           else
             {
@@ -2677,10 +2675,6 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
                                  src_address /* changed member */);
           ip0->checksum = ip_csum_fold (sum0);
 
-          /* Hairpinning */
-          nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
-                                   s0->ext_host_port, proto0);
-
           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
             {
               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
@@ -2697,8 +2691,6 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
                                          ip4_header_t /* cheat */,
                                          length /* changed member */);
                   tcp0->checksum = ip_csum_fold(sum0);
-                  if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
-                    goto trace0;
                 }
               else
                 {
@@ -2708,6 +2700,10 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
                 }
             }
 
+          /* Hairpinning */
+          nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
+                                   s0->ext_host_port, proto0);
+
           /* Accounting */
           s0->last_heard = now;
           s0->total_pkts++;
index 24aa5d1..4192cf1 100644 (file)
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-option version = "2.5.0";
+option version = "2.6.0";
 
 /**
  * @file nat.api
@@ -558,7 +558,14 @@ define nat44_user_session_dump {
     @param last_heard - last heard timer
     @param total_bytes - count of bytes sent through session
     @param total_pkts - count of pakets sent through session
-    @param is_closed - 1 if TCP session is closed
+    @param is_twicenat - 1 if session is twice-nat
+    @param ext_host_valid - 1 if external host address and port are valid
+    @param ext_host_address - external host IPv4 address
+    @param ext_host_port - external host port
+    @param ext_host_nat_address - post-NAT external host IPv4 address (valid
+                                  only if twice-nat session)
+    @param ext_host_nat_port - post-NAT external host port (valid only if
+                               twice-nat session)
 */
 define nat44_user_session_details {
   u32 context;
@@ -571,7 +578,12 @@ define nat44_user_session_details {
   u64 last_heard;
   u64 total_bytes;
   u32 total_pkts;
-  u8 is_closed;
+  u8 is_twicenat;
+  u8 ext_host_valid;
+  u8 ext_host_address[4];
+  u16 ext_host_port;
+  u8 ext_host_nat_address[4];
+  u16 ext_host_nat_port;
 };
 
 /** \brief NAT44 load-balancing address and port pair
@@ -665,6 +677,9 @@ manual_endian define nat44_lb_static_mapping_details {
     @param protocol - IP protocol
     @param port - port number
     @param vfr_id - VRF ID
+    @param ext_host_valid - 1 if external host address and port are valid
+    @param ext_host_address - external host IPv4 address
+    @param ext_host_port - external host port
 */
 autoreply define nat44_del_session {
   u32 client_index;
@@ -674,6 +689,9 @@ autoreply define nat44_del_session {
   u8 protocol;
   u16 port;
   u32 vrf_id;
+  u8 ext_host_valid;
+  u8 ext_host_address[4];
+  u16 ext_host_port;
 };
 
 /** \brief Enable/disable forwarding for NAT44
index 4f9b04a..ae34f23 100755 (executable)
@@ -162,8 +162,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
       ed_key.fib_index = 0;
       ed_kv.key[0] = ed_key.as_u64[0];
       ed_kv.key[1] = ed_key.as_u64[1];
-      if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) &&
-          s->state != SNAT_SESSION_TCP_CLOSED)
+      if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
         clib_warning ("in2out_ed key del failed");
       return;
     }
@@ -188,8 +187,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
         }
       ed_kv.key[0] = ed_key.as_u64[0];
       ed_kv.key[1] = ed_key.as_u64[1];
-      if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0) &&
-          s->state != SNAT_SESSION_TCP_CLOSED)
+      if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
         clib_warning ("out2in_ed key del failed");
 
       ed_key.l_addr = s->in2out.addr;
@@ -203,8 +201,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
         }
       ed_kv.key[0] = ed_key.as_u64[0];
       ed_kv.key[1] = ed_key.as_u64[1];
-      if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) &&
-          s->state != SNAT_SESSION_TCP_CLOSED)
+      if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
         clib_warning ("in2out_ed key del failed");
     }
 
@@ -220,7 +217,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
                                       s->in2out.fib_index);
 
   /* Twice NAT address and port for external host */
-  if (is_twice_nat_session (s) && s->state != SNAT_SESSION_TCP_CLOSED)
+  if (is_twice_nat_session (s))
     {
       for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
         {
@@ -241,18 +238,16 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
 
   /* Session lookup tables */
   kv.key = s->in2out.as_u64;
-  if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0) &&
-      s->state != SNAT_SESSION_TCP_CLOSED)
+  if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
     clib_warning ("in2out key del failed");
   kv.key = s->out2in.as_u64;
-  if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0) &&
-      s->state != SNAT_SESSION_TCP_CLOSED)
+  if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
     clib_warning ("out2in key del failed");
 
   if (snat_is_session_static (s))
     return;
 
-  if (s->outside_address_index != ~0 && s->state != SNAT_SESSION_TCP_CLOSED)
+  if (s->outside_address_index != ~0)
     snat_free_outside_address_and_port (sm->addresses, thread_index,
                                         &s->out2in, s->outside_address_index);
 }
@@ -931,7 +926,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
         clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
       if (twice_nat || out2in_only)
         {
-          m_key.port = clib_host_to_net_u16 (l_port);
+          m_key.port = clib_host_to_net_u16 (m->local_port);
           kv.key = m_key.as_u64;
           kv.value = ~0ULL;
           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
@@ -979,7 +974,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       if (snat_is_session_static (s))
                         continue;
 
-                      if (!addr_only && (clib_net_to_host_u16 (s->out2in.port) != m->local_port))
+                      if (!addr_only && (clib_net_to_host_u16 (s->in2out.port) != m->local_port))
                         continue;
 
                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
@@ -1067,7 +1062,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
           kv.key = m_key.as_u64;
           kv.value = ~0ULL;
           if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
-            clib_warning ("in2out key del failed");
+            clib_warning ("out2in key del failed");
         }
 
       /* Delete session(s) for static mapping if exist */
@@ -1104,6 +1099,9 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       if (is_lb_session (s))
                         continue;
 
+                      if (!snat_is_session_static (s))
+                        continue;
+
                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
                       pool_put_index (tsm->list_pool, s->per_user_index);
@@ -1527,7 +1525,10 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
                 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
                   {
                     u = pool_elt_at_index (tsm->users, value.value);
-                    u->nsessions--;
+                    if (snat_is_session_static (ses))
+                      u->nstaticsessions--;
+                    else
+                      u->nsessions--;
                   }
               }
           }));
@@ -2695,33 +2696,33 @@ u8 * format_snat_session (u8 * s, va_list * args)
       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
     }
-  if (is_twice_nat_session (sess))
+  if (is_ed_session (sess) || is_fwd_bypass_session (sess))
     {
-      s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
-                  format_ip4_address, &sess->ext_host_addr,
-                  clib_net_to_host_u16 (sess->ext_host_port),
-                  format_ip4_address, &sess->ext_host_nat_addr,
-                  clib_net_to_host_u16 (sess->ext_host_nat_port));
-    }
-  else
-    {
-      if (sess->ext_host_addr.as_u32)
-          s = format (s, "       external host %U:%u\n",
+      if (is_twice_nat_session (sess))
+        {
+          s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
                       format_ip4_address, &sess->ext_host_addr,
-                      clib_net_to_host_u16 (sess->ext_host_port));
+                      clib_net_to_host_u16 (sess->ext_host_port),
+                      format_ip4_address, &sess->ext_host_nat_addr,
+                      clib_net_to_host_u16 (sess->ext_host_nat_port));
+        }
+      else
+        {
+          if (sess->ext_host_addr.as_u32)
+              s = format (s, "       external host %U:%u\n",
+                          format_ip4_address, &sess->ext_host_addr,
+                          clib_net_to_host_u16 (sess->ext_host_port));
+        }
     }
   s = format (s, "       last heard %.2f\n", sess->last_heard);
   s = format (s, "       total pkts %d, total bytes %lld\n",
               sess->total_pkts, sess->total_bytes);
-  if (sess->in2out.protocol == SNAT_PROTOCOL_TCP)
-    {
-      s = format (s, "       state %s\n",
-                  sess->state == SNAT_SESSION_TCP_CLOSED ? "closed" : "open");
-    }
   if (snat_is_session_static (sess))
     s = format (s, "       static translation\n");
   else
     s = format (s, "       dynamic translation\n");
+  if (is_fwd_bypass_session (sess))
+    s = format (s, "       forwarding-bypass\n");
   if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
     s = format (s, "       load-balancing\n");
   if (is_twice_nat_session (sess))
@@ -3110,6 +3111,9 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
   t = is_in ? &tsm->in2out : &tsm->out2in;
   if (!clib_bihash_search_8_8 (t, &kv, &value))
     {
+      if (pool_is_free_index (tsm->sessions, value.value))
+        return VNET_API_ERROR_UNSPECIFIED;
+
       s = pool_elt_at_index (tsm->sessions, value.value);
       kv.key = s->in2out.as_u64;
       clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
@@ -3121,9 +3125,13 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
         {
           u = pool_elt_at_index (tsm->users, value.value);
-          u->nsessions--;
+          if (snat_is_session_static (s))
+            u->nstaticsessions--;
+          else
+            u->nsessions--;
         }
       clib_dlist_remove (tsm->list_pool, s->per_user_index);
+      pool_put_index (tsm->list_pool, s->per_user_index);
       pool_put (tsm->sessions, s);
       return 0;
     }
@@ -3131,6 +3139,45 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
   return VNET_API_ERROR_NO_SUCH_ENTRY;
 }
 
+int
+nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
+                      ip4_address_t *eh_addr, u16 eh_port, u8 proto,
+                      u32 vrf_id, int is_in)
+{
+  ip4_header_t ip;
+  clib_bihash_16_8_t *t;
+  nat_ed_ses_key_t key;
+  clib_bihash_kv_16_8_t kv, value;
+  u32 thread_index;
+  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+  snat_session_t *s;
+
+  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
+  if (sm->num_workers > 1)
+    thread_index = sm->worker_in2out_cb (&ip, fib_index);
+  else
+    thread_index = sm->num_workers;
+
+  t = is_in ? &sm->in2out_ed : &sm->out2in_ed;
+  key.l_addr.as_u32 = addr->as_u32;
+  key.r_addr.as_u32 = eh_addr->as_u32;
+  key.l_port = clib_host_to_net_u16 (port);
+  key.r_port = clib_host_to_net_u16 (eh_port);
+  key.proto = proto;
+  key.fib_index = clib_host_to_net_u32 (fib_index);
+  kv.key[0] = key.as_u64[0];
+  kv.key[1] = key.as_u64[1];
+  if (clib_bihash_search_16_8 (t, &kv, &value))
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+  if (pool_is_free_index (sm->per_thread_data[thread_index].sessions, value.value))
+    return VNET_API_ERROR_UNSPECIFIED;
+  s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value);
+  nat_free_session_data (sm, s, thread_index);
+  nat44_delete_session (sm, s, thread_index);
+  return 0;
+}
+
 void
 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
 {
index 78b7962..f889976 100644 (file)
@@ -126,6 +126,12 @@ typedef enum {
 #undef _
 } snat_session_state_t;
 
+#define NAT44_SES_I2O_FIN 1
+#define NAT44_SES_O2I_FIN 2
+#define NAT44_SES_I2O_FIN_ACK 4
+#define NAT44_SES_O2I_FIN_ACK 8
+
+#define nat44_is_ses_closed(s) (s->state == 0xf)
 
 #define SNAT_SESSION_FLAG_STATIC_MAPPING       1
 #define SNAT_SESSION_FLAG_UNKNOWN_PROTO        2
@@ -169,6 +175,8 @@ typedef CLIB_PACKED(struct {
 
   /* TCP session state */
   u8 state;
+  u32 i2o_fin_seq;
+  u32 o2i_fin_seq;
 }) snat_session_t;
 
 
@@ -588,6 +596,9 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                                      u8 *tag);
 int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
                        snat_protocol_t proto, u32 vrf_id, int is_in);
+int nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
+                          ip4_address_t *eh_addr, u16 eh_port, u8 proto,
+                          u32 vrf_id, int is_in);
 void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
                             u32 thread_index);
 snat_user_t * nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr,
@@ -710,31 +721,52 @@ nat44_delete_session(snat_main_t * sm, snat_session_t * ses, u32 thread_index)
   pool_put (tsm->sessions, ses);
 }
 
-/** \brief Set TCP session stet.
+/** \brief Set TCP session state.
     @return 1 if session was closed, otherwise 0
 */
 always_inline int
-nat44_set_tcp_session_state(snat_main_t * sm, snat_session_t * ses,
-                            tcp_header_t * tcp, u32 thread_index)
+nat44_set_tcp_session_state_i2o(snat_main_t * sm, snat_session_t * ses,
+                                tcp_header_t * tcp, u32 thread_index)
 {
-  if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_UNKNOWN)
-    ses->state = SNAT_SESSION_TCP_FIN_WAIT;
-  else if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_TCP_FIN_WAIT)
-    ses->state = SNAT_SESSION_TCP_CLOSING;
-  else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_FIN_WAIT)
-    ses->state = SNAT_SESSION_TCP_CLOSE_WAIT;
-  else if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_TCP_CLOSE_WAIT)
-    ses->state = SNAT_SESSION_TCP_LAST_ACK;
-  else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_CLOSING)
-    ses->state = SNAT_SESSION_TCP_LAST_ACK;
-  else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_LAST_ACK)
+  if (tcp->flags & TCP_FLAG_FIN)
+    {
+      ses->i2o_fin_seq = clib_net_to_host_u32 (tcp->seq_number);
+      ses->state |= NAT44_SES_I2O_FIN;
+    }
+  if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN))
+    {
+      if (clib_net_to_host_u32 (tcp->ack_number) > ses->o2i_fin_seq)
+        ses->state |= NAT44_SES_O2I_FIN_ACK;
+    }
+  if (nat44_is_ses_closed (ses))
     {
       nat_free_session_data (sm, ses, thread_index);
-      ses->state = SNAT_SESSION_TCP_CLOSED;
       nat44_delete_session (sm, ses, thread_index);
       return 1;
     }
+  return 0;
+}
 
+always_inline int
+nat44_set_tcp_session_state_o2i(snat_main_t * sm, snat_session_t * ses,
+                                tcp_header_t * tcp, u32 thread_index)
+{
+  if (tcp->flags & TCP_FLAG_FIN)
+    {
+      ses->o2i_fin_seq = clib_net_to_host_u32 (tcp->seq_number);
+      ses->state |= NAT44_SES_O2I_FIN;
+    }
+  if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN))
+    {
+      if (clib_net_to_host_u32 (tcp->ack_number) > ses->i2o_fin_seq)
+        ses->state |= NAT44_SES_I2O_FIN_ACK;
+    }
+  if (nat44_is_ses_closed (ses))
+    {
+      nat_free_session_data (sm, ses, thread_index);
+      nat44_delete_session (sm, ses, thread_index);
+      return 1;
+    }
   return 0;
 }
 
index f07b6dd..efde4be 100644 (file)
@@ -959,10 +959,10 @@ nat44_del_session_command_fn (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
   unformat_input_t _line_input, *line_input = &_line_input;
-  int is_in = 0;
+  int is_in = 0, is_ed = 0;
   clib_error_t *error = 0;
-  ip4_address_t addr;
-  u32 port = 0, vrf_id = sm->outside_vrf_id;
+  ip4_address_t addr, eh_addr;
+  u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
   snat_protocol_t proto;
   int rv;
 
@@ -984,8 +984,18 @@ nat44_del_session_command_fn (vlib_main_t * vm,
          is_in = 1;
          vrf_id = sm->inside_vrf_id;
        }
+      else if (unformat (line_input, "out"))
+       {
+         is_in = 0;
+         vrf_id = sm->outside_vrf_id;
+       }
       else if (unformat (line_input, "vrf %u", &vrf_id))
        ;
+      else
+       if (unformat
+           (line_input, "external-host %U:%u", unformat_ip4_address,
+            &eh_addr, &eh_port))
+       is_ed = 1;
       else
        {
          error = clib_error_return (0, "unknown input '%U'",
@@ -994,7 +1004,12 @@ nat44_del_session_command_fn (vlib_main_t * vm,
        }
     }
 
-  rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in);
+  if (is_ed)
+    rv =
+      nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port,
+                           snat_proto_to_ip_proto (proto), vrf_id, is_in);
+  else
+    rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in);
 
   switch (rv)
     {
@@ -1750,7 +1765,7 @@ VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
 ?*/
 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
     .path = "nat44 del session",
-    .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
+    .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
     .function = nat44_del_session_command_fn,
 };
 
index a1d70f8..11a6f0f 100644 (file)
@@ -1157,13 +1157,17 @@ send_nat44_user_details (snat_user_t * u, vl_api_registration_t * reg,
 {
   vl_api_nat44_user_details_t *rmp;
   snat_main_t *sm = &snat_main;
-  fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4);
+  ip4_main_t *im = &ip4_main;
 
   rmp = vl_msg_api_alloc (sizeof (*rmp));
   memset (rmp, 0, sizeof (*rmp));
   rmp->_vl_msg_id = ntohs (VL_API_NAT44_USER_DETAILS + sm->msg_id_base);
 
-  rmp->vrf_id = ntohl (fib->ft_table_id);
+  if (!pool_is_free_index (im->fibs, u->fib_index))
+    {
+      fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4);
+      rmp->vrf_id = ntohl (fib->ft_table_id);
+    }
 
   clib_memcpy (rmp->ip_address, &(u->addr), 4);
   rmp->nsessions = ntohl (u->nsessions);
@@ -1218,7 +1222,10 @@ send_nat44_user_session_details (snat_session_t * s,
     ntohs (VL_API_NAT44_USER_SESSION_DETAILS + sm->msg_id_base);
   clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4);
   clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4);
-  rmp->is_static = s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING ? 1 : 0;
+  rmp->is_static = snat_is_session_static (s) ? 1 : 0;
+  rmp->is_twicenat = is_twice_nat_session (s) ? 1 : 0;
+  rmp->ext_host_valid = is_ed_session (s)
+    || is_fwd_bypass_session (s) ? 1 : 0;
   rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard);
   rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes);
   rmp->total_pkts = ntohl (s->total_pkts);
@@ -1235,8 +1242,16 @@ send_nat44_user_session_details (snat_session_t * s,
       rmp->inside_port = s->in2out.port;
       rmp->protocol = ntohs (snat_proto_to_ip_proto (s->in2out.protocol));
     }
-  if (s->in2out.protocol == SNAT_PROTOCOL_TCP)
-    rmp->is_closed = s->state == SNAT_SESSION_TCP_CLOSED ? 1 : 0;
+  if (is_ed_session (s) || is_fwd_bypass_session (s))
+    {
+      clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4);
+      rmp->ext_host_port = s->ext_host_port;
+      if (is_twice_nat_session (s))
+       {
+         clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4);
+         rmp->ext_host_nat_port = s->ext_host_nat_port;
+       }
+    }
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
@@ -1469,8 +1484,8 @@ vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat44_del_session_reply_t *rmp;
-  ip4_address_t addr;
-  u16 port;
+  ip4_address_t addr, eh_addr;
+  u16 port, eh_port;
   u32 vrf_id;
   int rv = 0;
   snat_protocol_t proto;
@@ -1485,8 +1500,15 @@ vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp)
   port = clib_net_to_host_u16 (mp->port);
   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
   proto = ip_proto_to_snat_proto (mp->protocol);
+  memcpy (&eh_addr.as_u8, mp->ext_host_address, 4);
+  eh_port = clib_net_to_host_u16 (mp->ext_host_port);
 
-  rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in);
+  if (mp->ext_host_valid)
+    rv =
+      nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol,
+                           vrf_id, mp->is_in);
+  else
+    rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in);
 
 send_reply:
   REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY);
@@ -1503,6 +1525,10 @@ vl_api_nat44_del_session_t_print (vl_api_nat44_del_session_t * mp,
              format_ip4_address, mp->address,
              clib_net_to_host_u16 (mp->port),
              mp->protocol, clib_net_to_host_u32 (mp->vrf_id), mp->is_in);
+  if (mp->ext_host_valid)
+    s = format (s, "ext_host_address %U ext_host_port %d",
+               format_ip4_address, mp->ext_host_address,
+               clib_net_to_host_u16 (mp->ext_host_port));
 
   FINISH;
 }
@@ -1514,9 +1540,35 @@ static void
   snat_main_t *sm = &snat_main;
   vl_api_nat44_forwarding_enable_disable_reply_t *rmp;
   int rv = 0;
+  u32 *ses_to_be_removed = 0, *ses_index;
+  snat_main_per_thread_data_t *tsm;
+  snat_session_t *s;
 
   sm->forwarding_enabled = mp->enable != 0;
 
+  if (mp->enable == 0)
+    {
+      /* *INDENT-OFF* */
+      vec_foreach (tsm, sm->per_thread_data)
+      {
+        pool_foreach (s, tsm->sessions,
+        ({
+          if (is_fwd_bypass_session(s))
+            {
+              vec_add1 (ses_to_be_removed, s - tsm->sessions);
+            }
+        }));
+        vec_foreach (ses_index, ses_to_be_removed)
+        {
+          s = pool_elt_at_index(tsm->sessions, ses_index[0]);
+          nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+          nat44_delete_session (sm, s, tsm - sm->per_thread_data);
+        }
+        vec_free (ses_to_be_removed);
+      }
+      /* *INDENT-ON* */
+    }
+
   REPLY_MACRO (VL_API_NAT44_FORWARDING_ENABLE_DISABLE_REPLY);
 }
 
index 6bc25b8..c7eece8 100755 (executable)
@@ -342,6 +342,7 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
   snat_user_t *u;
   snat_session_t *s = 0;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  f64 now = vlib_time_now (sm->vlib_main);
 
   if (ip->protocol == IP_PROTOCOL_ICMP)
     {
@@ -410,13 +411,16 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
   if (ip->protocol == IP_PROTOCOL_TCP)
     {
       tcp_header_t *tcp = ip4_next_header(ip);
-      if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+      if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
         return;
     }
   /* 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);
+  /* Accounting */
+  s->last_heard = now;
+  s->total_pkts++;
 }
 
 /**
@@ -1066,7 +1070,7 @@ snat_out2in_lb (snat_main_t *sm,
           ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
         }
       tcp->checksum = ip_csum_fold(sum);
-      if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+      if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
         return s;
     }
   else
@@ -1308,8 +1312,6 @@ snat_out2in_node_fn (vlib_main_t * vm,
                                      ip4_header_t /* cheat */,
                                      length /* changed member */);
               tcp0->checksum = ip_csum_fold(sum0);
-              if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
-                goto trace0;
             }
           else
             {
@@ -1488,8 +1490,6 @@ snat_out2in_node_fn (vlib_main_t * vm,
                                      ip4_header_t /* cheat */,
                                      length /* changed member */);
               tcp1->checksum = ip_csum_fold(sum1);
-              if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index))
-                goto trace1;
             }
           else
             {
@@ -1704,8 +1704,6 @@ snat_out2in_node_fn (vlib_main_t * vm,
                                      ip4_header_t /* cheat */,
                                      length /* changed member */);
               tcp0->checksum = ip_csum_fold(sum0);
-              if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
-                goto trace00;
             }
           else
             {
@@ -1974,8 +1972,6 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
                                          ip4_header_t /* cheat */,
                                          length /* changed member */);
                   tcp0->checksum = ip_csum_fold(sum0);
-                  if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
-                    goto trace0;
                 }
               else
                 {
index 59641a2..e2f3465 100644 (file)
@@ -1302,6 +1302,19 @@ class TestNAT44(MethodHolder):
             finally:
                 self.pg0.remote_hosts[0] = host0
 
+            user = self.pg0.remote_hosts[1]
+            sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
+            self.assertEqual(len(sessions), 3)
+            self.assertTrue(sessions[0].ext_host_valid)
+            self.vapi.nat44_del_session(
+                sessions[0].inside_ip_address,
+                sessions[0].inside_port,
+                sessions[0].protocol,
+                ext_host_address=sessions[0].ext_host_address,
+                ext_host_port=sessions[0].ext_host_port)
+            sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
+            self.assertEqual(len(sessions), 2)
+
         finally:
             self.vapi.nat44_forwarding_enable_disable(0)
             self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
@@ -1737,6 +1750,18 @@ class TestNAT44(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
+        sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+        self.assertEqual(len(sessions), 1)
+        self.assertTrue(sessions[0].ext_host_valid)
+        self.vapi.nat44_del_session(
+            sessions[0].inside_ip_address,
+            sessions[0].inside_port,
+            sessions[0].protocol,
+            ext_host_address=sessions[0].ext_host_address,
+            ext_host_port=sessions[0].ext_host_port)
+        sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+        self.assertEqual(len(sessions), 0)
+
     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
     def test_static_lb_multi_clients(self):
         """ NAT44 local service load balancing - multiple clients"""
@@ -2073,6 +2098,7 @@ class TestNAT44(MethodHolder):
                 self.assertTrue(session.protocol in
                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
                                  IP_PROTOS.icmp])
+                self.assertFalse(session.ext_host_valid)
 
         # pg4 session dump
         sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4n, 10)
@@ -3908,6 +3934,20 @@ class TestNAT44(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
+        if eh_translate:
+            sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+            self.assertEqual(len(sessions), 1)
+            self.assertTrue(sessions[0].ext_host_valid)
+            self.assertTrue(sessions[0].is_twicenat)
+            self.vapi.nat44_del_session(
+                sessions[0].inside_ip_address,
+                sessions[0].inside_port,
+                sessions[0].protocol,
+                ext_host_address=sessions[0].ext_host_nat_address,
+                ext_host_port=sessions[0].ext_host_nat_port)
+            sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+            self.assertEqual(len(sessions), 0)
+
     def test_twice_nat(self):
         """ Twice NAT44 """
         self.twice_nat_common()
@@ -4018,7 +4058,7 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
-                     flags="FA"))
+                     flags="FA", seq=100, ack=300))
             self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
@@ -4030,14 +4070,14 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
-                     flags="A"))
+                     flags="A", seq=300, ack=101))
             pkts.append(p)
 
             # FIN packet out -> in
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
-                     flags="FA"))
+                     flags="FA", seq=300, ack=101))
             pkts.append(p)
 
             self.pg1.add_stream(pkts)
@@ -4049,7 +4089,7 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
-                     flags="A"))
+                     flags="A", seq=101, ack=301))
             self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
@@ -4081,38 +4121,28 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
-                     flags="FA"))
+                     flags="FA", seq=100, ack=300))
             self.pg1.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
             self.pg0.get_capture(1)
 
-            pkts = []
-
-            # ACK packet in -> out
-            p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
-                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
-                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
-                     flags="A"))
-            pkts.append(p)
-
-            # ACK packet in -> out
+            # FIN+ACK packet in -> out
             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
-                     flags="FA"))
-            pkts.append(p)
+                     flags="FA", seq=300, ack=101))
 
-            self.pg0.add_stream(pkts)
+            self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
-            self.pg1.get_capture(2)
+            self.pg1.get_capture(1)
 
             # ACK packet out -> in
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
-                     flags="A"))
+                     flags="A", seq=101, ack=301))
             self.pg1.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
@@ -4144,7 +4174,7 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
-                     flags="FA"))
+                     flags="FA", seq=100, ack=300))
             self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
@@ -4154,7 +4184,7 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
-                     flags="FA"))
+                     flags="FA", seq=300, ack=100))
             self.pg1.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
@@ -4164,7 +4194,7 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
                  IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
                  TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
-                     flags="A"))
+                     flags="A", seq=101, ack=301))
             self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
@@ -4174,7 +4204,7 @@ class TestNAT44(MethodHolder):
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
                  TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
-                     flags="A"))
+                     flags="A", seq=301, ack=101))
             self.pg1.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
index b362731..105a54f 100644 (file)
@@ -1540,7 +1540,9 @@ class VppPapiProvider(object):
             port,
             protocol,
             vrf_id=0,
-            is_in=1):
+            is_in=1,
+            ext_host_address=None,
+            ext_host_port=0):
         """Delete NAT44 session
 
         :param addr: IPv4 address
@@ -1548,14 +1550,28 @@ class VppPapiProvider(object):
         :param protocol: IP protocol number
         :param vrf_id: VRF ID
         :param is_in: 1 if inside network addres and port pari, 0 if outside
-        """
-        return self.api(
-            self.papi.nat44_del_session,
-            {'address': addr,
-             'port': port,
-             'protocol': protocol,
-             'vrf_id': vrf_id,
-             'is_in': is_in})
+        :param ext_host_address: external host IPv4 address
+        :param ext_host_port: external host port
+        """
+        if ext_host_address is None:
+            return self.api(
+                self.papi.nat44_del_session,
+                {'address': addr,
+                 'port': port,
+                 'protocol': protocol,
+                 'vrf_id': vrf_id,
+                 'is_in': is_in})
+        else:
+            return self.api(
+                self.papi.nat44_del_session,
+                {'address': addr,
+                 'port': port,
+                 'protocol': protocol,
+                 'vrf_id': vrf_id,
+                 'is_in': is_in,
+                 'ext_host_valid': 1,
+                 'ext_host_address': ext_host_address,
+                 'ext_host_port': ext_host_port})
 
     def nat44_forwarding_enable_disable(
             self,