blob: 7818d02e05d87580c6da7e876ba2fc126d107101 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vlib/vlib.h>
17#include <vnet/dpo/drop_dpo.h>
18
19#include <vnet/fib/fib_table.h>
20#include <vnet/fib/fib_entry_cover.h>
21#include <vnet/fib/fib_internal.h>
22#include <vnet/fib/ip4_fib.h>
23#include <vnet/fib/ip6_fib.h>
24#include <vnet/fib/mpls_fib.h>
25
26fib_table_t *
27fib_table_get (fib_node_index_t index,
28 fib_protocol_t proto)
29{
30 switch (proto)
31 {
32 case FIB_PROTOCOL_IP4:
33 return (pool_elt_at_index(ip4_main.fibs, index));
34 case FIB_PROTOCOL_IP6:
35 return (pool_elt_at_index(ip6_main.fibs, index));
36 case FIB_PROTOCOL_MPLS:
37 return (pool_elt_at_index(mpls_main.fibs, index));
38 }
39 ASSERT(0);
40 return (NULL);
41}
42
43static inline fib_node_index_t
44fib_table_lookup_i (fib_table_t *fib_table,
45 const fib_prefix_t *prefix)
46{
47 switch (prefix->fp_proto)
48 {
49 case FIB_PROTOCOL_IP4:
50 return (ip4_fib_table_lookup(&fib_table->v4,
51 &prefix->fp_addr.ip4,
52 prefix->fp_len));
53 case FIB_PROTOCOL_IP6:
54 return (ip6_fib_table_lookup(fib_table->ft_index,
55 &prefix->fp_addr.ip6,
56 prefix->fp_len));
57 case FIB_PROTOCOL_MPLS:
58 return (mpls_fib_table_lookup(&fib_table->mpls,
59 prefix->fp_label,
60 prefix->fp_eos));
61 }
62 return (FIB_NODE_INDEX_INVALID);
63}
64
65fib_node_index_t
66fib_table_lookup (u32 fib_index,
67 const fib_prefix_t *prefix)
68{
69 return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
70}
71
72static inline fib_node_index_t
73fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
74 const fib_prefix_t *prefix)
75{
76 switch (prefix->fp_proto)
77 {
78 case FIB_PROTOCOL_IP4:
79 return (ip4_fib_table_lookup_exact_match(&fib_table->v4,
80 &prefix->fp_addr.ip4,
81 prefix->fp_len));
82 case FIB_PROTOCOL_IP6:
83 return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
84 &prefix->fp_addr.ip6,
85 prefix->fp_len));
86 case FIB_PROTOCOL_MPLS:
87 return (mpls_fib_table_lookup(&fib_table->mpls,
88 prefix->fp_label,
89 prefix->fp_eos));
90 }
91 return (FIB_NODE_INDEX_INVALID);
92}
93
94fib_node_index_t
95fib_table_lookup_exact_match (u32 fib_index,
96 const fib_prefix_t *prefix)
97{
98 return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
99 prefix->fp_proto),
100 prefix));
101}
102
103static fib_node_index_t
104fib_table_get_less_specific_i (fib_table_t *fib_table,
105 const fib_prefix_t *prefix)
106{
107 fib_prefix_t pfx;
108
109 pfx = *prefix;
110
111 if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
112 {
113 return (FIB_NODE_INDEX_INVALID);
114 }
115
116 /*
117 * in the absence of a tree structure for the table that allows for an O(1)
118 * parent get, a cheeky way to find the cover is to LPM for the prefix with
119 * mask-1.
120 * there should always be a cover, though it may be the default route. the
121 * default route's cover is the default route.
122 */
123 if (pfx.fp_len != 0) {
124 pfx.fp_len -= 1;
125 }
126
127 return (fib_table_lookup_i(fib_table, &pfx));
128}
129
130fib_node_index_t
131fib_table_get_less_specific (u32 fib_index,
132 const fib_prefix_t *prefix)
133{
134 return (fib_table_get_less_specific_i(fib_table_get(fib_index,
135 prefix->fp_proto),
136 prefix));
137}
138
139static void
140fib_table_entry_remove (fib_table_t *fib_table,
141 const fib_prefix_t *prefix,
142 fib_node_index_t fib_entry_index)
143{
144 vlib_smp_unsafe_warning();
145
146 fib_table->ft_total_route_counts--;
147
148 switch (prefix->fp_proto)
149 {
150 case FIB_PROTOCOL_IP4:
151 ip4_fib_table_entry_remove(&fib_table->v4,
152 &prefix->fp_addr.ip4,
153 prefix->fp_len);
154 break;
155 case FIB_PROTOCOL_IP6:
156 ip6_fib_table_entry_remove(fib_table->ft_index,
157 &prefix->fp_addr.ip6,
158 prefix->fp_len);
159 break;
160 case FIB_PROTOCOL_MPLS:
161 mpls_fib_table_entry_remove(&fib_table->mpls,
162 prefix->fp_label,
163 prefix->fp_eos);
164 break;
165 }
166
167 fib_entry_unlock(fib_entry_index);
168}
169
170static void
171fib_table_post_insert_actions (fib_table_t *fib_table,
172 const fib_prefix_t *prefix,
173 fib_node_index_t fib_entry_index)
174{
175 fib_node_index_t fib_entry_cover_index;
176
177 /*
178 * no cover relationships in the MPLS FIB
179 */
180 if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
181 return;
182
183 /*
184 * find and inform the covering entry that a new more specific
185 * has been inserted beneath it
186 */
187 fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
188 /*
189 * the indicies are the same when the default route is first added
190 */
191 if (fib_entry_cover_index != fib_entry_index)
192 {
193 fib_entry_cover_change_notify(fib_entry_cover_index,
194 fib_entry_index);
195 }
196}
197
198static void
199fib_table_entry_insert (fib_table_t *fib_table,
200 const fib_prefix_t *prefix,
201 fib_node_index_t fib_entry_index)
202{
203 vlib_smp_unsafe_warning();
204
205 fib_entry_lock(fib_entry_index);
206 fib_table->ft_total_route_counts++;
207
208 switch (prefix->fp_proto)
209 {
210 case FIB_PROTOCOL_IP4:
211 ip4_fib_table_entry_insert(&fib_table->v4,
212 &prefix->fp_addr.ip4,
213 prefix->fp_len,
214 fib_entry_index);
215 break;
216 case FIB_PROTOCOL_IP6:
217 ip6_fib_table_entry_insert(fib_table->ft_index,
218 &prefix->fp_addr.ip6,
219 prefix->fp_len,
220 fib_entry_index);
221 break;
222 case FIB_PROTOCOL_MPLS:
223 mpls_fib_table_entry_insert(&fib_table->mpls,
224 prefix->fp_label,
225 prefix->fp_eos,
226 fib_entry_index);
227 break;
228 }
229
230 fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
231}
232
233void
234fib_table_fwding_dpo_update (u32 fib_index,
235 const fib_prefix_t *prefix,
236 const dpo_id_t *dpo)
237{
238 vlib_smp_unsafe_warning();
239
240 switch (prefix->fp_proto)
241 {
242 case FIB_PROTOCOL_IP4:
243 return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
244 &prefix->fp_addr.ip4,
245 prefix->fp_len,
246 dpo));
247 case FIB_PROTOCOL_IP6:
248 return (ip6_fib_table_fwding_dpo_update(fib_index,
249 &prefix->fp_addr.ip6,
250 prefix->fp_len,
251 dpo));
252 case FIB_PROTOCOL_MPLS:
253 return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
254 prefix->fp_label,
255 prefix->fp_eos,
256 dpo));
257 }
258}
259
260void
261fib_table_fwding_dpo_remove (u32 fib_index,
262 const fib_prefix_t *prefix,
263 const dpo_id_t *dpo)
264{
265 vlib_smp_unsafe_warning();
266
267 switch (prefix->fp_proto)
268 {
269 case FIB_PROTOCOL_IP4:
270 return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
271 &prefix->fp_addr.ip4,
272 prefix->fp_len,
273 dpo));
274 case FIB_PROTOCOL_IP6:
275 return (ip6_fib_table_fwding_dpo_remove(fib_index,
276 &prefix->fp_addr.ip6,
277 prefix->fp_len,
278 dpo));
279 case FIB_PROTOCOL_MPLS:
280 return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
281 prefix->fp_label,
282 prefix->fp_eos));
283 }
284}
285
286
287fib_node_index_t
288fib_table_entry_special_dpo_add (u32 fib_index,
289 const fib_prefix_t *prefix,
290 fib_source_t source,
291 fib_entry_flag_t flags,
292 const dpo_id_t *dpo)
293{
294 fib_node_index_t fib_entry_index;
295 fib_table_t *fib_table;
296
297 fib_table = fib_table_get(fib_index, prefix->fp_proto);
298 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
299
300 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
301 {
302 fib_entry_index = fib_entry_create_special(fib_index, prefix,
303 source, flags,
304 dpo);
305
306 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
307 fib_table->ft_src_route_counts[source]++;
308 }
309 else
310 {
311 int was_sourced;
312
313 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
314 fib_entry_special_add(fib_entry_index, source, flags, dpo);
315
316 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
317 {
318 fib_table->ft_src_route_counts[source]++;
319 }
320 }
321
322
323 return (fib_entry_index);
324}
325
326fib_node_index_t
Neale Ranns948e00f2016-10-20 13:39:34 +0100327fib_table_entry_special_dpo_update (u32 fib_index,
328 const fib_prefix_t *prefix,
329 fib_source_t source,
330 fib_entry_flag_t flags,
331 const dpo_id_t *dpo)
332{
333 fib_node_index_t fib_entry_index;
334 fib_table_t *fib_table;
335
336 fib_table = fib_table_get(fib_index, prefix->fp_proto);
337 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
338
339 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
340 {
341 fib_entry_index = fib_entry_create_special(fib_index, prefix,
342 source, flags,
343 dpo);
344
345 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
346 fib_table->ft_src_route_counts[source]++;
347 }
348 else
349 {
350 int was_sourced;
351
352 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
353
354 if (was_sourced)
355 fib_entry_special_update(fib_entry_index, source, flags, dpo);
356 else
357 fib_entry_special_add(fib_entry_index, source, flags, dpo);
358
359 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
360 {
361 fib_table->ft_src_route_counts[source]++;
362 }
363 }
364
365 return (fib_entry_index);
366}
367
368fib_node_index_t
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100369fib_table_entry_special_add (u32 fib_index,
370 const fib_prefix_t *prefix,
371 fib_source_t source,
372 fib_entry_flag_t flags,
373 adj_index_t adj_index)
374{
375 fib_node_index_t fib_entry_index;
Neale Ranns948e00f2016-10-20 13:39:34 +0100376 dpo_id_t tmp_dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100377
378 if (ADJ_INDEX_INVALID != adj_index)
379 {
380 dpo_set(&tmp_dpo,
381 DPO_ADJACENCY,
382 FIB_PROTOCOL_MAX,
383 adj_index);
384 }
385 else
386 {
387 dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
388 }
389
390 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
391 flags, &tmp_dpo);
392
393 dpo_unlock(&tmp_dpo);
394
395 return (fib_entry_index);
396}
397
398void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100399fib_table_entry_special_remove (u32 fib_index,
400 const fib_prefix_t *prefix,
401 fib_source_t source)
402{
403 /*
404 * 1 is it present
405 * yes => remove source
406 * 2 - is it still sourced?
407 * no => cover walk
408 */
409 fib_node_index_t fib_entry_index;
410 fib_table_t *fib_table;
411
412 fib_table = fib_table_get(fib_index, prefix->fp_proto);
413 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
414
415 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
416 {
417 /*
418 * removing an etry that does not exist. i'll allow it.
419 */
420 }
421 else
422 {
423 fib_entry_src_flag_t src_flag;
424 int was_sourced;
425
426 /*
427 * don't nobody go nowhere
428 */
429 fib_entry_lock(fib_entry_index);
430 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
431
432 src_flag = fib_entry_special_remove(fib_entry_index, source);
433
434 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
435 {
436 /*
437 * last source gone. remove from the table
438 */
439 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
440
441 /*
442 * now the entry is no longer in the table, we can
443 * inform the entries that it covers to re-calculate their cover
444 */
445 fib_entry_cover_change_notify(fib_entry_index,
446 FIB_NODE_INDEX_INVALID);
447 }
448 /*
449 * else
450 * still has sources, leave it be.
451 */
452 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
453 {
454 fib_table->ft_src_route_counts[source]--;
455 }
456
457 fib_entry_unlock(fib_entry_index);
458 }
459}
460
461/**
462 * fib_table_route_path_fixup
463 *
464 * Convert attached hosts to attached next-hops.
465 *
466 * This special case is required because an attached path will link to a
467 * glean, and the FIB entry will have the interface or API/CLI source. When
468 * the ARP/ND process is completes then that source (which will provide a
469 * complete adjacency) will be lower priority and so the FIB entry will
470 * remain linked to a glean and traffic will never reach the hosts. For
471 * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
472 * adjacency.
473 */
474static void
475fib_table_route_path_fixup (const fib_prefix_t *prefix,
476 fib_route_path_t *path)
477{
478 if (fib_prefix_is_host(prefix) &&
479 ip46_address_is_zero(&path->frp_addr) &&
480 path->frp_sw_if_index != ~0)
481 {
482 path->frp_addr = prefix->fp_addr;
Neale Ranns4b919a52017-03-11 05:55:21 -0800483 path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484 }
485}
486
487fib_node_index_t
488fib_table_entry_path_add (u32 fib_index,
489 const fib_prefix_t *prefix,
490 fib_source_t source,
491 fib_entry_flag_t flags,
492 fib_protocol_t next_hop_proto,
493 const ip46_address_t *next_hop,
494 u32 next_hop_sw_if_index,
495 u32 next_hop_fib_index,
496 u32 next_hop_weight,
Neale Rannsad422ed2016-11-02 14:20:04 +0000497 mpls_label_t *next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100498 fib_route_path_flags_t path_flags)
499{
500 fib_route_path_t path = {
501 .frp_proto = next_hop_proto,
502 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
503 .frp_sw_if_index = next_hop_sw_if_index,
504 .frp_fib_index = next_hop_fib_index,
505 .frp_weight = next_hop_weight,
506 .frp_flags = path_flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000507 .frp_label_stack = next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100508 };
509 fib_node_index_t fib_entry_index;
510 fib_route_path_t *paths = NULL;
511
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100512 vec_add1(paths, path);
513
514 fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
515 source, flags, paths);
516
517 vec_free(paths);
518 return (fib_entry_index);
519}
520
521fib_node_index_t
522fib_table_entry_path_add2 (u32 fib_index,
523 const fib_prefix_t *prefix,
524 fib_source_t source,
525 fib_entry_flag_t flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000526 fib_route_path_t *rpath)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100527{
528 fib_node_index_t fib_entry_index;
529 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000530 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100531
532 fib_table = fib_table_get(fib_index, prefix->fp_proto);
533 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
534
Neale Rannsad422ed2016-11-02 14:20:04 +0000535 for (ii = 0; ii < vec_len(rpath); ii++)
536 {
537 fib_table_route_path_fixup(prefix, &rpath[ii]);
538 }
539
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100540 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
541 {
542 fib_entry_index = fib_entry_create(fib_index, prefix,
543 source, flags,
544 rpath);
545
546 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
547 fib_table->ft_src_route_counts[source]++;
548 }
549 else
550 {
551 int was_sourced;
552
553 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
554 fib_entry_path_add(fib_entry_index, source, flags, rpath);;
555
556 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
557 {
558 fib_table->ft_src_route_counts[source]++;
559 }
560 }
561
562 return (fib_entry_index);
563}
564
565void
566fib_table_entry_path_remove2 (u32 fib_index,
Neale Rannsad422ed2016-11-02 14:20:04 +0000567 const fib_prefix_t *prefix,
568 fib_source_t source,
569 fib_route_path_t *rpath)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100570{
571 /*
572 * 1 is it present
573 * yes => remove source
574 * 2 - is it still sourced?
575 * no => cover walk
576 */
577 fib_node_index_t fib_entry_index;
578 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000579 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100580
581 fib_table = fib_table_get(fib_index, prefix->fp_proto);
582 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
583
Neale Rannsad422ed2016-11-02 14:20:04 +0000584 for (ii = 0; ii < vec_len(rpath); ii++)
585 {
586 fib_table_route_path_fixup(prefix, &rpath[ii]);
587 }
588
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100589 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
590 {
591 /*
592 * removing an etry that does not exist. i'll allow it.
593 */
594 }
595 else
596 {
597 fib_entry_src_flag_t src_flag;
598 int was_sourced;
599
600 /*
601 * don't nobody go nowhere
602 */
603 fib_entry_lock(fib_entry_index);
604 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
605
606 src_flag = fib_entry_path_remove(fib_entry_index, source, rpath);
607
608 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
609 {
610 /*
611 * last source gone. remove from the table
612 */
613 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
614
615 /*
616 * now the entry is no longer in the table, we can
617 * inform the entries that it covers to re-calculate their cover
618 */
619 fib_entry_cover_change_notify(fib_entry_index,
620 FIB_NODE_INDEX_INVALID);
621 }
622 /*
623 * else
624 * still has sources, leave it be.
625 */
626 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
627 {
628 fib_table->ft_src_route_counts[source]--;
629 }
630
631 fib_entry_unlock(fib_entry_index);
632 }
633}
634
635void
636fib_table_entry_path_remove (u32 fib_index,
637 const fib_prefix_t *prefix,
638 fib_source_t source,
639 fib_protocol_t next_hop_proto,
640 const ip46_address_t *next_hop,
641 u32 next_hop_sw_if_index,
642 u32 next_hop_fib_index,
643 u32 next_hop_weight,
644 fib_route_path_flags_t path_flags)
645{
646 /*
647 * 1 is it present
648 * yes => remove source
649 * 2 - is it still sourced?
650 * no => cover walk
651 */
652 fib_route_path_t path = {
653 .frp_proto = next_hop_proto,
654 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
655 .frp_sw_if_index = next_hop_sw_if_index,
656 .frp_fib_index = next_hop_fib_index,
657 .frp_weight = next_hop_weight,
658 .frp_flags = path_flags,
659 };
660 fib_route_path_t *paths = NULL;
661
662 fib_table_route_path_fixup(prefix, &path);
663 vec_add1(paths, path);
664
665 fib_table_entry_path_remove2(fib_index, prefix, source, paths);
666
667 vec_free(paths);
668}
669
670static int
671fib_route_path_cmp_for_sort (void * v1,
672 void * v2)
673{
674 return (fib_route_path_cmp(v1, v2));
675}
676
677fib_node_index_t
678fib_table_entry_update (u32 fib_index,
679 const fib_prefix_t *prefix,
680 fib_source_t source,
681 fib_entry_flag_t flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000682 fib_route_path_t *paths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100683{
684 fib_node_index_t fib_entry_index;
685 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000686 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100687
688 fib_table = fib_table_get(fib_index, prefix->fp_proto);
689 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
690
Neale Rannsad422ed2016-11-02 14:20:04 +0000691 for (ii = 0; ii < vec_len(paths); ii++)
692 {
693 fib_table_route_path_fixup(prefix, &paths[ii]);
694 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100695 /*
696 * sort the paths provided by the control plane. this means
697 * the paths and the extension on the entry will be sorted.
698 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000699 vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100700
701 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
702 {
703 fib_entry_index = fib_entry_create(fib_index, prefix,
704 source, flags,
705 paths);
706
707 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
708 fib_table->ft_src_route_counts[source]++;
709 }
710 else
711 {
712 int was_sourced;
713
714 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
715 fib_entry_update(fib_entry_index, source, flags, paths);
716
717 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
718 {
719 fib_table->ft_src_route_counts[source]++;
720 }
721 }
722
723 return (fib_entry_index);
724}
725
726fib_node_index_t
727fib_table_entry_update_one_path (u32 fib_index,
728 const fib_prefix_t *prefix,
729 fib_source_t source,
730 fib_entry_flag_t flags,
731 fib_protocol_t next_hop_proto,
732 const ip46_address_t *next_hop,
733 u32 next_hop_sw_if_index,
734 u32 next_hop_fib_index,
735 u32 next_hop_weight,
Neale Rannsad422ed2016-11-02 14:20:04 +0000736 mpls_label_t *next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100737 fib_route_path_flags_t path_flags)
738{
739 fib_node_index_t fib_entry_index;
740 fib_route_path_t path = {
741 .frp_proto = next_hop_proto,
742 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
743 .frp_sw_if_index = next_hop_sw_if_index,
744 .frp_fib_index = next_hop_fib_index,
745 .frp_weight = next_hop_weight,
746 .frp_flags = path_flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000747 .frp_label_stack = next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100748 };
749 fib_route_path_t *paths = NULL;
750
751 fib_table_route_path_fixup(prefix, &path);
752 vec_add1(paths, path);
753
754 fib_entry_index =
755 fib_table_entry_update(fib_index, prefix, source, flags, paths);
756
757 vec_free(paths);
758
759 return (fib_entry_index);
760}
761
762static void
763fib_table_entry_delete_i (u32 fib_index,
764 fib_node_index_t fib_entry_index,
765 const fib_prefix_t *prefix,
766 fib_source_t source)
767{
768 fib_entry_src_flag_t src_flag;
769 fib_table_t *fib_table;
770 int was_sourced;
771
772 fib_table = fib_table_get(fib_index, prefix->fp_proto);
773 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
774
775 /*
776 * don't nobody go nowhere
777 */
778 fib_entry_lock(fib_entry_index);
779
780 src_flag = fib_entry_delete(fib_entry_index, source);
781
782 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
783 {
784 /*
785 * last source gone. remove from the table
786 */
787 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
788
789 /*
790 * now the entry is no longer in the table, we can
791 * inform the entries that it covers to re-calculate their cover
792 */
793 fib_entry_cover_change_notify(fib_entry_index,
794 FIB_NODE_INDEX_INVALID);
795 }
796 /*
797 * else
798 * still has sources, leave it be.
799 */
800 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
801 {
802 fib_table->ft_src_route_counts[source]--;
803 }
804
805 fib_entry_unlock(fib_entry_index);
806}
807
808void
809fib_table_entry_delete (u32 fib_index,
810 const fib_prefix_t *prefix,
811 fib_source_t source)
812{
813 fib_node_index_t fib_entry_index;
814
815 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
816
817 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
818 {
819 /*
820 * removing an etry that does not exist.
821 * i'll allow it, but i won't like it.
822 */
823 clib_warning("%U not in FIB", format_fib_prefix, prefix);
824 }
825 else
826 {
827 fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
828 }
829}
830
831void
832fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
833 fib_source_t source)
834{
835 fib_prefix_t prefix;
836
837 fib_entry_get_prefix(fib_entry_index, &prefix);
838
839 fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
840 fib_entry_index, &prefix, source);
841}
842
843fib_node_index_t
844fib_table_entry_local_label_add (u32 fib_index,
845 const fib_prefix_t *prefix,
846 mpls_label_t label)
847{
848 fib_node_index_t fib_entry_index;
849
Neale Ranns1357f3b2016-10-16 12:01:42 -0700850 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
851
852 if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
853 !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
854 {
855 /*
856 * only source the prefix once. this allows the label change
857 * operation to work
858 */
859 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
860 FIB_SOURCE_MPLS,
861 FIB_ENTRY_FLAG_NONE,
862 NULL);
863 }
864
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100865 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
866
867 return (fib_entry_index);
868}
869
870void
871fib_table_entry_local_label_remove (u32 fib_index,
872 const fib_prefix_t *prefix,
873 mpls_label_t label)
874{
875 fib_node_index_t fib_entry_index;
876 const void *data;
877 mpls_label_t pl;
878
879 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
880
881 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
882 return;
883
884 data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
885
886 if (NULL == data)
887 return;
888
889 pl = *(mpls_label_t*)data;
890
891 if (pl != label)
892 return;
893
894 pl = MPLS_LABEL_INVALID;
895
896 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
897 fib_table_entry_special_remove(fib_index,
898 prefix,
899 FIB_SOURCE_MPLS);
900}
901
902u32
903fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
904 u32 sw_if_index)
905{
906 switch (proto)
907 {
908 case FIB_PROTOCOL_IP4:
909 return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
910 case FIB_PROTOCOL_IP6:
911 return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
912 case FIB_PROTOCOL_MPLS:
913 return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
914 }
915 return (~0);
916}
917
918flow_hash_config_t
919fib_table_get_flow_hash_config (u32 fib_index,
920 fib_protocol_t proto)
921{
922 switch (proto)
923 {
924 case FIB_PROTOCOL_IP4:
925 return (ip4_fib_table_get_flow_hash_config(fib_index));
926 case FIB_PROTOCOL_IP6:
927 return (ip6_fib_table_get_flow_hash_config(fib_index));
928 case FIB_PROTOCOL_MPLS:
929 return (mpls_fib_table_get_flow_hash_config(fib_index));
930 }
931 return (0);
932}
933
934
935u32
936fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
937 u32 sw_if_index)
938{
939 fib_table_t *fib_table;
940
941 fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
942 proto, sw_if_index),
943 proto);
944
945 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
946}
947
948u32
949fib_table_find (fib_protocol_t proto,
950 u32 table_id)
951{
952 switch (proto)
953 {
954 case FIB_PROTOCOL_IP4:
955 return (ip4_fib_index_from_table_id(table_id));
956 case FIB_PROTOCOL_IP6:
957 return (ip6_fib_index_from_table_id(table_id));
958 case FIB_PROTOCOL_MPLS:
959 return (mpls_fib_index_from_table_id(table_id));
960 }
961 return (~0);
962}
963
964u32
965fib_table_find_or_create_and_lock (fib_protocol_t proto,
966 u32 table_id)
967{
968 fib_table_t *fib_table;
969 fib_node_index_t fi;
970
971 switch (proto)
972 {
973 case FIB_PROTOCOL_IP4:
974 fi = ip4_fib_table_find_or_create_and_lock(table_id);
975 break;
976 case FIB_PROTOCOL_IP6:
977 fi = ip6_fib_table_find_or_create_and_lock(table_id);
978 break;
979 case FIB_PROTOCOL_MPLS:
980 fi = mpls_fib_table_find_or_create_and_lock(table_id);
981 break;
982 default:
983 return (~0);
984 }
985
986 fib_table = fib_table_get(fi, proto);
987
988 fib_table->ft_desc = format(NULL, "%U-VRF:%d",
989 format_fib_protocol, proto,
990 table_id);
991
992 return (fi);
993}
994
995u32
996fib_table_create_and_lock (fib_protocol_t proto,
997 const char *const fmt,
998 ...)
999{
1000 fib_table_t *fib_table;
1001 fib_node_index_t fi;
1002 va_list ap;
1003
1004 va_start(ap, fmt);
1005
1006 switch (proto)
1007 {
1008 case FIB_PROTOCOL_IP4:
1009 fi = ip4_fib_table_create_and_lock();
1010 break;
1011 case FIB_PROTOCOL_IP6:
1012 fi = ip6_fib_table_create_and_lock();
1013 break;
1014 case FIB_PROTOCOL_MPLS:
1015 fi = mpls_fib_table_create_and_lock();
1016 break;
1017 default:
1018 return (~0);
1019 }
1020
1021 fib_table = fib_table_get(fi, proto);
1022
1023 fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1024
1025 va_end(ap);
1026 return (fi);
1027}
1028
1029static void
1030fib_table_destroy (fib_table_t *fib_table)
1031{
1032 vec_free(fib_table->ft_desc);
1033
1034 switch (fib_table->ft_proto)
1035 {
1036 case FIB_PROTOCOL_IP4:
1037 ip4_fib_table_destroy(&fib_table->v4);
1038 break;
1039 case FIB_PROTOCOL_IP6:
1040 ip6_fib_table_destroy(fib_table->ft_index);
1041 break;
1042 case FIB_PROTOCOL_MPLS:
1043 mpls_fib_table_destroy(&fib_table->mpls);
1044 break;
1045 }
1046}
Neale Ranns5a8123b2017-01-26 01:18:23 -08001047
Neale Ranns32e1c012016-11-22 17:07:28 +00001048void
1049fib_table_walk (u32 fib_index,
1050 fib_protocol_t proto,
1051 fib_table_walk_fn_t fn,
1052 void *ctx)
1053{
1054 switch (proto)
1055 {
1056 case FIB_PROTOCOL_IP4:
1057 ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1058 break;
1059 case FIB_PROTOCOL_IP6:
1060 ip6_fib_table_walk(fib_index, fn, ctx);
1061 break;
1062 case FIB_PROTOCOL_MPLS:
1063 mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1064 break;
1065 }
1066}
1067
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001068void
1069fib_table_unlock (u32 fib_index,
1070 fib_protocol_t proto)
1071{
1072 fib_table_t *fib_table;
1073
1074 fib_table = fib_table_get(fib_index, proto);
1075 fib_table->ft_locks--;
1076
1077 if (0 == fib_table->ft_locks)
1078 {
1079 fib_table_destroy(fib_table);
1080 }
1081}
1082void
1083fib_table_lock (u32 fib_index,
1084 fib_protocol_t proto)
1085{
1086 fib_table_t *fib_table;
1087
1088 fib_table = fib_table_get(fib_index, proto);
1089 fib_table->ft_locks++;
1090}
1091
1092u32
1093fib_table_get_num_entries (u32 fib_index,
1094 fib_protocol_t proto,
1095 fib_source_t source)
1096{
1097 fib_table_t *fib_table;
1098
1099 fib_table = fib_table_get(fib_index, proto);
1100
1101 return (fib_table->ft_src_route_counts[source]);
1102}
1103
1104u8*
1105format_fib_table_name (u8* s, va_list ap)
1106{
1107 fib_node_index_t fib_index = va_arg(ap, fib_node_index_t);
1108 fib_protocol_t proto = va_arg(ap, int); // int promotion
1109 fib_table_t *fib_table;
1110
1111 fib_table = fib_table_get(fib_index, proto);
1112
1113 s = format(s, "%v", fib_table->ft_desc);
1114
1115 return (s);
1116}
1117
Neale Ranns32e1c012016-11-22 17:07:28 +00001118/**
1119 * @brief Table flush context. Store the indicies of matching FIB entries
1120 * that need to be removed.
1121 */
1122typedef struct fib_table_flush_ctx_t_
1123{
1124 /**
1125 * The list of entries to flush
1126 */
1127 fib_node_index_t *ftf_entries;
1128
1129 /**
1130 * The source we are flushing
1131 */
1132 fib_source_t ftf_source;
1133} fib_table_flush_ctx_t;
1134
1135static int
1136fib_table_flush_cb (fib_node_index_t fib_entry_index,
1137 void *arg)
1138{
1139 fib_table_flush_ctx_t *ctx = arg;
1140
1141 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1142 {
1143 vec_add1(ctx->ftf_entries, fib_entry_index);
1144 }
1145 return (1);
1146}
1147
1148
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001149void
1150fib_table_flush (u32 fib_index,
1151 fib_protocol_t proto,
1152 fib_source_t source)
1153{
Neale Ranns32e1c012016-11-22 17:07:28 +00001154 fib_node_index_t *fib_entry_index;
1155 fib_table_flush_ctx_t ctx = {
1156 .ftf_entries = NULL,
1157 .ftf_source = source,
1158 };
1159
1160 fib_table_walk(fib_index, proto,
1161 fib_table_flush_cb,
1162 &ctx);
1163
1164 vec_foreach(fib_entry_index, ctx.ftf_entries)
1165 {
Neale Rannsa8d9f302017-02-20 09:17:02 -08001166 fib_table_entry_delete_index(*fib_entry_index, source);
Neale Ranns32e1c012016-11-22 17:07:28 +00001167 }
1168
1169 vec_free(ctx.ftf_entries);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001170}