From 9b15f282952b12d1761c03ee48293baecaf32d0c Mon Sep 17 00:00:00 2001 From: Pierre Pfister Date: Thu, 15 Sep 2016 13:45:31 +0100 Subject: 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 --- plugins/ila-plugin/ila/ila.api | 62 +++++++ plugins/ila-plugin/ila/ila.c | 150 +++++++++------- plugins/ila-plugin/ila/ila.h | 32 +++- plugins/ila-plugin/ila/ila_api.c | 159 +++++++++++++++++ plugins/ila-plugin/ila/ila_api_test.c | 319 ++++++++++++++++++++++++++++++++++ 5 files changed, 654 insertions(+), 68 deletions(-) create mode 100644 plugins/ila-plugin/ila/ila.api create mode 100644 plugins/ila-plugin/ila/ila_api.c create mode 100644 plugins/ila-plugin/ila/ila_api_test.c (limited to 'plugins/ila-plugin/ila') 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 ] [sir-address
] [locator ] [vnid ]" - " [adj-index ] [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
] [locator ] [vnid ]" + " [adj-index ] [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 [disable]", - .function = ila_interface_command_fn, -}; +.path = "ila interface",.short_help = + "ila interface [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 + +#include +#include +#include +#include +#include + +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 + /* 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 +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#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 +#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 +#include +#include +#include +#include +#include + + +#define vl_msg_id(n,h) n, +typedef enum +{ +#include + /* 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 +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#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, " [disable]") \ +_(ila_add_del_entry, "[type ("ila_type_list")] [sir-address
]" \ +" [locator ] [vnid ]" \ +" [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; +} -- cgit 1.2.3-korg