aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuraj Sloboda <jsloboda@cisco.com>2018-04-10 13:51:54 +0200
committerDamjan Marion <dmarion.lists@gmail.com>2018-04-19 10:35:13 +0000
commit1e5c07d379a092f4829e7081aa962d013b31fdfc (patch)
tree1b1a3c386663b3356773cf374b55a64f14d43709
parentb14826e459302556febb391456ea90644278645a (diff)
Add special Twice-NAT feature (VPP-1221)
When enabled then Twice-NAT is applied only when source IP equals destination IP after DNAT Change-Id: I58a9d1d222b2a10c83eafffb2107f32c1b4aa3a8 Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
-rwxr-xr-xsrc/plugins/nat/in2out.c2
-rw-r--r--src/plugins/nat/nat.api16
-rwxr-xr-xsrc/plugins/nat/nat.c25
-rw-r--r--src/plugins/nat/nat.h29
-rw-r--r--src/plugins/nat/nat44_cli.c19
-rw-r--r--src/plugins/nat/nat_api.c24
-rwxr-xr-xsrc/plugins/nat/out2in.c9
-rw-r--r--test/test_nat.py221
-rw-r--r--test/vpp_papi_provider.py7
9 files changed, 226 insertions, 126 deletions
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index 7d9d6c3e6c1..786b6c6887b 100755
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -1273,6 +1273,7 @@ create_ses:
s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
+ s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
s->outside_address_index = address_index;
s->out2in.addr.as_u32 = new_addr;
s->out2in.fib_index = sm->outside_fib_index;
@@ -1402,6 +1403,7 @@ snat_in2out_lb (snat_main_t *sm,
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
if (lb)
s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
+ s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
s->outside_address_index = ~0;
s->in2out = l_key;
s->out2in = e_key;
diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api
index 69b6045c4cb..23c89adef7a 100644
--- a/src/plugins/nat/nat.api
+++ b/src/plugins/nat/nat.api
@@ -352,6 +352,9 @@ define nat44_interface_output_feature_details {
@param vfr_id - VRF ID
@param twice_nat - if 1 translate external host address and port, only for
1:1 NAPT (addr_only must be 0)
+ @param self_twice_nat - if 1 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
*/
@@ -368,6 +371,7 @@ autoreply define nat44_add_del_static_mapping {
u32 external_sw_if_index;
u32 vrf_id;
u8 twice_nat;
+ u8 self_twice_nat;
u8 out2in_only;
u8 tag[64];
};
@@ -392,6 +396,9 @@ define nat44_static_mapping_dump {
@param external_sw_if_index - external interface
@param vfr_id - VRF ID
@param twice_nat - if 1 translate external host address and port
+ @param self_twice_nat - if 1 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
*/
@@ -406,6 +413,7 @@ define nat44_static_mapping_details {
u32 external_sw_if_index;
u32 vrf_id;
u8 twice_nat;
+ u8 self_twice_nat;
u8 out2in_only;
u8 tag[64];
};
@@ -584,6 +592,9 @@ typeonly manual_endian define nat44_lb_addr_port {
@param protocol - IP protocol number of the service
@param vrf_id - internal network VRF ID
@param twice_nat - if 1 translate external host address and port
+ @param self_twice_nat - if 1 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
@param local_num - number of local network nodes
@@ -598,6 +609,7 @@ autoreply manual_endian define nat44_add_del_lb_static_mapping {
u8 protocol;
u32 vrf_id;
u8 twice_nat;
+ u8 self_twice_nat;
u8 out2in_only;
u8 tag[64];
u8 local_num;
@@ -621,6 +633,9 @@ define nat44_lb_static_mapping_dump {
@param protocol - IP protocol number of the service
@param vrf_id - internal network VRF ID
@param twice_nat - if 1 translate external host address and port
+ @param self_twice_nat - if 1 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
@param local_num - number of local network nodes
@@ -633,6 +648,7 @@ manual_endian define nat44_lb_static_mapping_details {
u8 protocol;
u32 vrf_id;
u8 twice_nat;
+ u8 self_twice_nat;
u8 out2in_only;
u8 tag[64];
u8 local_num;
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 51fbb1336e1..499f3a242cb 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -669,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
*
@@ -678,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;
@@ -1159,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;
@@ -1993,7 +1999,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 +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))
@@ -2750,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\%",
@@ -2762,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;
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index 8d7d1738fb3..775376fcbab 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -125,11 +125,12 @@ typedef enum {
} snat_session_state_t;
-#define SNAT_SESSION_FLAG_STATIC_MAPPING 1
-#define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2
-#define SNAT_SESSION_FLAG_LOAD_BALANCING 4
-#define SNAT_SESSION_FLAG_TWICE_NAT 8
-#define SNAT_SESSION_FLAG_FWD_BYPASS 16
+#define SNAT_SESSION_FLAG_STATIC_MAPPING 1
+#define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2
+#define SNAT_SESSION_FLAG_LOAD_BALANCING 4
+#define SNAT_SESSION_FLAG_TWICE_NAT 8
+#define SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT 16
+#define SNAT_SESSION_FLAG_FWD_BYPASS 32
#define NAT_INTERFACE_FLAG_IS_INSIDE 1
#define NAT_INTERFACE_FLAG_IS_OUTSIDE 2
@@ -211,13 +212,19 @@ typedef struct {
u8 prefix;
} nat44_lb_addr_port_t;
+typedef enum {
+ TWICE_NAT_DISABLED,
+ TWICE_NAT,
+ TWICE_NAT_SELF,
+} twice_nat_type_t;
+
typedef struct {
ip4_address_t local_addr;
ip4_address_t external_addr;
u16 local_port;
u16 external_port;
u8 addr_only;
- u8 twice_nat;
+ twice_nat_type_t twice_nat;
u8 out2in_only;
u32 vrf_id;
u32 fib_index;
@@ -422,7 +429,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);
void snat_add_del_addr_to_fib (ip4_address_t * addr,
@@ -474,7 +481,7 @@ typedef struct {
@param s NAT session
@return 1 if NAT session is endpoint dependent
*/
-#define is_ed_session(s) (snat_is_unk_proto_session (s) || is_twice_nat_session (s) || is_lb_session (s))
+#define is_ed_session(s) (s->flags & SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT)
#define nat_interface_is_inside(i) i->flags & NAT_INTERFACE_FLAG_IS_INSIDE
#define nat_interface_is_outside(i) i->flags & NAT_INTERFACE_FLAG_IS_OUTSIDE
@@ -558,7 +565,8 @@ void nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add);
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);
clib_error_t * snat_api_init(vlib_main_t * vm, snat_main_t * sm);
int snat_set_workers (uword * bitmap);
int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del);
@@ -571,7 +579,8 @@ u8 * format_snat_protocol(u8 * s, va_list * args);
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);
int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
snat_protocol_t proto, u32 vrf_id, int is_in);
void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index da97a801b7f..2f1e9a019ac 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -501,7 +501,7 @@ add_static_mapping_command_fn (vlib_main_t * vm,
int rv;
snat_protocol_t proto = ~0;
u8 proto_set = 0;
- u8 twice_nat = 0;
+ twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
u8 out2in_only = 0;
if (sm->deterministic)
@@ -538,7 +538,9 @@ add_static_mapping_command_fn (vlib_main_t * vm,
else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
proto_set = 1;
else if (unformat (line_input, "twice-nat"))
- twice_nat = 1;
+ twice_nat = TWICE_NAT;
+ else if (unformat (line_input, "self-twice-nat"))
+ twice_nat = TWICE_NAT_SELF;
else if (unformat (line_input, "out2in-only"))
out2in_only = 1;
else if (unformat (line_input, "del"))
@@ -688,7 +690,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
snat_protocol_t proto;
u8 proto_set = 0;
nat44_lb_addr_port_t *locals = 0, local;
- u8 twice_nat = 0;
+ twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
u8 out2in_only = 0;
if (sm->deterministic)
@@ -718,7 +720,9 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
&proto))
proto_set = 1;
else if (unformat (line_input, "twice-nat"))
- twice_nat = 1;
+ twice_nat = TWICE_NAT;
+ else if (unformat (line_input, "self-twice-nat"))
+ twice_nat = TWICE_NAT_SELF;
else if (unformat (line_input, "out2in-only"))
out2in_only = 1;
else if (unformat (line_input, "del"))
@@ -1584,7 +1588,8 @@ 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] [out2in-only] [del]",
+ "external <addr> [<port>] [vrf <table-id>] [twice-nat|self-twice-nat] "
+ "[out2in-only] [del]",
};
/*?
@@ -1622,8 +1627,8 @@ VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
.function = add_lb_static_mapping_command_fn,
.short_help =
"nat44 add load-balancing static mapping protocol tcp|udp "
- "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
- "[vrf <table-id>] [out2in-only] [del]",
+ "external <addr>:<port> local <addr>:<port> probability <n> "
+ "[twice-nat|self-twice-nat] [vrf <table-id>] [out2in-only] [del]",
};
/*?
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index 56b261d1bb9..417d2984011 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -724,6 +724,7 @@ static void
ip4_address_t local_addr, external_addr;
u16 local_port = 0, external_port = 0;
u32 vrf_id, external_sw_if_index;
+ twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
int rv = 0;
snat_protocol_t proto;
u8 *tag = 0;
@@ -744,6 +745,10 @@ static void
vrf_id = clib_net_to_host_u32 (mp->vrf_id);
external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
proto = ip_proto_to_snat_proto (mp->protocol);
+ if (mp->twice_nat)
+ twice_nat = TWICE_NAT;
+ else if (mp->self_twice_nat)
+ twice_nat = TWICE_NAT_SELF;
mp->tag[sizeof (mp->tag) - 1] = 0;
tag = format (0, "%s", mp->tag);
vec_terminate_c_string (tag);
@@ -751,7 +756,7 @@ static void
rv = snat_add_static_mapping (local_addr, external_addr, local_port,
external_port, vrf_id, mp->addr_only,
external_sw_if_index, proto, mp->is_add,
- mp->twice_nat, mp->out2in_only, tag);
+ twice_nat, mp->out2in_only, tag);
vec_free (tag);
@@ -804,7 +809,10 @@ send_nat44_static_mapping_details (snat_static_mapping_t * m,
rmp->external_sw_if_index = ~0;
rmp->vrf_id = htonl (m->vrf_id);
rmp->context = context;
- rmp->twice_nat = m->twice_nat;
+ if (m->twice_nat == TWICE_NAT)
+ rmp->twice_nat = 1;
+ else if (m->twice_nat == TWICE_NAT_SELF)
+ rmp->self_twice_nat = 1;
rmp->out2in_only = m->out2in_only;
if (m->addr_only == 0)
{
@@ -1324,6 +1332,7 @@ static void
{
snat_main_t *sm = &snat_main;
vl_api_nat44_add_del_lb_static_mapping_reply_t *rmp;
+ twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
int rv = 0;
nat44_lb_addr_port_t *locals = 0;
ip4_address_t e_addr;
@@ -1339,6 +1348,10 @@ static void
locals = unformat_nat44_lb_addr_port (mp->locals, mp->local_num);
clib_memcpy (&e_addr, mp->external_addr, 4);
proto = ip_proto_to_snat_proto (mp->protocol);
+ if (mp->twice_nat)
+ twice_nat = TWICE_NAT;
+ else if (mp->self_twice_nat)
+ twice_nat = TWICE_NAT_SELF;
mp->tag[sizeof (mp->tag) - 1] = 0;
tag = format (0, "%s", mp->tag);
vec_terminate_c_string (tag);
@@ -1347,7 +1360,7 @@ static void
nat44_add_del_lb_static_mapping (e_addr,
clib_net_to_host_u16 (mp->external_port),
proto, clib_net_to_host_u32 (mp->vrf_id),
- locals, mp->is_add, mp->twice_nat,
+ locals, mp->is_add, twice_nat,
mp->out2in_only, tag);
vec_free (locals);
@@ -1391,7 +1404,10 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t * m,
rmp->protocol = snat_proto_to_ip_proto (m->proto);
rmp->vrf_id = ntohl (m->vrf_id);
rmp->context = context;
- rmp->twice_nat = m->twice_nat;
+ if (m->twice_nat == TWICE_NAT)
+ rmp->twice_nat = 1;
+ else if (m->twice_nat == TWICE_NAT_SELF)
+ rmp->self_twice_nat = 1;
rmp->out2in_only = m->out2in_only;
if (m->tag)
strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c
index 637a07341e0..a0128b8d61d 100755
--- a/src/plugins/nat/out2in.c
+++ b/src/plugins/nat/out2in.c
@@ -871,6 +871,7 @@ snat_out2in_unknown_proto (snat_main_t *sm,
s->ext_host_addr.as_u32 = ip->src_address.as_u32;
s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
+ s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
s->outside_address_index = ~0;
s->out2in.addr.as_u32 = old_addr;
s->out2in.fib_index = rx_fib_index;
@@ -935,7 +936,8 @@ snat_out2in_lb (snat_main_t *sm,
snat_user_t *u;
u32 address_index;
snat_session_key_t eh_key;
- u8 twice_nat, lb;
+ twice_nat_type_t twice_nat;
+ u8 lb;
old_addr = ip->dst_address.as_u32;
@@ -987,6 +989,7 @@ snat_out2in_lb (snat_main_t *sm,
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
if (lb)
s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
+ s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
s->outside_address_index = ~0;
s->out2in = e_key;
s->in2out = l_key;
@@ -997,7 +1000,9 @@ snat_out2in_lb (snat_main_t *sm,
if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
clib_warning ("out2in-ed key add failed");
- if (twice_nat)
+ if (twice_nat == TWICE_NAT ||
+ (twice_nat == TWICE_NAT_SELF &&
+ ip->src_address.as_u32 == l_key.addr.as_u32))
{
eh_key.protocol = proto;
if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0,
diff --git a/test/test_nat.py b/test/test_nat.py
index 7c126199072..47f3b8c7299 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -922,6 +922,9 @@ class TestNAT44(MethodHolder):
cls.pg0.generate_remote_hosts(3)
cls.pg0.configure_ipv4_neighbors()
+ cls.pg1.generate_remote_hosts(1)
+ cls.pg1.configure_ipv4_neighbors()
+
cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
cls.vapi.ip_table_add_del(10, is_add=1)
cls.vapi.ip_table_add_del(20, is_add=1)
@@ -1029,6 +1032,7 @@ class TestNAT44(MethodHolder):
vrf_id=sm.vrf_id,
protocol=sm.protocol,
twice_nat=sm.twice_nat,
+ self_twice_nat=sm.self_twice_nat,
out2in_only=sm.out2in_only,
tag=sm.tag,
external_sw_if_index=sm.external_sw_if_index,
@@ -1042,6 +1046,7 @@ class TestNAT44(MethodHolder):
lb_sm.protocol,
vrf_id=lb_sm.vrf_id,
twice_nat=lb_sm.twice_nat,
+ self_twice_nat=lb_sm.self_twice_nat,
out2in_only=lb_sm.out2in_only,
tag=lb_sm.tag,
is_add=0,
@@ -1072,7 +1077,8 @@ class TestNAT44(MethodHolder):
def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
local_port=0, external_port=0, vrf_id=0,
is_add=1, external_sw_if_index=0xFFFFFFFF,
- proto=0, twice_nat=0, out2in_only=0, tag=""):
+ proto=0, twice_nat=0, self_twice_nat=0,
+ out2in_only=0, tag=""):
"""
Add/delete NAT44 static mapping
@@ -1085,6 +1091,9 @@ class TestNAT44(MethodHolder):
:param external_sw_if_index: External interface instead of IP address
:param proto: IP protocol (Mandatory if port specified)
:param twice_nat: 1 if translate external host address and port
+ :param self_twice_nat: 1 if translate external host address and port
+ whenever external host address equals
+ local address of internal host
:param out2in_only: if 1 rule is matching only out2in direction
:param tag: Opaque string tag
"""
@@ -1103,6 +1112,7 @@ class TestNAT44(MethodHolder):
vrf_id,
proto,
twice_nat,
+ self_twice_nat,
out2in_only,
tag,
is_add)
@@ -3844,56 +3854,128 @@ class TestNAT44(MethodHolder):
self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
- def test_twice_nat(self):
- """ Twice NAT44 """
+ def twice_nat_common(self, self_twice_nat=False, same_pg=False, lb=False,
+ client_id=None):
twice_nat_addr = '10.0.1.3'
+
port_in = 8080
+ if lb:
+ if not same_pg:
+ port_in1 = port_in
+ port_in2 = port_in
+ else:
+ port_in1 = port_in+1
+ port_in2 = port_in+2
+
port_out = 80
eh_port_out = 4567
- eh_port_in = 0
+
+ server1 = self.pg0.remote_hosts[0]
+ server2 = self.pg0.remote_hosts[1]
+ if lb and same_pg:
+ server2 = server1
+ if not lb:
+ server = server1
+
+ pg0 = self.pg0
+ if same_pg:
+ pg1 = self.pg0
+ else:
+ pg1 = self.pg1
+
+ eh_translate = ((not self_twice_nat) or (not lb and same_pg) or
+ client_id == 1)
+
self.nat44_add_address(self.nat_addr)
self.nat44_add_address(twice_nat_addr, twice_nat=1)
- self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
- port_in, port_out, proto=IP_PROTOS.tcp,
- twice_nat=1)
- self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
- self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
+ if not lb:
+ self.nat44_add_static_mapping(pg0.remote_ip4, self.nat_addr,
+ port_in, port_out,
+ proto=IP_PROTOS.tcp,
+ twice_nat=int(not self_twice_nat),
+ self_twice_nat=int(self_twice_nat))
+ else:
+ locals = [{'addr': server1.ip4n,
+ 'port': port_in1,
+ 'probability': 50},
+ {'addr': server2.ip4n,
+ 'port': port_in2,
+ 'probability': 50}]
+ out_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
+ self.vapi.nat44_add_del_lb_static_mapping(out_addr_n,
+ port_out,
+ IP_PROTOS.tcp,
+ twice_nat=int(
+ not self_twice_nat),
+ self_twice_nat=int(
+ self_twice_nat),
+ local_num=len(locals),
+ locals=locals)
+ self.vapi.nat44_interface_add_del_feature(pg0.sw_if_index)
+ self.vapi.nat44_interface_add_del_feature(pg1.sw_if_index,
is_inside=0)
- p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
- IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
+ if same_pg:
+ if not lb:
+ client = server
+ else:
+ assert client_id is not None
+ if client_id == 1:
+ client = self.pg0.remote_hosts[0]
+ elif client_id == 2:
+ client = self.pg0.remote_hosts[1]
+ else:
+ client = pg1.remote_hosts[0]
+ p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) /
+ IP(src=client.ip4, dst=self.nat_addr) /
TCP(sport=eh_port_out, dport=port_out))
- self.pg1.add_stream(p)
+ pg1.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
- capture = self.pg0.get_capture(1)
+ capture = pg0.get_capture(1)
p = capture[0]
try:
ip = p[IP]
tcp = p[TCP]
- self.assertEqual(ip.dst, self.pg0.remote_ip4)
- self.assertEqual(ip.src, twice_nat_addr)
- self.assertEqual(tcp.dport, port_in)
- self.assertNotEqual(tcp.sport, eh_port_out)
+ if lb:
+ if ip.dst == server1.ip4:
+ server = server1
+ port_in = port_in1
+ else:
+ server = server2
+ port_in = port_in2
+ self.assertEqual(ip.dst, server.ip4)
+ if lb and same_pg:
+ self.assertIn(tcp.dport, [port_in1, port_in2])
+ else:
+ self.assertEqual(tcp.dport, port_in)
+ if eh_translate:
+ self.assertEqual(ip.src, twice_nat_addr)
+ self.assertNotEqual(tcp.sport, eh_port_out)
+ else:
+ self.assertEqual(ip.src, client.ip4)
+ self.assertEqual(tcp.sport, eh_port_out)
+ eh_addr_in = ip.src
eh_port_in = tcp.sport
+ saved_port_in = tcp.dport
self.check_tcp_checksum(p)
self.check_ip_checksum(p)
except:
self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
- p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
- IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) /
- TCP(sport=port_in, dport=eh_port_in))
- self.pg0.add_stream(p)
+ p = (Ether(src=server.mac, dst=pg0.local_mac) /
+ IP(src=server.ip4, dst=eh_addr_in) /
+ TCP(sport=saved_port_in, dport=eh_port_in))
+ pg0.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
- capture = self.pg1.get_capture(1)
+ capture = pg1.get_capture(1)
p = capture[0]
try:
ip = p[IP]
tcp = p[TCP]
- self.assertEqual(ip.dst, self.pg1.remote_ip4)
+ self.assertEqual(ip.dst, client.ip4)
self.assertEqual(ip.src, self.nat_addr)
self.assertEqual(tcp.dport, eh_port_out)
self.assertEqual(tcp.sport, port_out)
@@ -3903,84 +3985,31 @@ class TestNAT44(MethodHolder):
self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
- def test_twice_nat_lb(self):
- """ Twice NAT44 local service load balancing """
- external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
- twice_nat_addr = '10.0.1.3'
- local_port = 8080
- external_port = 80
- eh_port_out = 4567
- eh_port_in = 0
- server1 = self.pg0.remote_hosts[0]
- server2 = self.pg0.remote_hosts[1]
+ def test_twice_nat(self):
+ """ Twice NAT44 """
+ self.twice_nat_common()
- locals = [{'addr': server1.ip4n,
- 'port': local_port,
- 'probability': 50},
- {'addr': server2.ip4n,
- 'port': local_port,
- 'probability': 50}]
+ def test_self_twice_nat_positive(self):
+ """ Self Twice NAT44 (positive test) """
+ self.twice_nat_common(self_twice_nat=True, same_pg=True)
- self.nat44_add_address(self.nat_addr)
- self.nat44_add_address(twice_nat_addr, twice_nat=1)
+ def test_self_twice_nat_negative(self):
+ """ Self Twice NAT44 (negative test) """
+ self.twice_nat_common(self_twice_nat=True)
- self.vapi.nat44_add_del_lb_static_mapping(external_addr_n,
- external_port,
- IP_PROTOS.tcp,
- twice_nat=1,
- local_num=len(locals),
- locals=locals)
- self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
- self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
- is_inside=0)
+ def test_twice_nat_lb(self):
+ """ Twice NAT44 local service load balancing """
+ self.twice_nat_common(lb=True)
- p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
- IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
- TCP(sport=eh_port_out, dport=external_port))
- self.pg1.add_stream(p)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- capture = self.pg0.get_capture(1)
- p = capture[0]
- server = None
- try:
- ip = p[IP]
- tcp = p[TCP]
- self.assertEqual(ip.src, twice_nat_addr)
- self.assertIn(ip.dst, [server1.ip4, server2.ip4])
- if ip.dst == server1.ip4:
- server = server1
- else:
- server = server2
- self.assertNotEqual(tcp.sport, eh_port_out)
- eh_port_in = tcp.sport
- self.assertEqual(tcp.dport, local_port)
- self.check_tcp_checksum(p)
- self.check_ip_checksum(p)
- except:
- self.logger.error(ppp("Unexpected or invalid packet:", p))
- raise
+ def test_self_twice_nat_lb_positive(self):
+ """ Self Twice NAT44 local service load balancing (positive test) """
+ self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
+ client_id=1)
- p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
- IP(src=server.ip4, dst=twice_nat_addr) /
- TCP(sport=local_port, dport=eh_port_in))
- self.pg0.add_stream(p)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- capture = self.pg1.get_capture(1)
- p = capture[0]
- try:
- ip = p[IP]
- tcp = p[TCP]
- self.assertEqual(ip.src, self.nat_addr)
- self.assertEqual(ip.dst, self.pg1.remote_ip4)
- self.assertEqual(tcp.sport, external_port)
- self.assertEqual(tcp.dport, eh_port_out)
- self.check_tcp_checksum(p)
- self.check_ip_checksum(p)
- except:
- self.logger.error(ppp("Unexpected or invalid packet:", p))
- raise
+ def test_self_twice_nat_lb_negative(self):
+ """ Self Twice NAT44 local service load balancing (negative test) """
+ self.twice_nat_common(lb=True, self_twice_nat=True, same_pg=True,
+ client_id=2)
def test_twice_nat_interface_addr(self):
""" Acquire twice NAT44 addresses from interface """
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 44cb7b6fc68..53be992aeeb 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1302,6 +1302,7 @@ class VppPapiProvider(object):
vrf_id=0,
protocol=0,
twice_nat=0,
+ self_twice_nat=0,
out2in_only=0,
tag="",
is_add=1):
@@ -1316,6 +1317,9 @@ class VppPapiProvider(object):
:param vrf_id: VRF ID
:param protocol: IP protocol (Default value = 0)
:param twice_nat: 1 if translate external host address and port
+ :param self_twice_nat: 1 if translate external host address and port
+ whenever external host address equals
+ local address of internal host
:param out2in_only: if 1 rule is matching only out2in direction
:param tag: Opaque string tag
:param is_add: 1 if add, 0 if delete (Default value = 1)
@@ -1332,6 +1336,7 @@ class VppPapiProvider(object):
'vrf_id': vrf_id,
'protocol': protocol,
'twice_nat': twice_nat,
+ 'self_twice_nat': self_twice_nat,
'out2in_only': out2in_only,
'tag': tag})
@@ -1496,6 +1501,7 @@ class VppPapiProvider(object):
protocol,
vrf_id=0,
twice_nat=0,
+ self_twice_nat=0,
out2in_only=0,
tag='',
local_num=0,
@@ -1515,6 +1521,7 @@ class VppPapiProvider(object):
'protocol': protocol,
'vrf_id': vrf_id,
'twice_nat': twice_nat,
+ 'self_twice_nat': self_twice_nat,
'out2in_only': out2in_only,
'tag': tag,
'local_num': local_num,