aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/nat/nat.api6
-rw-r--r--src/plugins/nat/nat.c46
-rw-r--r--src/plugins/nat/nat.h2
-rw-r--r--src/plugins/nat/nat_api.c10
-rw-r--r--test/test_nat.py105
-rw-r--r--test/vpp_papi_provider.py5
6 files changed, 146 insertions, 28 deletions
diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api
index 78f34509b69..1de70edaaad 100644
--- a/src/plugins/nat/nat.api
+++ b/src/plugins/nat/nat.api
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-vl_api_version 2.2.0
+vl_api_version 2.3.0
/**
* @file nat.api
@@ -352,6 +352,7 @@ 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 out2in_only - if 1 rule match only out2in direction
*/
autoreply define nat44_add_del_static_mapping {
u32 client_index;
@@ -366,6 +367,7 @@ autoreply define nat44_add_del_static_mapping {
u32 external_sw_if_index;
u32 vrf_id;
u8 twice_nat;
+ u8 out2in_only;
};
/** \brief Dump NAT44 static mappings
@@ -388,6 +390,7 @@ 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 out2in_only - if 1 rule match only out2in direction
*/
define nat44_static_mapping_details {
u32 context;
@@ -400,6 +403,7 @@ define nat44_static_mapping_details {
u32 external_sw_if_index;
u32 vrf_id;
u8 twice_nat;
+ u8 out2in_only;
};
/** \brief Add/delete NAT44 identity mapping
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 99c5f63cf12..6ed4877eafa 100644
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -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;
@@ -1273,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
@@ -2299,6 +2304,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))
@@ -2331,6 +2337,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
@@ -2355,7 +2363,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)
{
@@ -2403,7 +2411,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 *
@@ -2452,7 +2460,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)
{
@@ -3175,22 +3183,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;
}
@@ -3562,7 +3572,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);
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index ff7888a9128..eba005128de 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -545,7 +545,7 @@ 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 twice_nat, u8 out2in_only);
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);
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index f3d353fa20e..f23efa8d89f 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -711,7 +711,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->twice_nat, mp->out2in_only);
REPLY_MACRO (VL_API_NAT44_ADD_DEL_STATIC_MAPPING_REPLY);
}
@@ -732,7 +732,8 @@ static void *vl_api_nat44_add_del_static_mapping_t_print
clib_net_to_host_u16 (mp->local_port),
clib_net_to_host_u16 (mp->external_port));
- s = format (s, "twice_nat %d ", mp->twice_nat);
+ s = format (s, "twice_nat %d out2in_only %d ",
+ mp->twice_nat, mp->out2in_only);
if (mp->vrf_id != ~0)
s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id));
@@ -764,6 +765,7 @@ send_nat44_static_mapping_details (snat_static_mapping_t * m,
rmp->protocol = snat_proto_to_ip_proto (m->proto);
rmp->context = context;
rmp->twice_nat = m->twice_nat;
+ rmp->out2in_only = m->out2in_only;
vl_api_send_msg (reg, (u8 *) rmp);
}
@@ -861,7 +863,7 @@ static void
rv =
snat_add_static_mapping (addr, addr, port, port, vrf_id, mp->addr_only,
- sw_if_index, proto, mp->is_add, 0);
+ sw_if_index, proto, mp->is_add, 0, 0);
REPLY_MACRO (VL_API_NAT44_ADD_DEL_IDENTITY_MAPPING_REPLY);
}
@@ -1259,7 +1261,7 @@ static void *vl_api_nat44_add_del_lb_static_mapping_t_print
u8 *s;
s = format (0, "SCRIPT: nat44_add_del_lb_static_mapping ");
- s = format (s, "is_add %d twice_nat %d out2in_only ",
+ s = format (s, "is_add %d twice_nat %d out2in_only %d ",
mp->is_add, mp->twice_nat, mp->out2in_only);
FINISH;
diff --git a/test/test_nat.py b/test/test_nat.py
index 384ec8f273e..d2bc4569af0 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -1029,6 +1029,7 @@ class TestNAT44(MethodHolder):
vrf_id=sm.vrf_id,
protocol=sm.protocol,
twice_nat=sm.twice_nat,
+ out2in_only=sm.out2in_only,
is_add=0)
lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
@@ -1068,7 +1069,7 @@ 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):
+ proto=0, twice_nat=0, out2in_only=0):
"""
Add/delete NAT44 static mapping
@@ -1081,6 +1082,7 @@ 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 out2in_only: if 1 rule is matching only out2in direction
"""
addr_only = 1
if local_port and external_port:
@@ -1097,6 +1099,7 @@ class TestNAT44(MethodHolder):
vrf_id,
proto,
twice_nat,
+ out2in_only,
is_add)
def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
@@ -1493,6 +1496,102 @@ class TestNAT44(MethodHolder):
capture = self.pg1.get_capture(len(pkts))
self.verify_capture_out(capture)
+ def test_static_with_port_out2(self):
+ """ 1:1 NAPT symmetrical rule """
+
+ external_port = 80
+ local_port = 8080
+
+ self.vapi.nat44_forwarding_enable_disable(1)
+ self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
+ local_port, external_port,
+ proto=IP_PROTOS.tcp, out2in_only=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,
+ is_inside=0)
+
+ # from client to service
+ p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
+ IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
+ TCP(sport=12345, 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.dst, self.pg0.remote_ip4)
+ 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
+
+ # from service back to client
+ p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+ IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+ TCP(sport=local_port, dport=12345))
+ 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(tcp.sport, external_port)
+ self.check_tcp_checksum(p)
+ self.check_ip_checksum(p)
+ except:
+ self.logger.error(ppp("Unexpected or invalid packet:", p))
+ raise
+
+ # from client to server (no translation)
+ p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
+ IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4) /
+ TCP(sport=12346, dport=local_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.dst, self.pg0.remote_ip4)
+ 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
+
+ # from service back to client (no translation)
+ p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+ IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+ TCP(sport=local_port, dport=12346))
+ 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.pg0.remote_ip4)
+ self.assertEqual(tcp.sport, 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_static_vrf_aware(self):
""" 1:1 NAT VRF awareness """
@@ -2023,7 +2122,7 @@ class TestNAT44(MethodHolder):
self.assertEqual(tcp.dport, host_in_port)
self.check_tcp_checksum(p)
except:
- self.logger.error(ppp("Unexpected or invalid packet:"), p)
+ self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
def test_hairpinning2(self):
@@ -3082,7 +3181,7 @@ class TestNAT44(MethodHolder):
self.assertEqual(tcp.dport, host_in_port)
self.check_tcp_checksum(p)
except:
- self.logger.error(ppp("Unexpected or invalid packet:"), p)
+ self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
def test_one_armed_nat44(self):
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 6e6f7caf287..13dccc9283b 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1235,6 +1235,7 @@ class VppPapiProvider(object):
vrf_id=0,
protocol=0,
twice_nat=0,
+ out2in_only=0,
is_add=1):
"""Add/delete NAT44 static mapping
@@ -1247,6 +1248,7 @@ 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 out2in_only: if 1 rule is matching only out2in direction
:param is_add: 1 if add, 0 if delete (Default value = 1)
"""
return self.api(
@@ -1260,7 +1262,8 @@ class VppPapiProvider(object):
'external_sw_if_index': external_sw_if_index,
'vrf_id': vrf_id,
'protocol': protocol,
- 'twice_nat': twice_nat})
+ 'twice_nat': twice_nat,
+ 'out2in_only': out2in_only})
def nat44_add_del_identity_mapping(
self,