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