CGNAT: close session API and CLI commands. 76/6376/3
authorMartin Gálik <magalik@cisco.com>
Wed, 19 Apr 2017 08:12:27 +0000 (01:12 -0700)
committerMartin Gálik <magalik@cisco.com>
Wed, 26 Apr 2017 07:23:22 +0000 (00:23 -0700)
Change-Id: I9c8636bd2c4b8da2907e8e4a4f2be1a2c3a8e0bb
Signed-off-by: Martin Gálik <magalik@cisco.com>
src/plugins/snat/snat.api
src/plugins/snat/snat.c
src/plugins/snat/snat_test.c
test/test_snat.py
test/vpp_papi_provider.py

index 573b675..5990eae 100644 (file)
@@ -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;
+};
index 8569b04..594afa6 100644 (file)
@@ -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,
+};
index 4117d94..14e8d19 100644 (file)
@@ -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)
index ace1723..fe5af41 100644 (file)
@@ -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,
index 4541f01..a485cef 100644 (file)
@@ -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)