diff options
-rw-r--r-- | src/plugins/snat/snat.api | 38 | ||||
-rw-r--r-- | src/plugins/snat/snat.c | 243 | ||||
-rw-r--r-- | src/plugins/snat/snat_test.c | 74 | ||||
-rw-r--r-- | test/test_snat.py | 15 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 46 |
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) |