VPP-453: SNAT delete and dump addresses 40/3240/3
authorMatus Fabian <matfabia@cisco.com>
Tue, 4 Oct 2016 10:23:43 +0000 (03:23 -0700)
committerOle Trøan <otroan@employees.org>
Thu, 13 Oct 2016 09:52:07 +0000 (09:52 +0000)
Delete operation for SNAT addresses
Dump API for SNAT addresses

Change-Id: I84e888d20286ec2523fbd4ca7e68e3eef5927984
Signed-off-by: Matus Fabian <matfabia@cisco.com>
plugins/snat-plugin/snat/snat.api
plugins/snat-plugin/snat/snat.c
plugins/snat-plugin/snat/snat_test.c

index daacf9f..b2a21cf 100644 (file)
  * called through a shared memory interface.
  */
 
-/** \brief Add S-NAT address range
+/** \brief Add/del S-NAT address range
     @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
 */
 define snat_add_address_range {
   u32 client_index;
@@ -33,6 +34,7 @@ define snat_add_address_range {
   u8 is_ip4;
   u8 first_ip_address[16];
   u8 last_ip_address[16];
+  u8 is_add;
 };
 
 /** \brief Add S-NAT address range reply
@@ -45,6 +47,26 @@ define snat_add_address_range_reply {
   i32 retval;
 };
 
+/** \brief Dump S-NAT addresses
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define snat_address_dump {
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief S-NAT address details response
+    @param context - sender context, to match reply w/ request
+    @param is_ip4 - 1 if address type is IPv4
+    @param ip_address - IP address
+*/
+define snat_address_details {
+  u32 context;
+  u8 is_ip4;
+  u8 ip_address[16];
+};
+
 /** \brief Enable/disable S-NAT feature on the interface
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
index 3fd9ecb..8360db5 100644 (file)
@@ -207,6 +207,84 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr)
 
 }
 
+static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
+                                                   ip4_address_t addr)
+{
+  snat_static_mapping_t *m;
+  pool_foreach (m, sm->static_mappings,
+  ({
+      if (m->external_addr.as_u32 == addr.as_u32)
+        return 1;
+  }));
+
+  return 0;
+}
+
+int snat_del_address (snat_main_t *sm, ip4_address_t addr)
+{
+  clib_warning("%U", format_ip4_address, &addr);
+  snat_address_t *a = 0;
+  snat_session_t *ses;
+  u32 *ses_to_be_removed = 0, *ses_index;
+  clib_bihash_kv_8_8_t kv, value;
+  snat_user_key_t user_key;
+  snat_user_t *u;
+
+  int i;
+
+  /* Find SNAT address */
+  for (i=0; i < vec_len (sm->addresses); i++)
+    {
+      if (sm->addresses[i].addr.as_u32 == addr.as_u32)
+        {
+          a = sm->addresses + i;
+          break;
+        }
+    }
+  if (!a)
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+  /* Check if address is used in some static mapping */
+  if (is_snat_address_used_in_static_mapping(sm, addr))
+    {
+      clib_warning ("address used in static mapping");
+      return VNET_API_ERROR_UNSPECIFIED;
+    }
+
+  /* Delete sessions using address */
+  if (a->busy_ports)
+    {
+      pool_foreach (ses, sm->sessions, ({
+        if (ses->out2in.addr.as_u32 == addr.as_u32)
+          {
+            vec_add1 (ses_to_be_removed, ses - sm->sessions);
+            kv.key = ses->in2out.as_u64;
+            clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
+            kv.key = ses->out2in.as_u64;
+            clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
+            clib_dlist_remove (sm->list_pool, ses->per_user_index);
+            user_key.addr = ses->in2out.addr;
+            user_key.fib_index = ses->in2out.fib_index;
+            kv.key = user_key.as_u64;
+            if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
+              {
+                u = pool_elt_at_index (sm->users, value.value);
+                u->nsessions--;
+              }
+          }
+      }));
+
+      vec_foreach (ses_index, ses_to_be_removed)
+        pool_put_index (sm->sessions, ses_index[0]);
+
+      vec_free (ses_to_be_removed);
+    }
+
+  vec_del1 (sm->addresses, i);
+
+  return 0;
+}
+
 static void increment_v4_address (ip4_address_t * a)
 {
   u32 v;
@@ -490,7 +568,14 @@ vl_api_snat_add_address_range_t_handler
 
   for (i = 0; i < count; i++)
     {
-      snat_add_address (sm, &this_addr);
+      if (mp->is_add)
+        snat_add_address (sm, &this_addr);
+      else
+        rv = snat_del_address (sm, this_addr);
+
+      if (rv)
+        goto send_reply;
+
       increment_v4_address (&this_addr);
     }
 
@@ -512,6 +597,49 @@ static void *vl_api_snat_add_address_range_t_print
   FINISH;
 }
 
+static void
+send_snat_address_details
+(snat_address_t * a, unix_shared_memory_queue_t * q, u32 context)
+{
+  vl_api_snat_address_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_ADDRESS_DETAILS+sm->msg_id_base);
+  rmp->is_ip4 = 1;
+  clib_memcpy (rmp->ip_address, &(a->addr), 4);
+  rmp->context = context;
+
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_snat_address_dump_t_handler
+(vl_api_snat_address_dump_t * mp)
+{
+  unix_shared_memory_queue_t *q;
+  snat_main_t * sm = &snat_main;
+  snat_address_t * a;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (q == 0)
+    return;
+
+  vec_foreach (a, sm->addresses)
+    send_snat_address_details (a, q, mp->context);
+}
+
+static void *vl_api_snat_address_dump_t_print
+(vl_api_snat_address_dump_t *mp, void * handle)
+{
+  u8 *s;
+
+  s = format (0, "SCRIPT: snat_address_dump ");
+
+  FINISH;
+}
+
 static void
 vl_api_snat_interface_add_del_feature_t_handler
 (vl_api_snat_interface_add_del_feature_t * mp)
@@ -735,7 +863,8 @@ _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature)       \
 _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping)                     \
 _(SNAT_CONTROL_PING, snat_control_ping)                                 \
 _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump)                   \
-_(SNAT_SHOW_CONFIG, snat_show_config)
+_(SNAT_SHOW_CONFIG, snat_show_config)                                   \
+_(SNAT_ADDRESS_DUMP, snat_address_dump)
 
 /* Set up the API message handling tables */
 static clib_error_t *
@@ -921,20 +1050,27 @@ add_address_command_fn (vlib_main_t * vm,
   ip4_address_t start_addr, end_addr, this_addr;
   u32 start_host_order, end_host_order;
   int i, count;
+  int is_add = 1;
+  int rv = 0;
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
     return 0;
 
-  if (unformat (line_input, "%U - %U",
-                unformat_ip4_address, &start_addr,
-                unformat_ip4_address, &end_addr))
-    ;
-  else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
-    end_addr = start_addr;
-  else
-    return clib_error_return (0, "unknown input '%U'", format_unformat_error,
-      input);
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U - %U",
+                    unformat_ip4_address, &start_addr,
+                    unformat_ip4_address, &end_addr))
+        ;
+      else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
+        end_addr = start_addr;
+      else if (unformat (line_input, "del"))
+        is_add = 0;
+      else
+        return clib_error_return (0, "unknown input '%U'",
+          format_unformat_error, input);
+     }
   unformat_free (line_input);
 
   if (sm->static_mapping_only)
@@ -958,7 +1094,23 @@ add_address_command_fn (vlib_main_t * vm,
 
   for (i = 0; i < count; i++)
     {
-      snat_add_address (sm, &this_addr);
+      if (is_add)
+        snat_add_address (sm, &this_addr);
+      else
+        rv = snat_del_address (sm, this_addr);
+
+      switch (rv)
+        {
+        case VNET_API_ERROR_NO_SUCH_ENTRY:
+          return clib_error_return (0, "S-NAT address not exist.");
+          break;
+        case VNET_API_ERROR_UNSPECIFIED:
+          return clib_error_return (0, "S-NAT address used in static mapping.");
+          break;
+        default:
+          break;
+        }
+
       increment_v4_address (&this_addr);
     }
 
@@ -967,7 +1119,7 @@ add_address_command_fn (vlib_main_t * vm,
 
 VLIB_CLI_COMMAND (add_address_command, static) = {
   .path = "snat add address",
-  .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>]",
+  .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
   .function = add_address_command_fn,
 };
 
index 453c63f..29577e9 100644 (file)
@@ -89,7 +89,8 @@ _(SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY,                         \
 _(SNAT_ADD_STATIC_MAPPING_REPLY, snat_add_static_mapping_reply) \
 _(SNAT_CONTROL_PING_REPLY, snat_control_ping_reply)             \
 _(SNAT_STATIC_MAPPING_DETAILS, snat_static_mapping_details)     \
-_(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply)
+_(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply)               \
+_(SNAT_ADDRESS_DETAILS, snat_address_details)
 
 /* M: construct, but don't yet send a message */
 #define M(T,t)                                                  \
@@ -134,18 +135,24 @@ static int api_snat_add_address_range (vat_main_t * vam)
   ip4_address_t start_addr, end_addr;
   u32 start_host_order, end_host_order;
   vl_api_snat_add_address_range_t * mp;
+  u8 is_add = 1;
   int count;
 
-  if (unformat (i, "%U - %U", 
-                unformat_ip4_address, &start_addr,
-                unformat_ip4_address, &end_addr))
-    ;
-  else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
-    end_addr = start_addr;
-  else
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     {
-      clib_warning("unknown input '%U'", format_unformat_error, i);
-      return -99;
+      if (unformat (i, "%U - %U",
+                    unformat_ip4_address, &start_addr,
+                    unformat_ip4_address, &end_addr))
+        ;
+      else if (unformat (i, "%U", unformat_ip4_address, &start_addr))
+        end_addr = start_addr;
+      else if (unformat (i, "del"))
+        is_add = 0;
+      else
+        {
+          clib_warning("unknown input '%U'", format_unformat_error, i);
+          return -99;
+        }
     }
 
   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
@@ -172,6 +179,7 @@ static int api_snat_add_address_range (vat_main_t * vam)
   memcpy (mp->first_ip_address, &start_addr, 4);
   memcpy (mp->last_ip_address, &end_addr, 4);
   mp->is_ip4 = 1;
+  mp->is_add = is_add;
 
   S; W;
 
@@ -395,18 +403,53 @@ static int api_snat_show_config(vat_main_t * vam)
   return 0;
 }
 
+static void vl_api_snat_address_details_t_handler
+  (vl_api_snat_address_details_t *mp)
+{
+  snat_test_main_t * sm = &snat_test_main;
+  vat_main_t *vam = sm->vat_main;
+
+  fformat (vam->ofp, "%U\n", format_ip4_address, &mp->ip_address);
+}
+
+static int api_snat_address_dump(vat_main_t * vam)
+{
+  snat_test_main_t * sm = &snat_test_main;
+  f64 timeout;
+  vl_api_snat_address_dump_t * mp;
+
+  if (vam->json_output)
+    {
+      clib_warning ("JSON output not supported for snat_address_dump");
+      return -99;
+    }
+
+  M(SNAT_ADDRESS_DUMP, snat_address_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
  */
 #define foreach_vpe_api_msg                                      \
-_(snat_add_address_range, "<start-addr> [- <end-addr]")          \
+_(snat_add_address_range, "<start-addr> [- <end-addr] [del]")    \
 _(snat_interface_add_del_feature,                                \
   "<intfc> | sw_if_index <id> [in] [out] [del]")                 \
 _(snat_add_static_mapping, "local_addr <ip> external_addr <ip> " \
   "[local_port <n>] [external_port <n>] [vrf <table-id>] [del]") \
 _(snat_static_mapping_dump, "")                                  \
-_(snat_show_config, "")
+_(snat_show_config, "")                                          \
+_(snat_address_dump, "")
 
 void vat_api_hookup (vat_main_t *vam)
 {