/* * 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, };