NAT66: Do not translate if packet not aimed at outside interface
[vpp.git] / src / plugins / nat / nat.c
old mode 100644 (file)
new mode 100755 (executable)
index 9a62047..764bc1d
@@ -522,7 +522,7 @@ snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
   if (is_add)
     fib_table_entry_update_one_path(fib_index,
                                     &prefix,
-                                    FIB_SOURCE_PLUGIN_HI,
+                                    FIB_SOURCE_PLUGIN_LOW,
                                     (FIB_ENTRY_FLAG_CONNECTED |
                                      FIB_ENTRY_FLAG_LOCAL |
                                      FIB_ENTRY_FLAG_EXCLUSIVE),
@@ -536,7 +536,7 @@ snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
   else
     fib_table_entry_delete(fib_index,
                            &prefix,
-                           FIB_SOURCE_PLUGIN_HI);
+                           FIB_SOURCE_PLUGIN_LOW);
 }
 
 void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id,
@@ -562,7 +562,7 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id,
   if (vrf_id != ~0)
     ap->fib_index =
       fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
-                                         FIB_SOURCE_PLUGIN_HI);
+                                         FIB_SOURCE_PLUGIN_LOW);
   else
     ap->fib_index = ~0;
 #define _(N, i, n, s) \
@@ -682,12 +682,12 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
   u32 ses_index;
   u64 user_index;
   snat_session_t * s;
+  snat_static_map_resolve_t *rp, *rp_match = 0;
 
   /* If the external address is a specific interface address */
   if (sw_if_index != ~0)
     {
       ip4_address_t * first_int_addr;
-      snat_static_map_resolve_t *rp, *rp_match = 0;
 
       for (i = 0; i < vec_len (sm->to_resolve); i++)
         {
@@ -830,7 +830,26 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
             }
           /* External address must be allocated */
           if (!a && (l_addr.as_u32 != e_addr.as_u32))
-            return VNET_API_ERROR_NO_SUCH_ENTRY;
+            {
+              if (sw_if_index != ~0)
+                {
+                  for (i = 0; i < vec_len (sm->to_resolve); i++)
+                    {
+                      rp = sm->to_resolve + i;
+                      if (rp->addr_only)
+                         continue;
+                      if (rp->sw_if_index != sw_if_index &&
+                          rp->l_addr.as_u32 != l_addr.as_u32 &&
+                          rp->vrf_id != vrf_id && rp->l_port != l_port &&
+                          rp->e_port != e_port && rp->proto != proto)
+                        continue;
+
+                      vec_del1 (sm->to_resolve, i);
+                      break;
+                    }
+                }
+              return VNET_API_ERROR_NO_SUCH_ENTRY;
+            }
         }
 
       pool_get (sm->static_mappings, m);
@@ -942,7 +961,12 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
   else
     {
       if (!m)
-        return VNET_API_ERROR_NO_SUCH_ENTRY;
+        {
+          if (sw_if_index != ~0)
+            return 0;
+          else
+            return VNET_API_ERROR_NO_SUCH_ENTRY;
+        }
 
       /* Free external address port */
       if (!(addr_only || sm->static_mapping_only || out2in_only))
@@ -1040,6 +1064,9 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                             continue;
                         }
 
+                      if (is_lb_session (s))
+                        continue;
+
                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
                       pool_put_index (tsm->list_pool, s->per_user_index);
@@ -1049,7 +1076,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       if (!addr_only)
                         break;
                     }
-                  if (addr_only)
+                  if (addr_only && (u->nstaticsessions == 0))
                     {
                       pool_put (tsm->users, u);
                       clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
@@ -1154,7 +1181,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
 
       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
                                                      vrf_id,
-                                                     FIB_SOURCE_PLUGIN_HI);
+                                                     FIB_SOURCE_PLUGIN_LOW);
 
       /* Find external address in allocated addresses and reserve port for
          address and port pair mapping when dynamic translations enabled */
@@ -1267,7 +1294,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       if (!m)
         return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-      fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
+      fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
 
       /* Free external address port */
       if (!(sm->static_mapping_only || out2in_only))
@@ -1364,6 +1391,9 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
                       ses_index = elt->value;
 
+                      if (!(is_lb_session (s)))
+                        continue;
+
                       if ((s->in2out.addr.as_u32 != local->addr.as_u32) &&
                           (clib_net_to_host_u16 (s->in2out.port) != local->port))
                         continue;
@@ -1438,7 +1468,7 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
 
   if (a->fib_index != ~0)
     fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
-                     FIB_SOURCE_PLUGIN_HI);
+                     FIB_SOURCE_PLUGIN_LOW);
 
   /* Delete sessions using address */
   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
@@ -1939,6 +1969,7 @@ void snat_free_outside_address_and_port (snat_address_t * addresses,
  *                    address.
  * @param is_addr_only If matched mapping is address only
  * @param twice_nat If matched mapping is twice NAT.
+ * @param lb If matched mapping is load-balanced.
  *
  * @returns 0 if match found otherwise 1.
  */
@@ -1947,7 +1978,8 @@ int snat_static_mapping_match (snat_main_t * sm,
                                snat_session_key_t * mapping,
                                u8 by_external,
                                u8 *is_addr_only,
-                               u8 *twice_nat)
+                               u8 *twice_nat,
+                               u8 *lb)
 {
   clib_bihash_kv_8_8_t kv, value;
   snat_static_mapping_t *m;
@@ -2018,6 +2050,9 @@ int snat_static_mapping_match (snat_main_t * sm,
   if (PREDICT_FALSE(twice_nat != 0))
     *twice_nat = m->twice_nat;
 
+  if (PREDICT_FALSE(lb != 0))
+    *lb = vec_len (m->locals) > 0;
+
   return 0;
 }
 
@@ -2406,12 +2441,14 @@ static clib_error_t *
 snat_config (vlib_main_t * vm, unformat_input_t * input)
 {
   snat_main_t * sm = &snat_main;
+  nat66_main_t * nm = &nat66_main;
   u32 translation_buckets = 1024;
   u32 translation_memory_size = 128<<20;
   u32 user_buckets = 128;
   u32 user_memory_size = 64<<20;
   u32 max_translations_per_user = 100;
   u32 outside_vrf_id = 0;
+  u32 outside_ip6_vrf_id = 0;
   u32 inside_vrf_id = 0;
   u32 static_mapping_buckets = 1024;
   u32 static_mapping_memory_size = 64<<20;
@@ -2444,6 +2481,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
       else if (unformat (input, "outside VRF id %d",
                          &outside_vrf_id))
         ;
+      else if (unformat (input, "outside ip6 VRF id %d",
+                         &outside_ip6_vrf_id))
+        ;
       else if (unformat (input, "inside VRF id %d",
                          &inside_vrf_id))
         ;
@@ -2487,6 +2527,10 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
                                                              outside_vrf_id,
                                                              FIB_SOURCE_PLUGIN_HI);
+  nm->outside_vrf_id = outside_ip6_vrf_id;
+  nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
+                                                             outside_ip6_vrf_id,
+                                                             FIB_SOURCE_PLUGIN_HI);
   sm->inside_vrf_id = inside_vrf_id;
   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
                                                             inside_vrf_id,