NAT44: one-armed NAT and identity mapping (VPP-1212)
[vpp.git] / src / plugins / nat / nat.c
index 51fbb13..ab951cf 100755 (executable)
@@ -365,6 +365,7 @@ nat44_classify_node_fn_inline (vlib_main_t * vm,
   u32 n_left_from, * from, * to_next;
   nat44_classify_next_t next_index;
   snat_main_t *sm = &snat_main;
+  snat_static_mapping_t *m;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -416,7 +417,9 @@ nat44_classify_node_fn_inline (vlib_main_t * vm,
               kv0.key = m_key0.as_u64;
               if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
                 {
-                  next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
+                  m = pool_elt_at_index (sm->static_mappings, value0.value);
+                  if (m->local_addr.as_u32 != m->external_addr.as_u32)
+                    next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
                   goto enqueue0;
                 }
               udp_header_t * udp0 = ip4_next_header (ip0);
@@ -424,7 +427,11 @@ nat44_classify_node_fn_inline (vlib_main_t * vm,
               m_key0.protocol = ip_proto_to_snat_proto (ip0->protocol);
               kv0.key = m_key0.as_u64;
               if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
-                next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
+                {
+                  m = pool_elt_at_index (sm->static_mappings, value0.value);
+                  if (m->local_addr.as_u32 != m->external_addr.as_u32)
+                    next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
+                }
             }
 
         enqueue0:
@@ -669,7 +676,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
  *
@@ -678,7 +689,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;
@@ -1159,7 +1171,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;
@@ -1787,7 +1800,7 @@ fib:
 
   pool_foreach (m, sm->static_mappings,
   ({
-    if (!(m->addr_only))
+    if (!(m->addr_only)  || (m->local_addr.as_u32 == m->external_addr.as_u32))
       continue;
 
     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
@@ -1993,7 +2006,7 @@ 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;
@@ -2741,7 +2754,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))
@@ -2750,7 +2765,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\%",
@@ -2762,7 +2778,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;