nat: fixed return values of enable/disable call
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed.c
index bf802f5..348fff2 100644 (file)
@@ -59,7 +59,7 @@ static_always_inline void nat_validate_interface_counters (snat_main_t *sm,
       if (PREDICT_FALSE (sm->enabled))                                        \
        {                                                                     \
          nat_log_err ("plugin enabled");                                     \
-         return 1;                                                           \
+         return VNET_API_ERROR_FEATURE_ALREADY_ENABLED;                      \
        }                                                                     \
     }                                                                         \
   while (0)
@@ -71,7 +71,7 @@ static_always_inline void nat_validate_interface_counters (snat_main_t *sm,
       if (PREDICT_FALSE (!sm->enabled))                                       \
        {                                                                     \
          nat_log_err ("plugin disabled");                                    \
-         return 1;                                                           \
+         return VNET_API_ERROR_FEATURE_ALREADY_DISABLED;                     \
        }                                                                     \
     }                                                                         \
   while (0)
@@ -286,8 +286,7 @@ nat44_ed_resolve_nat_addr_len (snat_address_t *ap,
        {
          ap->addr_len = ia->address_length;
          ap->sw_if_index = i->sw_if_index;
-         ap->net.as_u32 = (ap->addr.as_u32 >> (32 - ap->addr_len))
-                          << (32 - ap->addr_len);
+         ap->net.as_u32 = ap->addr.as_u32 & ip4_main.fib_masks[ap->addr_len];
 
          nat_log_debug ("pool addr %U binds to -> sw_if_idx: %u net: %U/%u",
                         format_ip4_address, &ap->addr, ap->sw_if_index,
@@ -334,8 +333,7 @@ nat44_ed_bind_if_addr_to_nat_addr (u32 sw_if_index)
        {
          ap->addr_len = ia->address_length;
          ap->sw_if_index = sw_if_index;
-         ap->net.as_u32 = (ap->addr.as_u32 >> (32 - ap->addr_len))
-                          << (32 - ap->addr_len);
+         ap->net.as_u32 = ap->addr.as_u32 & ip4_main.fib_masks[ap->addr_len];
 
          nat_log_debug ("pool addr %U binds to -> sw_if_idx: %u net: %U/%u",
                         format_ip4_address, &ap->addr, ap->sw_if_index,
@@ -626,6 +624,134 @@ nat44_ed_del_address (ip4_address_t addr, u8 twice_nat)
   return 0;
 }
 
+vrf_table_t *
+nat44_ed_get_vrf_table (u32 table_vrf_id)
+{
+  snat_main_t *sm = &snat_main;
+  vrf_table_t *t;
+
+  pool_foreach (t, sm->vrf_tables)
+    {
+      if (table_vrf_id == t->table_vrf_id)
+       {
+         return t;
+       }
+    }
+  return NULL;
+}
+
+vrf_route_t *
+nat44_ed_get_vrf_route (vrf_table_t *t, u32 vrf_id)
+{
+  vrf_route_t *r;
+
+  pool_foreach (r, t->routes)
+    {
+      if (vrf_id == r->vrf_id)
+       {
+         return r;
+       }
+    }
+  return NULL;
+}
+
+int
+nat44_ed_add_del_vrf_table (u32 table_vrf_id, bool is_add)
+{
+  snat_main_t *sm = &snat_main;
+  vrf_table_t *t;
+  vrf_route_t *r;
+
+  t = nat44_ed_get_vrf_table (table_vrf_id);
+  if (t)
+    {
+      if (is_add)
+       {
+         return VNET_API_ERROR_VALUE_EXIST;
+       }
+      pool_foreach (r, t->routes)
+       {
+         fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
+       }
+      fib_table_unlock (t->table_fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
+
+      pool_free (t->routes);
+      pool_put (sm->vrf_tables, t);
+    }
+  else
+    {
+      if (!is_add)
+       {
+         return VNET_API_ERROR_NO_SUCH_ENTRY;
+       }
+      pool_get (sm->vrf_tables, t);
+      clib_memset (t, 0, sizeof (*t));
+      t->table_vrf_id = table_vrf_id;
+      t->table_fib_index = fib_table_find_or_create_and_lock (
+       FIB_PROTOCOL_IP4, table_vrf_id, sm->fib_src_low);
+    }
+
+  return 0;
+}
+
+void
+nat44_ed_del_vrf_tables ()
+{
+  snat_main_t *sm = &snat_main;
+  vrf_table_t *t;
+  vrf_route_t *r;
+
+  pool_foreach (t, sm->vrf_tables)
+    {
+      pool_foreach (r, t->routes)
+       {
+         fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
+       }
+      fib_table_unlock (t->table_fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
+      pool_free (t->routes);
+    }
+  pool_free (sm->vrf_tables);
+}
+
+int
+nat44_ed_add_del_vrf_route (u32 table_vrf_id, u32 vrf_id, bool is_add)
+{
+  snat_main_t *sm = &snat_main;
+  vrf_table_t *t;
+  vrf_route_t *r;
+
+  t = nat44_ed_get_vrf_table (table_vrf_id);
+  if (!t)
+    {
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
+
+  r = nat44_ed_get_vrf_route (t, vrf_id);
+  if (r)
+    {
+      if (is_add)
+       {
+         return VNET_API_ERROR_VALUE_EXIST;
+       }
+      fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
+      pool_put (t->routes, r);
+    }
+  else
+    {
+      if (!is_add)
+       {
+         return VNET_API_ERROR_NO_SUCH_ENTRY;
+       }
+      pool_get (t->routes, r);
+      clib_memset (r, 0, sizeof (*r));
+      r->vrf_id = vrf_id;
+      r->fib_index = fib_table_find_or_create_and_lock (
+       FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
+    }
+
+  return 0;
+}
+
 u32
 get_thread_idx_by_port (u16 e_port)
 {
@@ -633,9 +759,9 @@ get_thread_idx_by_port (u16 e_port)
   u32 thread_idx = sm->num_workers;
   if (sm->num_workers > 1)
     {
-      thread_idx =
-       sm->first_worker_index +
-       sm->workers[(e_port - 1024) / sm->port_per_thread];
+      thread_idx = sm->first_worker_index +
+                  sm->workers[(e_port - ED_USER_PORT_OFFSET) /
+                              sm->port_per_thread % _vec_len (sm->workers)];
     }
   return thread_idx;
 }
@@ -1507,19 +1633,19 @@ expire_per_vrf_sessions (u32 fib_index)
 
   vec_foreach (tsm, sm->per_thread_data)
     {
-      vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
-        {
-          if ((per_vrf_sessions->rx_fib_index == fib_index) ||
-              (per_vrf_sessions->tx_fib_index == fib_index))
-            {
-              per_vrf_sessions->expired = 1;
-            }
-        }
+      pool_foreach (per_vrf_sessions, tsm->per_vrf_sessions_pool)
+       {
+         if ((per_vrf_sessions->rx_fib_index == fib_index) ||
+             (per_vrf_sessions->tx_fib_index == fib_index))
+           {
+             per_vrf_sessions->expired = 1;
+           }
+       }
     }
 }
 
 void
-update_per_vrf_sessions_vec (u32 fib_index, int is_del)
+update_per_vrf_sessions_pool (u32 fib_index, int is_del)
 {
   snat_main_t *sm = &snat_main;
   nat_fib_t *fib;
@@ -1555,10 +1681,10 @@ update_per_vrf_sessions_vec (u32 fib_index, int is_del)
     }
 }
 
-static_always_inline nat_outside_fib_t *
-nat44_ed_get_outside_fib (nat_outside_fib_t *outside_fibs, u32 fib_index)
+static_always_inline nat_fib_t *
+nat44_ed_get_outside_fib (nat_fib_t *outside_fibs, u32 fib_index)
 {
-  nat_outside_fib_t *f;
+  nat_fib_t *f;
   vec_foreach (f, outside_fibs)
     {
       if (f->fib_index == fib_index)
@@ -1589,7 +1715,7 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside)
   const char *del_feature_name, *feature_name;
   snat_main_t *sm = &snat_main;
 
-  nat_outside_fib_t *outside_fib;
+  nat_fib_t *outside_fib;
   snat_interface_t *i;
   u32 fib_index;
   int rv;
@@ -1662,7 +1788,7 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside)
   fib_index =
     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
 
-  update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/);
+  update_per_vrf_sessions_pool (fib_index, 0 /*is_del*/);
 
   if (!is_inside)
     {
@@ -1671,13 +1797,13 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside)
       outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
       if (outside_fib)
        {
-         outside_fib->refcount++;
+         outside_fib->ref_count++;
        }
       else
        {
          vec_add2 (sm->outside_fibs, outside_fib, 1);
          outside_fib->fib_index = fib_index;
-         outside_fib->refcount = 1;
+         outside_fib->ref_count = 1;
        }
 
       nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 1);
@@ -1699,7 +1825,7 @@ nat44_ed_del_interface (u32 sw_if_index, u8 is_inside)
   const char *del_feature_name, *feature_name;
   snat_main_t *sm = &snat_main;
 
-  nat_outside_fib_t *outside_fib;
+  nat_fib_t *outside_fib;
   snat_interface_t *i;
   u32 fib_index;
   int rv;
@@ -1777,15 +1903,15 @@ nat44_ed_del_interface (u32 sw_if_index, u8 is_inside)
   fib_index =
     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
 
-  update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/);
+  update_per_vrf_sessions_pool (fib_index, 1 /*is_del*/);
 
   if (!is_inside)
     {
       outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
       if (outside_fib)
        {
-         outside_fib->refcount--;
-         if (!outside_fib->refcount)
+         outside_fib->ref_count--;
+         if (!outside_fib->ref_count)
            {
              vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
            }
@@ -1803,7 +1929,7 @@ nat44_ed_add_output_interface (u32 sw_if_index)
 {
   snat_main_t *sm = &snat_main;
 
-  nat_outside_fib_t *outside_fib;
+  nat_fib_t *outside_fib;
   snat_interface_t *i;
   u32 fib_index;
   int rv;
@@ -1876,18 +2002,18 @@ nat44_ed_add_output_interface (u32 sw_if_index)
 
   fib_index =
     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
-  update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/);
+  update_per_vrf_sessions_pool (fib_index, 0 /*is_del*/);
 
   outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
   if (outside_fib)
     {
-      outside_fib->refcount++;
+      outside_fib->ref_count++;
     }
   else
     {
       vec_add2 (sm->outside_fibs, outside_fib, 1);
       outside_fib->fib_index = fib_index;
-      outside_fib->refcount = 1;
+      outside_fib->ref_count = 1;
     }
 
   nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 1);
@@ -1903,7 +2029,7 @@ nat44_ed_del_output_interface (u32 sw_if_index)
 {
   snat_main_t *sm = &snat_main;
 
-  nat_outside_fib_t *outside_fib;
+  nat_fib_t *outside_fib;
   snat_interface_t *i;
   u32 fib_index;
   int rv;
@@ -1966,13 +2092,13 @@ nat44_ed_del_output_interface (u32 sw_if_index)
 
   fib_index =
     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
-  update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/);
+  update_per_vrf_sessions_pool (fib_index, 1 /*is_del*/);
 
   outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
   if (outside_fib)
     {
-      outside_fib->refcount--;
-      if (!outside_fib->refcount)
+      outside_fib->ref_count--;
+      if (!outside_fib->ref_count)
        {
          vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
        }
@@ -2005,7 +2131,7 @@ snat_set_workers (uword * bitmap)
       j++;
     }
 
-  sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
+  sm->port_per_thread = (65536 - ED_USER_PORT_OFFSET) / _vec_len (sm->workers);
 
   return 0;
 }
@@ -2036,7 +2162,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index,
                                u32 new_fib_index, u32 old_fib_index)
 {
   snat_main_t *sm = &snat_main;
-  nat_outside_fib_t *outside_fib;
+  nat_fib_t *outside_fib;
   snat_interface_t *i;
   u8 is_add = 1;
   u8 match = 0;
@@ -2074,8 +2200,8 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index,
     {
       if (outside_fib->fib_index == old_fib_index)
        {
-         outside_fib->refcount--;
-         if (!outside_fib->refcount)
+         outside_fib->ref_count--;
+         if (!outside_fib->ref_count)
            vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
          break;
        }
@@ -2085,7 +2211,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index,
     {
       if (outside_fib->fib_index == new_fib_index)
        {
-         outside_fib->refcount++;
+         outside_fib->ref_count++;
          is_add = 0;
          break;
        }
@@ -2094,7 +2220,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index,
   if (is_add)
     {
       vec_add2 (sm->outside_fibs, outside_fib, 1);
-      outside_fib->refcount = 1;
+      outside_fib->ref_count = 1;
       outside_fib->fib_index = new_fib_index;
     }
 }
@@ -2213,8 +2339,6 @@ nat_init (vlib_main_t * vm)
 
   clib_memset (sm, 0, sizeof (*sm));
 
-  // required
-  sm->vnet_main = vnet_get_main ();
   // convenience
   sm->ip4_main = &ip4_main;
 
@@ -2258,7 +2382,7 @@ nat_init (vlib_main_t * vm)
        }
     }
   num_threads = tm->n_vlib_mains - 1;
-  sm->port_per_thread = 0xffff - 1024;
+  sm->port_per_thread = 65536 - ED_USER_PORT_OFFSET;
   vec_validate (sm->per_thread_data, num_threads);
 
   /* Use all available workers by default */
@@ -2330,8 +2454,6 @@ nat44_plugin_enable (nat44_config_t c)
 
   nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets);
 
-  nat44_ed_init_tcp_state_stable (sm);
-
   nat_affinity_enable ();
 
   nat_reset_timeouts (&sm->timeouts);
@@ -2504,19 +2626,21 @@ nat44_plugin_disable ()
 
   rc = nat44_ed_del_static_mappings ();
   if (rc)
-    error = 1;
+    error = VNET_API_ERROR_BUG;
 
   rc = nat44_ed_del_addresses ();
   if (rc)
-    error = 1;
+    error = VNET_API_ERROR_BUG;
 
   rc = nat44_ed_del_interfaces ();
   if (rc)
-    error = 1;
+    error = VNET_API_ERROR_BUG;
 
   rc = nat44_ed_del_output_interfaces ();
   if (rc)
-    error = 1;
+    error = VNET_API_ERROR_BUG;
+
+  nat44_ed_del_vrf_tables ();
 
   vec_free (sm->max_translations_per_fib);
   sm->max_translations_per_fib = 0;
@@ -2587,11 +2711,12 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port,
       if (m)
        return m;
 
-      /* Try address only mapping */
+      // try address only mapping
       m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, match_fib_index, 0);
       if (m)
        return m;
 
+      // default static mapping fib index (based on configuration)
       if (sm->inside_fib_index != match_fib_index)
        {
          m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port,
@@ -2599,12 +2724,13 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port,
          if (m)
            return m;
 
-         /* Try address only mapping */
+         // try address only mapping
          m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->inside_fib_index,
                                      0);
          if (m)
            return m;
        }
+      // TODO: this specific use case may be deprecated (needs testing)
       if (sm->outside_fib_index != match_fib_index)
        {
          m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port,
@@ -2612,7 +2738,7 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port,
          if (m)
            return m;
 
-         /* Try address only mapping */
+         // try address only mapping
          m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->outside_fib_index,
                                      0);
          if (m)
@@ -2626,7 +2752,7 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port,
       if (m)
        return m;
 
-      /* Try address only mapping */
+      // try address only mapping
       m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0);
       if (m)
        return m;
@@ -2635,15 +2761,16 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port,
 }
 
 int
-snat_static_mapping_match (vlib_main_t *vm, snat_main_t *sm,
-                          ip4_address_t match_addr, u16 match_port,
-                          u32 match_fib_index, ip_protocol_t match_protocol,
+snat_static_mapping_match (vlib_main_t *vm, ip4_address_t match_addr,
+                          u16 match_port, u32 match_fib_index,
+                          ip_protocol_t match_protocol,
                           ip4_address_t *mapping_addr, u16 *mapping_port,
                           u32 *mapping_fib_index, int by_external,
                           u8 *is_addr_only, twice_nat_type_t *twice_nat,
                           lb_nat_type_t *lb, ip4_address_t *ext_host_addr,
                           u8 *is_identity_nat, snat_static_mapping_t **out)
 {
+  snat_main_t *sm = &snat_main;
   snat_static_mapping_t *m;
   u32 rand, lo = 0, hi, mid, *tmp = 0, i;
   nat44_lb_addr_port_t *local;
@@ -2787,7 +2914,7 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip,
       if (PREDICT_FALSE (is_output))
        {
          fib_index = sm->outside_fib_index;
-         nat_outside_fib_t *outside_fib;
+         nat_fib_t *outside_fib;
          fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
          fib_prefix_t pfx = {
                  .fp_proto = FIB_PROTOCOL_IP4,
@@ -3037,9 +3164,7 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip,
     }
 
   /* worker by outside port */
-  next_worker_index = sm->first_worker_index;
-  next_worker_index +=
-    sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
+  next_worker_index = get_thread_idx_by_port (clib_net_to_host_u16 (port));
 
 done:
   nat_elog_debug_handoff (sm, "HANDOFF OUT2IN", next_worker_index,
@@ -3162,7 +3287,7 @@ nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm)
 {
   pool_free (tsm->lru_pool);
   pool_free (tsm->sessions);
-  vec_free (tsm->per_vrf_sessions_vec);
+  pool_free (tsm->per_vrf_sessions_pool);
 }
 
 void
@@ -3307,8 +3432,8 @@ nat44_ed_add_del_interface_address_cb (ip4_main_t *im, uword opaque,
                    {
                      ap->addr_len = address_length;
                      ap->sw_if_index = sw_if_index;
-                     ap->net.as_u32 = (ap->addr.as_u32 >> (32 - ap->addr_len))
-                                      << (32 - ap->addr_len);
+                     ap->net.as_u32 =
+                       ap->addr.as_u32 & ip4_main.fib_masks[ap->addr_len];
 
                      nat_log_debug (
                        "pool addr %U binds to -> sw_if_idx: %u net: %U/%u",
@@ -3367,6 +3492,7 @@ nat44_ed_add_interface_address (u32 sw_if_index, u8 twice_nat)
 
   if (!sm->enabled)
     {
+      nat_log_err ("nat44 is disabled");
       return VNET_API_ERROR_UNSUPPORTED;
     }
 
@@ -3404,6 +3530,7 @@ nat44_ed_del_interface_address (u32 sw_if_index, u8 twice_nat)
 
   if (!sm->enabled)
     {
+      nat_log_err ("nat44 is disabled");
       return VNET_API_ERROR_UNSUPPORTED;
     }