blob: 34369fc000e64a7f1d1bb9419474d5138258ca9c [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
2 * mpls_fib.h: The Label/MPLS FIB
3 *
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:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17/**
18 * An MPLS_FIB table;
19 *
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.
Nathan Skrzypczakda331052021-09-29 15:28:26 +020025 * The design choice to make with an MPLS_FIB table is:
Neale Ranns0bfe5d82016-08-25 15:29:12 +010026 * 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.
30 *
31 * 20 bit key:
32 * Advantages:
33 * - lower memory overhead, since there are few DB entries.
34 * Disadvantages:
35 * - slower DP performance in the case the chains differ, as more objects are
Nathan Skrzypczakda331052021-09-29 15:28:26 +020036 * encountered in the switch path
Neale Ranns0bfe5d82016-08-25 15:29:12 +010037 *
38 * 21 bit key:
39 * Advantages:
40 * - faster DP performance
41 * Disadvantages
42 * - increased memory footprint.
43 *
44 * Switching between schemes based on observed/measured action similarity is not
45 * considered on the grounds of complexity and flip-flopping.
46 *
Neale Ranns32e1c012016-11-22 17:07:28 +000047 * VPP mantra - favour performance over memory. We choose a 21 bit key.
Neale Ranns0bfe5d82016-08-25 15:29:12 +010048 */
49
50#include <vnet/fib/fib_table.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000051#include <vnet/fib/mpls_fib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010052#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>
57
58/**
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
61 */
62static index_t mpls_fib_drop_dpo_index = INDEX_INVALID;
63
Neale Ranns0bfe5d82016-08-25 15:29:12 +010064static inline u32
65mpls_fib_entry_mk_key (mpls_label_t label,
66 mpls_eos_bit_t eos)
67{
68 ASSERT(eos <= 1);
69 return (label << 1 | eos);
70}
71
72u32
73mpls_fib_index_from_table_id (u32 table_id)
74{
75 mpls_main_t *mm = &mpls_main;
76 uword * p;
77
78 p = hash_get (mm->fib_index_by_table_id, table_id);
79 if (!p)
80 return FIB_NODE_INDEX_INVALID;
81
82 return p[0];
83}
84
85static u32
Neale Ranns15002542017-09-10 04:39:11 -070086mpls_fib_create_with_table_id (u32 table_id,
87 fib_source_t src)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010088{
Neale Ranns948e00f2016-10-20 13:39:34 +010089 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090 fib_table_t *fib_table;
91 mpls_eos_bit_t eos;
92 mpls_fib_t *mf;
93 int i;
94
Dave Baracheb987d32018-05-03 08:26:39 -040095 pool_get(mpls_main.fibs, fib_table);
Neale Rannsa3af3372017-03-28 03:49:52 -070096 pool_get_aligned(mpls_main.mpls_fibs, mf, CLIB_CACHE_LINE_BYTES);
97
98 ASSERT((fib_table - mpls_main.fibs) ==
99 (mf - mpls_main.mpls_fibs));
100
Dave Barachb7b92992018-10-17 10:38:51 -0400101 clib_memset(fib_table, 0, sizeof(*fib_table));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100102
103 fib_table->ft_proto = FIB_PROTOCOL_MPLS;
Neale Rannsa3af3372017-03-28 03:49:52 -0700104 fib_table->ft_index = (fib_table - mpls_main.fibs);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100105
106 hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index);
107
Neale Ranns227038a2017-04-21 01:07:59 -0700108 fib_table->ft_table_id = table_id;
109 fib_table->ft_flow_hash_config = MPLS_FLOW_HASH_DEFAULT;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100110
Neale Ranns15002542017-09-10 04:39:11 -0700111 fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100112
113 if (INDEX_INVALID == mpls_fib_drop_dpo_index)
114 {
115 mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0);
116 load_balance_set_bucket(mpls_fib_drop_dpo_index,
117 0,
118 drop_dpo_get(DPO_PROTO_MPLS));
119 }
120
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100121 mf->mf_entries = hash_create(0, sizeof(fib_node_index_t));
122 for (i = 0; i < MPLS_FIB_DB_SIZE; i++)
123 {
124 /*
125 * initialise each DPO in the data-path lookup table
126 * to be the special MPLS drop
127 */
128 mf->mf_lbs[i] = mpls_fib_drop_dpo_index;
129 }
130
131 /*
132 * non-default forwarding for the special labels.
133 */
134 fib_prefix_t prefix = {
135 .fp_proto = FIB_PROTOCOL_MPLS,
136 .fp_payload_proto = DPO_PROTO_MPLS,
137 };
138
139 /*
140 * PUNT the router alert, both EOS and non-eos
141 */
142 prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL;
143 FOR_EACH_MPLS_EOS_BIT(eos)
144 {
145 prefix.fp_eos = eos;
146 fib_table_entry_special_dpo_add(fib_table->ft_index,
147 &prefix,
148 FIB_SOURCE_SPECIAL,
149 FIB_ENTRY_FLAG_EXCLUSIVE,
150 punt_dpo_get(DPO_PROTO_MPLS));
151 }
152
153 /*
154 * IPv4 explicit NULL EOS lookup in the interface's IPv4 table
155 */
156 prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
157 prefix.fp_payload_proto = DPO_PROTO_IP4;
158 prefix.fp_eos = MPLS_EOS;
159
160 lookup_dpo_add_or_lock_w_fib_index(0, // unused
161 DPO_PROTO_IP4,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800162 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100163 LOOKUP_INPUT_DST_ADDR,
164 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
165 &dpo);
166 fib_table_entry_special_dpo_add(fib_table->ft_index,
167 &prefix,
168 FIB_SOURCE_SPECIAL,
169 FIB_ENTRY_FLAG_EXCLUSIVE,
170 &dpo);
171
172 prefix.fp_payload_proto = DPO_PROTO_MPLS;
173 prefix.fp_eos = MPLS_NON_EOS;
174
175 lookup_dpo_add_or_lock_w_fib_index(0, //unsued
176 DPO_PROTO_MPLS,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800177 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100178 LOOKUP_INPUT_DST_ADDR,
179 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
180 &dpo);
181 fib_table_entry_special_dpo_add(fib_table->ft_index,
182 &prefix,
183 FIB_SOURCE_SPECIAL,
184 FIB_ENTRY_FLAG_EXCLUSIVE,
185 &dpo);
186
187 /*
188 * IPv6 explicit NULL EOS lookup in the interface's IPv6 table
189 */
190 prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
191 prefix.fp_payload_proto = DPO_PROTO_IP6;
192 prefix.fp_eos = MPLS_EOS;
193
194 lookup_dpo_add_or_lock_w_fib_index(0, //unused
195 DPO_PROTO_IP6,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800196 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100197 LOOKUP_INPUT_DST_ADDR,
198 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
199 &dpo);
200 fib_table_entry_special_dpo_add(fib_table->ft_index,
201 &prefix,
202 FIB_SOURCE_SPECIAL,
203 FIB_ENTRY_FLAG_EXCLUSIVE,
204 &dpo);
205
206 prefix.fp_payload_proto = DPO_PROTO_MPLS;
207 prefix.fp_eos = MPLS_NON_EOS;
208 lookup_dpo_add_or_lock_w_fib_index(0, // unsued
209 DPO_PROTO_MPLS,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800210 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100211 LOOKUP_INPUT_DST_ADDR,
212 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
213 &dpo);
214 fib_table_entry_special_dpo_add(fib_table->ft_index,
215 &prefix,
216 FIB_SOURCE_SPECIAL,
217 FIB_ENTRY_FLAG_EXCLUSIVE,
218 &dpo);
219
220 return (fib_table->ft_index);
221}
222
223u32
Neale Ranns15002542017-09-10 04:39:11 -0700224mpls_fib_table_find_or_create_and_lock (u32 table_id,
225 fib_source_t src)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100226{
227 u32 index;
228
229 index = mpls_fib_index_from_table_id(table_id);
230 if (~0 == index)
Neale Ranns15002542017-09-10 04:39:11 -0700231 return mpls_fib_create_with_table_id(table_id, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100232
Neale Ranns15002542017-09-10 04:39:11 -0700233 fib_table_lock(index, FIB_PROTOCOL_MPLS, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100234
235 return (index);
236}
237u32
Neale Ranns15002542017-09-10 04:39:11 -0700238mpls_fib_table_create_and_lock (fib_source_t src)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100239{
Neale Ranns15002542017-09-10 04:39:11 -0700240 return (mpls_fib_create_with_table_id(~0, src));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100241}
242
243void
Neale Rannsa3af3372017-03-28 03:49:52 -0700244mpls_fib_table_destroy (u32 fib_index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100245{
Neale Rannsa3af3372017-03-28 03:49:52 -0700246 fib_table_t *fib_table = pool_elt_at_index(mpls_main.fibs, fib_index);
247 mpls_fib_t *mf = pool_elt_at_index(mpls_main.mpls_fibs, fib_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 fib_prefix_t prefix = {
249 .fp_proto = FIB_PROTOCOL_MPLS,
250 };
251 mpls_label_t special_labels[] = {
252 MPLS_IETF_ROUTER_ALERT_LABEL,
253 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
254 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL,
255 };
256 mpls_eos_bit_t eos;
257 u32 ii;
258
259 for (ii = 0; ii < ARRAY_LEN(special_labels); ii++)
260 {
261 FOR_EACH_MPLS_EOS_BIT(eos)
262 {
263 prefix.fp_label = special_labels[ii];
264 prefix.fp_eos = eos;
265
266 fib_table_entry_delete(fib_table->ft_index,
267 &prefix,
268 FIB_SOURCE_SPECIAL);
269 }
270 }
271 if (~0 != fib_table->ft_table_id)
272 {
273 hash_unset(mpls_main.fib_index_by_table_id,
274 fib_table->ft_table_id);
275 }
Neale Rannsbcc6aa42017-02-24 01:34:14 -0800276 hash_free(mf->mf_entries);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100277
Steven Luong97866a32022-02-08 07:59:11 -0800278 vec_free (fib_table->ft_locks);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000279 vec_free(fib_table->ft_src_route_counts);
Neale Rannsa3af3372017-03-28 03:49:52 -0700280 pool_put(mpls_main.mpls_fibs, mf);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281 pool_put(mpls_main.fibs, fib_table);
282}
283
284fib_node_index_t
285mpls_fib_table_lookup (const mpls_fib_t *mf,
286 mpls_label_t label,
287 mpls_eos_bit_t eos)
288{
289 uword *p;
290
291 p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
292
293 if (NULL == p)
294 return FIB_NODE_INDEX_INVALID;
295
296 return p[0];
297}
298
299void
300mpls_fib_table_entry_insert (mpls_fib_t *mf,
301 mpls_label_t label,
302 mpls_eos_bit_t eos,
303 fib_node_index_t lfei)
304{
305 hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei);
306}
307
308void
309mpls_fib_table_entry_remove (mpls_fib_t *mf,
310 mpls_label_t label,
311 mpls_eos_bit_t eos)
312{
313 hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
314}
315
316void
317mpls_fib_forwarding_table_update (mpls_fib_t *mf,
318 mpls_label_t label,
319 mpls_eos_bit_t eos,
320 const dpo_id_t *dpo)
321{
322 mpls_label_t key;
323
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800324 ASSERT((DPO_LOAD_BALANCE == dpo->dpoi_type) ||
325 (DPO_REPLICATE == dpo->dpoi_type));
326 if (CLIB_DEBUG > 0)
327 {
328 if (DPO_REPLICATE == dpo->dpoi_type)
329 ASSERT(dpo->dpoi_index & MPLS_IS_REPLICATE);
330 if (DPO_LOAD_BALANCE == dpo->dpoi_type)
331 ASSERT(!(dpo->dpoi_index & MPLS_IS_REPLICATE));
332 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100333 key = mpls_fib_entry_mk_key(label, eos);
334
335 mf->mf_lbs[key] = dpo->dpoi_index;
336}
337
338void
339mpls_fib_forwarding_table_reset (mpls_fib_t *mf,
340 mpls_label_t label,
341 mpls_eos_bit_t eos)
342{
343 mpls_label_t key;
344
345 key = mpls_fib_entry_mk_key(label, eos);
346
347 mf->mf_lbs[key] = mpls_fib_drop_dpo_index;
348}
349
Neale Ranns32e1c012016-11-22 17:07:28 +0000350void
351mpls_fib_table_walk (mpls_fib_t *mpls_fib,
352 fib_table_walk_fn_t fn,
353 void *ctx)
354{
355 fib_node_index_t lfei;
356 mpls_label_t key;
357
358 hash_foreach(key, lfei, mpls_fib->mf_entries,
359 ({
360 fn(lfei, ctx);
361 }));
362}
363
Neale Rannsc87aafa2017-11-29 00:59:31 -0800364u8 *
365format_mpls_fib_table_memory (u8 * s, va_list * args)
366{
367 u64 n_tables, mem;
368
369 n_tables = pool_elts(mpls_main.fibs);
370 mem = n_tables * sizeof(mpls_fib_t);
Neale Ranns05cac302019-05-28 11:09:40 +0000371 s = format(s, "%=30s %=6ld %=12ld\n", "MPLS", n_tables, mem);
Neale Rannsc87aafa2017-11-29 00:59:31 -0800372
373 return (s);
374}
375
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100376static void
377mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
378 vlib_main_t * vm)
379{
380 fib_node_index_t lfei, *lfeip, *lfeis = NULL;
381 mpls_label_t key;
382
383 hash_foreach(key, lfei, mpls_fib->mf_entries,
384 ({
385 vec_add1(lfeis, lfei);
386 }));
387
388 vec_sort_with_function(lfeis, fib_entry_cmp_for_sort);
389
390 vec_foreach(lfeip, lfeis)
391 {
392 vlib_cli_output (vm, "%U",
393 format_fib_entry, *lfeip,
394 FIB_ENTRY_FORMAT_DETAIL);
395 }
396 vec_free(lfeis);
397}
398
399static void
400mpls_fib_table_show_one (const mpls_fib_t *mpls_fib,
401 mpls_label_t label,
402 vlib_main_t * vm)
403{
404 fib_node_index_t lfei;
405 mpls_eos_bit_t eos;
406
407 FOR_EACH_MPLS_EOS_BIT(eos)
408 {
409 lfei = mpls_fib_table_lookup(mpls_fib, label, eos);
410
411 if (FIB_NODE_INDEX_INVALID != lfei)
412 {
413 vlib_cli_output (vm, "%U",
414 format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL);
415 }
416 }
417}
418
419static clib_error_t *
420mpls_fib_show (vlib_main_t * vm,
421 unformat_input_t * input,
422 vlib_cli_command_t * cmd)
423{
424 fib_table_t * fib_table;
425 mpls_label_t label;
426 int table_id;
427
428 table_id = -1;
429 label = MPLS_LABEL_INVALID;
430
431 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
432 {
433 /* if (unformat (input, "brief") || unformat (input, "summary") */
434 /* || unformat (input, "sum")) */
435 /* verbose = 0; */
436
437 if (unformat (input, "%d", &label))
438 continue;
439 else if (unformat (input, "table %d", &table_id))
440 ;
441 else
442 break;
443 }
444
Damjan Marionb2c31b62020-12-13 21:47:40 +0100445 pool_foreach (fib_table, mpls_main.fibs)
446 {
Neale Ranns097fa662018-05-01 05:17:55 -0700447 fib_source_t source;
448 u8 *s = NULL;
449
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450 if (table_id >= 0 && table_id != fib_table->ft_table_id)
451 continue;
452
Neale Ranns097fa662018-05-01 05:17:55 -0700453 s = format (s, "%v, fib_index:%d locks:[",
454 fib_table->ft_desc, mpls_main.fibs - fib_table);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000455 vec_foreach_index(source, fib_table->ft_locks)
Neale Ranns097fa662018-05-01 05:17:55 -0700456 {
457 if (0 != fib_table->ft_locks[source])
458 {
459 s = format(s, "%U:%d, ",
460 format_fib_source, source,
461 fib_table->ft_locks[source]);
462 }
463 }
464 vlib_cli_output (vm, "%v]", s);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100465
466 if (MPLS_LABEL_INVALID == label)
467 {
Neale Rannsa3af3372017-03-28 03:49:52 -0700468 mpls_fib_table_show_all(mpls_fib_get(fib_table->ft_index), vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100469 }
470 else
471 {
Neale Rannsa3af3372017-03-28 03:49:52 -0700472 mpls_fib_table_show_one(mpls_fib_get(fib_table->ft_index), label, vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100473 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100474 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100475
476 return 0;
477}
478
479VLIB_CLI_COMMAND (mpls_fib_show_command, static) = {
480 .path = "show mpls fib",
481 .short_help = "show mpls fib [summary] [table <n>]",
482 .function = mpls_fib_show,
483};