Add special Twice-NAT feature (VPP-1221)
[vpp.git] / src / plugins / nat / nat.c
index 48535d9..499f3a2 100755 (executable)
@@ -152,6 +152,21 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
   snat_main_per_thread_data_t *tsm =
     vec_elt_at_index (sm->per_thread_data, thread_index);
 
+  if (is_fwd_bypass_session (s))
+    {
+      ed_key.l_addr = s->in2out.addr;
+      ed_key.r_addr = s->ext_host_addr;
+      ed_key.l_port = s->in2out.port;
+      ed_key.r_port = s->ext_host_port;
+      ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
+      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 (&sm->in2out_ed, &ed_kv, 0))
+        clib_warning ("in2out_ed key del failed");
+      return;
+    }
+
   /* Endpoint dependent session lookup tables */
   if (is_ed_session (s))
     {
@@ -654,7 +669,11 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm,
  * @param addr_only If 0 address port and pair mapping, otherwise address only.
  * @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 twice_nat If value is TWICE_NAT then translate external host address
+ *                  and port.
+ *                  If value is TWICE_NAT_SELF then translate external host
+ *                  address and port whenever external host address equals
+ *                  local address of internal host.
  * @param out2in_only If 1 rule match only out2in direction
  * @param tag - opaque string tag
  *
@@ -663,7 +682,8 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm,
 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 out2in_only, u8 * tag)
+                            twice_nat_type_t twice_nat, u8 out2in_only,
+                            u8 * tag)
 {
   snat_main_t * sm = &snat_main;
   snat_static_mapping_t *m;
@@ -1063,9 +1083,9 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
                             continue;
                         }
-                      
-                      if (s->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
-                          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);
@@ -1144,7 +1164,8 @@ static int lb_local_exists (nat44_lb_addr_port_t * local,
 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 out2in_only, u8 *tag)
+                                     twice_nat_type_t twice_nat, u8 out2in_only,
+                                     u8 *tag)
 {
   snat_main_t * sm = &snat_main;
   snat_static_mapping_t *m;
@@ -1391,6 +1412,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;
@@ -1966,6 +1990,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.
  */
@@ -1974,7 +1999,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)
+                               twice_nat_type_t *twice_nat,
+                               u8 *lb)
 {
   clib_bihash_kv_8_8_t kv, value;
   snat_static_mapping_t *m;
@@ -2045,6 +2071,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;
 }
 
@@ -2433,12 +2462,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;
@@ -2471,6 +2502,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))
         ;
@@ -2514,6 +2548,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,
@@ -2709,7 +2747,9 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args)
       s = format (s, "local %U external %U vrf %d %s",
                   format_ip4_address, &m->local_addr,
                   format_ip4_address, &m->external_addr,
-                  m->vrf_id, m->twice_nat ? "twice-nat" : "");
+                  m->vrf_id,
+                  m->twice_nat == TWICE_NAT ? "twice-nat" :
+                  m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "");
   else
    {
       if (vec_len (m->locals))
@@ -2718,7 +2758,8 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args)
                       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 ? "twice-nat" :
+                      m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
                       m->out2in_only ? "out2in-only" : "");
           vec_foreach (local, m->locals)
             s = format (s, "\n  local %U:%d probability %d\%",
@@ -2730,7 +2771,9 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args)
                     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 ? "twice-nat" :
+                    m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
                     m->out2in_only ? "out2in-only" : "");
    }
   return s;