/* * 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. */ /** * bier_imposition : The BIER imposition object * * A BIER imposition object is present in the IP mcast output list * and represents the imposition of a BIER bitmask. After BIER header * imposition the packet is forward within the appropriate/specified * BIER table */ #include <vnet/bier/bier_imp.h> #include <vnet/bier/bier_table.h> #include <vnet/bier/bier_hdr_inlines.h> #include <vnet/fib/fib_node.h> #include <vnet/mpls/mpls_types.h> /** * The memory pool of all imp objects */ bier_imp_t *bier_imp_pool; /** * When constructing the BIER imp ID from an index and BSL, shift * the BSL this far */ #define BIER_IMP_ID_HLEN_SHIFT 24 static void bier_imp_lock_i (bier_imp_t *bi) { bi->bi_locks++; } void bier_imp_lock (index_t bii) { bier_imp_lock_i(bier_imp_get(bii)); } static index_t bier_imp_get_index(bier_imp_t *bi) { return (bi - bier_imp_pool); } index_t bier_imp_add_or_lock (const bier_table_id_t *bti, bier_bp_t sender, const bier_bit_string_t *bs) { bier_imp_t *bi = NULL; fib_protocol_t fproto; index_t btii; pool_get_aligned(bier_imp_pool, bi, CLIB_CACHE_LINE_BYTES); bi->bi_tbl = *bti; btii = bier_table_lock(bti); /* * init the BIER header we will paint on in the data plane */ bier_hdr_init(&bi->bi_hdr, BIER_HDR_VERSION_1, BIER_HDR_PROTO_INVALID, // filled in later bti->bti_hdr_len, 0, // entropy sender); bier_hdr_hton(&bi->bi_hdr); clib_memcpy_fast(&bi->bi_bits, bs->bbs_buckets, bs->bbs_len); bier_imp_lock_i(bi); /* * get and stack on the forwarding info from the table */ FOR_EACH_FIB_IP_PROTOCOL(fproto) { /* * initialise to invalid first, lest we pick up garbage * from the pool alloc */ dpo_id_t dpo = DPO_INVALID; bi->bi_dpo[fproto] = dpo; bier_table_contribute_forwarding(btii, &dpo); dpo_stack(DPO_BIER_IMP, fib_proto_to_dpo(fproto), &bi->bi_dpo[fproto], &dpo); dpo_reset(&dpo); } return (bier_imp_get_index(bi)); } void bier_imp_unlock (index_t bii) { fib_protocol_t fproto; bier_imp_t *bi; if (INDEX_INVALID == bii) { return; } bi = bier_imp_get(bii); bi->bi_locks--; if (0 == bi->bi_locks) { bier_table_unlock(&bi->bi_tbl); FOR_EACH_FIB_IP_PROTOCOL(fproto) { dpo_reset(&bi->bi_dpo[fproto]); } pool_put(bier_imp_pool, bi); } } u8* format_bier_imp (u8* s, va_list *args) { index_t bii = va_arg (*args, index_t); u32 indent = va_arg(*args, u32); bier_show_flags_t flags = va_arg(*args, bier_show_flags_t); bier_imp_t *bi; bi = bier_imp_get(bii); s = format(s, "bier-imp:[%d]: tbl:[%U] hdr:[%U]", bier_imp_get_index(bi), format_bier_table_id, &bi->bi_tbl, format_bier_hdr, &bi->bi_hdr); if (BIER_SHOW_DETAIL & flags) { bier_bit_string_t bbs; bier_hdr_t copy; copy = bi->bi_hdr; bier_hdr_ntoh(©); bier_bit_string_init(&bbs, bier_hdr_get_len_id(©), bi->bi_bits); s = format(s, "\n%U%U", format_white_space, indent, format_bier_bit_string, &bbs); s = format(s, "\n%U%U", format_white_space, indent, format_dpo_id, &bi->bi_dpo, indent+2); } return (s); } void bier_imp_contribute_forwarding (index_t bii, dpo_proto_t proto, dpo_id_t *dpo) { dpo_set(dpo, DPO_BIER_IMP, proto, bii); } const static char* const bier_imp_ip4_nodes[] = { "bier-imp-ip4", NULL, }; const static char* const bier_imp_ip6_nodes[] = { "bier-imp-ip6", NULL, }; const static char* const * const bier_imp_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP4] = bier_imp_ip4_nodes, [DPO_PROTO_IP6] = bier_imp_ip6_nodes, }; static void bier_imp_dpo_lock (dpo_id_t *dpo) { bier_imp_lock(dpo->dpoi_index); } static void bier_imp_dpo_unlock (dpo_id_t *dpo) { bier_imp_unlock(dpo->dpoi_index); } static void bier_imp_dpo_mem_show (void) { fib_show_memory_usage("BIER imposition", pool_elts(bier_imp_pool), pool_len(bier_imp_pool), sizeof(bier_imp_t)); } static u8* format_bier_imp_dpo (u8* s, va_list *ap) { index_t index = va_arg(*ap, index_t); u32 indent = va_arg(*ap, u32); s = format(s, "%U", format_bier_imp, index, indent, BIER_SHOW_DETAIL); return (s); } const static dpo_vft_t bier_imp_vft = { .dv_lock = bier_imp_dpo_lock, .dv_unlock = bier_imp_dpo_unlock, .dv_format = format_bier_imp_dpo, .dv_mem_show = bier_imp_dpo_mem_show, }; clib_error_t * bier_imp_db_module_init (vlib_main_t *vm) { dpo_register(DPO_BIER_IMP, &bier_imp_vft, bier_imp_nodes); return (NULL); } VLIB_INIT_FUNCTION (bier_imp_db_module_init); static clib_error_t * show_bier_imp (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { bier_imp_t *bi; index_t bii; bii = INDEX_INVALID; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "%d", &bii)) ; else { break; } } if (INDEX_INVALID == bii) { pool_foreach(bi, bier_imp_pool, ({ vlib_cli_output(vm, "%U", format_bier_imp, bier_imp_get_index(bi), 1, BIER_SHOW_BRIEF); })); } else { if (pool_is_free_index(bier_imp_pool, bii)) { vlib_cli_output(vm, "No such BIER imposition: %d", bii); } else { vlib_cli_output(vm, "%U", format_bier_imp, bii, 1, BIER_SHOW_DETAIL); } } return (NULL); } VLIB_CLI_COMMAND (show_bier_imp_node, static) = { .path = "show bier imp", .short_help = "show bier imp [index]", .function = show_bier_imp, };