SNAT: add API and test for NAT pool address from interface

Change-Id: I2a868f736fae8d37b438c604a9284653ea415541
Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:
Matus Fabian
2017-01-12 04:24:35 -08:00
committed by Damjan Marion
parent 97f6edc1f5
commit 8bf68e858a
5 changed files with 287 additions and 17 deletions

View File

@ -24,9 +24,9 @@
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_ip4 - 1 if address type is IPv4
@first_ip_address - first IP address
@last_ip_address - last IP address
@is_add - 1 if add, 0 if delete
@param first_ip_address - first IP address
@param last_ip_address - last IP address
@param is_add - 1 if add, 0 if delete
*/
define snat_add_address_range {
u32 client_index;
@ -38,7 +38,6 @@ define snat_add_address_range {
};
/** \brief Add S-NAT address range reply
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param retval - return code
*/
@ -83,7 +82,6 @@ define snat_interface_add_del_feature {
};
/** \brief Enable/disable S-NAT feature on the interface reply
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param retval - return code
*/
@ -138,7 +136,6 @@ define snat_add_static_mapping {
};
/** \brief Add/delete S-NAT static mapping reply
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param retval - return code
*/
@ -251,7 +248,6 @@ define snat_set_workers {
};
/** \brief Set S-NAT workers reply
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param retval - return code
*/
@ -281,3 +277,44 @@ define snat_worker_details {
u32 lcore_id;
u8 name[64];
};
/** \brief Add/delete S-NAT pool address from specific interfce
@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 sw_if_index - software index of the interface
*/
define snat_add_del_interface_addr {
u32 client_index;
u32 context;
u8 is_add;
u8 is_inside;
u32 sw_if_index;
};
/** \brief Add/delete S-NAT pool address from specific interfce reply
@param context - sender context, to match reply w/ request
@param retval - return code
*/
define snat_add_del_interface_addr_reply {
u32 context;
i32 retval;
};
/** \brief Dump S-NAT pool addresses interfaces
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
*/
define snat_interface_addr_dump {
u32 client_index;
u32 context;
};
/** \brief S-NAT pool addresses interfaces details response
@param context - sender context, to match reply w/ request
@param sw_if_index - software index of the interface
*/
define snat_interface_addr_details {
u32 context;
u32 sw_if_index;
};

View File

@ -1094,6 +1094,84 @@ static void *vl_api_snat_worker_dump_t_print
FINISH;
}
static int snat_add_interface_address(snat_main_t *sm,
u32 sw_if_index,
int is_del);
static void
vl_api_snat_add_del_interface_addr_t_handler
(vl_api_snat_add_del_interface_addr_t * mp)
{
snat_main_t * sm = &snat_main;
vl_api_snat_add_del_interface_addr_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_add_interface_address (sm, sw_if_index, is_del);
BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO(VL_API_SNAT_ADD_DEL_INTERFACE_ADDR_REPLY);
}
static void *vl_api_snat_add_del_interface_addr_t_print
(vl_api_snat_add_del_interface_addr_t * mp, void *handle)
{
u8 * s;
s = format (0, "SCRIPT: snat_add_del_interface_addr ");
s = format (s, "sw_if_index %d %s",
clib_host_to_net_u32(mp->sw_if_index),
mp->is_add ? "" : "del");
FINISH;
}
static void
send_snat_interface_addr_details
(u32 sw_if_index, unix_shared_memory_queue_t * q, u32 context)
{
vl_api_snat_interface_addr_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_ADDR_DETAILS+sm->msg_id_base);
rmp->sw_if_index = ntohl (sw_if_index);
rmp->context = context;
vl_msg_api_send_shmem (q, (u8 *) & rmp);
}
static void
vl_api_snat_interface_addr_dump_t_handler
(vl_api_snat_interface_addr_dump_t * mp)
{
unix_shared_memory_queue_t *q;
snat_main_t * sm = &snat_main;
u32 * i;
q = vl_api_client_index_to_input_queue (mp->client_index);
if (q == 0)
return;
vec_foreach (i, sm->auto_add_sw_if_indices)
send_snat_interface_addr_details(*i, q, mp->context);
}
static void *vl_api_snat_interface_addr_dump_t_print
(vl_api_snat_interface_addr_dump_t *mp, void * handle)
{
u8 *s;
s = format (0, "SCRIPT: snat_interface_addr_dump ");
FINISH;
}
/* List of message types that this plugin understands */
#define foreach_snat_plugin_api_msg \
_(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \
@ -1105,7 +1183,9 @@ _(SNAT_SHOW_CONFIG, snat_show_config) \
_(SNAT_ADDRESS_DUMP, snat_address_dump) \
_(SNAT_INTERFACE_DUMP, snat_interface_dump) \
_(SNAT_SET_WORKERS, snat_set_workers) \
_(SNAT_WORKER_DUMP, snat_worker_dump)
_(SNAT_WORKER_DUMP, snat_worker_dump) \
_(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr) \
_(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump)
/* Set up the API message handling tables */
static clib_error_t *
@ -1840,7 +1920,7 @@ show_snat_command_fn (vlib_main_t * vm,
snat_address_t * ap;
vnet_main_t *vnm = vnet_get_main();
snat_main_per_thread_data_t *tsm;
u32 users_num = 0, sessions_num = 0, *worker;
u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
uword j = 0;
if (unformat (input, "detail"))
@ -1870,6 +1950,16 @@ show_snat_command_fn (vlib_main_t * vm,
i->is_inside ? "in" : "out");
}));
if (vec_len (sm->auto_add_sw_if_indices))
{
vlib_cli_output (vm, "SNAT pool addresses interfaces:");
vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
{
vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
vnet_get_sw_interface (vnm, *sw_if_index));
}
}
vec_foreach (ap, sm->addresses)
{
u8 * s = format (0, "");
@ -2011,7 +2101,9 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
}
static int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index)
static int snat_add_interface_address (snat_main_t *sm,
u32 sw_if_index,
int is_del)
{
ip4_main_t * ip4_main = sm->ip4_main;
ip4_address_t * first_int_addr;
@ -2023,9 +2115,24 @@ static int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index)
for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
{
if (sm->auto_add_sw_if_indices[i] == sw_if_index)
return 0;
{
if (is_del)
{
/* if have address remove it */
if (first_int_addr)
(void) snat_del_address (sm, first_int_addr[0]);
vec_del1(sm->auto_add_sw_if_indices, i);
}
else
return VNET_API_ERROR_VALUE_EXIST;
return 0;
}
}
if (is_del)
return VNET_API_ERROR_NO_SUCH_ENTRY;
/* add to the auto-address list */
vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
@ -2045,6 +2152,7 @@ snat_add_interface_address_command_fn (vlib_main_t * vm,
unformat_input_t _line_input, *line_input = &_line_input;
u32 sw_if_index;
int rv;
int is_del = 0;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
@ -2055,12 +2163,14 @@ snat_add_interface_address_command_fn (vlib_main_t * vm,
if (unformat (line_input, "%U", unformat_vnet_sw_interface,
sm->vnet_main, &sw_if_index))
;
else if (unformat (line_input, "del"))
is_del = 1;
else
return clib_error_return (0, "unknown input '%U'",
format_unformat_error, line_input);
}
rv = snat_add_interface_address (sm, sw_if_index);
rv = snat_add_interface_address (sm, sw_if_index, is_del);
switch (rv)
{
@ -2076,6 +2186,6 @@ snat_add_interface_address_command_fn (vlib_main_t * vm,
VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
.path = "snat add interface address",
.short_help = "snat add interface address <interface>",
.short_help = "snat add interface address <interface> [del]",
.function = snat_add_interface_address_command_fn,
};

View File

@ -61,7 +61,8 @@ snat_test_main_t snat_test_main;
_(snat_add_address_range_reply) \
_(snat_interface_add_del_feature_reply) \
_(snat_add_static_mapping_reply) \
_(snat_set_workers_reply)
_(snat_set_workers_reply) \
_(snat_add_del_interface_addr_reply)
#define _(n) \
static void vl_api_##n##_t_handler \
@ -94,7 +95,10 @@ _(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply) \
_(SNAT_ADDRESS_DETAILS, snat_address_details) \
_(SNAT_INTERFACE_DETAILS, snat_interface_details) \
_(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply) \
_(SNAT_WORKER_DETAILS, snat_worker_details)
_(SNAT_WORKER_DETAILS, snat_worker_details) \
_(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY, \
snat_add_del_interface_addr_reply) \
_(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details)
/* M: construct, but don't yet send a message */
#define M(T,t) \
@ -539,6 +543,80 @@ static int api_snat_worker_dump(vat_main_t * vam)
return 0;
}
static int api_snat_add_del_interface_addr (vat_main_t * vam)
{
snat_test_main_t * sm = &snat_test_main;
unformat_input_t * i = vam->input;
f64 timeout;
vl_api_snat_add_del_interface_addr_t * mp;
u32 sw_if_index;
u8 sw_if_index_set = 0;
u8 is_add = 1;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
sw_if_index_set = 1;
else if (unformat (i, "sw_if_index %d", &sw_if_index))
sw_if_index_set = 1;
else if (unformat (i, "del"))
is_add = 0;
else
{
clib_warning("unknown input '%U'", format_unformat_error, i);
return -99;
}
}
if (sw_if_index_set == 0)
{
errmsg ("interface / sw_if_index required\n");
return -99;
}
M(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr);
mp->sw_if_index = ntohl(sw_if_index);
mp->is_add = is_add;
S; W;
/* NOTREACHED */
return 0;
}
static void vl_api_snat_interface_addr_details_t_handler
(vl_api_snat_interface_addr_details_t *mp)
{
snat_test_main_t * sm = &snat_test_main;
vat_main_t *vam = sm->vat_main;
fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index));
}
static int api_snat_interface_addr_dump(vat_main_t * vam)
{
snat_test_main_t * sm = &snat_test_main;
f64 timeout;
vl_api_snat_interface_addr_dump_t * mp;
if (vam->json_output)
{
clib_warning ("JSON output not supported for snat_address_dump");
return -99;
}
M(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump);
S;
/* Use a control ping for synchronization */
{
vl_api_snat_control_ping_t *mp;
M (SNAT_CONTROL_PING, snat_control_ping);
S;
}
W;
/* NOTREACHED */
return 0;
}
/*
* List of messages that the api test plugin sends,
* and that the data plane plugin processes
@ -554,7 +632,10 @@ _(snat_static_mapping_dump, "") \
_(snat_show_config, "") \
_(snat_address_dump, "") \
_(snat_interface_dump, "") \
_(snat_worker_dump, "")
_(snat_worker_dump, "") \
_(snat_add_del_interface_addr, \
"<intfc> | sw_if_index <id> [del]") \
_(snat_interface_addr_dump, "")
void vat_api_hookup (vat_main_t *vam)
{

View File

@ -26,7 +26,7 @@ class TestSNAT(VppTestCase):
cls.icmp_id_out = 6305
cls.snat_addr = '10.0.0.3'
cls.create_pg_interfaces(range(7))
cls.create_pg_interfaces(range(8))
cls.interfaces = list(cls.pg_interfaces[0:4])
for i in cls.interfaces:
@ -48,6 +48,8 @@ class TestSNAT(VppTestCase):
i.admin_up()
i.resolve_arp()
cls.pg7.admin_up()
except Exception:
super(TestSNAT, cls).tearDownClass()
raise
@ -178,6 +180,10 @@ class TestSNAT(VppTestCase):
"""
Clear SNAT configuration.
"""
interfaces = self.vapi.snat_interface_addr_dump()
for intf in interfaces:
self.vapi.snat_add_interface_addr(intf.sw_if_index, is_add=0)
interfaces = self.vapi.snat_interface_dump()
for intf in interfaces:
self.vapi.snat_interface_add_del_feature(intf.sw_if_index,
@ -623,6 +629,24 @@ class TestSNAT(VppTestCase):
# verify number of translated packet
self.pg1.get_capture(pkts_num)
def test_interface_addr(self):
""" Acquire SNAT addresses from interface """
self.vapi.snat_add_interface_addr(self.pg7.sw_if_index)
# no address in NAT pool
adresses = self.vapi.snat_address_dump()
self.assertEqual(0, len(adresses))
# configure interface address and check NAT address pool
self.pg7.config_ip4()
adresses = self.vapi.snat_address_dump()
self.assertEqual(1, len(adresses))
# remove interface address and check NAT address pool
self.pg7.unconfig_ip4()
adresses = self.vapi.snat_address_dump()
self.assertEqual(0, len(adresses))
def tearDown(self):
super(TestSNAT, self).tearDown()
if not self.vpp_dead:

View File

@ -916,6 +916,24 @@ class VppPapiProvider(object):
"""
return self.api(self.papi.snat_show_config, {})
def snat_add_interface_addr(
self,
sw_if_index,
is_add=1):
"""Add/del S-NAT address from interface
:param sw_if_index: Software index of the interface
:param is_add: 1 if add, 0 if delete (Default value = 1)
"""
return self.api(self.papi.snat_add_del_interface_addr,
{'is_add': is_add, 'sw_if_index': sw_if_index})
def snat_interface_addr_dump(self):
"""Dump S-NAT addresses interfaces
:return: Dictionary of S-NAT addresses interfaces
"""
return self.api(self.papi.snat_interface_addr_dump, {})
def control_ping(self):
self.api(self.papi.control_ping)