aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Pfister <ppfister@cisco.com>2016-09-15 13:45:31 +0100
committerKeith Burns <alagalah@gmail.com>2016-09-16 16:25:23 +0000
commit9b15f282952b12d1761c03ee48293baecaf32d0c (patch)
tree40903f8b32dac1ab9876b3f1779e0052947d11bc
parent2dfd08242d66fb79c9a861c6a0c7fee45ef6bc60 (diff)
Add ILA API and API test plugin VPP-412
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>
-rw-r--r--plugins/ila-plugin/Makefile.am17
-rw-r--r--plugins/ila-plugin/ila/ila.api62
-rw-r--r--plugins/ila-plugin/ila/ila.c150
-rw-r--r--plugins/ila-plugin/ila/ila.h32
-rw-r--r--plugins/ila-plugin/ila/ila_api.c159
-rw-r--r--plugins/ila-plugin/ila/ila_api_test.c319
6 files changed, 669 insertions, 70 deletions
diff --git a/plugins/ila-plugin/Makefile.am b/plugins/ila-plugin/Makefile.am
index fe785df9bc3..ebf1b9b5863 100644
--- a/plugins/ila-plugin/Makefile.am
+++ b/plugins/ila-plugin/Makefile.am
@@ -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
index 00000000000..9315fbb02d0
--- /dev/null
+++ b/plugins/ila-plugin/ila/ila.api
@@ -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;
+};
+
diff --git a/plugins/ila-plugin/ila/ila.c b/plugins/ila-plugin/ila/ila.c
index 2673c6269d2..b8348804a41 100644
--- a/plugins/ila-plugin/ila/ila.c
+++ b/plugins/ila-plugin/ila/ila.c
@@ -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,};
diff --git a/plugins/ila-plugin/ila/ila.h b/plugins/ila-plugin/ila/ila.h
index b800fdd7b7a..29b87fa0c3d 100644
--- a/plugins/ila-plugin/ila/ila.h
+++ b/plugins/ila-plugin/ila/ila.h
@@ -29,7 +29,10 @@
_(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
index 00000000000..c8bce6b57a3
--- /dev/null
+++ b/plugins/ila-plugin/ila/ila_api.c
@@ -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
index 00000000000..dbd001a0fb6
--- /dev/null
+++ b/plugins/ila-plugin/ila/ila_api_test.c
@@ -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;
+}