NAT44: Fix interface feature removal.
[vpp.git] / src / plugins / nat / nat.c
index 721ad16..bedf4e5 100644 (file)
@@ -643,13 +643,14 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm,
  * @param sw_if_index External port instead of specific IP address.
  * @param is_add If 0 delete static mapping, otherwise add.
  * @param twice_nat If 1 translate external host address and port.
+ * @param out2in_only If 1 rule match only out2in direction
  *
  * @returns
  */
 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                             u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
                             u32 sw_if_index, snat_protocol_t proto, int is_add,
-                            u8 twice_nat)
+                            u8 twice_nat, u8 out2in_only)
 {
   snat_main_t * sm = &snat_main;
   snat_static_mapping_t *m;
@@ -723,7 +724,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
 
       /* Find external address in allocated addresses and reserve port for
          address and port pair mapping when dynamic translations enabled */
-      if (!addr_only && !(sm->static_mapping_only))
+      if (!(addr_only || sm->static_mapping_only || out2in_only))
         {
           for (i = 0; i < vec_len (sm->addresses); i++)
             {
@@ -766,6 +767,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
       m->vrf_id = vrf_id;
       m->fib_index = fib_index;
       m->twice_nat = twice_nat;
+      m->out2in_only = out2in_only;
       if (!addr_only)
         {
           m->local_port = l_port;
@@ -790,8 +792,9 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
       m_key.fib_index = m->fib_index;
       kv.key = m_key.as_u64;
       kv.value = m - sm->static_mappings;
-      clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
-      if (twice_nat)
+      if (!out2in_only)
+        clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
+      if (twice_nat || out2in_only)
         {
           m_key.port = clib_host_to_net_u16 (l_port);
           kv.key = m_key.as_u64;
@@ -806,7 +809,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
       kv.key = m_key.as_u64;
       kv.value = m - sm->static_mappings;
       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
-      if (twice_nat)
+      if (twice_nat || out2in_only)
         {
           m_key.port = clib_host_to_net_u16 (e_port);
           kv.key = m_key.as_u64;
@@ -822,7 +825,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
         return VNET_API_ERROR_NO_SUCH_ENTRY;
 
       /* Free external address port */
-      if (!addr_only && !(sm->static_mapping_only))
+      if (!(addr_only || sm->static_mapping_only || out2in_only))
         {
           for (i = 0; i < vec_len (sm->addresses); i++)
             {
@@ -861,8 +864,9 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
       m_key.protocol = m->proto;
       m_key.fib_index = m->fib_index;
       kv.key = m_key.as_u64;
-      clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
-      if (twice_nat)
+      if (!out2in_only)
+        clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
+      if (twice_nat || out2in_only)
         {
           m_key.port = clib_host_to_net_u16 (m->local_port);
           kv.key = m_key.as_u64;
@@ -876,7 +880,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
       m_key.fib_index = sm->outside_fib_index;
       kv.key = m_key.as_u64;
       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
-      if (twice_nat)
+      if (twice_nat || out2in_only)
         {
           m_key.port = clib_host_to_net_u16 (m->external_port);
           kv.key = m_key.as_u64;
@@ -973,7 +977,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                                      snat_protocol_t proto, u32 vrf_id,
                                      nat44_lb_addr_port_t *locals, u8 is_add,
-                                     u8 twice_nat)
+                                     u8 twice_nat, u8 out2in_only)
 {
   snat_main_t * sm = &snat_main;
   snat_static_mapping_t *m;
@@ -1014,7 +1018,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
 
       /* Find external address in allocated addresses and reserve port for
          address and port pair mapping when dynamic translations enabled */
-      if (!sm->static_mapping_only)
+      if (!(sm->static_mapping_only || out2in_only))
         {
           for (i = 0; i < vec_len (sm->addresses); i++)
             {
@@ -1058,6 +1062,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       m->external_port = e_port;
       m->proto = proto;
       m->twice_nat = twice_nat;
+      m->out2in_only = out2in_only;
 
       m_key.addr = m->external_addr;
       m_key.port = m->external_port;
@@ -1095,10 +1100,13 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       for (i = 0; i < vec_len (locals); i++)
         {
           m_key.addr = locals[i].addr;
-          m_key.port = locals[i].port;
-          kv.key = m_key.as_u64;
-          kv.value = m - sm->static_mappings;
-          clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
+          if (!out2in_only)
+            {
+              m_key.port = locals[i].port;
+              kv.key = m_key.as_u64;
+              kv.value = m - sm->static_mappings;
+              clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
+            }
           locals[i].prefix = (i == 0) ? locals[i].probability :\
             (locals[i - 1].prefix + locals[i].probability);
           vec_add1 (m->locals, locals[i]);
@@ -1121,7 +1129,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
 
       /* Free external address port */
-      if (!sm->static_mapping_only)
+      if (!(sm->static_mapping_only || out2in_only))
         {
           for (i = 0; i < vec_len (sm->addresses); i++)
             {
@@ -1173,13 +1181,16 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       vec_foreach (local, m->locals)
         {
           m_key.addr = local->addr;
-          m_key.port = local->port;
-          m_key.fib_index = m->fib_index;
-          kv.key = m_key.as_u64;
-          if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
+          if (!out2in_only)
             {
-              clib_warning ("static_mapping_by_local key del failed");
-              return VNET_API_ERROR_UNSPECIFIED;
+              m_key.port = local->port;
+              m_key.fib_index = m->fib_index;
+              kv.key = m_key.as_u64;
+              if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
+                {
+                  clib_warning ("static_mapping_by_local key del failed");
+                  return VNET_API_ERROR_UNSPECIFIED;
+                }
             }
 
           m_key.port = clib_host_to_net_u16 (local->port);
@@ -1266,7 +1277,8 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
                                             m->local_port, m->external_port,
                                             m->vrf_id, m->addr_only, ~0,
-                                            m->proto, 0, m->twice_nat);
+                                            m->proto, 0, m->twice_nat,
+                                            m->out2in_only);
       }));
     }
   else
@@ -1387,11 +1399,22 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
 
                 if (sm->num_workers > 1 && !sm->deterministic)
-                  del_feature_name = "nat44-handoff-classify";
+                  {
+                    del_feature_name = "nat44-handoff-classify";
+                    feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
+                                                 "nat44-out2in-worker-handoff";
+                  }
                 else if (sm->deterministic)
-                  del_feature_name = "nat44-det-classify";
+                  {
+                    del_feature_name = "nat44-det-classify";
+                    feature_name = !is_inside ?  "nat44-det-in2out" :
+                                                 "nat44-det-out2in";
+                  }
                 else
-                  del_feature_name = "nat44-classify";
+                  {
+                    del_feature_name = "nat44-classify";
+                    feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
+                  }
 
                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
                                              sw_if_index, 0, 0, 0);
@@ -1586,7 +1609,7 @@ int snat_set_workers (uword * bitmap)
   clib_bitmap_foreach (i, bitmap,
     ({
       vec_add1(sm->workers, i);
-      sm->per_thread_data[i].snat_thread_index = j;
+      sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
       j++;
     }));
 
@@ -2292,6 +2315,7 @@ add_static_mapping_command_fn (vlib_main_t * vm,
   snat_protocol_t proto = ~0;
   u8 proto_set = 0;
   u8 twice_nat = 0;
+  u8 out2in_only = 0;
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -2324,6 +2348,8 @@ add_static_mapping_command_fn (vlib_main_t * vm,
         proto_set = 1;
       else if (unformat (line_input, "twice-nat"))
         twice_nat = 1;
+      else if (unformat (line_input, "out2in-only"))
+        out2in_only = 1;
       else if (unformat (line_input, "del"))
         is_add = 0;
       else
@@ -2348,7 +2374,7 @@ add_static_mapping_command_fn (vlib_main_t * vm,
 
   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
                                vrf_id, addr_only, sw_if_index, proto, is_add,
-                               twice_nat);
+                               twice_nat, out2in_only);
 
   switch (rv)
     {
@@ -2396,7 +2422,7 @@ VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
   .function = add_static_mapping_command_fn,
   .short_help =
     "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
-    "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
+    "external <addr> [<port>] [vrf <table-id>] [twice-nat] [out2in-only] [del]",
 };
 
 static clib_error_t *
@@ -2445,7 +2471,7 @@ add_identity_mapping_command_fn (vlib_main_t * vm,
 
   rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
                                vrf_id, addr_only, sw_if_index, proto, is_add,
-                               0);
+                               0, 0);
 
   switch (rv)
     {
@@ -2509,6 +2535,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
   u8 proto_set = 0;
   nat44_lb_addr_port_t *locals = 0, local;
   u8 twice_nat = 0;
+  u8 out2in_only = 0;
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -2535,6 +2562,8 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
         proto_set = 1;
       else if (unformat (line_input, "twice-nat"))
         twice_nat = 1;
+      else if (unformat (line_input, "out2in-only"))
+        out2in_only = 1;
       else if (unformat (line_input, "del"))
         is_add = 0;
       else
@@ -2558,7 +2587,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
     }
 
   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
-                                        locals, is_add, twice_nat);
+                                        locals, is_add, twice_nat, out2in_only);
 
   switch (rv)
     {
@@ -2591,7 +2620,7 @@ VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
   .short_help =
     "nat44 add load-balancing static mapping protocol tcp|udp "
     "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
-    "[vrf <table-id>] [del]",
+    "[vrf <table-id>] [out2in-only] [del]",
 };
 
 static clib_error_t *
@@ -2758,6 +2787,7 @@ snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
   snat_session_t *s;
   int i;
   u32 proto;
+  u32 next_worker_index = 0;
 
   /* first try static mappings without port */
   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
@@ -2873,7 +2903,10 @@ snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
     }
 
   /* worker by outside port */
-  return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
+  next_worker_index = sm->first_worker_index;
+  next_worker_index +=
+    sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
+  return next_worker_index;
 }
 
 static clib_error_t *
@@ -2896,6 +2929,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
   u8 static_mapping_only = 0;
   u8 static_mapping_connection_tracking = 0;
   snat_main_per_thread_data_t *tsm;
+  dslite_main_t * dm = &dslite_main;
 
   sm->deterministic = 0;
   sm->out2in_dpo = 0;
@@ -2941,6 +2975,8 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
         ;
       else if (unformat (input, "out2in dpo"))
         sm->out2in_dpo = 1;
+      else if (unformat (input, "dslite ce"))
+        dslite_set_ce(dm, 1);
       else
        return clib_error_return (0, "unknown input '%U'",
                                  format_unformat_error, input);
@@ -3158,22 +3194,24 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args)
    {
       if (vec_len (m->locals))
         {
-          s = format (s, "%U vrf %d external %U:%d %s",
+          s = format (s, "%U vrf %d external %U:%d %s %s",
                       format_snat_protocol, m->proto,
                       m->vrf_id,
                       format_ip4_address, &m->external_addr, m->external_port,
-                      m->twice_nat ? "twice-nat" : "");
+                      m->twice_nat ? "twice-nat" : "",
+                      m->out2in_only ? "out2in-only" : "");
           vec_foreach (local, m->locals)
             s = format (s, "\n  local %U:%d probability %d\%",
                         format_ip4_address, &local->addr, local->port,
                         local->probability);
         }
       else
-        s = format (s, "%U local %U:%d external %U:%d vrf %d %s",
+        s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
                     format_snat_protocol, m->proto,
                     format_ip4_address, &m->local_addr, m->local_port,
                     format_ip4_address, &m->external_addr, m->external_port,
-                    m->vrf_id, m->twice_nat ? "twice-nat" : "");
+                    m->vrf_id, m->twice_nat ? "twice-nat" : "",
+                    m->out2in_only ? "out2in-only" : "");
    }
   return s;
 }
@@ -3545,7 +3583,7 @@ match:
                                             ~0 /* sw_if_index */,
                                             rp->proto,
                                             rp->is_add,
-                                            0);
+                                            0, 0);
               if (rv)
                 clib_warning ("snat_add_static_mapping returned %d",
                               rv);