Line data Source code
1 : /*
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 design 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 : * encountered 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/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>
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 : */
62 : static index_t mpls_fib_drop_dpo_index = INDEX_INVALID;
63 :
64 : static inline u32
65 3587 : mpls_fib_entry_mk_key (mpls_label_t label,
66 : mpls_eos_bit_t eos)
67 : {
68 3587 : ASSERT(eos <= 1);
69 3587 : return (label << 1 | eos);
70 : }
71 :
72 : u32
73 1212 : mpls_fib_index_from_table_id (u32 table_id)
74 : {
75 1212 : mpls_main_t *mm = &mpls_main;
76 : uword * p;
77 :
78 1212 : p = hash_get (mm->fib_index_by_table_id, table_id);
79 1212 : if (!p)
80 50 : return FIB_NODE_INDEX_INVALID;
81 :
82 1162 : return p[0];
83 : }
84 :
85 : static u32
86 49 : mpls_fib_create_with_table_id (u32 table_id,
87 : fib_source_t src)
88 : {
89 49 : dpo_id_t dpo = DPO_INVALID;
90 : fib_table_t *fib_table;
91 : mpls_eos_bit_t eos;
92 : mpls_fib_t *mf;
93 : int i;
94 :
95 49 : pool_get(mpls_main.fibs, fib_table);
96 49 : pool_get_aligned(mpls_main.mpls_fibs, mf, CLIB_CACHE_LINE_BYTES);
97 :
98 49 : ASSERT((fib_table - mpls_main.fibs) ==
99 : (mf - mpls_main.mpls_fibs));
100 :
101 49 : clib_memset(fib_table, 0, sizeof(*fib_table));
102 :
103 49 : fib_table->ft_proto = FIB_PROTOCOL_MPLS;
104 49 : fib_table->ft_index = (fib_table - mpls_main.fibs);
105 :
106 49 : hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index);
107 :
108 49 : fib_table->ft_table_id = table_id;
109 49 : fib_table->ft_flow_hash_config = MPLS_FLOW_HASH_DEFAULT;
110 :
111 49 : fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS, src);
112 :
113 49 : if (INDEX_INVALID == mpls_fib_drop_dpo_index)
114 : {
115 17 : mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0);
116 17 : load_balance_set_bucket(mpls_fib_drop_dpo_index,
117 : 0,
118 : drop_dpo_get(DPO_PROTO_MPLS));
119 : }
120 :
121 49 : mf->mf_entries = hash_create(0, sizeof(fib_node_index_t));
122 102760000 : 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 102760000 : mf->mf_lbs[i] = mpls_fib_drop_dpo_index;
129 : }
130 :
131 : /*
132 : * non-default forwarding for the special labels.
133 : */
134 49 : 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 49 : prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL;
143 147 : FOR_EACH_MPLS_EOS_BIT(eos)
144 : {
145 98 : prefix.fp_eos = eos;
146 98 : 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 49 : prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
157 49 : prefix.fp_payload_proto = DPO_PROTO_IP4;
158 49 : prefix.fp_eos = MPLS_EOS;
159 :
160 49 : lookup_dpo_add_or_lock_w_fib_index(0, // unused
161 : DPO_PROTO_IP4,
162 : LOOKUP_UNICAST,
163 : LOOKUP_INPUT_DST_ADDR,
164 : LOOKUP_TABLE_FROM_INPUT_INTERFACE,
165 : &dpo);
166 49 : 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 49 : prefix.fp_payload_proto = DPO_PROTO_MPLS;
173 49 : prefix.fp_eos = MPLS_NON_EOS;
174 :
175 49 : lookup_dpo_add_or_lock_w_fib_index(0, //unsued
176 : DPO_PROTO_MPLS,
177 : LOOKUP_UNICAST,
178 : LOOKUP_INPUT_DST_ADDR,
179 : LOOKUP_TABLE_FROM_INPUT_INTERFACE,
180 : &dpo);
181 49 : 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 49 : prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
191 49 : prefix.fp_payload_proto = DPO_PROTO_IP6;
192 49 : prefix.fp_eos = MPLS_EOS;
193 :
194 49 : lookup_dpo_add_or_lock_w_fib_index(0, //unused
195 : DPO_PROTO_IP6,
196 : LOOKUP_UNICAST,
197 : LOOKUP_INPUT_DST_ADDR,
198 : LOOKUP_TABLE_FROM_INPUT_INTERFACE,
199 : &dpo);
200 49 : 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 49 : prefix.fp_payload_proto = DPO_PROTO_MPLS;
207 49 : prefix.fp_eos = MPLS_NON_EOS;
208 49 : lookup_dpo_add_or_lock_w_fib_index(0, // unsued
209 : DPO_PROTO_MPLS,
210 : LOOKUP_UNICAST,
211 : LOOKUP_INPUT_DST_ADDR,
212 : LOOKUP_TABLE_FROM_INPUT_INTERFACE,
213 : &dpo);
214 49 : 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 49 : return (fib_table->ft_index);
221 : }
222 :
223 : u32
224 198 : mpls_fib_table_find_or_create_and_lock (u32 table_id,
225 : fib_source_t src)
226 : {
227 : u32 index;
228 :
229 198 : index = mpls_fib_index_from_table_id(table_id);
230 198 : if (~0 == index)
231 49 : return mpls_fib_create_with_table_id(table_id, src);
232 :
233 149 : fib_table_lock(index, FIB_PROTOCOL_MPLS, src);
234 :
235 149 : return (index);
236 : }
237 : u32
238 0 : mpls_fib_table_create_and_lock (fib_source_t src)
239 : {
240 0 : return (mpls_fib_create_with_table_id(~0, src));
241 : }
242 :
243 : void
244 49 : mpls_fib_table_destroy (u32 fib_index)
245 : {
246 49 : fib_table_t *fib_table = pool_elt_at_index(mpls_main.fibs, fib_index);
247 49 : mpls_fib_t *mf = pool_elt_at_index(mpls_main.mpls_fibs, fib_index);
248 49 : fib_prefix_t prefix = {
249 : .fp_proto = FIB_PROTOCOL_MPLS,
250 : };
251 49 : 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 196 : for (ii = 0; ii < ARRAY_LEN(special_labels); ii++)
260 : {
261 441 : FOR_EACH_MPLS_EOS_BIT(eos)
262 : {
263 294 : prefix.fp_label = special_labels[ii];
264 294 : prefix.fp_eos = eos;
265 :
266 294 : fib_table_entry_delete(fib_table->ft_index,
267 : &prefix,
268 : FIB_SOURCE_SPECIAL);
269 : }
270 : }
271 49 : if (~0 != fib_table->ft_table_id)
272 : {
273 49 : hash_unset(mpls_main.fib_index_by_table_id,
274 : fib_table->ft_table_id);
275 : }
276 49 : hash_free(mf->mf_entries);
277 :
278 49 : vec_free (fib_table->ft_locks);
279 49 : vec_free(fib_table->ft_src_route_counts);
280 49 : pool_put(mpls_main.mpls_fibs, mf);
281 49 : pool_put(mpls_main.fibs, fib_table);
282 49 : }
283 :
284 : fib_node_index_t
285 1058 : mpls_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 1058 : p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
292 :
293 1058 : if (NULL == p)
294 640 : return FIB_NODE_INDEX_INVALID;
295 :
296 418 : return p[0];
297 : }
298 :
299 : void
300 631 : mpls_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 631 : hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei);
306 631 : }
307 :
308 : void
309 631 : mpls_fib_table_entry_remove (mpls_fib_t *mf,
310 : mpls_label_t label,
311 : mpls_eos_bit_t eos)
312 : {
313 631 : hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
314 631 : }
315 :
316 : void
317 636 : mpls_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 :
324 636 : ASSERT((DPO_LOAD_BALANCE == dpo->dpoi_type) ||
325 : (DPO_REPLICATE == dpo->dpoi_type));
326 : if (CLIB_DEBUG > 0)
327 : {
328 636 : if (DPO_REPLICATE == dpo->dpoi_type)
329 7 : ASSERT(dpo->dpoi_index & MPLS_IS_REPLICATE);
330 636 : if (DPO_LOAD_BALANCE == dpo->dpoi_type)
331 629 : ASSERT(!(dpo->dpoi_index & MPLS_IS_REPLICATE));
332 : }
333 636 : key = mpls_fib_entry_mk_key(label, eos);
334 :
335 636 : mf->mf_lbs[key] = dpo->dpoi_index;
336 636 : }
337 :
338 : void
339 631 : mpls_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 631 : key = mpls_fib_entry_mk_key(label, eos);
346 :
347 631 : mf->mf_lbs[key] = mpls_fib_drop_dpo_index;
348 631 : }
349 :
350 : void
351 335 : mpls_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 78696 : hash_foreach(key, lfei, mpls_fib->mf_entries,
359 : ({
360 : fn(lfei, ctx);
361 : }));
362 335 : }
363 :
364 : u8 *
365 1 : format_mpls_fib_table_memory (u8 * s, va_list * args)
366 : {
367 : u64 n_tables, mem;
368 :
369 1 : n_tables = pool_elts(mpls_main.fibs);
370 1 : mem = n_tables * sizeof(mpls_fib_t);
371 1 : s = format(s, "%=30s %=6ld %=12ld\n", "MPLS", n_tables, mem);
372 :
373 1 : return (s);
374 : }
375 :
376 : static void
377 0 : mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
378 : vlib_main_t * vm)
379 : {
380 0 : fib_node_index_t lfei, *lfeip, *lfeis = NULL;
381 : mpls_label_t key;
382 :
383 0 : hash_foreach(key, lfei, mpls_fib->mf_entries,
384 : ({
385 : vec_add1(lfeis, lfei);
386 : }));
387 :
388 0 : vec_sort_with_function(lfeis, fib_entry_cmp_for_sort);
389 :
390 0 : vec_foreach(lfeip, lfeis)
391 : {
392 0 : vlib_cli_output (vm, "%U",
393 : format_fib_entry, *lfeip,
394 : FIB_ENTRY_FORMAT_DETAIL);
395 : }
396 0 : vec_free(lfeis);
397 0 : }
398 :
399 : static void
400 2 : mpls_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 6 : FOR_EACH_MPLS_EOS_BIT(eos)
408 : {
409 4 : lfei = mpls_fib_table_lookup(mpls_fib, label, eos);
410 :
411 4 : if (FIB_NODE_INDEX_INVALID != lfei)
412 : {
413 2 : vlib_cli_output (vm, "%U",
414 : format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL);
415 : }
416 : }
417 2 : }
418 :
419 : static clib_error_t *
420 2 : mpls_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 2 : table_id = -1;
429 2 : label = MPLS_LABEL_INVALID;
430 :
431 4 : 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 2 : if (unformat (input, "%d", &label))
438 2 : continue;
439 0 : else if (unformat (input, "table %d", &table_id))
440 : ;
441 : else
442 0 : break;
443 : }
444 :
445 4 : pool_foreach (fib_table, mpls_main.fibs)
446 : {
447 : fib_source_t source;
448 2 : u8 *s = NULL;
449 :
450 2 : if (table_id >= 0 && table_id != fib_table->ft_table_id)
451 0 : continue;
452 :
453 2 : s = format (s, "%v, fib_index:%d locks:[",
454 2 : fib_table->ft_desc, fib_table - mpls_main.fibs);
455 30 : vec_foreach_index(source, fib_table->ft_locks)
456 : {
457 28 : if (0 != fib_table->ft_locks[source])
458 : {
459 5 : s = format(s, "%U:%d, ",
460 : format_fib_source, source,
461 5 : fib_table->ft_locks[source]);
462 : }
463 : }
464 2 : vlib_cli_output (vm, "%v]", s);
465 :
466 2 : if (MPLS_LABEL_INVALID == label)
467 : {
468 0 : mpls_fib_table_show_all(mpls_fib_get(fib_table->ft_index), vm);
469 : }
470 : else
471 : {
472 2 : mpls_fib_table_show_one(mpls_fib_get(fib_table->ft_index), label, vm);
473 : }
474 : }
475 :
476 2 : return 0;
477 : }
478 :
479 272887 : VLIB_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 : };
|