NAT44: code cleanup and refactor (VPP-1285) 65/12765/3
authorMatus Fabian <matfabia@cisco.com>
Mon, 28 May 2018 11:09:52 +0000 (04:09 -0700)
committerDamjan Marion <dmarion.lists@gmail.com>
Mon, 28 May 2018 20:01:19 +0000 (20:01 +0000)
Change-Id: I088163f10ae5515d7a9115781cc13ef563fafed5
Signed-off-by: Matus Fabian <matfabia@cisco.com>
18 files changed:
src/plugins/nat/dslite_ce_decap.c
src/plugins/nat/dslite_ce_encap.c
src/plugins/nat/dslite_in2out.c
src/plugins/nat/dslite_out2in.c
src/plugins/nat/in2out.c
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44_cli.c
src/plugins/nat/nat64.c
src/plugins/nat/nat64_cli.c
src/plugins/nat/nat64_db.c
src/plugins/nat/nat64_in2out.c
src/plugins/nat/nat64_out2in.c
src/plugins/nat/nat_api.c
src/plugins/nat/nat_inlines.h [new file with mode: 0644]
src/plugins/nat/nat_ipfix_logging.c
src/plugins/nat/out2in.c
test/test_nat.py

index 615a424..c16ac17 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 #include <nat/dslite.h>
+#include <nat/nat_inlines.h>
 
 vlib_node_registration_t dslite_ce_decap_node;
 
index f098d75..d83ca9c 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 #include <nat/dslite.h>
+#include <nat/nat_inlines.h>
 
 vlib_node_registration_t dslite_ce_encap_node;
 
index 98b3a16..ab0055c 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 #include <nat/dslite.h>
+#include <nat/nat_inlines.h>
 
 vlib_node_registration_t dslite_in2out_node;
 vlib_node_registration_t dslite_in2out_slowpath_node;
index 802b2a9..6bfc6e9 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 #include <nat/dslite.h>
+#include <nat/nat_inlines.h>
 
 vlib_node_registration_t dslite_out2in_node;
 
index 1659ed0..c724553 100755 (executable)
@@ -25,6 +25,7 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_det.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
@@ -127,7 +128,8 @@ _(NO_TRANSLATION, "No translation")                     \
 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded")   \
 _(DROP_FRAGMENT, "Drop fragment")                       \
 _(MAX_REASS, "Maximum reassemblies exceeded")           \
-_(MAX_FRAG, "Maximum fragments per reassembly exceeded")
+_(MAX_FRAG, "Maximum fragments per reassembly exceeded")\
+_(FQ_CONGESTED, "Handoff frame queue congested")
 
 typedef enum {
 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
@@ -316,6 +318,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
     {
       b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
       nat_ipfix_logging_max_sessions(sm->max_translations);
+      nat_log_notice ("maximum sessions exceeded");
       return SNAT_IN2OUT_NEXT_DROP;
     }
 
@@ -333,7 +336,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
                               thread_index);
   if (!u)
     {
-      clib_warning ("create NAT user failed");
+      nat_log_warn ("create NAT user failed");
       return SNAT_IN2OUT_NEXT_DROP;
     }
 
@@ -357,7 +360,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
   s = nat_session_alloc_or_recycle (sm, u, thread_index);
   if (!s)
     {
-      clib_warning ("create NAT session failed");
+      nat_log_warn ("create NAT session failed");
       return SNAT_IN2OUT_NEXT_DROP;
     }
 
@@ -378,14 +381,14 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
   kv0.value = s - sm->per_thread_data[thread_index].sessions;
   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
                                1 /* is_add */))
-      clib_warning ("in2out key add failed");
+      nat_log_notice ("in2out key add failed");
 
   kv0.key = s->out2in.as_u64;
   kv0.value = s - sm->per_thread_data[thread_index].sessions;
 
   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
                                1 /* is_add */))
-      clib_warning ("out2in key add failed");
+      nat_log_notice ("out2in key add failed");
 
   /* log NAT event */
   snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
@@ -497,7 +500,6 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
   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];
   f64 now = vlib_time_now (sm->vlib_main);
 
   if (!sm->forwarding_enabled)
@@ -540,12 +542,9 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
                 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);
+          nat44_session_update_lru (sm, s, thread_index);
           /* Accounting */
-          s->last_heard = now;
-          s->total_pkts++;
+          nat44_session_update_counters (s, now, 0);
           return 1;
         }
       else
@@ -1083,15 +1082,10 @@ static inline u32 icmp_in2out_slow_path (snat_main_t *sm,
       if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == 0)
         snat_icmp_hairpinning(sm, b0, ip0, icmp0);
       /* Accounting */
-      s0->last_heard = now;
-      s0->total_pkts++;
-      s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
+      nat44_session_update_counters (s0, now,
+                                     vlib_buffer_length_in_chain (sm->vlib_main, b0));
       /* Per-user LRU list maintenance */
-      clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                         s0->per_user_index);
-      clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                          s0->per_user_list_head_index,
-                          s0->per_user_index);
+      nat44_session_update_lru (sm, s0, thread_index);
     }
   return next0;
 }
@@ -1198,6 +1192,7 @@ snat_in2out_unknown_proto (snat_main_t *sm,
         {
           b->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
           nat_ipfix_logging_max_sessions(sm->max_translations);
+          nat_log_notice ("maximum sessions exceeded");
           return 0;
         }
 
@@ -1205,7 +1200,7 @@ snat_in2out_unknown_proto (snat_main_t *sm,
                                   thread_index);
       if (!u)
         {
-          clib_warning ("create NAT user failed");
+          nat_log_warn ("create NAT user failed");
           return 0;
         }
 
@@ -1280,7 +1275,7 @@ create_ses:
       s = nat_session_alloc_or_recycle (sm, u, thread_index);
       if (!s)
         {
-          clib_warning ("create NAT session failed");
+          nat_log_warn ("create NAT session failed");
           return 0;
         }
 
@@ -1306,14 +1301,14 @@ create_ses:
       s_kv.key[1] = key.as_u64[1];
       s_kv.value = s - tsm->sessions;
       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
-        clib_warning ("in2out key add failed");
+        nat_log_notice ("in2out key add failed");
 
       key.l_addr.as_u32 = new_addr;
       key.fib_index = sm->outside_fib_index;
       s_kv.key[0] = key.as_u64[0];
       s_kv.key[1] = key.as_u64[1];
       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
-        clib_warning ("out2in key add failed");
+        nat_log_notice ("out2in key add failed");
   }
 
   /* Update IP checksum */
@@ -1322,13 +1317,9 @@ create_ses:
   ip->checksum = ip_csum_fold (sum);
 
   /* Accounting */
-  s->last_heard = now;
-  s->total_pkts++;
-  s->total_bytes += vlib_buffer_length_in_chain (vm, b);
+  nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b));
   /* 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);
+  nat44_session_update_lru (sm, s, thread_index);
 
   /* Hairpinning */
   if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
@@ -1386,9 +1377,7 @@ snat_in2out_lb (snat_main_t *sm,
                 return 0;
             }
           /* 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);
+          nat44_session_update_lru (sm, s, thread_index);
           return 0;
         }
     }
@@ -1398,6 +1387,7 @@ snat_in2out_lb (snat_main_t *sm,
         {
           b->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
           nat_ipfix_logging_max_sessions(sm->max_translations);
+          nat_log_notice ("maximum sessions exceeded");
           return 0;
         }
 
@@ -1412,18 +1402,19 @@ snat_in2out_lb (snat_main_t *sm,
                                   thread_index);
       if (!u)
         {
-          clib_warning ("create NAT user failed");
+          nat_log_warn ("create NAT user failed");
           return 0;
         }
 
       s = nat_session_alloc_or_recycle (sm, u, thread_index);
       if (!s)
         {
-          clib_warning ("create NAT session failed");
+          nat_log_warn ("create NAT session failed");
           return 0;
         }
 
       s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
+      s->ext_host_port = udp->dst_port;
       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
       if (lb)
         s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
@@ -1437,7 +1428,7 @@ snat_in2out_lb (snat_main_t *sm,
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
-        clib_warning ("in2out-ed key add failed");
+        nat_log_notice ("in2out-ed key add failed");
 
       key.l_addr = e_key.addr;
       key.fib_index = e_key.fib_index;
@@ -1445,7 +1436,7 @@ snat_in2out_lb (snat_main_t *sm,
       s_kv.key[0] = key.as_u64[0];
       s_kv.key[1] = key.as_u64[1];
       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
-        clib_warning ("out2in-ed key add failed");
+        nat_log_notice ("out2in-ed key add failed");
     }
 
   new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
@@ -1496,13 +1487,10 @@ snat_in2out_lb (snat_main_t *sm,
     }
 
   /* Accounting */
-  s->last_heard = now;
-  s->total_pkts++;
-  s->total_bytes += vlib_buffer_length_in_chain (vm, b);
+  nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b));
   /* 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);
+  nat44_session_update_lru (sm, s, thread_index);
+
   return s;
 }
 
@@ -1747,15 +1735,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s0->last_heard = now;
-          s0->total_pkts++;
-          s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
+          nat44_session_update_counters (s0, now,
+                                         vlib_buffer_length_in_chain (vm, b0));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s0->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s0->per_user_list_head_index,
-                              s0->per_user_index);
+          nat44_session_update_lru (sm, s0, thread_index);
         trace00:
 
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -1939,15 +1922,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s1->last_heard = now;
-          s1->total_pkts++;
-          s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
+          nat44_session_update_counters (s1, now,
+                                         vlib_buffer_length_in_chain (vm, b1));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s1->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s1->per_user_list_head_index,
-                              s1->per_user_index);
+          nat44_session_update_lru (sm, s1, thread_index);
         trace01:
 
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -2168,15 +2146,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s0->last_heard = now;
-          s0->total_pkts++;
-          s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
+          nat44_session_update_counters (s0, now,
+                                         vlib_buffer_length_in_chain (vm, b0));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s0->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s0->per_user_list_head_index,
-                              s0->per_user_index);
+          nat44_session_update_lru (sm, s0, thread_index);
 
         trace0:
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -2614,6 +2587,7 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
             {
               next0 = SNAT_IN2OUT_NEXT_DROP;
               b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_REASS];
+              nat_log_notice ("maximum reassemblies exceeded");
               goto trace0;
             }
 
@@ -2654,6 +2628,7 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
                   if (nat_ip4_reass_add_fragment (reass0, bi0))
                     {
                       b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_FRAG];
+                      nat_log_notice ("maximum fragments per reassembly exceeded");
                       next0 = SNAT_IN2OUT_NEXT_DROP;
                       goto trace0;
                     }
@@ -2705,15 +2680,10 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
                                    s0->ext_host_port, proto0);
 
           /* Accounting */
-          s0->last_heard = now;
-          s0->total_pkts++;
-          s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
+          nat44_session_update_counters (s0, now,
+                                         vlib_buffer_length_in_chain (vm, b0));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s0->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s0->per_user_list_head_index,
-                              s0->per_user_index);
+          nat44_session_update_lru (sm, s0, thread_index);
 
         trace0:
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -2907,8 +2877,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm,
           dm0 = snat_det_map_by_user(sm, &ip0->src_address);
           if (PREDICT_FALSE(!dm0))
             {
-              clib_warning("no match for internal host %U",
-                           format_ip4_address, &ip0->src_address);
+              nat_log_info ("no match for internal host %U",
+                            format_ip4_address, &ip0->src_address);
               next0 = SNAT_IN2OUT_NEXT_DROP;
               b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
               goto trace0;
@@ -3057,8 +3027,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm,
           dm1 = snat_det_map_by_user(sm, &ip1->src_address);
           if (PREDICT_FALSE(!dm1))
             {
-              clib_warning("no match for internal host %U",
-                           format_ip4_address, &ip0->src_address);
+              nat_log_info ("no match for internal host %U",
+                            format_ip4_address, &ip0->src_address);
               next1 = SNAT_IN2OUT_NEXT_DROP;
               b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
               goto trace1;
@@ -3243,8 +3213,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm,
           dm0 = snat_det_map_by_user(sm, &ip0->src_address);
           if (PREDICT_FALSE(!dm0))
             {
-              clib_warning("no match for internal host %U",
-                           format_ip4_address, &ip0->src_address);
+              nat_log_info ("no match for internal host %U",
+                            format_ip4_address, &ip0->src_address);
               next0 = SNAT_IN2OUT_NEXT_DROP;
               b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
               goto trace00;
@@ -3476,8 +3446,8 @@ u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node,
   dm0 = snat_det_map_by_user(sm, &in_addr);
   if (PREDICT_FALSE(!dm0))
     {
-      clib_warning("no match for internal host %U",
-                   format_ip4_address, &in_addr);
+      nat_log_info ("no match for internal host %U",
+                    format_ip4_address, &in_addr);
       if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
           IP_PROTOCOL_ICMP, rx_fib_index0)))
         {
@@ -3568,11 +3538,12 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
-  u32 n_left_from, *from, *to_next = 0;
+  u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0;
   static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
   static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
     = 0;
   vlib_frame_queue_elt_t *hf = 0;
+  vlib_frame_queue_t *fq;
   vlib_frame_t *f = 0;
   int i;
   u32 n_left_to_next_worker = 0, *to_next_worker = 0;
@@ -3581,6 +3552,7 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
   u32 thread_index = vlib_get_thread_index ();
   u32 fq_index;
   u32 to_node_index;
+  vlib_frame_t *d = 0;
 
   ASSERT (vec_len (sm->workers));
 
@@ -3600,7 +3572,7 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
       vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
 
       vec_validate_init_empty (congested_handoff_queue_by_worker_index,
-                              sm->first_worker_index + sm->num_workers - 1,
+                              tm->n_vlib_mains - 1,
                               (vlib_frame_queue_t *) (~0));
     }
 
@@ -3635,6 +3607,26 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
 
           if (next_worker_index != current_worker_index)
             {
+              fq = is_vlib_frame_queue_congested (
+                fq_index, next_worker_index, NAT_FQ_NELTS - 2,
+                congested_handoff_queue_by_worker_index);
+
+              if (fq)
+                {
+                  /* if this is 1st frame */
+                  if (!d)
+                    {
+                      d = vlib_get_frame_to_node (vm, sm->error_node_index);
+                      to_next_drop = vlib_frame_vector_args (d);
+                    }
+
+                  to_next_drop[0] = bi0;
+                  to_next_drop += 1;
+                  d->n_vectors++;
+                  b0->error = node->errors[SNAT_IN2OUT_ERROR_FQ_CONGESTED];
+                  goto trace0;
+                }
+
               if (hf)
                 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
 
@@ -3676,6 +3668,7 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
           f->n_vectors++;
         }
 
+trace0:
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
@@ -3689,6 +3682,9 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
   if (f)
     vlib_put_frame_to_node (vm, to_node_index, f);
 
+  if (d)
+    vlib_put_frame_to_node (vm, sm->error_node_index, d);
+
   if (hf)
     hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
 
@@ -3733,6 +3729,9 @@ VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = {
   .format_trace = format_snat_in2out_worker_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
+  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
+  .error_strings = snat_in2out_error_strings,
+
   .n_next_nodes = 1,
 
   .next_nodes = {
index 8ebec58..1d493a6 100755 (executable)
@@ -27,6 +27,7 @@
 #include <nat/nat66.h>
 #include <nat/dslite.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/ip4_fib.h>
 
@@ -164,7 +165,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))
-        clib_warning ("in2out_ed key del failed");
+        nat_log_warn ("in2out_ed key del failed");
       return;
     }
 
@@ -189,7 +190,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))
-        clib_warning ("out2in_ed key del failed");
+        nat_log_warn ("out2in_ed key del failed");
 
       ed_key.l_addr = s->in2out.addr;
       ed_key.fib_index = s->in2out.fib_index;
@@ -203,7 +204,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))
-        clib_warning ("in2out_ed key del failed");
+        nat_log_warn ("in2out_ed key del failed");
     }
 
   if (snat_is_unk_proto_session (s))
@@ -240,10 +241,10 @@ 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))
-    clib_warning ("in2out key del failed");
+    nat_log_warn ("in2out key del failed");
   kv.key = s->out2in.as_u64;
   if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
-    clib_warning ("out2in key del failed");
+    nat_log_warn ("out2in key del failed");
 
   if (snat_is_session_static (s))
     return;
@@ -287,7 +288,7 @@ nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr, u32 fib_index,
 
       /* add user */
       if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
-        clib_warning ("user_hash keay add failed");
+        nat_log_warn ("user_hash keay add failed");
     }
   else
     {
@@ -367,6 +368,24 @@ nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index)
   return s;
 }
 
+typedef struct {
+  u8 next_in2out;
+} nat44_classify_trace_t;
+
+static u8 * format_nat44_classify_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *);
+  char *next;
+
+  next = t->next_in2out ? "nat44-in2out" : "nat44-out2in";
+
+  s = format (s, "nat44-classify: next %s", next);
+
+  return s;
+}
+
 static inline uword
 nat44_classify_node_fn_inline (vlib_main_t * vm,
                                vlib_node_runtime_t * node,
@@ -445,6 +464,14 @@ nat44_classify_node_fn_inline (vlib_main_t * vm,
             }
 
         enqueue0:
+          if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+            {
+              nat44_classify_trace_t *t =
+                  vlib_add_trace (vm, node, b0, sizeof (*t));
+              t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
+            }
+
           /* verify speculative enqueue, maybe switch current next frame */
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                           to_next, n_left_to_next,
@@ -469,6 +496,7 @@ VLIB_REGISTER_NODE (nat44_classify_node) = {
   .function = nat44_classify_node_fn,
   .name = "nat44-classify",
   .vector_size = sizeof (u32),
+  .format_trace = format_nat44_classify_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
   .next_nodes = {
@@ -492,6 +520,7 @@ VLIB_REGISTER_NODE (nat44_det_classify_node) = {
   .function = nat44_det_classify_node_fn,
   .name = "nat44-det-classify",
   .vector_size = sizeof (u32),
+  .format_trace = format_nat44_classify_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
   .next_nodes = {
@@ -515,6 +544,7 @@ VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
   .function = nat44_handoff_classify_node_fn,
   .name = "nat44-handoff-classify",
   .vector_size = sizeof (u32),
+  .format_trace = format_nat44_classify_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
   .next_nodes = {
@@ -859,7 +889,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       foreach_snat_protocol
 #undef _
                     default:
-                      clib_warning("unknown_protocol");
+                      nat_log_info ("unknown protocol");
                       return VNET_API_ERROR_INVALID_VALUE_2;
                     }
                   break;
@@ -931,7 +961,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->in2out, &kv, 1))
-            clib_warning ("in2out key add failed");
+            nat_log_warn ("in2out key add failed");
         }
 
       m_key.addr = m->external_addr;
@@ -946,7 +976,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, 1))
-            clib_warning ("out2in key add failed");
+            nat_log_warn ("out2in key add failed");
         }
 
       /* Delete dynamic sessions matching local address (+ local port) */
@@ -979,10 +1009,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                         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);
-                      pool_put (tsm->sessions, s);
-                      u->nsessions--;
+                      nat44_delete_session (sm, s, tsm - sm->per_thread_data);
 
                       if (!addr_only)
                         break;
@@ -1023,7 +1050,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       foreach_snat_protocol
 #undef _
                     default:
-                      clib_warning("unknown_protocol");
+                      nat_log_info ("unknown protocol");
                       return VNET_API_ERROR_INVALID_VALUE_2;
                     }
                   break;
@@ -1049,7 +1076,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->in2out, &kv, 0))
-            clib_warning ("in2out key del failed");
+            nat_log_warn ("in2out key del failed");
         }
 
       m_key.addr = m->external_addr;
@@ -1063,7 +1090,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 ("out2in key del failed");
+            nat_log_warn ("out2in key del failed");
         }
 
       /* Delete session(s) for static mapping if exist */
@@ -1104,15 +1131,12 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                         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);
-                      pool_put (tsm->sessions, s);
-                      u->nstaticsessions--;
+                      nat44_delete_session (sm, s, tsm - sm->per_thread_data);
 
                       if (!addr_only)
                         break;
                     }
-                  if (addr_only && (u->nstaticsessions == 0))
+                  if (addr_only && (u->nstaticsessions == 0) && (u->nsessions == 0))
                     {
                       pool_put (tsm->users, u);
                       clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
@@ -1246,7 +1270,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       foreach_snat_protocol
 #undef _
                     default:
-                      clib_warning("unknown_protocol");
+                      nat_log_info ("unknown protocol");
                       return VNET_API_ERROR_INVALID_VALUE_2;
                     }
                   break;
@@ -1277,7 +1301,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       kv.value = m - sm->static_mappings;
       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
         {
-          clib_warning ("static_mapping_by_external key add failed");
+          nat_log_err ("static_mapping_by_external key add failed");
           return VNET_API_ERROR_UNSPECIFIED;
         }
 
@@ -1297,7 +1321,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       kv.value = ~0ULL;
       if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
         {
-          clib_warning ("out2in key add failed");
+          nat_log_err ("out2in key add failed");
           return VNET_API_ERROR_UNSPECIFIED;
         }
 
@@ -1321,7 +1345,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
           kv.value = ~0ULL;
           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
             {
-              clib_warning ("in2out key add failed");
+              nat_log_err ("in2out key add failed");
               return VNET_API_ERROR_UNSPECIFIED;
             }
         }
@@ -1355,7 +1379,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       foreach_snat_protocol
 #undef _
                     default:
-                      clib_warning("unknown_protocol");
+                      nat_log_info ("unknown protocol");
                       return VNET_API_ERROR_INVALID_VALUE_2;
                     }
                   break;
@@ -1371,7 +1395,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       kv.key = m_key.as_u64;
       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
         {
-          clib_warning ("static_mapping_by_external key del failed");
+          nat_log_err ("static_mapping_by_external key del failed");
           return VNET_API_ERROR_UNSPECIFIED;
         }
 
@@ -1379,7 +1403,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       kv.key = m_key.as_u64;
       if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
         {
-          clib_warning ("outi2in key del failed");
+          nat_log_err ("outi2in key del failed");
           return VNET_API_ERROR_UNSPECIFIED;
         }
 
@@ -1393,7 +1417,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
               kv.key = m_key.as_u64;
               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
                 {
-                  clib_warning ("static_mapping_by_local key del failed");
+                  nat_log_err ("static_mapping_by_local key del failed");
                   return VNET_API_ERROR_UNSPECIFIED;
                 }
             }
@@ -1404,7 +1428,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
               kv.key = m_key.as_u64;
               if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
                 {
-                  clib_warning ("in2out key del failed");
+                  nat_log_err ("in2out key del failed");
                   return VNET_API_ERROR_UNSPECIFIED;
                 }
             }
@@ -1436,10 +1460,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                         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);
-                      pool_put (tsm->sessions, s);
-                      u->nstaticsessions--;
+                      nat44_delete_session (sm, s, tsm - sm->per_thread_data);
                     }
                 }
             }
@@ -1460,9 +1481,6 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
   snat_address_t *a = 0;
   snat_session_t *ses;
   u32 *ses_to_be_removed = 0, *ses_index;
-  clib_bihash_kv_8_8_t kv, value;
-  snat_user_key_t user_key;
-  snat_user_t *u;
   snat_main_per_thread_data_t *tsm;
   snat_static_mapping_t *m;
   snat_interface_t *interface;
@@ -1498,7 +1516,7 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
       /* Check if address is used in some static mapping */
       if (is_snat_address_used_in_static_mapping(sm, addr))
         {
-          clib_warning ("address used in static mapping");
+          nat_log_notice ("address used in static mapping");
           return VNET_API_ERROR_UNSPECIFIED;
         }
     }
@@ -1517,25 +1535,15 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
               {
                 ses->outside_address_index = ~0;
                 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
-                clib_dlist_remove (tsm->list_pool, ses->per_user_index);
-                pool_put_index (tsm->list_pool, ses->per_user_index);
                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
-                user_key.addr = ses->in2out.addr;
-                user_key.fib_index = ses->in2out.fib_index;
-                kv.key = user_key.as_u64;
-                if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
-                  {
-                    u = pool_elt_at_index (tsm->users, value.value);
-                    if (snat_is_session_static (ses))
-                      u->nstaticsessions--;
-                    else
-                      u->nsessions--;
-                  }
               }
           }));
 
           vec_foreach (ses_index, ses_to_be_removed)
-            pool_put_index (tsm->sessions, ses_index[0]);
+            {
+              ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
+              nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
+            }
 
           vec_free (ses_to_be_removed);
        }
@@ -1601,10 +1609,12 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
     }
 
   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
-    sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
+    sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
+                                                      NAT_FQ_NELTS);
 
   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
-    sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
+    sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
+                                                      NAT_FQ_NELTS);
 
   pool_foreach (i, sm->interfaces,
   ({
@@ -1895,6 +1905,7 @@ static clib_error_t * snat_init (vlib_main_t * vm)
   uword *bitmap = 0;
   u32 i;
   ip4_add_del_interface_address_callback_t cb4;
+  vlib_node_t * error_drop_node;
 
   sm->vlib_main = vm;
   sm->vnet_main = vnet_get_main();
@@ -1915,6 +1926,9 @@ static clib_error_t * snat_init (vlib_main_t * vm)
   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
   sm->forwarding_enabled = 0;
+  sm->log_class = vlib_log_register_class ("nat", 0);
+  error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
+  sm->error_node_index = error_drop_node->index;
 
   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
   if (p)
@@ -2003,7 +2017,7 @@ void snat_free_outside_address_and_port (snat_address_t * addresses,
       foreach_snat_protocol
 #undef _
     default:
-      clib_warning("unknown_protocol");
+      nat_log_info ("unknown protocol");
       return;
     }
 }
@@ -2179,7 +2193,7 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses,
           foreach_snat_protocol
 #undef _
         default:
-          clib_warning("unknown protocol");
+          nat_log_info ("unknown protocol");
           return 1;
         }
 
@@ -2211,7 +2225,7 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses,
          foreach_snat_protocol
 #undef _
        default:
-         clib_warning ("unknown protocol");
+         nat_log_info ("unknown protocol");
          return 1;
        }
     }
@@ -2264,7 +2278,7 @@ nat_alloc_addr_and_port_mape (snat_address_t * addresses,
       foreach_snat_protocol
 #undef _
     default:
-      clib_warning("unknown protocol");
+      nat_log_info ("unknown protocol");
       return 1;
     }
 
@@ -2330,6 +2344,65 @@ format_snat_protocol (u8 * s, va_list * args)
   return s;
 }
 
+u8 * format_snat_key (u8 * s, va_list * args);
+
+u8 *
+format_session_kvp (u8 * s, va_list * args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+  snat_session_key_t k;
+
+  k.as_u64 = v->key;
+
+  s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
+
+  return s;
+}
+
+u8 *
+format_static_mapping_kvp (u8 * s, va_list * args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+  snat_session_key_t k;
+
+  k.as_u64 = v->key;
+
+  s = format (s, "%U static-mapping-index %llu", format_snat_key, &k, v->value);
+
+  return s;
+}
+
+u8 *
+format_user_kvp (u8 * s, va_list * args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+  snat_user_key_t k;
+
+  k.as_u64 = v->key;
+
+  s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
+              k.fib_index, v->value);
+
+  return s;
+}
+
+u8 *
+format_ed_session_kvp (u8 * s, va_list * args)
+{
+  clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
+  nat_ed_ses_key_t k;
+
+  k.as_u64[0] = v->key[0];
+  k.as_u64[1] = v->key[1];
+
+  s = format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
+              format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
+              format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
+              format_ip_protocol, k.proto, k.fib_index, v->value);
+
+  return s;
+}
+
 static u32
 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
 {
@@ -2615,19 +2688,29 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
             {
               clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
                                     translation_memory_size);
+              clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
+                                                 format_session_kvp);
 
               clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
                                     translation_memory_size);
+              clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
+                                                 format_session_kvp);
 
               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
                                     user_memory_size);
+              clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
+                                                 format_user_kvp);
             }
 
           clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
                                  translation_buckets, translation_memory_size);
+          clib_bihash_set_kvp_format_fn_16_8 (&sm->in2out_ed,
+                                              format_ed_session_kvp);
 
           clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
                                  translation_buckets, translation_memory_size);
+          clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
+                                              format_ed_session_kvp);
         }
       else
         {
@@ -2637,10 +2720,14 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
                             "static_mapping_by_local", static_mapping_buckets,
                             static_mapping_memory_size);
+      clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
+                                         format_static_mapping_kvp);
 
       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
                             "static_mapping_by_external", static_mapping_buckets,
                             static_mapping_memory_size);
+      clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
+                                         format_static_mapping_kvp);
     }
 
   return 0;
@@ -2678,7 +2765,7 @@ u8 * format_snat_key (u8 * s, va_list * args)
 
 u8 * format_snat_session (u8 * s, va_list * args)
 {
-  snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
+  snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
   snat_session_t * sess = va_arg (*args, snat_session_t *);
 
   if (snat_is_unk_proto_session (sess))
@@ -2715,6 +2802,7 @@ u8 * format_snat_session (u8 * s, va_list * args)
                           clib_net_to_host_u16 (sess->ext_host_port));
         }
     }
+  s = format (s, "       index %llu\n", sess - sm->sessions);
   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);
@@ -2724,7 +2812,7 @@ u8 * format_snat_session (u8 * s, va_list * args)
     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)
+  if (is_lb_session (sess))
     s = format (s, "       load-balancing\n");
   if (is_twice_nat_session (sess))
     s = format (s, "       twice-nat\n");
@@ -2931,7 +3019,7 @@ match:
                                 !is_delete,
                                 0, 0, rp->tag);
   if (rv)
-    clib_warning ("snat_add_static_mapping returned %d", rv);
+    nat_log_notice ("snat_add_static_mapping returned %d", rv);
 }
 
 static void
@@ -3002,8 +3090,7 @@ match:
                                             rp->is_add,
                                             0, 0, rp->tag);
               if (rv)
-                clib_warning ("snat_add_static_mapping returned %d",
-                              rv);
+                nat_log_notice ("snat_add_static_mapping returned %d", rv);
             }
         }
       return;
@@ -3093,8 +3180,6 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
   snat_session_key_t key;
   snat_session_t *s;
   clib_bihash_8_8_t *t;
-  snat_user_key_t u_key;
-  snat_user_t *u;
 
   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
   if (sm->num_workers > 1)
@@ -3116,24 +3201,8 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
         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);
-      kv.key = s->out2in.as_u64;
-      clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
-      u_key.addr = s->in2out.addr;
-      u_key.fib_index = s->in2out.fib_index;
-      kv.key = u_key.as_u64;
-      if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
-        {
-          u = pool_elt_at_index (tsm->users, value.value);
-          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);
+      nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+      nat44_delete_session (sm, s, tsm - sm->per_thread_data);
       return 0;
     }
 
index f889976..9de65d9 100644 (file)
@@ -28,6 +28,7 @@
 #include <vppinfra/dlist.h>
 #include <vppinfra/error.h>
 #include <vlibapi/api.h>
+#include <vlib/log.h>
 
 
 #define SNAT_UDP_TIMEOUT 300
@@ -37,6 +38,8 @@
 #define SNAT_TCP_INCOMING_SYN 6
 #define SNAT_ICMP_TIMEOUT 60
 
+#define NAT_FQ_NELTS 64
+
 #define SNAT_FLAG_HAIRPINNING (1 << 0)
 
 /* Key */
@@ -131,7 +134,7 @@ typedef enum {
 #define NAT44_SES_I2O_FIN_ACK 4
 #define NAT44_SES_O2I_FIN_ACK 8
 
-#define nat44_is_ses_closed(s) (s->state == 0xf)
+#define nat44_is_ses_closed(s) s->state == 0xf
 
 #define SNAT_SESSION_FLAG_STATIC_MAPPING       1
 #define SNAT_SESSION_FLAG_UNKNOWN_PROTO        2
@@ -370,6 +373,7 @@ typedef struct snat_main_s {
   u32 in2out_node_index;
   u32 in2out_output_node_index;
   u32 out2in_node_index;
+  u32 error_node_index;
 
   /* Deterministic NAT */
   snat_det_map_t * det_maps;
@@ -402,6 +406,9 @@ typedef struct snat_main_s {
   /* API message ID base */
   u16 msg_id_base;
 
+  /* log class */
+  vlib_log_class_t log_class;
+
   /* convenience */
   vlib_main_t * vlib_main;
   vnet_main_t * vnet_main;
@@ -453,6 +460,7 @@ void snat_add_del_addr_to_fib (ip4_address_t * addr,
 format_function_t format_snat_user;
 format_function_t format_snat_static_mapping;
 format_function_t format_snat_static_map_to_resolve;
+format_function_t format_snat_session;
 format_function_t format_det_map_ses;
 
 typedef struct {
@@ -499,6 +507,17 @@ typedef struct {
 #define nat_interface_is_inside(i) i->flags & NAT_INTERFACE_FLAG_IS_INSIDE
 #define nat_interface_is_outside(i) i->flags & NAT_INTERFACE_FLAG_IS_OUTSIDE
 
+#define nat_log_err(...) \
+  vlib_log(VLIB_LOG_LEVEL_ERR, snat_main.log_class, __VA_ARGS__)
+#define nat_log_warn(...) \
+  vlib_log(VLIB_LOG_LEVEL_WARNING, snat_main.log_class, __VA_ARGS__)
+#define nat_log_notice(...) \
+  vlib_log(VLIB_LOG_LEVEL_NOTICE, snat_main.log_class, __VA_ARGS__)
+#define nat_log_info(...) \
+  vlib_log(VLIB_LOG_LEVEL_INFO, snat_main.log_class, __VA_ARGS__)
+#define nat_log_debug(...)\
+  vlib_log(VLIB_LOG_LEVEL_DEBUG, snat_main.log_class, __VA_ARGS__)
+
 /*
  * Why is this here? Because we don't need to touch this layer to
  * simply reply to an icmp. We need to change id to a unique
@@ -510,31 +529,6 @@ typedef struct {
   u16 sequence;
 } icmp_echo_header_t;
 
-always_inline u32
-ip_proto_to_snat_proto (u8 ip_proto)
-{
-  u32 snat_proto = ~0;
-
-  snat_proto = (ip_proto == IP_PROTOCOL_UDP) ? SNAT_PROTOCOL_UDP : snat_proto;
-  snat_proto = (ip_proto == IP_PROTOCOL_TCP) ? SNAT_PROTOCOL_TCP : snat_proto;
-  snat_proto = (ip_proto == IP_PROTOCOL_ICMP) ? SNAT_PROTOCOL_ICMP : snat_proto;
-  snat_proto = (ip_proto == IP_PROTOCOL_ICMP6) ? SNAT_PROTOCOL_ICMP : snat_proto;
-
-  return snat_proto;
-}
-
-always_inline u8
-snat_proto_to_ip_proto (snat_protocol_t snat_proto)
-{
-  u8 ip_proto = ~0;
-
-  ip_proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : ip_proto;
-  ip_proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : ip_proto;
-  ip_proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : ip_proto;
-
-  return ip_proto;
-}
-
 typedef struct {
   u16 src_port, dst_port;
 } tcp_udp_header_t;
@@ -609,165 +603,4 @@ void nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset,
                                        u16 psid_length);
 void nat_set_alloc_addr_and_port_default (void);
 
-static_always_inline u8
-icmp_is_error_message (icmp46_header_t * icmp)
-{
-  switch(icmp->type)
-    {
-    case ICMP4_destination_unreachable:
-    case ICMP4_time_exceeded:
-    case ICMP4_parameter_problem:
-    case ICMP4_source_quench:
-    case ICMP4_redirect:
-    case ICMP4_alternate_host_address:
-      return 1;
-    }
-  return 0;
-}
-
-static_always_inline u8
-is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0,
-                  u32 ip4_addr)
-{
-  snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
-  ip4_address_t * first_int_addr;
-
-  if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0))
-    {
-      first_int_addr =
-        ip4_interface_first_address (sm->ip4_main, sw_if_index0,
-                                     0 /* just want the address */);
-      rt->cached_sw_if_index = sw_if_index0;
-      if (first_int_addr)
-        rt->cached_ip4_address = first_int_addr->as_u32;
-      else
-        rt->cached_ip4_address = 0;
-    }
-
-  if (PREDICT_FALSE(ip4_addr == rt->cached_ip4_address))
-    return 1;
-  else
-    return 0;
-}
-
-always_inline u8
-maximum_sessions_exceeded (snat_main_t *sm, u32 thread_index)
-{
-  if (pool_elts (sm->per_thread_data[thread_index].sessions) >= sm->max_translations)
-    return 1;
-
-  return 0;
-}
-
-static_always_inline void
-nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector,
-                     vlib_node_runtime_t *node, vlib_error_t *error, u32 next)
-{
-  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
-
-  from = bi_vector;
-  n_left_from = vec_len(bi_vector);
-  next_index = node->cached_next_index;
-  while (n_left_from > 0) {
-    vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
-    while (n_left_from > 0 && n_left_to_next > 0) {
-      u32 bi0 = to_next[0] = from[0];
-      from += 1;
-      n_left_from -= 1;
-      to_next += 1;
-      n_left_to_next -= 1;
-      vlib_buffer_t *p0 = vlib_get_buffer(vm, bi0);
-      p0->error = *error;
-      vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
-                                      n_left_to_next, bi0, next);
-    }
-    vlib_put_next_frame(vm, node, next_index, n_left_to_next);
-  }
-}
-
-always_inline void
-user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
-{
-  if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user)
-    {
-      if (is_static)
-       u->nstaticsessions++;
-      else
-       u->nsessions++;
-    }
-}
-
-always_inline void
-nat44_delete_session(snat_main_t * sm, snat_session_t * ses, u32 thread_index)
-{
-  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
-                                                       thread_index);
-  clib_bihash_kv_8_8_t kv, value;
-  snat_user_key_t u_key;
-  snat_user_t *u;
-  u_key.addr = ses->in2out.addr;
-  u_key.fib_index = ses->in2out.fib_index;
-  kv.key = u_key.as_u64;
-  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
-    {
-      u = pool_elt_at_index (tsm->users, value.value);
-      if (snat_is_session_static(ses))
-        u->nstaticsessions--;
-      else
-        u->nsessions--;
-    }
-  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
-  pool_put_index (tsm->list_pool, ses->per_user_index);
-  pool_put (tsm->sessions, ses);
-}
-
-/** \brief Set TCP session state.
-    @return 1 if session was closed, otherwise 0
-*/
-always_inline int
-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->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);
-      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;
-}
-
 #endif /* __included_snat_h__ */
index efde4be..7a8be98 100644 (file)
@@ -20,6 +20,7 @@
 #include <nat/nat.h>
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_det.h>
+#include <nat/nat_inlines.h>
 #include <vnet/fib/fib_table.h>
 
 #define UNSUPPORTED_IN_DET_MODE_STR \
@@ -181,6 +182,8 @@ nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
   vec_foreach_index (i, sm->per_thread_data)
   {
     tsm = vec_elt_at_index (sm->per_thread_data, i);
+    vlib_cli_output (vm, "-------- thread %d %s --------\n",
+                    i, vlib_worker_threads[i].name);
     vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->in2out, verbose);
     vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->out2in, verbose);
     vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->user_hash, verbose);
@@ -292,7 +295,7 @@ add_address_command_fn (vlib_main_t * vm,
   count = (end_host_order - start_host_order) + 1;
 
   if (count > 1024)
-    clib_warning ("%U - %U, %d addresses...",
+    nat_log_info ("%U - %U, %d addresses...",
                  format_ip4_address, &start_addr,
                  format_ip4_address, &end_addr, count);
 
@@ -942,6 +945,8 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
     {
       tsm = vec_elt_at_index (sm->per_thread_data, i);
 
+      vlib_cli_output (vm, "-------- thread %d %s --------\n",
+                       i, vlib_worker_threads[i].name);
       pool_foreach (u, tsm->users,
       ({
         vlib_cli_output (vm, "  %U", format_snat_user, tsm, u, verbose);
index 0b7536f..53c2cab 100644 (file)
@@ -20,6 +20,7 @@
 #include <nat/nat64.h>
 #include <nat/nat64_db.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vppinfra/crc32.h>
 
index 5b46fed..c2639f4 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <nat/nat64.h>
 #include <nat/nat.h>
+#include <nat/nat_inlines.h>
 #include <vnet/fib/fib_table.h>
 
 static clib_error_t *
index 3edc1a4..9ff68c8 100644 (file)
@@ -18,6 +18,7 @@
  */
 #include <nat/nat64_db.h>
 #include <nat/nat_ipfix_logging.h>
+#include <nat/nat_inlines.h>
 #include <vnet/fib/fib_table.h>
 
 int
index ef322d5..603b30e 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <nat/nat64.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 #include <vnet/ip/ip6_to_ip4.h>
 #include <vnet/fib/fib_table.h>
 
index 17513c5..f43d3e0 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <nat/nat64.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 #include <vnet/ip/ip4_to_ip6.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/udp/udp.h>
index 11a6f0f..f5f4161 100644 (file)
@@ -24,6 +24,7 @@
 #include <nat/nat66.h>
 #include <nat/dslite.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 #include <vlibapi/api.h>
 #include <vlibmemory/api.h>
 
@@ -444,7 +445,7 @@ static void
   vrf_id = clib_host_to_net_u32 (mp->vrf_id);
 
   if (count > 1024)
-    clib_warning ("%U - %U, %d addresses...",
+    nat_log_info ("%U - %U, %d addresses...",
                  format_ip4_address, mp->first_ip_address,
                  format_ip4_address, mp->last_ip_address, count);
 
diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h
new file mode 100644 (file)
index 0000000..db5b295
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @brief The NAT inline functions
+ */
+
+#ifndef __included_nat_inlines_h__
+#define __included_nat_inlines_h__
+
+#include <nat/nat.h>
+
+always_inline u32
+ip_proto_to_snat_proto (u8 ip_proto)
+{
+  u32 snat_proto = ~0;
+
+  snat_proto = (ip_proto == IP_PROTOCOL_UDP) ? SNAT_PROTOCOL_UDP : snat_proto;
+  snat_proto = (ip_proto == IP_PROTOCOL_TCP) ? SNAT_PROTOCOL_TCP : snat_proto;
+  snat_proto =
+    (ip_proto == IP_PROTOCOL_ICMP) ? SNAT_PROTOCOL_ICMP : snat_proto;
+  snat_proto =
+    (ip_proto == IP_PROTOCOL_ICMP6) ? SNAT_PROTOCOL_ICMP : snat_proto;
+
+  return snat_proto;
+}
+
+always_inline u8
+snat_proto_to_ip_proto (snat_protocol_t snat_proto)
+{
+  u8 ip_proto = ~0;
+
+  ip_proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : ip_proto;
+  ip_proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : ip_proto;
+  ip_proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : ip_proto;
+
+  return ip_proto;
+}
+
+static_always_inline u8
+icmp_is_error_message (icmp46_header_t * icmp)
+{
+  switch (icmp->type)
+    {
+    case ICMP4_destination_unreachable:
+    case ICMP4_time_exceeded:
+    case ICMP4_parameter_problem:
+    case ICMP4_source_quench:
+    case ICMP4_redirect:
+    case ICMP4_alternate_host_address:
+      return 1;
+    }
+  return 0;
+}
+
+always_inline u8
+is_interface_addr (snat_main_t * sm, vlib_node_runtime_t * node,
+                  u32 sw_if_index0, u32 ip4_addr)
+{
+  snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
+  ip4_address_t *first_int_addr;
+
+  if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
+    {
+      first_int_addr =
+       ip4_interface_first_address (sm->ip4_main, sw_if_index0,
+                                    0 /* just want the address */ );
+      rt->cached_sw_if_index = sw_if_index0;
+      if (first_int_addr)
+       rt->cached_ip4_address = first_int_addr->as_u32;
+      else
+       rt->cached_ip4_address = 0;
+    }
+
+  if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
+    return 1;
+  else
+    return 0;
+}
+
+always_inline u8
+maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
+{
+  if (pool_elts (sm->per_thread_data[thread_index].sessions) >=
+      sm->max_translations)
+    return 1;
+
+  return 0;
+}
+
+always_inline void
+nat_send_all_to_node (vlib_main_t * vm, u32 * bi_vector,
+                     vlib_node_runtime_t * node, vlib_error_t * error,
+                     u32 next)
+{
+  u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
+
+  from = bi_vector;
+  n_left_from = vec_len (bi_vector);
+  next_index = node->cached_next_index;
+  while (n_left_from > 0)
+    {
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 bi0 = to_next[0] = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next += 1;
+         n_left_to_next -= 1;
+         vlib_buffer_t *p0 = vlib_get_buffer (vm, bi0);
+         p0->error = *error;
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+}
+
+always_inline void
+user_session_increment (snat_main_t * sm, snat_user_t * u, u8 is_static)
+{
+  if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user)
+    {
+      if (is_static)
+       u->nstaticsessions++;
+      else
+       u->nsessions++;
+    }
+}
+
+always_inline void
+nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
+                     u32 thread_index)
+{
+  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
+                                                      thread_index);
+  clib_bihash_kv_8_8_t kv, value;
+  snat_user_key_t u_key;
+  snat_user_t *u;
+
+  nat_log_debug ("session deleted %U", format_snat_session, tsm, ses);
+  u_key.addr = ses->in2out.addr;
+  u_key.fib_index = ses->in2out.fib_index;
+  kv.key = u_key.as_u64;
+  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+    {
+      u = pool_elt_at_index (tsm->users, value.value);
+      if (snat_is_session_static (ses))
+       u->nstaticsessions--;
+      else
+       u->nsessions--;
+    }
+  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
+  pool_put_index (tsm->list_pool, ses->per_user_index);
+  pool_put (tsm->sessions, ses);
+}
+
+/** \brief Set TCP session state.
+    @return 1 if session was closed, otherwise 0
+*/
+always_inline int
+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->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_log_debug ("TCP close connection %U", format_snat_session,
+                    &sm->per_thread_data[thread_index], ses);
+      nat_free_session_data (sm, ses, thread_index);
+      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_log_debug ("TCP close connection %U", format_snat_session,
+                    &sm->per_thread_data[thread_index], ses);
+      nat_free_session_data (sm, ses, thread_index);
+      nat44_delete_session (sm, ses, thread_index);
+      return 1;
+    }
+  return 0;
+}
+
+always_inline void
+nat44_session_update_counters (snat_session_t * s, f64 now, uword bytes)
+{
+  s->last_heard = now;
+  s->total_pkts++;
+  s->total_bytes += bytes;
+}
+
+/** \brief Per-user LRU list maintenance */
+always_inline void
+nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
+                         u32 thread_index)
+{
+  clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
+                    s->per_user_index);
+  clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
+                     s->per_user_list_head_index, s->per_user_index);
+}
+
+#endif /* __included_nat_inlines_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 0f29133..4a61fb0 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <vnet/ipfix-export/flow_report.h>
 #include <vlibmemory/api.h>
+#include <nat/nat_inlines.h>
 #include <nat/nat_ipfix_logging.h>
 
 snat_ipfix_logging_main_t snat_ipfix_logging_main;
index c7eece8..83e1426 100755 (executable)
@@ -26,6 +26,7 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_det.h>
 #include <nat/nat_reass.h>
+#include <nat/nat_inlines.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
@@ -113,7 +114,8 @@ _(NO_TRANSLATION, "No translation")                     \
 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded")   \
 _(DROP_FRAGMENT, "Drop fragment")                       \
 _(MAX_REASS, "Maximum reassemblies exceeded")           \
-_(MAX_FRAG, "Maximum fragments per reassembly exceeded")
+_(MAX_FRAG, "Maximum fragments per reassembly exceeded")\
+_(FQ_CONGESTED, "Handoff frame queue congested")
 
 typedef enum {
 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
@@ -168,6 +170,7 @@ create_session_for_static_mapping (snat_main_t *sm,
   if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
     {
       b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
+      nat_log_notice ("maximum sessions exceeded");
       return 0;
     }
 
@@ -177,14 +180,14 @@ create_session_for_static_mapping (snat_main_t *sm,
   u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
   if (!u)
     {
-      clib_warning ("create NAT user failed");
+      nat_log_warn ("create NAT user failed");
       return 0;
     }
 
   s = nat_session_alloc_or_recycle (sm, u, thread_index);
   if (!s)
     {
-      clib_warning ("create NAT session failed");
+      nat_log_warn ("create NAT session failed");
       return 0;
     }
 
@@ -202,13 +205,13 @@ create_session_for_static_mapping (snat_main_t *sm,
   kv0.value = s - sm->per_thread_data[thread_index].sessions;
   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
                                1 /* is_add */))
-      clib_warning ("in2out key add failed");
+      nat_log_notice ("in2out key add failed");
 
   kv0.key = s->out2in.as_u64;
 
   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
                                1 /* is_add */))
-      clib_warning ("out2in key add failed");
+      nat_log_notice ("out2in key add failed");
 
   /* log NAT event */
   snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
@@ -381,14 +384,14 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
       u = nat_user_get_or_create (sm, &ip->dst_address, sm->inside_fib_index, thread_index);
       if (!u)
         {
-          clib_warning ("create NAT user failed");
+          nat_log_warn ("create NAT user failed");
           return;
         }
 
       s = nat_session_alloc_or_recycle (sm, u, thread_index);
       if (!s)
         {
-          clib_warning ("create NAT session failed");
+          nat_log_warn ("create NAT session failed");
           return;
         }
 
@@ -405,7 +408,7 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
 
       kv.value = s - tsm->sessions;
       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1))
-        clib_warning ("in2out_ed key add failed");
+        nat_log_notice ("in2out_ed key add failed");
     }
 
   if (ip->protocol == IP_PROTOCOL_TCP)
@@ -415,12 +418,9 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_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);
+  nat44_session_update_lru (sm, s, thread_index);
   /* Accounting */
-  s->last_heard = now;
-  s->total_pkts++;
+  nat44_session_update_counters (s, now, 0);
 }
 
 /**
@@ -789,15 +789,10 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm,
   if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
     {
       /* Accounting */
-      s0->last_heard = now;
-      s0->total_pkts++;
-      s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
+      nat44_session_update_counters (s0, now,
+                                     vlib_buffer_length_in_chain (sm->vlib_main, b0));
       /* Per-user LRU list maintenance */
-      clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                         s0->per_user_index);
-      clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                          s0->per_user_list_head_index,
-                          s0->per_user_index);
+      nat44_session_update_lru (sm, s0, thread_index);
     }
   return next0;
 }
@@ -844,6 +839,7 @@ snat_out2in_unknown_proto (snat_main_t *sm,
       if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
         {
           b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
+          nat_log_notice ("maximum sessions exceeded");
           return 0;
         }
 
@@ -866,7 +862,7 @@ snat_out2in_unknown_proto (snat_main_t *sm,
                                   thread_index);
       if (!u)
         {
-          clib_warning ("create NAT user failed");
+          nat_log_warn ("create NAT user failed");
           return 0;
         }
 
@@ -874,7 +870,7 @@ snat_out2in_unknown_proto (snat_main_t *sm,
       s = nat_session_alloc_or_recycle (sm, u, thread_index);
       if (!s)
         {
-          clib_warning ("create NAT session failed");
+          nat_log_warn ("create NAT session failed");
           return 0;
         }
 
@@ -893,14 +889,14 @@ snat_out2in_unknown_proto (snat_main_t *sm,
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
-        clib_warning ("out2in key add failed");
+        nat_log_notice ("out2in key add failed");
 
       key.l_addr = ip->dst_address;
       key.fib_index = m->fib_index;
       s_kv.key[0] = key.as_u64[0];
       s_kv.key[1] = key.as_u64[1];
       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
-        clib_warning ("in2out key add failed");
+        nat_log_notice ("in2out key add failed");
    }
 
   /* Update IP checksum */
@@ -911,13 +907,10 @@ snat_out2in_unknown_proto (snat_main_t *sm,
   vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
 
   /* Accounting */
-  s->last_heard = now;
-  s->total_pkts++;
-  s->total_bytes += vlib_buffer_length_in_chain (vm, b);
+  nat44_session_update_counters (s, now,
+                                 vlib_buffer_length_in_chain (vm, b));
   /* 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);
+  nat44_session_update_lru (sm, s, thread_index);
 
   return s;
 }
@@ -969,6 +962,7 @@ snat_out2in_lb (snat_main_t *sm,
       if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
         {
           b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
+          nat_log_notice ("maximum sessions exceeded");
           return 0;
         }
 
@@ -983,14 +977,14 @@ snat_out2in_lb (snat_main_t *sm,
                                   thread_index);
       if (!u)
       {
-        clib_warning ("create NAT user failed");
+        nat_log_warn ("create NAT user failed");
         return 0;
       }
 
       s = nat_session_alloc_or_recycle (sm, u, thread_index);
       if (!s)
         {
-          clib_warning ("create NAT session failed");
+          nat_log_warn ("create NAT session failed");
           return 0;
         }
 
@@ -1008,7 +1002,7 @@ snat_out2in_lb (snat_main_t *sm,
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
-        clib_warning ("out2in-ed key add failed");
+        nat_log_notice ("out2in-ed key add failed");
 
       if (twice_nat == TWICE_NAT ||
           (twice_nat == TWICE_NAT_SELF &&
@@ -1034,7 +1028,7 @@ snat_out2in_lb (snat_main_t *sm,
       s_kv.key[0] = key.as_u64[0];
       s_kv.key[1] = key.as_u64[1];
       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
-        clib_warning ("in2out-ed key add failed");
+        nat_log_notice ("in2out-ed key add failed");
     }
 
   new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
@@ -1085,13 +1079,9 @@ snat_out2in_lb (snat_main_t *sm,
     }
 
   /* Accounting */
-  s->last_heard = now;
-  s->total_pkts++;
-  s->total_bytes += vlib_buffer_length_in_chain (vm, b);
+  nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b));
   /* 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);
+  nat44_session_update_lru (sm, s, thread_index);
 
   return s;
 }
@@ -1321,15 +1311,10 @@ snat_out2in_node_fn (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s0->last_heard = now;
-          s0->total_pkts++;
-          s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
+          nat44_session_update_counters (s0, now,
+                                         vlib_buffer_length_in_chain (vm, b0));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s0->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s0->per_user_list_head_index,
-                              s0->per_user_index);
+          nat44_session_update_lru (sm, s0, thread_index);
         trace0:
 
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -1499,15 +1484,10 @@ snat_out2in_node_fn (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s1->last_heard = now;
-          s1->total_pkts++;
-          s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
+          nat44_session_update_counters (s1, now,
+                                         vlib_buffer_length_in_chain (vm, b1));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s1->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s1->per_user_list_head_index,
-                              s1->per_user_index);
+          nat44_session_update_lru (sm, s1, thread_index);
         trace1:
 
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -1713,15 +1693,10 @@ snat_out2in_node_fn (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s0->last_heard = now;
-          s0->total_pkts++;
-          s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
+          nat44_session_update_counters (s0, now,
+                                         vlib_buffer_length_in_chain (vm, b0));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s0->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s0->per_user_list_head_index,
-                              s0->per_user_index);
+          nat44_session_update_lru (sm, s0, thread_index);
         trace00:
 
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -1858,6 +1833,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
             {
               next0 = SNAT_OUT2IN_NEXT_DROP;
               b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
+              nat_log_notice ("maximum reassemblies exceeded");
               goto trace0;
             }
 
@@ -1934,6 +1910,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
                   if (nat_ip4_reass_add_fragment (reass0, bi0))
                     {
                       b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
+                      nat_log_notice ("maximum fragments per reassembly exceeded");
                       next0 = SNAT_OUT2IN_NEXT_DROP;
                       goto trace0;
                     }
@@ -1982,15 +1959,10 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
             }
 
           /* Accounting */
-          s0->last_heard = now;
-          s0->total_pkts++;
-          s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
+          nat44_session_update_counters (s0, now,
+                                         vlib_buffer_length_in_chain (vm, b0));
           /* Per-user LRU list maintenance */
-          clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                             s0->per_user_index);
-          clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                              s0->per_user_list_head_index,
-                              s0->per_user_index);
+          nat44_session_update_lru (sm, s0, thread_index);
 
         trace0:
           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
@@ -2185,8 +2157,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm,
           dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
           if (PREDICT_FALSE(!dm0))
             {
-              clib_warning("unknown dst address:  %U",
-                           format_ip4_address, &ip0->dst_address);
+              nat_log_info ("unknown dst address:  %U",
+                            format_ip4_address, &ip0->dst_address);
               next0 = SNAT_OUT2IN_NEXT_DROP;
               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace0;
@@ -2198,12 +2170,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm,
           ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
           if (PREDICT_FALSE(!ses0))
             {
-              clib_warning("no match src %U:%d dst %U:%d for user %U",
-                           format_ip4_address, &ip0->src_address,
-                           clib_net_to_host_u16 (tcp0->src),
-                           format_ip4_address, &ip0->dst_address,
-                           clib_net_to_host_u16 (tcp0->dst),
-                           format_ip4_address, &new_addr0);
+              nat_log_info ("no match src %U:%d dst %U:%d for user %U",
+                            format_ip4_address, &ip0->src_address,
+                            clib_net_to_host_u16 (tcp0->src),
+                            format_ip4_address, &ip0->dst_address,
+                            clib_net_to_host_u16 (tcp0->dst),
+                            format_ip4_address, &new_addr0);
               next0 = SNAT_OUT2IN_NEXT_DROP;
               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace0;
@@ -2301,8 +2273,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm,
           dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
           if (PREDICT_FALSE(!dm1))
             {
-              clib_warning("unknown dst address:  %U",
-                           format_ip4_address, &ip1->dst_address);
+              nat_log_info ("unknown dst address:  %U",
+                            format_ip4_address, &ip1->dst_address);
               next1 = SNAT_OUT2IN_NEXT_DROP;
               b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace1;
@@ -2314,12 +2286,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm,
           ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
           if (PREDICT_FALSE(!ses1))
             {
-              clib_warning("no match src %U:%d dst %U:%d for user %U",
-                           format_ip4_address, &ip1->src_address,
-                           clib_net_to_host_u16 (tcp1->src),
-                           format_ip4_address, &ip1->dst_address,
-                           clib_net_to_host_u16 (tcp1->dst),
-                           format_ip4_address, &new_addr1);
+              nat_log_info ("no match src %U:%d dst %U:%d for user %U",
+                            format_ip4_address, &ip1->src_address,
+                            clib_net_to_host_u16 (tcp1->src),
+                            format_ip4_address, &ip1->dst_address,
+                            clib_net_to_host_u16 (tcp1->dst),
+                            format_ip4_address, &new_addr1);
               next1 = SNAT_OUT2IN_NEXT_DROP;
               b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace1;
@@ -2450,8 +2422,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm,
           dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
           if (PREDICT_FALSE(!dm0))
             {
-              clib_warning("unknown dst address:  %U",
-                           format_ip4_address, &ip0->dst_address);
+              nat_log_info ("unknown dst address:  %U",
+                            format_ip4_address, &ip0->dst_address);
               next0 = SNAT_OUT2IN_NEXT_DROP;
               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace00;
@@ -2463,12 +2435,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm,
           ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
           if (PREDICT_FALSE(!ses0))
             {
-              clib_warning("no match src %U:%d dst %U:%d for user %U",
-                           format_ip4_address, &ip0->src_address,
-                           clib_net_to_host_u16 (tcp0->src),
-                           format_ip4_address, &ip0->dst_address,
-                           clib_net_to_host_u16 (tcp0->dst),
-                           format_ip4_address, &new_addr0);
+              nat_log_info ("no match src %U:%d dst %U:%d for user %U",
+                            format_ip4_address, &ip0->src_address,
+                            clib_net_to_host_u16 (tcp0->src),
+                            format_ip4_address, &ip0->dst_address,
+                            clib_net_to_host_u16 (tcp0->dst),
+                            format_ip4_address, &new_addr0);
               next0 = SNAT_OUT2IN_NEXT_DROP;
               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
               goto trace00;
@@ -2652,8 +2624,8 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node,
           dont_translate = 1;
           goto out;
         }
-      clib_warning("unknown dst address:  %U",
-                   format_ip4_address, &ip0->dst_address);
+      nat_log_info ("unknown dst address:  %U",
+                    format_ip4_address, &ip0->dst_address);
       goto out;
     }
 
@@ -2670,12 +2642,12 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node,
           dont_translate = 1;
           goto out;
         }
-      clib_warning("no match src %U:%d dst %U:%d for user %U",
-                   format_ip4_address, &key0.ext_host_addr,
-                   clib_net_to_host_u16 (key0.ext_host_port),
-                   format_ip4_address, &out_addr,
-                   clib_net_to_host_u16 (key0.out_port),
-                   format_ip4_address, &new_addr0);
+      nat_log_info ("no match src %U:%d dst %U:%d for user %U",
+                    format_ip4_address, &key0.ext_host_addr,
+                    clib_net_to_host_u16 (key0.ext_host_port),
+                    format_ip4_address, &out_addr,
+                    clib_net_to_host_u16 (key0.out_port),
+                    format_ip4_address, &new_addr0);
       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
       next0 = SNAT_OUT2IN_NEXT_DROP;
       goto out;
@@ -2717,17 +2689,19 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
-  u32 n_left_from, *from, *to_next = 0;
+  u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0;
   static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
   static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
     = 0;
   vlib_frame_queue_elt_t *hf = 0;
+  vlib_frame_queue_t *fq;
   vlib_frame_t *f = 0;
   int i;
   u32 n_left_to_next_worker = 0, *to_next_worker = 0;
   u32 next_worker_index = 0;
   u32 current_worker_index = ~0;
   u32 thread_index = vlib_get_thread_index ();
+  vlib_frame_t *d = 0;
 
   ASSERT (vec_len (sm->workers));
 
@@ -2736,7 +2710,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm,
       vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
 
       vec_validate_init_empty (congested_handoff_queue_by_worker_index,
-                              sm->first_worker_index + sm->num_workers - 1,
+                              tm->n_vlib_mains - 1,
                               (vlib_frame_queue_t *) (~0));
     }
 
@@ -2771,6 +2745,26 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm,
 
           if (next_worker_index != current_worker_index)
             {
+              fq = is_vlib_frame_queue_congested (
+                sm->fq_out2in_index, next_worker_index, NAT_FQ_NELTS - 2,
+                congested_handoff_queue_by_worker_index);
+
+              if (fq)
+                {
+                  /* if this is 1st frame */
+                  if (!d)
+                    {
+                      d = vlib_get_frame_to_node (vm, sm->error_node_index);
+                      to_next_drop = vlib_frame_vector_args (d);
+                    }
+
+                  to_next_drop[0] = bi0;
+                  to_next_drop += 1;
+                  d->n_vectors++;
+                  b0->error = node->errors[SNAT_OUT2IN_ERROR_FQ_CONGESTED];
+                  goto trace0;
+                }
+
               if (hf)
                 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
 
@@ -2812,6 +2806,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm,
           f->n_vectors++;
         }
 
+trace0:
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
@@ -2825,6 +2820,9 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm,
   if (f)
     vlib_put_frame_to_node (vm, sm->out2in_node_index, f);
 
+  if (d)
+    vlib_put_frame_to_node (vm, sm->error_node_index, d);
+
   if (hf)
     hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
 
@@ -2861,6 +2859,9 @@ VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = {
   .format_trace = format_snat_out2in_worker_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
+  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
+  .error_strings = snat_out2in_error_strings,
+
   .n_next_nodes = 1,
 
   .next_nodes = {
index e2f3465..ad2b964 100644 (file)
@@ -826,6 +826,7 @@ class TestNAT44(MethodHolder):
     @classmethod
     def setUpClass(cls):
         super(TestNAT44, cls).setUpClass()
+        cls.vapi.cli("set log class nat level debug")
 
         try:
             cls.tcp_port_in = 6303
@@ -2582,7 +2583,8 @@ class TestNAT44(MethodHolder):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
+        sleep(1)
         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
         capture = self.pg3.get_capture(9)
         ipfix = IPFIXDecoder()
@@ -2639,7 +2641,8 @@ class TestNAT44(MethodHolder):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
+        sleep(1)
         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
         capture = self.pg3.get_capture(9)
         ipfix = IPFIXDecoder()
@@ -2698,7 +2701,7 @@ class TestNAT44(MethodHolder):
         self.pg2.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
 
         # remove addresses and verify
         self.nat44_add_address(self.nat_addr, is_add=0)
@@ -2711,7 +2714,7 @@ class TestNAT44(MethodHolder):
         self.pg1.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
 
         p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') /
              ARP(op=ARP.who_has, pdst=static_addr,
@@ -2719,7 +2722,7 @@ class TestNAT44(MethodHolder):
         self.pg1.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
 
     def test_vrf_mode(self):
         """ NAT44 tenant VRF aware address pool mode """
@@ -3117,7 +3120,7 @@ class TestNAT44(MethodHolder):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture(1)
+        self.pg0.get_capture(1)
 
         p = (Ether(dst=self.pg0.local_mac, src=host.mac) /
              IP(src=host.ip4, dst=server_nat_ip) /
@@ -3608,7 +3611,7 @@ class TestNAT44(MethodHolder):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture(len(pkts))
+        self.pg1.get_capture(len(pkts))
 
         sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
         nsessions = len(sessions)
@@ -4018,7 +4021,8 @@ class TestNAT44(MethodHolder):
         self.pg0.add_stream(pkts[-1])
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        frags = self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
+        sleep(1)
         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
         capture = self.pg3.get_capture(9)
         ipfix = IPFIXDecoder()
@@ -4042,7 +4046,14 @@ class TestNAT44(MethodHolder):
 
     def test_tcp_session_close_in(self):
         """ Close TCP session from inside network """
+        self.tcp_port_out = 10505
         self.nat44_add_address(self.nat_addr)
+        self.nat44_add_static_mapping(self.pg0.remote_ip4,
+                                      self.nat_addr,
+                                      self.tcp_port_in,
+                                      self.tcp_port_out,
+                                      proto=IP_PROTOS.tcp,
+                                      twice_nat=1)
         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
                                                   is_inside=0)
@@ -4052,60 +4063,61 @@ class TestNAT44(MethodHolder):
 
         self.initiate_tcp_session(self.pg0, self.pg1)
 
-        # close the session from inside
-        try:
-            # FIN 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", seq=100, ack=300))
-            self.pg0.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg1.get_capture(1)
+        # FIN 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", seq=100, ack=300))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg1.get_capture(1)
 
-            pkts = []
+        pkts = []
 
-            # 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", seq=300, ack=101))
-            pkts.append(p)
+        # 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", 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", 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", seq=300, ack=101))
+        pkts.append(p)
 
-            self.pg1.add_stream(pkts)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg0.get_capture(2)
+        self.pg1.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg0.get_capture(2)
 
-            # 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", seq=101, ack=301))
-            self.pg0.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg1.get_capture(1)
+        # 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", seq=101, ack=301))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg1.get_capture(1)
 
-            self.initiate_tcp_session(self.pg0, self.pg1)
-            sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
-                                                         0)
-            self.assertEqual(len(sessions) - start_sessnum, 1)
-        except:
-            self.logger.error("TCP session termination failed")
-            raise
+        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
+                                                     0)
+        self.assertEqual(len(sessions) - start_sessnum, 0)
 
     def test_tcp_session_close_out(self):
         """ Close TCP session from outside network """
+        self.tcp_port_out = 10505
         self.nat44_add_address(self.nat_addr)
+        self.nat44_add_static_mapping(self.pg0.remote_ip4,
+                                      self.nat_addr,
+                                      self.tcp_port_in,
+                                      self.tcp_port_out,
+                                      proto=IP_PROTOS.tcp,
+                                      twice_nat=1)
         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
                                                   is_inside=0)
@@ -4115,50 +4127,51 @@ class TestNAT44(MethodHolder):
 
         self.initiate_tcp_session(self.pg0, self.pg1)
 
-        # close the session from outside
-        try:
-            # 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", seq=100, ack=300))
-            self.pg1.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg0.get_capture(1)
+        # 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", seq=100, ack=300))
+        self.pg1.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg0.get_capture(1)
 
-            # 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", seq=300, ack=101))
+        # 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", seq=300, ack=101))
 
-            self.pg0.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg1.get_capture(1)
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        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", seq=101, ack=301))
-            self.pg1.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg0.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", seq=101, ack=301))
+        self.pg1.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg0.get_capture(1)
 
-            self.initiate_tcp_session(self.pg0, self.pg1)
-            sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
-                                                         0)
-            self.assertEqual(len(sessions) - start_sessnum, 1)
-        except:
-            self.logger.error("TCP session termination failed")
-            raise
+        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
+                                                     0)
+        self.assertEqual(len(sessions) - start_sessnum, 0)
 
     def test_tcp_session_close_simultaneous(self):
         """ Close TCP session from inside network """
+        self.tcp_port_out = 10505
         self.nat44_add_address(self.nat_addr)
+        self.nat44_add_static_mapping(self.pg0.remote_ip4,
+                                      self.nat_addr,
+                                      self.tcp_port_in,
+                                      self.tcp_port_out,
+                                      proto=IP_PROTOS.tcp,
+                                      twice_nat=1)
         self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
         self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
                                                   is_inside=0)
@@ -4168,55 +4181,49 @@ class TestNAT44(MethodHolder):
 
         self.initiate_tcp_session(self.pg0, self.pg1)
 
-        # close the session from inside
-        try:
-            # FIN 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", seq=100, ack=300))
-            self.pg0.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg1.get_capture(1)
+        # FIN 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", seq=100, ack=300))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg1.get_capture(1)
 
-            # 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", seq=300, ack=100))
-            self.pg1.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg0.get_capture(1)
+        # 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", seq=300, ack=100))
+        self.pg1.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg0.get_capture(1)
 
-            # 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", seq=101, ack=301))
-            self.pg0.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg1.get_capture(1)
+        # 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", seq=101, ack=301))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        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", seq=301, ack=101))
-            self.pg1.add_stream(p)
-            self.pg_enable_capture(self.pg_interfaces)
-            self.pg_start()
-            self.pg0.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", seq=301, ack=101))
+        self.pg1.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg0.get_capture(1)
 
-            self.initiate_tcp_session(self.pg0, self.pg1)
-            sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
-                                                         0)
-            self.assertEqual(len(sessions) - start_sessnum, 1)
-        except:
-            self.logger.error("TCP session termination failed")
-            raise
+        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n,
+                                                     0)
+        self.assertEqual(len(sessions) - start_sessnum, 0)
 
     def tearDown(self):
         super(TestNAT44, self).tearDown()
@@ -4227,8 +4234,10 @@ class TestNAT44(MethodHolder):
             self.logger.info(self.vapi.cli("show nat44 interface address"))
             self.logger.info(self.vapi.cli("show nat44 sessions detail"))
             self.logger.info(self.vapi.cli("show nat virtual-reassembly"))
+            self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
             self.vapi.cli("nat addr-port-assignment-alg default")
             self.clear_nat44()
+            self.vapi.cli("clear logging")
 
 
 class TestNAT44Out2InDPO(MethodHolder):
@@ -4242,6 +4251,7 @@ class TestNAT44Out2InDPO(MethodHolder):
     @classmethod
     def setUpClass(cls):
         super(TestNAT44Out2InDPO, cls).setUpClass()
+        cls.vapi.cli("set log class nat level debug")
 
         try:
             cls.tcp_port_in = 6303
@@ -4359,6 +4369,7 @@ class TestDeterministicNAT(MethodHolder):
     @classmethod
     def setUpClass(cls):
         super(TestDeterministicNAT, cls).setUpClass()
+        cls.vapi.cli("set log class nat level debug")
 
         try:
             cls.tcp_port_in = 6303
@@ -5950,7 +5961,8 @@ class TestNAT64(MethodHolder):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
+        sleep(1)
         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
         capture = self.pg3.get_capture(9)
         ipfix = IPFIXDecoder()
@@ -5977,7 +5989,8 @@ class TestNAT64(MethodHolder):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
+        sleep(1)
         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
         capture = self.pg3.get_capture(1)
         # verify events in data set
@@ -6013,7 +6026,8 @@ class TestNAT64(MethodHolder):
         self.pg0.add_stream(pkts[-1])
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        self.pg1.get_capture(0)
+        self.pg1.assert_nothing_captured()
+        sleep(1)
         self.vapi.cli("ipfix flush")  # FIXME this should be an API call
         capture = self.pg3.get_capture(9)
         ipfix = IPFIXDecoder()