Line data Source code
1 : /*
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 :
26 : const static char * fib_table_flags_strings[] = FIB_TABLE_ATTRIBUTES;
27 :
28 : fib_table_t *
29 638197 : fib_table_get (fib_node_index_t index,
30 : fib_protocol_t proto)
31 : {
32 638197 : switch (proto)
33 : {
34 477669 : case FIB_PROTOCOL_IP4:
35 477669 : return (pool_elt_at_index(ip4_main.fibs, index));
36 137567 : case FIB_PROTOCOL_IP6:
37 137567 : return (pool_elt_at_index(ip6_main.fibs, index));
38 22961 : case FIB_PROTOCOL_MPLS:
39 22961 : return (pool_elt_at_index(mpls_main.fibs, index));
40 : }
41 0 : ASSERT(0);
42 0 : return (NULL);
43 : }
44 :
45 : static inline fib_node_index_t
46 142810 : fib_table_lookup_i (fib_table_t *fib_table,
47 : const fib_prefix_t *prefix)
48 : {
49 142810 : switch (prefix->fp_proto)
50 : {
51 113921 : case FIB_PROTOCOL_IP4:
52 113922 : return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
53 : &prefix->fp_addr.ip4,
54 113921 : prefix->fp_len));
55 28857 : case FIB_PROTOCOL_IP6:
56 28857 : return (ip6_fib_table_lookup(fib_table->ft_index,
57 : &prefix->fp_addr.ip6,
58 28857 : prefix->fp_len));
59 32 : case FIB_PROTOCOL_MPLS:
60 32 : return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
61 : prefix->fp_label,
62 : prefix->fp_eos));
63 : }
64 0 : return (FIB_NODE_INDEX_INVALID);
65 : }
66 :
67 : fib_node_index_t
68 67340 : fib_table_lookup (u32 fib_index,
69 : const fib_prefix_t *prefix)
70 : {
71 67340 : return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
72 : }
73 :
74 : static inline fib_node_index_t
75 245460 : fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
76 : const fib_prefix_t *prefix)
77 : {
78 245460 : switch (prefix->fp_proto)
79 : {
80 190295 : case FIB_PROTOCOL_IP4:
81 190295 : return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
82 : &prefix->fp_addr.ip4,
83 190295 : prefix->fp_len));
84 54143 : case FIB_PROTOCOL_IP6:
85 54143 : return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
86 : &prefix->fp_addr.ip6,
87 54143 : prefix->fp_len));
88 1022 : case FIB_PROTOCOL_MPLS:
89 1022 : return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
90 : prefix->fp_label,
91 : prefix->fp_eos));
92 : }
93 0 : return (FIB_NODE_INDEX_INVALID);
94 : }
95 :
96 : fib_node_index_t
97 178385 : fib_table_lookup_exact_match (u32 fib_index,
98 : const fib_prefix_t *prefix)
99 : {
100 178385 : return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
101 178385 : prefix->fp_proto),
102 : prefix));
103 : }
104 :
105 : static fib_node_index_t
106 75470 : fib_table_get_less_specific_i (fib_table_t *fib_table,
107 : const fib_prefix_t *prefix)
108 : {
109 : fib_prefix_t pfx;
110 :
111 75470 : pfx = *prefix;
112 :
113 75470 : if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
114 : {
115 0 : return (FIB_NODE_INDEX_INVALID);
116 : }
117 :
118 : /*
119 : * in the absence of a tree structure for the table that allows for an O(1)
120 : * parent get, a cheeky way to find the cover is to LPM for the prefix with
121 : * mask-1.
122 : * there should always be a cover, though it may be the default route. the
123 : * default route's cover is the default route.
124 : */
125 75470 : if (pfx.fp_len != 0) {
126 71647 : pfx.fp_len -= 1;
127 : }
128 :
129 75470 : return (fib_table_lookup_i(fib_table, &pfx));
130 : }
131 :
132 : fib_node_index_t
133 36179 : fib_table_get_less_specific (u32 fib_index,
134 : const fib_prefix_t *prefix)
135 : {
136 36179 : return (fib_table_get_less_specific_i(fib_table_get(fib_index,
137 36179 : prefix->fp_proto),
138 : prefix));
139 : }
140 :
141 : static void
142 29967 : fib_table_entry_remove (fib_table_t *fib_table,
143 : const fib_prefix_t *prefix,
144 : fib_node_index_t fib_entry_index)
145 : {
146 29967 : vlib_smp_unsafe_warning();
147 :
148 29967 : fib_table->ft_total_route_counts--;
149 :
150 29967 : switch (prefix->fp_proto)
151 : {
152 15812 : case FIB_PROTOCOL_IP4:
153 15812 : ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
154 : &prefix->fp_addr.ip4,
155 15812 : prefix->fp_len);
156 15812 : break;
157 13524 : case FIB_PROTOCOL_IP6:
158 13524 : ip6_fib_table_entry_remove(fib_table->ft_index,
159 : &prefix->fp_addr.ip6,
160 13524 : prefix->fp_len);
161 13524 : break;
162 631 : case FIB_PROTOCOL_MPLS:
163 631 : mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
164 : prefix->fp_label,
165 : prefix->fp_eos);
166 631 : break;
167 : }
168 :
169 29967 : fib_entry_unlock(fib_entry_index);
170 29967 : }
171 :
172 : static void
173 39922 : fib_table_post_insert_actions (fib_table_t *fib_table,
174 : const fib_prefix_t *prefix,
175 : fib_node_index_t fib_entry_index)
176 : {
177 : fib_node_index_t fib_entry_cover_index;
178 :
179 : /*
180 : * no cover relationships in the MPLS FIB
181 : */
182 39922 : if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
183 631 : return;
184 :
185 : /*
186 : * find the covering entry
187 : */
188 39291 : fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
189 : /*
190 : * the indicies are the same when the default route is first added
191 : */
192 39291 : if (fib_entry_cover_index != fib_entry_index)
193 : {
194 : /*
195 : * push any inherting sources from the cover onto the covered
196 : */
197 35720 : fib_entry_inherit(fib_entry_cover_index,
198 : fib_entry_index);
199 :
200 : /*
201 : * inform the covering entry that a new more specific
202 : * has been inserted beneath it.
203 : * If the prefix that has been inserted is a host route
204 : * then it is not possible that it will be the cover for any
205 : * other entry, so we can elide the walk. This is particularly
206 : * beneficial since there are often many host entries sharing the
207 : * same cover (i.e. ADJ or RR sourced entries).
208 : */
209 35720 : if (!fib_entry_is_host(fib_entry_index))
210 : {
211 9154 : fib_entry_cover_change_notify(fib_entry_cover_index,
212 : fib_entry_index);
213 : }
214 : }
215 : }
216 :
217 : static void
218 39922 : fib_table_entry_insert (fib_table_t *fib_table,
219 : const fib_prefix_t *prefix,
220 : fib_node_index_t fib_entry_index)
221 : {
222 39922 : vlib_smp_unsafe_warning();
223 :
224 39922 : fib_entry_lock(fib_entry_index);
225 39922 : fib_table->ft_total_route_counts++;
226 :
227 39922 : switch (prefix->fp_proto)
228 : {
229 21954 : case FIB_PROTOCOL_IP4:
230 21954 : ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
231 : &prefix->fp_addr.ip4,
232 21954 : prefix->fp_len,
233 : fib_entry_index);
234 21954 : break;
235 17337 : case FIB_PROTOCOL_IP6:
236 17337 : ip6_fib_table_entry_insert(fib_table->ft_index,
237 : &prefix->fp_addr.ip6,
238 17337 : prefix->fp_len,
239 : fib_entry_index);
240 17337 : break;
241 631 : case FIB_PROTOCOL_MPLS:
242 631 : mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
243 : prefix->fp_label,
244 : prefix->fp_eos,
245 : fib_entry_index);
246 631 : break;
247 : }
248 :
249 39922 : fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
250 39922 : }
251 :
252 : void
253 39656 : fib_table_fwding_dpo_update (u32 fib_index,
254 : const fib_prefix_t *prefix,
255 : const dpo_id_t *dpo)
256 : {
257 39656 : vlib_smp_unsafe_warning();
258 :
259 39656 : switch (prefix->fp_proto)
260 : {
261 21662 : case FIB_PROTOCOL_IP4:
262 21662 : return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
263 : &prefix->fp_addr.ip4,
264 21662 : prefix->fp_len,
265 : dpo));
266 17358 : case FIB_PROTOCOL_IP6:
267 17358 : return (ip6_fib_table_fwding_dpo_update(fib_index,
268 : &prefix->fp_addr.ip6,
269 17358 : prefix->fp_len,
270 : dpo));
271 636 : case FIB_PROTOCOL_MPLS:
272 636 : return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
273 : prefix->fp_label,
274 : prefix->fp_eos,
275 : dpo));
276 : }
277 : }
278 :
279 : void
280 29677 : fib_table_fwding_dpo_remove (u32 fib_index,
281 : const fib_prefix_t *prefix,
282 : const dpo_id_t *dpo)
283 : {
284 29677 : vlib_smp_unsafe_warning();
285 :
286 29677 : switch (prefix->fp_proto)
287 : {
288 15505 : case FIB_PROTOCOL_IP4:
289 31010 : return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
290 : &prefix->fp_addr.ip4,
291 15505 : prefix->fp_len,
292 : dpo,
293 : fib_table_get_less_specific(fib_index,
294 : prefix)));
295 13541 : case FIB_PROTOCOL_IP6:
296 13541 : return (ip6_fib_table_fwding_dpo_remove(fib_index,
297 : &prefix->fp_addr.ip6,
298 13541 : prefix->fp_len,
299 : dpo));
300 631 : case FIB_PROTOCOL_MPLS:
301 631 : return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
302 : prefix->fp_label,
303 : prefix->fp_eos));
304 : }
305 : }
306 :
307 : static void
308 44163 : fib_table_source_count_inc (fib_table_t *fib_table,
309 : fib_source_t source)
310 : {
311 44163 : vec_validate (fib_table->ft_src_route_counts, source);
312 44163 : fib_table->ft_src_route_counts[source]++;
313 44163 : }
314 :
315 : static void
316 34158 : fib_table_source_count_dec (fib_table_t *fib_table,
317 : fib_source_t source)
318 : {
319 34158 : vec_validate (fib_table->ft_src_route_counts, source);
320 34158 : fib_table->ft_src_route_counts[source]--;
321 34158 : }
322 :
323 : fib_node_index_t
324 21159 : fib_table_entry_special_dpo_add (u32 fib_index,
325 : const fib_prefix_t *prefix,
326 : fib_source_t source,
327 : fib_entry_flag_t flags,
328 : const dpo_id_t *dpo)
329 : {
330 : fib_node_index_t fib_entry_index;
331 : fib_table_t *fib_table;
332 :
333 21159 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
334 21159 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
335 :
336 21159 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
337 : {
338 15408 : fib_entry_index = fib_entry_create_special(fib_index, prefix,
339 : source, flags,
340 : dpo);
341 :
342 15408 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
343 15408 : fib_table_source_count_inc(fib_table, source);
344 : }
345 : else
346 : {
347 : int was_sourced;
348 :
349 5751 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
350 5751 : fib_entry_special_add(fib_entry_index, source, flags, dpo);
351 :
352 5751 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
353 : {
354 3982 : fib_table_source_count_inc(fib_table, source);
355 : }
356 : }
357 :
358 :
359 21159 : return (fib_entry_index);
360 : }
361 :
362 : fib_node_index_t
363 17 : fib_table_entry_special_dpo_update (u32 fib_index,
364 : const fib_prefix_t *prefix,
365 : fib_source_t source,
366 : fib_entry_flag_t flags,
367 : const dpo_id_t *dpo)
368 : {
369 : fib_node_index_t fib_entry_index;
370 : fib_table_t *fib_table;
371 :
372 17 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
373 17 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
374 :
375 17 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
376 : {
377 12 : fib_entry_index = fib_entry_create_special(fib_index, prefix,
378 : source, flags,
379 : dpo);
380 :
381 12 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
382 12 : fib_table_source_count_inc(fib_table, source);
383 : }
384 : else
385 : {
386 : int was_sourced;
387 :
388 5 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
389 :
390 5 : if (was_sourced)
391 1 : fib_entry_special_update(fib_entry_index, source, flags, dpo);
392 : else
393 4 : fib_entry_special_add(fib_entry_index, source, flags, dpo);
394 :
395 5 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
396 : {
397 4 : fib_table_source_count_inc(fib_table, source);
398 : }
399 : }
400 :
401 17 : return (fib_entry_index);
402 : }
403 :
404 : fib_node_index_t
405 17554 : fib_table_entry_special_add (u32 fib_index,
406 : const fib_prefix_t *prefix,
407 : fib_source_t source,
408 : fib_entry_flag_t flags)
409 : {
410 : fib_node_index_t fib_entry_index;
411 17554 : dpo_id_t tmp_dpo = DPO_INVALID;
412 :
413 17554 : dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
414 :
415 17554 : fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
416 : flags, &tmp_dpo);
417 :
418 17554 : dpo_unlock(&tmp_dpo);
419 :
420 17554 : return (fib_entry_index);
421 : }
422 :
423 : void
424 12285 : fib_table_entry_special_remove (u32 fib_index,
425 : const fib_prefix_t *prefix,
426 : fib_source_t source)
427 : {
428 : /*
429 : * 1 is it present
430 : * yes => remove source
431 : * 2 - is it still sourced?
432 : * no => cover walk
433 : */
434 : fib_node_index_t fib_entry_index;
435 : fib_table_t *fib_table;
436 :
437 12285 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
438 12285 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
439 :
440 12285 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
441 : {
442 : /*
443 : * removing an etry that does not exist. i'll allow it.
444 : */
445 : }
446 : else
447 : {
448 : fib_entry_src_flag_t src_flag;
449 : int was_sourced;
450 :
451 : /*
452 : * don't nobody go nowhere
453 : */
454 9849 : fib_entry_lock(fib_entry_index);
455 9849 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
456 :
457 9849 : src_flag = fib_entry_special_remove(fib_entry_index, source);
458 :
459 9849 : if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
460 : {
461 : /*
462 : * last source gone. remove from the table
463 : */
464 7875 : fib_table_entry_remove(fib_table, prefix, fib_entry_index);
465 :
466 : /*
467 : * now the entry is no longer in the table, we can
468 : * inform the entries that it covers to re-calculate their cover
469 : */
470 7875 : fib_entry_cover_change_notify(fib_entry_index,
471 : FIB_NODE_INDEX_INVALID);
472 : }
473 : /*
474 : * else
475 : * still has sources, leave it be.
476 : */
477 9849 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
478 : {
479 8161 : fib_table_source_count_dec(fib_table, source);
480 : }
481 :
482 9849 : fib_entry_unlock(fib_entry_index);
483 : }
484 12285 : }
485 :
486 : /**
487 : * fib_table_route_path_fixup
488 : *
489 : * Convert attached hosts to attached next-hops.
490 : *
491 : * This special case is required because an attached path will link to a
492 : * glean, and the FIB entry will have the interface or API/CLI source. When
493 : * the ARP/ND process is completes then that source (which will provide a
494 : * complete adjacency) will be lower priority and so the FIB entry will
495 : * remain linked to a glean and traffic will never reach the hosts. For
496 : * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
497 : * adjacency.
498 : */
499 : static void
500 47826 : fib_table_route_path_fixup (const fib_prefix_t *prefix,
501 : fib_entry_flag_t *eflags,
502 : fib_route_path_t *path)
503 : {
504 : /*
505 : * not all zeros next hop &&
506 : * is recursive path &&
507 : * nexthop is same as the route's address
508 : */
509 47826 : if ((!ip46_address_is_zero(&path->frp_addr)) &&
510 44216 : (~0 == path->frp_sw_if_index) &&
511 3680 : (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
512 : {
513 : /* Prefix recurses via itself */
514 2 : path->frp_flags |= FIB_ROUTE_PATH_DROP;
515 : }
516 93600 : if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
517 84698 : fib_prefix_is_host(prefix) &&
518 38924 : ip46_address_is_zero(&path->frp_addr) &&
519 656 : path->frp_sw_if_index != ~0 &&
520 591 : path->frp_proto != DPO_PROTO_ETHERNET)
521 : {
522 588 : path->frp_addr = prefix->fp_addr;
523 588 : path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
524 : }
525 47238 : else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
526 9112 : !(*eflags & FIB_ENTRY_FLAG_LOCAL))
527 : {
528 4518 : if (ip46_address_is_zero(&path->frp_addr))
529 : {
530 4518 : path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
531 4518 : fib_prefix_normalize(prefix, &path->frp_connected);
532 : }
533 : }
534 42720 : else if (fib_route_path_is_attached(path))
535 : {
536 14439 : path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
537 14439 : fib_prefix_normalize(prefix, &path->frp_connected);
538 : }
539 47826 : if (*eflags & FIB_ENTRY_FLAG_DROP)
540 : {
541 0 : path->frp_flags |= FIB_ROUTE_PATH_DROP;
542 : }
543 47826 : if (*eflags & FIB_ENTRY_FLAG_LOCAL)
544 : {
545 7126 : path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
546 : }
547 47826 : if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
548 : {
549 476 : path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
550 : }
551 47826 : if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
552 : {
553 7129 : *eflags |= FIB_ENTRY_FLAG_LOCAL;
554 :
555 7129 : if (path->frp_sw_if_index != ~0)
556 : {
557 7127 : *eflags |= FIB_ENTRY_FLAG_CONNECTED;
558 : }
559 : }
560 47826 : }
561 :
562 : fib_node_index_t
563 9839 : fib_table_entry_path_add (u32 fib_index,
564 : const fib_prefix_t *prefix,
565 : fib_source_t source,
566 : fib_entry_flag_t flags,
567 : dpo_proto_t next_hop_proto,
568 : const ip46_address_t *next_hop,
569 : u32 next_hop_sw_if_index,
570 : u32 next_hop_fib_index,
571 : u32 next_hop_weight,
572 : fib_mpls_label_t *next_hop_labels,
573 : fib_route_path_flags_t path_flags)
574 : {
575 9839 : fib_route_path_t path = {
576 : .frp_proto = next_hop_proto,
577 : .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
578 : .frp_sw_if_index = next_hop_sw_if_index,
579 : .frp_fib_index = next_hop_fib_index,
580 : .frp_weight = next_hop_weight,
581 : .frp_flags = path_flags,
582 : .frp_rpf_id = INDEX_INVALID,
583 : .frp_label_stack = next_hop_labels,
584 : };
585 : fib_node_index_t fib_entry_index;
586 9839 : fib_route_path_t *paths = NULL;
587 :
588 9839 : vec_add1(paths, path);
589 :
590 9839 : fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
591 : source, flags, paths);
592 :
593 9839 : vec_free(paths);
594 9839 : return (fib_entry_index);
595 : }
596 :
597 : static int
598 80115 : fib_route_path_cmp_for_sort (void * v1,
599 : void * v2)
600 : {
601 80115 : return (fib_route_path_cmp(v1, v2));
602 : }
603 :
604 : fib_node_index_t
605 9924 : fib_table_entry_path_add2 (u32 fib_index,
606 : const fib_prefix_t *prefix,
607 : fib_source_t source,
608 : fib_entry_flag_t flags,
609 : fib_route_path_t *rpaths)
610 : {
611 : fib_node_index_t fib_entry_index;
612 : fib_table_t *fib_table;
613 : u32 ii;
614 :
615 9924 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
616 9924 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
617 :
618 19991 : for (ii = 0; ii < vec_len(rpaths); ii++)
619 : {
620 10067 : fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
621 : }
622 : /*
623 : * sort the paths provided by the control plane. this means
624 : * the paths and the extension on the entry will be sorted.
625 : */
626 9924 : vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
627 :
628 9924 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
629 : {
630 9572 : fib_entry_index = fib_entry_create(fib_index, prefix,
631 : source, flags,
632 : rpaths);
633 :
634 9572 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
635 9572 : fib_table_source_count_inc(fib_table, source);
636 : }
637 : else
638 : {
639 : int was_sourced;
640 :
641 352 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
642 352 : fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
643 :
644 352 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
645 : {
646 67 : fib_table_source_count_inc(fib_table, source);
647 : }
648 : }
649 :
650 9924 : return (fib_entry_index);
651 : }
652 :
653 : void
654 5455 : fib_table_entry_path_remove2 (u32 fib_index,
655 : const fib_prefix_t *prefix,
656 : fib_source_t source,
657 : fib_route_path_t *rpaths)
658 : {
659 : /*
660 : * 1 is it present
661 : * yes => remove source
662 : * 2 - is it still sourced?
663 : * no => cover walk
664 : */
665 : fib_node_index_t fib_entry_index;
666 : fib_route_path_t *rpath;
667 : fib_table_t *fib_table;
668 :
669 5455 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
670 5455 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
671 :
672 5455 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
673 : {
674 : /*
675 : * removing an etry that does not exist. i'll allow it.
676 : */
677 : }
678 : else
679 : {
680 : fib_entry_src_flag_t src_flag;
681 : int was_sourced;
682 :
683 : /*
684 : * if it's not sourced, then there's nowt to remove
685 : */
686 5454 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
687 5454 : if (!was_sourced)
688 : {
689 0 : return;
690 : }
691 :
692 : /*
693 : * don't nobody go nowhere
694 : */
695 5454 : fib_entry_lock(fib_entry_index);
696 :
697 10908 : vec_foreach(rpath, rpaths)
698 : {
699 : fib_entry_flag_t eflags;
700 :
701 5454 : eflags = fib_entry_get_flags_for_source(fib_entry_index,
702 : source);
703 5454 : fib_table_route_path_fixup(prefix, &eflags, rpath);
704 : }
705 :
706 5454 : src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
707 :
708 5454 : if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
709 : {
710 : /*
711 : * last source gone. remove from the table
712 : */
713 5331 : fib_table_entry_remove(fib_table, prefix, fib_entry_index);
714 :
715 : /*
716 : * now the entry is no longer in the table, we can
717 : * inform the entries that it covers to re-calculate their cover
718 : */
719 5331 : fib_entry_cover_change_notify(fib_entry_index,
720 : FIB_NODE_INDEX_INVALID);
721 : }
722 : /*
723 : * else
724 : * still has sources, leave it be.
725 : */
726 5454 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
727 : {
728 5438 : fib_table_source_count_dec(fib_table, source);
729 : }
730 :
731 5454 : fib_entry_unlock(fib_entry_index);
732 : }
733 : }
734 :
735 : void
736 5444 : fib_table_entry_path_remove (u32 fib_index,
737 : const fib_prefix_t *prefix,
738 : fib_source_t source,
739 : dpo_proto_t next_hop_proto,
740 : const ip46_address_t *next_hop,
741 : u32 next_hop_sw_if_index,
742 : u32 next_hop_fib_index,
743 : u32 next_hop_weight,
744 : fib_route_path_flags_t path_flags)
745 : {
746 : /*
747 : * 1 is it present
748 : * yes => remove source
749 : * 2 - is it still sourced?
750 : * no => cover walk
751 : */
752 5444 : fib_route_path_t path = {
753 : .frp_proto = next_hop_proto,
754 : .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
755 : .frp_sw_if_index = next_hop_sw_if_index,
756 : .frp_fib_index = next_hop_fib_index,
757 : .frp_weight = next_hop_weight,
758 : .frp_flags = path_flags,
759 : };
760 5444 : fib_route_path_t *paths = NULL;
761 :
762 5444 : vec_add1(paths, path);
763 :
764 5444 : fib_table_entry_path_remove2(fib_index, prefix, source, paths);
765 :
766 5444 : vec_free(paths);
767 5444 : }
768 :
769 : fib_node_index_t
770 18235 : fib_table_entry_update (u32 fib_index,
771 : const fib_prefix_t *prefix,
772 : fib_source_t source,
773 : fib_entry_flag_t flags,
774 : fib_route_path_t *paths)
775 : {
776 : fib_node_index_t fib_entry_index;
777 : fib_table_t *fib_table;
778 : u32 ii;
779 :
780 18235 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
781 18235 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
782 :
783 50540 : for (ii = 0; ii < vec_len(paths); ii++)
784 : {
785 32305 : fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
786 : }
787 : /*
788 : * sort the paths provided by the control plane. this means
789 : * the paths and the extension on the entry will be sorted.
790 : */
791 18235 : vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
792 :
793 18235 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
794 : {
795 14930 : fib_entry_index = fib_entry_create(fib_index, prefix,
796 : source, flags,
797 : paths);
798 :
799 14930 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
800 14930 : fib_table_source_count_inc(fib_table, source);
801 : }
802 : else
803 : {
804 : int was_sourced;
805 :
806 3305 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
807 3305 : fib_entry_update(fib_entry_index, source, flags, paths);
808 :
809 3305 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
810 : {
811 188 : fib_table_source_count_inc(fib_table, source);
812 : }
813 : }
814 :
815 18235 : return (fib_entry_index);
816 : }
817 :
818 : fib_node_index_t
819 11753 : fib_table_entry_update_one_path (u32 fib_index,
820 : const fib_prefix_t *prefix,
821 : fib_source_t source,
822 : fib_entry_flag_t flags,
823 : dpo_proto_t next_hop_proto,
824 : const ip46_address_t *next_hop,
825 : u32 next_hop_sw_if_index,
826 : u32 next_hop_fib_index,
827 : u32 next_hop_weight,
828 : fib_mpls_label_t *next_hop_labels,
829 : fib_route_path_flags_t path_flags)
830 : {
831 : fib_node_index_t fib_entry_index;
832 11753 : fib_route_path_t path = {
833 : .frp_proto = next_hop_proto,
834 : .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
835 : .frp_sw_if_index = next_hop_sw_if_index,
836 : .frp_fib_index = next_hop_fib_index,
837 : .frp_weight = next_hop_weight,
838 : .frp_flags = path_flags,
839 : .frp_label_stack = next_hop_labels,
840 : };
841 11753 : fib_route_path_t *paths = NULL;
842 :
843 11753 : vec_add1(paths, path);
844 :
845 : fib_entry_index =
846 11753 : fib_table_entry_update(fib_index, prefix, source, flags, paths);
847 :
848 11753 : vec_free(paths);
849 :
850 11753 : return (fib_entry_index);
851 : }
852 :
853 : static void
854 20601 : fib_table_entry_delete_i (u32 fib_index,
855 : fib_node_index_t fib_entry_index,
856 : const fib_prefix_t *prefix,
857 : fib_source_t source)
858 : {
859 : fib_entry_src_flag_t src_flag;
860 : fib_table_t *fib_table;
861 : int was_sourced;
862 :
863 20601 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
864 20601 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
865 :
866 : /*
867 : * don't nobody go nowhere
868 : */
869 20601 : fib_entry_lock(fib_entry_index);
870 :
871 20601 : src_flag = fib_entry_delete(fib_entry_index, source);
872 :
873 20601 : if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
874 : {
875 : /*
876 : * last source gone. remove from the table
877 : */
878 16761 : fib_table_entry_remove(fib_table, prefix, fib_entry_index);
879 :
880 : /*
881 : * now the entry is no longer in the table, we can
882 : * inform the entries that it covers to re-calculate their cover
883 : */
884 16761 : fib_entry_cover_change_notify(fib_entry_index,
885 : FIB_NODE_INDEX_INVALID);
886 : }
887 : /*
888 : * else
889 : * still has sources, leave it be.
890 : */
891 20601 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
892 : {
893 20559 : fib_table_source_count_dec(fib_table, source);
894 : }
895 :
896 20601 : fib_entry_unlock(fib_entry_index);
897 20601 : }
898 :
899 : void
900 14457 : fib_table_entry_delete (u32 fib_index,
901 : const fib_prefix_t *prefix,
902 : fib_source_t source)
903 : {
904 : fib_node_index_t fib_entry_index;
905 :
906 14457 : fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
907 :
908 14457 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
909 : {
910 : /*
911 : * removing an etry that does not exist.
912 : * i'll allow it, but i won't like it.
913 : */
914 : if (0)
915 : clib_warning("%U not in FIB", format_fib_prefix, prefix);
916 : }
917 : else
918 : {
919 14359 : fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
920 : }
921 14457 : }
922 :
923 : void
924 6242 : fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
925 : fib_source_t source)
926 : {
927 : const fib_prefix_t *prefix;
928 :
929 6242 : prefix = fib_entry_get_prefix(fib_entry_index);
930 :
931 6242 : fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
932 : fib_entry_index, prefix, source);
933 6242 : }
934 :
935 : u32
936 158907 : fib_table_entry_get_stats_index (u32 fib_index,
937 : const fib_prefix_t *prefix)
938 : {
939 158907 : return (fib_entry_get_stats_index(
940 : fib_table_lookup_exact_match(fib_index, prefix)));
941 : }
942 :
943 : fib_node_index_t
944 141 : fib_table_entry_local_label_add (u32 fib_index,
945 : const fib_prefix_t *prefix,
946 : mpls_label_t label)
947 : {
948 : fib_node_index_t fib_entry_index;
949 :
950 141 : fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
951 :
952 282 : if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
953 141 : !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
954 : {
955 : /*
956 : * only source the prefix once. this allows the label change
957 : * operation to work
958 : */
959 140 : fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
960 : FIB_SOURCE_MPLS,
961 : FIB_ENTRY_FLAG_NONE,
962 : NULL);
963 : }
964 :
965 141 : fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
966 :
967 141 : return (fib_entry_index);
968 : }
969 :
970 : void
971 140 : fib_table_entry_local_label_remove (u32 fib_index,
972 : const fib_prefix_t *prefix,
973 : mpls_label_t label)
974 : {
975 : fib_node_index_t fib_entry_index;
976 : const void *data;
977 : mpls_label_t pl;
978 :
979 140 : fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
980 :
981 140 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
982 0 : return;
983 :
984 140 : data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
985 :
986 140 : if (NULL == data)
987 0 : return;
988 :
989 140 : pl = *(mpls_label_t*)data;
990 :
991 140 : if (pl != label)
992 0 : return;
993 :
994 140 : pl = MPLS_LABEL_INVALID;
995 :
996 140 : fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
997 140 : fib_table_entry_special_remove(fib_index,
998 : prefix,
999 : FIB_SOURCE_MPLS);
1000 : }
1001 :
1002 : u32
1003 106077 : fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
1004 : u32 sw_if_index)
1005 : {
1006 106077 : switch (proto)
1007 : {
1008 92492 : case FIB_PROTOCOL_IP4:
1009 92492 : return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
1010 13585 : case FIB_PROTOCOL_IP6:
1011 13585 : return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
1012 0 : case FIB_PROTOCOL_MPLS:
1013 0 : return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
1014 : }
1015 0 : return (~0);
1016 : }
1017 :
1018 : flow_hash_config_t
1019 39325 : fib_table_get_flow_hash_config (u32 fib_index,
1020 : fib_protocol_t proto)
1021 : {
1022 : fib_table_t *fib;
1023 :
1024 39325 : fib = fib_table_get(fib_index, proto);
1025 :
1026 39325 : return (fib->ft_flow_hash_config);
1027 : }
1028 :
1029 : flow_hash_config_t
1030 375 : fib_table_get_default_flow_hash_config (fib_protocol_t proto)
1031 : {
1032 375 : switch (proto)
1033 : {
1034 12 : case FIB_PROTOCOL_IP4:
1035 : case FIB_PROTOCOL_IP6:
1036 12 : return (IP_FLOW_HASH_DEFAULT);
1037 :
1038 363 : case FIB_PROTOCOL_MPLS:
1039 363 : return (MPLS_FLOW_HASH_DEFAULT);
1040 : }
1041 :
1042 0 : ASSERT(0);
1043 0 : return (IP_FLOW_HASH_DEFAULT);
1044 : }
1045 :
1046 : /**
1047 : * @brief Table set flow hash config context.
1048 : */
1049 : typedef struct fib_table_set_flow_hash_config_ctx_t_
1050 : {
1051 : /**
1052 : * the flow hash config to set
1053 : */
1054 : flow_hash_config_t hash_config;
1055 : } fib_table_set_flow_hash_config_ctx_t;
1056 :
1057 : static fib_table_walk_rc_t
1058 138 : fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1059 : void *arg)
1060 : {
1061 138 : fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1062 :
1063 138 : fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1064 :
1065 138 : return (FIB_TABLE_WALK_CONTINUE);
1066 : }
1067 :
1068 : void
1069 6 : fib_table_set_flow_hash_config (u32 fib_index,
1070 : fib_protocol_t proto,
1071 : flow_hash_config_t hash_config)
1072 : {
1073 6 : fib_table_set_flow_hash_config_ctx_t ctx = {
1074 : .hash_config = hash_config,
1075 : };
1076 : fib_table_t *fib;
1077 :
1078 6 : fib = fib_table_get(fib_index, proto);
1079 6 : fib->ft_flow_hash_config = hash_config;
1080 :
1081 6 : fib_table_walk(fib_index, proto,
1082 : fib_table_set_flow_hash_config_cb,
1083 : &ctx);
1084 6 : }
1085 :
1086 : u32
1087 10156 : fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1088 : u32 sw_if_index)
1089 : {
1090 : fib_table_t *fib_table;
1091 :
1092 10156 : fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1093 : proto, sw_if_index),
1094 : proto);
1095 :
1096 10156 : return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1097 : }
1098 :
1099 : u32
1100 195681 : fib_table_get_table_id (u32 fib_index,
1101 : fib_protocol_t proto)
1102 : {
1103 : fib_table_t *fib_table;
1104 :
1105 195681 : fib_table = fib_table_get(fib_index, proto);
1106 :
1107 195681 : return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1108 : }
1109 :
1110 : u32
1111 32046 : fib_table_find (fib_protocol_t proto,
1112 : u32 table_id)
1113 : {
1114 32046 : switch (proto)
1115 : {
1116 20701 : case FIB_PROTOCOL_IP4:
1117 20701 : return (ip4_fib_index_from_table_id(table_id));
1118 10333 : case FIB_PROTOCOL_IP6:
1119 10333 : return (ip6_fib_index_from_table_id(table_id));
1120 1012 : case FIB_PROTOCOL_MPLS:
1121 1012 : return (mpls_fib_index_from_table_id(table_id));
1122 : }
1123 0 : return (~0);
1124 : }
1125 :
1126 : static u32
1127 2589 : fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1128 : u32 table_id,
1129 : fib_source_t src,
1130 : const u8 *name)
1131 : {
1132 : fib_table_t *fib_table;
1133 : fib_node_index_t fi;
1134 :
1135 2589 : switch (proto)
1136 : {
1137 1632 : case FIB_PROTOCOL_IP4:
1138 1632 : fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
1139 1632 : break;
1140 759 : case FIB_PROTOCOL_IP6:
1141 759 : fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
1142 759 : break;
1143 198 : case FIB_PROTOCOL_MPLS:
1144 198 : fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
1145 198 : break;
1146 0 : default:
1147 0 : return (~0);
1148 : }
1149 :
1150 2589 : fib_table = fib_table_get(fi, proto);
1151 :
1152 2589 : if (NULL == fib_table->ft_desc)
1153 : {
1154 1566 : if (name && name[0])
1155 : {
1156 0 : fib_table->ft_desc = format(NULL, "%s", name);
1157 : }
1158 : else
1159 : {
1160 1566 : fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1161 : format_fib_protocol, proto,
1162 : table_id);
1163 : }
1164 : }
1165 :
1166 2589 : return (fi);
1167 : }
1168 :
1169 : u32
1170 2104 : fib_table_find_or_create_and_lock (fib_protocol_t proto,
1171 : u32 table_id,
1172 : fib_source_t src)
1173 : {
1174 2104 : return (fib_table_find_or_create_and_lock_i(proto, table_id,
1175 : src, NULL));
1176 : }
1177 :
1178 : u32
1179 485 : fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1180 : u32 table_id,
1181 : fib_source_t src,
1182 : const u8 *name)
1183 : {
1184 485 : return (fib_table_find_or_create_and_lock_i(proto, table_id,
1185 : src, name));
1186 : }
1187 :
1188 : u32
1189 6 : fib_table_create_and_lock (fib_protocol_t proto,
1190 : fib_source_t src,
1191 : const char *const fmt,
1192 : ...)
1193 : {
1194 : fib_table_t *fib_table;
1195 : fib_node_index_t fi;
1196 : va_list ap;
1197 :
1198 :
1199 6 : switch (proto)
1200 : {
1201 0 : case FIB_PROTOCOL_IP4:
1202 0 : fi = ip4_fib_table_create_and_lock(src);
1203 0 : break;
1204 6 : case FIB_PROTOCOL_IP6:
1205 6 : fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
1206 6 : break;
1207 0 : case FIB_PROTOCOL_MPLS:
1208 0 : fi = mpls_fib_table_create_and_lock(src);
1209 0 : break;
1210 0 : default:
1211 0 : return (~0);
1212 : }
1213 :
1214 6 : fib_table = fib_table_get(fi, proto);
1215 :
1216 6 : va_start(ap, fmt);
1217 :
1218 6 : fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1219 :
1220 6 : va_end(ap);
1221 6 : return (fi);
1222 : }
1223 :
1224 : static void
1225 2298 : fib_table_destroy (fib_table_t *fib_table)
1226 : {
1227 2298 : vec_free(fib_table->ft_desc);
1228 :
1229 2298 : switch (fib_table->ft_proto)
1230 : {
1231 252 : case FIB_PROTOCOL_IP4:
1232 252 : ip4_fib_table_destroy(fib_table->ft_index);
1233 252 : break;
1234 1997 : case FIB_PROTOCOL_IP6:
1235 1997 : ip6_fib_table_destroy(fib_table->ft_index);
1236 1997 : break;
1237 49 : case FIB_PROTOCOL_MPLS:
1238 49 : mpls_fib_table_destroy(fib_table->ft_index);
1239 49 : break;
1240 : }
1241 2298 : }
1242 :
1243 : void
1244 4462 : fib_table_walk (u32 fib_index,
1245 : fib_protocol_t proto,
1246 : fib_table_walk_fn_t fn,
1247 : void *ctx)
1248 : {
1249 4462 : switch (proto)
1250 : {
1251 2936 : case FIB_PROTOCOL_IP4:
1252 2936 : ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1253 2936 : break;
1254 1191 : case FIB_PROTOCOL_IP6:
1255 1191 : ip6_fib_table_walk(fib_index, fn, ctx);
1256 1191 : break;
1257 335 : case FIB_PROTOCOL_MPLS:
1258 335 : mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1259 335 : break;
1260 : }
1261 4462 : }
1262 :
1263 : typedef struct fib_table_walk_w_src_ctx_t_
1264 : {
1265 : fib_table_walk_fn_t fn;
1266 : void *data;
1267 : fib_source_t src;
1268 : } fib_table_walk_w_src_cxt_t;
1269 :
1270 : static fib_table_walk_rc_t
1271 40 : fib_table_walk_w_src_cb (fib_node_index_t fei,
1272 : void *arg)
1273 : {
1274 40 : fib_table_walk_w_src_cxt_t *ctx = arg;
1275 :
1276 40 : if (ctx->src == fib_entry_get_best_source(fei))
1277 : {
1278 10 : return (ctx->fn(fei, ctx->data));
1279 : }
1280 30 : return (FIB_TABLE_WALK_CONTINUE);
1281 : }
1282 :
1283 : void
1284 4 : fib_table_walk_w_src (u32 fib_index,
1285 : fib_protocol_t proto,
1286 : fib_source_t src,
1287 : fib_table_walk_fn_t fn,
1288 : void *data)
1289 : {
1290 4 : fib_table_walk_w_src_cxt_t ctx = {
1291 : .fn = fn,
1292 : .src = src,
1293 : .data = data,
1294 : };
1295 :
1296 4 : fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
1297 4 : }
1298 :
1299 : void
1300 62 : fib_table_sub_tree_walk (u32 fib_index,
1301 : fib_protocol_t proto,
1302 : const fib_prefix_t *root,
1303 : fib_table_walk_fn_t fn,
1304 : void *ctx)
1305 : {
1306 62 : switch (proto)
1307 : {
1308 56 : case FIB_PROTOCOL_IP4:
1309 56 : ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1310 56 : break;
1311 6 : case FIB_PROTOCOL_IP6:
1312 6 : ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1313 6 : break;
1314 0 : case FIB_PROTOCOL_MPLS:
1315 0 : break;
1316 : }
1317 62 : }
1318 :
1319 : static void
1320 6423 : fib_table_lock_dec (fib_table_t *fib_table,
1321 : fib_source_t source)
1322 : {
1323 6423 : vec_validate(fib_table->ft_locks, source);
1324 :
1325 6423 : ASSERT(fib_table->ft_locks[source] > 0);
1326 6423 : fib_table->ft_locks[source]--;
1327 6423 : fib_table->ft_total_locks--;
1328 6423 : }
1329 :
1330 : static void
1331 8257 : fib_table_lock_inc (fib_table_t *fib_table,
1332 : fib_source_t source)
1333 : {
1334 8257 : vec_validate(fib_table->ft_locks, source);
1335 :
1336 8257 : ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1337 8257 : fib_table->ft_locks[source]++;
1338 8257 : fib_table->ft_total_locks++;
1339 8257 : }
1340 :
1341 :
1342 : static void
1343 421 : fib_table_lock_clear (fib_table_t *fib_table,
1344 : fib_source_t source)
1345 : {
1346 421 : vec_validate(fib_table->ft_locks, source);
1347 :
1348 421 : ASSERT(fib_table->ft_locks[source] <= 1);
1349 421 : if (fib_table->ft_locks[source])
1350 : {
1351 421 : fib_table->ft_locks[source]--;
1352 421 : fib_table->ft_total_locks--;
1353 : }
1354 421 : }
1355 :
1356 : static void
1357 489 : fib_table_lock_set (fib_table_t *fib_table,
1358 : fib_source_t source)
1359 : {
1360 489 : vec_validate(fib_table->ft_locks, source);
1361 :
1362 489 : ASSERT(fib_table->ft_locks[source] <= 1);
1363 489 : ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1364 489 : if (!fib_table->ft_locks[source])
1365 : {
1366 439 : fib_table->ft_locks[source]++;
1367 439 : fib_table->ft_total_locks++;
1368 : }
1369 489 : }
1370 :
1371 : void
1372 6844 : fib_table_unlock (u32 fib_index,
1373 : fib_protocol_t proto,
1374 : fib_source_t source)
1375 : {
1376 : fib_table_t *fib_table;
1377 :
1378 6844 : fib_table = fib_table_get(fib_index, proto);
1379 :
1380 6844 : if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1381 421 : fib_table_lock_clear(fib_table, source);
1382 : else
1383 6423 : fib_table_lock_dec(fib_table, source);
1384 :
1385 6844 : if (0 == fib_table->ft_total_locks)
1386 : {
1387 : /*
1388 : * no more lock from any source - kill it
1389 : */
1390 2298 : fib_table_destroy(fib_table);
1391 : }
1392 6844 : }
1393 :
1394 : void
1395 8746 : fib_table_lock (u32 fib_index,
1396 : fib_protocol_t proto,
1397 : fib_source_t source)
1398 : {
1399 : fib_table_t *fib_table;
1400 :
1401 8746 : fib_table = fib_table_get(fib_index, proto);
1402 :
1403 8746 : if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1404 489 : fib_table_lock_set(fib_table, source);
1405 : else
1406 8257 : fib_table_lock_inc(fib_table, source);
1407 8746 : }
1408 :
1409 : u32
1410 1884 : fib_table_get_num_entries (u32 fib_index,
1411 : fib_protocol_t proto,
1412 : fib_source_t source)
1413 : {
1414 : fib_table_t *fib_table;
1415 :
1416 1884 : fib_table = fib_table_get(fib_index, proto);
1417 :
1418 1884 : return (fib_table->ft_src_route_counts[source]);
1419 : }
1420 :
1421 : u8*
1422 640 : format_fib_table_name (u8* s, va_list* ap)
1423 : {
1424 640 : fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1425 640 : fib_protocol_t proto = va_arg(*ap, int); // int promotion
1426 : fib_table_t *fib_table;
1427 :
1428 640 : fib_table = fib_table_get(fib_index, proto);
1429 :
1430 640 : s = format(s, "%v", fib_table->ft_desc);
1431 :
1432 640 : return (s);
1433 : }
1434 :
1435 : u8*
1436 572 : format_fib_table_flags (u8 *s, va_list *args)
1437 : {
1438 572 : fib_table_flags_t flags = va_arg(*args, int);
1439 : fib_table_attribute_t attr;
1440 :
1441 572 : if (!flags)
1442 : {
1443 572 : return format(s, "none");
1444 : }
1445 :
1446 0 : FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1447 0 : if (1 << attr & flags) {
1448 0 : s = format(s, "%s", fib_table_flags_strings[attr]);
1449 : }
1450 : }
1451 :
1452 0 : return (s);
1453 : }
1454 :
1455 : /**
1456 : * @brief Table flush context. Store the indicies of matching FIB entries
1457 : * that need to be removed.
1458 : */
1459 : typedef struct fib_table_flush_ctx_t_
1460 : {
1461 : /**
1462 : * The list of entries to flush
1463 : */
1464 : fib_node_index_t *ftf_entries;
1465 :
1466 : /**
1467 : * The source we are flushing
1468 : */
1469 : fib_source_t ftf_source;
1470 : } fib_table_flush_ctx_t;
1471 :
1472 : static fib_table_walk_rc_t
1473 269 : fib_table_flush_cb (fib_node_index_t fib_entry_index,
1474 : void *arg)
1475 : {
1476 269 : fib_table_flush_ctx_t *ctx = arg;
1477 :
1478 269 : if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1479 : {
1480 156 : vec_add1(ctx->ftf_entries, fib_entry_index);
1481 : }
1482 269 : return (FIB_TABLE_WALK_CONTINUE);
1483 : }
1484 :
1485 : void
1486 34 : fib_table_flush (u32 fib_index,
1487 : fib_protocol_t proto,
1488 : fib_source_t source)
1489 : {
1490 : fib_node_index_t *fib_entry_index;
1491 34 : fib_table_flush_ctx_t ctx = {
1492 : .ftf_entries = NULL,
1493 : .ftf_source = source,
1494 : };
1495 :
1496 34 : fib_table_walk(fib_index, proto,
1497 : fib_table_flush_cb,
1498 : &ctx);
1499 :
1500 190 : vec_foreach(fib_entry_index, ctx.ftf_entries)
1501 : {
1502 156 : fib_table_entry_delete_index(*fib_entry_index, source);
1503 : }
1504 :
1505 34 : vec_free(ctx.ftf_entries);
1506 34 : }
1507 :
1508 : static fib_table_walk_rc_t
1509 552 : fib_table_mark_cb (fib_node_index_t fib_entry_index,
1510 : void *arg)
1511 : {
1512 552 : fib_table_flush_ctx_t *ctx = arg;
1513 :
1514 552 : if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1515 : {
1516 468 : fib_entry_mark(fib_entry_index, ctx->ftf_source);
1517 : }
1518 552 : return (FIB_TABLE_WALK_CONTINUE);
1519 : }
1520 :
1521 : void
1522 24 : fib_table_mark (u32 fib_index,
1523 : fib_protocol_t proto,
1524 : fib_source_t source)
1525 : {
1526 24 : fib_table_flush_ctx_t ctx = {
1527 : .ftf_source = source,
1528 : };
1529 : fib_table_t *fib_table;
1530 :
1531 24 : fib_table = fib_table_get(fib_index, proto);
1532 :
1533 24 : fib_table->ft_epoch++;
1534 24 : fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1535 :
1536 24 : fib_table_walk(fib_index, proto,
1537 : fib_table_mark_cb,
1538 : &ctx);
1539 24 : }
1540 :
1541 : static fib_table_walk_rc_t
1542 552 : fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1543 : void *arg)
1544 : {
1545 552 : fib_table_flush_ctx_t *ctx = arg;
1546 :
1547 552 : if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1548 : {
1549 228 : vec_add1(ctx->ftf_entries, fib_entry_index);
1550 : }
1551 552 : return (FIB_TABLE_WALK_CONTINUE);
1552 : }
1553 :
1554 : void
1555 24 : fib_table_sweep (u32 fib_index,
1556 : fib_protocol_t proto,
1557 : fib_source_t source)
1558 : {
1559 24 : fib_table_flush_ctx_t ctx = {
1560 : .ftf_source = source,
1561 : };
1562 : fib_node_index_t *fib_entry_index;
1563 : fib_table_t *fib_table;
1564 :
1565 24 : fib_table = fib_table_get(fib_index, proto);
1566 :
1567 24 : fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1568 :
1569 24 : fib_table_walk(fib_index, proto,
1570 : fib_table_sweep_cb,
1571 : &ctx);
1572 :
1573 252 : vec_foreach(fib_entry_index, ctx.ftf_entries)
1574 : {
1575 228 : fib_table_entry_delete_index(*fib_entry_index, source);
1576 : }
1577 :
1578 24 : vec_free(ctx.ftf_entries);
1579 24 : }
1580 :
1581 : u8 *
1582 1 : format_fib_table_memory (u8 *s, va_list *args)
1583 : {
1584 1 : s = format(s, "%U", format_ip4_fib_table_memory);
1585 1 : s = format(s, "%U", format_ip6_fib_table_memory);
1586 1 : s = format(s, "%U", format_mpls_fib_table_memory);
1587 :
1588 1 : return (s);
1589 : }
|