2 * mpls_fib.h: The Label/MPLS FIB
4 * Copyright (c) 2012 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * The entries in the table are programmed wtih one or more MOIs. These MOIs
21 * may result in different forwarding actions for end-of-stack (EOS) and non-EOS
22 * packets. Whether the two actions are the same more often than they are
23 * different, or vice versa, is a function of the deployment in which the router
24 * is used and thus not predictable.
25 * The desgin choice to make with an MPLS_FIB table is:
26 * 1 - 20 bit key: label only.
27 * When the EOS and non-EOS actions differ the result is a 'EOS-choice' object.
28 * 2 - 21 bit key: label and EOS-bit.
29 * The result is then the specific action based on EOS-bit.
33 * - lower memory overhead, since there are few DB entries.
35 * - slower DP performance in the case the chains differ, as more objects are
36 * encounterd in the switch path
40 * - faster DP performance
42 * - increased memory footprint.
44 * Switching between schemes based on observed/measured action similarity is not
45 * considered on the grounds of complexity and flip-flopping.
47 * VPP mantra - favour performance over memory. We choose a 21 bit key.
50 #include <vnet/fib/fib_table.h>
51 #include <vnet/fib/mpls_fib.h>
52 #include <vnet/dpo/load_balance.h>
53 #include <vnet/dpo/drop_dpo.h>
54 #include <vnet/dpo/punt_dpo.h>
55 #include <vnet/dpo/lookup_dpo.h>
56 #include <vnet/mpls/mpls.h>
59 * All lookups in an MPLS_FIB table must result in a DPO of type load-balance.
60 * This is the default result which links to drop
62 static index_t mpls_fib_drop_dpo_index = INDEX_INVALID;
67 #define MPLS_FLOW_HASH_DEFAULT 0
70 mpls_fib_entry_mk_key (mpls_label_t label,
74 return (label << 1 | eos);
78 mpls_fib_index_from_table_id (u32 table_id)
80 mpls_main_t *mm = &mpls_main;
83 p = hash_get (mm->fib_index_by_table_id, table_id);
85 return FIB_NODE_INDEX_INVALID;
91 mpls_fib_create_with_table_id (u32 table_id)
93 dpo_id_t dpo = DPO_INVALID;
94 fib_table_t *fib_table;
99 pool_get_aligned(mpls_main.fibs, fib_table, CLIB_CACHE_LINE_BYTES);
100 pool_get_aligned(mpls_main.mpls_fibs, mf, CLIB_CACHE_LINE_BYTES);
102 ASSERT((fib_table - mpls_main.fibs) ==
103 (mf - mpls_main.mpls_fibs));
105 memset(fib_table, 0, sizeof(*fib_table));
107 fib_table->ft_proto = FIB_PROTOCOL_MPLS;
108 fib_table->ft_index = (fib_table - mpls_main.fibs);
110 hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index);
112 fib_table->ft_table_id =
114 fib_table->ft_flow_hash_config =
115 MPLS_FLOW_HASH_DEFAULT;
117 fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS);
119 if (INDEX_INVALID == mpls_fib_drop_dpo_index)
121 mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0);
122 load_balance_set_bucket(mpls_fib_drop_dpo_index,
124 drop_dpo_get(DPO_PROTO_MPLS));
127 mf->mf_entries = hash_create(0, sizeof(fib_node_index_t));
128 for (i = 0; i < MPLS_FIB_DB_SIZE; i++)
131 * initialise each DPO in the data-path lookup table
132 * to be the special MPLS drop
134 mf->mf_lbs[i] = mpls_fib_drop_dpo_index;
138 * non-default forwarding for the special labels.
140 fib_prefix_t prefix = {
141 .fp_proto = FIB_PROTOCOL_MPLS,
142 .fp_payload_proto = DPO_PROTO_MPLS,
146 * PUNT the router alert, both EOS and non-eos
148 prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL;
149 FOR_EACH_MPLS_EOS_BIT(eos)
152 fib_table_entry_special_dpo_add(fib_table->ft_index,
155 FIB_ENTRY_FLAG_EXCLUSIVE,
156 punt_dpo_get(DPO_PROTO_MPLS));
160 * IPv4 explicit NULL EOS lookup in the interface's IPv4 table
162 prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
163 prefix.fp_payload_proto = DPO_PROTO_IP4;
164 prefix.fp_eos = MPLS_EOS;
166 lookup_dpo_add_or_lock_w_fib_index(0, // unused
168 LOOKUP_INPUT_DST_ADDR,
169 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
171 fib_table_entry_special_dpo_add(fib_table->ft_index,
174 FIB_ENTRY_FLAG_EXCLUSIVE,
177 prefix.fp_payload_proto = DPO_PROTO_MPLS;
178 prefix.fp_eos = MPLS_NON_EOS;
180 lookup_dpo_add_or_lock_w_fib_index(0, //unsued
182 LOOKUP_INPUT_DST_ADDR,
183 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
185 fib_table_entry_special_dpo_add(fib_table->ft_index,
188 FIB_ENTRY_FLAG_EXCLUSIVE,
192 * IPv6 explicit NULL EOS lookup in the interface's IPv6 table
194 prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
195 prefix.fp_payload_proto = DPO_PROTO_IP6;
196 prefix.fp_eos = MPLS_EOS;
198 lookup_dpo_add_or_lock_w_fib_index(0, //unused
200 LOOKUP_INPUT_DST_ADDR,
201 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
203 fib_table_entry_special_dpo_add(fib_table->ft_index,
206 FIB_ENTRY_FLAG_EXCLUSIVE,
209 prefix.fp_payload_proto = DPO_PROTO_MPLS;
210 prefix.fp_eos = MPLS_NON_EOS;
211 lookup_dpo_add_or_lock_w_fib_index(0, // unsued
213 LOOKUP_INPUT_DST_ADDR,
214 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
216 fib_table_entry_special_dpo_add(fib_table->ft_index,
219 FIB_ENTRY_FLAG_EXCLUSIVE,
222 return (fib_table->ft_index);
226 mpls_fib_table_find_or_create_and_lock (u32 table_id)
230 index = mpls_fib_index_from_table_id(table_id);
232 return mpls_fib_create_with_table_id(table_id);
234 fib_table_lock(index, FIB_PROTOCOL_MPLS);
239 mpls_fib_table_create_and_lock (void)
241 return (mpls_fib_create_with_table_id(~0));
245 mpls_fib_table_destroy (u32 fib_index)
247 fib_table_t *fib_table = pool_elt_at_index(mpls_main.fibs, fib_index);
248 mpls_fib_t *mf = pool_elt_at_index(mpls_main.mpls_fibs, fib_index);
249 fib_prefix_t prefix = {
250 .fp_proto = FIB_PROTOCOL_MPLS,
252 mpls_label_t special_labels[] = {
253 MPLS_IETF_ROUTER_ALERT_LABEL,
254 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
255 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL,
260 for (ii = 0; ii < ARRAY_LEN(special_labels); ii++)
262 FOR_EACH_MPLS_EOS_BIT(eos)
264 prefix.fp_label = special_labels[ii];
267 fib_table_entry_delete(fib_table->ft_index,
272 if (~0 != fib_table->ft_table_id)
274 hash_unset(mpls_main.fib_index_by_table_id,
275 fib_table->ft_table_id);
277 hash_free(mf->mf_entries);
279 pool_put(mpls_main.mpls_fibs, mf);
280 pool_put(mpls_main.fibs, fib_table);
284 mpls_fib_table_lookup (const mpls_fib_t *mf,
290 p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
293 return FIB_NODE_INDEX_INVALID;
299 mpls_fib_table_entry_insert (mpls_fib_t *mf,
302 fib_node_index_t lfei)
304 hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei);
308 mpls_fib_table_entry_remove (mpls_fib_t *mf,
312 hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
316 mpls_fib_forwarding_table_update (mpls_fib_t *mf,
323 ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type);
325 key = mpls_fib_entry_mk_key(label, eos);
327 mf->mf_lbs[key] = dpo->dpoi_index;
331 mpls_fib_forwarding_table_reset (mpls_fib_t *mf,
337 key = mpls_fib_entry_mk_key(label, eos);
339 mf->mf_lbs[key] = mpls_fib_drop_dpo_index;
343 mpls_fib_table_get_flow_hash_config (u32 fib_index)
350 mpls_fib_table_walk (mpls_fib_t *mpls_fib,
351 fib_table_walk_fn_t fn,
354 fib_node_index_t lfei;
357 hash_foreach(key, lfei, mpls_fib->mf_entries,
364 mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
367 fib_node_index_t lfei, *lfeip, *lfeis = NULL;
370 hash_foreach(key, lfei, mpls_fib->mf_entries,
372 vec_add1(lfeis, lfei);
375 vec_sort_with_function(lfeis, fib_entry_cmp_for_sort);
377 vec_foreach(lfeip, lfeis)
379 vlib_cli_output (vm, "%U",
380 format_fib_entry, *lfeip,
381 FIB_ENTRY_FORMAT_DETAIL);
387 mpls_fib_table_show_one (const mpls_fib_t *mpls_fib,
391 fib_node_index_t lfei;
394 FOR_EACH_MPLS_EOS_BIT(eos)
396 lfei = mpls_fib_table_lookup(mpls_fib, label, eos);
398 if (FIB_NODE_INDEX_INVALID != lfei)
400 vlib_cli_output (vm, "%U",
401 format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL);
406 static clib_error_t *
407 mpls_fib_show (vlib_main_t * vm,
408 unformat_input_t * input,
409 vlib_cli_command_t * cmd)
411 fib_table_t * fib_table;
416 label = MPLS_LABEL_INVALID;
418 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
420 /* if (unformat (input, "brief") || unformat (input, "summary") */
421 /* || unformat (input, "sum")) */
424 if (unformat (input, "%d", &label))
426 else if (unformat (input, "table %d", &table_id))
432 pool_foreach (fib_table, mpls_main.fibs,
434 if (table_id >= 0 && table_id != fib_table->ft_table_id)
437 vlib_cli_output (vm, "%v, fib_index %d",
438 fib_table->ft_desc, mpls_main.fibs - fib_table);
440 if (MPLS_LABEL_INVALID == label)
442 mpls_fib_table_show_all(mpls_fib_get(fib_table->ft_index), vm);
446 mpls_fib_table_show_one(mpls_fib_get(fib_table->ft_index), label, vm);
453 VLIB_CLI_COMMAND (mpls_fib_show_command, static) = {
454 .path = "show mpls fib",
455 .short_help = "show mpls fib [summary] [table <n>]",
456 .function = mpls_fib_show,