nat: improve perf - long read after short write 03/26603/11
authorKlement Sekera <ksekera@cisco.com>
Fri, 17 Apr 2020 18:42:28 +0000 (18:42 +0000)
committerOle Trøan <otroan@employees.org>
Mon, 27 Apr 2020 08:21:53 +0000 (08:21 +0000)
Type: improvement
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: Idbbad246161d28f595c25e10d7282c8b33fa9876

src/plugins/nat/in2out_ed.c
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44_classify.c
src/plugins/nat/nat44_hairpinning.c
src/plugins/nat/nat_inlines.h
src/plugins/nat/out2in_ed.c

index 95f80a4..d78e552 100644 (file)
@@ -72,7 +72,10 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
   nat44_is_idle_session_ctx_t *ctx = arg;
   snat_session_t *s;
   u64 sess_timeout_time;
-  nat_ed_ses_key_t ed_key;
+  u8 proto;
+  u16 r_port, l_port;
+  ip4_address_t *l_addr, *r_addr;
+  u32 fib_index;
   clib_bihash_kv_16_8_t ed_kv;
   int i;
   snat_address_t *a;
@@ -87,23 +90,23 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
       if (is_fwd_bypass_session (s))
        goto delete;
 
-      ed_key.l_addr = s->out2in.addr;
-      ed_key.r_addr = s->ext_host_addr;
-      ed_key.fib_index = s->out2in.fib_index;
+      l_addr = &s->out2in.addr;
+      r_addr = &s->ext_host_addr;
+      fib_index = s->out2in.fib_index;
       if (snat_is_unk_proto_session (s))
        {
-         ed_key.proto = s->in2out.port;
-         ed_key.r_port = 0;
-         ed_key.l_port = 0;
+         proto = s->in2out.port;
+         r_port = 0;
+         l_port = 0;
        }
       else
        {
-         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
-         ed_key.l_port = s->out2in.port;
-         ed_key.r_port = s->ext_host_port;
+         proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         l_port = s->out2in.port;
+         r_port = s->ext_host_port;
        }
-      ed_kv.key[0] = ed_key.as_u64[0];
-      ed_kv.key[1] = ed_key.as_u64[1];
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+                 &ed_kv);
       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
        nat_elog_warn ("out2in_ed key del failed");
 
@@ -191,11 +194,13 @@ snat_random_port (u16 min, u16 max)
 }
 
 static int
-nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index,
-                           u32 thread_index, nat_ed_ses_key_t * key,
-                           snat_session_key_t * key1, u16 port_per_thread,
-                           u32 snat_thread_index,
+nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 rx_fib_index,
+                           u32 snat_proto, u32 thread_index,
+                           ip4_address_t r_addr, u16 r_port, u8 proto,
+                           u16 port_per_thread, u32 snat_thread_index,
                            snat_session_t * s,
+                           ip4_address_t * allocated_addr,
+                           u16 * allocated_port,
                            clib_bihash_kv_16_8_t * out2in_ed_kv)
 {
   int i;
@@ -208,11 +213,11 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index,
   for (i = 0; i < vec_len (sm->addresses); i++)
     {
       a = sm->addresses + i;
-      switch (key1->protocol)
+      switch (snat_proto)
        {
 #define _(N, j, n, unused)                                                    \
   case SNAT_PROTOCOL_##N:                                                     \
-    if (a->fib_index == fib_index)                                            \
+    if (a->fib_index == rx_fib_index)                                         \
       {                                                                       \
         u16 port = snat_random_port (1, port_per_thread);                     \
         u16 attempts = port_per_thread;                                       \
@@ -220,10 +225,9 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index,
           {                                                                   \
             --attempts;                                                       \
             portnum = port_thread_offset + port;                              \
-            make_ed_kv (out2in_ed_kv, &a->addr, &key->r_addr, key->proto,     \
-                        s->out2in.fib_index, clib_host_to_net_u16 (portnum),  \
-                        key->r_port);                                         \
-            out2in_ed_kv->value = s - tsm->sessions;                          \
+            make_ed_kv (&a->addr, &r_addr, proto, s->out2in.fib_index,        \
+                        clib_host_to_net_u16 (portnum), r_port,               \
+                        s - tsm->sessions, out2in_ed_kv);                     \
             int rv = clib_bihash_add_del_16_8 (&tsm->out2in_ed, out2in_ed_kv, \
                                                2 /* is_add */);               \
             if (0 == rv)                                                      \
@@ -231,8 +235,8 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index,
                 ++a->busy_##n##_port_refcounts[portnum];                      \
                 a->busy_##n##_ports_per_thread[thread_index]++;               \
                 a->busy_##n##_ports++;                                        \
-                key1->addr = a->addr;                                         \
-                key1->port = clib_host_to_net_u16 (portnum);                  \
+                *allocated_addr = a->addr;                                    \
+                *allocated_port = clib_host_to_net_u16 (portnum);             \
                 return 0;                                                     \
               }                                                               \
             port = (port + 1) % port_per_thread;                              \
@@ -254,9 +258,9 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index,
   if (ga)
     {
       /* fake fib_index to reuse macro */
-      fib_index = ~0;
+      rx_fib_index = ~0;
       a = ga;
-      switch (key1->protocol)
+      switch (snat_proto)
        {
          foreach_snat_protocol;
        default:
@@ -275,8 +279,12 @@ nat_ed_alloc_addr_and_port (snat_main_t * sm, u32 fib_index,
 static u32
 slow_path_ed (snat_main_t * sm,
              vlib_buffer_t * b,
+             ip4_address_t l_addr,
+             ip4_address_t r_addr,
+             u16 l_port,
+             u16 r_port,
+             u8 proto,
              u32 rx_fib_index,
-             clib_bihash_kv_16_8_t * kv,
              snat_session_t ** sessionp,
              vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now)
 {
@@ -284,23 +292,22 @@ slow_path_ed (snat_main_t * sm,
   snat_session_key_t key0, key1;
   lb_nat_type_t lb = 0;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key;
-  u32 proto = ip_proto_to_snat_proto (key->proto);
+  u32 snat_proto = ip_proto_to_snat_proto (proto);
   nat_outside_fib_t *outside_fib;
   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
   clib_bihash_kv_16_8_t out2in_ed_kv;
   bool out2in_ed_inserted = false;
+  ip4_address_t allocated_addr;
+  u16 allocated_port;
   u8 identity_nat;
   fib_prefix_t pfx = {
     .fp_proto = FIB_PROTOCOL_IP4,
     .fp_len = 32,
-    .fp_addr = {
-               .ip4.as_u32 = key->r_addr.as_u32,
-               },
+    .fp_addr = {.ip4.as_u32 = r_addr.as_u32,},
   };
   nat44_is_idle_session_ctx_t ctx;
 
-  if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP))
+  if (PREDICT_TRUE (snat_proto == SNAT_PROTOCOL_TCP))
     {
       if (PREDICT_FALSE
          (!tcp_flags_is_init
@@ -322,9 +329,9 @@ slow_path_ed (snat_main_t * sm,
        }
     }
 
-  key0.addr = key->l_addr;
-  key0.port = key->l_port;
-  key1.protocol = key0.protocol = proto;
+  key0.addr = l_addr;
+  key0.port = l_port;
+  key1.protocol = key0.protocol = snat_proto;
   key0.fib_index = rx_fib_index;
   key1.fib_index = sm->outside_fib_index;
 
@@ -366,11 +373,12 @@ slow_path_ed (snat_main_t * sm,
        }
 
       /* Try to create dynamic translation */
-      if (nat_ed_alloc_addr_and_port (sm, rx_fib_index,
-                                     thread_index, key, &key1,
+      if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, snat_proto,
+                                     thread_index, r_addr, r_port, proto,
                                      sm->port_per_thread,
                                      tsm->snat_thread_index, s,
-                                     &out2in_ed_kv))
+                                     &allocated_addr,
+                                     &allocated_port, &out2in_ed_kv))
        {
          nat_elog_notice ("addresses exhausted");
          b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
@@ -378,6 +386,8 @@ slow_path_ed (snat_main_t * sm,
        }
 
       out2in_ed_inserted = true;
+      key1.addr = allocated_addr;
+      key1.port = allocated_port;
     }
   else
     {
@@ -422,9 +432,9 @@ slow_path_ed (snat_main_t * sm,
       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
 
 
-      make_ed_kv (&out2in_ed_kv, &key1.addr, &key->r_addr, key->proto,
-                 s->out2in.fib_index, key1.port, key->r_port);
-      out2in_ed_kv.value = s - tsm->sessions;
+      make_ed_kv (&key1.addr, &r_addr, proto,
+                 s->out2in.fib_index, key1.port, r_port, 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,
           &ctx))
@@ -435,16 +445,18 @@ slow_path_ed (snat_main_t * sm,
   if (lb)
     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
   s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
-  s->ext_host_addr = key->r_addr;
-  s->ext_host_port = key->r_port;
+  s->ext_host_addr = r_addr;
+  s->ext_host_port = r_port;
   s->in2out = key0;
   s->out2in = key1;
   s->out2in.protocol = key0.protocol;
 
-  kv->value = s - tsm->sessions;
+  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);
   ctx.now = now;
   ctx.thread_index = thread_index;
-  if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, kv,
+  if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &in2out_ed_kv,
                                               nat44_i2o_ed_is_idle_session_cb,
                                               &ctx))
     nat_elog_notice ("in2out-ed key add failed");
@@ -497,11 +509,11 @@ nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
   clib_bihash_kv_16_8_t kv, value;
   snat_session_key_t key0, key1;
 
-  make_ed_kv (&kv, &ip->dst_address, &ip->src_address, ip->protocol,
-             sm->outside_fib_index, udp->dst_port, udp->src_port);
+  make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
+             sm->outside_fib_index, udp->dst_port, udp->src_port, ~0ULL,
+             &kv);
 
-  /* NAT packet aimed at external address if */
-  /* has active sessions */
+  /* NAT packet aimed at external address if has active sessions */
   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
     {
       key0.addr = ip->dst_address;
@@ -527,7 +539,6 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
                                      u32 thread_index, f64 now,
                                      vlib_main_t * vm, vlib_buffer_t * b)
 {
-  nat_ed_ses_key_t key;
   clib_bihash_kv_16_8_t kv, value;
   snat_session_t *s = 0;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
@@ -537,23 +548,19 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
 
   if (ip->protocol == IP_PROTOCOL_ICMP)
     {
-      key.as_u64[0] = key.as_u64[1] = 0;
-      if (get_icmp_i2o_ed_key (b, ip, &key))
+      if (get_icmp_i2o_ed_key (b, ip, 0, ~0ULL, 0, 0, 0, &kv))
        return 0;
-      key.fib_index = 0;
-      kv.key[0] = key.as_u64[0];
-      kv.key[1] = key.as_u64[1];
     }
   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
     {
-      make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0,
+      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);
+                 vnet_buffer (b)->ip.reass.l4_dst_port, ~0ULL, &kv);
     }
   else
     {
-      make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
-                 0);
+      make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
+                 0, ~0ULL, &kv);
     }
 
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
@@ -584,7 +591,7 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
 
 static_always_inline int
 nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
-                                      u8 proto, u16 src_port, u16 dst_port,
+                                      u16 src_port, u16 dst_port,
                                       u32 thread_index, u32 rx_sw_if_index,
                                       u32 tx_sw_if_index)
 {
@@ -596,8 +603,8 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
   u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
 
   /* src NAT check */
-  make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, tx_fib_index,
-             src_port, dst_port);
+  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))
     {
       s = pool_elt_at_index (tsm->sessions, value.value);
@@ -612,8 +619,8 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
     }
 
   /* dst NAT check */
-  make_ed_kv (&kv, &ip->dst_address, &ip->src_address, proto, rx_fib_index,
-             dst_port, src_port);
+  make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
+             rx_fib_index, dst_port, src_port, ~0ULL, &kv);
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     {
       s = pool_elt_at_index (tsm->sessions, value.value);
@@ -643,29 +650,26 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
 {
   u32 sw_if_index;
   u32 rx_fib_index;
-  nat_ed_ses_key_t key;
   snat_session_t *s = 0;
   u8 dont_translate = 0;
   clib_bihash_kv_16_8_t kv, value;
   u32 next = ~0;
   int err;
+  u16 l_port = 0, r_port = 0;  // initialize to workaround gcc warning
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
 
   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
 
-  key.as_u64[0] = key.as_u64[1] = 0;
-  err = get_icmp_i2o_ed_key (b, ip, &key);
+  err =
+    get_icmp_i2o_ed_key (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port,
+                        &r_port, &kv);
   if (err != 0)
     {
       b->error = node->errors[err];
       next = NAT_NEXT_DROP;
       goto out;
     }
-  key.fib_index = rx_fib_index;
-
-  kv.key[0] = key.as_u64[0];
-  kv.key[1] = key.as_u64[1];
 
   if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     {
@@ -673,7 +677,7 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
        {
          if (PREDICT_FALSE
              (nat44_ed_not_translate_output_feature
-              (sm, ip, key.proto, key.l_port, key.r_port, thread_index,
+              (sm, ip, l_port, r_port, thread_index,
                sw_if_index, vnet_buffer (b)->sw_if_index[VLIB_TX])))
            {
              dont_translate = 1;
@@ -701,8 +705,10 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
          goto out;
        }
 
-      next = slow_path_ed (sm, b, rx_fib_index, &kv, &s, node, next,
-                          thread_index, vlib_time_now (sm->vlib_main));
+      next =
+       slow_path_ed (sm, b, ip->src_address, ip->dst_address, l_port, r_port,
+                     ip->protocol, rx_fib_index, &s, node, next,
+                     thread_index, vlib_time_now (sm->vlib_main));
 
       if (PREDICT_FALSE (next == NAT_NEXT_DROP))
        goto out;
@@ -730,8 +736,6 @@ icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
 
       s = pool_elt_at_index (tsm->sessions, value.value);
     }
-
-  *p_proto = ip_proto_to_snat_proto (key.proto);
 out:
   if (s)
     *p_value = s->out2in;
@@ -798,8 +802,8 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
     }
   old_addr = ip->src_address.as_u32;
 
-  make_ed_kv (&s_kv, &ip->src_address, &ip->dst_address, ip->protocol,
-             rx_fib_index, 0, 0);
+  make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol,
+             rx_fib_index, 0, 0, ~0ULL, &s_kv);
 
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
     {
@@ -834,8 +838,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_kv, &s->out2in.addr, &ip->dst_address, ip->protocol,
-                           outside_fib_index, 0, 0);
+               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))
                  goto create_ses;
 
@@ -846,8 +850,9 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
 
          for (i = 0; i < vec_len (sm->addresses); i++)
            {
-             make_ed_kv (&s_kv, &sm->addresses[i].addr, &ip->dst_address,
-                         ip->protocol, outside_fib_index, 0, 0);
+             make_ed_kv (&sm->addresses[i].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))
                {
                  new_addr = ip->src_address.as_u32 =
@@ -879,15 +884,13 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
        s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
 
       /* Add to lookup tables */
-      make_ed_kv (&s_kv, &s->in2out.addr, &ip->dst_address, ip->protocol,
-                 rx_fib_index, 0, 0);
-      s_kv.value = s - tsm->sessions;
+      make_ed_kv (&s->in2out.addr, &ip->dst_address, ip->protocol,
+                 rx_fib_index, 0, 0, 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_kv, &s->out2in.addr, &ip->dst_address, ip->protocol,
-                 outside_fib_index, 0, 0);
-      s_kv.value = s - tsm->sessions;
+      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))
        nat_elog_notice ("out2in key add failed");
     }
@@ -1016,10 +1019,10 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
+         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);
+                     vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL, &kv0);
 
          // lookup for session
          if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
@@ -1302,10 +1305,10 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
            }
 
          // move down
-         make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
+         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);
+                     vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL, &kv0);
 
          if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
            {
@@ -1325,10 +1328,9 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
                {
                  if (PREDICT_FALSE
                      (nat44_ed_not_translate_output_feature
-                      (sm, ip0, ip0->protocol,
-                       vnet_buffer (b0)->ip.reass.l4_src_port,
-                       vnet_buffer (b0)->ip.reass.l4_dst_port,
-                       thread_index, sw_if_index0,
+                      (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
+                       vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
+                       sw_if_index0,
                        vnet_buffer (b0)->sw_if_index[VLIB_TX])))
                    goto trace0;
 
@@ -1352,8 +1354,12 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
                    goto trace0;
                }
 
-             next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
-                                   next0, thread_index, now);
+             next0 =
+               slow_path_ed (sm, b0, ip0->src_address, ip0->dst_address,
+                             vnet_buffer (b0)->ip.reass.l4_src_port,
+                             vnet_buffer (b0)->ip.reass.l4_dst_port,
+                             ip0->protocol, rx_fib_index0, &s0, node, next0,
+                             thread_index, now);
 
              if (PREDICT_FALSE (next0 == NAT_NEXT_DROP))
                goto trace0;
index b0c30d6..ba682f9 100755 (executable)
@@ -199,7 +199,10 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
 {
   snat_session_key_t key;
   clib_bihash_kv_8_8_t kv;
-  nat_ed_ses_key_t ed_key;
+  u8 proto;
+  u16 r_port, l_port;
+  ip4_address_t *l_addr, *r_addr;
+  u32 fib_index = 0;
   clib_bihash_kv_16_8_t ed_kv;
   snat_main_per_thread_data_t *tsm =
     vec_elt_at_index (sm->per_thread_data, thread_index);
@@ -208,21 +211,20 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
     {
       if (snat_is_unk_proto_session (s))
        {
-         ed_key.proto = s->in2out.port;
-         ed_key.r_port = 0;
-         ed_key.l_port = 0;
+         make_ed_kv (&s->in2out.addr, &s->ext_host_addr, s->in2out.port, 0,
+                     0, 0, ~0ULL, &ed_kv);
        }
       else
        {
-         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
-         ed_key.l_port = s->in2out.port;
-         ed_key.r_port = s->ext_host_port;
+         proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         l_port = s->in2out.port;
+         r_port = s->ext_host_port;
+         l_addr = &s->in2out.addr;
+         r_addr = &s->ext_host_addr;
+         proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+                     &ed_kv);
        }
-      ed_key.l_addr = s->in2out.addr;
-      ed_key.r_addr = s->ext_host_addr;
-      ed_key.fib_index = 0;
-      ed_kv.key[0] = ed_key.as_u64[0];
-      ed_kv.key[1] = ed_key.as_u64[1];
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
        nat_elog_warn ("in2out_ed key del failed");
       return;
@@ -234,36 +236,36 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
       if (is_affinity_sessions (s))
        nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
                             s->in2out.protocol, s->out2in.port);
-      ed_key.l_addr = s->out2in.addr;
-      ed_key.r_addr = s->ext_host_addr;
-      ed_key.fib_index = s->out2in.fib_index;
+      l_addr = &s->out2in.addr;
+      r_addr = &s->ext_host_addr;
+      fib_index = s->out2in.fib_index;
       if (snat_is_unk_proto_session (s))
        {
-         ed_key.proto = s->in2out.port;
-         ed_key.r_port = 0;
-         ed_key.l_port = 0;
+         proto = s->in2out.port;
+         r_port = 0;
+         l_port = 0;
        }
       else
        {
-         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
-         ed_key.l_port = s->out2in.port;
-         ed_key.r_port = s->ext_host_port;
+         proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         l_port = s->out2in.port;
+         r_port = s->ext_host_port;
        }
-      ed_kv.key[0] = ed_key.as_u64[0];
-      ed_kv.key[1] = ed_key.as_u64[1];
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+                 &ed_kv);
       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
        nat_elog_warn ("out2in_ed key del failed");
-      ed_key.l_addr = s->in2out.addr;
-      ed_key.fib_index = s->in2out.fib_index;
+      l_addr = &s->in2out.addr;
+      fib_index = s->in2out.fib_index;
       if (!snat_is_unk_proto_session (s))
-       ed_key.l_port = s->in2out.port;
+       l_port = s->in2out.port;
       if (is_twice_nat_session (s))
        {
-         ed_key.r_addr = s->ext_host_nat_addr;
-         ed_key.r_port = s->ext_host_nat_port;
+         r_addr = &s->ext_host_nat_addr;
+         r_port = s->ext_host_nat_port;
        }
-      ed_kv.key[0] = ed_key.as_u64[0];
-      ed_kv.key[1] = ed_key.as_u64[1];
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+                 &ed_kv);
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
        nat_elog_warn ("in2out_ed key del failed");
 
@@ -332,7 +334,10 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
                         u32 thread_index, u8 is_ha)
 {
   snat_session_key_t key;
-  nat_ed_ses_key_t ed_key;
+  u8 proto;
+  u16 r_port, l_port;
+  ip4_address_t *l_addr, *r_addr;
+  u32 fib_index;
   clib_bihash_kv_16_8_t ed_kv;
   snat_main_per_thread_data_t *tsm =
     vec_elt_at_index (sm->per_thread_data, thread_index);
@@ -341,22 +346,22 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
     {
       if (snat_is_unk_proto_session (s))
        {
-         ed_key.proto = s->in2out.port;
-         ed_key.r_port = 0;
-         ed_key.l_port = 0;
+         proto = s->in2out.port;
+         r_port = 0;
+         l_port = 0;
        }
       else
        {
-         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
-         ed_key.l_port = s->in2out.port;
-         ed_key.r_port = s->ext_host_port;
+         proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         l_port = s->in2out.port;
+         r_port = s->ext_host_port;
        }
 
-      ed_key.l_addr = s->in2out.addr;
-      ed_key.r_addr = s->ext_host_addr;
-      ed_key.fib_index = 0;
-      ed_kv.key[0] = ed_key.as_u64[0];
-      ed_kv.key[1] = ed_key.as_u64[1];
+      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,
+                 &ed_kv);
 
       if (PREDICT_FALSE
          (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
@@ -368,41 +373,40 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
   if (is_affinity_sessions (s))
     nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
                         s->in2out.protocol, s->out2in.port);
-  ed_key.l_addr = s->out2in.addr;
-  ed_key.r_addr = s->ext_host_addr;
-  ed_key.fib_index = s->out2in.fib_index;
+  l_addr = &s->out2in.addr;
+  r_addr = &s->ext_host_addr;
+  fib_index = s->out2in.fib_index;
   if (snat_is_unk_proto_session (s))
     {
-      ed_key.proto = s->in2out.port;
-      ed_key.r_port = 0;
-      ed_key.l_port = 0;
+      proto = s->in2out.port;
+      r_port = 0;
+      l_port = 0;
     }
   else
     {
-      ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
-      ed_key.l_port = s->out2in.port;
-      ed_key.r_port = s->ext_host_port;
+      proto = snat_proto_to_ip_proto (s->in2out.protocol);
+      l_port = s->out2in.port;
+      r_port = s->ext_host_port;
     }
-  ed_kv.key[0] = ed_key.as_u64[0];
-  ed_kv.key[1] = ed_key.as_u64[1];
+  make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+             &ed_kv);
 
   if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
     nat_elog_warn ("out2in_ed key del failed");
 
-  ed_key.l_addr = s->in2out.addr;
-  ed_key.fib_index = s->in2out.fib_index;
+  l_addr = &s->in2out.addr;
+  fib_index = s->in2out.fib_index;
 
   if (!snat_is_unk_proto_session (s))
-    ed_key.l_port = s->in2out.port;
+    l_port = s->in2out.port;
 
   if (is_twice_nat_session (s))
     {
-      ed_key.r_addr = s->ext_host_nat_addr;
-      ed_key.r_port = s->ext_host_nat_port;
+      r_addr = &s->ext_host_nat_addr;
+      r_port = s->ext_host_nat_port;
     }
-
-  ed_kv.key[0] = ed_key.as_u64[0];
-  ed_kv.key[1] = ed_key.as_u64[1];
+  make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+             &ed_kv);
 
   if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
     nat_elog_warn ("in2out_ed key del failed");
@@ -2487,6 +2491,46 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses,
                                 snat_session_key_t * k,
                                 u16 port_per_thread, u32 snat_thread_index);
 
+void
+test_ed_make_split ()
+{
+  ip4_address_t l_addr;
+  l_addr.as_u8[0] = 1;
+  l_addr.as_u8[1] = 1;
+  l_addr.as_u8[2] = 1;
+  l_addr.as_u8[3] = 1;
+  ip4_address_t r_addr;
+  r_addr.as_u8[0] = 2;
+  r_addr.as_u8[1] = 2;
+  r_addr.as_u8[2] = 2;
+  r_addr.as_u8[3] = 2;
+  u16 l_port = 40001;
+  u16 r_port = 40301;
+  u8 proto = 9;
+  u32 fib_index = 9000001;
+  u64 value = ~0ULL;
+  clib_bihash_kv_16_8_t kv;
+  make_ed_kv (&l_addr, &r_addr, proto, fib_index, l_port, r_port, value, &kv);
+  ip4_address_t l_addr2;
+  ip4_address_t r_addr2;
+  clib_memset (&l_addr2, 0, sizeof (l_addr2));
+  clib_memset (&r_addr2, 0, sizeof (r_addr2));
+  u16 l_port2 = 0;
+  u16 r_port2 = 0;
+  u8 proto2 = 0;
+  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);
+}
+
 static clib_error_t *
 snat_init (vlib_main_t * vm)
 {
@@ -2656,6 +2700,7 @@ snat_init (vlib_main_t * vm)
                                         FIB_SOURCE_PRIORITY_LOW,
                                         FIB_SOURCE_BH_SIMPLE);
 
+  test_ed_make_split ();
   return error;
 }
 
@@ -3159,16 +3204,18 @@ 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];
+  u8 proto;
+  u16 r_port, l_port;
+  ip4_address_t l_addr, r_addr;
+  u32 fib_index;
 
+  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_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);
+           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);
 
   return s;
 }
@@ -3340,8 +3387,9 @@ nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
          break;
        }
 
-      make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
-                 ip->protocol, fib_index, udp->src_port, udp->dst_port);
+      make_ed_kv (&ip->src_address, &ip->dst_address,
+                 ip->protocol, fib_index, udp->src_port, udp->dst_port,
+                 ~0ULL, &kv16);
 
       /* *INDENT-OFF* */
       vec_foreach (tsm, sm->per_thread_data)
@@ -3410,8 +3458,9 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
     {
       udp = ip4_next_header (ip);
 
-      make_ed_kv (&kv16, &ip->dst_address, &ip->src_address,
-                 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port);
+      make_ed_kv (&ip->dst_address, &ip->src_address,
+                 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port,
+                 ~0ULL, &kv16);
 
       /* *INDENT-OFF* */
       vec_foreach (tsm, sm->per_thread_data)
@@ -3431,15 +3480,8 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
     }
   else if (proto == SNAT_PROTOCOL_ICMP)
     {
-      nat_ed_ses_key_t key;
-
-      if (!get_icmp_o2i_ed_key (b, ip, &key))
+      if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0ULL, 0, 0, 0, &kv16))
        {
-
-         key.fib_index = rx_fib_index;
-         kv16.key[0] = key.as_u64[0];
-         kv16.key[1] = key.as_u64[1];
-
           /* *INDENT-OFF* */
           vec_foreach (tsm, sm->per_thread_data)
             {
@@ -3796,14 +3838,14 @@ nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
   key.fib_index = fib_index;
   s->in2out = key;
 
-  make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
+  make_ed_kv (in_addr, &s->ext_host_nat_addr,
              snat_proto_to_ip_proto (proto), fib_index, in_port,
-             s->ext_host_nat_port);
+             s->ext_host_nat_port, 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 (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
-             s->out2in.fib_index, out_port, eh_port);
+  make_ed_kv (out_addr, eh_addr, snat_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))
     nat_elog_warn ("out2in key add failed");
 }
@@ -3814,7 +3856,6 @@ nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
                   u32 fib_index, u32 ti)
 {
   snat_main_t *sm = &snat_main;
-  nat_ed_ses_key_t key;
   clib_bihash_kv_16_8_t kv, value;
   u32 thread_index;
   snat_session_t *s;
@@ -3829,14 +3870,8 @@ 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);
 
-  key.l_addr.as_u32 = out_addr->as_u32;
-  key.l_port = out_port;
-  key.r_addr.as_u32 = eh_addr->as_u32;
-  key.r_port = eh_port;
-  key.proto = proto;
-  key.fib_index = fib_index;
-  kv.key[0] = key.as_u64[0];
-  kv.key[1] = key.as_u64[1];
+  make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
+             &kv);
   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
     return;
 
@@ -3852,21 +3887,14 @@ nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
                   u32 thread_index)
 {
   snat_main_t *sm = &snat_main;
-  nat_ed_ses_key_t key;
   clib_bihash_kv_16_8_t kv, value;
   snat_session_t *s;
   snat_main_per_thread_data_t *tsm;
 
   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
 
-  key.l_addr.as_u32 = out_addr->as_u32;
-  key.l_port = out_port;
-  key.r_addr.as_u32 = eh_addr->as_u32;
-  key.r_port = eh_port;
-  key.proto = proto;
-  key.fib_index = fib_index;
-  kv.key[0] = key.as_u64[0];
-  kv.key[1] = key.as_u64[1];
+  make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
+             &kv);
   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
     return;
 
@@ -4411,7 +4439,6 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
 {
   ip4_header_t ip;
   clib_bihash_16_8_t *t;
-  nat_ed_ses_key_t key;
   clib_bihash_kv_16_8_t kv, value;
   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
   snat_session_t *s;
@@ -4429,16 +4456,12 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
 
   t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
-  key.l_addr.as_u32 = addr->as_u32;
-  key.r_addr.as_u32 = eh_addr->as_u32;
-  key.l_port = clib_host_to_net_u16 (port);
-  key.r_port = clib_host_to_net_u16 (eh_port);
-  key.proto = proto;
-  key.fib_index = fib_index;
-  kv.key[0] = key.as_u64[0];
-  kv.key[1] = key.as_u64[1];
+  make_ed_kv (addr, eh_addr, proto, fib_index, clib_host_to_net_u16 (port),
+             clib_host_to_net_u16 (eh_port), ~0ULL, &kv);
   if (clib_bihash_search_16_8 (t, &kv, &value))
-    return VNET_API_ERROR_NO_SUCH_ENTRY;
+    {
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
 
   if (pool_is_free_index (tsm->sessions, value.value))
     return VNET_API_ERROR_UNSPECIFIED;
index 98c18c0..c4f1be2 100644 (file)
@@ -88,23 +88,6 @@ typedef struct
   };
 } snat_session_key_t;
 
-/* endpoint-dependent session key (6-tuple) */
-typedef struct
-{
-  union
-  {
-    struct
-    {
-      ip4_address_t l_addr;
-      ip4_address_t r_addr;
-      u32 proto:8, fib_index:24;
-      u16 l_port;
-      u16 r_port;
-    };
-    u64 as_u64[2];
-  };
-} nat_ed_ses_key_t;
-
 /* deterministic session outside key */
 typedef struct
 {
index 2afc479..a57f241 100644 (file)
@@ -258,11 +258,11 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm,
              rx_fib_index0 =
                fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
                                                     sw_if_index0);
-             make_ed_kv (&ed_kv0, &ip0->src_address,
-                         &ip0->dst_address, ip0->protocol,
-                         rx_fib_index0,
+             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);
+                         vnet_buffer (b0)->ip.reass.l4_dst_port, ~0ULL,
+                         &ed_kv0);
              /* process whole packet */
              if (!clib_bihash_search_16_8
                  (&tsm->in2out_ed, &ed_kv0, &ed_value0))
index c0b8412..bdf9e3c 100644 (file)
@@ -126,9 +126,9 @@ snat_hairpinning (snat_main_t * sm,
       if (is_ed)
        {
          clib_bihash_kv_16_8_t ed_kv, ed_value;
-         make_ed_kv (&ed_kv, &ip0->dst_address, &ip0->src_address,
+         make_ed_kv (&ip0->dst_address, &ip0->src_address,
                      ip0->protocol, sm->outside_fib_index, udp0->dst_port,
-                     udp0->src_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;
@@ -226,11 +226,12 @@ snat_icmp_hairpinning (snat_main_t * sm,
       if (is_ed)
        {
          clib_bihash_kv_16_8_t ed_kv, ed_value;
-         make_ed_kv (&ed_kv, &ip0->dst_address, &ip0->src_address,
+         make_ed_kv (&ip0->dst_address, &ip0->src_address,
                      inner_ip0->protocol, sm->outside_fib_index,
-                     l4_header->src_port, l4_header->dst_port);
-         if (clib_bihash_search_16_8 (&sm->per_thread_data[ti].out2in_ed,
-                                      &ed_kv, &ed_value))
+                     l4_header->src_port, l4_header->dst_port, ~0ULL,
+                     &ed_kv);
+         if (clib_bihash_search_16_8
+             (&sm->per_thread_data[ti].out2in_ed, &ed_kv, &ed_value))
            return 1;
          si = ed_value.value;
        }
@@ -397,8 +398,8 @@ nat44_ed_hairpinning_unknown_proto (snat_main_t * sm,
   tsm = &sm->per_thread_data[ti];
 
   old_addr = ip->dst_address.as_u32;
-  make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
-             sm->outside_fib_index, 0, 0);
+  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))
     {
       make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
index daf501d..a080356 100644 (file)
@@ -473,43 +473,67 @@ nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
 }
 
 always_inline void
-make_ed_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t * l_addr,
-           ip4_address_t * r_addr, u8 proto, u32 fib_index, u16 l_port,
-           u16 r_port)
+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)
 {
-  nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key;
-
-  key->l_addr.as_u32 = l_addr->as_u32;
-  key->r_addr.as_u32 = r_addr->as_u32;
-  key->fib_index = fib_index;
-  key->proto = proto;
-  key->l_port = l_port;
-  key->r_port = r_port;
+  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 = ~0ULL;
+always_inline void
+split_ed_kv (clib_bihash_kv_16_8_t * kv,
+            ip4_address_t * l_addr, ip4_address_t * r_addr, u8 * proto,
+            u32 * fib_index, u16 * l_port, u16 * r_port)
+{
+  if (l_addr)
+    {
+      l_addr->as_u32 = kv->key[0] & (u32) ~ 0;
+    }
+  if (r_addr)
+    {
+      r_addr->as_u32 = kv->key[0] >> 32;
+    }
+  if (r_port)
+    {
+      *r_port = kv->key[1] >> 48;
+    }
+  if (l_port)
+    {
+      *l_port = (kv->key[1] >> 32) & (u16) ~ 0;
+    }
+  if (fib_index)
+    {
+      *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
+    }
+  if (proto)
+    {
+      *proto = kv->key[1] & (u8) ~ 0;
+    }
 }
 
 always_inline void
 make_sm_kv (clib_bihash_kv_8_8_t * kv, ip4_address_t * addr, u8 proto,
            u32 fib_index, u16 port)
 {
-  snat_session_key_t key;
-
-  key.addr.as_u32 = addr->as_u32;
-  key.port = port;
-  key.protocol = proto;
-  key.fib_index = fib_index;
+  kv->key = (u64) fib_index << 51 | (u64) proto << 48 | (u64) port << 32 |
+    addr->as_u32;
 
-  kv->key = key.as_u64;
   kv->value = ~0ULL;
 }
 
 static_always_inline int
-get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0,
-                    nat_ed_ses_key_t * p_key0)
+get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
+                    u64 value, u8 * snat_proto, u16 * l_port, u16 * r_port,
+                    clib_bihash_kv_16_8_t * kv)
 {
+  u8 proto;
+  u16 _l_port, _r_port;
+  ip4_address_t *l_addr, *r_addr;
+
   icmp46_header_t *icmp0;
-  nat_ed_ses_key_t key0;
   icmp_echo_header_t *echo0, *inner_echo0 = 0;
   ip4_header_t *inner_ip0 = 0;
   void *l4_header = 0;
@@ -521,47 +545,63 @@ get_icmp_i2o_ed_key (vlib_buffer_t * b, ip4_header_t * ip0,
   if (!icmp_type_is_error_message
       (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
     {
-      key0.proto = IP_PROTOCOL_ICMP;
-      key0.l_addr = ip0->src_address;
-      key0.r_addr = ip0->dst_address;
-      key0.l_port = vnet_buffer (b)->ip.reass.l4_src_port;     // TODO should this be src or dst?
-      key0.r_port = 0;
+      proto = IP_PROTOCOL_ICMP;
+      l_addr = &ip0->src_address;
+      r_addr = &ip0->dst_address;
+      _l_port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be src or dst?
+      _r_port = 0;
     }
   else
     {
       inner_ip0 = (ip4_header_t *) (echo0 + 1);
       l4_header = ip4_next_header (inner_ip0);
-      key0.proto = inner_ip0->protocol;
-      key0.r_addr = inner_ip0->src_address;
-      key0.l_addr = inner_ip0->dst_address;
+      proto = inner_ip0->protocol;
+      r_addr = &inner_ip0->src_address;
+      l_addr = &inner_ip0->dst_address;
       switch (ip_proto_to_snat_proto (inner_ip0->protocol))
        {
        case SNAT_PROTOCOL_ICMP:
          inner_icmp0 = (icmp46_header_t *) l4_header;
          inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
-         key0.r_port = 0;
-         key0.l_port = inner_echo0->identifier;
+         _r_port = 0;
+         _l_port = inner_echo0->identifier;
          break;
        case SNAT_PROTOCOL_UDP:
        case SNAT_PROTOCOL_TCP:
-         key0.l_port = ((tcp_udp_header_t *) l4_header)->dst_port;
-         key0.r_port = ((tcp_udp_header_t *) l4_header)->src_port;
+         _l_port = ((tcp_udp_header_t *) l4_header)->dst_port;
+         _r_port = ((tcp_udp_header_t *) l4_header)->src_port;
          break;
        default:
          return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
        }
     }
-  *p_key0 = key0;
+  make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port, value,
+             kv);
+  if (snat_proto)
+    {
+      *snat_proto = ip_proto_to_snat_proto (proto);
+    }
+  if (l_port)
+    {
+      *l_port = _l_port;
+    }
+  if (r_port)
+    {
+      *r_port = _r_port;
+    }
   return 0;
 }
 
 
 static_always_inline int
-get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0,
-                    nat_ed_ses_key_t * p_key0)
+get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0, u32 rx_fib_index,
+                    u64 value, u8 * snat_proto, u16 * l_port, u16 * r_port,
+                    clib_bihash_kv_16_8_t * kv)
 {
   icmp46_header_t *icmp0;
-  nat_ed_ses_key_t key0;
+  u8 proto;
+  ip4_address_t *l_addr, *r_addr;
+  u16 _l_port, _r_port;
   icmp_echo_header_t *echo0, *inner_echo0 = 0;
   ip4_header_t *inner_ip0;
   void *l4_header = 0;
@@ -573,37 +613,50 @@ get_icmp_o2i_ed_key (vlib_buffer_t * b, ip4_header_t * ip0,
   if (!icmp_type_is_error_message
       (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
     {
-      key0.proto = IP_PROTOCOL_ICMP;
-      key0.l_addr = ip0->dst_address;
-      key0.r_addr = ip0->src_address;
-      key0.l_port = vnet_buffer (b)->ip.reass.l4_src_port;     // TODO should this be src or dst?
-      key0.r_port = 0;
+      proto = IP_PROTOCOL_ICMP;
+      l_addr = &ip0->dst_address;
+      r_addr = &ip0->src_address;
+      _l_port = vnet_buffer (b)->ip.reass.l4_src_port; // TODO should this be src or dst?
+      _r_port = 0;
     }
   else
     {
       inner_ip0 = (ip4_header_t *) (echo0 + 1);
       l4_header = ip4_next_header (inner_ip0);
-      key0.proto = inner_ip0->protocol;
-      key0.l_addr = inner_ip0->src_address;
-      key0.r_addr = inner_ip0->dst_address;
+      proto = inner_ip0->protocol;
+      l_addr = &inner_ip0->src_address;
+      r_addr = &inner_ip0->dst_address;
       switch (ip_proto_to_snat_proto (inner_ip0->protocol))
        {
        case SNAT_PROTOCOL_ICMP:
          inner_icmp0 = (icmp46_header_t *) l4_header;
          inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
-         key0.l_port = inner_echo0->identifier;
-         key0.r_port = 0;
+         _l_port = inner_echo0->identifier;
+         _r_port = 0;
          break;
        case SNAT_PROTOCOL_UDP:
        case SNAT_PROTOCOL_TCP:
-         key0.l_port = ((tcp_udp_header_t *) l4_header)->src_port;
-         key0.r_port = ((tcp_udp_header_t *) l4_header)->dst_port;
+         _l_port = ((tcp_udp_header_t *) l4_header)->src_port;
+         _r_port = ((tcp_udp_header_t *) l4_header)->dst_port;
          break;
        default:
          return -1;
        }
     }
-  *p_key0 = key0;
+  make_ed_kv (l_addr, r_addr, proto, rx_fib_index, _l_port, _r_port, value,
+             kv);
+  if (snat_proto)
+    {
+      *snat_proto = ip_proto_to_snat_proto (proto);
+    }
+  if (l_port)
+    {
+      *l_port = _l_port;
+    }
+  if (r_port)
+    {
+      *r_port = _r_port;
+    }
   return 0;
 }
 
index 560dc0d..1382125 100644 (file)
@@ -94,7 +94,10 @@ nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
   nat44_is_idle_session_ctx_t *ctx = arg;
   snat_session_t *s;
   u64 sess_timeout_time;
-  nat_ed_ses_key_t ed_key;
+  u8 proto;
+  u16 r_port, l_port;
+  ip4_address_t *l_addr, *r_addr;
+  u32 fib_index;
   clib_bihash_kv_16_8_t ed_kv;
   int i;
   snat_address_t *a;
@@ -106,28 +109,28 @@ nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
   if (ctx->now >= sess_timeout_time)
     {
-      ed_key.l_addr = s->in2out.addr;
-      ed_key.r_addr = s->ext_host_addr;
-      ed_key.fib_index = s->in2out.fib_index;
+      l_addr = &s->in2out.addr;
+      r_addr = &s->ext_host_addr;
+      fib_index = s->in2out.fib_index;
       if (snat_is_unk_proto_session (s))
        {
-         ed_key.proto = s->in2out.port;
-         ed_key.r_port = 0;
-         ed_key.l_port = 0;
+         proto = s->in2out.port;
+         r_port = 0;
+         l_port = 0;
        }
       else
        {
-         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
-         ed_key.l_port = s->in2out.port;
-         ed_key.r_port = s->ext_host_port;
+         proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         l_port = s->in2out.port;
+         r_port = s->ext_host_port;
        }
       if (is_twice_nat_session (s))
        {
-         ed_key.r_addr = s->ext_host_nat_addr;
-         ed_key.r_port = s->ext_host_nat_port;
+         r_addr = &s->ext_host_nat_addr;
+         r_port = s->ext_host_nat_port;
        }
-      ed_kv.key[0] = ed_key.as_u64[0];
-      ed_kv.key[1] = ed_key.as_u64[1];
+      make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
+                 &ed_kv);
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
        nat_elog_warn ("in2out_ed key del failed");
 
@@ -233,9 +236,9 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
   s->in2out.protocol = s->out2in.protocol;
 
   /* Add to lookup tables */
-  make_ed_kv (&kv, &e_key.addr, &s->ext_host_addr, ip->protocol,
-             e_key.fib_index, e_key.port, s->ext_host_port);
-  kv.value = s - tsm->sessions;
+  make_ed_kv (&e_key.addr, &s->ext_host_addr, ip->protocol,
+             e_key.fib_index, e_key.port, s->ext_host_port,
+             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,
@@ -261,15 +264,16 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
       s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
       s->ext_host_nat_port = eh_key.port;
       s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
-      make_ed_kv (&kv, &l_key.addr, &s->ext_host_nat_addr, ip->protocol,
-                 l_key.fib_index, l_key.port, s->ext_host_nat_port);
+      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);
     }
   else
     {
-      make_ed_kv (&kv, &l_key.addr, &s->ext_host_addr, ip->protocol,
-                 l_key.fib_index, l_key.port, s->ext_host_port);
+      make_ed_kv (&l_key.addr, &s->ext_host_addr, ip->protocol,
+                 l_key.fib_index, l_key.port, s->ext_host_port,
+                 s - tsm->sessions, &kv);
     }
-  kv.value = s - tsm->sessions;
   if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv,
                                               nat44_i2o_ed_is_idle_session_cb,
                                               &ctx))
@@ -299,14 +303,14 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
 }
 
 static int
-next_src_nat (snat_main_t * sm, ip4_header_t * ip, u8 proto, u16 src_port,
+next_src_nat (snat_main_t * sm, ip4_header_t * ip, u16 src_port,
              u16 dst_port, u32 thread_index, u32 rx_fib_index)
 {
   clib_bihash_kv_16_8_t kv, value;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
 
-  make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto,
-             rx_fib_index, src_port, dst_port);
+  make_ed_kv (&ip->src_address, &ip->dst_address, ip->protocol,
+             rx_fib_index, src_port, dst_port, ~0ULL, &kv);
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     return 1;
 
@@ -317,37 +321,35 @@ static void
 create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
                       u32 rx_fib_index, u32 thread_index)
 {
-  nat_ed_ses_key_t key;
   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);
+  u16 l_port, r_port;
 
   if (ip->protocol == IP_PROTOCOL_ICMP)
     {
-      if (get_icmp_o2i_ed_key (b, ip, &key))
+      if (get_icmp_o2i_ed_key
+         (b, ip, rx_fib_index, ~0ULL, 0, &l_port, &r_port, &kv))
        return;
     }
-  else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
-    {
-      udp = ip4_next_header (ip);
-      key.r_addr = ip->src_address;
-      key.l_addr = ip->dst_address;
-      key.proto = ip->protocol;
-      key.l_port = udp->dst_port;
-      key.r_port = udp->src_port;
-    }
   else
     {
-      key.r_addr = ip->src_address;
-      key.l_addr = ip->dst_address;
-      key.proto = ip->protocol;
-      key.l_port = key.r_port = 0;
+      if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
+       {
+         udp = ip4_next_header (ip);
+         l_port = udp->dst_port;
+         r_port = udp->src_port;
+       }
+      else
+       {
+         l_port = 0;
+         r_port = 0;
+       }
+      make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
+                 rx_fib_index, l_port, r_port, ~0ULL, &kv);
     }
-  key.fib_index = 0;
-  kv.key[0] = key.as_u64[0];
-  kv.key[1] = key.as_u64[1];
 
   if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
     {
@@ -367,13 +369,13 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
          return;
        }
 
-      proto = ip_proto_to_snat_proto (key.proto);
+      proto = ip_proto_to_snat_proto (ip->protocol);
 
-      s->ext_host_addr = key.r_addr;
-      s->ext_host_port = key.r_port;
+      s->ext_host_addr = ip->src_address;
+      s->ext_host_port = r_port;
       s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
-      s->out2in.addr = key.l_addr;
-      s->out2in.port = key.l_port;
+      s->out2in.addr = ip->dst_address;
+      s->out2in.port = l_port;
       s->out2in.protocol = proto;
       if (proto == ~0)
        {
@@ -423,32 +425,30 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
                      u8 * p_dont_translate, void *d, void *e)
 {
   u32 next = ~0, sw_if_index, rx_fib_index;
-  nat_ed_ses_key_t key;
   clib_bihash_kv_16_8_t kv, value;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
   snat_session_t *s = 0;
   u8 dont_translate = 0, is_addr_only, identity_nat;
   snat_session_key_t e_key, l_key;
+  u16 l_port, r_port;
 
   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
 
-  if (get_icmp_o2i_ed_key (b, ip, &key))
+  if (get_icmp_o2i_ed_key
+      (b, ip, rx_fib_index, ~0ULL, p_proto, &l_port, &r_port, &kv))
     {
       b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
       next = NAT_NEXT_DROP;
       goto out;
     }
-  key.fib_index = rx_fib_index;
-  kv.key[0] = key.as_u64[0];
-  kv.key[1] = key.as_u64[1];
 
   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
     {
       /* Try to match static mapping */
       e_key.addr = ip->dst_address;
-      e_key.port = key.l_port;
-      e_key.protocol = ip_proto_to_snat_proto (key.proto);
+      e_key.port = l_port;
+      e_key.protocol = ip_proto_to_snat_proto (ip->protocol);
       e_key.fib_index = rx_fib_index;
       if (snat_static_mapping_match
          (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0, &identity_nat))
@@ -469,7 +469,7 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
          else
            {
              dont_translate = 1;
-             if (next_src_nat (sm, ip, key.proto, key.l_port, key.r_port,
+             if (next_src_nat (sm, ip, l_port, r_port,
                                thread_index, rx_fib_index))
                {
                  next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
@@ -529,8 +529,6 @@ icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
 
       s = pool_elt_at_index (tsm->sessions, value.value);
     }
-
-  *p_proto = ip_proto_to_snat_proto (key.proto);
 out:
   if (s)
     *p_value = s->in2out;
@@ -560,8 +558,8 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm,
 
   old_addr = ip->dst_address.as_u32;
 
-  make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
-             rx_fib_index, 0, 0);
+  make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol, rx_fib_index,
+             0, 0, ~0ULL, &s_kv);
 
   if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
     {
@@ -613,9 +611,8 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm,
       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
        nat_elog_notice ("out2in key add failed");
 
-      make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
-                 m->fib_index, 0, 0);
-      s_kv.value = s - tsm->sessions;
+      make_ed_kv (&ip->dst_address, &ip->src_address, ip->protocol,
+                 m->fib_index, 0, 0, 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");
     }
@@ -721,10 +718,10 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address,
+         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);
+                     vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0);
 
          if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
            {
@@ -1006,10 +1003,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address,
+         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);
+                     vnet_buffer (b0)->ip.reass.l4_src_port, ~0ULL, &kv0);
 
          s0 = NULL;
          if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
@@ -1059,12 +1056,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
                    }
                  else
                    {
-                     if (next_src_nat (sm, ip0, ip0->protocol,
-                                       vnet_buffer (b0)->ip.
-                                       reass.l4_src_port,
-                                       vnet_buffer (b0)->ip.
-                                       reass.l4_dst_port, thread_index,
-                                       rx_fib_index0))
+                     if (next_src_nat
+                         (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
+                          vnet_buffer (b0)->ip.reass.l4_dst_port,
+                          thread_index, rx_fib_index0))
                        {
                          next0 = NAT_NEXT_IN2OUT_ED_FAST_PATH;
                          goto trace0;