diff options
39 files changed, 1249 insertions, 554 deletions
diff --git a/src/vnet.am b/src/vnet.am index bd7efb24c4b..ae125bc57ef 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -1175,7 +1175,8 @@ libvnet_la_SOURCES += \ vnet/bier/bier_disp_entry.c \ vnet/bier/bier_disp_lookup_node.c \ vnet/bier/bier_disp_dispatch_node.c \ - vnet/bier/bier_disp_table.c + vnet/bier/bier_disp_table.c \ + vnet/bier/bier_bift_table.c nobase_include_HEADERS += \ vnet/bier/bier_types.h \ diff --git a/src/vnet/bier/bier.api b/src/vnet/bier/bier.api index 466524cc6a3..e4edfa1768a 100644 --- a/src/vnet/bier/bier.api +++ b/src/vnet/bier/bier.api @@ -36,7 +36,9 @@ typeonly define bier_table_id @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param bt_tbl_id - The BIER table-id the route is added in - @param bt_mpls_label - The MPLS label for the table + @param bt_label - The MPLS label for the table (0 or all ones means not set) + If the label is not set, then it is assumed that non-MPLS + encoding is used. @param bt_is_add - Is this a route add or delete */ autoreply define bier_table_add_del @@ -67,10 +69,11 @@ define bier_table_details @param preference - The preference of the path. lowest preference is prefered @param is_local - local if non-zero, else remote @param is_drop - Drop the packet - @param is_unreach - Drop the packet and rate limit send ICMP unreachable - @param is_prohibit - Drop the packet and rate limit send ICMP prohibited + @param is_udp_encap - The path describes a UDP-o-IP encapsulation. @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2 @param next_hop[16] - the next hop address + @param next_hop_id - Used when the path resolves via an object that has a unique + identifier. e.g. the UDP encap object WARNING: this type is replicated, pending cleanup completion */ @@ -82,10 +85,10 @@ typeonly define fib_path3 u8 preference; u8 is_local; u8 is_drop; - u8 is_unreach; - u8 is_prohibit; + u8 is_udp_encap; u8 afi; u8 next_hop[16]; + u32 next_hop_id; u32 rpf_id; u8 n_labels; u32 label_stack[16]; diff --git a/src/vnet/bier/bier_api.c b/src/vnet/bier/bier_api.c index cd1f40b1eaa..67c70462540 100644 --- a/src/vnet/bier/bier_api.c +++ b/src/vnet/bier/bier_api.c @@ -83,7 +83,17 @@ vl_api_bier_table_add_del_t_handler (vl_api_bier_table_add_del_t * mp) if (mp->bt_is_add) { - bier_table_add_or_lock(&bti, ntohl(mp->bt_label)); + mpls_label_t label = ntohl(mp->bt_label); + + /* + * convert acceptable 'don't want a label' values from + * the API to the correct internal INVLID value + */ + if ((0 == label) || (~0 == label)) + { + label = MPLS_LABEL_INVALID; + } + bier_table_add_or_lock(&bti, label); } else { @@ -175,7 +185,7 @@ vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp) { brpath = &brpaths[ii]; memset(brpath, 0, sizeof(*brpath)); - brpath->frp_flags = FIB_ROUTE_PATH_BIER_FMASK; + brpath->frp_sw_if_index = ~0; vec_validate(brpath->frp_label_stack, mp->br_paths[ii].n_labels - 1); @@ -185,30 +195,41 @@ vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp) ntohl(mp->br_paths[ii].label_stack[jj]); } - if (0 == mp->br_paths[ii].afi) + if (mp->br_paths[ii].is_udp_encap) { - clib_memcpy (&brpath->frp_addr.ip4, - mp->br_paths[ii].next_hop, - sizeof (brpath->frp_addr.ip4)); + brpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP; + brpath->frp_udp_encap_id = ntohl(mp->br_paths[ii].next_hop_id); } else { - clib_memcpy (&brpath->frp_addr.ip6, - mp->br_paths[ii].next_hop, - sizeof (brpath->frp_addr.ip6)); - } - if (ip46_address_is_zero(&brpath->frp_addr)) - { - index_t bdti; - - bdti = bier_disp_table_find(ntohl(mp->br_paths[ii].table_id)); - - if (INDEX_INVALID != bdti) - brpath->frp_fib_index = bdti; + if (0 == mp->br_paths[ii].afi) + { + clib_memcpy (&brpath->frp_addr.ip4, + mp->br_paths[ii].next_hop, + sizeof (brpath->frp_addr.ip4)); + } else { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto done; + clib_memcpy (&brpath->frp_addr.ip6, + mp->br_paths[ii].next_hop, + sizeof (brpath->frp_addr.ip6)); + } + if (ip46_address_is_zero(&brpath->frp_addr)) + { + index_t bdti; + + bdti = bier_disp_table_find(ntohl(mp->br_paths[ii].table_id)); + + if (INDEX_INVALID != bdti) + { + brpath->frp_fib_index = bdti; + brpath->frp_proto = DPO_PROTO_BIER; + } + else + { + rv = VNET_API_ERROR_NO_SUCH_FIB; + goto done; + } } } } diff --git a/src/vnet/bier/bier_bift_table.c b/src/vnet/bier/bier_bift_table.c new file mode 100644 index 00000000000..e0f6c64ea59 --- /dev/null +++ b/src/vnet/bier/bier_bift_table.c @@ -0,0 +1,290 @@ +/* + * 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 <vnet/bier/bier_bift_table.h> +#include <vnet/dpo/drop_dpo.h> +#include <vnet/udp/udp.h> + +typedef enum { +#define bier_error(n,s) BIER_INPUT_ERROR_##n, +#include <vnet/bier/bier_input_error.def> +#undef bier_error + BIER_INPUT_N_ERROR, +} bier_input_error_t; + +static char * bier_error_strings[] = { +#define bier_error(n,s) s, +#include <vnet/bier/bier_input_error.def> +#undef bier_error +}; + +/** + * Global BIFT table + */ +bier_bfit_table_t *bier_bift_table; + +/** + * Forward declare the node + */ +vlib_node_registration_t bier_bift_input_node; + +void +bier_bift_table_entry_add (bier_bift_id_t id, + const dpo_id_t *dpo) +{ + if (NULL == bier_bift_table) + { + u32 ii; + + /* + * allocate the table and + * set each of the entries therein to a BIER drop + */ + bier_bift_table = clib_mem_alloc_aligned(sizeof(*bier_bift_table), + CLIB_CACHE_LINE_BYTES); + memset(bier_bift_table, 0, sizeof(*bier_bift_table)); + + for (ii = 0; ii < BIER_BIFT_N_ENTRIES; ii++) + { + dpo_stack_from_node(bier_bift_input_node.index, + &bier_bift_table->bblt_dpos[ii], + drop_dpo_get(DPO_PROTO_BIER)); + } + + /* + * register to handle packets that arrive on the assigned + * UDP port + */ + udp_register_dst_port(vlib_get_main(), + UDP_DST_PORT_BIER, + bier_bift_input_node.index, + 0); + udp_register_dst_port(vlib_get_main(), + UDP_DST_PORT_BIER, + bier_bift_input_node.index, + 1); + } + + dpo_stack_from_node(bier_bift_input_node.index, + &bier_bift_table->bblt_dpos[id], + dpo); + + bier_bift_table->bblt_n_entries++; +} + +void +bier_bift_table_entry_remove (bier_bift_id_t id) +{ + ASSERT(NULL != bier_bift_table); + + dpo_reset(&bier_bift_table->bblt_dpos[id]); + + bier_bift_table->bblt_n_entries--; + + if (0 == bier_bift_table->bblt_n_entries) + { + udp_unregister_dst_port(vlib_get_main(), + UDP_DST_PORT_BIER, + 0); + udp_unregister_dst_port(vlib_get_main(), + UDP_DST_PORT_BIER, + 1); + + clib_mem_free(bier_bift_table); + bier_bift_table = NULL; + } +} + +/** + * @brief Packet trace record for BIER input + */ +typedef struct bier_bift_input_trace_t_ +{ + u32 bift_id; +} bier_bift_input_trace_t; + +static uword +bier_bift_input (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + u32 n_left_from, next_index, * from, * to_next; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + bier_bift_id_t *biftp0, bift0; + const dpo_id_t *dpo0; + vlib_buffer_t * b0; + u32 bi0, next0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + biftp0 = vlib_buffer_get_current (b0); + vlib_buffer_advance(b0, sizeof(bift0)); + bift0 = clib_net_to_host_u32(*biftp0); + + /* + * Do the lookup based on the first 20 bits, i.e. the + * encoding of the set, sub-domain and BSL + */ + dpo0 = bier_bift_dp_lookup(bift0); + + /* + * save the TTL for later during egress + */ + vnet_buffer(b0)->mpls.ttl = vnet_mpls_uc_get_ttl(bift0); + + next0 = dpo0->dpoi_next_node; + vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + bier_bift_input_trace_t *tr; + + tr = vlib_add_trace(vm, node, b0, sizeof (*tr)); + tr->bift_id = bift0; + } + + vlib_validate_buffer_enqueue_x1(vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame(vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter(vm, bier_bift_input_node.index, + BIER_INPUT_ERROR_PKTS_VALID, + from_frame->n_vectors); + return (from_frame->n_vectors); +} + +static u8 * +format_bier_bift_input_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + bier_bift_input_trace_t * t = va_arg (*args, bier_bift_input_trace_t *); + + s = format (s, "BIFT-ID:[%U]", format_bier_bift_id, + vnet_mpls_uc_get_label(t->bift_id)); + return s; +} + +VLIB_REGISTER_NODE (bier_bift_input_node) = { + .function = bier_bift_input, + .name = "bier-bift-input", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + .n_errors = BIER_INPUT_N_ERROR, + .error_strings = bier_error_strings, + .n_next_nodes = 0, + .format_trace = format_bier_bift_input_trace, +}; + +clib_error_t * +show_bier_bift_cmd (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + clib_error_t * error = NULL; + u32 hdr_len, set, sub_domain; + + set = hdr_len = sub_domain = ~0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { + if (unformat (input, "sd %d", &sub_domain)) { + ; + } else if (unformat (input, "set %d", &set)) { + ; + } else if (unformat (input, "bsl %d", &hdr_len)) { + ; + } + else + { + error = unformat_parse_error (input); + goto done; + } + } + + if (NULL == bier_bift_table) + { + vlib_cli_output(vm, "no BIFT entries"); + } + + if (~0 == set) + { + u32 ii; + + for (ii = 0; ii < BIER_BIFT_N_ENTRIES; ii++) + { + if (!dpo_is_drop(&bier_bift_table->bblt_dpos[ii])) + { + bier_hdr_len_id_t bsl; + + bier_bift_id_decode(ii, &set, &sub_domain, &bsl); + + vlib_cli_output(vm, "set: %d, sub-domain:%d, BSL:%U", + set, sub_domain, + format_bier_hdr_len_id, bsl); + vlib_cli_output(vm, " %U", + format_dpo_id, + &bier_bift_table->bblt_dpos[ii], 0); + } + } + } + else + { + bier_bift_id_t id; + + id = bier_bift_id_encode(set, sub_domain, + bier_hdr_bit_len_to_id(hdr_len)); + + if (!dpo_is_drop(&bier_bift_table->bblt_dpos[id])) + { + vlib_cli_output(vm, "set: %d, sub-domain:%d, BSL:%U", + set, sub_domain, + format_bier_hdr_len_id, hdr_len); + vlib_cli_output(vm, " %U", + format_dpo_id, + &bier_bift_table->bblt_dpos[id], 0); + } + } +done: + return (error); +} + +VLIB_CLI_COMMAND (show_bier_bift_command, static) = { + .path = "show bier bift", + .short_help = "show bier bift [set <value> sd <value> bsl <value>]", + .function = show_bier_bift_cmd, +}; diff --git a/src/vnet/bier/bier_bift_table.h b/src/vnet/bier/bier_bift_table.h new file mode 100644 index 00000000000..bc77c37ae3a --- /dev/null +++ b/src/vnet/bier/bier_bift_table.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef __BIER_BIFT_TABLE_H__ +#define __BIER_BIFT_TABLE_H__ + +#include <vnet/dpo/dpo.h> +#include <vnet/bier/bier_types.h> +#include <vnet/mpls/packet.h> + +/* + * the lookup table used to get from a BFIT_ID to a load-balance. + * As per-draft draft-ietf-bier-mpls-encapsulation-10 this isthe + * use case for non-MPLS networks + */ +#define BIER_BIFT_N_ENTRIES (1 << 20) +typedef struct bier_bfit_table_t_ +{ + /** + * Forwarding information for each BIFT ID + */ + dpo_id_t bblt_dpos[BIER_BIFT_N_ENTRIES]; + + /** + * The number of entries in the table + */ + u32 bblt_n_entries; +} bier_bfit_table_t; + + +extern void bier_bift_table_entry_add(bier_bift_id_t id, + const dpo_id_t *dpo); + +extern void bier_bift_table_entry_remove(bier_bift_id_t id); + +/** + * Global BIFT table + */ +extern bier_bfit_table_t *bier_bift_table; + +static inline const dpo_id_t* +bier_bift_dp_lookup (bier_bift_id_t key_host_order) +{ + return (&bier_bift_table->bblt_dpos[vnet_mpls_uc_get_label(key_host_order)]); +} +#endif diff --git a/src/vnet/bier/bier_disp_dispatch_node.c b/src/vnet/bier/bier_disp_dispatch_node.c index a00c2eea5f9..40d0a293658 100644 --- a/src/vnet/bier/bier_disp_dispatch_node.c +++ b/src/vnet/bier/bier_disp_dispatch_node.c @@ -86,7 +86,7 @@ bier_disp_dispatch_inline (vlib_main_t * vm, * the packets flow-hash field * DSCP mumble mumble... */ - vlib_buffer_advance(b0, (vnet_buffer(b0)->bier.n_bytes + + vlib_buffer_advance(b0, (vnet_buffer(b0)->mpls.bier.n_bytes + sizeof(*hdr0))); vnet_buffer(b0)->ip.flow_hash = entropy0; diff --git a/src/vnet/bier/bier_disp_entry.c b/src/vnet/bier/bier_disp_entry.c index 3326aba2f86..2fe2e4ab909 100644 --- a/src/vnet/bier/bier_disp_entry.c +++ b/src/vnet/bier/bier_disp_entry.c @@ -145,6 +145,7 @@ bier_disp_entry_restack (bier_disp_entry_t *bde, fib_path_list_contribute_forwarding(pli, fib_forw_chain_type_from_dpo_proto( bier_hdr_proto_to_dpo(pproto)), + FIB_PATH_LIST_FWD_FLAG_COLLAPSE, &via_dpo); bier_disp_entry_path_list_walk_ctx_t ctx = { @@ -254,24 +255,26 @@ format_bier_disp_entry (u8* s, va_list *args) bde = bier_disp_entry_get(bdei); - s = format(s, "bier-disp:[%d]", bdei); + s = format(s, "%Ubier-disp:[%d]", format_white_space, indent, bdei); FOR_EACH_BIER_HDR_PROTO(pproto) { if (INDEX_INVALID != bde->bde_pl[pproto]) { - s = format(s, "\n"); - s = fib_path_list_format(bde->bde_pl[pproto], s); + s = format(s, "\n%U%U\n", + format_white_space, indent+2, + format_bier_hdr_proto, pproto); + s = format(s, "%U", format_fib_path_list, bde->bde_pl[pproto], indent+4); if (flags & BIER_SHOW_DETAIL) { s = format(s, "\n%UForwarding:", - format_white_space, indent); + format_white_space, indent+4); s = format(s, "\n%Urpf-id:%d", - format_white_space, indent+1, + format_white_space, indent+6, bde->bde_fwd[pproto].bde_rpf_id); s = format(s, "\n%U%U", - format_white_space, indent+1, + format_white_space, indent+6, format_dpo_id, &bde->bde_fwd[pproto].bde_dpo, indent+2); } } diff --git a/src/vnet/bier/bier_disp_table.c b/src/vnet/bier/bier_disp_table.c index 47d23e8ac3b..db4a2a82d2b 100644 --- a/src/vnet/bier/bier_disp_table.c +++ b/src/vnet/bier/bier_disp_table.c @@ -161,9 +161,9 @@ format_bier_disp_table (u8* s, va_list *ap) if (INDEX_INVALID != bdt->bdt_db[ii]) { u16 src = ii; - s = format(s, "\n%Usrc:%d", format_white_space, indent, + s = format(s, "\n%Usrc:%d", format_white_space, indent+1, clib_host_to_net_u16(src)); - s = format(s, "\n%U%U", format_white_space, indent+2, + s = format(s, "\n%U", format_bier_disp_entry, bdt->bdt_db[ii], indent+4, BIER_SHOW_BRIEF); } @@ -380,13 +380,12 @@ show_bier_disp_table (vlib_main_t * vm, ({ vlib_cli_output(vm, "%U", format_bier_disp_table, bier_disp_table_get_index(bdt), - 1, - BIER_SHOW_BRIEF); + 0, BIER_SHOW_BRIEF); })); } else { - vlib_cli_output(vm, "%U", format_bier_disp_table, bdti, 1, + vlib_cli_output(vm, "%U", format_bier_disp_table, bdti, 0, BIER_SHOW_DETAIL); } return (NULL); diff --git a/src/vnet/bier/bier_entry.c b/src/vnet/bier/bier_entry.c index 88be8125f51..2f8d25008cc 100644 --- a/src/vnet/bier/bier_entry.c +++ b/src/vnet/bier/bier_entry.c @@ -116,18 +116,23 @@ bier_entry_table_ecmp_walk_add_fmask (index_t btei, fib_path_list_contribute_forwarding(be->be_path_list, FIB_FORW_CHAIN_TYPE_BIER, + FIB_PATH_LIST_FWD_FLAG_COLLAPSE, &dpo); /* * select the appropriate bucket from the LB */ - ASSERT(dpo.dpoi_type == DPO_LOAD_BALANCE); - - lb = load_balance_get(dpo.dpoi_index); - - choice = load_balance_get_bucket_i(lb, - btid->bti_ecmp & - (lb->lb_n_buckets_minus_1)); + if (dpo.dpoi_type == DPO_LOAD_BALANCE) + { + lb = load_balance_get(dpo.dpoi_index); + choice = load_balance_get_bucket_i(lb, + btid->bti_ecmp & + (lb->lb_n_buckets_minus_1)); + } + else + { + choice = &dpo; + } if (choice->dpoi_type == DPO_BIER_FMASK) { @@ -293,6 +298,7 @@ bier_entry_contribute_forwarding(index_t bei, fib_path_list_contribute_forwarding(be->be_path_list, FIB_FORW_CHAIN_TYPE_BIER, + FIB_PATH_LIST_FWD_FLAG_COLLAPSE, dpo); } diff --git a/src/vnet/bier/bier_fmask.c b/src/vnet/bier/bier_fmask.c index 32bece0c665..2fc24dca819 100644 --- a/src/vnet/bier/bier_fmask.c +++ b/src/vnet/bier/bier_fmask.c @@ -16,6 +16,7 @@ #include <vnet/fib/fib_entry.h> #include <vnet/fib/fib_table.h> #include <vnet/fib/fib_walk.h> +#include <vnet/fib/fib_path_list.h> #include <vnet/bier/bier_table.h> #include <vnet/bier/bier_fmask.h> @@ -74,26 +75,27 @@ static void bier_fmask_stack (bier_fmask_t *bfm) { dpo_id_t via_dpo = DPO_INVALID; + fib_forward_chain_type_t fct; - if (bfm->bfm_flags & BIER_FMASK_FLAG_DISP) + if (bfm->bfm_flags & BIER_FMASK_FLAG_MPLS) { - bier_disp_table_contribute_forwarding(bfm->bfm_disp, - &via_dpo); + fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS; } else { - fib_entry_contribute_forwarding(bfm->bfm_fei, - FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, - &via_dpo); + fct = FIB_FORW_CHAIN_TYPE_BIER; } + fib_path_list_contribute_forwarding(bfm->bfm_pl, fct, + FIB_PATH_LIST_FWD_FLAG_COLLAPSE, + &via_dpo); + /* - * If the via fib entry provides no forwarding (i.e. a drop) - * then niether does this fmask. That way children consider this fmask + * If the via PL entry provides no forwarding (i.e. a drop) + * then neither does this fmask. That way children consider this fmask * unresolved and other ECMP options are used instead. */ - if (dpo_is_drop(&via_dpo) || - load_balance_is_drop(&via_dpo)) + if (dpo_is_drop(&via_dpo)) { bfm->bfm_flags &= ~BIER_FMASK_FLAG_FORWARDING; } @@ -130,65 +132,6 @@ bier_fmask_contribute_forwarding (index_t bfmi, } } -static void -bier_fmask_resolve (bier_fmask_t *bfm) -{ - if (bfm->bfm_flags & BIER_FMASK_FLAG_DISP) - { - bier_disp_table_lock(bfm->bfm_disp); - } - else - { - /* - * source a recursive route through which we resolve. - */ - fib_prefix_t pfx = { - .fp_addr = bfm->bfm_id.bfmi_nh, - .fp_proto = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ? - FIB_PROTOCOL_IP4 : - FIB_PROTOCOL_IP6), - .fp_len = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ? 32 : 128), - }; - - bfm->bfm_fei = fib_table_entry_special_add(0, // default table - &pfx, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE); - - bfm->bfm_sibling = fib_entry_child_add(bfm->bfm_fei, - FIB_NODE_TYPE_BIER_FMASK, - bier_fmask_get_index(bfm)); - } - - bier_fmask_stack(bfm); -} - -static void -bier_fmask_unresolve (bier_fmask_t *bfm) -{ - if (bfm->bfm_flags & BIER_FMASK_FLAG_DISP) - { - bier_disp_table_unlock(bfm->bfm_disp); - } - else - { - /* - * un-source the recursive route through which we resolve. - */ - fib_prefix_t pfx = { - .fp_addr = bfm->bfm_id.bfmi_nh, - .fp_proto = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ? - FIB_PROTOCOL_IP4 : - FIB_PROTOCOL_IP6), - .fp_len = (ip46_address_is_ip4(&(bfm->bfm_id.bfmi_nh)) ? 32 : 128), - }; - - fib_entry_child_remove(bfm->bfm_fei, bfm->bfm_sibling); - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_RR); - } - dpo_reset(&bfm->bfm_dpo); -} - u32 bier_fmask_child_add (fib_node_index_t bfmi, fib_node_type_t child_type, @@ -204,6 +147,11 @@ void bier_fmask_child_remove (fib_node_index_t bfmi, u32 sibling_index) { + if (INDEX_INVALID == bfmi) + { + return; + } + fib_node_child_remove(FIB_NODE_TYPE_BIER_FMASK, bfmi, sibling_index); @@ -212,38 +160,64 @@ bier_fmask_child_remove (fib_node_index_t bfmi, static void bier_fmask_init (bier_fmask_t *bfm, const bier_fmask_id_t *fmid, - index_t bti, - const fib_route_path_t *rpath) + const fib_route_path_t *rpaths) { const bier_table_id_t *btid; mpls_label_t olabel; - bfm->bfm_id = *fmid; - bfm->bfm_fib_index = bti; + *bfm->bfm_id = *fmid; dpo_reset(&bfm->bfm_dpo); + btid = bier_table_get_id(bfm->bfm_id->bfmi_bti); + bier_fmask_bits_init(&bfm->bfm_bits, btid->bti_hdr_len); - if (ip46_address_is_zero(&(bfm->bfm_id.bfmi_nh))) + if (ip46_address_is_zero(&(bfm->bfm_id->bfmi_nh))) { bfm->bfm_flags |= BIER_FMASK_FLAG_DISP; } if (!(bfm->bfm_flags & BIER_FMASK_FLAG_DISP)) { - olabel = rpath->frp_label_stack[0]; - vnet_mpls_uc_set_label(&bfm->bfm_label, olabel); - vnet_mpls_uc_set_exp(&bfm->bfm_label, 0); - vnet_mpls_uc_set_s(&bfm->bfm_label, 1); - vnet_mpls_uc_set_ttl(&bfm->bfm_label, 0xff); - bfm->bfm_label = clib_host_to_net_u32(bfm->bfm_label); - } - else - { - bfm->bfm_disp = rpath->frp_bier_fib_index; + /* + * leave this label in host byte order so we can OR in the TTL + */ + if (NULL != rpaths->frp_label_stack) + { + olabel = rpaths->frp_label_stack[0]; + vnet_mpls_uc_set_label(&bfm->bfm_label, olabel); + vnet_mpls_uc_set_exp(&bfm->bfm_label, 0); + vnet_mpls_uc_set_s(&bfm->bfm_label, 1); + vnet_mpls_uc_set_ttl(&bfm->bfm_label, 0); + bfm->bfm_flags |= BIER_FMASK_FLAG_MPLS; + } + else + { + bier_bift_id_t id; + + /* + * not an MPLS label + */ + bfm->bfm_flags &= ~BIER_FMASK_FLAG_MPLS; + + /* + * use a label as encoded for BIFT value + */ + id = bier_bift_id_encode(btid->bti_set, + btid->bti_sub_domain, + btid->bti_hdr_len); + vnet_mpls_uc_set_label(&bfm->bfm_label, id); + vnet_mpls_uc_set_s(&bfm->bfm_label, 1); + vnet_mpls_uc_set_exp(&bfm->bfm_label, 0); + } } - btid = bier_table_get_id(bfm->bfm_fib_index); - bier_fmask_bits_init(&bfm->bfm_bits, btid->bti_hdr_len); - bier_fmask_resolve(bfm); + bfm->bfm_pl = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED | + FIB_PATH_LIST_FLAG_NO_URPF), + rpaths); + bfm->bfm_sibling = fib_path_list_child_add(bfm->bfm_pl, + FIB_NODE_TYPE_BIER_FMASK, + bier_fmask_get_index(bfm)); + + bier_fmask_stack(bfm); } static void @@ -252,8 +226,11 @@ bier_fmask_destroy (bier_fmask_t *bfm) clib_mem_free(bfm->bfm_bits.bfmb_refs); clib_mem_free(bfm->bfm_bits.bfmb_input_reset_string.bbs_buckets); - bier_fmask_db_remove(bfm->bfm_fib_index, &(bfm->bfm_id)); - bier_fmask_unresolve(bfm); + bier_fmask_db_remove(bfm->bfm_id); + fib_path_list_child_remove(bfm->bfm_pl, + bfm->bfm_sibling); + dpo_reset(&bfm->bfm_dpo); + clib_mem_free(bfm->bfm_id); pool_put(bier_fmask_pool, bfm); } @@ -289,8 +266,7 @@ bier_fmask_lock (index_t bfmi) index_t bier_fmask_create_and_lock (const bier_fmask_id_t *fmid, - index_t bti, - const fib_route_path_t *rpath) + const fib_route_path_t *rpaths) { bier_fmask_t *bfm; @@ -298,8 +274,11 @@ bier_fmask_create_and_lock (const bier_fmask_id_t *fmid, memset(bfm, 0, sizeof(*bfm)); + bfm->bfm_id = clib_mem_alloc(sizeof(*bfm->bfm_id)); + + ASSERT(1 == vec_len(rpaths)); fib_node_init(&bfm->bfm_node, FIB_NODE_TYPE_BIER_FMASK); - bier_fmask_init(bfm, fmid, bti, rpath); + bier_fmask_init(bfm, fmid, rpaths); bier_fmask_lock(bier_fmask_get_index(bfm)); @@ -362,7 +341,7 @@ format_bier_fmask (u8 *s, va_list *ap) bfm = bier_fmask_get(bfmi); s = format(s, "fmask: nh:%U bs:%U locks:%d ", - format_ip46_address, &bfm->bfm_id.bfmi_nh, IP46_TYPE_ANY, + format_ip46_address, &bfm->bfm_id->bfmi_nh, IP46_TYPE_ANY, format_bier_bit_string, &bfm->bfm_bits.bfmb_input_reset_string, bfm->bfm_node.fn_locks); s = format(s, "flags:"); @@ -371,7 +350,22 @@ format_bier_fmask (u8 *s, va_list *ap) s = format (s, "%s,", bier_fmask_attr_names[attr]); } } - s = format(s, "\n%U%U", + s = format(s, "\n"); + s = fib_path_list_format(bfm->bfm_pl, s); + + if (bfm->bfm_flags & BIER_FMASK_FLAG_MPLS) + { + s = format(s, " output-label:%U", + format_mpls_unicast_label, + vnet_mpls_uc_get_label(bfm->bfm_label)); + } + else + { + s = format(s, " output-bfit:[%U]", + format_bier_bift_id, + vnet_mpls_uc_get_label(bfm->bfm_label)); + } + s = format(s, "\n %U%U", format_white_space, indent, format_dpo_id, &bfm->bfm_dpo, indent+2); @@ -509,7 +503,8 @@ bier_fmask_show (vlib_main_t * vm, { pool_foreach(bfm, bier_fmask_pool, ({ - vlib_cli_output (vm, "%U", + vlib_cli_output (vm, "[@%d] %U", + bier_fmask_get_index(bfm), format_bier_fmask, bier_fmask_get_index(bfm), 0); })); } diff --git a/src/vnet/bier/bier_fmask.h b/src/vnet/bier/bier_fmask.h index 13eab5360e1..81b3923f54c 100644 --- a/src/vnet/bier/bier_fmask.h +++ b/src/vnet/bier/bier_fmask.h @@ -65,12 +65,14 @@ typedef enum bier_fmask_attributes_t_ BIER_FMASK_ATTR_FIRST, BIER_FMASK_ATTR_FORWARDING = BIER_FMASK_ATTR_FIRST, BIER_FMASK_ATTR_DISP, + BIER_FMASK_ATTR_MPLS, BIER_FMASK_ATTR_LAST = BIER_FMASK_ATTR_DISP, } bier_fmask_attributes_t; #define BIER_FMASK_ATTR_NAMES { \ [BIER_FMASK_ATTR_FORWARDING] = "forwarding", \ [BIER_FMASK_ATTR_DISP] = "disposition", \ + [BIER_FMASK_ATTR_MPLS] = "mpls", \ } #define FOR_EACH_BIER_FMASK_ATTR(_item) \ @@ -82,6 +84,7 @@ typedef enum bier_fmask_flags_t_ { BIER_FMASK_FLAG_FORWARDING = (1 << BIER_FMASK_ATTR_FORWARDING), BIER_FMASK_FLAG_DISP = (1 << BIER_FMASK_ATTR_DISP), + BIER_FMASK_FLAG_MPLS = (1 << BIER_FMASK_ATTR_MPLS), } bier_fmask_flags_t; /** @@ -110,47 +113,20 @@ typedef struct bier_fmask_t_ { */ bier_fmask_bits_t bfm_bits; - struct - { - /** - * The key to this fmask - used for store/lookup in the DB - */ - bier_fmask_id_t bfm_id; - - /** - * The BIER Table this Fmask is used in - */ - index_t bfm_fib_index; - }; - - union - { - /** - * For forwarding via a next-hop - */ - struct - { - /** - * The parent fib entry - */ - fib_node_index_t bfm_fei; - /** - * The MPLS label to paint on the header during forwarding - */ - mpls_label_t bfm_label; - }; - - /** - * For disposition - */ - struct - { - /** - * The parent disposition table object - */ - index_t bfm_disp; - }; - }; + /** + * The key to this fmask - used for store/lookup in the DB + */ + bier_fmask_id_t *bfm_id; + + /** + * The MPLS label to paint on the header during forwarding + */ + mpls_label_t bfm_label; + + /** + * The path-list + */ + fib_node_index_t bfm_pl; /** * the index of this fmask in the parent's child list. @@ -170,7 +146,6 @@ extern void bier_fmask_unlock(index_t bfmi); extern void bier_fmask_lock(index_t bfmi); extern index_t bier_fmask_create_and_lock(const bier_fmask_id_t *fmid, - index_t bti, const fib_route_path_t *rpath); extern u8* format_bier_fmask(u8 *s, va_list *ap); diff --git a/src/vnet/bier/bier_fmask_db.c b/src/vnet/bier/bier_fmask_db.c index 37cbb365897..67d3bd1cf85 100644 --- a/src/vnet/bier/bier_fmask_db.c +++ b/src/vnet/bier/bier_fmask_db.c @@ -40,16 +40,6 @@ typedef struct bier_fmask_db_t_ { } bier_fmask_db_t; /** - * The key used in the fmask DB to compare fmask objects. - * There is one global DB, so we need to use the table's ID and the fmasks ID - */ -typedef struct bier_fmask_db_key_t_ { - bier_fmask_id_t bfmdbk_fm_id; - index_t bfmdbk_tbl_id; -} bier_fmask_db_key_t; -// TODO packed? - -/** * Single fmask DB */ static bier_fmask_db_t bier_fmask_db; @@ -61,82 +51,93 @@ bier_fmask_get_index (const bier_fmask_t *bfm) return (bfm - bier_fmask_db.bfdb_pool); } -u32 -bier_fmask_db_find_or_create_and_lock (index_t bti, - const bier_fmask_id_t *fmid, - const fib_route_path_t *rpath) +static void +bier_fmask_db_mk_key (index_t bti, + const fib_route_path_t *rpath, + bier_fmask_id_t *key) { - bier_fmask_db_key_t key; - u32 index; - uword *p; - /* - * there be padding in that thar key, and it's - * used as a memcmp in the mhash. + * Depending on what the ID is there may be padding. + * This key will be memcmp'd in the mhash, so make sure it's all 0 */ - memset(&key, 0, sizeof(key)); - key.bfmdbk_tbl_id = bti; - key.bfmdbk_fm_id = *fmid; - - index = INDEX_INVALID; - p = mhash_get (&bier_fmask_db.bfdb_hash, &key); + memset(key, 0, sizeof(*key)); - if (NULL == p) + /* + * Pick the attributes from the path that make the FMask unique + */ + if (FIB_ROUTE_PATH_UDP_ENCAP & rpath->frp_flags) { - /* - * adding a new fmask object - */ - index = bier_fmask_create_and_lock(fmid, bti, rpath); - - mhash_set (&bier_fmask_db.bfdb_hash, &key, index, 0 /*old_value*/); + key->bfmi_id = rpath->frp_udp_encap_id; } else { - index = p[0]; - bier_fmask_lock(index); + key->bfmi_sw_if_index = rpath->frp_sw_if_index; + memcpy(&key->bfmi_nh, &rpath->frp_addr, sizeof(rpath->frp_addr)); + } + if (NULL == rpath->frp_label_stack) + { + key->bfmi_hdr_type = BIER_HDR_O_OTHER; + } + else + { + key->bfmi_hdr_type = BIER_HDR_O_MPLS; } - - return (index); } u32 bier_fmask_db_find (index_t bti, - const bier_fmask_id_t *fmid) + const fib_route_path_t *rpath) { - bier_fmask_db_key_t key; - u32 index; + bier_fmask_id_t fmid; uword *p; - /* - * there be padding in that thar key, and it's - * used as a memcmp in the mhash. - */ - memset(&key, 0, sizeof(key)); - key.bfmdbk_tbl_id = bti; - key.bfmdbk_fm_id = *fmid; - - index = INDEX_INVALID; - p = mhash_get(&bier_fmask_db.bfdb_hash, &key); + bier_fmask_db_mk_key(bti, rpath, &fmid); + p = mhash_get(&bier_fmask_db.bfdb_hash, &fmid); if (NULL != p) { + return (p[0]); + } + + return (INDEX_INVALID); +} + +u32 +bier_fmask_db_find_or_create_and_lock (index_t bti, + const fib_route_path_t *rpath) +{ + bier_fmask_id_t fmid; + u32 index; + uword *p; + + bier_fmask_db_mk_key(bti, rpath, &fmid); + p = mhash_get(&bier_fmask_db.bfdb_hash, &fmid); + + if (NULL == p) + { + bier_fmask_t *bfm; + /* + * adding a new fmask object + */ + index = bier_fmask_create_and_lock(&fmid, rpath); + bfm = bier_fmask_get(index); + mhash_set(&bier_fmask_db.bfdb_hash, bfm->bfm_id, index, 0); + } + else + { index = p[0]; + bier_fmask_lock(index); } return (index); } void -bier_fmask_db_remove (index_t bti, - const bier_fmask_id_t *fmid) +bier_fmask_db_remove (const bier_fmask_id_t *fmid) { - bier_fmask_db_key_t key = { - .bfmdbk_tbl_id = bti, - .bfmdbk_fm_id = *fmid, - }; uword *p; - p = mhash_get (&bier_fmask_db.bfdb_hash, &key); + p = mhash_get(&bier_fmask_db.bfdb_hash, fmid); if (NULL == p) { /* @@ -144,16 +145,16 @@ bier_fmask_db_remove (index_t bti, */ ASSERT (!"remove non-existant fmask"); } else { - mhash_unset (&(bier_fmask_db.bfdb_hash), &key, 0); + mhash_unset(&(bier_fmask_db.bfdb_hash), (void*)fmid, 0); } } clib_error_t * bier_fmask_db_module_init (vlib_main_t *vm) { - mhash_init (&bier_fmask_db.bfdb_hash, - sizeof(uword), - sizeof(bier_fmask_db_key_t)); + mhash_init(&bier_fmask_db.bfdb_hash, + sizeof(index_t), + sizeof(bier_fmask_id_t)); return (NULL); } diff --git a/src/vnet/bier/bier_fmask_db.h b/src/vnet/bier/bier_fmask_db.h index 6ba40f3a839..a7f29c2b6a6 100644 --- a/src/vnet/bier/bier_fmask_db.h +++ b/src/vnet/bier/bier_fmask_db.h @@ -21,18 +21,27 @@ #include <vnet/ip/ip.h> -#include <vnet/bier/bier_types.h> +#include <vnet/fib/fib_types.h> /** - * Foward declarations + * BIER header encapulsation types */ -struct bier_fmask_t_; - typedef enum bier_hdr_type_t_ { - BIER_HDR_IN_IP6, + /** + * BIER Header in MPLS networks + */ BIER_HDR_O_MPLS, + + /** + * BIER header in non-MPLS networks + */ + BIER_HDR_O_OTHER, } bier_hdr_type_t; +/** + * A key/ID for a BIER forwarding Mas (FMask). + * This is a simplified version of a fib_route_path_t. + */ typedef struct bier_fmask_id_t_ { /** * Type of BIER header this fmask supports @@ -40,22 +49,35 @@ typedef struct bier_fmask_id_t_ { bier_hdr_type_t bfmi_hdr_type; /** - * next-hop of the peer + * The BIER table this fmask is in + */ + index_t bfmi_bti; + + union { + /** + * next-hop of the peer + */ + ip46_address_t bfmi_nh; + + /** + * ID of the next-hop object, e.g. a UDP-encap + */ + u32 bfmi_id; + }; + + /** + * Software interface index */ - ip46_address_t bfmi_nh; -} bier_fmask_id_t; + u32 bfmi_sw_if_index; +} __attribute__((packed)) bier_fmask_id_t; -extern u32 +extern index_t bier_fmask_db_find_or_create_and_lock(index_t bti, - const bier_fmask_id_t *fmid, const fib_route_path_t *rpath); +extern index_t bier_fmask_db_find (index_t bti, + const fib_route_path_t *rpath); -extern u32 -bier_fmask_db_find(index_t bti, - const bier_fmask_id_t *fmid); +extern void bier_fmask_db_remove (const bier_fmask_id_t *fmid); -extern void -bier_fmask_db_remove(index_t bti, - const bier_fmask_id_t *fmid); #endif diff --git a/src/vnet/bier/bier_imp_node.c b/src/vnet/bier/bier_imp_node.c index e9aae93b460..9c09d6722bc 100644 --- a/src/vnet/bier/bier_imp_node.c +++ b/src/vnet/bier/bier_imp_node.c @@ -134,6 +134,12 @@ bier_imp_dpo_inline (vlib_main_t * vm, BIER_HDR_ENTROPY_FIELD_MASK) << BIER_HDR_ENTROPY_FIELD_SHIFT); + /* + * use TTL 64 for the post enacp MPLS label/BIFT-ID + * this we be decremeted in bier_output node. + */ + vnet_buffer(b0)->mpls.ttl = 65; + /* next node */ next0 = bimp0->bi_dpo[fproto].dpoi_next_node; vnet_buffer(b0)->ip.adj_index[VLIB_TX] = diff --git a/src/vnet/bier/bier_input.c b/src/vnet/bier/bier_input.c index 88b37fc80c0..dca990d07f6 100644 --- a/src/vnet/bier/bier_input.c +++ b/src/vnet/bier/bier_input.c @@ -40,7 +40,7 @@ typedef enum bier_input_next_t_ { vlib_node_registration_t bier_input_node; /** - * @brief Packet trace recoed for a BIER output + * @brief Packet trace record for BIER input */ typedef struct bier_input_trace_t_ { diff --git a/src/vnet/bier/bier_lookup.c b/src/vnet/bier/bier_lookup.c index 4cf29f886e4..817dcc6f3e8 100644 --- a/src/vnet/bier/bier_lookup.c +++ b/src/vnet/bier/bier_lookup.c @@ -138,7 +138,7 @@ bier_lookup (vlib_main_t * vm, * number of integer sized buckets */ n_bytes = bier_hdr_len_id_to_num_buckets(bt0->bt_id.bti_hdr_len); - vnet_buffer(b0)->bier.n_bytes = n_bytes; + vnet_buffer(b0)->mpls.bier.n_bytes = n_bytes; vnet_buffer(b0)->sw_if_index[VLIB_TX] = ~0; num_buckets = n_bytes / sizeof(int); bier_bit_string_init(&bbs, @@ -178,7 +178,6 @@ bier_lookup (vlib_main_t * vm, if (PREDICT_TRUE(INDEX_INVALID != bfmi0)) { bfm0 = bier_fmask_get(bfmi0); - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = bfmi0; /* * use the bit-string on the fmask to reset @@ -237,6 +236,8 @@ bier_lookup (vlib_main_t * vm, ci0 = blm->blm_clones[thread_index][clone]; c0 = vlib_get_buffer(vm, ci0); + vnet_buffer(c0)->ip.adj_index[VLIB_TX] = + blm->blm_fmasks[thread_index][clone]; to_next[0] = ci0; to_next += 1; diff --git a/src/vnet/bier/bier_output.c b/src/vnet/bier/bier_output.c index fce6c50b309..db115d3ad5e 100644 --- a/src/vnet/bier/bier_output.c +++ b/src/vnet/bier/bier_output.c @@ -89,9 +89,10 @@ bier_output (vlib_main_t * vm, bier_bit_string_t bbs; vlib_buffer_t * b0; bier_fmask_t *bfm0; + mpls_label_t *h0; bier_hdr_t *bh0; - u32 bi0, *h0; u32 bfmi0; + u32 bi0; bi0 = from[0]; to_next[0] = bi0; @@ -131,9 +132,16 @@ bier_output (vlib_main_t * vm, */ if (!(bfm0->bfm_flags & BIER_FMASK_FLAG_DISP)) { + /* + * since a BIFT value and a MPLS label are formated the + * same, this painting works OK. + */ vlib_buffer_advance(b0, -(word)sizeof(mpls_label_t)); h0 = vlib_buffer_get_current(b0); + h0[0] = bfm0->bfm_label; + vnet_mpls_uc_set_ttl(h0, vnet_buffer(b0)->mpls.ttl - 1); + h0[0] = clib_host_to_net_u32(h0[0]); } /* diff --git a/src/vnet/bier/bier_table.c b/src/vnet/bier/bier_table.c index 191ac01e373..0f0f37677e9 100644 --- a/src/vnet/bier/bier_table.c +++ b/src/vnet/bier/bier_table.c @@ -20,6 +20,7 @@ #include <vnet/bier/bier_update.h> #include <vnet/bier/bier_fmask_db.h> #include <vnet/bier/bier_fmask.h> +#include <vnet/bier/bier_bift_table.h> #include <vnet/fib/mpls_fib.h> #include <vnet/mpls/mpls.h> @@ -96,9 +97,6 @@ bier_table_init (bier_table_t *bt, num_entries, INDEX_INVALID, CLIB_CACHE_LINE_BYTES); - fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS, - MPLS_FIB_DEFAULT_TABLE_ID, - FIB_SOURCE_BIER); } else { @@ -110,12 +108,42 @@ bier_table_init (bier_table_t *bt, } static void +bier_table_rm_bift (bier_table_t *bt) +{ + ASSERT(MPLS_LABEL_INVALID == bt->bt_ll); + + bier_bift_table_entry_remove(bier_bift_id_encode(bt->bt_id.bti_set, + bt->bt_id.bti_sub_domain, + bt->bt_id.bti_hdr_len)); +} + +static void +bier_table_mk_bift (bier_table_t *bt) +{ + dpo_id_t dpo = DPO_INVALID; + + ASSERT(MPLS_LABEL_INVALID == bt->bt_ll); + + bier_table_contribute_forwarding(bier_table_get_index(bt), &dpo); + + bier_bift_table_entry_add(bier_bift_id_encode(bt->bt_id.bti_set, + bt->bt_id.bti_sub_domain, + bt->bt_id.bti_hdr_len), + &dpo); + + dpo_reset(&dpo); +} + +static void bier_table_rm_lfib (bier_table_t *bt) { if (FIB_NODE_INDEX_INVALID != bt->bt_lfei) { fib_table_entry_delete_index(bt->bt_lfei, FIB_SOURCE_BIER); + fib_table_unlock(MPLS_FIB_DEFAULT_TABLE_ID, + FIB_PROTOCOL_MPLS, + FIB_SOURCE_BIER); } bt->bt_lfei = FIB_NODE_INDEX_INVALID; } @@ -127,6 +155,15 @@ bier_table_destroy (bier_table_t *bt) { index_t *bei; + if (MPLS_LABEL_INVALID != bt->bt_ll) + { + bier_table_rm_lfib(bt); + } + else + { + bier_table_rm_bift(bt); + } + fib_path_list_unlock(bt->bt_pl); bt->bt_pl = FIB_NODE_INDEX_INVALID; /* @@ -140,10 +177,6 @@ bier_table_destroy (bier_table_t *bt) } } vec_free (bt->bt_entries); - fib_table_unlock(fib_table_find(FIB_PROTOCOL_MPLS, - MPLS_FIB_DEFAULT_TABLE_ID), - FIB_PROTOCOL_MPLS, - FIB_SOURCE_BIER); } else { @@ -177,7 +210,6 @@ bier_table_unlock_i (bier_table_t *bt) if (0 == bt->bt_locks) { - bier_table_rm_lfib(bt); bier_table_destroy(bt); } } @@ -214,12 +246,17 @@ bier_table_mk_lfib (bier_table_t *bt) u32 mpls_fib_index; dpo_id_t dpo = DPO_INVALID; + fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS, + MPLS_FIB_DEFAULT_TABLE_ID, + FIB_SOURCE_BIER); + /* * stack the entry on the forwarding chain prodcued by the * path-list via the ECMP tables. */ fib_path_list_contribute_forwarding(bt->bt_pl, FIB_FORW_CHAIN_TYPE_BIER, + FIB_PATH_LIST_FWD_FLAG_COLLAPSE, &dpo); mpls_fib_index = fib_table_find(FIB_PROTOCOL_MPLS, @@ -306,13 +343,37 @@ bier_table_add_or_lock (const bier_table_id_t *btid, * modify an existing table. * change the lfib entry to the new local label */ - if (bier_table_is_main(bt) && - (local_label != MPLS_LABEL_INVALID)) + if (bier_table_is_main(bt)) { - bier_table_rm_lfib(bt); + /* + * remove the mpls-fib or bift entry + */ + if (MPLS_LABEL_INVALID != bt->bt_ll) + { + bier_table_rm_lfib(bt); + } + else + { + bier_table_rm_bift(bt); + } + + /* + * reset + */ + bt->bt_ll = MPLS_LABEL_INVALID; - bt->bt_ll = local_label; - bier_table_mk_lfib(bt); + /* + * add whichever mpls-fib or bift we need + */ + if (local_label != MPLS_LABEL_INVALID) + { + bt->bt_ll = local_label; + bier_table_mk_lfib(bt); + } + else + { + bier_table_mk_bift(bt); + } } bti = bier_table_get_index(bt); } @@ -334,7 +395,19 @@ bier_table_add_or_lock (const bier_table_id_t *btid, if (bier_table_is_main(bt)) { bt = bier_table_mk_ecmp(bti); - bier_table_mk_lfib(bt); + + /* + * add whichever mpls-fib or bift we need + */ + if (local_label != MPLS_LABEL_INVALID) + { + bt->bt_ll = local_label; + bier_table_mk_lfib(bt); + } + else + { + bier_table_mk_bift(bt); + } } } @@ -459,16 +532,19 @@ bier_table_route_add (const bier_table_id_t *btid, */ vec_foreach(brp, brps) { - bier_fmask_id_t fmid = { - .bfmi_nh = brp->frp_addr, - .bfmi_hdr_type = BIER_HDR_O_MPLS, - }; - bfmi = bier_fmask_db_find_or_create_and_lock(bier_table_get_index(bt), - &fmid, - brp); - - brp->frp_bier_fib_index = bti; + /* + * First use the path to find or construct an FMask object + * via the next-hop + */ + bfmi = bier_fmask_db_find_or_create_and_lock(bti, brp); vec_add1(bfmis, bfmi); + + /* + * then modify the path to resolve via this fmask object + * and use it to resolve the BIER entry. + */ + brp->frp_flags = FIB_ROUTE_PATH_BIER_FMASK; + brp->frp_bier_fmask = bfmi; } if (INDEX_INVALID == bei) @@ -536,6 +612,7 @@ bier_table_contribute_forwarding (index_t bti, */ fib_path_list_contribute_forwarding(bt->bt_pl, FIB_FORW_CHAIN_TYPE_BIER, + FIB_PATH_LIST_FWD_FLAG_COLLAPSE, dpo); } else @@ -642,12 +719,12 @@ format_bier_table (u8 *s, va_list *ap) if (pool_is_free_index(bier_table_pool, bti)) { - return (format(s, "No BIER f-mask %d", bti)); + return (format(s, "No BIER table %d", bti)); } bt = bier_table_get(bti); - s = format(s, "[@%d] bier-table:[%U local-label:%U]", + s = format(s, "[@%d] bier-table:[%U local-label:%U", bti, format_bier_table_id, &bt->bt_id, format_mpls_unicast_label, bt->bt_ll); diff --git a/src/vnet/bier/bier_test.c b/src/vnet/bier/bier_test.c index f0e7b0cab2f..cf75c2eb072 100644 --- a/src/vnet/bier/bier_test.c +++ b/src/vnet/bier/bier_test.c @@ -312,7 +312,7 @@ bier_test_mpls_spf (void) fib_route_path_t path_1_1_1_1 = { .frp_addr = nh_1_1_1_1, .frp_bier_fib_index = bti, - .frp_flags = FIB_ROUTE_PATH_BIER_FMASK, + .frp_sw_if_index = ~0, }; vec_add1(path_1_1_1_1.frp_label_stack, 500); vec_add1(paths_1_1_1_1, path_1_1_1_1); @@ -321,10 +321,6 @@ bier_test_mpls_spf (void) .fp_len = 32, .fp_proto = FIB_PROTOCOL_IP4, }; - const bier_fmask_id_t bfm_id_1_1_1_1 = { - .bfmi_hdr_type = BIER_HDR_O_MPLS, - .bfmi_nh = nh_1_1_1_1, - }; index_t bei_1; bier_table_route_add(&bt_0_0_0_256, 1, paths_1_1_1_1); @@ -345,20 +341,12 @@ bier_test_mpls_spf (void) FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &neos_dpo_1_1_1_1); - bfmi_1_1_1_1 = bier_fmask_db_find(bti, &bfm_id_1_1_1_1); + bfmi_1_1_1_1 = bier_fmask_db_find(bti, &path_1_1_1_1); bfm_1_1_1_1 = bier_fmask_get(bfmi_1_1_1_1); - BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_1, &bfm_1_1_1_1->bfm_dpo), - "Fmask via 1.1.1.1 stacks on neos from 1.1.1.1/32"); - - /* - * and that n-eos LB at this stage is a drop.. - */ - const fib_test_lb_bucket_t bucket_drop = { - .type = FT_LB_DROP, - }; - BIER_TEST(fib_test_validate_lb(&neos_dpo_1_1_1_1, 1, &bucket_drop), - "1.1.1.1/32 n-eos LB 1 buckets via: DROP"); + BIER_TEST(!dpo_cmp(drop_dpo_get(DPO_PROTO_MPLS), + &bfm_1_1_1_1->bfm_dpo), + "Fmask via 1.1.1.1 stacks on MPLS drop"); /* * The BIER entry should stack on the forwarding chain of the fmask @@ -369,8 +357,11 @@ bier_test_mpls_spf (void) .fmask = bfmi_1_1_1_1, }, }; - BIER_TEST(bier_test_validate_entry(bei_1, 1, &bucket_drop), - "BP:1 stacks on bier drop"); + dpo_id_t dpo_bei = DPO_INVALID; + bier_entry_contribute_forwarding(bei_1, &dpo_bei); + + BIER_TEST(!dpo_cmp(&dpo_bei, drop_dpo_get(DPO_PROTO_BIER)), + "BP:1 stacks on bier drop"); /* * give 1.1.1.1/32 a path and hence a interesting n-eos chain @@ -418,7 +409,8 @@ bier_test_mpls_spf (void) BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_1, &bfm_1_1_1_1->bfm_dpo), "Fmask via 1.1.1.1 stacks on updated non-eos of 1.1.1.1/32"); - BIER_TEST(bier_test_validate_entry(bei_1, 1, &dpo_o_bfm_1_1_1_1), + bier_entry_contribute_forwarding(bei_1, &dpo_bei); + BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1), "BP:1 stacks on fmask 1.1.1.1"); /* @@ -486,8 +478,9 @@ bier_test_mpls_spf (void) bier_table_route_add(&bt_0_0_0_256, 2, paths_1_1_1_1); bei_2 = bier_table_lookup(bier_table_get(bti), 2); - BIER_TEST(bier_test_validate_entry(bei_2, 1, &dpo_o_bfm_1_1_1_1), - "BP:2 stacks on fmask 1.1.1.1"); + bier_entry_contribute_forwarding(bei_2, &dpo_bei); + BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1), + "BP:2 stacks on fmask 1.1.1.1"); /* * now add a bit-position via a different next hop and expect to @@ -506,14 +499,10 @@ bier_test_mpls_spf (void) fib_route_path_t *paths_1_1_1_2 = NULL, path_1_1_1_2 = { .frp_addr = nh_1_1_1_2, .frp_bier_fib_index = bti, - .frp_flags = FIB_ROUTE_PATH_BIER_FMASK, + .frp_sw_if_index = ~0, }; vec_add1(path_1_1_1_2.frp_label_stack, 501); vec_add1(paths_1_1_1_2, path_1_1_1_2); - const bier_fmask_id_t bfm_id_1_1_1_2 = { - .bfmi_hdr_type = BIER_HDR_O_MPLS, - .bfmi_nh = nh_1_1_1_2, - }; index_t bei_3; mpls_label_t *out_lbl_101 = NULL; @@ -547,7 +536,7 @@ bier_test_mpls_spf (void) FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &neos_dpo_1_1_1_2); - bfmi_1_1_1_2 = bier_fmask_db_find(bti, &bfm_id_1_1_1_2); + bfmi_1_1_1_2 = bier_fmask_db_find(bti, &path_1_1_1_2); bfm_1_1_1_2 = bier_fmask_get(bfmi_1_1_1_2); BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_2, @@ -563,12 +552,14 @@ bier_test_mpls_spf (void) .fmask = bfmi_1_1_1_2, }, }; - BIER_TEST(bier_test_validate_entry(bei_3, 1, &dpo_o_bfm_1_1_1_2), - "BP:3 stacks on fmask 1.1.1.2"); + bier_entry_contribute_forwarding(bei_3, &dpo_bei); + BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_2), + "BP:2 stacks on fmask 1.1.1.2"); /* * Load-balance BP:3 over both next-hops */ + paths_1_1_1_1[0] = path_1_1_1_1; bier_table_route_add(&bt_0_0_0_256, 3, paths_1_1_1_1); BIER_TEST(bier_test_validate_entry(bei_3, 2, @@ -589,13 +580,13 @@ bier_test_mpls_spf (void) /* * Withdraw one of the via FIB and thus bring down the fmask - * expect the bier0entry forwarding to remove this from the set + * expect the bier-entry forwarding to remove this from the set */ fib_table_entry_delete(0, &pfx_1_1_1_2_s_32, FIB_SOURCE_API); - BIER_TEST(bier_test_validate_entry(bei_3, 1, - &dpo_o_bfm_1_1_1_1), - "BP:3 post 1.1.1.2 removal stacks on fmask 1.1.1.1"); + bier_entry_contribute_forwarding(bei_3, &dpo_bei); + BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1), + "BP:3 stacks on fmask 1.1.1.1"); BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[0].bier.table), 3) == bfmi_1_1_1_1), @@ -638,9 +629,10 @@ bier_test_mpls_spf (void) * remove the original 1.1.1.2 fmask from BP:3 */ bier_table_route_remove(&bt_0_0_0_256, 3, paths_1_1_1_2); - BIER_TEST(bier_test_validate_entry(bei_3, 1, - &dpo_o_bfm_1_1_1_1), + bier_entry_contribute_forwarding(bei_3, &dpo_bei); + BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1), "BP:3 stacks on fmask 1.1.1.1"); + /* * test that the ECMP choices for BP:3 have been updated */ @@ -659,7 +651,6 @@ bier_test_mpls_spf (void) bier_table_route_remove(&bt_0_0_0_256, 3, paths_1_1_1_1); bier_table_route_remove(&bt_0_0_0_256, 1, paths_1_1_1_1); - /* * delete the table */ @@ -668,6 +659,7 @@ bier_test_mpls_spf (void) /* * test resources are freed */ + dpo_reset(&dpo_bei); for (ii = 0; ii < N_BIER_ECMP_TABLES; ii++) { bier_table_ecmp_unlock(l_o_bt[ii].bier.table); @@ -769,10 +761,6 @@ bier_test_mpls_imp (void) static int bier_test_mpls_disp (void) { - /* test_main_t *tm; */ - - /* tm = &test_main; */ - /* * Add the BIER Main table */ @@ -801,8 +789,9 @@ bier_test_mpls_disp (void) */ fib_route_path_t *paths_via_disp = NULL, path_via_disp = { // .frp_addr = all-zeros + .frp_proto = DPO_PROTO_BIER, .frp_bier_fib_index = bdti1, - .frp_flags = FIB_ROUTE_PATH_BIER_FMASK, + .frp_sw_if_index = ~0, }; vec_add1(paths_via_disp, path_via_disp); @@ -811,16 +800,13 @@ bier_test_mpls_disp (void) /* * the fmask should stack on the BIER disp table */ - const bier_fmask_id_t bfm_id_0_0_0_0 = { - .bfmi_hdr_type = BIER_HDR_O_MPLS, - }; bier_fmask_t *bfm_0_0_0_0; index_t bfmi_0_0_0_0; dpo_id_t dpo_disp_tbl_1 = DPO_INVALID; bier_disp_table_contribute_forwarding(bdti1, &dpo_disp_tbl_1); - bfmi_0_0_0_0 = bier_fmask_db_find(bti, &bfm_id_0_0_0_0); + bfmi_0_0_0_0 = bier_fmask_db_find(bti, &path_via_disp); bfm_0_0_0_0 = bier_fmask_get(bfmi_0_0_0_0); BIER_TEST(!dpo_cmp(&dpo_disp_tbl_1, &bfm_0_0_0_0->bfm_dpo), @@ -842,21 +828,13 @@ bier_test_mpls_disp (void) BIER_HDR_PROTO_IPV4, rpaths); /* which should stack on a lookup in the mfib table */ - const dpo_id_t *dpo_disp_entry_lb; const dpo_id_t *dpo_disp_entry_v4; bier_disp_entry_t *bde_99; index_t bdei; bdei = bier_disp_table_lookup(bdti1, clib_host_to_net_u16(src)); bde_99 = bier_disp_entry_get(bdei); - dpo_disp_entry_lb = &bde_99->bde_fwd[BIER_HDR_PROTO_IPV4].bde_dpo; - - BIER_TEST(dpo_disp_entry_lb->dpoi_type == DPO_LOAD_BALANCE, - "BIER Disp entry stacks on LB"); - - load_balance_t *lb; - lb = load_balance_get(dpo_disp_entry_lb->dpoi_index); - dpo_disp_entry_v4 = load_balance_get_bucket_i(lb, 0); + dpo_disp_entry_v4 = &bde_99->bde_fwd[BIER_HDR_PROTO_IPV4].bde_dpo; lookup_dpo_t *lkd = lookup_dpo_get(dpo_disp_entry_v4->dpoi_index); diff --git a/src/vnet/bier/bier_types.c b/src/vnet/bier/bier_types.c index 680182de597..5c812a4557d 100644 --- a/src/vnet/bier/bier_types.c +++ b/src/vnet/bier/bier_types.c @@ -160,6 +160,35 @@ bier_hdr_proto_to_dpo (bier_hdr_proto_id_t bproto) return (DPO_PROTO_NUM); } +bier_bift_id_t +bier_bift_id_encode (bier_table_set_id_t set, + bier_table_sub_domain_id_t sd, + bier_hdr_len_id_t bsl) +{ + bier_bift_id_t id; + + id = bsl; + id = id << 8; + id |= sd; + id = id << 8; + id |= set; + + return (id); +} + +void +bier_bift_id_decode (bier_bift_id_t id, + bier_table_set_id_t *set, + bier_table_sub_domain_id_t *sd, + bier_hdr_len_id_t *bsl) +{ + *set = id & 0xff; + id = id >> 8; + *sd = id & 0xff; + id = id >> 8; + *bsl = id; +} + u8 * format_bier_table_id (u8 *s, va_list *ap) { @@ -188,3 +217,17 @@ format_bier_hdr (u8 *s, va_list *ap) format_bier_hdr_proto, bier_hdr_get_proto_id(©), bier_hdr_get_src_id(©))); } + + u8* + format_bier_bift_id(u8 *s, va_list *ap) + { + bier_bift_id_t id = va_arg(*ap, bier_bift_id_t); + bier_table_sub_domain_id_t sd; + bier_table_set_id_t set; + bier_hdr_len_id_t bsl; + + bier_bift_id_decode(id, &set, &sd, &bsl); + + return (format(s, "0x%x -> set:%d sd:%d hdr-len:%U", + id, set, sd, format_bier_hdr_len_id, bsl)); + } diff --git a/src/vnet/bier/bier_types.h b/src/vnet/bier/bier_types.h index fa1cd423278..d484ba9ed03 100644 --- a/src/vnet/bier/bier_types.h +++ b/src/vnet/bier/bier_types.h @@ -504,4 +504,32 @@ extern u32 bier_hdr_len_id_to_prefix_len(bier_hdr_len_id_t id); #define BIER_ERR_PANIC 3 typedef int bier_rc; +/** + * The BIER universal 'label' + */ +typedef u32 bier_bift_id_t; + +/** + * An invalid value for the BIFT ID + * all ones implies a BSL that's invalid. + */ +#define BIER_BIFT_ID_INVALID (~0) + +extern u16 bier_bfit_id_get_sub_domain(bier_bift_id_t bift_id); +extern u16 bier_bfit_id_get_set(bier_bift_id_t bift_id); +extern bier_hdr_proto_id_t bier_bift_id_get_bit_string_length(bier_bift_id_t bift_id); + +/** + * Encode a BIFT-ID as per draft-wijnandsxu-bier-non-mpls-bift-encoding-00.txt + */ +extern bier_bift_id_t bier_bift_id_encode(bier_table_set_id_t set, + bier_table_sub_domain_id_t sd, + bier_hdr_len_id_t bsl); +extern void bier_bift_id_decode(bier_bift_id_t id, + bier_table_set_id_t *set, + bier_table_sub_domain_id_t *sd, + bier_hdr_len_id_t *bsl); + +extern u8* format_bier_bift_id(u8 *s, va_list *ap); + #endif /* __BIER_TYPES_H__ */ diff --git a/src/vnet/bier/bier_update.c b/src/vnet/bier/bier_update.c index c66090f3cba..326f8bf3f0b 100644 --- a/src/vnet/bier/bier_update.c +++ b/src/vnet/bier/bier_update.c @@ -32,6 +32,8 @@ vnet_bier_table_cmd (vlib_main_t * vm, }; u32 is_add = 0; + local_label = MPLS_LABEL_INVALID; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "del")) { is_add = 0; @@ -66,7 +68,7 @@ done: VLIB_CLI_COMMAND (bier_table_command) = { .path = "bier table", - .short_help = "Add/delete BIER Tables", + .short_help = "bier table [add|del] sd <sub-domain> set <SET> bsl <bit-string-length> [mpls <label>]", .function = vnet_bier_table_cmd, }; @@ -81,6 +83,7 @@ vnet_bier_route_cmd (vlib_main_t * vm, }; u32 hdr_len, payload_proto; bier_table_id_t bti = { + .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN, }; bier_bp_t bp; u32 add = 1; @@ -90,6 +93,8 @@ vnet_bier_route_cmd (vlib_main_t * vm, while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "del")) { add = 0; + } else if (unformat (input, "add")) { + add = 1; } else if (unformat (input, "sd %d", &bti.bti_sub_domain)) { } else if (unformat (input, "set %d", &bti.bti_set)) { } else if (unformat (input, "bsl %d", &hdr_len)) { @@ -110,11 +115,11 @@ vnet_bier_route_cmd (vlib_main_t * vm, if (add) { - bier_table_route_add(&bti, bp, &brp); + bier_table_route_add(&bti, bp, brps); } else { - bier_table_route_remove(&bti, bp, &brp); + bier_table_route_remove(&bti, bp, brps); } done: @@ -124,7 +129,7 @@ done: VLIB_CLI_COMMAND (bier_route_command) = { .path = "bier route", - .short_help = "bier route sd <sud-domain> set <set> bsl <bit-string-length> bp <bit-position> via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]", + .short_help = "bier route [add|del] sd <sud-domain> set <set> bsl <bit-string-length> bp <bit-position> via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]", .function = vnet_bier_route_cmd, }; diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 50b94f7ff2d..8cb55454462 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -92,7 +92,6 @@ _(map) \ _(map_t) \ _(ip_frag) \ _(mpls) \ -_(bier) \ _(tcp) /* @@ -168,18 +167,17 @@ typedef struct u8 ttl; u8 exp; u8 first; + /* + * BIER - the nubmer of bytes in the header. + * the len field inthe header is not authoritative. It's the + * value in the table that counts. + */ + struct + { + u8 n_bytes; + } bier; } mpls; - /* - * BIER - the nubmer of bytes in the header. - * the len field inthe header is not authoritative. It's the - * value in the table that counts. - */ - struct - { - u8 n_bytes; - } bier; - /* ip4-in-ip6 softwire termination, only valid there */ struct { diff --git a/src/vnet/dpo/load_balance.c b/src/vnet/dpo/load_balance.c index 807455597f8..db0ebcdceb8 100644 --- a/src/vnet/dpo/load_balance.c +++ b/src/vnet/dpo/load_balance.c @@ -198,6 +198,16 @@ load_balance_create (u32 n_buckets, return (load_balance_get_index(load_balance_create_i(n_buckets, lb_proto, fhc))); } +u16 +load_balance_n_buckets (index_t lbi) +{ + load_balance_t *lb; + + lb = load_balance_get(lbi); + + return (lb->lb_n_buckets); +} + static inline void load_balance_set_bucket_i (load_balance_t *lb, u32 bucket, diff --git a/src/vnet/dpo/load_balance.h b/src/vnet/dpo/load_balance.h index b901c5beb84..d37f07d579f 100644 --- a/src/vnet/dpo/load_balance.h +++ b/src/vnet/dpo/load_balance.h @@ -182,6 +182,7 @@ extern u8* format_load_balance(u8 * s, va_list * args); extern const dpo_id_t *load_balance_get_bucket(index_t lbi, u32 bucket); extern int load_balance_is_drop(const dpo_id_t *dpo); +extern u16 load_balance_n_buckets(index_t lbi); extern f64 load_balance_get_multipath_tolerance(void); diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c index 214dafe9b8d..1d73af3bf0d 100644 --- a/src/vnet/fib/fib_entry_src.c +++ b/src/vnet/fib/fib_entry_src.c @@ -1321,6 +1321,7 @@ fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index, fib_path_list_contribute_forwarding( esrc->fes_pl, fib_entry_get_default_chain_type(fib_entry), + FIB_PATH_LIST_FWD_FLAG_NONE, dpo); return (dpo_id_is_valid(dpo)); diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index c6677fb12f2..8d738c2b727 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -41,6 +41,7 @@ #include <vnet/bier/bier_fmask.h> #include <vnet/bier/bier_table.h> #include <vnet/bier/bier_imp.h> +#include <vnet/bier/bier_disp_table.h> /** * Enurmeration of path types @@ -286,13 +287,9 @@ typedef struct fib_path_t_ { } recursive; struct { /** - * The next-hop + * BIER FMask ID */ - ip46_address_t fp_nh; - /** - * The BIER FIB the fmask is in - */ - index_t fp_bier_fib; + index_t fp_bier_fmask; } bier_fmask; struct { /** @@ -369,13 +366,13 @@ typedef struct fib_path_t_ { */ fib_node_index_t fp_via_fib; /** - * the resolving bier-fmask - */ - index_t fp_via_bier_fmask; - /** * the resolving bier-table */ index_t fp_via_bier_tbl; + /** + * the resolving bier-fmask + */ + index_t fp_via_bier_fmask; }; /** @@ -409,8 +406,8 @@ static fib_path_t *fib_path_pool; { \ u8 *_tmp = NULL; \ _tmp = fib_path_format(fib_path_get_index(_p), _tmp); \ - clib_warning("path:[%d:%s]:" _fmt, \ - fib_path_get_index(_p), _tmp, \ + clib_warning("path:[%d:%U]:" _fmt, \ + fib_path_get_index(_p), format_fib_path, _p, 0,\ ##_args); \ vec_free(_tmp); \ } @@ -446,12 +443,17 @@ fib_path_from_fib_node (fib_node_t *node) u8 * format_fib_path (u8 * s, va_list * args) { - fib_path_t *path = va_arg (*args, fib_path_t *); + fib_node_index_t path_index = va_arg (*args, fib_node_index_t); + u32 indent = va_arg (*args, u32); vnet_main_t * vnm = vnet_get_main(); fib_path_oper_attribute_t oattr; fib_path_cfg_attribute_t cattr; + fib_path_t *path; - s = format (s, " index:%d ", fib_path_get_index(path)); + path = fib_path_get(path_index); + + s = format (s, "%Upath:[%d] ", format_white_space, indent, + fib_path_get_index(path)); s = format (s, "pl-index:%d ", path->fp_pl_index); s = format (s, "%U ", format_dpo_proto, path->fp_nh_proto); s = format (s, "weight=%d ", path->fp_weight); @@ -473,7 +475,7 @@ format_fib_path (u8 * s, va_list * args) } } } - s = format(s, "\n "); + s = format(s, "\n%U", format_white_space, indent+2); switch (path->fp_type) { @@ -501,19 +503,20 @@ format_fib_path (u8 * s, va_list * args) } if (!dpo_id_is_valid(&path->fp_dpo)) { - s = format(s, "\n unresolved"); + s = format(s, "\n%Uunresolved", format_white_space, indent+2); } else { - s = format(s, "\n %U", - format_dpo_id, + s = format(s, "\n%U%U", + format_white_space, indent, + format_dpo_id, &path->fp_dpo, 13); } break; case FIB_PATH_TYPE_ATTACHED: if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP) { - s = format (s, " if_index:%d", path->attached_next_hop.fp_interface); + s = format (s, "if_index:%d", path->attached_next_hop.fp_interface); } else { @@ -551,7 +554,7 @@ format_fib_path (u8 * s, va_list * args) break; case FIB_PATH_TYPE_UDP_ENCAP: - s = format (s, " UDP-encap ID:%d", path->udp_encap.fp_udp_encap_id); + s = format (s, "UDP-encap ID:%d", path->udp_encap.fp_udp_encap_id); break; case FIB_PATH_TYPE_BIER_TABLE: s = format (s, "via bier-table:[%U}", @@ -562,14 +565,7 @@ format_fib_path (u8 * s, va_list * args) path->fp_dpo.dpoi_index); break; case FIB_PATH_TYPE_BIER_FMASK: - s = format (s, "via %U", - format_ip46_address, - &path->bier_fmask.fp_nh, - IP46_TYPE_ANY); - s = format (s, " in BIER-fib:%d", - path->bier_fmask.fp_bier_fib, - path->fp_via_fib); - s = format (s, " via-fmask:%d", path->fp_via_bier_fmask); + s = format (s, "via-fmask:%d", path->bier_fmask.fp_bier_fmask); s = format (s, " via-dpo:[%U:%d]", format_dpo_type, path->fp_dpo.dpoi_type, path->fp_dpo.dpoi_index); @@ -586,7 +582,7 @@ format_fib_path (u8 * s, va_list * args) if (dpo_id_is_valid(&path->fp_dpo)) { s = format(s, "%U", format_dpo_id, - &path->fp_dpo, 2); + &path->fp_dpo, indent+2); } break; } @@ -604,29 +600,6 @@ fib_path_format (fib_node_index_t pi, u8 *s) return (format (s, "%U", format_fib_path, path)); } -u8 * -fib_path_adj_format (fib_node_index_t pi, - u32 indent, - u8 *s) -{ - fib_path_t *path; - - path = fib_path_get(pi); - ASSERT(NULL != path); - - if (!dpo_id_is_valid(&path->fp_dpo)) - { - s = format(s, " unresolved"); - } - else - { - s = format(s, "%U", format_dpo_id, - &path->fp_dpo, 2); - } - - return (s); -} - /* * fib_path_last_lock_gone * @@ -832,7 +805,7 @@ static void fib_path_bier_fmask_update (fib_path_t *path, dpo_id_t *dpo) { - bier_fmask_contribute_forwarding(path->fp_via_bier_fmask, dpo); + bier_fmask_contribute_forwarding(path->bier_fmask.fp_bier_fmask, dpo); /* * if we are stakcing on the drop, then the path is not resolved @@ -893,12 +866,8 @@ fib_path_unresolve (fib_path_t *path) } break; case FIB_PATH_TYPE_BIER_FMASK: - if (FIB_NODE_INDEX_INVALID != path->fp_via_bier_fmask) - { - bier_fmask_child_remove(path->fp_via_bier_fmask, - path->fp_sibling); - path->fp_via_bier_fmask = FIB_NODE_INDEX_INVALID; - } + bier_fmask_child_remove(path->fp_via_bier_fmask, + path->fp_sibling); break; case FIB_PATH_TYPE_BIER_IMP: bier_imp_unlock(path->fp_dpo.dpoi_index); @@ -1313,8 +1282,7 @@ fib_path_create (fib_node_index_t pl_index, else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_FMASK) { path->fp_type = FIB_PATH_TYPE_BIER_FMASK; - path->bier_fmask.fp_nh = rpath->frp_addr; - path->bier_fmask.fp_bier_fib = rpath->frp_bier_fib_index; + path->bier_fmask.fp_bier_fmask = rpath->frp_bier_fmask; } else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP) { @@ -1549,14 +1517,8 @@ fib_path_cmp_i (const fib_path_t *path1, } break; case FIB_PATH_TYPE_BIER_FMASK: - res = ip46_address_cmp(&path1->bier_fmask.fp_nh, - &path2->bier_fmask.fp_nh); - - if (0 == res) - { - res = (path1->bier_fmask.fp_bier_fib - - path2->bier_fmask.fp_bier_fib); - } + res = (path1->bier_fmask.fp_bier_fmask - + path2->bier_fmask.fp_bier_fmask); break; case FIB_PATH_TYPE_BIER_IMP: res = (path1->bier_imp.fp_bier_imp - @@ -1691,13 +1653,7 @@ fib_path_cmp_w_route_path (fib_node_index_t path_index, } break; case FIB_PATH_TYPE_BIER_FMASK: - res = ip46_address_cmp(&path->bier_fmask.fp_nh, - &rpath->frp_addr); - - if (0 == res) - { - res = (path->bier_fmask.fp_bier_fib - rpath->frp_bier_fib_index); - } + res = (path->bier_fmask.fp_bier_fmask - rpath->frp_bier_fmask); break; case FIB_PATH_TYPE_BIER_IMP: res = (path->bier_imp.fp_bier_imp - rpath->frp_bier_imp); @@ -1944,26 +1900,14 @@ fib_path_resolve (fib_node_index_t path_index) case FIB_PATH_TYPE_BIER_FMASK: { /* - * Find the BIER f-mask to link to - */ - bier_fmask_id_t fmid = { - .bfmi_nh = path->bier_fmask.fp_nh, - .bfmi_hdr_type = BIER_HDR_O_MPLS, - }; - - ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_bier_fmask); - - path->fp_via_bier_fmask = bier_fmask_db_find(path->bier_fmask.fp_bier_fib, - &fmid); - - /* * become a dependent child of the entry so the path is * informed when the forwarding for the entry changes. */ - path->fp_sibling = bier_fmask_child_add(path->fp_via_bier_fmask, + path->fp_sibling = bier_fmask_child_add(path->bier_fmask.fp_bier_fmask, FIB_NODE_TYPE_PATH, fib_path_get_index(path)); + path->fp_via_bier_fmask = path->bier_fmask.fp_bier_fmask; fib_path_bier_fmask_update(path, &path->fp_dpo); break; @@ -1996,27 +1940,35 @@ fib_path_resolve (fib_node_index_t path_index) break; case FIB_PATH_TYPE_DEAG: { - /* - * Resolve via a lookup DPO. - * FIXME. control plane should add routes with a table ID - */ - lookup_input_t input; - lookup_cast_t cast; - - cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ? - LOOKUP_MULTICAST : - LOOKUP_UNICAST); - input = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DEAG_SRC ? - LOOKUP_INPUT_SRC_ADDR : - LOOKUP_INPUT_DST_ADDR); - - lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id, - path->fp_nh_proto, - cast, - input, - LOOKUP_TABLE_FROM_CONFIG, - &path->fp_dpo); - break; + if (DPO_PROTO_BIER == path->fp_nh_proto) + { + bier_disp_table_contribute_forwarding(path->deag.fp_tbl_id, + &path->fp_dpo); + } + else + { + /* + * Resolve via a lookup DPO. + * FIXME. control plane should add routes with a table ID + */ + lookup_input_t input; + lookup_cast_t cast; + + cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ? + LOOKUP_MULTICAST : + LOOKUP_UNICAST); + input = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DEAG_SRC ? + LOOKUP_INPUT_SRC_ADDR : + LOOKUP_INPUT_DST_ADDR); + + lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id, + path->fp_nh_proto, + cast, + input, + LOOKUP_TABLE_FROM_CONFIG, + &path->fp_dpo); + } + break; } case FIB_PATH_TYPE_RECEIVE: /* @@ -2109,7 +2061,7 @@ fib_path_get_resolving_index (fib_node_index_t path_index) case FIB_PATH_TYPE_RECURSIVE: return (path->fp_via_fib); case FIB_PATH_TYPE_BIER_FMASK: - return (path->fp_via_bier_fmask); + return (path->bier_fmask.fp_bier_fmask); case FIB_PATH_TYPE_BIER_TABLE: return (path->fp_via_bier_tbl); case FIB_PATH_TYPE_BIER_IMP: @@ -2623,8 +2575,7 @@ fib_path_encode (fib_node_index_t path_list_index, api_rpath->rpath.frp_addr = path->attached_next_hop.fp_nh; break; case FIB_PATH_TYPE_BIER_FMASK: - api_rpath->rpath.frp_fib_index = path->bier_fmask.fp_bier_fib; - api_rpath->rpath.frp_addr = path->bier_fmask.fp_nh; + api_rpath->rpath.frp_bier_fmask = path->bier_fmask.fp_bier_fmask; break; case FIB_PATH_TYPE_SPECIAL: break; @@ -2673,7 +2624,7 @@ show_fib_path_command (vlib_main_t * vm, if (!pool_is_free_index(fib_path_pool, pi)) { path = fib_path_get(pi); - u8 *s = fib_path_format(pi, NULL); + u8 *s = format(NULL, "%U", format_fib_path, pi, 1); s = format(s, "children:"); s = fib_node_children_format(path->fp_node.fn_children, s); vlib_cli_output (vm, "%s", s); diff --git a/src/vnet/fib/fib_path.h b/src/vnet/fib/fib_path.h index 861bda95933..70b2f503aa8 100644 --- a/src/vnet/fib/fib_path.h +++ b/src/vnet/fib/fib_path.h @@ -128,12 +128,7 @@ typedef enum fib_path_cfg_flags_t_ { } __attribute__ ((packed)) fib_path_cfg_flags_t; -extern u8 *fib_path_format(fib_node_index_t pi, u8 *s); -extern u8 *fib_path_adj_format(fib_node_index_t pi, - u32 indent, - u8 *s); - -extern u8 * format_fib_path(u8 * s, va_list * args); +extern u8 *format_fib_path(u8 *s, va_list *args); extern fib_node_index_t fib_path_create(fib_node_index_t pl_index, const fib_route_path_t *path); diff --git a/src/vnet/fib/fib_path_list.c b/src/vnet/fib/fib_path_list.c index 597a700a448..5201b5a14e8 100644 --- a/src/vnet/fib/fib_path_list.c +++ b/src/vnet/fib/fib_path_list.c @@ -126,16 +126,21 @@ fib_path_list_get_index (fib_path_list_t *path_list) return (path_list - fib_path_list_pool); } -static u8 * +u8 * format_fib_path_list (u8 * s, va_list * args) { + fib_node_index_t *path_index, path_list_index; fib_path_list_attribute_t attr; - fib_node_index_t *path_index; fib_path_list_t *path_list; + u32 indent; - path_list = va_arg (*args, fib_path_list_t *); - - s = format (s, " index:%u", fib_path_list_get_index(path_list)); + path_list_index = va_arg (*args, fib_node_index_t); + indent = va_arg (*args, u32); + path_list = fib_path_list_get(path_list_index); + + s = format (s, "%Upath-list:[%d]", + format_white_space, indent, + fib_path_list_get_index(path_list)); s = format (s, " locks:%u", path_list->fpl_node.fn_locks); if (FIB_PATH_LIST_FLAG_NONE != path_list->fpl_flags) @@ -153,7 +158,7 @@ format_fib_path_list (u8 * s, va_list * args) vec_foreach (path_index, path_list->fpl_paths) { - s = fib_path_format(*path_index, s); + s = format(s, "%U", format_fib_path, *path_index, indent+2); s = format(s, "\n"); } @@ -164,11 +169,7 @@ u8 * fib_path_list_format (fib_node_index_t path_list_index, u8 * s) { - fib_path_list_t *path_list; - - path_list = fib_path_list_get(path_list_index); - - return (format(s, "%U", format_fib_path_list, path_list)); + return (format(s, "%U", format_fib_path_list, path_list_index, 4)); } static uword @@ -353,20 +354,7 @@ fib_path_list_mk_lb (fib_path_list_t *path_list, load_balance_path_t *nhs; fib_node_index_t *path_index; - nhs = NULL; - - if (!dpo_id_is_valid(dpo)) - { - /* - * first time create - */ - dpo_set(dpo, - DPO_LOAD_BALANCE, - fib_forw_chain_type_to_dpo_proto(fct), - load_balance_create(0, - fib_forw_chain_type_to_dpo_proto(fct), - 0 /* FIXME FLOW HASH */)); - } + nhs = NULL; /* * We gather the DPOs from resolved paths. @@ -382,6 +370,12 @@ fib_path_list_mk_lb (fib_path_list_t *path_list, * Path-list load-balances, which if used, would be shared and hence * never need a load-balance map. */ + dpo_set(dpo, + DPO_LOAD_BALANCE, + fib_forw_chain_type_to_dpo_proto(fct), + load_balance_create(vec_len(nhs), + fib_forw_chain_type_to_dpo_proto(fct), + 0 /* FIXME FLOW HASH */)); load_balance_multipath_update(dpo, nhs, LOAD_BALANCE_FLAG_NONE); FIB_PATH_LIST_DBG(path_list, "mk lb: %d", dpo->dpoi_index); @@ -1146,6 +1140,7 @@ fib_path_list_copy_and_path_remove (fib_node_index_t orig_path_list_index, void fib_path_list_contribute_forwarding (fib_node_index_t path_list_index, fib_forward_chain_type_t fct, + fib_path_list_fwd_flags_t flags, dpo_id_t *dpo) { fib_path_list_t *path_list; @@ -1153,6 +1148,18 @@ fib_path_list_contribute_forwarding (fib_node_index_t path_list_index, path_list = fib_path_list_get(path_list_index); fib_path_list_mk_lb(path_list, fct, dpo); + + ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type); + + /* + * If there's only one bucket in the load-balance then we can + * squash it out. + */ + if ((1 == load_balance_n_buckets(dpo->dpoi_index)) && + (FIB_PATH_LIST_FWD_FLAG_COLLAPSE & flags)) + { + dpo_copy(dpo, load_balance_get_bucket(dpo->dpoi_index, 0)); + } } /* diff --git a/src/vnet/fib/fib_path_list.h b/src/vnet/fib/fib_path_list.h index a54b79e2a6d..76870dc6c78 100644 --- a/src/vnet/fib/fib_path_list.h +++ b/src/vnet/fib/fib_path_list.h @@ -127,8 +127,18 @@ extern fib_node_index_t fib_path_list_path_remove ( extern u32 fib_path_list_get_n_paths(fib_node_index_t pl_index); +/** + * Flags to control how the path-list returns forwarding information + */ +typedef enum fib_path_list_fwd_flags_t_ +{ + FIB_PATH_LIST_FWD_FLAG_NONE = 0, + FIB_PATH_LIST_FWD_FLAG_COLLAPSE = (1 << 0), +} fib_path_list_fwd_flags_t; + extern void fib_path_list_contribute_forwarding(fib_node_index_t path_list_index, fib_forward_chain_type_t type, + fib_path_list_fwd_flags_t flags, dpo_id_t *dpo); extern void fib_path_list_contribute_urpf(fib_node_index_t path_index, index_t urpf); @@ -153,6 +163,8 @@ extern int fib_path_list_is_popular(fib_node_index_t path_list_index); extern dpo_proto_t fib_path_list_get_proto(fib_node_index_t path_list_index); extern u8 * fib_path_list_format(fib_node_index_t pl_index, u8 * s); +extern u8 * format_fib_path_list(u8 * s, va_list *args); + extern index_t fib_path_list_lb_map_add_or_lock(fib_node_index_t pl_index, const fib_node_index_t *pis); extern u32 fib_path_list_find_rpath (fib_node_index_t path_list_index, diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h index be6a24ee9cd..94c94228bb3 100644 --- a/src/vnet/fib/fib_types.h +++ b/src/vnet/fib/fib_types.h @@ -443,6 +443,11 @@ typedef struct fib_route_path_t_ { * UDP encap ID */ u32 frp_udp_encap_id; + + /** + * Resolving via a BIER Fmask + */ + index_t frp_bier_fmask; }; /** * [un]equal cost path weight diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index 7ed2e12cb1f..ca1e320700e 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -787,6 +787,7 @@ lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe) { fib_path_list_contribute_forwarding (lfe->l2.path_list_index, FIB_FORW_CHAIN_TYPE_ETHERNET, + FIB_PATH_LIST_FWD_FLAG_NONE, &lfe->l2.dpo); dpo_copy (&dpo, &lfe->l2.dpo); } @@ -1048,6 +1049,7 @@ lisp_gpe_nsh_update_fwding (lisp_gpe_fwd_entry_t * lfe) { fib_path_list_contribute_forwarding (lfe->nsh.path_list_index, FIB_FORW_CHAIN_TYPE_NSH, + FIB_PATH_LIST_FWD_FLAG_NONE, &lfe->nsh.dpo); /* diff --git a/src/vnet/mpls/mpls_output.c b/src/vnet/mpls/mpls_output.c index e0874cd1aa1..0dc12b8d5bd 100644 --- a/src/vnet/mpls/mpls_output.c +++ b/src/vnet/mpls/mpls_output.c @@ -24,9 +24,6 @@ typedef struct { /* Adjacency taken. */ u32 adj_index; u32 flow_hash; - - /* Packet data, possibly *after* rewrite. */ - u8 packet_data[64 - 1*sizeof(u32)]; } mpls_output_trace_t; #define foreach_mpls_output_next \ @@ -45,16 +42,11 @@ format_mpls_output_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); mpls_output_trace_t * t = va_arg (*args, mpls_output_trace_t *); - u32 indent = format_get_indent (s); s = format (s, "adj-idx %d : %U flow hash: 0x%08x", t->adj_index, format_ip_adjacency, t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash); - s = format (s, "\n%U%U", - format_white_space, indent, - format_ip_adjacency_packet_data, - t->adj_index, t->packet_data, sizeof (t->packet_data)); return s; } @@ -206,9 +198,6 @@ mpls_output_inline (vlib_main_t * vm, p0, sizeof (*tr)); tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX]; tr->flow_hash = vnet_buffer(p0)->ip.flow_hash; - clib_memcpy (tr->packet_data, - vlib_buffer_get_current (p0), - sizeof (tr->packet_data)); } if (PREDICT_FALSE(p1->flags & VLIB_BUFFER_IS_TRACED)) { @@ -216,9 +205,6 @@ mpls_output_inline (vlib_main_t * vm, p1, sizeof (*tr)); tr->adj_index = vnet_buffer(p1)->ip.adj_index[VLIB_TX]; tr->flow_hash = vnet_buffer(p1)->ip.flow_hash; - clib_memcpy (tr->packet_data, - vlib_buffer_get_current (p1), - sizeof (tr->packet_data)); } vlib_validate_buffer_enqueue_x2 (vm, node, next_index, diff --git a/src/vnet/udp/udp.h b/src/vnet/udp/udp.h index 920ef963ace..af6c6b82c6a 100644 --- a/src/vnet/udp/udp.h +++ b/src/vnet/udp/udp.h @@ -72,6 +72,7 @@ _ (4342, lisp_cp6) \ _ (4790, VXLAN6_GPE) \ _ (6633, vpath6_3) \ _ (6081, geneve6) \ +_ (8138, BIER) \ _ (53053, dns_reply6) typedef enum diff --git a/src/vnet/udp/udp_encap.c b/src/vnet/udp/udp_encap.c index 2999d4a73ce..91d730c0ade 100644 --- a/src/vnet/udp/udp_encap.c +++ b/src/vnet/udp/udp_encap.c @@ -392,6 +392,11 @@ const static char *const udp4_encap_mpls_nodes[] = { NULL, }; +const static char *const udp4_encap_bier_nodes[] = { + "udp4-encap", + NULL, +}; + const static char *const udp6_encap_ip4_nodes[] = { "udp6-encap", NULL, @@ -407,16 +412,23 @@ const static char *const udp6_encap_mpls_nodes[] = { NULL, }; +const static char *const udp6_encap_bier_nodes[] = { + "udp6-encap", + NULL, +}; + const static char *const *const udp4_encap_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP4] = udp4_encap_ip4_nodes, [DPO_PROTO_IP6] = udp4_encap_ip6_nodes, [DPO_PROTO_MPLS] = udp4_encap_mpls_nodes, + [DPO_PROTO_BIER] = udp4_encap_bier_nodes, }; const static char *const *const udp6_encap_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP4] = udp6_encap_ip4_nodes, [DPO_PROTO_IP6] = udp6_encap_ip6_nodes, [DPO_PROTO_MPLS] = udp6_encap_mpls_nodes, + [DPO_PROTO_BIER] = udp6_encap_bier_nodes, }; /* @@ -433,7 +445,6 @@ const static dpo_vft_t udp_encap_dpo_vft = { .dv_lock = udp_encap_dpo_lock, .dv_unlock = udp_encap_dpo_unlock, .dv_format = format_udp_encap_dpo, - //.dv_mem_show = replicate_mem_show, }; clib_error_t * diff --git a/test/patches/scapy-2.3.3/bier.patch b/test/patches/scapy-2.3.3/bier.patch index 024805d0501..50814d41315 100644 --- a/test/patches/scapy-2.3.3/bier.patch +++ b/test/patches/scapy-2.3.3/bier.patch @@ -3,7 +3,7 @@ new file mode 100644 index 0000000..e173cdb --- /dev/null +++ b/scapy/contrib/bier.py -@@ -0,0 +1,39 @@ +@@ -0,0 +1,53 @@ +# http://trac.secdev.org/scapy/ticket/31 + +# scapy.contrib.description = MPLS @@ -11,7 +11,7 @@ index 0000000..e173cdb + +from scapy.packet import * +from scapy.fields import * -+from scapy.layers.inet import IP ++from scapy.layers.inet import IP, UDP +from scapy.layers.inet6 import IPv6 + +class BIERLength: @@ -20,12 +20,25 @@ index 0000000..e173cdb + BIER_LEN_256 = 2 + + -+ +BIERnhcls = { 1: "MPLS", + 2: "MPLS", + 4: "IPv4", + 5: "IPv6" } + ++ ++class BIFT(Packet): ++ name = "BIFT" ++ fields_desc = [ BitField("bsl", 0, 4), ++ BitField("sd", 0, 8), ++ BitField("set", 0, 8), ++ BitField("cos", 0, 3), ++ BitField("s", 1, 1), ++ ByteField("ttl", 0) ] ++ ++ def guess_payload_class(self, payload): ++ return BIER ++ ++ +class BIER(Packet): + name = "BIER" + fields_desc = [ BitField("id", 5, 4), @@ -43,3 +56,4 @@ index 0000000..e173cdb + +bind_layers(BIER, IP, Proto=4) +bind_layers(BIER, IPv6, Proto=5) ++bind_layers(UDP, BIFT, dport=8138) diff --git a/test/test_bier.py b/test/test_bier.py index 1a4567bd656..48d0a297ca6 100644 --- a/test/test_bier.py +++ b/test/test_bier.py @@ -8,6 +8,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \ VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \ MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto from vpp_bier import * +from vpp_udp_encap import * from scapy.packet import Raw from scapy.layers.l2 import Ether @@ -78,6 +79,7 @@ class TestBier(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = output.get_capture(len(pkts)) + return rx def test_bier_midpoint(self): """BIER midpoint""" @@ -119,7 +121,9 @@ class TestBier(VppTestCase): labels=[2000+i])])) nh_routes[-1].add_vpp_config() - bier_routes.append(VppBierRoute(self, bti, i, nh, 100+i)) + bier_routes.append(VppBierRoute(self, bti, i, + [VppRoutePath(nh, 0xffffffff, + labels=[100+i])])) bier_routes[-1].add_vpp_config() # @@ -150,6 +154,7 @@ class TestBier(VppTestCase): blabel = olabel[MPLS].payload self.assertEqual(blabel.label, 100+bp) + self.assertEqual(blabel.ttl, 254) bier_hdr = blabel[MPLS].payload @@ -203,8 +208,12 @@ class TestBier(VppTestCase): ip_route_1.add_vpp_config() ip_route_2.add_vpp_config() - bier_route_1 = VppBierRoute(self, bti, 1, nh1, 101) - bier_route_2 = VppBierRoute(self, bti, 2, nh2, 102) + bier_route_1 = VppBierRoute(self, bti, 1, + [VppRoutePath(nh1, 0xffffffff, + labels=[101])]) + bier_route_2 = VppBierRoute(self, bti, 2, + [VppRoutePath(nh2, 0xffffffff, + labels=[102])]) bier_route_1.add_vpp_config() bier_route_2.add_vpp_config() @@ -231,7 +240,7 @@ class TestBier(VppTestCase): route_ing_232_1_1_1.add_vpp_config() # - # inject a packet an IP. We expect it to be BIER encapped, + # inject an IP packet. We expect it to be BIER encapped and # replicated. # p = (Ether(dst=self.pg0.local_mac, @@ -245,6 +254,29 @@ class TestBier(VppTestCase): rx = self.pg1.get_capture(2) + # + # Encap Stack is; eth, MPLS, MPLS, BIER + # + igp_mpls = rx[0][MPLS] + self.assertEqual(igp_mpls.label, 2001) + self.assertEqual(igp_mpls.ttl, 64) + self.assertEqual(igp_mpls.s, 0) + bier_mpls = igp_mpls[MPLS].payload + self.assertEqual(bier_mpls.label, 101) + self.assertEqual(bier_mpls.ttl, 64) + self.assertEqual(bier_mpls.s, 1) + self.assertEqual(rx[0][BIER].length, 2) + + igp_mpls = rx[1][MPLS] + self.assertEqual(igp_mpls.label, 2002) + self.assertEqual(igp_mpls.ttl, 64) + self.assertEqual(igp_mpls.s, 0) + bier_mpls = igp_mpls[MPLS].payload + self.assertEqual(bier_mpls.label, 102) + self.assertEqual(bier_mpls.ttl, 64) + self.assertEqual(bier_mpls.s, 1) + self.assertEqual(rx[0][BIER].length, 2) + def test_bier_tail(self): """BIER Tail""" @@ -264,8 +296,10 @@ class TestBier(VppTestCase): # # BIER route in table that's for-us # - bier_route_1 = VppBierRoute(self, bti, 1, "0.0.0.0", 0, - disp_table=8) + bier_route_1 = VppBierRoute(self, bti, 1, + [VppRoutePath("0.0.0.0", + 0xffffffff, + nh_table_id=8)]) bier_route_1.add_vpp_config() # @@ -344,9 +378,10 @@ class TestBier(VppTestCase): # BIER route in table that's for-us, resolving through # disp table 8. # - bier_route_1 = VppBierRoute(self, bti, 1, "0.0.0.0", - MPLS_LABEL_INVALID, - disp_table=8) + bier_route_1 = VppBierRoute(self, bti, 1, + [VppRoutePath("0.0.0.0", + 0xffffffff, + nh_table_id=8)]) bier_route_1.add_vpp_config() # @@ -383,7 +418,155 @@ class TestBier(VppTestCase): IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234)) - self.send_and_expect(self.pg0, p*65, self.pg1) + rx = self.send_and_expect(self.pg0, p*65, self.pg1) + + # + # should be IP + # + self.assertEqual(rx[0][IP].src, "1.1.1.1") + self.assertEqual(rx[0][IP].dst, "232.1.1.1") + + def test_bier_head_o_udp(self): + """BIER head over UDP""" + + # + # Add a BIER table for sub-domain 1, set 0, and BSL 256 + # + bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256) + bt = VppBierTable(self, bti, 77) + bt.add_vpp_config() + + # + # 1 bit positions via 1 next hops + # + nh1 = "10.0.0.1" + ip_route = VppIpRoute(self, nh1, 32, + [VppRoutePath(self.pg1.remote_ip4, + self.pg1.sw_if_index, + labels=[2001])]) + ip_route.add_vpp_config() + + udp_encap = VppUdpEncap(self, 4, + self.pg0.local_ip4, + nh1, + 330, 8138) + udp_encap.add_vpp_config() + + bier_route = VppBierRoute(self, bti, 1, + [VppRoutePath("0.0.0.0", + 0xFFFFFFFF, + is_udp_encap=1, + next_hop_id=4)]) + bier_route.add_vpp_config() + + # + # An imposition object with all bit-positions set + # + bi = VppBierImp(self, bti, 333, chr(0xff) * 32) + bi.add_vpp_config() + + # + # Add a multicast route that will forward into the BIER doamin + # + route_ing_232_1_1_1 = VppIpMRoute( + self, + "0.0.0.0", + "232.1.1.1", 32, + MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, + paths=[VppMRoutePath(self.pg0.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), + VppMRoutePath(0xffffffff, + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD, + proto=DpoProto.DPO_PROTO_BIER, + bier_imp=bi.bi_index)]) + route_ing_232_1_1_1.add_vpp_config() + + # + # inject a packet an IP. We expect it to be BIER and UDP encapped, + # + p = (Ether(dst=self.pg0.local_mac, + src=self.pg0.remote_mac) / + IP(src="1.1.1.1", dst="232.1.1.1") / + UDP(sport=1234, dport=1234)) + + self.pg0.add_stream([p]) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + + # + # Encap Stack is, eth, IP, UDP, BIFT, BIER + # + self.assertEqual(rx[0][IP].src, self.pg0.local_ip4) + self.assertEqual(rx[0][IP].dst, nh1) + self.assertEqual(rx[0][UDP].sport, 330) + self.assertEqual(rx[0][UDP].dport, 8138) + self.assertEqual(rx[0][BIFT].bsl, 2) + self.assertEqual(rx[0][BIFT].sd, 1) + self.assertEqual(rx[0][BIFT].set, 0) + self.assertEqual(rx[0][BIFT].ttl, 64) + self.assertEqual(rx[0][BIER].length, 2) + + def test_bier_tail_o_udp(self): + """BIER Tail over UDP""" + + # + # Add a BIER table for sub-domain 0, set 0, and BSL 256 + # + bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256) + bt = VppBierTable(self, bti, MPLS_LABEL_INVALID) + bt.add_vpp_config() + + # + # disposition table + # + bdt = VppBierDispTable(self, 8) + bdt.add_vpp_config() + + # + # BIER route in table that's for-us + # + bier_route_1 = VppBierRoute(self, bti, 1, + [VppRoutePath("0.0.0.0", + 0xffffffff, + nh_table_id=8)]) + bier_route_1.add_vpp_config() + + # + # An entry in the disposition table + # + bier_de_1 = VppBierDispEntry(self, bdt.id, 99, + BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4, + "0.0.0.0", 0, rpf_id=8192) + bier_de_1.add_vpp_config() + + # + # A multicast route to forward post BIER disposition + # + route_eg_232_1_1_1 = VppIpMRoute( + self, + "0.0.0.0", + "232.1.1.1", 32, + MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, + paths=[VppMRoutePath(self.pg1.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)]) + route_eg_232_1_1_1.add_vpp_config() + route_eg_232_1_1_1.update_rpf_id(8192) + + # + # A packet with all bits set gets spat out to BP:1 + # + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=333, dport=8138) / + BIFT(sd=1, set=0, bsl=2, ttl=255) / + BIER(length=BIERLength.BIER_LEN_256, BFRID=99) / + IP(src="1.1.1.1", dst="232.1.1.1") / + UDP(sport=1234, dport=1234) / + Raw()) + + rx = self.send_and_expect(self.pg0, [p], self.pg1) if __name__ == '__main__': diff --git a/test/vpp_bier.py b/test/vpp_bier.py index 58c4f7248da..328d4f03eb5 100644 --- a/test/vpp_bier.py +++ b/test/vpp_bier.py @@ -4,6 +4,7 @@ import socket from vpp_object import VppObject +from vpp_ip_route import MPLS_LABEL_INVALID, VppRoutePath class BIER_HDR_PAYLOAD: @@ -18,7 +19,7 @@ class BIER_HDR_PAYLOAD: class VppBierTableID(): - def __init__(self, set_id, sub_domain_id, hdr_len_id): + def __init__(self, sub_domain_id, set_id, hdr_len_id): self.set_id = set_id self.sub_domain_id = sub_domain_id self.hdr_len_id = hdr_len_id @@ -113,22 +114,17 @@ class VppBierRoute(VppObject): BIER route """ - def __init__(self, test, tbl_id, bp, nh, out_label, - disp_table=0): + def __init__(self, test, tbl_id, bp, paths): self._test = test self.tbl_id = tbl_id - self.out_label = out_label self.bp = bp - self.disp_table = disp_table - self.nh = socket.inet_pton(socket.AF_INET, nh) + self.paths = paths def add_vpp_config(self): self._test.vapi.bier_route_add_del( self.tbl_id, self.bp, - self.nh, - self.out_label, - self.disp_table, + self.paths, is_add=1) self._test.registry.register(self, self._test.logger) @@ -136,9 +132,7 @@ class VppBierRoute(VppObject): self._test.vapi.bier_route_add_del( self.tbl_id, self.bp, - self.nh, - self.out_label, - self.disp_table, + self.paths, is_add=0) def __str__(self): diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index f8bca821631..c4b1601eb42 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -2701,24 +2701,28 @@ class VppPapiProvider(object): def bier_route_add_del(self, bti, bp, - next_hop, - next_hop_label, - next_hop_table_id, - next_hop_is_ip4=1, + paths, is_add=1): """ BIER Route add/del """ + br_paths = [] + for p in paths: + br_paths.append({'next_hop': p.nh_addr, + 'weight': 1, + 'afi': 0, + 'preference': 0, + 'table_id': p.nh_table_id, + 'next_hop_id': p.next_hop_id, + 'is_udp_encap': p.is_udp_encap, + 'n_labels': len(p.nh_labels), + 'label_stack': p.nh_labels}) return self.api( self.papi.bier_route_add_del, {'br_tbl_id': {"bt_set": bti.set_id, "bt_sub_domain": bti.sub_domain_id, "bt_hdr_len_id": bti.hdr_len_id}, 'br_bp': bp, - 'br_n_paths': 1, - 'br_paths': [{'next_hop': next_hop, - 'afi': 0, - 'n_labels': 1, - 'table_id': next_hop_table_id, - 'label_stack': [next_hop_label]}], + 'br_n_paths': len(br_paths), + 'br_paths': br_paths, 'br_is_add': is_add}) def bier_route_dump(self, bti): |