Add ILA API and API test plugin VPP-412 00/2900/4
authorPierre Pfister <ppfister@cisco.com>
Thu, 15 Sep 2016 12:45:31 +0000 (13:45 +0100)
committerKeith Burns <alagalah@gmail.com>
Fri, 16 Sep 2016 16:25:23 +0000 (16:25 +0000)
The ILA plugin could only be configured through CLI.
This patch adds API support to ila_interface and
ila_add_del_entry functions.
The patch also adds a test plugin for vpp_api_test.

Change-Id: I35d96c4e56bb32862cd08cc86a9fa25ff56ef583
Signed-off-by: Pierre Pfister <ppfister@cisco.com>
plugins/ila-plugin/Makefile.am
plugins/ila-plugin/ila/ila.api [new file with mode: 0644]
plugins/ila-plugin/ila/ila.c
plugins/ila-plugin/ila/ila.h
plugins/ila-plugin/ila/ila_api.c [new file with mode: 0644]
plugins/ila-plugin/ila/ila_api_test.c [new file with mode: 0644]

index fe785df..ebf1b9b 100644 (file)
@@ -16,14 +16,27 @@ AUTOMAKE_OPTIONS = foreign subdir-objects
 AM_CFLAGS = -Wall
 AM_LDFLAGS = -module -shared -avoid-version
 
+vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins
 vpppluginsdir = ${libdir}/vpp_plugins
 
+vppapitestplugins_LTLIBRARIES = ila_test_plugin.la
 vppplugins_LTLIBRARIES = ila_plugin.la
 
-ila_plugin_la_SOURCES = ila/ila.c
+ila_plugin_la_SOURCES = ila/ila.c ila/ila_api.c
 
-noinst_HEADERS = ila/ila.h
+SUFFIXES = .api.h .api
+
+%.api.h: %.api
+       mkdir -p `dirname $@` ; \
+       $(CC) $(CPPFLAGS) -E -P -C -x c $^ \
+       | vppapigen --input - --output $@ --show-name $@
+
+noinst_HEADERS = ila/ila.h ila/ila.api.h
+
+ila_test_plugin_la_SOURCES = \
+  ila/ila_api_test.c
 
 # Remove *.la files
 install-data-hook:
        @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES))
+       @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES))
diff --git a/plugins/ila-plugin/ila/ila.api b/plugins/ila-plugin/ila/ila.api
new file mode 100644 (file)
index 0000000..9315fbb
--- /dev/null
@@ -0,0 +1,62 @@
+/** \brief Enable ILA processing of SIR-to-ILA packets on a given interface.
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param sw_if_index - The software interface index.
+    @param enable - Enable if not null, disable otherwise.
+*/
+define ila_iface
+{
+  u32 client_index;
+  u32 context;
+  u32 sw_if_index;
+  u8 enable;
+};
+
+define ila_iface_reply {
+  u32 context;
+  i32 retval;
+};
+
+/** \brief Add or delete an ILA entry.
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param type - The ILA type to be used.
+      Supported values:
+        0: Interface Identifier (iid)
+        1: Locally Unique Identifier (luid) 
+        3: IPv6 Virtual Network Identifier (vnid-ip6)
+        4: Multicast Virtual Network Identifier (vnid-multicast) 
+    @param sir_address - Standard Identifier Representation address which uniquely
+      identifies the ILA entry.
+    @param local_adj_index - The local FIB index if the entry is a local entry,
+      ~0 if the entry is not local (only used to translate from SIR to ILA).
+    @param csum_mode - The checksum mode for this entry.
+      Supported values:
+        0: No action
+        1: Neutral Mapping
+        2: Adjust for Transport Layer
+    @param dir - The translation direction
+      Supported values:
+        0: Bidirection
+        1: SIR to ILA only
+        2: ILA to SIR only
+    @param is_del - Whether the entry with the given SIR address should be deleted.
+*/
+define ila_add_del_entry {
+  u32 client_index;
+  u32 context;
+  u8 type;
+  u8 sir_address[16];
+  u64 locator;
+  u32 vnid;
+  u32 local_adj_index;
+  u8 csum_mode;
+  u8 dir;
+  u8 is_del;
+};
+
+define ila_add_del_entry_reply {
+  u32 context;
+  i32 retval;
+};
+
index 2673c62..b834880 100644 (file)
@@ -25,7 +25,8 @@ static ila_main_t ila_main;
 #define foreach_ila_error \
  _(NONE, "valid ILA packets")
 
-typedef enum {
+typedef enum
+{
 #define _(sym,str) ILA_ERROR_##sym,
   foreach_ila_error
 #undef _
@@ -38,13 +39,15 @@ static char *ila_error_strings[] = {
 #undef _
 };
 
-typedef enum {
+typedef enum
+{
   ILA_ILA2SIR_NEXT_IP6_REWRITE,
   ILA_ILA2SIR_NEXT_DROP,
   ILA_ILA2SIR_N_NEXT,
 } ila_ila2sir_next_t;
 
-typedef struct {
+typedef struct
+{
   u32 ila_index;
   ip6_address_t initial_dst;
   u32 adj_index;
@@ -53,7 +56,7 @@ typedef struct {
 static ila_entry_t ila_sir2ila_default_entry = {
   .csum_mode = ILA_CSUM_MODE_NO_ACTION,
   .type = ILA_TYPE_IID,
-  .dir = ILA_DIR_ILA2SIR, //Will pass the packet with no
+  .dir = ILA_DIR_ILA2SIR,      //Will pass the packet with no
 };
 
 u8 *
@@ -78,8 +81,8 @@ format_ila_direction (u8 * s, va_list * args)
     return format (s, "invalid_ila_direction");
 }
 
-static u8 *
-format_csum_mode (u8 * s, va_list * va)
+u8 *
+format_ila_csum_mode (u8 * s, va_list * va)
 {
   ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t);
   char *txt;
@@ -119,8 +122,9 @@ format_ila_entry (u8 * s, va_list * va)
 
   if (!e)
     {
-      return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address",
-                    "ILA Address", "Adjacency Index", "Checksum Mode", "Direction");
+      return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type",
+                    "SIR Address", "ILA Address", "Adjacency Index",
+                    "Checksum Mode", "Direction");
 
     }
   else if (vnm)
@@ -131,7 +135,7 @@ format_ila_entry (u8 * s, va_list * va)
                         format_ila_type, e->type,
                         format_ip6_address, &e->sir_address,
                         format_ip6_address, &e->ila_address,
-                        "n/a", format_csum_mode, e->csum_mode,
+                        "n/a", format_ila_csum_mode, e->csum_mode,
                         format_ila_direction, e->dir);
        }
       else
@@ -140,7 +144,7 @@ format_ila_entry (u8 * s, va_list * va)
                         format_ila_type, e->type,
                         format_ip6_address, &e->sir_address,
                         format_ip6_address, &e->ila_address,
-                        e->ila_adj_index, format_csum_mode, e->csum_mode,
+                        e->ila_adj_index, format_ila_csum_mode, e->csum_mode,
                         format_ila_direction, e->dir);
        }
     }
@@ -314,8 +318,10 @@ ila_ila2sir (vlib_main_t * vm,
              tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
            }
 
-         sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0;
-         sir_address1 = (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1;
+         sir_address0 =
+           (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0;
+         sir_address1 =
+           (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1;
          ip60->dst_address.as_u64[0] = sir_address0->as_u64[0];
          ip60->dst_address.as_u64[1] = sir_address0->as_u64[1];
          ip61->dst_address.as_u64[0] = sir_address1->as_u64[0];
@@ -364,7 +370,8 @@ ila_ila2sir (vlib_main_t * vm,
              tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
            }
 
-         sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0;
+         sir_address0 =
+           (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0;
          ip60->dst_address.as_u64[0] = sir_address0->as_u64[0];
          ip60->dst_address.as_u64[1] = sir_address0->as_u64[1];
          vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_adj_index;
@@ -478,24 +485,31 @@ ila_sir2ila (vlib_main_t * vm,
          kv1.key[1] = ip61->dst_address.as_u64[1];
          kv1.key[2] = 0;
 
-         if (PREDICT_TRUE((BV (clib_bihash_search)
-             (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) {
+         if (PREDICT_TRUE ((BV (clib_bihash_search)
+                            (&ilm->id_to_entry_table, &kv0, &value0)) == 0))
+           {
              ie0 = &ilm->entries[value0.value];
-             ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0;
-         }
+             ila_address0 =
+               (ie0->dir !=
+                ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0;
+           }
 
          if ((BV (clib_bihash_search)
-              (&ilm->id_to_entry_table, &kv1, &value1)) == 0) {
-           ie1 = &ilm->entries[value1.value];
-           ila_address1 = (ie1->dir != ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1;
-         }
+              (&ilm->id_to_entry_table, &kv1, &value1)) == 0)
+           {
+             ie1 = &ilm->entries[value1.value];
+             ila_address1 =
+               (ie1->dir !=
+                ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1;
+           }
 
          if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
            {
              ila_sir2ila_trace_t *tr =
                vlib_add_trace (vm, node, p0, sizeof (*tr));
              tr->ila_index =
-               (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0;
+               (ie0 !=
+                &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0;
              tr->initial_dst = ip60->dst_address;
            }
 
@@ -504,7 +518,8 @@ ila_sir2ila (vlib_main_t * vm,
              ila_sir2ila_trace_t *tr =
                vlib_add_trace (vm, node, p1, sizeof (*tr));
              tr->ila_index =
-               (ie1 != &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0;
+               (ie1 !=
+                &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0;
              tr->initial_dst = ip61->dst_address;
            }
 
@@ -549,18 +564,22 @@ ila_sir2ila (vlib_main_t * vm,
          kv0.key[1] = ip60->dst_address.as_u64[1];
          kv0.key[2] = 0;
 
-         if (PREDICT_TRUE((BV (clib_bihash_search)
-              (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) {
-           ie0 = &ilm->entries[value0.value];
-           ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0;
-         }
+         if (PREDICT_TRUE ((BV (clib_bihash_search)
+                            (&ilm->id_to_entry_table, &kv0, &value0)) == 0))
+           {
+             ie0 = &ilm->entries[value0.value];
+             ila_address0 =
+               (ie0->dir !=
+                ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0;
+           }
 
          if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
            {
              ila_sir2ila_trace_t *tr =
                vlib_add_trace (vm, node, p0, sizeof (*tr));
              tr->ila_index =
-               (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0;
+               (ie0 !=
+                &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0;
              tr->initial_dst = ip60->dst_address;
            }
 
@@ -637,6 +656,17 @@ ila_add_del_entry (ila_add_del_entry_args_t * args)
 
   if (!args->is_del)
     {
+      kv.key[0] = args->sir_address.as_u64[0];
+      kv.key[1] = args->sir_address.as_u64[1];
+      kv.key[2] = 0;
+
+      if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) >=
+          0))
+       {
+         clib_warning ("Entry already exists");
+         return -1;
+       }
+
       ila_entry_t *e;
       pool_get (ilm->entries, e);
       e->type = args->type;
@@ -690,9 +720,6 @@ ila_add_del_entry (ila_add_del_entry_args_t * args)
        }
 
       //Create entry with the sir address
-      kv.key[0] = e->sir_address.as_u64[0];
-      kv.key[1] = e->sir_address.as_u64[1];
-      kv.key[2] = 0;
       kv.value = e - ilm->entries;
       BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv,
                                1 /* is_add */ );
@@ -795,14 +822,17 @@ vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
   return error;
 }
 
-u8 *ila_format_adjacency(u8 * s, va_list * va)
+u8 *
+ila_format_adjacency (u8 * s, va_list * va)
 {
   ila_main_t *ilm = &ila_main;
-  __attribute((unused)) ip_lookup_main_t *lm = va_arg (*va, ip_lookup_main_t *);
+  __attribute ((unused)) ip_lookup_main_t *lm =
+    va_arg (*va, ip_lookup_main_t *);
   ip_adjacency_t *adj = va_arg (*va, ip_adjacency_t *);
-  ila_adj_data_t * ad = (ila_adj_data_t *) & adj->opaque;
+  ila_adj_data_t *ad = (ila_adj_data_t *) & adj->opaque;
   ila_entry_t *ie = pool_elt_at_index (ilm->entries, ad->entry_index);
-  return format(s, "idx:%d sir:%U", ad->entry_index, format_ip6_address, &ie->sir_address);
+  return format (s, "idx:%d sir:%U", ad->entry_index, format_ip6_address,
+                &ie->sir_address);
 }
 
 clib_error_t *
@@ -824,11 +854,10 @@ ila_init (vlib_main_t * vm)
   return NULL;
 }
 
-VNET_IP6_REGISTER_ADJACENCY(ila2sir) = {
-  .node_name = "ila-to-sir",
-  .fn = ila_format_adjacency,
-  .next_index = &ila_main.ip6_lookup_next_index
-};
+VNET_IP6_REGISTER_ADJACENCY (ila2sir) =
+{
+.node_name = "ila-to-sir",.fn = ila_format_adjacency,.next_index =
+    &ila_main.ip6_lookup_next_index};
 
 VLIB_INIT_FUNCTION (ila_init);
 
@@ -879,8 +908,9 @@ ila_entry_command_fn (vlib_main_t * vm,
            (line_input, "next-hop %U", unformat_ip6_address, &next_hop))
        next_hop_set = 1;
       else if (unformat
-             (line_input, "direction %U", unformat_ila_direction, &args.dir))
-           ;
+              (line_input, "direction %U", unformat_ila_direction,
+               &args.dir))
+       ;
       else if (unformat (line_input, "del"))
        args.is_del = 1;
       else
@@ -919,12 +949,12 @@ ila_entry_command_fn (vlib_main_t * vm,
 
 VLIB_CLI_COMMAND (ila_entry_command, static) =
 {
-  .path = "ila entry",
-  .short_help = "ila entry [type <type>] [sir-address <address>] [locator <locator>] [vnid <hex-vnid>]"
-    " [adj-index <adj-index>] [next-hop <next-hop>] [direction (bidir|sir2ila|ila2sir)]"
-    " [csum-mode (no-action|neutral-map|transport-adjust)] [del]",
-  .function = ila_entry_command_fn,
-};
+.path = "ila entry",.short_help = "ila entry [type (" ila_type_list ")]"
+    " [sir-address <address>] [locator <locator>] [vnid <hex-vnid>]"
+    " [adj-index <adj-index>] [next-hop <next-hop>]"
+    " [direction (" ila_direction_list ")]"
+    " [csum-mode (" ila_csum_list ")] [del]",.function =
+    ila_entry_command_fn,};
 
 static clib_error_t *
 ila_interface_command_fn (vlib_main_t * vm,
@@ -953,10 +983,9 @@ ila_interface_command_fn (vlib_main_t * vm,
 
 VLIB_CLI_COMMAND (ila_interface_command, static) =
 {
-  .path = "ila interface",
-  .short_help = "ila interface <interface-name> [disable]",
-  .function = ila_interface_command_fn,
-};
+.path = "ila interface",.short_help =
+    "ila interface <interface-name> [disable]",.function =
+    ila_interface_command_fn,};
 
 static clib_error_t *
 ila_show_entries_command_fn (vlib_main_t * vm,
@@ -968,17 +997,16 @@ ila_show_entries_command_fn (vlib_main_t * vm,
   ila_entry_t *e;
 
   vlib_cli_output (vm, "  %U\n", format_ila_entry, vnm, NULL);
-  pool_foreach (e, ilm->entries,
-    ({
-      vlib_cli_output (vm, "  %U\n", format_ila_entry, vnm, e);
-    }));
+  pool_foreach (e, ilm->entries, (
+                                  {
+                                  vlib_cli_output (vm, "  %U\n",
+                                                   format_ila_entry, vnm, e);
+                                  }));
 
   return NULL;
 }
 
 VLIB_CLI_COMMAND (ila_show_entries_command, static) =
 {
-  .path = "show ila entries",
-  .short_help = "show ila entries",
-  .function = ila_show_entries_command_fn,
-};
+.path = "show ila entries",.short_help = "show ila entries",.function =
+    ila_show_entries_command_fn,};
index b800fdd..29b87fa 100644 (file)
   _(VNID6, 3, "vnid-ip6")              \
   _(VNIDM, 4, "vnid-multicast")
 
-typedef enum {
+#define ila_type_list "iid,luid,vnid-ip4,vnid-ip6,vnid-multicast"
+
+typedef enum
+{
 #define _(i,n,s) ILA_TYPE_##i = n,
   ila_foreach_type
 #undef _
@@ -40,7 +43,10 @@ _(NO_ACTION, 0, "no-action") \
 _(NEUTRAL_MAP, 1, "neutral-map") \
 _(ADJUST_TRANSPORT, 2, "adjust-transport")
 
-typedef enum {
+#define ila_csum_list "no-action,neutral-map,adjust-transport"
+
+typedef enum
+{
 #define _(i,n,s) ILA_CSUM_MODE_##i = n,
   ila_csum_foreach_type
 #undef _
@@ -52,13 +58,17 @@ _(BIDIR, 0, "bidir") \
 _(SIR2ILA, 1, "sir2ila") \
 _(ILA2SIR, 2, "ila2sir")
 
-typedef enum {
+#define ila_direction_list "bidir,sir2ila,ila2sir"
+
+typedef enum
+{
 #define _(i,n,s) ILA_DIR_##i = n,
   ila_foreach_direction
 #undef _
 } ila_direction_t;
 
-typedef struct {
+typedef struct
+{
   ila_type_t type;
   ip6_address_t sir_address;
   ip6_address_t ila_address;
@@ -67,11 +77,13 @@ typedef struct {
   ila_direction_t dir;
 } ila_entry_t;
 
-typedef struct {
+typedef struct
+{
   u32 entry_index;
 } ila_adj_data_t;
 
-typedef struct {
+typedef struct
+{
   ila_entry_t *entries;                //Pool of ILA entries
 
   u64 lookup_table_nbuckets;
@@ -84,7 +96,8 @@ typedef struct {
 } ila_main_t;
 
 
-typedef struct {
+typedef struct
+{
   ila_type_t type;
   ip6_address_t sir_address;
   u64 locator;
@@ -98,4 +111,9 @@ typedef struct {
 int ila_add_del_entry (ila_add_del_entry_args_t * args);
 int ila_interface (u32 sw_if_index, u8 disable);
 
+u8 *format_half_ip6_address (u8 * s, va_list * va);
+u8 *format_ila_direction (u8 * s, va_list * args);
+u8 *format_ila_csum_mode (u8 * s, va_list * va);
+u8 *format_ila_type (u8 * s, va_list * args);
+
 #endif //ILA_H
diff --git a/plugins/ila-plugin/ila/ila_api.c b/plugins/ila-plugin/ila/ila_api.c
new file mode 100644 (file)
index 0000000..c8bce6b
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 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 <ila/ila.h>
+
+#include <vppinfra/byte_order.h>
+#include <vlibapi/api.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vlibsocket/api.h>
+
+typedef struct
+{
+  u16 msg_id_base;
+} ila_api_main_t;
+
+ila_api_main_t ila_api_main;
+
+#define vl_msg_id(n,h) n,
+typedef enum
+{
+#include <ila/ila.api.h>
+  /* We'll want to know how many messages IDs we need... */
+  VL_MSG_FIRST_AVAILABLE,
+} vl_msg_id_t;
+#undef vl_msg_id
+
+/* define message structures */
+#define vl_typedefs
+#include <ila/ila.api.h>
+#undef vl_typedefs
+
+/* define generated endian-swappers */
+#define vl_endianfun
+#include <ila/ila.api.h>
+#undef vl_endianfun
+
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+
+/* Get the API version number */
+#define vl_api_version(n,v) static u32 api_version=(v);
+#include <ila/ila.api.h>
+#undef vl_api_version
+
+#define FINISH                                  \
+    vec_add1 (s, 0);                            \
+    vl_print (handle, (char *)s);               \
+    vec_free (s);                               \
+    return handle;
+
+#define REPLY_MACRO(t)                                          \
+do {                                                            \
+    unix_shared_memory_queue_t * q =                            \
+    vl_api_client_index_to_input_queue (mp->client_index);      \
+    if (!q)                                                     \
+        return;                                                 \
+                                                                \
+    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
+    rmp->_vl_msg_id = ntohs((t)+ila_api_main.msg_id_base);      \
+    rmp->context = mp->context;                                 \
+    rmp->retval = ntohl(rv);                                    \
+                                                                \
+    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
+} while(0);
+
+static void
+vl_api_ila_iface_t_handler (vl_api_ila_iface_t * mp)
+{
+  vl_api_ila_iface_reply_t *rmp;
+  int rv = 0;
+  rv = ila_interface (mp->sw_if_index, !mp->enable);
+
+  REPLY_MACRO (VL_API_ILA_IFACE_REPLY);
+}
+
+static void *
+vl_api_ila_iface_t_print (vl_api_ila_iface_t * mp, void *handle)
+{
+  u8 *s;
+  s = format (0, "SCRIPT: ila_iface ");
+  s = format (s, "%d ", mp->sw_if_index);
+  s = format (s, "%s", mp->enable ? "enable" : "disable");
+  FINISH;
+}
+
+static void
+vl_api_ila_add_del_entry_t_handler (vl_api_ila_add_del_entry_t * mp)
+{
+  vl_api_ila_add_del_entry_reply_t *rmp;
+  int rv = 0;
+  ila_add_del_entry_args_t args;
+  args.type = mp->type;
+  memcpy (&args.sir_address, mp->sir_address, sizeof (args.sir_address));
+  args.locator = mp->locator;
+  args.vnid = mp->vnid;
+  args.local_adj_index = mp->local_adj_index;
+  args.csum_mode = mp->csum_mode;
+  args.dir = mp->dir;
+  args.is_del = mp->is_del;
+
+  rv = ila_add_del_entry (&args);
+  REPLY_MACRO (VL_API_ILA_ADD_DEL_ENTRY_REPLY);
+}
+
+static void *vl_api_ila_add_del_entry_t_print
+  (vl_api_ila_add_del_entry_t * mp, void *handle)
+{
+  u8 *s;
+  s = format (0, "SCRIPT: ila_add_del_entry ");
+  s = format (s, "%U ", format_ila_type, mp->type);
+  s = format (s, "%U ", format_ip6_address, mp->sir_address);
+  s = format (s, "%U ", format_half_ip6_address, mp->locator);
+  s = format (s, "%d ", mp->vnid);
+  s = format (s, "%d ", mp->local_adj_index);
+  s = format (s, "%U ", format_ila_csum_mode, mp->csum_mode);
+  s = format (s, "%U ", format_ila_direction, mp->dir);
+  s = format (s, "%s ", mp->is_del ? "del" : "add");
+  FINISH;
+}
+
+/* List of message types that this plugin understands */
+#define foreach_ila_plugin_api_msg            \
+_(ILA_IFACE, ila_iface)                       \
+_(ILA_ADD_DEL_ENTRY, ila_add_del_entry)
+
+static clib_error_t *
+ila_api_init (vlib_main_t * vm)
+{
+  u8 *name = format (0, "ila_%08x%c", api_version, 0);
+  ila_api_main.msg_id_base = vl_msg_api_get_msg_ids
+    ((char *) name, VL_MSG_FIRST_AVAILABLE);
+
+#define _(N,n)                                                  \
+    vl_msg_api_set_handlers((VL_API_##N + ila_api_main.msg_id_base), \
+                           #n,                  \
+                           vl_api_##n##_t_handler,              \
+                           vl_noop_handler,                     \
+                           vl_api_##n##_t_endian,               \
+                           vl_api_##n##_t_print,                \
+                           sizeof(vl_api_##n##_t), 1);
+  foreach_ila_plugin_api_msg;
+#undef _
+
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (ila_api_init);
diff --git a/plugins/ila-plugin/ila/ila_api_test.c b/plugins/ila-plugin/ila/ila_api_test.c
new file mode 100644 (file)
index 0000000..dbd001a
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2016 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 <vlibsocket/api.h>
+#include <vppinfra/error.h>
+#include <ila/ila.h>
+
+
+#define vl_msg_id(n,h) n,
+typedef enum
+{
+#include <ila/ila.api.h>
+  /* We'll want to know how many messages IDs we need... */
+  VL_MSG_FIRST_AVAILABLE,
+} vl_msg_id_t;
+#undef vl_msg_id
+
+/* define message structures */
+#define vl_typedefs
+#include <ila/ila.api.h>
+#undef vl_typedefs
+
+/* declare message handlers for each api */
+
+#define vl_endianfun           /* define message structures */
+#include <ila/ila.api.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <ila/ila.api.h>
+#undef vl_printfun
+
+/* Get the API version number. */
+#define vl_api_version(n,v) static u32 api_version=(v);
+#include <ila/ila.api.h>
+#undef vl_api_version
+
+typedef struct
+{
+  /* API message ID base */
+  u16 msg_id_base;
+  vat_main_t *vat_main;
+} ila_api_test_main_t;
+
+
+/*
+ * Unformat functions are replicate from ila.c
+ *
+ */
+
+static uword
+unformat_ila_direction (unformat_input_t * input, va_list * args)
+{
+  ila_direction_t *result = va_arg (*args, ila_direction_t *);
+#define _(i,n,s) \
+  if (unformat(input, s)) \
+      { \
+        *result = ILA_DIR_##i; \
+        return 1;\
+      }
+
+  ila_foreach_direction
+#undef _
+    return 0;
+}
+
+static uword
+unformat_ila_type (unformat_input_t * input, va_list * args)
+{
+  ila_type_t *result = va_arg (*args, ila_type_t *);
+#define _(i,n,s) \
+  if (unformat(input, s)) \
+      { \
+        *result = ILA_TYPE_##i; \
+        return 1;\
+      }
+
+  ila_foreach_type
+#undef _
+    return 0;
+}
+
+static uword
+unformat_ila_csum_mode (unformat_input_t * input, va_list * args)
+{
+  ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *);
+  if (unformat (input, "none") || unformat (input, "no-action"))
+    {
+      *result = ILA_CSUM_MODE_NO_ACTION;
+      return 1;
+    }
+  if (unformat (input, "neutral-map"))
+    {
+      *result = ILA_CSUM_MODE_NEUTRAL_MAP;
+      return 1;
+    }
+  if (unformat (input, "adjust-transport"))
+    {
+      *result = ILA_CSUM_MODE_ADJUST_TRANSPORT;
+      return 1;
+    }
+  return 0;
+}
+
+static uword
+unformat_half_ip6_address (unformat_input_t * input, va_list * args)
+{
+  u64 *result = va_arg (*args, u64 *);
+  u32 a[4];
+
+  if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3]))
+    return 0;
+
+  if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF)
+    return 0;
+
+  *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) |
+                                 (((u64) a[1]) << 32) |
+                                 (((u64) a[2]) << 16) | (((u64) a[3])));
+
+  return 1;
+}
+
+ila_api_test_main_t ila_api_test_main;
+
+#define foreach_standard_reply_retval_handler   \
+  _(ila_iface_reply)                  \
+  _(ila_add_del_entry_reply)
+
+#define _(n)                                            \
+    static void vl_api_##n##_t_handler                  \
+    (vl_api_##n##_t * mp)                               \
+    {                                                   \
+        vat_main_t * vam = ila_api_test_main.vat_main;  \
+        i32 retval = ntohl(mp->retval);                 \
+        if (vam->async_mode) {                          \
+            vam->async_errors += (retval < 0);          \
+        } else {                                        \
+            vam->retval = retval;                       \
+            vam->result_ready = 1;                      \
+        }                                               \
+    }
+foreach_standard_reply_retval_handler;
+#undef _
+
+#define foreach_vpe_api_reply_msg                               \
+  _(ILA_IFACE_REPLY, ila_iface_reply)                           \
+  _(ILA_ADD_DEL_ENTRY_REPLY, ila_add_del_entry_reply)
+
+/* M: construct, but don't yet send a message */
+#define M(T,t)                                                  \
+do {                                                            \
+    vam->result_ready = 0;                                      \
+    mp = vl_msg_api_alloc(sizeof(*mp));                         \
+    memcpy (mp, &mps, sizeof (*mp));                            \
+    mp->_vl_msg_id =                                            \
+      ntohs (VL_API_##T + ila_api_test_main.msg_id_base);       \
+    mp->client_index = vam->my_client_index;                    \
+} while(0);
+
+/* S: send a message */
+#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp))
+
+/* W: wait for results, with timeout */
+#define W                                       \
+do {                                            \
+    timeout = vat_time_now (vam) + 1.0;         \
+                                                \
+    while (vat_time_now (vam) < timeout) {      \
+        if (vam->result_ready == 1) {           \
+            return (vam->retval);               \
+        }                                       \
+    }                                           \
+    return -99;                                 \
+} while(0);
+
+static int
+api_ila_iface (vat_main_t * vam)
+{
+  unformat_input_t *i = vam->input;
+  f64 timeout;
+  vl_api_ila_iface_t mps, *mp;
+
+  mps.enable = 1;
+  if (!unformat (i, "%u", &mps.sw_if_index))
+    {
+      errmsg ("invalid arguments\n");
+      return -99;
+    }
+
+  if (unformat (i, "disable"))
+    mps.enable = 0;
+
+  M (ILA_IFACE, ila_iface);
+  S;
+  W;
+  /* NOTREACHED */
+  return 0;
+}
+
+static int
+api_ila_add_del_entry (vat_main_t * vam)
+{
+  unformat_input_t *i = vam->input;
+  f64 timeout;
+  vl_api_ila_add_del_entry_t mps, *mp;
+
+  mps.type = ILA_TYPE_IID;
+  mps.csum_mode = ILA_CSUM_MODE_NO_ACTION;
+  mps.local_adj_index = ~0;
+  mps.dir = ILA_DIR_BIDIR;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "type %U", unformat_ila_type, &mps.type))
+       ;
+      else if (unformat
+              (i, "sir-address %U", unformat_ip6_address, &mps.sir_address))
+       ;
+      else if (unformat
+              (i, "locator %U", unformat_half_ip6_address, &mps.locator))
+       ;
+      else if (unformat (i, "adj-index %u", &mps.local_adj_index))
+       ;
+      else if (unformat
+              (i, "csum-mode %U", unformat_ila_csum_mode, &mps.csum_mode))
+       ;
+      else if (unformat (i, "vnid %x", &mps.vnid))
+       ;
+      else if (unformat (i, "direction %U", unformat_ila_direction, &mps.dir))
+       ;
+      else if (unformat (i, "del"))
+       mps.is_del = 1;
+      else
+       {
+         errmsg ("invalid arguments\n");
+         return -99;
+       }
+    }
+
+  M (ILA_ADD_DEL_ENTRY, ila_add_del_entry);
+  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                             \
+_(ila_iface, "<sw-if-index> [disable]")                 \
+_(ila_add_del_entry, "[type ("ila_type_list")] [sir-address <address>]" \
+" [locator <locator>] [vnid <hex-vnid>]" \
+" [adj-index <adj-index>] [direction ("ila_direction_list")]" \
+" [csum-mode ("ila_csum_list")] [del]")
+
+void
+vat_api_hookup (vat_main_t * vam)
+{
+  /* Hook up handlers for replies from the data plane plug-in */
+#define _(N,n)                                                          \
+  vl_msg_api_set_handlers((VL_API_##N + ila_api_test_main.msg_id_base), \
+                          #n,                                           \
+                          vl_api_##n##_t_handler,                       \
+                          vl_noop_handler,                              \
+                          vl_api_##n##_t_endian,                        \
+                          vl_api_##n##_t_print,                         \
+                          sizeof(vl_api_##n##_t), 1);
+  foreach_vpe_api_reply_msg;
+#undef _
+
+  /* API messages we can send */
+#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n);
+  foreach_vpe_api_msg;
+#undef _
+
+  /* Help strings */
+#define _(n,h) hash_set_mem (vam->help_by_name, #n, h);
+  foreach_vpe_api_msg;
+#undef _
+}
+
+clib_error_t *
+vat_plugin_register (vat_main_t * vam)
+{
+  u8 *name;
+
+  ila_api_test_main.vat_main = vam;
+
+  /* Ask the vpp engine for the first assigned message-id */
+  name = format (0, "ila_%08x%c", api_version, 0);
+  ila_api_test_main.msg_id_base =
+    vl_client_get_first_plugin_msg_id ((char *) name);
+
+  if (ila_api_test_main.msg_id_base != (u16) ~ 0)
+    vat_api_hookup (vam);
+
+  vec_free (name);
+  return 0;
+}