nat: static mappings in flow hash
[vpp.git] / src / plugins / nat / nat44-ei / nat44_ei.c
index 6775701..3691af3 100644 (file)
@@ -86,6 +86,12 @@ VNET_FEATURE_INIT (ip4_nat_classify, static) = {
   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
                               "ip4-sv-reassembly-feature"),
 };
+VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-handoff-classify",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature"),
+};
 VNET_FEATURE_INIT (ip4_nat44_ei_in2out, static) = {
   .arc_name = "ip4-unicast",
   .node_name = "nat44-ei-in2out",
@@ -322,8 +328,6 @@ nat44_ei_init (vlib_main_t *vm)
   nm->fq_out2in_index = ~0;
   nm->fq_in2out_index = ~0;
   nm->fq_in2out_output_index = ~0;
-  nm->worker_in2out_cb = nat44_ei_get_in2out_worker_index;
-  nm->worker_out2in_cb = nat44_ei_get_out2in_worker_index;
 
   nm->log_level = NAT_LOG_ERROR;
 
@@ -424,6 +428,9 @@ nat44_ei_plugin_enable (nat44_ei_config_t c)
   if (!c.sessions)
     c.sessions = 10 * 1024;
 
+  if (!c.user_sessions)
+    c.user_sessions = c.sessions;
+
   nm->rconfig = c;
 
   if (!nm->frame_queue_nelts)
@@ -444,8 +451,7 @@ nat44_ei_plugin_enable (nat44_ei_config_t c)
 
   nm->max_users_per_thread = c.users;
   nm->max_translations_per_thread = c.sessions;
-  nm->max_translations_per_user =
-    c.user_sessions ? c.user_sessions : nm->max_translations_per_thread;
+  nm->max_translations_per_user = c.user_sessions;
 
   nm->inside_vrf_id = c.inside_vrf;
   nm->inside_fib_index = fib_table_find_or_create_and_lock (
@@ -577,7 +583,9 @@ feature_set:
 
                  if (nm->num_workers > 1)
                    {
-                     del_feature_name = "nat44-handoff-classify";
+                     del_feature_name = "nat44-ei-handoff-classify";
+                     clib_warning (
+                       "del_feature_name = nat44-ei-handoff-classify");
                      feature_name = !is_inside ?
                                       "nat44-ei-in2out-worker-handoff" :
                                       "nat44-ei-out2in-worker-handoff";
@@ -585,6 +593,7 @@ feature_set:
                  else
                    {
                      del_feature_name = "nat44-ei-classify";
+                     clib_warning ("del_feature_name = nat44-ei-classify");
                      feature_name =
                        !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
                    }
@@ -593,15 +602,21 @@ feature_set:
                    ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
                  if (rv)
                    return rv;
-                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
-                                              sw_if_index, 0, 0, 0);
-                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
-                                              sw_if_index, 1, 0, 0);
+                 rv = vnet_feature_enable_disable (
+                   "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0);
+                 if (rv)
+                   return rv;
+                 rv = vnet_feature_enable_disable (
+                   "ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
+                 if (rv)
+                   return rv;
                  if (!is_inside)
                    {
-                     vnet_feature_enable_disable ("ip4-local",
-                                                  "nat44-ei-hairpinning",
-                                                  sw_if_index, 1, 0, 0);
+                     rv = vnet_feature_enable_disable ("ip4-local",
+                                                       "nat44-ei-hairpinning",
+                                                       sw_if_index, 1, 0, 0);
+                     if (rv)
+                       return rv;
                    }
                }
              else
@@ -610,14 +625,18 @@ feature_set:
                    ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
                  if (rv)
                    return rv;
-                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
-                                              sw_if_index, 0, 0, 0);
+                 rv = vnet_feature_enable_disable (
+                   "ip4-unicast", feature_name, sw_if_index, 0, 0, 0);
+                 if (rv)
+                   return rv;
                  pool_put (nm->interfaces, i);
                  if (is_inside)
                    {
-                     vnet_feature_enable_disable ("ip4-local",
-                                                  "nat44-ei-hairpinning",
-                                                  sw_if_index, 0, 0, 0);
+                     rv = vnet_feature_enable_disable ("ip4-local",
+                                                       "nat44-ei-hairpinning",
+                                                       sw_if_index, 0, 0, 0);
+                     if (rv)
+                       return rv;
                    }
                }
            }
@@ -632,27 +651,35 @@ feature_set:
                  del_feature_name = !is_inside ?
                                       "nat44-ei-in2out-worker-handoff" :
                                       "nat44-ei-out2in-worker-handoff";
-                 feature_name = "nat44-handoff-classify";
+                 feature_name = "nat44-ei-handoff-classify";
+                 clib_warning ("feature_name = nat44-ei-handoff-classify");
                }
              else
                {
                  del_feature_name =
                    !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
                  feature_name = "nat44-ei-classify";
+                 clib_warning ("feature_name = nat44-ei-classify");
                }
 
              int rv =
                ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
              if (rv)
                return rv;
-             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
-                                          sw_if_index, 0, 0, 0);
-             vnet_feature_enable_disable ("ip4-unicast", feature_name,
-                                          sw_if_index, 1, 0, 0);
+             rv = vnet_feature_enable_disable (
+               "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0);
+             if (rv)
+               return rv;
+             rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                               sw_if_index, 1, 0, 0);
+             if (rv)
+               return rv;
              if (!is_inside)
                {
-                 vnet_feature_enable_disable (
+                 rv = vnet_feature_enable_disable (
                    "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
+                 if (rv)
+                   return rv;
                }
              goto set_flags;
            }
@@ -672,17 +699,21 @@ feature_set:
   i->flags = 0;
   nat_validate_interface_counters (nm, sw_if_index);
 
-  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
-                              0);
+  int rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                       sw_if_index, 1, 0, 0);
+  if (rv)
+    return rv;
 
-  int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+  rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
   if (rv)
     return rv;
 
   if (is_inside && !nm->out2in_dpo)
     {
-      vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning",
-                                  sw_if_index, 1, 0, 0);
+      rv = vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning",
+                                       sw_if_index, 1, 0, 0);
+      if (rv)
+       return rv;
     }
 
 set_flags:
@@ -777,10 +808,14 @@ feature_set:
        ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
       if (rv)
        return rv;
-      vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-hairpin-dst",
-                                  sw_if_index, !is_del, 0, 0);
-      vnet_feature_enable_disable ("ip4-output", "nat44-ei-hairpin-src",
-                                  sw_if_index, !is_del, 0, 0);
+      rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-hairpin-dst",
+                                       sw_if_index, !is_del, 0, 0);
+      if (rv)
+       return rv;
+      rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-hairpin-src",
+                                       sw_if_index, !is_del, 0, 0);
+      if (rv)
+       return rv;
       goto fq;
     }
 
@@ -793,12 +828,16 @@ feature_set:
        ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
       if (rv)
        return rv;
-      vnet_feature_enable_disable ("ip4-unicast",
-                                  "nat44-ei-out2in-worker-handoff",
-                                  sw_if_index, !is_del, 0, 0);
-      vnet_feature_enable_disable ("ip4-output",
-                                  "nat44-ei-in2out-output-worker-handoff",
-                                  sw_if_index, !is_del, 0, 0);
+      rv = vnet_feature_enable_disable ("ip4-unicast",
+                                       "nat44-ei-out2in-worker-handoff",
+                                       sw_if_index, !is_del, 0, 0);
+      if (rv)
+       return rv;
+      rv = vnet_feature_enable_disable (
+       "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index,
+       !is_del, 0, 0);
+      if (rv)
+       return rv;
     }
   else
     {
@@ -809,10 +848,14 @@ feature_set:
        ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
       if (rv)
        return rv;
-      vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
-                                  sw_if_index, !is_del, 0, 0);
-      vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
-                                  sw_if_index, !is_del, 0, 0);
+      rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
+                                       sw_if_index, !is_del, 0, 0);
+      if (rv)
+       return rv;
+      rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
+                                       sw_if_index, !is_del, 0, 0);
+      if (rv)
+       return rv;
     }
 
 fq:
@@ -877,12 +920,12 @@ int
 nat44_ei_plugin_disable ()
 {
   nat44_ei_main_t *nm = &nat44_ei_main;
-  nat44_ei_interface_t *i, *vec;
+  nat44_ei_interface_t *i, *pool;
   int error = 0;
 
   // first unregister all nodes from interfaces
-  vec = vec_dup (nm->interfaces);
-  vec_foreach (i, vec)
+  pool = pool_dup (nm->interfaces);
+  pool_foreach (i, pool)
     {
       if (nat44_ei_interface_is_inside (i))
        error = nat44_ei_interface_add_del (i->sw_if_index, 1, 1);
@@ -895,11 +938,11 @@ nat44_ei_plugin_disable ()
                            i->sw_if_index);
        }
     }
-  vec_free (vec);
-  nm->interfaces = 0;
+  pool_free (pool);
+  pool_free (nm->interfaces);
 
-  vec = vec_dup (nm->output_feature_interfaces);
-  vec_foreach (i, vec)
+  pool = pool_dup (nm->output_feature_interfaces);
+  pool_foreach (i, pool)
     {
       if (nat44_ei_interface_is_inside (i))
        error =
@@ -914,8 +957,8 @@ nat44_ei_plugin_disable ()
                            i->sw_if_index);
        }
     }
-  vec_free (vec);
-  nm->output_feature_interfaces = 0;
+  pool_free (pool);
+  pool_free (nm->output_feature_interfaces);
 
   nat_ha_disable ();
   nat44_ei_db_free ();
@@ -933,7 +976,7 @@ nat44_ei_plugin_disable ()
   nm->enabled = 0;
   clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
 
-  return error;
+  return 0;
 }
 
 int
@@ -1059,7 +1102,8 @@ nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s,
       /* log NAT event */
       nat_ipfix_logging_nat44_ses_delete (
        thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
-       s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+       nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+       s->in2out.fib_index);
 
       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
                   s->ext_host_port, s->nat_proto, s->out2in.fib_index,
@@ -1227,7 +1271,8 @@ nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
 
       nat_ipfix_logging_nat44_ses_delete (
        thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
-       s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+       nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+       s->in2out.fib_index);
 
       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
                   s->ext_host_port, s->nat_proto, s->out2in.fib_index,
@@ -1744,26 +1789,23 @@ nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
 {
   nat44_ei_main_per_thread_data_t *tnm;
   clib_bihash_kv_8_8_t kv, value;
-  ip4_header_t ip;
   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
   nat44_ei_session_t *s;
   clib_bihash_8_8_t *t;
 
-  ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
-  if (nm->num_workers > 1)
-    tnm = vec_elt_at_index (nm->per_thread_data,
-                           nm->worker_in2out_cb (&ip, fib_index, 0));
-  else
-    tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
-
   init_nat_k (&kv, *addr, port, fib_index, proto);
   t = is_in ? &nm->in2out : &nm->out2in;
   if (!clib_bihash_search_8_8 (t, &kv, &value))
     {
-      if (pool_is_free_index (tnm->sessions, value.value))
+      // this is called from API/CLI, so the world is stopped here
+      // it's safe to manipulate arbitrary per-thread data
+      u32 thread_index = nat_value_get_thread_index (&value);
+      tnm = vec_elt_at_index (nm->per_thread_data, thread_index);
+      u32 session_index = nat_value_get_session_index (&value);
+      if (pool_is_free_index (tnm->sessions, session_index))
        return VNET_API_ERROR_UNSPECIFIED;
 
-      s = pool_elt_at_index (tnm->sessions, value.value);
+      s = pool_elt_at_index (tnm->sessions, session_index);
       nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data, 0);
       nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
       return 0;
@@ -2036,7 +2078,8 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
          ip4_header_t ip = {
            .src_address = m->local_addr,
          };
-         vec_add1 (m->workers, nm->worker_in2out_cb (&ip, m->fib_index, 0));
+         vec_add1 (m->workers,
+                   nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0));
          tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
        }
       else
@@ -2321,8 +2364,9 @@ format_nat44_ei_session_kvp (u8 *s, va_list *args)
 {
   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
 
-  s =
-    format (s, "%U session-index %llu", format_nat44_ei_key, v->key, v->value);
+  s = format (s, "%U thread-index %llu session-index %llu",
+             format_nat44_ei_key, v->key, nat_value_get_thread_index (v),
+             nat_value_get_session_index (v));
 
   return s;
 }
@@ -2900,8 +2944,9 @@ match:
                        "i4", rv);
 }
 
-VLIB_NODE_FN (nat44_ei_classify_node)
-(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+static_always_inline uword
+nat44_ei_classify_inline_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+                            vlib_frame_t *frame)
 {
   u32 n_left_from, *from, *to_next;
   nat44_ei_classify_next_t next_index;
@@ -3000,6 +3045,12 @@ VLIB_NODE_FN (nat44_ei_classify_node)
   return frame->n_vectors;
 }
 
+VLIB_NODE_FN (nat44_ei_classify_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return nat44_ei_classify_inline_fn (vm, node, frame);
+}
+
 VLIB_REGISTER_NODE (nat44_ei_classify_node) = {
   .name = "nat44-ei-classify",
   .vector_size = sizeof (u32),
@@ -3015,6 +3066,27 @@ VLIB_REGISTER_NODE (nat44_ei_classify_node) = {
   },
 };
 
+VLIB_NODE_FN (nat44_ei_handoff_classify_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return nat44_ei_classify_inline_fn (vm, node, frame);
+}
+
+VLIB_REGISTER_NODE (nat44_ei_handoff_classify_node) = {
+  .name = "nat44-ei-handoff-classify",
+  .vector_size = sizeof (u32),
+  .format_trace = format_nat44_ei_classify_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(nat44_ei_classify_error_strings),
+  .error_strings = nat44_ei_classify_error_strings,
+  .n_next_nodes = NAT44_EI_CLASSIFY_N_NEXT,
+  .next_nodes = {
+    [NAT44_EI_CLASSIFY_NEXT_IN2OUT] = "nat44-ei-in2out-worker-handoff",
+    [NAT44_EI_CLASSIFY_NEXT_OUT2IN] = "nat44-ei-out2in-worker-handoff",
+    [NAT44_EI_CLASSIFY_NEXT_DROP] = "error-drop",
+  },
+};
+
 /*
  * fd.io coding-style-patch-verification: ON
  *