SNAT: in2out translation as an output feature (VPP-903)
in2out translation as an output feature on the outside interface (postrouting) Change-Id: I32c0311be09bdf102b9a0885b8b89c7588cb558f Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:
Matus Fabian
committed by
Florin Coras
parent
b12ac56c44
commit
93d84c9fc2
File diff suppressed because it is too large
Load Diff
@ -96,6 +96,42 @@ define snat_interface_details {
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief Enable/disbale S-NAT as an interface output feature (postrouting
|
||||
in2out translation)
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param is_add - 1 if add, 0 if delete
|
||||
@param is_inside - 1 if inside, 0 if outside
|
||||
@param sw_if_index - software index of the interface
|
||||
*/
|
||||
autoreply define snat_interface_add_del_output_feature {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u8 is_add;
|
||||
u8 is_inside;
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief Dump interfaces with S-NAT output feature
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
*/
|
||||
define snat_interface_output_feature_dump {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
};
|
||||
|
||||
/** \brief S-NAT interface with output feature details response
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param is_inside - 1 if inside, 0 if outside
|
||||
@param sw_if_index - software index of the interface
|
||||
*/
|
||||
define snat_interface_output_feature_details {
|
||||
u32 context;
|
||||
u8 is_inside;
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief Add/delete S-NAT static mapping
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
|
@ -73,6 +73,20 @@ VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
|
||||
.runs_before = VNET_FEATURES ("ip4-lookup"),
|
||||
};
|
||||
|
||||
/* Hook up output features */
|
||||
VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
|
||||
.arc_name = "ip4-output",
|
||||
.node_name = "snat-in2out-output",
|
||||
.runs_before = VNET_FEATURES ("interface-output"),
|
||||
};
|
||||
|
||||
VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
|
||||
.arc_name = "ip4-output",
|
||||
.node_name = "snat-in2out-output-worker-handoff",
|
||||
.runs_before = VNET_FEATURES ("interface-output"),
|
||||
};
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
VLIB_PLUGIN_REGISTER () = {
|
||||
.version = VPP_BUILD_VER,
|
||||
@ -157,6 +171,14 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id)
|
||||
snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
|
||||
break;
|
||||
}));
|
||||
pool_foreach (i, sm->output_feature_interfaces,
|
||||
({
|
||||
if (i->is_inside)
|
||||
continue;
|
||||
|
||||
snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
|
||||
break;
|
||||
}));
|
||||
}
|
||||
|
||||
static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
|
||||
@ -542,6 +564,14 @@ delete:
|
||||
snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
|
||||
break;
|
||||
}));
|
||||
pool_foreach (interface, sm->output_feature_interfaces,
|
||||
({
|
||||
if (interface->is_inside)
|
||||
continue;
|
||||
|
||||
snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
|
||||
break;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -668,6 +698,14 @@ int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
|
||||
snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
|
||||
break;
|
||||
}));
|
||||
pool_foreach (interface, sm->output_feature_interfaces,
|
||||
({
|
||||
if (interface->is_inside)
|
||||
continue;
|
||||
|
||||
snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
|
||||
break;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -746,6 +784,85 @@ fib:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snat_interface_add_del_output_feature (u32 sw_if_index,
|
||||
u8 is_inside,
|
||||
int is_del)
|
||||
{
|
||||
snat_main_t *sm = &snat_main;
|
||||
snat_interface_t *i;
|
||||
snat_address_t * ap;
|
||||
snat_static_mapping_t * m;
|
||||
|
||||
if (sm->deterministic ||
|
||||
(sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
|
||||
return VNET_API_ERROR_UNSUPPORTED;
|
||||
|
||||
if (is_inside)
|
||||
goto find;
|
||||
|
||||
if (sm->num_workers > 1)
|
||||
{
|
||||
vnet_feature_enable_disable ("ip4-unicast", "snat-out2in-worker-handoff",
|
||||
sw_if_index, !is_del, 0, 0);
|
||||
vnet_feature_enable_disable ("ip4-output",
|
||||
"snat-in2out-output-worker-handoff",
|
||||
sw_if_index, !is_del, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vnet_feature_enable_disable ("ip4-unicast", "snat-out2in", sw_if_index,
|
||||
!is_del, 0, 0);
|
||||
vnet_feature_enable_disable ("ip4-output", "snat-in2out-output",
|
||||
sw_if_index, !is_del, 0, 0);
|
||||
}
|
||||
|
||||
if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
|
||||
sm->fq_in2out_output_index =
|
||||
vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
|
||||
|
||||
if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
|
||||
sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
|
||||
|
||||
find:
|
||||
pool_foreach (i, sm->output_feature_interfaces,
|
||||
({
|
||||
if (i->sw_if_index == sw_if_index)
|
||||
{
|
||||
if (is_del)
|
||||
pool_put (sm->output_feature_interfaces, i);
|
||||
else
|
||||
return VNET_API_ERROR_VALUE_EXIST;
|
||||
|
||||
goto fib;
|
||||
}
|
||||
}));
|
||||
|
||||
if (is_del)
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
|
||||
pool_get (sm->output_feature_interfaces, i);
|
||||
i->sw_if_index = sw_if_index;
|
||||
i->is_inside = is_inside;
|
||||
|
||||
/* Add/delete external addresses to FIB */
|
||||
fib:
|
||||
if (is_inside)
|
||||
return 0;
|
||||
|
||||
vec_foreach (ap, sm->addresses)
|
||||
snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
|
||||
|
||||
pool_foreach (m, sm->static_mappings,
|
||||
({
|
||||
if (!(m->addr_only))
|
||||
continue;
|
||||
|
||||
snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snat_set_workers (uword * bitmap)
|
||||
{
|
||||
snat_main_t *sm = &snat_main;
|
||||
@ -1103,6 +1220,7 @@ snat_feature_command_fn (vlib_main_t * vm,
|
||||
u32 sw_if_index;
|
||||
u32 * inside_sw_if_indices = 0;
|
||||
u32 * outside_sw_if_indices = 0;
|
||||
u8 is_output_feature = 0;
|
||||
int is_del = 0;
|
||||
int i;
|
||||
|
||||
@ -1120,6 +1238,8 @@ snat_feature_command_fn (vlib_main_t * vm,
|
||||
else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
|
||||
vnm, &sw_if_index))
|
||||
vec_add1 (outside_sw_if_indices, sw_if_index);
|
||||
else if (unformat (line_input, "output-feature"))
|
||||
is_output_feature = 1;
|
||||
else if (unformat (line_input, "del"))
|
||||
is_del = 1;
|
||||
else
|
||||
@ -1135,7 +1255,30 @@ snat_feature_command_fn (vlib_main_t * vm,
|
||||
for (i = 0; i < vec_len(inside_sw_if_indices); i++)
|
||||
{
|
||||
sw_if_index = inside_sw_if_indices[i];
|
||||
snat_interface_add_del (sw_if_index, 1, is_del);
|
||||
if (is_output_feature)
|
||||
{
|
||||
if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
|
||||
{
|
||||
error = clib_error_return (0, "%s %U failed",
|
||||
is_del ? "del" : "add",
|
||||
format_vnet_sw_interface_name, vnm,
|
||||
vnet_get_sw_interface (vnm,
|
||||
sw_if_index));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (snat_interface_add_del (sw_if_index, 1, is_del))
|
||||
{
|
||||
error = clib_error_return (0, "%s %U failed",
|
||||
is_del ? "del" : "add",
|
||||
format_vnet_sw_interface_name, vnm,
|
||||
vnet_get_sw_interface (vnm,
|
||||
sw_if_index));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1144,7 +1287,30 @@ snat_feature_command_fn (vlib_main_t * vm,
|
||||
for (i = 0; i < vec_len(outside_sw_if_indices); i++)
|
||||
{
|
||||
sw_if_index = outside_sw_if_indices[i];
|
||||
snat_interface_add_del (sw_if_index, 0, is_del);
|
||||
if (is_output_feature)
|
||||
{
|
||||
if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
|
||||
{
|
||||
error = clib_error_return (0, "%s %U failed",
|
||||
is_del ? "del" : "add",
|
||||
format_vnet_sw_interface_name, vnm,
|
||||
vnet_get_sw_interface (vnm,
|
||||
sw_if_index));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (snat_interface_add_del (sw_if_index, 0, is_del))
|
||||
{
|
||||
error = clib_error_return (0, "%s %U failed",
|
||||
is_del ? "del" : "add",
|
||||
format_vnet_sw_interface_name, vnm,
|
||||
vnet_get_sw_interface (vnm,
|
||||
sw_if_index));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1159,7 +1325,8 @@ done:
|
||||
VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
|
||||
.path = "set interface snat",
|
||||
.function = snat_feature_command_fn,
|
||||
.short_help = "set interface snat in <intfc> out <intfc> [del]",
|
||||
.short_help = "set interface snat in <intfc> out <intfc> [output-feature] "
|
||||
"[del]",
|
||||
};
|
||||
|
||||
uword
|
||||
@ -1597,6 +1764,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
|
||||
if (sm->deterministic)
|
||||
{
|
||||
sm->in2out_node_index = snat_det_in2out_node.index;
|
||||
sm->in2out_output_node_index = ~0;
|
||||
sm->out2in_node_index = snat_det_out2in_node.index;
|
||||
sm->icmp_match_in2out_cb = icmp_match_in2out_det;
|
||||
sm->icmp_match_out2in_cb = icmp_match_out2in_det;
|
||||
@ -1606,6 +1774,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
|
||||
sm->worker_in2out_cb = snat_get_worker_in2out_cb;
|
||||
sm->worker_out2in_cb = snat_get_worker_out2in_cb;
|
||||
sm->in2out_node_index = snat_in2out_node.index;
|
||||
sm->in2out_output_node_index = snat_in2out_output_node.index;
|
||||
sm->out2in_node_index = snat_out2in_node.index;
|
||||
if (!static_mapping_only ||
|
||||
(static_mapping_only && static_mapping_connection_tracking))
|
||||
@ -1881,6 +2050,14 @@ show_snat_command_fn (vlib_main_t * vm,
|
||||
i->is_inside ? "in" : "out");
|
||||
}));
|
||||
|
||||
pool_foreach (i, sm->output_feature_interfaces,
|
||||
({
|
||||
vlib_cli_output (vm, "%U output-feature %s",
|
||||
format_vnet_sw_interface_name, vnm,
|
||||
vnet_get_sw_interface (vnm, i->sw_if_index),
|
||||
i->is_inside ? "in" : "out");
|
||||
}));
|
||||
|
||||
if (vec_len (sm->auto_add_sw_if_indices))
|
||||
{
|
||||
vlib_cli_output (vm, "SNAT pool addresses interfaces:");
|
||||
|
@ -297,6 +297,7 @@ typedef struct snat_main_s {
|
||||
|
||||
/* Interface pool */
|
||||
snat_interface_t * interfaces;
|
||||
snat_interface_t * output_feature_interfaces;
|
||||
|
||||
/* Vector of outside addresses */
|
||||
snat_address_t * addresses;
|
||||
@ -312,10 +313,12 @@ typedef struct snat_main_s {
|
||||
|
||||
/* Worker handoff index */
|
||||
u32 fq_in2out_index;
|
||||
u32 fq_in2out_output_index;
|
||||
u32 fq_out2in_index;
|
||||
|
||||
/* in2out and out2in node index */
|
||||
u32 in2out_node_index;
|
||||
u32 in2out_output_node_index;
|
||||
u32 out2in_node_index;
|
||||
|
||||
/* Deterministic NAT */
|
||||
@ -357,10 +360,12 @@ typedef struct snat_main_s {
|
||||
|
||||
extern snat_main_t snat_main;
|
||||
extern vlib_node_registration_t snat_in2out_node;
|
||||
extern vlib_node_registration_t snat_in2out_output_node;
|
||||
extern vlib_node_registration_t snat_out2in_node;
|
||||
extern vlib_node_registration_t snat_in2out_fast_node;
|
||||
extern vlib_node_registration_t snat_out2in_fast_node;
|
||||
extern vlib_node_registration_t snat_in2out_worker_handoff_node;
|
||||
extern vlib_node_registration_t snat_in2out_output_worker_handoff_node;
|
||||
extern vlib_node_registration_t snat_out2in_worker_handoff_node;
|
||||
extern vlib_node_registration_t snat_det_in2out_node;
|
||||
extern vlib_node_registration_t snat_det_out2in_node;
|
||||
@ -477,6 +482,8 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
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);
|
||||
int snat_interface_add_del_output_feature(u32 sw_if_index, u8 is_inside,
|
||||
int is_del);
|
||||
int snat_add_interface_address(snat_main_t *sm, u32 sw_if_index, int is_del);
|
||||
uword unformat_snat_protocol(unformat_input_t * input, va_list * args);
|
||||
u8 * format_snat_protocol(u8 * s, va_list * args);
|
||||
|
@ -253,7 +253,91 @@ static void *vl_api_snat_interface_dump_t_print
|
||||
s = format (0, "SCRIPT: snat_interface_dump ");
|
||||
|
||||
FINISH;
|
||||
} static void
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_snat_interface_add_del_output_feature_t_handler
|
||||
(vl_api_snat_interface_add_del_output_feature_t * mp)
|
||||
{
|
||||
snat_main_t *sm = &snat_main;
|
||||
vl_api_snat_interface_add_del_output_feature_reply_t *rmp;
|
||||
u8 is_del = mp->is_add == 0;
|
||||
u32 sw_if_index = ntohl (mp->sw_if_index);
|
||||
int rv = 0;
|
||||
|
||||
VALIDATE_SW_IF_INDEX (mp);
|
||||
|
||||
rv = snat_interface_add_del_output_feature (sw_if_index, mp->is_inside,
|
||||
is_del);
|
||||
|
||||
BAD_SW_IF_INDEX_LABEL;
|
||||
|
||||
REPLY_MACRO (VL_API_SNAT_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY);
|
||||
}
|
||||
|
||||
static void *vl_api_snat_interface_add_del_output_feature_t_print
|
||||
(vl_api_snat_interface_add_del_output_feature_t * mp, void *handle)
|
||||
{
|
||||
u8 *s;
|
||||
|
||||
s = format (0, "SCRIPT: snat_interface_add_del_output_feature ");
|
||||
s = format (s, "sw_if_index %d %s %s",
|
||||
clib_host_to_net_u32 (mp->sw_if_index),
|
||||
mp->is_inside ? "in" : "out", mp->is_add ? "" : "del");
|
||||
|
||||
FINISH;
|
||||
}
|
||||
|
||||
static void
|
||||
send_snat_interface_output_feature_details (snat_interface_t * i,
|
||||
unix_shared_memory_queue_t * q,
|
||||
u32 context)
|
||||
{
|
||||
vl_api_snat_interface_output_feature_details_t *rmp;
|
||||
snat_main_t *sm = &snat_main;
|
||||
|
||||
rmp = vl_msg_api_alloc (sizeof (*rmp));
|
||||
memset (rmp, 0, sizeof (*rmp));
|
||||
rmp->_vl_msg_id =
|
||||
ntohs (VL_API_SNAT_INTERFACE_OUTPUT_FEATURE_DETAILS + sm->msg_id_base);
|
||||
rmp->sw_if_index = ntohl (i->sw_if_index);
|
||||
rmp->context = context;
|
||||
rmp->is_inside = i->is_inside;
|
||||
|
||||
vl_msg_api_send_shmem (q, (u8 *) & rmp);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_snat_interface_output_feature_dump_t_handler
|
||||
(vl_api_snat_interface_output_feature_dump_t * mp)
|
||||
{
|
||||
unix_shared_memory_queue_t *q;
|
||||
snat_main_t *sm = &snat_main;
|
||||
snat_interface_t *i;
|
||||
|
||||
q = vl_api_client_index_to_input_queue (mp->client_index);
|
||||
if (q == 0)
|
||||
return;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
pool_foreach (i, sm->output_feature_interfaces,
|
||||
({
|
||||
send_snat_interface_output_feature_details(i, q, mp->context);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
static void *vl_api_snat_interface_output_feature_dump_t_print
|
||||
(vl_api_snat_interface_output_feature_dump_t * mp, void *handle)
|
||||
{
|
||||
u8 *s;
|
||||
|
||||
s = format (0, "SCRIPT: snat_interface_output_feature_dump ");
|
||||
|
||||
FINISH;
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_snat_add_static_mapping_t_handler
|
||||
(vl_api_snat_add_static_mapping_t * mp)
|
||||
{
|
||||
@ -1792,6 +1876,10 @@ _(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump) \
|
||||
_(SNAT_IPFIX_ENABLE_DISABLE, snat_ipfix_enable_disable) \
|
||||
_(SNAT_USER_DUMP, snat_user_dump) \
|
||||
_(SNAT_USER_SESSION_DUMP, snat_user_session_dump) \
|
||||
_(SNAT_INTERFACE_ADD_DEL_OUTPUT_FEATURE, \
|
||||
snat_interface_add_del_output_feature) \
|
||||
_(SNAT_INTERFACE_OUTPUT_FEATURE_DUMP, \
|
||||
snat_interface_output_feature_dump) \
|
||||
_(SNAT_ADD_DET_MAP, snat_add_det_map) \
|
||||
_(SNAT_DET_FORWARD, snat_det_forward) \
|
||||
_(SNAT_DET_REVERSE, snat_det_reverse) \
|
||||
|
@ -615,6 +615,12 @@ class TestSNAT(MethodHolder):
|
||||
intf.is_inside,
|
||||
is_add=0)
|
||||
|
||||
interfaces = self.vapi.snat_interface_output_feature_dump()
|
||||
for intf in interfaces:
|
||||
self.vapi.snat_interface_add_del_output_feature(intf.sw_if_index,
|
||||
intf.is_inside,
|
||||
is_add=0)
|
||||
|
||||
static_mappings = self.vapi.snat_static_mapping_dump()
|
||||
for sm in static_mappings:
|
||||
self.vapi.snat_add_static_mapping(sm.local_ip_address,
|
||||
@ -2108,6 +2114,146 @@ class TestSNAT(MethodHolder):
|
||||
self.logger.error(ppp("Unexpected or invalid packet:", packet))
|
||||
raise
|
||||
|
||||
def test_output_feature(self):
|
||||
""" S-NAT interface output feature (in2out postrouting) """
|
||||
self.snat_add_address(self.snat_addr)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg0.sw_if_index)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg1.sw_if_index,
|
||||
is_inside=0)
|
||||
|
||||
# in2out
|
||||
pkts = self.create_stream_in(self.pg0, self.pg1)
|
||||
self.pg0.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg1.get_capture(len(pkts))
|
||||
self.verify_capture_out(capture)
|
||||
|
||||
# out2in
|
||||
pkts = self.create_stream_out(self.pg1)
|
||||
self.pg1.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg0.get_capture(len(pkts))
|
||||
self.verify_capture_in(capture, self.pg0)
|
||||
|
||||
def test_output_feature_vrf_aware(self):
|
||||
""" S-NAT interface output feature VRF aware (in2out postrouting) """
|
||||
nat_ip_vrf10 = "10.0.0.10"
|
||||
nat_ip_vrf20 = "10.0.0.20"
|
||||
|
||||
self.vapi.ip_add_del_route(dst_address=self.pg3.remote_ip4n,
|
||||
dst_address_length=32,
|
||||
next_hop_address=self.pg3.remote_ip4n,
|
||||
next_hop_sw_if_index=self.pg3.sw_if_index,
|
||||
table_id=10)
|
||||
self.vapi.ip_add_del_route(dst_address=self.pg3.remote_ip4n,
|
||||
dst_address_length=32,
|
||||
next_hop_address=self.pg3.remote_ip4n,
|
||||
next_hop_sw_if_index=self.pg3.sw_if_index,
|
||||
table_id=20)
|
||||
|
||||
self.snat_add_address(nat_ip_vrf10, vrf_id=10)
|
||||
self.snat_add_address(nat_ip_vrf20, vrf_id=20)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg4.sw_if_index)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg6.sw_if_index)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg3.sw_if_index,
|
||||
is_inside=0)
|
||||
|
||||
# in2out VRF 10
|
||||
pkts = self.create_stream_in(self.pg4, self.pg3)
|
||||
self.pg4.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg3.get_capture(len(pkts))
|
||||
self.verify_capture_out(capture, nat_ip=nat_ip_vrf10)
|
||||
|
||||
# out2in VRF 10
|
||||
pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf10)
|
||||
self.pg3.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg4.get_capture(len(pkts))
|
||||
self.verify_capture_in(capture, self.pg4)
|
||||
|
||||
# in2out VRF 20
|
||||
pkts = self.create_stream_in(self.pg6, self.pg3)
|
||||
self.pg6.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg3.get_capture(len(pkts))
|
||||
self.verify_capture_out(capture, nat_ip=nat_ip_vrf20)
|
||||
|
||||
# out2in VRF 20
|
||||
pkts = self.create_stream_out(self.pg3, dst_ip=nat_ip_vrf20)
|
||||
self.pg3.add_stream(pkts)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg6.get_capture(len(pkts))
|
||||
self.verify_capture_in(capture, self.pg6)
|
||||
|
||||
def _test_output_feature_hairpinning(self):
|
||||
""" S-NAT interface output feature hairpinning (in2out postrouting) """
|
||||
host = self.pg0.remote_hosts[0]
|
||||
server = self.pg0.remote_hosts[1]
|
||||
host_in_port = 1234
|
||||
host_out_port = 0
|
||||
server_in_port = 5678
|
||||
server_out_port = 8765
|
||||
|
||||
self.snat_add_address(self.snat_addr)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg0.sw_if_index)
|
||||
self.vapi.snat_interface_add_del_output_feature(self.pg1.sw_if_index,
|
||||
is_inside=0)
|
||||
|
||||
# add static mapping for server
|
||||
self.snat_add_static_mapping(server.ip4, self.snat_addr,
|
||||
server_in_port, server_out_port,
|
||||
proto=IP_PROTOS.tcp)
|
||||
|
||||
# send packet from host to server
|
||||
p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
|
||||
IP(src=host.ip4, dst=self.snat_addr) /
|
||||
TCP(sport=host_in_port, dport=server_out_port))
|
||||
self.pg0.add_stream(p)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg0.get_capture(1)
|
||||
p = capture[0]
|
||||
try:
|
||||
ip = p[IP]
|
||||
tcp = p[TCP]
|
||||
self.assertEqual(ip.src, self.snat_addr)
|
||||
self.assertEqual(ip.dst, server.ip4)
|
||||
self.assertNotEqual(tcp.sport, host_in_port)
|
||||
self.assertEqual(tcp.dport, server_in_port)
|
||||
self.check_tcp_checksum(p)
|
||||
host_out_port = tcp.sport
|
||||
except:
|
||||
self.logger.error(ppp("Unexpected or invalid packet:", p))
|
||||
raise
|
||||
|
||||
# send reply from server to host
|
||||
p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
|
||||
IP(src=server.ip4, dst=self.snat_addr) /
|
||||
TCP(sport=server_in_port, dport=host_out_port))
|
||||
self.pg0.add_stream(p)
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
capture = self.pg0.get_capture(1)
|
||||
p = capture[0]
|
||||
try:
|
||||
ip = p[IP]
|
||||
tcp = p[TCP]
|
||||
self.assertEqual(ip.src, self.snat_addr)
|
||||
self.assertEqual(ip.dst, host.ip4)
|
||||
self.assertEqual(tcp.sport, server_out_port)
|
||||
self.assertEqual(tcp.dport, host_in_port)
|
||||
self.check_tcp_checksum(p)
|
||||
except:
|
||||
self.logger.error(ppp("Unexpected or invalid packet:"), p)
|
||||
raise
|
||||
|
||||
def tearDown(self):
|
||||
super(TestSNAT, self).tearDown()
|
||||
if not self.vpp_dead:
|
||||
|
@ -1055,6 +1055,23 @@ class VppPapiProvider(object):
|
||||
'is_inside': is_inside,
|
||||
'sw_if_index': sw_if_index})
|
||||
|
||||
def snat_interface_add_del_output_feature(
|
||||
self,
|
||||
sw_if_index,
|
||||
is_inside=1,
|
||||
is_add=1):
|
||||
"""Enable/disable S-NAT output feature on the interface
|
||||
|
||||
:param sw_if_index: Software index of the interface
|
||||
:param is_inside: 1 if inside, 0 if outside (Default value = 1)
|
||||
:param is_add: 1 if add, 0 if delete (Default value = 1)
|
||||
"""
|
||||
return self.api(
|
||||
self.papi.snat_interface_add_del_output_feature,
|
||||
{'is_add': is_add,
|
||||
'is_inside': is_inside,
|
||||
'sw_if_index': sw_if_index})
|
||||
|
||||
def snat_add_static_mapping(
|
||||
self,
|
||||
local_ip,
|
||||
@ -1128,6 +1145,12 @@ class VppPapiProvider(object):
|
||||
"""
|
||||
return self.api(self.papi.snat_interface_dump, {})
|
||||
|
||||
def snat_interface_output_feature_dump(self):
|
||||
"""Dump interfaces with S-NAT output feature
|
||||
:return: Dictionary of interfaces with S-NAT output feature
|
||||
"""
|
||||
return self.api(self.papi.snat_interface_output_feature_dump, {})
|
||||
|
||||
def snat_static_mapping_dump(self):
|
||||
"""Dump S-NAT static mappings
|
||||
:return: Dictionary of S-NAT static mappings
|
||||
|
Reference in New Issue
Block a user