blob: ca6271fe3d7278f11d0a758115c2ee1e4ea26434 [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.
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.
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
36 * encounterd in the switch path
37 *
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
86mpls_fib_create_with_table_id (u32 table_id)
87{
Neale Ranns948e00f2016-10-20 13:39:34 +010088 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010089 fib_table_t *fib_table;
90 mpls_eos_bit_t eos;
91 mpls_fib_t *mf;
92 int i;
93
94 pool_get_aligned(mpls_main.fibs, fib_table, CLIB_CACHE_LINE_BYTES);
Neale Rannsa3af3372017-03-28 03:49:52 -070095 pool_get_aligned(mpls_main.mpls_fibs, mf, CLIB_CACHE_LINE_BYTES);
96
97 ASSERT((fib_table - mpls_main.fibs) ==
98 (mf - mpls_main.mpls_fibs));
99
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100100 memset(fib_table, 0, sizeof(*fib_table));
101
102 fib_table->ft_proto = FIB_PROTOCOL_MPLS;
Neale Rannsa3af3372017-03-28 03:49:52 -0700103 fib_table->ft_index = (fib_table - mpls_main.fibs);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100104
105 hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index);
106
Neale Ranns227038a2017-04-21 01:07:59 -0700107 fib_table->ft_table_id = table_id;
108 fib_table->ft_flow_hash_config = MPLS_FLOW_HASH_DEFAULT;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100109
110 fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS);
111
112 if (INDEX_INVALID == mpls_fib_drop_dpo_index)
113 {
114 mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0);
115 load_balance_set_bucket(mpls_fib_drop_dpo_index,
116 0,
117 drop_dpo_get(DPO_PROTO_MPLS));
118 }
119
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100120 mf->mf_entries = hash_create(0, sizeof(fib_node_index_t));
121 for (i = 0; i < MPLS_FIB_DB_SIZE; i++)
122 {
123 /*
124 * initialise each DPO in the data-path lookup table
125 * to be the special MPLS drop
126 */
127 mf->mf_lbs[i] = mpls_fib_drop_dpo_index;
128 }
129
130 /*
131 * non-default forwarding for the special labels.
132 */
133 fib_prefix_t prefix = {
134 .fp_proto = FIB_PROTOCOL_MPLS,
135 .fp_payload_proto = DPO_PROTO_MPLS,
136 };
137
138 /*
139 * PUNT the router alert, both EOS and non-eos
140 */
141 prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL;
142 FOR_EACH_MPLS_EOS_BIT(eos)
143 {
144 prefix.fp_eos = eos;
145 fib_table_entry_special_dpo_add(fib_table->ft_index,
146 &prefix,
147 FIB_SOURCE_SPECIAL,
148 FIB_ENTRY_FLAG_EXCLUSIVE,
149 punt_dpo_get(DPO_PROTO_MPLS));
150 }
151
152 /*
153 * IPv4 explicit NULL EOS lookup in the interface's IPv4 table
154 */
155 prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
156 prefix.fp_payload_proto = DPO_PROTO_IP4;
157 prefix.fp_eos = MPLS_EOS;
158
159 lookup_dpo_add_or_lock_w_fib_index(0, // unused
160 DPO_PROTO_IP4,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800161 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162 LOOKUP_INPUT_DST_ADDR,
163 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
164 &dpo);
165 fib_table_entry_special_dpo_add(fib_table->ft_index,
166 &prefix,
167 FIB_SOURCE_SPECIAL,
168 FIB_ENTRY_FLAG_EXCLUSIVE,
169 &dpo);
170
171 prefix.fp_payload_proto = DPO_PROTO_MPLS;
172 prefix.fp_eos = MPLS_NON_EOS;
173
174 lookup_dpo_add_or_lock_w_fib_index(0, //unsued
175 DPO_PROTO_MPLS,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800176 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100177 LOOKUP_INPUT_DST_ADDR,
178 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
179 &dpo);
180 fib_table_entry_special_dpo_add(fib_table->ft_index,
181 &prefix,
182 FIB_SOURCE_SPECIAL,
183 FIB_ENTRY_FLAG_EXCLUSIVE,
184 &dpo);
185
186 /*
187 * IPv6 explicit NULL EOS lookup in the interface's IPv6 table
188 */
189 prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
190 prefix.fp_payload_proto = DPO_PROTO_IP6;
191 prefix.fp_eos = MPLS_EOS;
192
193 lookup_dpo_add_or_lock_w_fib_index(0, //unused
194 DPO_PROTO_IP6,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800195 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100196 LOOKUP_INPUT_DST_ADDR,
197 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
198 &dpo);
199 fib_table_entry_special_dpo_add(fib_table->ft_index,
200 &prefix,
201 FIB_SOURCE_SPECIAL,
202 FIB_ENTRY_FLAG_EXCLUSIVE,
203 &dpo);
204
205 prefix.fp_payload_proto = DPO_PROTO_MPLS;
206 prefix.fp_eos = MPLS_NON_EOS;
207 lookup_dpo_add_or_lock_w_fib_index(0, // unsued
208 DPO_PROTO_MPLS,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800209 LOOKUP_UNICAST,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100210 LOOKUP_INPUT_DST_ADDR,
211 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
212 &dpo);
213 fib_table_entry_special_dpo_add(fib_table->ft_index,
214 &prefix,
215 FIB_SOURCE_SPECIAL,
216 FIB_ENTRY_FLAG_EXCLUSIVE,
217 &dpo);
218
219 return (fib_table->ft_index);
220}
221
222u32
223mpls_fib_table_find_or_create_and_lock (u32 table_id)
224{
225 u32 index;
226
227 index = mpls_fib_index_from_table_id(table_id);
228 if (~0 == index)
229 return mpls_fib_create_with_table_id(table_id);
230
231 fib_table_lock(index, FIB_PROTOCOL_MPLS);
232
233 return (index);
234}
235u32
236mpls_fib_table_create_and_lock (void)
237{
238 return (mpls_fib_create_with_table_id(~0));
239}
240
241void
Neale Rannsa3af3372017-03-28 03:49:52 -0700242mpls_fib_table_destroy (u32 fib_index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100243{
Neale Rannsa3af3372017-03-28 03:49:52 -0700244 fib_table_t *fib_table = pool_elt_at_index(mpls_main.fibs, fib_index);
245 mpls_fib_t *mf = pool_elt_at_index(mpls_main.mpls_fibs, fib_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100246 fib_prefix_t prefix = {
247 .fp_proto = FIB_PROTOCOL_MPLS,
248 };
249 mpls_label_t special_labels[] = {
250 MPLS_IETF_ROUTER_ALERT_LABEL,
251 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
252 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL,
253 };
254 mpls_eos_bit_t eos;
255 u32 ii;
256
257 for (ii = 0; ii < ARRAY_LEN(special_labels); ii++)
258 {
259 FOR_EACH_MPLS_EOS_BIT(eos)
260 {
261 prefix.fp_label = special_labels[ii];
262 prefix.fp_eos = eos;
263
264 fib_table_entry_delete(fib_table->ft_index,
265 &prefix,
266 FIB_SOURCE_SPECIAL);
267 }
268 }
269 if (~0 != fib_table->ft_table_id)
270 {
271 hash_unset(mpls_main.fib_index_by_table_id,
272 fib_table->ft_table_id);
273 }
Neale Rannsbcc6aa42017-02-24 01:34:14 -0800274 hash_free(mf->mf_entries);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100275
Neale Rannsa3af3372017-03-28 03:49:52 -0700276 pool_put(mpls_main.mpls_fibs, mf);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100277 pool_put(mpls_main.fibs, fib_table);
278}
279
280fib_node_index_t
281mpls_fib_table_lookup (const mpls_fib_t *mf,
282 mpls_label_t label,
283 mpls_eos_bit_t eos)
284{
285 uword *p;
286
287 p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
288
289 if (NULL == p)
290 return FIB_NODE_INDEX_INVALID;
291
292 return p[0];
293}
294
295void
296mpls_fib_table_entry_insert (mpls_fib_t *mf,
297 mpls_label_t label,
298 mpls_eos_bit_t eos,
299 fib_node_index_t lfei)
300{
301 hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei);
302}
303
304void
305mpls_fib_table_entry_remove (mpls_fib_t *mf,
306 mpls_label_t label,
307 mpls_eos_bit_t eos)
308{
309 hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
310}
311
312void
313mpls_fib_forwarding_table_update (mpls_fib_t *mf,
314 mpls_label_t label,
315 mpls_eos_bit_t eos,
316 const dpo_id_t *dpo)
317{
318 mpls_label_t key;
319
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800320 ASSERT((DPO_LOAD_BALANCE == dpo->dpoi_type) ||
321 (DPO_REPLICATE == dpo->dpoi_type));
322 if (CLIB_DEBUG > 0)
323 {
324 if (DPO_REPLICATE == dpo->dpoi_type)
325 ASSERT(dpo->dpoi_index & MPLS_IS_REPLICATE);
326 if (DPO_LOAD_BALANCE == dpo->dpoi_type)
327 ASSERT(!(dpo->dpoi_index & MPLS_IS_REPLICATE));
328 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100329 key = mpls_fib_entry_mk_key(label, eos);
330
331 mf->mf_lbs[key] = dpo->dpoi_index;
332}
333
334void
335mpls_fib_forwarding_table_reset (mpls_fib_t *mf,
336 mpls_label_t label,
337 mpls_eos_bit_t eos)
338{
339 mpls_label_t key;
340
341 key = mpls_fib_entry_mk_key(label, eos);
342
343 mf->mf_lbs[key] = mpls_fib_drop_dpo_index;
344}
345
Neale Ranns32e1c012016-11-22 17:07:28 +0000346void
347mpls_fib_table_walk (mpls_fib_t *mpls_fib,
348 fib_table_walk_fn_t fn,
349 void *ctx)
350{
351 fib_node_index_t lfei;
352 mpls_label_t key;
353
354 hash_foreach(key, lfei, mpls_fib->mf_entries,
355 ({
356 fn(lfei, ctx);
357 }));
358}
359
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100360static void
361mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
362 vlib_main_t * vm)
363{
364 fib_node_index_t lfei, *lfeip, *lfeis = NULL;
365 mpls_label_t key;
366
367 hash_foreach(key, lfei, mpls_fib->mf_entries,
368 ({
369 vec_add1(lfeis, lfei);
370 }));
371
372 vec_sort_with_function(lfeis, fib_entry_cmp_for_sort);
373
374 vec_foreach(lfeip, lfeis)
375 {
376 vlib_cli_output (vm, "%U",
377 format_fib_entry, *lfeip,
378 FIB_ENTRY_FORMAT_DETAIL);
379 }
380 vec_free(lfeis);
381}
382
383static void
384mpls_fib_table_show_one (const mpls_fib_t *mpls_fib,
385 mpls_label_t label,
386 vlib_main_t * vm)
387{
388 fib_node_index_t lfei;
389 mpls_eos_bit_t eos;
390
391 FOR_EACH_MPLS_EOS_BIT(eos)
392 {
393 lfei = mpls_fib_table_lookup(mpls_fib, label, eos);
394
395 if (FIB_NODE_INDEX_INVALID != lfei)
396 {
397 vlib_cli_output (vm, "%U",
398 format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL);
399 }
400 }
401}
402
403static clib_error_t *
404mpls_fib_show (vlib_main_t * vm,
405 unformat_input_t * input,
406 vlib_cli_command_t * cmd)
407{
408 fib_table_t * fib_table;
409 mpls_label_t label;
410 int table_id;
411
412 table_id = -1;
413 label = MPLS_LABEL_INVALID;
414
415 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
416 {
417 /* if (unformat (input, "brief") || unformat (input, "summary") */
418 /* || unformat (input, "sum")) */
419 /* verbose = 0; */
420
421 if (unformat (input, "%d", &label))
422 continue;
423 else if (unformat (input, "table %d", &table_id))
424 ;
425 else
426 break;
427 }
428
429 pool_foreach (fib_table, mpls_main.fibs,
430 ({
431 if (table_id >= 0 && table_id != fib_table->ft_table_id)
432 continue;
433
434 vlib_cli_output (vm, "%v, fib_index %d",
435 fib_table->ft_desc, mpls_main.fibs - fib_table);
436
437 if (MPLS_LABEL_INVALID == label)
438 {
Neale Rannsa3af3372017-03-28 03:49:52 -0700439 mpls_fib_table_show_all(mpls_fib_get(fib_table->ft_index), vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100440 }
441 else
442 {
Neale Rannsa3af3372017-03-28 03:49:52 -0700443 mpls_fib_table_show_one(mpls_fib_get(fib_table->ft_index), label, vm);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100444 }
445 }));
446
447 return 0;
448}
449
450VLIB_CLI_COMMAND (mpls_fib_show_command, static) = {
451 .path = "show mpls fib",
452 .short_help = "show mpls fib [summary] [table <n>]",
453 .function = mpls_fib_show,
454};