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>
This commit is contained in:
Pierre Pfister
2016-09-15 13:45:31 +01:00
committed by Keith Burns
parent 2dfd08242d
commit 9b15f28295
6 changed files with 669 additions and 70 deletions

View 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))

View File

@ -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;
};

View 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,};

View File

@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff