blob: 6a9b1ac29892cf54b7c469ca51babda2234db14c [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 *
47 * VPP mantra - favour performance over memory. We choose a 21 bit key.
48 */
49
50#include <vnet/fib/fib_table.h>
51#include <vnet/dpo/load_balance.h>
52#include <vnet/dpo/drop_dpo.h>
53#include <vnet/dpo/punt_dpo.h>
54#include <vnet/dpo/lookup_dpo.h>
55#include <vnet/mpls/mpls.h>
56
57/**
58 * All lookups in an MPLS_FIB table must result in a DPO of type load-balance.
59 * This is the default result which links to drop
60 */
61static index_t mpls_fib_drop_dpo_index = INDEX_INVALID;
62
63/**
64 * FIXME
65 */
66#define MPLS_FLOW_HASH_DEFAULT 0
67
68static inline u32
69mpls_fib_entry_mk_key (mpls_label_t label,
70 mpls_eos_bit_t eos)
71{
72 ASSERT(eos <= 1);
73 return (label << 1 | eos);
74}
75
76u32
77mpls_fib_index_from_table_id (u32 table_id)
78{
79 mpls_main_t *mm = &mpls_main;
80 uword * p;
81
82 p = hash_get (mm->fib_index_by_table_id, table_id);
83 if (!p)
84 return FIB_NODE_INDEX_INVALID;
85
86 return p[0];
87}
88
89static u32
90mpls_fib_create_with_table_id (u32 table_id)
91{
Neale Ranns948e00f2016-10-20 13:39:34 +010092 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010093 fib_table_t *fib_table;
94 mpls_eos_bit_t eos;
95 mpls_fib_t *mf;
96 int i;
97
98 pool_get_aligned(mpls_main.fibs, fib_table, CLIB_CACHE_LINE_BYTES);
99 memset(fib_table, 0, sizeof(*fib_table));
100
101 fib_table->ft_proto = FIB_PROTOCOL_MPLS;
102 fib_table->ft_index =
103 (fib_table - mpls_main.fibs);
104
105 hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index);
106
107 fib_table->ft_table_id =
108 table_id;
109 fib_table->ft_flow_hash_config =
110 MPLS_FLOW_HASH_DEFAULT;
111 fib_table->v4.fwd_classify_table_index = ~0;
112 fib_table->v4.rev_classify_table_index = ~0;
113
114 fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS);
115
116 if (INDEX_INVALID == mpls_fib_drop_dpo_index)
117 {
118 mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0);
119 load_balance_set_bucket(mpls_fib_drop_dpo_index,
120 0,
121 drop_dpo_get(DPO_PROTO_MPLS));
122 }
123
124 mf = &fib_table->mpls;
125 mf->mf_entries = hash_create(0, sizeof(fib_node_index_t));
126 for (i = 0; i < MPLS_FIB_DB_SIZE; i++)
127 {
128 /*
129 * initialise each DPO in the data-path lookup table
130 * to be the special MPLS drop
131 */
132 mf->mf_lbs[i] = mpls_fib_drop_dpo_index;
133 }
134
135 /*
136 * non-default forwarding for the special labels.
137 */
138 fib_prefix_t prefix = {
139 .fp_proto = FIB_PROTOCOL_MPLS,
140 .fp_payload_proto = DPO_PROTO_MPLS,
141 };
142
143 /*
144 * PUNT the router alert, both EOS and non-eos
145 */
146 prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL;
147 FOR_EACH_MPLS_EOS_BIT(eos)
148 {
149 prefix.fp_eos = eos;
150 fib_table_entry_special_dpo_add(fib_table->ft_index,
151 &prefix,
152 FIB_SOURCE_SPECIAL,
153 FIB_ENTRY_FLAG_EXCLUSIVE,
154 punt_dpo_get(DPO_PROTO_MPLS));
155 }
156
157 /*
158 * IPv4 explicit NULL EOS lookup in the interface's IPv4 table
159 */
160 prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
161 prefix.fp_payload_proto = DPO_PROTO_IP4;
162 prefix.fp_eos = MPLS_EOS;
163
164 lookup_dpo_add_or_lock_w_fib_index(0, // unused
165 DPO_PROTO_IP4,
166 LOOKUP_INPUT_DST_ADDR,
167 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
168 &dpo);
169 fib_table_entry_special_dpo_add(fib_table->ft_index,
170 &prefix,
171 FIB_SOURCE_SPECIAL,
172 FIB_ENTRY_FLAG_EXCLUSIVE,
173 &dpo);
174
175 prefix.fp_payload_proto = DPO_PROTO_MPLS;
176 prefix.fp_eos = MPLS_NON_EOS;
177
178 lookup_dpo_add_or_lock_w_fib_index(0, //unsued
179 DPO_PROTO_MPLS,
180 LOOKUP_INPUT_DST_ADDR,
181 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
182 &dpo);
183 fib_table_entry_special_dpo_add(fib_table->ft_index,
184 &prefix,
185 FIB_SOURCE_SPECIAL,
186 FIB_ENTRY_FLAG_EXCLUSIVE,
187 &dpo);
188
189 /*
190 * IPv6 explicit NULL EOS lookup in the interface's IPv6 table
191 */
192 prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
193 prefix.fp_payload_proto = DPO_PROTO_IP6;
194 prefix.fp_eos = MPLS_EOS;
195
196 lookup_dpo_add_or_lock_w_fib_index(0, //unused
197 DPO_PROTO_IP6,
198 LOOKUP_INPUT_DST_ADDR,
199 LOOKUP_TABLE_FROM_INPUT_INTERFACE,
200 &dpo);
201 fib_table_entry_special_dpo_add(fib_table->ft_index,
202 &prefix,
203 FIB_SOURCE_SPECIAL,
204 FIB_ENTRY_FLAG_EXCLUSIVE,
205 &dpo);
206
207 prefix.fp_payload_proto = DPO_PROTO_MPLS;
208 prefix.fp_eos = MPLS_NON_EOS;
209 lookup_dpo_add_or_lock_w_fib_index(0, // unsued
210 DPO_PROTO_MPLS,
211 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
224mpls_fib_table_find_or_create_and_lock (u32 table_id)
225{
226 u32 index;
227
228 index = mpls_fib_index_from_table_id(table_id);
229 if (~0 == index)
230 return mpls_fib_create_with_table_id(table_id);
231
232 fib_table_lock(index, FIB_PROTOCOL_MPLS);
233
234 return (index);
235}
236u32
237mpls_fib_table_create_and_lock (void)
238{
239 return (mpls_fib_create_with_table_id(~0));
240}
241
242void
243mpls_fib_table_destroy (mpls_fib_t *mf)
244{
245 fib_table_t *fib_table = (fib_table_t*)mf;
246 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 }
274 hash_delete(mf->mf_entries);
275
276 pool_put(mpls_main.fibs, fib_table);
277}
278
279fib_node_index_t
280mpls_fib_table_lookup (const mpls_fib_t *mf,
281 mpls_label_t label,
282 mpls_eos_bit_t eos)
283{
284 uword *p;
285
286 p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
287
288 if (NULL == p)
289 return FIB_NODE_INDEX_INVALID;
290
291 return p[0];
292}
293
294void
295mpls_fib_table_entry_insert (mpls_fib_t *mf,
296 mpls_label_t label,
297 mpls_eos_bit_t eos,
298 fib_node_index_t lfei)
299{
300 hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei);
301}
302
303void
304mpls_fib_table_entry_remove (mpls_fib_t *mf,
305 mpls_label_t label,
306 mpls_eos_bit_t eos)
307{
308 hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
309}
310
311void
312mpls_fib_forwarding_table_update (mpls_fib_t *mf,
313 mpls_label_t label,
314 mpls_eos_bit_t eos,
315 const dpo_id_t *dpo)
316{
317 mpls_label_t key;
318
319 ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type);
320
321 key = mpls_fib_entry_mk_key(label, eos);
322
323 mf->mf_lbs[key] = dpo->dpoi_index;
324}
325
326void
327mpls_fib_forwarding_table_reset (mpls_fib_t *mf,
328 mpls_label_t label,
329 mpls_eos_bit_t eos)
330{
331 mpls_label_t key;
332
333 key = mpls_fib_entry_mk_key(label, eos);
334
335 mf->mf_lbs[key] = mpls_fib_drop_dpo_index;
336}
337
338flow_hash_config_t
339mpls_fib_table_get_flow_hash_config (u32 fib_index)
340{
341 // FIXME.
342 return (0);
343}
344
345static void
346mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
347 vlib_main_t * vm)
348{
349 fib_node_index_t lfei, *lfeip, *lfeis = NULL;
350 mpls_label_t key;
351
352 hash_foreach(key, lfei, mpls_fib->mf_entries,
353 ({
354 vec_add1(lfeis, lfei);
355 }));
356
357 vec_sort_with_function(lfeis, fib_entry_cmp_for_sort);
358
359 vec_foreach(lfeip, lfeis)
360 {
361 vlib_cli_output (vm, "%U",
362 format_fib_entry, *lfeip,
363 FIB_ENTRY_FORMAT_DETAIL);
364 }
365 vec_free(lfeis);
366}
367
368static void
369mpls_fib_table_show_one (const mpls_fib_t *mpls_fib,
370 mpls_label_t label,
371 vlib_main_t * vm)
372{
373 fib_node_index_t lfei;
374 mpls_eos_bit_t eos;
375
376 FOR_EACH_MPLS_EOS_BIT(eos)
377 {
378 lfei = mpls_fib_table_lookup(mpls_fib, label, eos);
379
380 if (FIB_NODE_INDEX_INVALID != lfei)
381 {
382 vlib_cli_output (vm, "%U",
383 format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL);
384 }
385 }
386}
387
388static clib_error_t *
389mpls_fib_show (vlib_main_t * vm,
390 unformat_input_t * input,
391 vlib_cli_command_t * cmd)
392{
393 fib_table_t * fib_table;
394 mpls_label_t label;
395 int table_id;
396
397 table_id = -1;
398 label = MPLS_LABEL_INVALID;
399
400 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
401 {
402 /* if (unformat (input, "brief") || unformat (input, "summary") */
403 /* || unformat (input, "sum")) */
404 /* verbose = 0; */
405
406 if (unformat (input, "%d", &label))
407 continue;
408 else if (unformat (input, "table %d", &table_id))
409 ;
410 else
411 break;
412 }
413
414 pool_foreach (fib_table, mpls_main.fibs,
415 ({
416 if (table_id >= 0 && table_id != fib_table->ft_table_id)
417 continue;
418
419 vlib_cli_output (vm, "%v, fib_index %d",
420 fib_table->ft_desc, mpls_main.fibs - fib_table);
421
422 if (MPLS_LABEL_INVALID == label)
423 {
424 mpls_fib_table_show_all(&(fib_table->mpls), vm);
425 }
426 else
427 {
428 mpls_fib_table_show_one(&(fib_table->mpls), label, vm);
429 }
430 }));
431
432 return 0;
433}
434
435VLIB_CLI_COMMAND (mpls_fib_show_command, static) = {
436 .path = "show mpls fib",
437 .short_help = "show mpls fib [summary] [table <n>]",
438 .function = mpls_fib_show,
439};