aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/snat/snat.api38
-rw-r--r--src/plugins/snat/snat.c243
-rw-r--r--src/plugins/snat/snat_test.c74
-rw-r--r--test/test_snat.py15
-rw-r--r--test/vpp_papi_provider.py46
5 files changed, 412 insertions, 4 deletions
diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api
index 573b6753711..5990eae5a24 100644
--- a/src/plugins/snat/snat.api
+++ b/src/plugins/snat/snat.api
@@ -527,3 +527,41 @@ define snat_det_get_timeouts_reply {
u32 tcp_transitory;
u32 icmp;
};
+
+/** \brief Close CGNAT session by outside address and port
+ @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
+ @param out_addr - outside IP address
+ @param out_port - outside port
+ @param ext_addr - external host address
+ @param ext_port - external host port
+*/
+autoreply define snat_det_close_session_out {
+ u32 client_index;
+ u32 context;
+ u8 is_ip4;
+ u8 out_addr[16];
+ u16 out_port;
+ u8 ext_addr[16];
+ u16 ext_port;
+};
+
+/** \brief Close CGNAT session by inside address and port
+ @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
+ @param in_addr - inside IP address
+ @param in_port - inside port
+ @param ext_addr - external host address
+ @param ext_port - external host port
+*/
+autoreply define snat_det_close_session_in {
+ u32 client_index;
+ u32 context;
+ u8 is_ip4;
+ u8 in_addr[16];
+ u16 in_port;
+ u8 ext_addr[16];
+ u16 ext_port;
+};
diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c
index 8569b041b49..594afa62c80 100644
--- a/src/plugins/snat/snat.c
+++ b/src/plugins/snat/snat.c
@@ -1712,6 +1712,105 @@ static void *vl_api_snat_det_get_timeouts_t_print
FINISH;
}
+static void
+vl_api_snat_det_close_session_out_t_handler
+(vl_api_snat_det_close_session_out_t * mp)
+{
+ snat_main_t * sm = &snat_main;
+ vl_api_snat_det_close_session_out_reply_t * rmp;
+ ip4_address_t out_addr, ext_addr, in_addr;
+ snat_det_out_key_t key;
+ snat_det_map_t * dm;
+ snat_det_session_t * ses;
+ int rv = 0;
+
+ clib_memcpy(&out_addr, mp->out_addr, 4);
+ clib_memcpy(&ext_addr, mp->ext_addr, 4);
+
+ dm = snat_det_map_by_out(sm, &out_addr);
+ if (!dm)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto send_reply;
+ }
+ snat_det_reverse(dm, &ext_addr, ntohs(mp->out_port), &in_addr);
+ key.ext_host_addr = ext_addr;
+ key.ext_host_port = mp->ext_port;
+ key.out_port = mp->out_port;
+ ses = snat_det_get_ses_by_out(dm, &in_addr, key.as_u64);
+ if (!ses)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto send_reply;
+ }
+ snat_det_ses_close(dm, ses);
+
+send_reply:
+ REPLY_MACRO (VL_API_SNAT_DET_CLOSE_SESSION_OUT_REPLY);
+}
+
+static void *vl_api_snat_det_close_session_out_t_print
+(vl_api_snat_det_close_session_out_t *mp, void * handle)
+{
+ u8 * s;
+
+ s = format (0, "SCRIPT: snat_det_close_session_out ");
+ s = format (s, "out_addr %U out_port %d "
+ "ext_addr %U ext_port %d\n",
+ format_ip4_address, mp->out_addr, ntohs(mp->out_port),
+ format_ip4_address, mp->ext_addr, ntohs(mp->ext_port));
+
+ FINISH;
+}
+
+static void
+vl_api_snat_det_close_session_in_t_handler
+(vl_api_snat_det_close_session_in_t * mp)
+{
+ snat_main_t * sm = &snat_main;
+ vl_api_snat_det_close_session_in_reply_t * rmp;
+ ip4_address_t in_addr, ext_addr;
+ snat_det_out_key_t key;
+ snat_det_map_t * dm;
+ snat_det_session_t * ses;
+ int rv = 0;
+
+ clib_memcpy(&in_addr, mp->in_addr, 4);
+ clib_memcpy(&ext_addr, mp->ext_addr, 4);
+
+ dm = snat_det_map_by_user(sm, &in_addr);
+ if (!dm)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto send_reply;
+ }
+ key.ext_host_addr = ext_addr;
+ key.ext_host_port = mp->ext_port;
+ ses = snat_det_find_ses_by_in(dm, &in_addr, mp->in_port, key);
+ if (!ses)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto send_reply;
+ }
+ snat_det_ses_close(dm, ses);
+
+send_reply:
+ REPLY_MACRO (VL_API_SNAT_DET_CLOSE_SESSION_OUT_REPLY);
+}
+
+static void *vl_api_snat_det_close_session_in_t_print
+(vl_api_snat_det_close_session_in_t *mp, void * handle)
+{
+ u8 * s;
+ s = format (0, "SCRIPT: snat_det_close_session_in ");
+ s = format (s, "in_addr %U in_port %d "
+ "ext_addr %U ext_port %d\n",
+ format_ip4_address, mp->in_addr, ntohs(mp->in_port),
+ format_ip4_address, mp->ext_addr, ntohs(mp->ext_port));
+
+ FINISH;
+}
+
/* List of message types that this plugin understands */
#define foreach_snat_plugin_api_msg \
_(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \
@@ -1734,7 +1833,9 @@ _(SNAT_DET_FORWARD, snat_det_forward) \
_(SNAT_DET_REVERSE, snat_det_reverse) \
_(SNAT_DET_MAP_DUMP, snat_det_map_dump) \
_(SNAT_DET_SET_TIMEOUTS, snat_det_set_timeouts) \
-_(SNAT_DET_GET_TIMEOUTS, snat_det_get_timeouts)
+_(SNAT_DET_GET_TIMEOUTS, snat_det_get_timeouts) \
+_(SNAT_DET_CLOSE_SESSION_OUT, snat_det_close_session_out) \
+_(SNAT_DET_CLOSE_SESSION_IN, snat_det_close_session_in)
/* Set up the API message handling tables */
@@ -3488,3 +3589,143 @@ VLIB_CLI_COMMAND (set_timeout_command, static) = {
"set snat deterministic timeout [udp <sec> | tcp-established <sec> "
"tcp-transitory <sec> | icmp <sec> | reset]",
};
+
+static clib_error_t *
+snat_det_close_session_out_fn (vlib_main_t *vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ snat_main_t *sm = &snat_main;
+ unformat_input_t _line_input, *line_input = &_line_input;
+ ip4_address_t out_addr, ext_addr, in_addr;
+ u16 out_port, ext_port;
+ snat_det_map_t * dm;
+ snat_det_session_t * ses;
+ snat_det_out_key_t key;
+ clib_error_t *error = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "%U:%d %U:%d",
+ unformat_ip4_address, &out_addr, &out_port,
+ unformat_ip4_address, &ext_addr, &ext_port))
+ ;
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ unformat_free (line_input);
+
+ dm = snat_det_map_by_out(sm, &out_addr);
+ if (!dm)
+ vlib_cli_output (vm, "no match");
+ else
+ {
+ snat_det_reverse(dm, &ext_addr, out_port, &in_addr);
+ key.ext_host_addr = out_addr;
+ key.ext_host_port = ntohs(ext_port);
+ key.out_port = ntohs(out_port);
+ ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
+ if (!ses)
+ vlib_cli_output (vm, "no match");
+ else
+ snat_det_ses_close(dm, ses);
+ }
+
+done:
+ unformat_free (line_input);
+
+ return error;
+}
+
+/*?
+ * @cliexpar
+ * @cliexstart{snat deterministic close session out}
+ * Close session using outside ip address and port
+ * and external ip address and port, use:
+ * vpp# snat deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
+ .path = "snat deterministic close session out",
+ .short_help = "snat deterministic close session out "
+ "<out_addr>:<out_port> <ext_addr>:<ext_port>",
+ .function = snat_det_close_session_out_fn,
+};
+
+static clib_error_t *
+snat_det_close_session_in_fn (vlib_main_t *vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ snat_main_t *sm = &snat_main;
+ unformat_input_t _line_input, *line_input = &_line_input;
+ ip4_address_t in_addr, ext_addr;
+ u16 in_port, ext_port;
+ snat_det_map_t * dm;
+ snat_det_session_t * ses;
+ snat_det_out_key_t key;
+ clib_error_t *error = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "%U:%d %U:%d",
+ unformat_ip4_address, &in_addr, &in_port,
+ unformat_ip4_address, &ext_addr, &ext_port))
+ ;
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ unformat_free (line_input);
+
+ dm = snat_det_map_by_user (sm, &in_addr);
+ if (!dm)
+ vlib_cli_output (vm, "no match");
+ else
+ {
+ key.ext_host_addr = ext_addr;
+ key.ext_host_port = ntohs (ext_port);
+ ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs(in_port), key);
+ if (!ses)
+ vlib_cli_output (vm, "no match");
+ else
+ snat_det_ses_close(dm, ses);
+ }
+
+done:
+ unformat_free(line_input);
+
+ return error;
+}
+
+/*?
+ * @cliexpar
+ * @cliexstart{snat deterministic close_session_in}
+ * Close session using inside ip address and port
+ * and external ip address and port, use:
+ * vpp# snat deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
+ .path = "snat deterministic close session in",
+ .short_help = "snat deterministic close session in "
+ "<in_addr>:<in_port> <ext_addr>:<ext_port>",
+ .function = snat_det_close_session_in_fn,
+};
diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c
index 4117d9448aa..14e8d1990b7 100644
--- a/src/plugins/snat/snat_test.c
+++ b/src/plugins/snat/snat_test.c
@@ -69,7 +69,9 @@ _(snat_set_workers_reply) \
_(snat_add_del_interface_addr_reply) \
_(snat_ipfix_enable_disable_reply) \
_(snat_add_det_map_reply) \
-_(snat_det_set_timeouts_reply)
+_(snat_det_set_timeouts_reply) \
+_(snat_det_close_session_out_reply) \
+_(snat_det_close_session_in_reply)
#define _(n) \
static void vl_api_##n##_t_handler \
@@ -115,7 +117,11 @@ _(SNAT_DET_FORWARD_REPLY, snat_det_forward_reply) \
_(SNAT_DET_REVERSE_REPLY, snat_det_reverse_reply) \
_(SNAT_DET_MAP_DETAILS, snat_det_map_details) \
_(SNAT_DET_SET_TIMEOUTS_REPLY, snat_det_set_timeouts_reply) \
-_(SNAT_DET_GET_TIMEOUTS_REPLY, snat_det_get_timeouts_reply)
+_(SNAT_DET_GET_TIMEOUTS_REPLY, snat_det_get_timeouts_reply) \
+_(SNAT_DET_CLOSE_SESSION_OUT_REPLY, \
+ snat_det_close_session_out_reply) \
+_(SNAT_DET_CLOSE_SESSION_IN_REPLY, \
+ snat_det_close_session_in_reply)
static int api_snat_add_address_range (vat_main_t * vam)
{
@@ -969,6 +975,64 @@ static int api_snat_det_get_timeouts(vat_main_t * vam)
return ret;
}
+static int api_snat_det_close_session_out (vat_main_t * vam)
+{
+ unformat_input_t * i = vam->input;
+ vl_api_snat_det_close_session_out_t * mp;
+ ip4_address_t out_addr, ext_addr;
+ u16 out_port, ext_port;
+ int ret;
+
+ if (unformat (i, "%U:%d %U:%d",
+ unformat_ip4_address, &out_addr, &out_port,
+ unformat_ip4_address, &ext_addr, &ext_port))
+ ;
+ else
+ {
+ clib_warning("unknown input '%U'", format_unformat_error, i);
+ return -99;
+ }
+
+ M(SNAT_DET_CLOSE_SESSION_OUT, mp);
+ clib_memcpy(mp->out_addr, &out_addr, 4);
+ mp->out_port = ntohs(out_port);
+ clib_memcpy(mp->ext_addr, &ext_addr, 4);
+ mp->ext_port = ntohs(ext_port);
+
+ S(mp);
+ W (ret);
+ return ret;
+}
+
+static int api_snat_det_close_session_in (vat_main_t * vam)
+{
+ unformat_input_t * i = vam->input;
+ vl_api_snat_det_close_session_in_t * mp;
+ ip4_address_t in_addr, ext_addr;
+ u16 in_port, ext_port;
+ int ret;
+
+ if (unformat (i, "%U:%d %U:%d",
+ unformat_ip4_address, &in_addr, &in_port,
+ unformat_ip4_address, &ext_addr, &ext_port))
+ ;
+ else
+ {
+ clib_warning("unknown input '%U'", format_unformat_error, i);
+ return -99;
+ }
+
+ M(SNAT_DET_CLOSE_SESSION_IN, mp);
+ clib_memcpy(mp->in_addr, &in_addr, 4);
+ mp->in_port = ntohs(in_port);
+ clib_memcpy(mp->ext_addr, &ext_addr, 4);
+ mp->ext_port = ntohs(ext_port);
+
+ S(mp);
+ W (ret);
+ return ret;
+}
+
/*
* List of messages that the api test plugin sends,
* and that the data plane plugin processes
@@ -1001,7 +1065,11 @@ _(snat_det_reverse, "<out_addr> <out_port>") \
_(snat_det_map_dump, "") \
_(snat_det_set_timeouts, "[udp <sec> | tcp_established <sec> | " \
"tcp_transitory <sec> | icmp <sec>]") \
-_(snat_det_get_timeouts, "")
+_(snat_det_get_timeouts, "") \
+_(snat_det_close_session_out, "<out_addr>:<out_port> " \
+ "<ext_addr>:<ext_port>") \
+_(snat_det_close_session_in, "<in_addr>:<in_port> " \
+ "<out_addr>:<out_port>")
static void
snat_vat_api_hookup (vat_main_t *vam)
diff --git a/test/test_snat.py b/test/test_snat.py
index ace17237b38..fe5af418aea 100644
--- a/test/test_snat.py
+++ b/test/test_snat.py
@@ -1686,6 +1686,21 @@ class TestDeterministicNAT(MethodHolder):
self.logger.error(ppp("Unexpected or invalid packet", p))
raise
+ # session close api test
+ self.vapi.snat_det_close_session_out(socket.inet_aton(nat_ip),
+ external_port1,
+ self.pg1.remote_ip4n,
+ port_out)
+ dms = self.vapi.snat_det_map_dump()
+ self.assertEqual(dms[0].ses_num, 1)
+
+ self.vapi.snat_det_close_session_in(host0.ip4n,
+ port_in,
+ self.pg1.remote_ip4n,
+ port_out)
+ dms = self.vapi.snat_det_map_dump()
+ self.assertEqual(dms[0].ses_num, 0)
+
def test_tcp_session_close_detection_in(self):
""" CGNAT TCP session close initiated from inside network """
self.vapi.snat_add_det_map(self.pg0.remote_ip4n,
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 4541f01a1bd..a485cefcf96 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1226,6 +1226,52 @@ class VppPapiProvider(object):
"""
return self.api(self.papi.snat_det_get_timeouts, {})
+ def snat_det_close_session_out(
+ self,
+ out_addr,
+ out_port,
+ ext_addr,
+ ext_port,
+ is_ip4=1):
+ """Close CGN session using outside address and port
+
+ :param out_addr - outside IP address
+ :param out_port - outside port
+ :param ext_addr - external host IP address
+ :param ext_port - external host port
+ :param is_ip4: 1 if address type is IPv4 (Default value = 1)
+ """
+ return self.api(
+ self.papi.snat_det_close_session_out,
+ {'out_addr': out_addr,
+ 'out_port': out_port,
+ 'ext_addr': ext_addr,
+ 'ext_port': ext_port,
+ 'is_ip4': is_ip4})
+
+ def snat_det_close_session_in(
+ self,
+ in_addr,
+ in_port,
+ ext_addr,
+ ext_port,
+ is_ip4=1):
+ """Close CGN session using inside address and port
+
+ :param in_addr - inside IP address
+ :param in_port - inside port
+ :param ext_addr - external host IP address
+ :param ext_port - external host port
+ :param is_ip4: 1 if address type is IPv4 (Default value = 1)
+ """
+ return self.api(
+ self.papi.snat_det_close_session_in,
+ {'in_addr': in_addr,
+ 'in_port': in_port,
+ 'ext_addr': ext_addr,
+ 'ext_port': ext_port,
+ 'is_ip4': is_ip4})
+
def control_ping(self):
self.api(self.papi.control_ping)