blob: bdbc9a9cb59249582107581ab0f0fcc9c1e5758b [file] [log] [blame]
/*
* Copyright (c) 2017 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 <vnet/bier/bier_disp_table.h>
#include <vnet/bier/bier_disp_entry.h>
/**
* memory pool for disposition tables
*/
bier_disp_table_t *bier_disp_table_pool;
/**
* Hash table to map client table IDs to VPP index
*/
static uword *bier_disp_table_id_to_index;
static index_t
bier_disp_table_get_index (const bier_disp_table_t *bdt)
{
return (bdt - bier_disp_table_pool);
}
static void
bier_disp_table_lock_i (bier_disp_table_t *bdt)
{
bdt->bdt_locks++;
}
index_t
bier_disp_table_find(u32 table_id)
{
uword *p;
p = hash_get(bier_disp_table_id_to_index, table_id);
if (NULL != p)
{
return (p[0]);
}
return (INDEX_INVALID);
}
index_t
bier_disp_table_add_or_lock (u32 table_id)
{
bier_disp_table_t *bdt;
index_t bdti;
bdti = bier_disp_table_find(table_id);
if (INDEX_INVALID == bdti)
{
pool_get_aligned(bier_disp_table_pool, bdt,
CLIB_CACHE_LINE_BYTES);
bdt->bdt_table_id = table_id;
bdt->bdt_locks = 0;
hash_set(bier_disp_table_id_to_index, table_id,
bier_disp_table_get_index(bdt));
/**
* Set the result for each entry in the DB to be invalid
*/
clib_memset(bdt->bdt_db, 0xff, sizeof(bdt->bdt_db));
}
else
{
bdt = pool_elt_at_index(bier_disp_table_pool, bdti);
}
bier_disp_table_lock_i(bdt);
return (bier_disp_table_get_index(bdt));
}
void
bier_disp_table_unlock_w_table_id (u32 table_id)
{
index_t bdti;
bdti = bier_disp_table_find(table_id);
if (INDEX_INVALID != bdti)
{
bier_disp_table_unlock(bdti);
}
}
void
bier_disp_table_unlock (index_t bdti)
{
bier_disp_table_t *bdt;
bdt = bier_disp_table_get(bdti);
bdt->bdt_locks--;
if (0 == bdt->bdt_locks)
{
u32 ii;
for (ii = 0; ii < BIER_BP_MAX; ii++)
{
bier_disp_entry_unlock(bdt->bdt_db[ii]);
}
hash_unset(bier_disp_table_id_to_index, bdt->bdt_table_id);
pool_put(bier_disp_table_pool, bdt);
}
}
void
bier_disp_table_lock (index_t bdti)
{
bier_disp_table_lock_i(bier_disp_table_get(bdti));
}
void
bier_disp_table_contribute_forwarding (index_t bdti,
dpo_id_t *dpo)
{
dpo_set(dpo,
DPO_BIER_DISP_TABLE,
DPO_PROTO_BIER,
bdti);
}
u8*
format_bier_disp_table (u8* s, va_list *ap)
{
index_t bdti = va_arg(*ap, index_t);
u32 indent = va_arg(*ap, u32);
bier_show_flags_t flags = va_arg(*ap, bier_show_flags_t);
bier_disp_table_t *bdt;
bdt = bier_disp_table_get(bdti);
s = format(s, "bier-disp-table:[%d]; table-id:%d locks:%d",
bdti, bdt->bdt_table_id, bdt->bdt_locks);
if (flags & BIER_SHOW_DETAIL)
{
u32 ii;
for (ii = 0; ii < BIER_BP_MAX; ii++)
{
if (INDEX_INVALID != bdt->bdt_db[ii])
{
u16 src = ii;
s = format(s, "\n%Usrc:%d", format_white_space, indent+1,
clib_host_to_net_u16(src));
s = format(s, "\n%U",
format_bier_disp_entry, bdt->bdt_db[ii],
indent+4, BIER_SHOW_BRIEF);
}
}
}
return (s);
}
static u8*
format_bier_disp_table_dpo (u8* s, va_list *ap)
{
index_t bdti = va_arg(*ap, index_t);
u32 indent = va_arg(*ap, u32);
return (format(s, "%U",
format_bier_disp_table, bdti, indent,
BIER_SHOW_BRIEF));
}
static void
bier_disp_table_entry_insert (index_t bdti,
bier_bp_t src,
index_t bdei)
{
bier_disp_table_t *bdt;
bdt = bier_disp_table_get(bdti);
bdt->bdt_db[clib_host_to_net_u16(src)] = bdei;
}
static void
bier_disp_table_entry_remove (index_t bdti,
bier_bp_t src)
{
bier_disp_table_t *bdt;
bdt = bier_disp_table_get(bdti);
bdt->bdt_db[clib_host_to_net_u16(src)] = INDEX_INVALID;
}
static index_t
bier_disp_table_lookup_hton(index_t bdti,
bier_bp_t bp)
{
bier_hdr_src_id_t src = bp;
return (bier_disp_table_lookup(bdti, clib_host_to_net_u16(src)));
}
void
bier_disp_table_entry_path_add (u32 table_id,
bier_bp_t src,
bier_hdr_proto_id_t payload_proto,
const fib_route_path_t *rpaths)
{
index_t bdti, bdei;
bdti = bier_disp_table_find(table_id);
if (INDEX_INVALID == bdti)
{
return;
}
bdei = bier_disp_table_lookup_hton(bdti, src);
if (INDEX_INVALID == bdei)
{
bdei = bier_disp_entry_add_or_lock();
bier_disp_table_entry_insert(bdti, src, bdei);
}
bier_disp_entry_path_add(bdei, payload_proto, rpaths);
}
void
bier_disp_table_entry_path_remove (u32 table_id,
bier_bp_t src,
bier_hdr_proto_id_t payload_proto,
const fib_route_path_t *rpath)
{
index_t bdti, bdei;
bdti = bier_disp_table_find(table_id);
if (INDEX_INVALID == bdti)
{
return;
}
bdei = bier_disp_table_lookup_hton(bdti, src);
if (INDEX_INVALID != bdei)
{
int remove;
remove = bier_disp_entry_path_remove(bdei, payload_proto, rpath);
if (remove)
{
bier_disp_table_entry_remove(bdti, src);
bier_disp_entry_unlock(bdei);
}
}
}
void
bier_disp_table_walk (u32 table_id,
bier_disp_table_walk_fn_t fn,
void *ctx)
{
const bier_disp_table_t *bdt;
const bier_disp_entry_t *bde;
index_t bdti;
u32 ii;
bdti = bier_disp_table_find(table_id);
if (INDEX_INVALID != bdti)
{
bdt = bier_disp_table_get(bdti);
for (ii = 0; ii < BIER_BP_MAX; ii++)
{
if (INDEX_INVALID != bdt->bdt_db[ii])
{
u16 src = ii;
bde = bier_disp_entry_get(bdt->bdt_db[ii]);
fn(bdt, bde, clib_host_to_net_u16(src), ctx);
}
}
}
}
static void
bier_disp_table_dpo_lock (dpo_id_t *dpo)
{
bier_disp_table_lock(dpo->dpoi_index);
}
static void
bier_disp_table_dpo_unlock (dpo_id_t *dpo)
{
bier_disp_table_unlock(dpo->dpoi_index);
}
static void
bier_disp_table_dpo_mem_show (void)
{
fib_show_memory_usage("BIER disposition table",
pool_elts(bier_disp_table_pool),
pool_len(bier_disp_table_pool),
sizeof(bier_disp_table_t));
}
const static dpo_vft_t bier_disp_table_dpo_vft = {
.dv_lock = bier_disp_table_dpo_lock,
.dv_unlock = bier_disp_table_dpo_unlock,
.dv_mem_show = bier_disp_table_dpo_mem_show,
.dv_format = format_bier_disp_table_dpo,
};
const static char *const bier_disp_table_bier_nodes[] =
{
"bier-disp-lookup",
NULL
};
const static char * const * const bier_disp_table_nodes[DPO_PROTO_NUM] =
{
[DPO_PROTO_BIER] = bier_disp_table_bier_nodes,
};
clib_error_t *
bier_disp_table_module_init (vlib_main_t *vm)
{
dpo_register(DPO_BIER_DISP_TABLE,
&bier_disp_table_dpo_vft,
bier_disp_table_nodes);
bier_disp_table_id_to_index = hash_create(0, sizeof(index_t));
return (NULL);
}
VLIB_INIT_FUNCTION (bier_disp_table_module_init);
static clib_error_t *
show_bier_disp_table (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
bier_disp_table_t *bdt;
index_t bdti;
bdti = INDEX_INVALID;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
if (unformat (input, "%d", &bdti))
;
else if (unformat (input, "%d", &bdti))
;
else
{
break;
}
}
if (INDEX_INVALID == bdti)
{
pool_foreach (bdt, bier_disp_table_pool)
{
vlib_cli_output(vm, "%U", format_bier_disp_table,
bier_disp_table_get_index(bdt),
0, BIER_SHOW_BRIEF);
}
}
else
{
if (pool_is_free_index(bier_disp_table_pool, bdti))
{
vlib_cli_output(vm, "No such BIER disp table: %d", bdti);
}
else
{
vlib_cli_output(vm, "%U", format_bier_disp_table, bdti, 0,
BIER_SHOW_DETAIL);
}
}
return (NULL);
}
VLIB_CLI_COMMAND (show_bier_disp_table_node, static) = {
.path = "show bier disp table",
.short_help = "show bier disp table [index]",
.function = show_bier_disp_table,
};