diff options
Diffstat (limited to 'src/vnet/fib/mpls_fib.c')
-rw-r--r-- | src/vnet/fib/mpls_fib.c | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/vnet/fib/mpls_fib.c b/src/vnet/fib/mpls_fib.c new file mode 100644 index 00000000000..6a9b1ac2989 --- /dev/null +++ b/src/vnet/fib/mpls_fib.c @@ -0,0 +1,439 @@ +/* + * mpls_fib.h: The Label/MPLS FIB + * + * Copyright (c) 2012 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. + */ +/** + * An MPLS_FIB table; + * + * The entries in the table are programmed wtih one or more MOIs. These MOIs + * may result in different forwarding actions for end-of-stack (EOS) and non-EOS + * packets. Whether the two actions are the same more often than they are + * different, or vice versa, is a function of the deployment in which the router + * is used and thus not predictable. + * The desgin choice to make with an MPLS_FIB table is: + * 1 - 20 bit key: label only. + * When the EOS and non-EOS actions differ the result is a 'EOS-choice' object. + * 2 - 21 bit key: label and EOS-bit. + * The result is then the specific action based on EOS-bit. + * + * 20 bit key: + * Advantages: + * - lower memory overhead, since there are few DB entries. + * Disadvantages: + * - slower DP performance in the case the chains differ, as more objects are + * encounterd in the switch path + * + * 21 bit key: + * Advantages: + * - faster DP performance + * Disadvantages + * - increased memory footprint. + * + * Switching between schemes based on observed/measured action similarity is not + * considered on the grounds of complexity and flip-flopping. + * + * VPP mantra - favour performance over memory. We choose a 21 bit key. + */ + +#include <vnet/fib/fib_table.h> +#include <vnet/dpo/load_balance.h> +#include <vnet/dpo/drop_dpo.h> +#include <vnet/dpo/punt_dpo.h> +#include <vnet/dpo/lookup_dpo.h> +#include <vnet/mpls/mpls.h> + +/** + * All lookups in an MPLS_FIB table must result in a DPO of type load-balance. + * This is the default result which links to drop + */ +static index_t mpls_fib_drop_dpo_index = INDEX_INVALID; + +/** + * FIXME + */ +#define MPLS_FLOW_HASH_DEFAULT 0 + +static inline u32 +mpls_fib_entry_mk_key (mpls_label_t label, + mpls_eos_bit_t eos) +{ + ASSERT(eos <= 1); + return (label << 1 | eos); +} + +u32 +mpls_fib_index_from_table_id (u32 table_id) +{ + mpls_main_t *mm = &mpls_main; + uword * p; + + p = hash_get (mm->fib_index_by_table_id, table_id); + if (!p) + return FIB_NODE_INDEX_INVALID; + + return p[0]; +} + +static u32 +mpls_fib_create_with_table_id (u32 table_id) +{ + dpo_id_t dpo = DPO_INVALID; + fib_table_t *fib_table; + mpls_eos_bit_t eos; + mpls_fib_t *mf; + int i; + + pool_get_aligned(mpls_main.fibs, fib_table, CLIB_CACHE_LINE_BYTES); + memset(fib_table, 0, sizeof(*fib_table)); + + fib_table->ft_proto = FIB_PROTOCOL_MPLS; + fib_table->ft_index = + (fib_table - mpls_main.fibs); + + hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index); + + fib_table->ft_table_id = + table_id; + fib_table->ft_flow_hash_config = + MPLS_FLOW_HASH_DEFAULT; + fib_table->v4.fwd_classify_table_index = ~0; + fib_table->v4.rev_classify_table_index = ~0; + + fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS); + + if (INDEX_INVALID == mpls_fib_drop_dpo_index) + { + mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0); + load_balance_set_bucket(mpls_fib_drop_dpo_index, + 0, + drop_dpo_get(DPO_PROTO_MPLS)); + } + + mf = &fib_table->mpls; + mf->mf_entries = hash_create(0, sizeof(fib_node_index_t)); + for (i = 0; i < MPLS_FIB_DB_SIZE; i++) + { + /* + * initialise each DPO in the data-path lookup table + * to be the special MPLS drop + */ + mf->mf_lbs[i] = mpls_fib_drop_dpo_index; + } + + /* + * non-default forwarding for the special labels. + */ + fib_prefix_t prefix = { + .fp_proto = FIB_PROTOCOL_MPLS, + .fp_payload_proto = DPO_PROTO_MPLS, + }; + + /* + * PUNT the router alert, both EOS and non-eos + */ + prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL; + FOR_EACH_MPLS_EOS_BIT(eos) + { + prefix.fp_eos = eos; + fib_table_entry_special_dpo_add(fib_table->ft_index, + &prefix, + FIB_SOURCE_SPECIAL, + FIB_ENTRY_FLAG_EXCLUSIVE, + punt_dpo_get(DPO_PROTO_MPLS)); + } + + /* + * IPv4 explicit NULL EOS lookup in the interface's IPv4 table + */ + prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL; + prefix.fp_payload_proto = DPO_PROTO_IP4; + prefix.fp_eos = MPLS_EOS; + + lookup_dpo_add_or_lock_w_fib_index(0, // unused + DPO_PROTO_IP4, + LOOKUP_INPUT_DST_ADDR, + LOOKUP_TABLE_FROM_INPUT_INTERFACE, + &dpo); + fib_table_entry_special_dpo_add(fib_table->ft_index, + &prefix, + FIB_SOURCE_SPECIAL, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + + prefix.fp_payload_proto = DPO_PROTO_MPLS; + prefix.fp_eos = MPLS_NON_EOS; + + lookup_dpo_add_or_lock_w_fib_index(0, //unsued + DPO_PROTO_MPLS, + LOOKUP_INPUT_DST_ADDR, + LOOKUP_TABLE_FROM_INPUT_INTERFACE, + &dpo); + fib_table_entry_special_dpo_add(fib_table->ft_index, + &prefix, + FIB_SOURCE_SPECIAL, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + + /* + * IPv6 explicit NULL EOS lookup in the interface's IPv6 table + */ + prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL; + prefix.fp_payload_proto = DPO_PROTO_IP6; + prefix.fp_eos = MPLS_EOS; + + lookup_dpo_add_or_lock_w_fib_index(0, //unused + DPO_PROTO_IP6, + LOOKUP_INPUT_DST_ADDR, + LOOKUP_TABLE_FROM_INPUT_INTERFACE, + &dpo); + fib_table_entry_special_dpo_add(fib_table->ft_index, + &prefix, + FIB_SOURCE_SPECIAL, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + + prefix.fp_payload_proto = DPO_PROTO_MPLS; + prefix.fp_eos = MPLS_NON_EOS; + lookup_dpo_add_or_lock_w_fib_index(0, // unsued + DPO_PROTO_MPLS, + LOOKUP_INPUT_DST_ADDR, + LOOKUP_TABLE_FROM_INPUT_INTERFACE, + &dpo); + fib_table_entry_special_dpo_add(fib_table->ft_index, + &prefix, + FIB_SOURCE_SPECIAL, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + + return (fib_table->ft_index); +} + +u32 +mpls_fib_table_find_or_create_and_lock (u32 table_id) +{ + u32 index; + + index = mpls_fib_index_from_table_id(table_id); + if (~0 == index) + return mpls_fib_create_with_table_id(table_id); + + fib_table_lock(index, FIB_PROTOCOL_MPLS); + + return (index); +} +u32 +mpls_fib_table_create_and_lock (void) +{ + return (mpls_fib_create_with_table_id(~0)); +} + +void +mpls_fib_table_destroy (mpls_fib_t *mf) +{ + fib_table_t *fib_table = (fib_table_t*)mf; + fib_prefix_t prefix = { + .fp_proto = FIB_PROTOCOL_MPLS, + }; + mpls_label_t special_labels[] = { + MPLS_IETF_ROUTER_ALERT_LABEL, + MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL, + MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL, + }; + mpls_eos_bit_t eos; + u32 ii; + + for (ii = 0; ii < ARRAY_LEN(special_labels); ii++) + { + FOR_EACH_MPLS_EOS_BIT(eos) + { + prefix.fp_label = special_labels[ii]; + prefix.fp_eos = eos; + + fib_table_entry_delete(fib_table->ft_index, + &prefix, + FIB_SOURCE_SPECIAL); + } + } + if (~0 != fib_table->ft_table_id) + { + hash_unset(mpls_main.fib_index_by_table_id, + fib_table->ft_table_id); + } + hash_delete(mf->mf_entries); + + pool_put(mpls_main.fibs, fib_table); +} + +fib_node_index_t +mpls_fib_table_lookup (const mpls_fib_t *mf, + mpls_label_t label, + mpls_eos_bit_t eos) +{ + uword *p; + + p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos)); + + if (NULL == p) + return FIB_NODE_INDEX_INVALID; + + return p[0]; +} + +void +mpls_fib_table_entry_insert (mpls_fib_t *mf, + mpls_label_t label, + mpls_eos_bit_t eos, + fib_node_index_t lfei) +{ + hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei); +} + +void +mpls_fib_table_entry_remove (mpls_fib_t *mf, + mpls_label_t label, + mpls_eos_bit_t eos) +{ + hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos)); +} + +void +mpls_fib_forwarding_table_update (mpls_fib_t *mf, + mpls_label_t label, + mpls_eos_bit_t eos, + const dpo_id_t *dpo) +{ + mpls_label_t key; + + ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type); + + key = mpls_fib_entry_mk_key(label, eos); + + mf->mf_lbs[key] = dpo->dpoi_index; +} + +void +mpls_fib_forwarding_table_reset (mpls_fib_t *mf, + mpls_label_t label, + mpls_eos_bit_t eos) +{ + mpls_label_t key; + + key = mpls_fib_entry_mk_key(label, eos); + + mf->mf_lbs[key] = mpls_fib_drop_dpo_index; +} + +flow_hash_config_t +mpls_fib_table_get_flow_hash_config (u32 fib_index) +{ + // FIXME. + return (0); +} + +static void +mpls_fib_table_show_all (const mpls_fib_t *mpls_fib, + vlib_main_t * vm) +{ + fib_node_index_t lfei, *lfeip, *lfeis = NULL; + mpls_label_t key; + + hash_foreach(key, lfei, mpls_fib->mf_entries, + ({ + vec_add1(lfeis, lfei); + })); + + vec_sort_with_function(lfeis, fib_entry_cmp_for_sort); + + vec_foreach(lfeip, lfeis) + { + vlib_cli_output (vm, "%U", + format_fib_entry, *lfeip, + FIB_ENTRY_FORMAT_DETAIL); + } + vec_free(lfeis); +} + +static void +mpls_fib_table_show_one (const mpls_fib_t *mpls_fib, + mpls_label_t label, + vlib_main_t * vm) +{ + fib_node_index_t lfei; + mpls_eos_bit_t eos; + + FOR_EACH_MPLS_EOS_BIT(eos) + { + lfei = mpls_fib_table_lookup(mpls_fib, label, eos); + + if (FIB_NODE_INDEX_INVALID != lfei) + { + vlib_cli_output (vm, "%U", + format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL); + } + } +} + +static clib_error_t * +mpls_fib_show (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + fib_table_t * fib_table; + mpls_label_t label; + int table_id; + + table_id = -1; + label = MPLS_LABEL_INVALID; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + /* if (unformat (input, "brief") || unformat (input, "summary") */ + /* || unformat (input, "sum")) */ + /* verbose = 0; */ + + if (unformat (input, "%d", &label)) + continue; + else if (unformat (input, "table %d", &table_id)) + ; + else + break; + } + + pool_foreach (fib_table, mpls_main.fibs, + ({ + if (table_id >= 0 && table_id != fib_table->ft_table_id) + continue; + + vlib_cli_output (vm, "%v, fib_index %d", + fib_table->ft_desc, mpls_main.fibs - fib_table); + + if (MPLS_LABEL_INVALID == label) + { + mpls_fib_table_show_all(&(fib_table->mpls), vm); + } + else + { + mpls_fib_table_show_one(&(fib_table->mpls), label, vm); + } + })); + + return 0; +} + +VLIB_CLI_COMMAND (mpls_fib_show_command, static) = { + .path = "show mpls fib", + .short_help = "show mpls fib [summary] [table <n>]", + .function = mpls_fib_show, +}; |