interface: add api test file

Type: improvement

Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
Change-Id: Ib07029204ecf12bf2adb5a39afa54bc98fb81f34
diff --git a/src/plugins/arping/arping_test.c b/src/plugins/arping/arping_test.c
index ac4349d..00b0b98 100644
--- a/src/plugins/arping/arping_test.c
+++ b/src/plugins/arping/arping_test.c
@@ -52,7 +52,6 @@
   arping_args_t args = { 0 };
   int ret;
   unformat_input_t *input = vam->input;
-  vnet_main_t *vnm = vnet_get_main ();
   f64 interval = ARPING_DEFAULT_INTERVAL;
   vl_api_control_ping_t *mp_ping;
   arping_test_main_t *atm = &arping_test_main;
@@ -76,8 +75,7 @@
       return -99;
     }
 
-  if (!unformat_user (input, unformat_vnet_sw_interface, vnm,
-		      &args.sw_if_index))
+  if (!unformat_user (input, api_unformat_sw_if_index, vam, &args.sw_if_index))
     {
       errmsg ("unknown interface `%U'", format_unformat_error, input);
       return -99;
diff --git a/src/plugins/gtpu/gtpu_test.c b/src/plugins/gtpu/gtpu_test.c
index 373e788..dcfe3d0 100644
--- a/src/plugins/gtpu/gtpu_test.c
+++ b/src/plugins/gtpu/gtpu_test.c
@@ -91,24 +91,6 @@
 }
 
 static uword
-api_unformat_sw_if_index (unformat_input_t * input, va_list * args)
-{
-  vat_main_t *vam = va_arg (*args, vat_main_t *);
-  u32 *result = va_arg (*args, u32 *);
-  u8 *if_name;
-  uword *p;
-
-  if (!unformat (input, "%s", &if_name))
-    return 0;
-
-  p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name);
-  if (p == 0)
-    return 0;
-  *result = p[0];
-  return 1;
-}
-
-static uword
 api_unformat_hw_if_index (unformat_input_t * input, va_list * args)
 {
   return 0;
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 61ac92f..a759ba2 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -57,6 +57,8 @@
 
 #include <vlibmemory/memclnt.api_enum.h>
 #include <vlibmemory/memclnt.api_types.h>
+#include <vlibmemory/memclnt.api_tojson.h>
+#include <vlibmemory/memclnt.api_fromjson.h>
 
 #define vl_endianfun		/* define message structures */
 #include <vlibmemory/memclnt.api.h>
@@ -170,23 +172,6 @@
 }
 
 #if VPP_API_TEST_BUILTIN == 0
-static uword
-api_unformat_sw_if_index (unformat_input_t * input, va_list * args)
-{
-  vat_main_t *vam = va_arg (*args, vat_main_t *);
-  u32 *result = va_arg (*args, u32 *);
-  u8 *if_name;
-  uword *p;
-
-  if (!unformat (input, "%s", &if_name))
-    return 0;
-
-  p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name);
-  if (p == 0)
-    return 0;
-  *result = p[0];
-  return 1;
-}
 
 /* Parse an IP4 address %d.%d.%d.%d. */
 uword
@@ -644,6 +629,48 @@
   return s;
 }
 
+static void
+vl_api_control_ping_reply_t_handler (vl_api_control_ping_reply_t *mp)
+{
+  vat_main_t *vam = &vat_main;
+  i32 retval = ntohl (mp->retval);
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+    }
+  else
+    {
+      vam->retval = retval;
+      vam->result_ready = 1;
+    }
+  if (vam->socket_client_main)
+    vam->socket_client_main->control_pings_outstanding--;
+}
+
+static void
+vl_api_control_ping_reply_t_handler_json (vl_api_control_ping_reply_t *mp)
+{
+  vat_main_t *vam = &vat_main;
+  i32 retval = ntohl (mp->retval);
+
+  if (VAT_JSON_NONE != vam->json_tree.type)
+    {
+      vat_json_print (vam->ofp, &vam->json_tree);
+      vat_json_free (&vam->json_tree);
+      vam->json_tree.type = VAT_JSON_NONE;
+    }
+  else
+    {
+      /* just print [] */
+      vat_json_init_array (&vam->json_tree);
+      vat_json_print (vam->ofp, &vam->json_tree);
+      vam->json_tree.type = VAT_JSON_NONE;
+    }
+
+  vam->retval = retval;
+  vam->result_ready = 1;
+}
+
 /*
  * Generate boilerplate reply handlers, which
  * dig the return value out of the xxx_reply_t API message,
@@ -693,6 +720,7 @@
 
 #define foreach_vpe_api_reply_msg                                             \
   _ (GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply)                          \
+  _ (CONTROL_PING_REPLY, control_ping_reply)
 
 #define foreach_standalone_reply_msg					\
 
@@ -706,10 +734,23 @@
     case L2_VTR_ ## op:         \
         return "" # op;
 
-int
-api_sw_interface_dump (vat_main_t *vam)
+static const char *
+str_vtr_op (u32 vtr_op)
 {
-  return 0;
+  switch (vtr_op)
+    {
+      STR_VTR_OP_CASE (DISABLED);
+      STR_VTR_OP_CASE (PUSH_1);
+      STR_VTR_OP_CASE (PUSH_2);
+      STR_VTR_OP_CASE (POP_1);
+      STR_VTR_OP_CASE (POP_2);
+      STR_VTR_OP_CASE (TRANSLATE_1_1);
+      STR_VTR_OP_CASE (TRANSLATE_1_2);
+      STR_VTR_OP_CASE (TRANSLATE_2_1);
+      STR_VTR_OP_CASE (TRANSLATE_2_2);
+    }
+
+  return "UNKNOWN";
 }
 
 uword
@@ -2299,12 +2340,10 @@
 
   print (vam->ofp, "Help is available for the following:");
 
-    /* *INDENT-OFF* */
     hash_foreach_pair (p, vam->function_by_name,
     ({
       vec_add1 (cmds, (u8 *)(p->key));
     }));
-    /* *INDENT-ON* */
 
   vec_sort_with_function (cmds, cmd_cmp);
 
@@ -2377,14 +2416,11 @@
   int i;
   hash_pair_t *p;
 
-    /* *INDENT-OFF* */
-    hash_foreach_pair (p, vam->macro_main.the_value_table_hash,
-    ({
-      vec_add2 (sort_me, sm, 1);
-      sm->name = (u8 *)(p->key);
-      sm->value = (u8 *) (p->value[0]);
-    }));
-    /* *INDENT-ON* */
+  hash_foreach_pair (p, vam->macro_main.the_value_table_hash, ({
+		       vec_add2 (sort_me, sm, 1);
+		       sm->name = (u8 *) (p->key);
+		       sm->value = (u8 *) (p->value[0]);
+		     }));
 
   vec_sort_with_function (sort_me, macro_sort_cmp);
 
@@ -2420,14 +2456,12 @@
   hash_pair_t *hp;
   int i;
 
-  /* *INDENT-OFF* */
   hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
   ({
     vec_add2 (nses, ns, 1);
     ns->name = (u8 *)(hp->key);
     ns->value = (u32) hp->value[0];
   }));
-  /* *INDENT-ON* */
 
   vec_sort_with_function (nses, value_sort_cmp);
 
@@ -2580,29 +2614,107 @@
   return -1;
 }
 
+static int
+name_sort_cmp (void *a1, void *a2)
+{
+  name_sort_t *n1 = a1;
+  name_sort_t *n2 = a2;
+
+  return strcmp ((char *) n1->name, (char *) n2->name);
+}
+
+static int
+dump_interface_table (vat_main_t *vam)
+{
+  hash_pair_t *p;
+  name_sort_t *nses = 0, *ns;
+
+  if (vam->json_output)
+    {
+      clib_warning (
+	"JSON output supported only for VPE API calls and dump_stats_table");
+      return -99;
+    }
+
+  hash_foreach_pair (p, vam->sw_if_index_by_interface_name, ({
+		       vec_add2 (nses, ns, 1);
+		       ns->name = (u8 *) (p->key);
+		       ns->value = (u32) p->value[0];
+		     }));
+
+  vec_sort_with_function (nses, name_sort_cmp);
+
+  print (vam->ofp, "%-25s%-15s", "Interface", "sw_if_index");
+  vec_foreach (ns, nses)
+    {
+      print (vam->ofp, "%-25s%-15d", ns->name, ns->value);
+    }
+  vec_free (nses);
+  return 0;
+}
+
+static int
+dump_sub_interface_table (vat_main_t *vam)
+{
+  const sw_interface_subif_t *sub = NULL;
+
+  if (vam->json_output)
+    {
+      clib_warning (
+	"JSON output supported only for VPE API calls and dump_stats_table");
+      return -99;
+    }
+
+  print (vam->ofp, "%-30s%-12s%-11s%-7s%-5s%-9s%-9s%-6s%-8s%-10s%-10s",
+	 "Interface", "sw_if_index", "sub id", "dot1ad", "tags", "outer id",
+	 "inner id", "exact", "default", "outer any", "inner any");
+
+  vec_foreach (sub, vam->sw_if_subif_table)
+    {
+      print (vam->ofp, "%-30s%-12d%-11d%-7s%-5d%-9d%-9d%-6d%-8d%-10d%-10d",
+	     sub->interface_name, sub->sw_if_index, sub->sub_id,
+	     sub->sub_dot1ad ? "dot1ad" : "dot1q", sub->sub_number_of_tags,
+	     sub->sub_outer_vlan_id, sub->sub_inner_vlan_id,
+	     sub->sub_exact_match, sub->sub_default,
+	     sub->sub_outer_vlan_id_any, sub->sub_inner_vlan_id_any);
+      if (sub->vtr_op != L2_VTR_DISABLED)
+	{
+	  print (vam->ofp,
+		 "  vlan-tag-rewrite - op: %-14s [ dot1q: %d "
+		 "tag1: %d tag2: %d ]",
+		 str_vtr_op (sub->vtr_op), sub->vtr_push_dot1q, sub->vtr_tag1,
+		 sub->vtr_tag2);
+	}
+    }
+
+  return 0;
+}
+
 /* List of API message constructors, CLI names map to api_xxx */
 #define foreach_vpe_api_msg                                             \
 _(get_first_msg_id, "client <name>")					\
 _(sock_init_shm, "size <nnn>")						\
 /* List of command functions, CLI names map directly to functions */
-#define foreach_cli_function                                    \
-_(comment, "usage: comment <ignore-rest-of-line>")		\
-_(dump_macro_table, "usage: dump_macro_table ")                 \
-_(dump_msg_api_table, "usage: dump_msg_api_table")		\
-_(elog_setup, "usage: elog_setup [nevents, default 128K]")      \
-_(elog_disable, "usage: elog_disable")                          \
-_(elog_enable, "usage: elog_enable")                            \
-_(elog_save, "usage: elog_save <filename>")                     \
-_(get_msg_id, "usage: get_msg_id name_and_crc")			\
-_(echo, "usage: echo <message>")				\
-_(help, "usage: help")                                          \
-_(q, "usage: quit")                                             \
-_(quit, "usage: quit")                                          \
-_(search_node_table, "usage: search_node_table <name>...")	\
-_(set, "usage: set <variable-name> <value>")                    \
-_(script, "usage: script <file-name>")                          \
-_(statseg, "usage: statseg")                                    \
-_(unset, "usage: unset <variable-name>")
+#define foreach_cli_function                                                  \
+  _ (comment, "usage: comment <ignore-rest-of-line>")                         \
+  _ (dump_interface_table, "usage: dump_interface_table")                     \
+  _ (dump_sub_interface_table, "usage: dump_sub_interface_table")             \
+  _ (dump_macro_table, "usage: dump_macro_table ")                            \
+  _ (dump_msg_api_table, "usage: dump_msg_api_table")                         \
+  _ (elog_setup, "usage: elog_setup [nevents, default 128K]")                 \
+  _ (elog_disable, "usage: elog_disable")                                     \
+  _ (elog_enable, "usage: elog_enable")                                       \
+  _ (elog_save, "usage: elog_save <filename>")                                \
+  _ (get_msg_id, "usage: get_msg_id name_and_crc")                            \
+  _ (echo, "usage: echo <message>")                                           \
+  _ (help, "usage: help")                                                     \
+  _ (q, "usage: quit")                                                        \
+  _ (quit, "usage: quit")                                                     \
+  _ (search_node_table, "usage: search_node_table <name>...")                 \
+  _ (set, "usage: set <variable-name> <value>")                               \
+  _ (script, "usage: script <file-name>")                                     \
+  _ (statseg, "usage: statseg")                                               \
+  _ (unset, "usage: unset <variable-name>")
 
 #define _(N,n)                                  \
     static void vl_api_##n##_t_handler_uni      \
diff --git a/src/vat/main.c b/src/vat/main.c
index c718197..d052493 100644
--- a/src/vat/main.c
+++ b/src/vat/main.c
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 #include "vat.h"
+#include <dlfcn.h>
 #include "plugin.h"
 #include <signal.h>
 #include <limits.h>
@@ -181,7 +182,7 @@
       if (vam->regenerate_interface_table)
 	{
 	  vam->regenerate_interface_table = 0;
-	  api_sw_interface_dump (vam);
+	  vam->api_sw_interface_dump (vam);
 	}
 
       /* Hack to pick up new client index after memfd_segment_create pivot */
@@ -380,6 +381,30 @@
 					    1 /* do_sort */, is_global);
 }
 
+static void
+vat_register_interface_dump (vat_main_t *vam)
+{
+  void *handle;
+  plugin_info_t *pi;
+
+  vec_foreach (pi, vat_plugin_main.plugin_info)
+    {
+      handle = dlsym (pi->handle, "api_sw_interface_dump");
+      if (handle)
+	{
+	  vam->api_sw_interface_dump = handle;
+	  break;
+	}
+    }
+
+  if (!vam->api_sw_interface_dump)
+    {
+      fformat (stderr,
+	       "sw_interface_dump not found in interface_test plugin!\n");
+      exit (1);
+    }
+}
+
 int
 main (int argc, char **argv)
 {
@@ -484,9 +509,6 @@
 
   vam->json_output = json_output;
 
-  if (!json_output)
-    api_sw_interface_dump (vam);
-
   vec_validate (vam->inbuf, 4096);
 
   load_features ();
@@ -494,6 +516,11 @@
   vam->current_file = (u8 *) "plugin-init";
   vat_plugin_init (vam);
 
+  vat_register_interface_dump (vam);
+
+  if (!json_output)
+    vam->api_sw_interface_dump (vam);
+
   /* Set up the init function hash table */
   vgm->init_functions_called = hash_create (0, 0);
 
diff --git a/src/vat/vat.h b/src/vat/vat.h
index 32de90e..10199e3 100644
--- a/src/vat/vat.h
+++ b/src/vat/vat.h
@@ -33,6 +33,8 @@
 #include <vlib/unix/unix.h>
 #include <vlibapi/api.h>
 #include <vlibmemory/api.h>
+#include <vlibmemory/memclnt.api_enum.h>
+#include <vlibmemory/memclnt.api_types.h>
 
 #include "vat/json_format.h"
 
@@ -232,6 +234,8 @@
 
   struct vat_registered_features_t *feature_function_registrations;
 
+  int (*api_sw_interface_dump) ();
+
   /* Convenience */
   vlib_main_t *vlib_main;
 } vat_main_t;
@@ -295,6 +299,25 @@
     .function = x,						       \
    }
 
+#if VPP_API_TEST_BUILTIN == 0
+static_always_inline uword
+api_unformat_sw_if_index (unformat_input_t *input, va_list *args)
+{
+  vat_main_t *vam = va_arg (*args, vat_main_t *);
+  u32 *result = va_arg (*args, u32 *);
+  u8 *if_name;
+  uword *p;
+
+  if (!unformat (input, "%s", &if_name))
+    return 0;
+
+  p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name);
+  if (p == 0)
+    return 0;
+  *result = p[0];
+  return 1;
+}
+#endif /* VPP_API_TEST_BUILTIN */
 
 #endif /* __included_vat_h__ */
 
diff --git a/src/vat2/vat2_helpers.h b/src/vat2/vat2_helpers.h
index beb2a78..7b19760 100644
--- a/src/vat2/vat2_helpers.h
+++ b/src/vat2/vat2_helpers.h
@@ -20,7 +20,7 @@
 
 /* For control ping */
 #define vl_endianfun
-#include <vlibmemory/vlib.api.h>
+#include <vlibmemory/memclnt.api.h>
 #undef vl_endianfun
 
 static inline void
diff --git a/src/vlibapi/vat_helper_macros.h b/src/vlibapi/vat_helper_macros.h
index 2e1b942..1dd597c 100644
--- a/src/vlibapi/vat_helper_macros.h
+++ b/src/vlibapi/vat_helper_macros.h
@@ -65,13 +65,16 @@
 #define PING(_tm, mp_ping)                                                    \
   do                                                                          \
     {                                                                         \
-      if (!(_tm)->ping_id)                                                    \
-	(_tm)->ping_id =                                                      \
-	  vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC));        \
-      mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));            \
-      mp_ping->_vl_msg_id = htons ((_tm)->ping_id);                           \
+      socket_client_main_t *scm = vam->socket_client_main;                    \
+      if (scm && scm->socket_enable)                                          \
+	mp_ping = vl_socket_client_msg_alloc (sizeof (*mp_ping));             \
+      else                                                                    \
+	mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping));          \
+      mp_ping->_vl_msg_id = htons (VL_API_CONTROL_PING + 1);                  \
       mp_ping->client_index = vam->my_client_index;                           \
       vam->result_ready = 0;                                                  \
+      if (scm)                                                                \
+	scm->control_pings_outstanding++;                                     \
     }                                                                         \
   while (0);
 
diff --git a/src/vlibmemory/memclnt.api b/src/vlibmemory/memclnt.api
index a5194cd..bd999b5 100644
--- a/src/vlibmemory/memclnt.api
+++ b/src/vlibmemory/memclnt.api
@@ -207,3 +207,28 @@
   u32 client_index;
   u32 context;
 };
+
+/** \brief Control ping from client to api server request
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define control_ping
+{
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Control ping from the client to the server response
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param retval - return code for the request
+    @param vpe_pid - the pid of the vpe, returned by the server
+*/
+define control_ping_reply
+{
+  u32 context;
+  i32 retval;
+  u32 client_index;
+  u32 vpe_pid;
+};
+
diff --git a/src/vlibmemory/memclnt_api.c b/src/vlibmemory/memclnt_api.c
index e7d689b..2b4a239 100644
--- a/src/vlibmemory/memclnt_api.c
+++ b/src/vlibmemory/memclnt_api.c
@@ -29,6 +29,7 @@
 #include <vlib/unix/unix.h>
 #include <vlibapi/api.h>
 #include <vlibmemory/api.h>
+#include <vlibapi/api_helper_macros.h>
 
 /**
  * @file
@@ -131,9 +132,20 @@
   vl_api_send_msg (reg, (u8 *) rmp);
 }
 
+static void
+vl_api_control_ping_t_handler (vl_api_control_ping_t *mp)
+{
+  vl_api_control_ping_reply_t *rmp;
+  int rv = 0;
+
+  REPLY_MACRO2 (VL_API_CONTROL_PING_REPLY,
+		({ rmp->vpe_pid = ntohl (getpid ()); }));
+}
+
 #define foreach_vlib_api_msg                                                  \
   _ (GET_FIRST_MSG_ID, get_first_msg_id)                                      \
-  _ (API_VERSIONS, api_versions)
+  _ (API_VERSIONS, api_versions)                                              \
+  _ (CONTROL_PING, control_ping)
 
 /*
  * vl_api_init
@@ -141,6 +153,7 @@
 static int
 vlib_api_init (void)
 {
+  api_main_t *am = vlibapi_get_main ();
   vl_msg_api_msg_config_t cfg;
   vl_msg_api_msg_config_t *c = &cfg;
 
@@ -175,6 +188,9 @@
   foreach_vlib_api_msg;
 #undef _
 
+  am->is_mp_safe[VL_API_CONTROL_PING] = 1;
+  am->is_mp_safe[VL_API_CONTROL_PING_REPLY] = 1;
+
   return 0;
 }
 
diff --git a/src/vlibmemory/vlib.api b/src/vlibmemory/vlib.api
index c017fc7..ce12368 100644
--- a/src/vlibmemory/vlib.api
+++ b/src/vlibmemory/vlib.api
@@ -243,32 +243,8 @@
   f64 f64_value;
 };
 
-/** \brief Control ping from client to api server request
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-*/
-define control_ping
-{
-  u32 client_index;
-  u32 context;
-};
-
-/** \brief Control ping from the client to the server response
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-    @param retval - return code for the request
-    @param vpe_pid - the pid of the vpe, returned by the server
-*/
-define control_ping_reply
-{
-  u32 context;
-  i32 retval;
-  u32 client_index;
-  u32 vpe_pid;
-};
-
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
  * End:
- */
\ No newline at end of file
+ */
diff --git a/src/vlibmemory/vlib_api.c b/src/vlibmemory/vlib_api.c
index 6962ea0..b598f0b 100644
--- a/src/vlibmemory/vlib_api.c
+++ b/src/vlibmemory/vlib_api.c
@@ -329,16 +329,6 @@
 		}));
 }
 
-static void
-vl_api_control_ping_t_handler (vl_api_control_ping_t *mp)
-{
-  vl_api_control_ping_reply_t *rmp;
-  int rv = 0;
-
-  REPLY_MACRO2 (VL_API_CONTROL_PING_REPLY,
-		({ rmp->vpe_pid = ntohl (getpid ()); }));
-}
-
 #include <vlibmemory/vlib.api.c>
 static clib_error_t *
 vlib_apis_hookup (vlib_main_t *vm)
@@ -351,9 +341,6 @@
   msg_id_base = setup_message_id_table ();
 
   am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;
-  am->is_mp_safe[VL_API_CONTROL_PING] = 1;
-  am->is_mp_safe[VL_API_CONTROL_PING_REPLY] = 1;
-
   return 0;
 }
 
diff --git a/src/vlibmemory/vlibapi_test.c b/src/vlibmemory/vlibapi_test.c
index c91cd79..820096a 100644
--- a/src/vlibmemory/vlibapi_test.c
+++ b/src/vlibmemory/vlibapi_test.c
@@ -449,31 +449,6 @@
   return ret;
 }
 
-static void
-vl_api_control_ping_reply_t_handler (vl_api_control_ping_reply_t *mp)
-{
-  vat_main_t *vam = &vat_main;
-  i32 retval = ntohl (mp->retval);
-  if (vam->async_mode)
-    {
-      vam->async_errors += (retval < 0);
-    }
-  else
-    {
-      vam->retval = retval;
-      vam->result_ready = 1;
-    }
-  if (vam->socket_client_main)
-    vam->socket_client_main->control_pings_outstanding--;
-}
-
-static int
-api_control_ping (vat_main_t *vam)
-{
-  // not yet implemented
-  return -1;
-}
-
 #define VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE local_setup_message_id_table
 static void
 local_setup_message_id_table (vat_main_t *vam)
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index 5e1cbc2..3b19108 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -1522,6 +1522,7 @@
 )
 
 add_vat_test_library(vnet
+  interface_test.c
   ip/ip_test.c
   arp/arp_test.c
   ip6-nd/ip6_nd_test.c
diff --git a/src/vnet/interface_test.c b/src/vnet/interface_test.c
new file mode 100644
index 0000000..4a1681f
--- /dev/null
+++ b/src/vnet/interface_test.c
@@ -0,0 +1,1170 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vppinfra/error.h>
+#include <vpp/api/types.h>
+
+#include <vnet/ip/ip_types_api.h>
+
+#define __plugin_msg_base interface_test_main.msg_id_base
+#include <vlibapi/vat_helper_macros.h>
+
+/* Declare message IDs */
+#include <vnet/format_fns.h>
+#include <vnet/interface.api_enum.h>
+#include <vnet/interface.api_types.h>
+#include <vlibmemory/vlib.api_types.h>
+#include <vlibmemory/memclnt.api_enum.h>
+
+#define vl_endianfun /* define message structures */
+#include <vnet/interface.api.h>
+#undef vl_endianfun
+
+typedef struct
+{
+  /* API message ID base */
+  u16 msg_id_base;
+  vat_main_t *vat_main;
+} interface_test_main_t;
+
+static interface_test_main_t interface_test_main;
+
+static int
+api_sw_interface_set_flags (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_set_flags_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  u8 admin_up = 0;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "admin-up"))
+	admin_up = 1;
+      else if (unformat (i, "admin-down"))
+	admin_up = 0;
+      else if (unformat (i, "%U", api_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
+	break;
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_SET_FLAGS, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->flags = ntohl ((admin_up) ? IF_STATUS_API_FLAG_ADMIN_UP : 0);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply, return the good/bad news... */
+  W (ret);
+  return ret;
+}
+
+static int
+api_hw_interface_set_mtu (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_hw_interface_set_mtu_t *mp;
+  u32 sw_if_index = ~0;
+  u32 mtu = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "mtu %d", &mtu))
+	;
+      if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	;
+      else if (unformat (i, "sw_if_index %d", &sw_if_index))
+	;
+      else
+	break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (mtu == 0)
+    {
+      errmsg ("no mtu specified");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (HW_INTERFACE_SET_MTU, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->mtu = ntohs ((u16) mtu);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_tag_add_del (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_tag_add_del_t *mp;
+  u32 sw_if_index = ~0;
+  u8 *tag = 0;
+  u8 enable = 1;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "tag %s", &tag))
+	;
+      if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	;
+      else if (unformat (i, "sw_if_index %d", &sw_if_index))
+	;
+      else if (unformat (i, "del"))
+	enable = 0;
+      else
+	break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (enable && (tag == 0))
+    {
+      errmsg ("no tag specified");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_TAG_ADD_DEL, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->is_add = enable;
+  if (enable)
+    strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
+  vec_free (tag);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_add_del_mac_address (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_mac_address_t mac = { 0 };
+  vl_api_sw_interface_add_del_mac_address_t *mp;
+  u32 sw_if_index = ~0;
+  u8 is_add = 1;
+  u8 mac_set = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	;
+      else if (unformat (i, "sw_if_index %d", &sw_if_index))
+	;
+      else if (unformat (i, "%U", unformat_vl_api_mac_address, &mac))
+	mac_set++;
+      else if (unformat (i, "del"))
+	is_add = 0;
+      else
+	break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (!mac_set)
+    {
+      errmsg ("missing MAC address");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_ADD_DEL_MAC_ADDRESS, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->is_add = is_add;
+  clib_memcpy (&mp->addr, &mac, sizeof (mac));
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static void
+vl_api_sw_interface_details_t_handler (vl_api_sw_interface_details_t *mp)
+{
+  vat_main_t *vam = &vat_main;
+  u8 *s = format (0, "%s%c", mp->interface_name, 0);
+
+  hash_set_mem (vam->sw_if_index_by_interface_name, s,
+		ntohl (mp->sw_if_index));
+
+  /* In sub interface case, fill the sub interface table entry */
+  if (mp->sw_if_index != mp->sup_sw_if_index)
+    {
+      sw_interface_subif_t *sub = NULL;
+
+      vec_add2 (vam->sw_if_subif_table, sub, 1);
+
+      vec_validate (sub->interface_name, strlen ((char *) s) + 1);
+      strncpy ((char *) sub->interface_name, (char *) s,
+	       vec_len (sub->interface_name));
+      sub->sw_if_index = ntohl (mp->sw_if_index);
+      sub->sub_id = ntohl (mp->sub_id);
+
+      sub->raw_flags = ntohl (mp->sub_if_flags & SUB_IF_API_FLAG_MASK_VNET);
+
+      sub->sub_number_of_tags = mp->sub_number_of_tags;
+      sub->sub_outer_vlan_id = ntohs (mp->sub_outer_vlan_id);
+      sub->sub_inner_vlan_id = ntohs (mp->sub_inner_vlan_id);
+
+      /* vlan tag rewrite */
+      sub->vtr_op = ntohl (mp->vtr_op);
+      sub->vtr_push_dot1q = ntohl (mp->vtr_push_dot1q);
+      sub->vtr_tag1 = ntohl (mp->vtr_tag1);
+      sub->vtr_tag2 = ntohl (mp->vtr_tag2);
+    }
+}
+
+static int
+api_sw_interface_get_mac_address (vat_main_t *vat)
+{
+  return -1;
+}
+
+static void
+vl_api_sw_interface_get_mac_address_reply_t_handler (
+  vl_api_sw_interface_get_mac_address_reply_t *mp)
+{
+}
+
+static int
+api_sw_interface_add_del_address (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_add_del_address_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  u8 is_add = 1, del_all = 0;
+  u32 address_length = 0;
+  u8 v4_address_set = 0;
+  u8 v6_address_set = 0;
+  ip4_address_t v4address;
+  ip6_address_t v6address;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "del-all"))
+	del_all = 1;
+      else if (unformat (i, "del"))
+	is_add = 0;
+      else if (unformat (i, "%U", api_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, "%U/%d", unformat_ip4_address, &v4address,
+			 &address_length))
+	v4_address_set = 1;
+      else if (unformat (i, "%U/%d", unformat_ip6_address, &v6address,
+			 &address_length))
+	v6_address_set = 1;
+      else
+	break;
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+  if (v4_address_set && v6_address_set)
+    {
+      errmsg ("both v4 and v6 addresses set");
+      return -99;
+    }
+  if (!v4_address_set && !v6_address_set && !del_all)
+    {
+      errmsg ("no addresses set");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_ADD_DEL_ADDRESS, mp);
+
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->is_add = is_add;
+  mp->del_all = del_all;
+  if (v6_address_set)
+    {
+      mp->prefix.address.af = ADDRESS_IP6;
+      clib_memcpy (mp->prefix.address.un.ip6, &v6address, sizeof (v6address));
+    }
+  else
+    {
+      mp->prefix.address.af = ADDRESS_IP4;
+      clib_memcpy (mp->prefix.address.un.ip4, &v4address, sizeof (v4address));
+    }
+  mp->prefix.len = address_length;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply, return good/bad news  */
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_get_table (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_get_table_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  u8 is_ipv6 = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_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, "ipv6"))
+	is_ipv6 = 1;
+      else
+	break;
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  M (SW_INTERFACE_GET_TABLE, mp);
+  mp->sw_if_index = htonl (sw_if_index);
+  mp->is_ipv6 = is_ipv6;
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_set_rx_mode (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_set_rx_mode_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  int ret;
+  u8 queue_id_valid = 0;
+  u32 queue_id;
+  vnet_hw_if_rx_mode mode = VNET_HW_IF_RX_MODE_UNKNOWN;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "queue %d", &queue_id))
+	queue_id_valid = 1;
+      else if (unformat (i, "polling"))
+	mode = VNET_HW_IF_RX_MODE_POLLING;
+      else if (unformat (i, "interrupt"))
+	mode = VNET_HW_IF_RX_MODE_INTERRUPT;
+      else if (unformat (i, "adaptive"))
+	mode = VNET_HW_IF_RX_MODE_ADAPTIVE;
+      else if (unformat (i, "%U", api_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
+	break;
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+  if (mode == VNET_HW_IF_RX_MODE_UNKNOWN)
+    {
+      errmsg ("missing rx-mode");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_SET_RX_MODE, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->mode = (vl_api_rx_mode_t) mode;
+  mp->queue_id_valid = queue_id_valid;
+  mp->queue_id = queue_id_valid ? ntohl (queue_id) : ~0;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply, return the good/bad news... */
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_set_unnumbered (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_set_unnumbered_t *mp;
+  u32 sw_if_index;
+  u32 unnum_sw_index = ~0;
+  u8 is_add = 1;
+  u8 sw_if_index_set = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_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, "unnum_if_index %d", &unnum_sw_index))
+	;
+      else if (unformat (i, "del"))
+	is_add = 0;
+      else
+	{
+	  clib_warning ("parse error '%U'", format_unformat_error, i);
+	  return -99;
+	}
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  M (SW_INTERFACE_SET_UNNUMBERED, mp);
+
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->unnumbered_sw_if_index = ntohl (unnum_sw_index);
+  mp->is_add = is_add;
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static void
+vl_api_sw_interface_get_table_reply_t_handler (
+  vl_api_sw_interface_get_table_reply_t *mp)
+{
+  vat_main_t *vam = interface_test_main.vat_main;
+
+  fformat (vam->ofp, "%d", ntohl (mp->vrf_id));
+
+  vam->retval = ntohl (mp->retval);
+  vam->result_ready = 1;
+}
+
+static int
+api_sw_interface_address_replace_begin (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_sw_interface_set_mac_address (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_sw_interface_set_rx_placement (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_set_rx_placement_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  int ret;
+  u8 is_main = 0;
+  u32 queue_id, thread_index;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "queue %d", &queue_id))
+	;
+      else if (unformat (i, "main"))
+	is_main = 1;
+      else if (unformat (i, "worker %d", &thread_index))
+	;
+      else if (unformat (i, "%U", api_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
+	break;
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (is_main)
+    thread_index = 0;
+  /* Construct the API message */
+  M (SW_INTERFACE_SET_RX_PLACEMENT, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->worker_id = ntohl (thread_index);
+  mp->queue_id = ntohl (queue_id);
+  mp->is_main = is_main;
+
+  /* send it... */
+  S (mp);
+  /* Wait for a reply, return the good/bad news... */
+  W (ret);
+  return ret;
+}
+
+static int
+api_interface_name_renumber (vat_main_t *vam)
+{
+  unformat_input_t *line_input = vam->input;
+  vl_api_interface_name_renumber_t *mp;
+  u32 sw_if_index = ~0;
+  u32 new_show_dev_instance = ~0;
+  int ret;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", api_unformat_sw_if_index, vam,
+		    &sw_if_index))
+	;
+      else if (unformat (line_input, "sw_if_index %d", &sw_if_index))
+	;
+      else if (unformat (line_input, "new_show_dev_instance %d",
+			 &new_show_dev_instance))
+	;
+      else
+	break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (new_show_dev_instance == ~0)
+    {
+      errmsg ("missing new_show_dev_instance");
+      return -99;
+    }
+
+  M (INTERFACE_NAME_RENUMBER, mp);
+
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->new_show_dev_instance = ntohl (new_show_dev_instance);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_delete_subif (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_delete_subif_t *mp;
+  u32 sw_if_index = ~0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	;
+      if (unformat (i, "sw_if_index %d", &sw_if_index))
+	;
+      else
+	break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing sw_if_index");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (DELETE_SUBIF, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_delete_loopback (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_delete_loopback_t *mp;
+  u32 sw_if_index = ~0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "sw_if_index %d", &sw_if_index))
+	;
+      else
+	break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing sw_if_index");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (DELETE_LOOPBACK, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_create_loopback_instance (vat_main_t *vat)
+{
+  return -1;
+}
+
+static int
+api_create_loopback (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_create_loopback_t *mp;
+  vl_api_create_loopback_instance_t *mp_lbi;
+  u8 mac_address[6];
+  u8 mac_set = 0;
+  u8 is_specified = 0;
+  u32 user_instance = 0;
+  int ret;
+
+  clib_memset (mac_address, 0, sizeof (mac_address));
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "mac %U", unformat_ethernet_address, mac_address))
+	mac_set = 1;
+      if (unformat (i, "instance %d", &user_instance))
+	is_specified = 1;
+      else
+	break;
+    }
+
+  if (is_specified)
+    {
+      M (CREATE_LOOPBACK_INSTANCE, mp_lbi);
+      mp_lbi->is_specified = is_specified;
+      if (is_specified)
+	mp_lbi->user_instance = htonl (user_instance);
+      if (mac_set)
+	clib_memcpy (mp_lbi->mac_address, mac_address, sizeof (mac_address));
+      S (mp_lbi);
+    }
+  else
+    {
+      /* Construct the API message */
+      M (CREATE_LOOPBACK, mp);
+      if (mac_set)
+	clib_memcpy (mp->mac_address, mac_address, sizeof (mac_address));
+      S (mp);
+    }
+
+  W (ret);
+  return ret;
+}
+
+static void
+vl_api_create_subif_reply_t_handler (vl_api_create_subif_reply_t *mp)
+{
+  vat_main_t *vam = interface_test_main.vat_main;
+  vam->result_ready = 1;
+}
+
+#define foreach_create_subif_bit                                              \
+  _ (no_tags)                                                                 \
+  _ (one_tag)                                                                 \
+  _ (two_tags)                                                                \
+  _ (dot1ad)                                                                  \
+  _ (exact_match)                                                             \
+  _ (default_sub)                                                             \
+  _ (outer_vlan_id_any)                                                       \
+  _ (inner_vlan_id_any)
+
+#define foreach_create_subif_flag                                             \
+  _ (0, "no_tags")                                                            \
+  _ (1, "one_tag")                                                            \
+  _ (2, "two_tags")                                                           \
+  _ (3, "dot1ad")                                                             \
+  _ (4, "exact_match")                                                        \
+  _ (5, "default_sub")                                                        \
+  _ (6, "outer_vlan_id_any")                                                  \
+  _ (7, "inner_vlan_id_any")
+
+static int
+api_create_subif (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_create_subif_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  u32 sub_id;
+  u8 sub_id_set = 0;
+  u32 __attribute__ ((unused)) no_tags = 0;
+  u32 __attribute__ ((unused)) one_tag = 0;
+  u32 __attribute__ ((unused)) two_tags = 0;
+  u32 __attribute__ ((unused)) dot1ad = 0;
+  u32 __attribute__ ((unused)) exact_match = 0;
+  u32 __attribute__ ((unused)) default_sub = 0;
+  u32 __attribute__ ((unused)) outer_vlan_id_any = 0;
+  u32 __attribute__ ((unused)) inner_vlan_id_any = 0;
+  u32 tmp;
+  u16 outer_vlan_id = 0;
+  u16 inner_vlan_id = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "sw_if_index %d", &sw_if_index))
+	sw_if_index_set = 1;
+      else if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	sw_if_index_set = 1;
+      else if (unformat (i, "sub_id %d", &sub_id))
+	sub_id_set = 1;
+      else if (unformat (i, "outer_vlan_id %d", &tmp))
+	outer_vlan_id = tmp;
+      else if (unformat (i, "inner_vlan_id %d", &tmp))
+	inner_vlan_id = tmp;
+
+#define _(a) else if (unformat (i, #a)) a = 1;
+      foreach_create_subif_bit
+#undef _
+	else
+      {
+	clib_warning ("parse error '%U'", format_unformat_error, i);
+	return -99;
+      }
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (sub_id_set == 0)
+    {
+      errmsg ("missing sub_id");
+      return -99;
+    }
+  M (CREATE_SUBIF, mp);
+
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->sub_id = ntohl (sub_id);
+
+#define _(a, b) mp->sub_if_flags |= (1 << a);
+  foreach_create_subif_flag;
+#undef _
+
+  mp->outer_vlan_id = ntohs (outer_vlan_id);
+  mp->inner_vlan_id = ntohs (inner_vlan_id);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static void
+vl_api_sw_interface_rx_placement_details_t_handler (
+  vl_api_sw_interface_rx_placement_details_t *mp)
+{
+  vat_main_t *vam = interface_test_main.vat_main;
+  u32 worker_id = ntohl (mp->worker_id);
+
+  print (vam->ofp, "\n%-11d %-11s %-6d %-5d %-9s", ntohl (mp->sw_if_index),
+	 (worker_id == 0) ? "main" : "worker", worker_id, ntohl (mp->queue_id),
+	 (mp->mode == 1) ? "polling" :
+			   ((mp->mode == 2) ? "interrupt" : "adaptive"));
+}
+
+static void
+vl_api_create_vlan_subif_reply_t_handler (vl_api_create_vlan_subif_reply_t *mp)
+{
+  vat_main_t *vam = interface_test_main.vat_main;
+  vam->result_ready = 1;
+}
+
+static void
+vl_api_create_loopback_reply_t_handler (vl_api_create_loopback_reply_t *mp)
+{
+  vat_main_t *vam = interface_test_main.vat_main;
+  vam->result_ready = 1;
+}
+
+static void
+vl_api_create_loopback_instance_reply_t_handler (
+  vl_api_create_loopback_instance_reply_t *mp)
+{
+  vat_main_t *vam = interface_test_main.vat_main;
+  vam->result_ready = 1;
+}
+
+static int
+api_create_vlan_subif (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_create_vlan_subif_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  u32 vlan_id;
+  u8 vlan_id_set = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "sw_if_index %d", &sw_if_index))
+	sw_if_index_set = 1;
+      else if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	sw_if_index_set = 1;
+      else if (unformat (i, "vlan %d", &vlan_id))
+	vlan_id_set = 1;
+      else
+	{
+	  clib_warning ("parse error '%U'", format_unformat_error, i);
+	  return -99;
+	}
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  if (vlan_id_set == 0)
+    {
+      errmsg ("missing vlan_id");
+      return -99;
+    }
+  M (CREATE_VLAN_SUBIF, mp);
+
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->vlan_id = ntohl (vlan_id);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+static int
+api_collect_detailed_interface_stats (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_sw_interface_rx_placement_dump (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_rx_placement_dump_t *mp;
+  vl_api_control_ping_t *mp_ping;
+  int ret;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+	sw_if_index_set++;
+      else if (unformat (i, "sw_if_index %d", &sw_if_index))
+	sw_if_index_set++;
+      else
+	break;
+    }
+
+  fformat (vam->ofp, "\n%-11s %-11s %-6s %-5s %-4s", "sw_if_index",
+	   "main/worker", "thread", "queue", "mode");
+
+  /* Dump Interface rx placement */
+  M (SW_INTERFACE_RX_PLACEMENT_DUMP, mp);
+
+  if (sw_if_index_set)
+    mp->sw_if_index = htonl (sw_if_index);
+  else
+    mp->sw_if_index = ~0;
+
+  S (mp);
+
+  /* Use a control ping for synchronization */
+  PING (&interface_test_main, mp_ping);
+  S (mp_ping);
+
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_clear_stats (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_clear_stats_t *mp;
+  u32 sw_if_index;
+  u8 sw_if_index_set = 0;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_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
+	break;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_CLEAR_STATS, mp);
+
+  if (sw_if_index_set == 1)
+    mp->sw_if_index = ntohl (sw_if_index);
+  else
+    mp->sw_if_index = ~0;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply, return the good/bad news... */
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_set_table (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_set_table_t *mp;
+  u32 sw_if_index, vrf_id = 0;
+  u8 sw_if_index_set = 0;
+  u8 is_ipv6 = 0;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_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, "vrf %d", &vrf_id))
+	;
+      else if (unformat (i, "ipv6"))
+	is_ipv6 = 1;
+      else
+	break;
+    }
+
+  if (sw_if_index_set == 0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_SET_TABLE, mp);
+
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->is_ipv6 = is_ipv6;
+  mp->vrf_id = ntohl (vrf_id);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_address_replace_end (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_sw_interface_set_ip_directed_broadcast (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_sw_interface_set_mtu (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_sw_interface_set_promisc (vat_main_t *vam)
+{
+  return -1;
+}
+
+static int
+api_want_interface_events (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_want_interface_events_t *mp;
+  int enable = -1;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "enable"))
+	enable = 1;
+      else if (unformat (i, "disable"))
+	enable = 0;
+      else
+	break;
+    }
+
+  if (enable == -1)
+    {
+      errmsg ("missing enable|disable");
+      return -99;
+    }
+
+  M (WANT_INTERFACE_EVENTS, mp);
+  mp->enable_disable = enable;
+
+  vam->interface_event_display = enable;
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
+typedef struct
+{
+  u8 *name;
+  u32 value;
+} name_sort_t;
+
+int
+api_sw_interface_dump (vat_main_t *vam)
+{
+  vl_api_sw_interface_dump_t *mp;
+  vl_api_control_ping_t *mp_ping;
+  hash_pair_t *p;
+  name_sort_t *nses = 0, *ns;
+  sw_interface_subif_t *sub = NULL;
+  int ret;
+
+  /* Toss the old name table */
+  hash_foreach_pair (p, vam->sw_if_index_by_interface_name, ({
+		       vec_add2 (nses, ns, 1);
+		       ns->name = (u8 *) (p->key);
+		       ns->value = (u32) p->value[0];
+		     }));
+
+  hash_free (vam->sw_if_index_by_interface_name);
+
+  vec_foreach (ns, nses)
+    vec_free (ns->name);
+
+  vec_free (nses);
+
+  vec_foreach (sub, vam->sw_if_subif_table)
+    {
+      vec_free (sub->interface_name);
+    }
+  vec_free (vam->sw_if_subif_table);
+
+  /* recreate the interface name hash table */
+  vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
+
+  /*
+   * Ask for all interface names. Otherwise, the epic catalog of
+   * name filters becomes ridiculously long, and vat ends up needing
+   * to be taught about new interface types.
+   */
+  M (SW_INTERFACE_DUMP, mp);
+  S (mp);
+
+  /* Use a control ping for synchronization */
+  PING (&interface_test_main, mp_ping);
+  S (mp_ping);
+
+  W (ret);
+  return ret;
+}
+
+static int
+api_sw_interface_set_interface_name (vat_main_t *vam)
+{
+  return -1;
+}
+
+#include <vnet/interface.api_test.c>
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/ip/ip_test.c b/src/vnet/ip/ip_test.c
index 3ba38d3..c47cd3d 100644
--- a/src/vnet/ip/ip_test.c
+++ b/src/vnet/ip/ip_test.c
@@ -40,7 +40,6 @@
 {
   /* API message ID base */
   u16 msg_id_base;
-  u32 ping_id;
   vat_main_t *vat_main;
 } ip_test_main_t;
 
@@ -100,7 +99,7 @@
 static uword
 unformat_fib_path (unformat_input_t *input, va_list *args)
 {
-  vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
+  vat_main_t *vam = va_arg (*args, vat_main_t *);
   vl_api_fib_path_t *path = va_arg (*args, vl_api_fib_path_t *);
   u32 weight, preference;
   mpls_label_t out_label;
@@ -114,14 +113,14 @@
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "%U %U", unformat_vl_api_ip4_address,
-		    &path->nh.address.ip4, unformat_vnet_sw_interface, vnm,
+		    &path->nh.address.ip4, api_unformat_sw_if_index, vam,
 		    &path->sw_if_index))
 	{
 	  path->proto = FIB_API_PATH_NH_PROTO_IP4;
 	}
       else if (unformat (input, "%U %U", unformat_vl_api_ip6_address,
-			 &path->nh.address.ip6, unformat_vnet_sw_interface,
-			 vnm, &path->sw_if_index))
+			 &path->nh.address.ip6, api_unformat_sw_if_index, vam,
+			 &path->sw_if_index))
 	{
 	  path->proto = FIB_API_PATH_NH_PROTO_IP6;
 	}
@@ -238,7 +237,6 @@
 static int
 api_ip_route_add_del (vat_main_t *vam)
 {
-  vnet_main_t *vnm = vnet_get_main ();
   unformat_input_t *i = vam->input;
   vl_api_ip_route_add_del_t *mp;
   u32 vrf_id = 0;
@@ -274,7 +272,7 @@
 	is_multipath = 1;
       else if (unformat (i, "seed %d", &random_seed))
 	;
-      else if (unformat (i, "via %U", unformat_fib_path, vnm,
+      else if (unformat (i, "via %U", unformat_fib_path, vam,
 			 &paths[path_count]))
 	{
 	  path_count++;
@@ -704,7 +702,6 @@
 static int
 api_ip_address_dump (vat_main_t *vam)
 {
-  vnet_main_t *vnm = vnet_get_main ();
   unformat_input_t *i = vam->input;
   vl_api_ip_address_dump_t *mp;
   vl_api_control_ping_t *mp_ping;
@@ -718,8 +715,7 @@
     {
       if (unformat (i, "sw_if_index %d", &sw_if_index))
 	sw_if_index_set = 1;
-      else if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
-			 &sw_if_index))
+      else if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
 	sw_if_index_set = 1;
       else if (unformat (i, "ipv4"))
 	ipv4_set = 1;
@@ -1022,7 +1018,6 @@
 int
 api_ip_source_and_port_range_check_interface_add_del (vat_main_t *vam)
 {
-  vnet_main_t *vnm = vnet_get_main ();
   unformat_input_t *input = vam->input;
   vl_api_ip_source_and_port_range_check_interface_add_del_t *mp;
   u32 sw_if_index = ~0;
@@ -1034,8 +1029,7 @@
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
-		    &sw_if_index))
+      if (unformat (input, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
 	;
       else if (unformat (input, "sw_if_index %d", &sw_if_index))
 	;
@@ -1214,7 +1208,6 @@
 static int
 api_sw_interface_ip6_enable_disable (vat_main_t *vam)
 {
-  vnet_main_t *vnm = vnet_get_main ();
   unformat_input_t *i = vam->input;
   vl_api_sw_interface_ip6_enable_disable_t *mp;
   u32 sw_if_index;
@@ -1224,7 +1217,7 @@
 
   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (i, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
+      if (unformat (i, "%U", api_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;
diff --git a/src/vpp-api/client/test.c b/src/vpp-api/client/test.c
index b7e6f01..9855ffa 100644
--- a/src/vpp-api/client/test.c
+++ b/src/vpp-api/client/test.c
@@ -38,6 +38,8 @@
 
 #include <vlibmemory/vlib.api_enum.h>
 #include <vlibmemory/vlib.api_types.h>
+#include <vlibmemory/memclnt.api_enum.h>
+#include <vlibmemory/memclnt.api_types.h>
 
 #include <vpp/api/vpe.api_enum.h>
 #include <vpp/api/vpe.api_types.h>
diff --git a/src/vpp-api/vapi/vapi.c b/src/vpp-api/vapi/vapi.c
index 1bd8e5b..513ff98 100644
--- a/src/vpp-api/vapi/vapi.c
+++ b/src/vpp-api/vapi/vapi.c
@@ -31,8 +31,8 @@
 #include <vlibapi/api_common.h>
 #include <vlibmemory/memory_client.h>
 
-#include <vapi/vlib.api.vapi.h>
 #include <vapi/memclnt.api.vapi.h>
+#include <vapi/vlib.api.vapi.h>
 
 /* we need to use control pings for some stuff and because we're forced to put
  * the code in headers, we need a way to be able to grab the ids of these
diff --git a/src/vpp-api/vapi/vapi_c_gen.py b/src/vpp-api/vapi/vapi_c_gen.py
index eacfab4..1a5665e 100755
--- a/src/vpp-api/vapi/vapi_c_gen.py
+++ b/src/vpp-api/vapi/vapi_c_gen.py
@@ -705,7 +705,7 @@
     print("#ifdef __cplusplus")
     print("extern \"C\" {")
     print("#endif")
-    if name == "vlib.api.vapi.h":
+    if name == "memclnt.api.vapi.h":
         print("")
         print("static inline vapi_error_e vapi_send_with_control_ping "
               "(vapi_ctx_t ctx, void * msg, u32 context);")
diff --git a/src/vpp-api/vapi/vapi_c_test.c b/src/vpp-api/vapi/vapi_c_test.c
index 52b930d..85fc8b3 100644
--- a/src/vpp-api/vapi/vapi_c_test.c
+++ b/src/vpp-api/vapi/vapi_c_test.c
@@ -24,6 +24,8 @@
 #include <check.h>
 #include <vppinfra/string.h>
 #include <vapi/vapi.h>
+#include <vapi/memclnt.api.vapi.h>
+#include <vapi/vlib.api.vapi.h>
 #include <vapi/vpe.api.vapi.h>
 #include <vapi/interface.api.vapi.h>
 #include <vapi/l2.api.vapi.h>
diff --git a/src/vpp-api/vapi/vapi_cpp_test.cpp b/src/vpp-api/vapi/vapi_cpp_test.cpp
index c574dd7..c0e0cdc 100644
--- a/src/vpp-api/vapi/vapi_cpp_test.cpp
+++ b/src/vpp-api/vapi/vapi_cpp_test.cpp
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <setjmp.h>
 #include <check.h>
+#include <vapi/memclnt.api.vapi.h>
 #include <vapi/vapi.hpp>
 #include <vapi/vpe.api.vapi.hpp>
 #include <vapi/interface.api.vapi.hpp>
diff --git a/src/vpp/api/api_main.c b/src/vpp/api/api_main.c
index 97dec9e..9b915ee 100644
--- a/src/vpp/api/api_main.c
+++ b/src/vpp/api/api_main.c
@@ -1,4 +1,6 @@
 #include "vat.h"
+#include <dlfcn.h>
+#include <vat/plugin.h>
 
 vat_main_t vat_main;
 
@@ -94,6 +96,30 @@
 }
 
 static void
+vat_register_interface_dump (vat_main_t *vam)
+{
+  void *handle;
+  plugin_info_t *pi;
+
+  vec_foreach (pi, vat_plugin_main.plugin_info)
+    {
+      handle = dlsym (pi->handle, "api_sw_interface_dump");
+      if (handle)
+	{
+	  vam->api_sw_interface_dump = handle;
+	  break;
+	}
+    }
+
+  if (!vam->api_sw_interface_dump)
+    {
+      fformat (stderr,
+	       "sw_interface_dump not found in interface_test plugin!\n");
+      exit (1);
+    }
+}
+
+static void
 maybe_register_api_client (vat_main_t * vam)
 {
   vl_api_registration_t **regpp;
@@ -130,7 +156,8 @@
      am->shmem_hdr->application_restarts);
 
   vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
-  api_sw_interface_dump (vam);
+  vat_register_interface_dump (vam);
+  vam->api_sw_interface_dump (vam);
 }
 
 static clib_error_t *
@@ -234,7 +261,7 @@
   if (vam->regenerate_interface_table)
     {
       vam->regenerate_interface_table = 0;
-      api_sw_interface_dump (vam);
+      vam->api_sw_interface_dump (vam);
     }
   unformat_free (vam->input);
   return 0;