
- the flow hash config is (and was) cached on the load-balance object so the fib_table_t struct is not used a switch time. Therefore changes to the table's flow hash config need to be propagated to all load-balances and hance all FIB entries in the table. - enable API for setting the IPv6 table flow hash config - use only the hash config in the fib_table_t object and not on the ipX_fib_t - add tests. Change-Id: Ib804c11162c6d4972c764957562c372f663e05d4 Signed-off-by: Neale Ranns <nranns@cisco.com>
455 lines
12 KiB
C
455 lines
12 KiB
C
/*
|
|
* 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/fib/mpls_fib.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;
|
|
|
|
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);
|
|
pool_get_aligned(mpls_main.mpls_fibs, mf, CLIB_CACHE_LINE_BYTES);
|
|
|
|
ASSERT((fib_table - mpls_main.fibs) ==
|
|
(mf - mpls_main.mpls_fibs));
|
|
|
|
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_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->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_UNICAST,
|
|
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_UNICAST,
|
|
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_UNICAST,
|
|
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_UNICAST,
|
|
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 (u32 fib_index)
|
|
{
|
|
fib_table_t *fib_table = pool_elt_at_index(mpls_main.fibs, fib_index);
|
|
mpls_fib_t *mf = pool_elt_at_index(mpls_main.mpls_fibs, fib_index);
|
|
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_free(mf->mf_entries);
|
|
|
|
pool_put(mpls_main.mpls_fibs, mf);
|
|
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) ||
|
|
(DPO_REPLICATE == dpo->dpoi_type));
|
|
if (CLIB_DEBUG > 0)
|
|
{
|
|
if (DPO_REPLICATE == dpo->dpoi_type)
|
|
ASSERT(dpo->dpoi_index & MPLS_IS_REPLICATE);
|
|
if (DPO_LOAD_BALANCE == dpo->dpoi_type)
|
|
ASSERT(!(dpo->dpoi_index & MPLS_IS_REPLICATE));
|
|
}
|
|
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;
|
|
}
|
|
|
|
void
|
|
mpls_fib_table_walk (mpls_fib_t *mpls_fib,
|
|
fib_table_walk_fn_t fn,
|
|
void *ctx)
|
|
{
|
|
fib_node_index_t lfei;
|
|
mpls_label_t key;
|
|
|
|
hash_foreach(key, lfei, mpls_fib->mf_entries,
|
|
({
|
|
fn(lfei, ctx);
|
|
}));
|
|
}
|
|
|
|
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(mpls_fib_get(fib_table->ft_index), vm);
|
|
}
|
|
else
|
|
{
|
|
mpls_fib_table_show_one(mpls_fib_get(fib_table->ft_index), 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,
|
|
};
|