nat: ED: store both thread&session idx in hash 24/26724/10
authorKlement Sekera <ksekera@cisco.com>
Wed, 22 Apr 2020 12:45:50 +0000 (12:45 +0000)
committerOle Trøan <otroan@employees.org>
Thu, 14 May 2020 12:12:45 +0000 (12:12 +0000)
By storing thread and session index in hash table we are able to skip
multiple hash lookups in multi-worker scenario, which were used for
handoff before. Also, by storing sesion index in vnet_buffer2, we can
avoid repeating the lookup after handoff.

Type: improvement
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: I406fb12f4e2dd8f4a5ca5d83d59dbc37e1af9abf

src/plugins/nat/in2out_ed.c
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44/inlines.h
src/plugins/nat/nat44_classify.c
src/plugins/nat/nat44_cli.c
src/plugins/nat/nat44_hairpinning.c
src/plugins/nat/nat_inlines.h
src/plugins/nat/out2in_ed.c
src/vnet/buffer.h

index 0f1500f..c49ce07 100644 (file)
@@ -84,7 +84,8 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
   snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
                                                       ctx->thread_index);
 
-  s = pool_elt_at_index (tsm->sessions, kv->value);
+  ASSERT (ctx->thread_index == ed_value_get_thread_index (kv));
+  s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (kv));
   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
   if (ctx->now >= sess_timeout_time)
     {
@@ -106,9 +107,9 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
          l_port = s->out2in.port;
          r_port = s->ext_host_port;
        }
-      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
                  &ed_kv);
-      if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
+      if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
        nat_elog_warn ("out2in_ed key del failed");
 
       if (snat_is_unk_proto_session (s))
@@ -229,9 +230,9 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 rx_fib_index,
             --attempts;                                                       \
             portnum = port_thread_offset + port;                              \
             make_ed_kv (&a->addr, &r_addr, proto, s->out2in.fib_index,        \
-                        clib_host_to_net_u16 (portnum), r_port,               \
+                        clib_host_to_net_u16 (portnum), r_port, thread_index, \
                         s - tsm->sessions, out2in_ed_kv);                     \
-            int rv = clib_bihash_add_del_16_8 (&tsm->out2in_ed, out2in_ed_kv, \
+            int rv = clib_bihash_add_del_16_8 (&sm->out2in_ed, out2in_ed_kv,  \
                                                2 /* is_add */);               \
             if (0 == rv)                                                      \
               {                                                               \
@@ -436,10 +437,10 @@ slow_path_ed (snat_main_t * sm,
 
 
       make_ed_kv (&key1.addr, &r_addr, proto,
-                 s->out2in.fib_index, key1.port, r_port, s - tsm->sessions,
-                 &out2in_ed_kv);
+                 s->out2in.fib_index, key1.port, r_port, thread_index,
+                 s - tsm->sessions, &out2in_ed_kv);
       if (clib_bihash_add_or_overwrite_stale_16_8
-         (&tsm->out2in_ed, &out2in_ed_kv, nat44_o2i_ed_is_idle_session_cb,
+         (&sm->out2in_ed, &out2in_ed_kv, nat44_o2i_ed_is_idle_session_cb,
           &ctx))
        nat_elog_notice ("out2in-ed key add failed");
     }
@@ -455,7 +456,7 @@ slow_path_ed (snat_main_t * sm,
 
   clib_bihash_kv_16_8_t in2out_ed_kv;
   make_ed_kv (&l_addr, &r_addr, proto, rx_fib_index, l_port, r_port,
-             s - tsm->sessions, &in2out_ed_kv);
+             thread_index, s - tsm->sessions, &in2out_ed_kv);
   ctx.now = now;
   ctx.thread_index = thread_index;
   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &in2out_ed_kv,
@@ -495,16 +496,15 @@ nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
                        u32 rx_fib_index, u32 thread_index)
 {
   udp_header_t *udp = ip4_next_header (ip);
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
   clib_bihash_kv_16_8_t kv, value;
   snat_session_key_t key0, key1;
 
   make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
-             sm->outside_fib_index, udp->dst_port, udp->src_port, ~0ULL,
+             sm->outside_fib_index, udp->dst_port, udp->src_port, ~0, ~0,
              &kv);
 
   /* NAT packet aimed at external address if has active sessions */
-  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+  if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
     {
       key0.addr = ip->dst_address;
       key0.port = udp->dst_port;
@@ -538,24 +538,27 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
 
   if (ip->protocol == IP_PROTOCOL_ICMP)
     {
-      if (get_icmp_i2o_ed_key (b, ip, 0, ~0ULL, 0, 0, 0, &kv))
+      if (get_icmp_i2o_ed_key (b, ip, 0, ~0, ~0, 0, 0, 0, &kv))
        return 0;
     }
   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
     {
       make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, 0,
                  vnet_buffer (b)->ip.reass.l4_src_port,
-                 vnet_buffer (b)->ip.reass.l4_dst_port, ~0ULL, &kv);
+                 vnet_buffer (b)->ip.reass.l4_dst_port, ~0, ~0, &kv);
     }
   else
     {
       make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
-                 0, ~0ULL, &kv);
+                 0, ~0, ~0, &kv);
     }
 
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     {
-      s = pool_elt_at_index (tsm->sessions, value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&value));
       if (is_fwd_bypass_session (s))
        {
          if (ip->protocol == IP_PROTOCOL_TCP)
@@ -594,10 +597,13 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
 
   /* src NAT check */
   make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol,
-             tx_fib_index, src_port, dst_port, ~0ULL, &kv);
-  if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+             tx_fib_index, src_port, dst_port, ~0, ~0, &kv);
+  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
     {
-      s = pool_elt_at_index (tsm->sessions, value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&value));
       if (nat44_is_ses_closed (s))
        {
          nat_free_session_data (sm, s, thread_index, 0);
@@ -610,10 +616,13 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
 
   /* dst NAT check */
   make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
-             rx_fib_index, dst_port, src_port, ~0ULL, &kv);
+             rx_fib_index, dst_port, src_port, ~0, ~0, &kv);
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     {
-      s = pool_elt_at_index (tsm->sessions, value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&value));
       if (is_fwd_bypass_session (s))
        return 0;
 
@@ -653,7 +662,7 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
 
   err =
-    get_icmp_i2o_ed_key (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port,
+    get_icmp_i2o_ed_key (b, ip, rx_fib_index, ~0, ~0, p_proto, &l_port,
                         &r_port, &kv);
   if (err != 0)
     {
@@ -725,7 +734,10 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
          goto out;
        }
 
-      s = pool_elt_at_index (tsm->sessions, value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&value));
     }
 out:
   if (s)
@@ -794,11 +806,14 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
   old_addr = ip->src_address.as_u32;
 
   make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol,
-             rx_fib_index, 0, 0, ~0ULL, &s_kv);
+             rx_fib_index, 0, 0, ~0, ~0, &s_kv);
 
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
     {
-      s = pool_elt_at_index (tsm->sessions, s_value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&s_value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&s_value));
       new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
     }
   else
@@ -832,8 +847,8 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
                new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
 
                make_ed_kv (&s->out2in.addr, &ip->dst_address, ip->protocol,
-                           outside_fib_index, 0, 0, ~0ULL, &s_kv);
-               if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
+                           outside_fib_index, 0, 0, ~0, ~0, &s_kv);
+               if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
                  goto create_ses;
 
                break;
@@ -844,9 +859,9 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
          for (i = 0; i < vec_len (sm->addresses); i++)
            {
              make_ed_kv (&sm->addresses[i].addr, &ip->dst_address,
-                         ip->protocol, outside_fib_index, 0, 0, ~0ULL,
+                         ip->protocol, outside_fib_index, 0, 0, ~0, ~0,
                          &s_kv);
-             if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
+             if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
                {
                  new_addr = ip->src_address.as_u32 =
                    sm->addresses[i].addr.as_u32;
@@ -878,13 +893,14 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
 
       /* Add to lookup tables */
       make_ed_kv (&s->in2out.addr, &ip->dst_address, ip->protocol,
-                 rx_fib_index, 0, 0, s - tsm->sessions, &s_kv);
+                 rx_fib_index, 0, 0, thread_index, s - tsm->sessions, &s_kv);
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
        nat_elog_notice ("in2out key add failed");
 
       make_ed_kv (&s->out2in.addr, &ip->dst_address, ip->protocol,
-                 outside_fib_index, 0, 0, s - tsm->sessions, &s_kv);
-      if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
+                 outside_fib_index, 0, 0, thread_index, s - tsm->sessions,
+                 &s_kv);
+      if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
        nat_elog_notice ("out2in key add failed");
     }
 
@@ -1015,7 +1031,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
          make_ed_kv (&ip0->src_address, &ip0->dst_address,
                      ip0->protocol, rx_fib_index0,
                      vnet_buffer (b0)->ip.reass.l4_src_port,
-                     vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL, &kv0);
+                     vnet_buffer (b0)->ip.reass.l4_dst_port, ~0, ~0, &kv0);
 
          // lookup for session
          if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
@@ -1024,7 +1040,10 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
              next0 = def_slow;
              goto trace0;
            }
-         s0 = pool_elt_at_index (tsm->sessions, value0.value);
+         ASSERT (thread_index == ed_value_get_thread_index (&value0));
+         s0 =
+           pool_elt_at_index (tsm->sessions,
+                              ed_value_get_session_index (&value0));
 
          if (s0->tcp_closed_timestamp)
            {
@@ -1301,11 +1320,14 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
          make_ed_kv (&ip0->src_address, &ip0->dst_address,
                      ip0->protocol, rx_fib_index0,
                      vnet_buffer (b0)->ip.reass.l4_src_port,
-                     vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL, &kv0);
+                     vnet_buffer (b0)->ip.reass.l4_dst_port, ~0, ~0, &kv0);
 
          if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
            {
-             s0 = pool_elt_at_index (tsm->sessions, value0.value);
+             ASSERT (thread_index == ed_value_get_thread_index (&value0));
+             s0 =
+               pool_elt_at_index (tsm->sessions,
+                                  ed_value_get_session_index (&value0));
 
              if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
                {
index ee35a57..ae9927f 100755 (executable)
@@ -213,7 +213,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
       if (snat_is_unk_proto_session (s))
        {
          make_ed_kv (&s->in2out.addr, &s->ext_host_addr, s->in2out.port, 0,
-                     0, 0, ~0ULL, &ed_kv);
+                     0, 0, ~0, ~0, &ed_kv);
        }
       else
        {
@@ -222,8 +222,8 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
          l_addr = &s->in2out.addr;
          r_addr = &s->ext_host_addr;
          proto = nat_proto_to_ip_proto (s->in2out.protocol);
-         make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
-                     &ed_kv);
+         make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0,
+                     ~0, &ed_kv);
        }
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
        nat_elog_warn ("in2out_ed key del failed");
@@ -251,9 +251,9 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
          l_port = s->out2in.port;
          r_port = s->ext_host_port;
        }
-      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
                  &ed_kv);
-      if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
+      if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
        nat_elog_warn ("out2in_ed key del failed");
       l_addr = &s->in2out.addr;
       fib_index = s->in2out.fib_index;
@@ -264,7 +264,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
          r_addr = &s->ext_host_nat_addr;
          r_port = s->ext_host_nat_port;
        }
-      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
                  &ed_kv);
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
        nat_elog_warn ("in2out_ed key del failed");
@@ -379,7 +379,7 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
       l_addr = &s->in2out.addr;
       r_addr = &s->ext_host_addr;
       fib_index = 0;
-      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
                  &ed_kv);
 
       if (PREDICT_FALSE
@@ -407,10 +407,10 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
       l_port = s->out2in.port;
       r_port = s->ext_host_port;
     }
-  make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+  make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
              &ed_kv);
 
-  if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
+  if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0)))
     nat_elog_warn ("out2in_ed key del failed");
 
   l_addr = &s->in2out.addr;
@@ -424,7 +424,7 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
       r_addr = &s->ext_host_nat_addr;
       r_port = s->ext_host_nat_port;
     }
-  make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+  make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
              &ed_kv);
 
   if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
@@ -2467,9 +2467,11 @@ test_ed_make_split ()
   u16 r_port = 40301;
   u8 proto = 9;
   u32 fib_index = 9000001;
-  u64 value = ~0ULL;
+  u32 thread_index = 3000000001;
+  u32 session_index = 3000000221;
   clib_bihash_kv_16_8_t kv;
-  make_ed_kv (&l_addr, &r_addr, proto, fib_index, l_port, r_port, value, &kv);
+  make_ed_kv (&l_addr, &r_addr, proto, fib_index, l_port, r_port,
+             thread_index, session_index, &kv);
   ip4_address_t l_addr2;
   ip4_address_t r_addr2;
   clib_memset (&l_addr2, 0, sizeof (l_addr2));
@@ -2480,14 +2482,14 @@ test_ed_make_split ()
   u32 fib_index2 = 0;
   split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2,
               &r_port2);
-  u64 value2 = kv.value;
   ASSERT (l_addr.as_u32 == l_addr2.as_u32);
   ASSERT (r_addr.as_u32 == r_addr2.as_u32);
   ASSERT (l_port == l_port2);
   ASSERT (r_port == r_port2);
   ASSERT (proto == proto2);
   ASSERT (fib_index == fib_index2);
-  ASSERT (value == value2);
+  ASSERT (thread_index == ed_value_get_thread_index (&kv));
+  ASSERT (session_index == ed_value_get_session_index (&kv));
 }
 
 static clib_error_t *
@@ -3171,10 +3173,12 @@ format_ed_session_kvp (u8 * s, va_list * args)
 
   split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port);
   s =
-    format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
+    format (s,
+           "local %U:%d remote %U:%d proto %U fib %d thread-index %u session-index %u",
            format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port),
            format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port),
-           format_ip_protocol, proto, fib_index, v->value);
+           format_ip_protocol, proto, fib_index,
+           ed_value_get_session_index (v), ed_value_get_thread_index (v));
 
   return s;
 }
@@ -3348,26 +3352,25 @@ nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
 
       make_ed_kv (&ip->src_address, &ip->dst_address,
                  ip->protocol, fib_index, udp->src_port, udp->dst_port,
-                 ~0ULL, &kv16);
+                 ~0, ~0, &kv16);
 
-      /* *INDENT-OFF* */
-      vec_foreach (tsm, sm->per_thread_data)
-        {
-          if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
-                                                      &kv16, &value16)))
-            {
-              next_worker_index += tsm->thread_index;
-
-              nat_elog_debug_handoff (
-                "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
-                next_worker_index, fib_index,
-               clib_net_to_host_u32 (ip->src_address.as_u32),
-               clib_net_to_host_u32 (ip->dst_address.as_u32));
-
-              return next_worker_index;
-            }
-        }
-      /* *INDENT-ON* */
+      if (PREDICT_TRUE (!clib_bihash_search_16_8 (&sm->out2in_ed,
+                                                 &kv16, &value16)))
+       {
+         tsm =
+           vec_elt_at_index (sm->per_thread_data,
+                             ed_value_get_thread_index (&value16));
+         next_worker_index += tsm->thread_index;
+
+         nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
+                                 next_worker_index, fib_index,
+                                 clib_net_to_host_u32 (ip->
+                                                       src_address.as_u32),
+                                 clib_net_to_host_u32 (ip->
+                                                       dst_address.as_u32));
+
+         return next_worker_index;
+       }
     }
 
   hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
@@ -3419,44 +3422,45 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
 
       make_ed_kv (&ip->dst_address, &ip->src_address,
                  ip->protocol, rx_fib_index, udp->dst_port, udp->src_port,
-                 ~0ULL, &kv16);
+                 ~0, ~0, &kv16);
 
-      /* *INDENT-OFF* */
-      vec_foreach (tsm, sm->per_thread_data)
-        {
-          if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
-                                                      &kv16, &value16)))
-            {
-              next_worker_index = sm->first_worker_index + tsm->thread_index;
-              nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
-                          next_worker_index, rx_fib_index,
-                         clib_net_to_host_u32 (ip->src_address.as_u32),
-                         clib_net_to_host_u32 (ip->dst_address.as_u32));
-              return next_worker_index;
-            }
-          }
-        /* *INDENT-ON* */
+      if (PREDICT_TRUE (!clib_bihash_search_16_8 (&sm->out2in_ed,
+                                                 &kv16, &value16)))
+       {
+         tsm =
+           vec_elt_at_index (sm->per_thread_data,
+                             ed_value_get_thread_index (&value16));
+         vnet_buffer2 (b)->nat.ed_out2in_nat_session_index =
+           ed_value_get_session_index (&value16);
+         next_worker_index = sm->first_worker_index + tsm->thread_index;
+         nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
+                                 next_worker_index, rx_fib_index,
+                                 clib_net_to_host_u32 (ip->
+                                                       src_address.as_u32),
+                                 clib_net_to_host_u32 (ip->
+                                                       dst_address.as_u32));
+         return next_worker_index;
+       }
     }
   else if (proto == NAT_PROTOCOL_ICMP)
     {
-      if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0ULL, 0, 0, 0, &kv16))
+      if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0, ~0, 0, 0, 0, &kv16))
        {
-          /* *INDENT-OFF* */
-          vec_foreach (tsm, sm->per_thread_data)
-            {
-              if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
-                                                          &kv16, &value16)))
-                {
-                  next_worker_index = sm->first_worker_index +
-                                      tsm->thread_index;
-                  nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
-                              next_worker_index, rx_fib_index,
-                             clib_net_to_host_u32 (ip->src_address.as_u32),
-                             clib_net_to_host_u32 (ip->dst_address.as_u32));
-                  return next_worker_index;
-                }
-            }
-          /* *INDENT-ON* */
+         if (PREDICT_TRUE (!clib_bihash_search_16_8 (&sm->out2in_ed,
+                                                     &kv16, &value16)))
+           {
+             tsm =
+               vec_elt_at_index (sm->per_thread_data,
+                                 ed_value_get_thread_index (&value16));
+             next_worker_index = sm->first_worker_index + tsm->thread_index;
+             nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
+                                     next_worker_index, rx_fib_index,
+                                     clib_net_to_host_u32 (ip->
+                                                           src_address.as_u32),
+                                     clib_net_to_host_u32 (ip->
+                                                           dst_address.as_u32));
+             return next_worker_index;
+           }
        }
     }
 
@@ -3802,13 +3806,14 @@ nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
 
   make_ed_kv (in_addr, &s->ext_host_nat_addr,
              nat_proto_to_ip_proto (proto), fib_index, in_port,
-             s->ext_host_nat_port, s - tsm->sessions, &kv);
+             s->ext_host_nat_port, thread_index, s - tsm->sessions, &kv);
   if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
     nat_elog_warn ("in2out key add failed");
 
   make_ed_kv (out_addr, eh_addr, nat_proto_to_ip_proto (proto),
-             s->out2in.fib_index, out_port, eh_port, s - tsm->sessions, &kv);
-  if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
+             s->out2in.fib_index, out_port, eh_port, thread_index,
+             s - tsm->sessions, &kv);
+  if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &kv, 1))
     nat_elog_warn ("out2in key add failed");
 }
 
@@ -3832,12 +3837,12 @@ nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
     thread_index = sm->num_workers;
   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
 
-  make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
+  make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0, ~0,
              &kv);
-  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+  if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
     return;
 
-  s = pool_elt_at_index (tsm->sessions, value.value);
+  s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value));
   nat_free_session_data (sm, s, thread_index, 1);
   nat44_delete_session (sm, s, thread_index);
 }
@@ -3855,12 +3860,12 @@ nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
 
   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
 
-  make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
+  make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0, ~0,
              &kv);
-  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+  if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
     return;
 
-  s = pool_elt_at_index (tsm->sessions, value.value);
+  s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value));
   s->total_pkts = total_pkts;
   s->total_bytes = total_bytes;
 }
@@ -3902,11 +3907,6 @@ nat44_db_init (snat_main_per_thread_data_t * tsm)
                             sm->translation_memory_size);
       clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
                                          format_ed_session_kvp);
-      clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
-                            sm->translation_buckets,
-                            sm->translation_memory_size);
-      clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
-                                         format_ed_session_kvp);
     }
   else
     {
@@ -3938,7 +3938,6 @@ nat44_db_free (snat_main_per_thread_data_t * tsm)
   if (sm->endpoint_dependent)
     {
       clib_bihash_free_16_8 (&tsm->in2out_ed);
-      clib_bihash_free_16_8 (&tsm->out2in_ed);
     }
   else
     {
@@ -3952,6 +3951,40 @@ nat44_db_free (snat_main_per_thread_data_t * tsm)
   clib_bihash_free_8_8 (&tsm->user_hash);
 }
 
+void
+nat44_sessions_clear ()
+{
+  snat_main_t *sm = &snat_main;
+  snat_main_per_thread_data_t *tsm;
+
+  if (sm->endpoint_dependent)
+    {
+      clib_bihash_free_16_8 (&sm->out2in_ed);
+      clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
+                            clib_max (1, sm->num_workers) *
+                            sm->translation_buckets,
+                            clib_max (1, sm->num_workers) *
+                            sm->translation_memory_size);
+      clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
+                                         format_ed_session_kvp);
+    }
+
+  /* *INDENT-OFF* */
+  vec_foreach (tsm, sm->per_thread_data)
+    {
+      u32 ti;
+
+      nat44_db_free (tsm);
+      nat44_db_init (tsm);
+
+      ti = tsm->snat_thread_index;
+      // clear per thread session counters
+      vlib_set_simple_counter (&sm->total_users, ti, 0, 0);
+      vlib_set_simple_counter (&sm->total_sessions, ti, 0, 0);
+    }
+  /* *INDENT-ON* */
+}
+
 static clib_error_t *
 snat_config (vlib_main_t * vm, unformat_input_t * input)
 {
@@ -4122,6 +4155,11 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
          nat_affinity_init (vm);
          nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
                       nat_ha_sref_ed_cb);
+         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
        {
@@ -4454,9 +4492,9 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
   else
     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
 
-  t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
+  t = is_in ? &tsm->in2out_ed : &sm->out2in_ed;
   make_ed_kv (addr, eh_addr, proto, fib_index, clib_host_to_net_u16 (port),
-             clib_host_to_net_u16 (eh_port), ~0ULL, &kv);
+             clib_host_to_net_u16 (eh_port), ~0, ~0, &kv);
   if (clib_bihash_search_16_8 (t, &kv, &value))
     {
       return VNET_API_ERROR_NO_SUCH_ENTRY;
index 7a4d020..3107227 100644 (file)
@@ -454,7 +454,6 @@ typedef struct
   clib_bihash_8_8_t in2out;
 
   /* Endpoint dependent sessions lookup tables */
-  clib_bihash_16_8_t out2in_ed;
   clib_bihash_16_8_t in2out_ed;
 
   /* Find-a-user => src address lookup */
@@ -544,6 +543,9 @@ typedef struct snat_main_s
   /* Static mapping pool */
   snat_static_mapping_t *static_mappings;
 
+  /* Endpoint-dependent out2in mappings */
+  clib_bihash_16_8_t out2in_ed;
+
   /* Interface pool */
   snat_interface_t *interfaces;
   snat_interface_t *output_feature_interfaces;
@@ -1288,6 +1290,8 @@ void nat44_db_init (snat_main_per_thread_data_t * tsm);
  */
 void nat44_db_free (snat_main_per_thread_data_t * tsm);
 
+void nat44_sessions_clear ();
+
 /**
  * @brief Find or create NAT user
  *
index 62121df..6e462d7 100644 (file)
@@ -64,28 +64,6 @@ nat44_session_reuse_old (snat_main_t * sm, snat_user_t * u,
   return s;
 }
 
-static_always_inline void
-nat44_sessions_clear ()
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
-
-  /* *INDENT-OFF* */
-  vec_foreach (tsm, sm->per_thread_data)
-    {
-      u32 ti;
-
-      nat44_db_free (tsm);
-      nat44_db_init (tsm);
-
-      ti = tsm->snat_thread_index;
-      // clear per thread session counters
-      vlib_set_simple_counter (&sm->total_users, ti, 0, 0);
-      vlib_set_simple_counter (&sm->total_sessions, ti, 0, 0);
-    }
-  /* *INDENT-ON* */
-}
-
 static_always_inline void
 nat44_user_del_sessions (snat_user_t * u, u32 thread_index)
 {
index 5ff5579..bb3584e 100644 (file)
@@ -369,7 +369,7 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm,
              make_ed_kv (&ip0->src_address, &ip0->dst_address,
                          ip0->protocol, rx_fib_index0,
                          vnet_buffer (b0)->ip.reass.l4_src_port,
-                         vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL,
+                         vnet_buffer (b0)->ip.reass.l4_dst_port, ~0, ~0,
                          &ed_kv0);
              /* process whole packet */
              if (!clib_bihash_search_16_8
index 796e349..ccc2eac 100644 (file)
@@ -228,6 +228,7 @@ nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
   vlib_cli_output (vm, "%U",
                   format_bihash_8_8, &sm->static_mapping_by_external,
                   verbose);
+  vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed, verbose);
   vec_foreach_index (i, sm->per_thread_data)
   {
     tsm = vec_elt_at_index (sm->per_thread_data, i);
@@ -237,8 +238,6 @@ nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
       {
        vlib_cli_output (vm, "%U", format_bihash_16_8, &tsm->in2out_ed,
                         verbose);
-       vlib_cli_output (vm, "%U", format_bihash_16_8, &tsm->out2in_ed,
-                        verbose);
       }
     else
       {
index d109bb8..02cdfb1 100644 (file)
@@ -128,10 +128,10 @@ snat_hairpinning (snat_main_t * sm,
          clib_bihash_kv_16_8_t ed_kv, ed_value;
          make_ed_kv (&ip0->dst_address, &ip0->src_address,
                      ip0->protocol, sm->outside_fib_index, udp0->dst_port,
-                     udp0->src_port, ~0ULL, &ed_kv);
-         rv = clib_bihash_search_16_8 (&sm->per_thread_data[ti].out2in_ed,
-                                       &ed_kv, &ed_value);
-         si = ed_value.value;
+                     udp0->src_port, ~0, ~0, &ed_kv);
+         rv = clib_bihash_search_16_8 (&sm->out2in_ed, &ed_kv, &ed_value);
+         ASSERT (ti == ed_value_get_thread_index (&ed_value));
+         si = ed_value_get_session_index (&ed_value);
        }
       else
        {
@@ -228,12 +228,12 @@ snat_icmp_hairpinning (snat_main_t * sm,
          clib_bihash_kv_16_8_t ed_kv, ed_value;
          make_ed_kv (&ip0->dst_address, &ip0->src_address,
                      inner_ip0->protocol, sm->outside_fib_index,
-                     l4_header->src_port, l4_header->dst_port, ~0ULL,
+                     l4_header->src_port, l4_header->dst_port, ~0, ~0,
                      &ed_kv);
-         if (clib_bihash_search_16_8
-             (&sm->per_thread_data[ti].out2in_ed, &ed_kv, &ed_value))
+         if (clib_bihash_search_16_8 (&sm->out2in_ed, &ed_kv, &ed_value))
            return 1;
-         si = ed_value.value;
+         ASSERT (ti == ed_value_get_thread_index (&ed_value));
+         si = ed_value_get_session_index (&ed_value);
        }
       else
        {
@@ -389,18 +389,16 @@ nat44_ed_hairpinning_unknown_proto (snat_main_t * sm,
   snat_static_mapping_t *m;
   ip_csum_t sum;
   snat_session_t *s;
-  snat_main_per_thread_data_t *tsm;
 
   if (sm->num_workers > 1)
     ti = sm->worker_out2in_cb (b, ip, sm->outside_fib_index, 0);
   else
     ti = sm->num_workers;
-  tsm = &sm->per_thread_data[ti];
 
   old_addr = ip->dst_address.as_u32;
   make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
-             sm->outside_fib_index, 0, 0, ~0ULL, &s_kv);
-  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
+             sm->outside_fib_index, 0, 0, ~0, ~0, &s_kv);
+  if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
     {
       make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
       if (clib_bihash_search_8_8
@@ -414,7 +412,10 @@ nat44_ed_hairpinning_unknown_proto (snat_main_t * sm,
     }
   else
     {
-      s = pool_elt_at_index (sm->per_thread_data[ti].sessions, s_value.value);
+      ASSERT (ti == ed_value_get_thread_index (&s_value));
+      s =
+       pool_elt_at_index (sm->per_thread_data[ti].sessions,
+                          ed_value_get_session_index (&s_value));
       if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
        vnet_buffer (b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
index d37cb10..121d2c7 100644 (file)
@@ -445,13 +445,39 @@ nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
 
 always_inline void
 make_ed_kv (ip4_address_t * l_addr, ip4_address_t * r_addr, u8 proto,
-           u32 fib_index, u16 l_port, u16 r_port, u64 value,
-           clib_bihash_kv_16_8_t * kv)
+           u32 fib_index, u16 l_port, u16 r_port, u32 thread_index,
+           u32 session_index, clib_bihash_kv_16_8_t * kv)
 {
   kv->key[0] = (u64) r_addr->as_u32 << 32 | l_addr->as_u32;
   kv->key[1] =
     (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
-  kv->value = value;
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline u32
+ed_value_get_thread_index (clib_bihash_kv_16_8_t * value)
+{
+  return value->value >> 32;
+}
+
+always_inline u32
+ed_value_get_session_index (clib_bihash_kv_16_8_t * value)
+{
+  return value->value & ~(u32) 0;
+}
+
+always_inline void
+split_ed_value (clib_bihash_kv_16_8_t * value, u32 * thread_index,
+               u32 * session_index)
+{
+  if (thread_index)
+    {
+      *thread_index = ed_value_get_thread_index (value);
+    }
+  if (session_index)
+    {
+      *session_index = ed_value_get_session_index (value);
+    }
 }
 
 always_inline void
@@ -497,8 +523,8 @@ make_sm_kv (clib_bihash_kv_8_8_t * kv, ip4_address_t * addr, u8 proto,
 
 static_always_inline int
 get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
-                    u64 value, u8 * nat_proto, u16 * l_port, u16 * r_port,
-                    clib_bihash_kv_16_8_t * kv)
+                    u32 thread_index, u32 session_index, u8 * nat_proto,
+                    u16 * l_port, u16 * r_port, clib_bihash_kv_16_8_t * kv)
 {
   u8 proto;
   u16 _l_port, _r_port;
@@ -546,8 +572,8 @@ get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
          return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
        }
     }
-  make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port, value,
-             kv);
+  make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port,
+             thread_index, session_index, kv);
   if (nat_proto)
     {
       *nat_proto = ip_proto_to_nat_proto (proto);
@@ -566,8 +592,8 @@ get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
 
 static_always_inline int
 get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
-                    u64 value, u8 * nat_proto, u16 * l_port, u16 * r_port,
-                    clib_bihash_kv_16_8_t * kv)
+                    u32 thread_index, u32 session_index, u8 * nat_proto,
+                    u16 * l_port, u16 * r_port, clib_bihash_kv_16_8_t * kv)
 {
   icmp46_header_t *icmp0;
   u8 proto;
@@ -614,8 +640,8 @@ get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
          return -1;
        }
     }
-  make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port, value,
-             kv);
+  make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port,
+             thread_index, session_index, kv);
   if (nat_proto)
     {
       *nat_proto = ip_proto_to_nat_proto (proto);
index e597191..abd7045 100644 (file)
@@ -132,7 +132,7 @@ nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
          r_addr = &s->ext_host_nat_addr;
          r_port = s->ext_host_nat_port;
        }
-      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0, ~0,
                  &ed_kv);
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
        nat_elog_warn ("in2out_ed key del failed");
@@ -242,11 +242,11 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
 
   /* Add to lookup tables */
   make_ed_kv (&e_key.addr, &s->ext_host_addr, ip->protocol,
-             e_key.fib_index, e_key.port, s->ext_host_port,
+             e_key.fib_index, e_key.port, s->ext_host_port, thread_index,
              s - tsm->sessions, &kv);
   ctx.now = now;
   ctx.thread_index = thread_index;
-  if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, &kv,
+  if (clib_bihash_add_or_overwrite_stale_16_8 (&sm->out2in_ed, &kv,
                                               nat44_o2i_ed_is_idle_session_cb,
                                               &ctx))
     nat_elog_notice ("out2in-ed key add failed");
@@ -262,7 +262,7 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
        {
          b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS];
          nat_ed_session_delete (sm, s, thread_index, 1);
-         if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 0))
+         if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &kv, 0))
            nat_elog_notice ("out2in-ed key del failed");
          return 0;
        }
@@ -271,12 +271,12 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
       s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
       make_ed_kv (&l_key.addr, &s->ext_host_nat_addr, ip->protocol,
                  l_key.fib_index, l_key.port, s->ext_host_nat_port,
-                 s - tsm->sessions, &kv);
+                 thread_index, s - tsm->sessions, &kv);
     }
   else
     {
       make_ed_kv (&l_key.addr, &s->ext_host_addr, ip->protocol,
-                 l_key.fib_index, l_key.port, s->ext_host_port,
+                 l_key.fib_index, l_key.port, s->ext_host_port, thread_index,
                  s - tsm->sessions, &kv);
     }
   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv,
@@ -315,7 +315,7 @@ next_src_nat (snat_main_t * sm, ip4_header_t * ip, u16 src_port,
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
 
   make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol,
-             rx_fib_index, src_port, dst_port, ~0ULL, &kv);
+             rx_fib_index, src_port, dst_port, ~0, ~0, &kv);
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     return 1;
 
@@ -337,7 +337,7 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
   if (ip->protocol == IP_PROTOCOL_ICMP)
     {
       if (get_icmp_o2i_ed_key
-         (b, ip, rx_fib_index, ~0ULL, 0, &l_port, &r_port, &kv))
+         (b, ip, rx_fib_index, ~0, ~0, 0, &l_port, &r_port, &kv))
        return;
     }
   else
@@ -354,12 +354,15 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
          r_port = 0;
        }
       make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
-                 rx_fib_index, l_port, r_port, ~0ULL, &kv);
+                 rx_fib_index, l_port, r_port, ~0, ~0, &kv);
     }
 
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     {
-      s = pool_elt_at_index (tsm->sessions, value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&value));
     }
   else
     {
@@ -445,14 +448,14 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
 
   if (get_icmp_o2i_ed_key
-      (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port, &r_port, &kv))
+      (b, ip, rx_fib_index, ~0, ~0, p_proto, &l_port, &r_port, &kv))
     {
       b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
       next = NAT_NEXT_DROP;
       goto out;
     }
 
-  if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+  if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
     {
       /* Try to match static mapping */
       e_key.addr = ip->dst_address;
@@ -535,7 +538,10 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
          goto out;
        }
 
-      s = pool_elt_at_index (tsm->sessions, value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&value));
     }
 out:
   if (s)
@@ -567,11 +573,14 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm,
   old_addr = ip->dst_address.as_u32;
 
   make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, rx_fib_index,
-             0, 0, ~0ULL, &s_kv);
+             0, 0, ~0, ~0, &s_kv);
 
-  if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
+  if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
     {
-      s = pool_elt_at_index (tsm->sessions, s_value.value);
+      ASSERT (thread_index == ed_value_get_thread_index (&s_value));
+      s =
+       pool_elt_at_index (tsm->sessions,
+                          ed_value_get_session_index (&s_value));
       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
     }
   else
@@ -618,11 +627,11 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm,
 
       /* Add to lookup tables */
       s_kv.value = s - tsm->sessions;
-      if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
+      if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
        nat_elog_notice ("out2in key add failed");
 
       make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
-                 m->fib_index, 0, 0, s - tsm->sessions, &s_kv);
+                 m->fib_index, 0, 0, thread_index, s - tsm->sessions, &s_kv);
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
        nat_elog_notice ("in2out key add failed");
     }
@@ -646,7 +655,8 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm,
 static inline uword
 nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
                                          vlib_node_runtime_t * node,
-                                         vlib_frame_t * frame)
+                                         vlib_frame_t * frame,
+                                         int is_multi_worker)
 {
   u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
   nat_next_t next_index;
@@ -731,15 +741,45 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
          make_ed_kv (&ip0->dst_address, &ip0->src_address,
                      ip0->protocol, rx_fib_index0,
                      vnet_buffer (b0)->ip.reass.l4_dst_port,
-                     vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0);
+                     vnet_buffer (b0)->ip.reass.l4_src_port, ~0, ~0, &kv0);
+
+         /* there is a stashed index in vnet_buffer2 from handoff node,
+          * see if we can use it */
+         if (is_multi_worker && PREDICT_TRUE
+             (!pool_is_free_index
+              (tsm->sessions,
+               vnet_buffer2 (b0)->nat.ed_out2in_nat_session_index)))
+           {
+             s0 = pool_elt_at_index (tsm->sessions,
+                                     vnet_buffer2 (b0)->
+                                     nat.ed_out2in_nat_session_index);
+             if (PREDICT_TRUE
+                 (s0->out2in.addr.as_u32 == ip0->dst_address.as_u32
+                  && s0->out2in.port ==
+                  vnet_buffer (b0)->ip.reass.l4_dst_port
+                  && s0->out2in.protocol ==
+                  ip_proto_to_nat_proto (ip0->protocol)
+                  && s0->out2in.fib_index == rx_fib_index0
+                  && s0->ext_host_addr.as_u32 == ip0->src_address.as_u32
+                  && s0->ext_host_port ==
+                  vnet_buffer (b0)->ip.reass.l4_src_port))
+               {
+                 /* yes, this is the droid we're looking for */
+                 goto skip_lookup;
+               }
+           }
 
-         if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
+         if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv0, &value0))
            {
              next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
              goto trace0;
            }
-         s0 = pool_elt_at_index (tsm->sessions, value0.value);
+         ASSERT (thread_index == ed_value_get_thread_index (&value0));
+         s0 =
+           pool_elt_at_index (tsm->sessions,
+                              ed_value_get_session_index (&value0));
 
+       skip_lookup:
          if (s0->tcp_closed_timestamp)
            {
              if (now >= s0->tcp_closed_timestamp)
@@ -1017,12 +1057,15 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
          make_ed_kv (&ip0->dst_address, &ip0->src_address,
                      ip0->protocol, rx_fib_index0,
                      vnet_buffer (b0)->ip.reass.l4_dst_port,
-                     vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0);
+                     vnet_buffer (b0)->ip.reass.l4_src_port, ~0, ~0, &kv0);
 
          s0 = NULL;
-         if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
+         if (!clib_bihash_search_16_8 (&sm->out2in_ed, &kv0, &value0))
            {
-             s0 = pool_elt_at_index (tsm->sessions, value0.value);
+             ASSERT (thread_index == ed_value_get_thread_index (&value0));
+             s0 =
+               pool_elt_at_index (tsm->sessions,
+                                  ed_value_get_session_index (&value0));
 
              if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
                {
@@ -1256,7 +1299,14 @@ VLIB_NODE_FN (nat44_ed_out2in_node) (vlib_main_t * vm,
                                     vlib_node_runtime_t * node,
                                     vlib_frame_t * frame)
 {
-  return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame);
+  if (snat_main.num_workers > 1)
+    {
+      return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame, 1);
+    }
+  else
+    {
+      return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame, 0);
+    }
 }
 
 /* *INDENT-OFF* */
index bdb5892..50515c4 100644 (file)
@@ -458,7 +458,7 @@ typedef struct
   struct
   {
     u32 arc_next;
-    u32 unused;
+    u32 ed_out2in_nat_session_index;
   } nat;
 
   union