NAT44: nat44_del_session and nat44_user_session_details API update (VPP-1271)
[vpp.git] / src / plugins / nat / nat.c
index ab951cf..ae34f23 100755 (executable)
@@ -329,10 +329,19 @@ nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index)
       /* Get the session */
       s = pool_elt_at_index (tsm->sessions, session_index);
       nat_free_session_data (sm, s, thread_index);
+      if (snat_is_session_static(s))
+        u->nstaticsessions--;
+      else
+        u->nsessions--;
       s->outside_address_index = ~0;
       s->flags = 0;
       s->total_bytes = 0;
       s->total_pkts = 0;
+      s->state = 0;
+      s->ext_host_addr.as_u32 = 0;
+      s->ext_host_port = 0;
+      s->ext_host_nat_addr.as_u32 = 0;
+      s->ext_host_nat_port = 0;
     }
   else
     {
@@ -917,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))
@@ -965,12 +974,8 @@ 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)
-                        {
-                          if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
-                              (clib_net_to_host_u16 (s->out2in.port) != e_port))
-                            continue;
-                        }
+                      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);
                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
@@ -1057,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 */
@@ -1094,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);
@@ -1517,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--;
                   }
               }
           }));
@@ -1629,12 +1640,18 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
                                              sw_if_index, 0, 0, 0);
                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
                                              sw_if_index, 1, 0, 0);
+                if (!is_inside)
+                  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
+                                               sw_if_index, 1, 0, 0);
               }
             else
               {
                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
                                              sw_if_index, 0, 0, 0);
                 pool_put (sm->interfaces, i);
+                if (is_inside)
+                  vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
+                                               sw_if_index, 0, 0, 0);
               }
           }
         else
@@ -1665,6 +1682,9 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
                                          sw_if_index, 0, 0, 0);
             vnet_feature_enable_disable ("ip4-unicast", feature_name,
                                          sw_if_index, 1, 0, 0);
+            if (!is_inside)
+              vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
+                                           sw_if_index, 0, 0, 0);
             goto set_flags;
           }
 
@@ -1680,21 +1700,21 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
   i->flags = 0;
   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
 
+  if (is_inside && !sm->out2in_dpo)
+    vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
+                                 sw_if_index, 1, 0, 0);
+
 set_flags:
   if (is_inside)
-    i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
+    {
+      i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
+      return 0;
+    }
   else
     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
 
   /* Add/delete external addresses to FIB */
 fib:
-  if (is_inside && !sm->out2in_dpo)
-    {
-      vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
-                                   sw_if_index, !is_del, 0, 0);
-      return 0;
-    }
-
   vec_foreach (ap, sm->addresses)
     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
 
@@ -2676,19 +2696,23 @@ 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))
-    {
-      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 (is_ed_session (sess) || is_fwd_bypass_session (sess))
     {
-      if (sess->ext_host_addr.as_u32)
-          s = format (s, "       external host %U\n",
-                      format_ip4_address, &sess->ext_host_addr);
+      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),
+                      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",
@@ -2697,6 +2721,8 @@ u8 * format_snat_session (u8 * s, va_list * args)
     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))
@@ -2751,12 +2777,13 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args)
   nat44_lb_addr_port_t *local;
 
   if (m->addr_only)
-      s = format (s, "local %U external %U vrf %d %s",
+      s = format (s, "local %U external %U vrf %d %s %s",
                   format_ip4_address, &m->local_addr,
                   format_ip4_address, &m->external_addr,
                   m->vrf_id,
                   m->twice_nat == TWICE_NAT ? "twice-nat" :
-                  m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "");
+                  m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
+                  m->out2in_only ? "out2in-only" : "");
   else
    {
       if (vec_len (m->locals))
@@ -3084,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);
@@ -3095,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;
     }
@@ -3105,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)
 {