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 645275 : fib_table_get (fib_node_index_t index,
30 : fib_protocol_t proto)
31 : {
32 645275 : switch (proto)
33 : {
34 481278 : case FIB_PROTOCOL_IP4:
35 481278 : return (pool_elt_at_index(ip4_main.fibs, index));
36 141036 : case FIB_PROTOCOL_IP6:
37 141036 : 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 144646 : fib_table_lookup_i (fib_table_t *fib_table,
47 : const fib_prefix_t *prefix)
48 : {
49 144646 : switch (prefix->fp_proto)
50 : {
51 114982 : case FIB_PROTOCOL_IP4:
52 114981 : return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
53 : &prefix->fp_addr.ip4,
54 114982 : prefix->fp_len));
55 29632 : case FIB_PROTOCOL_IP6:
56 29632 : return (ip6_fib_table_lookup(fib_table->ft_index,
57 : &prefix->fp_addr.ip6,
58 29632 : 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 67353 : fib_table_lookup (u32 fib_index,
69 : const fib_prefix_t *prefix)
70 : {
71 67353 : return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
72 : }
73 :
74 : static inline fib_node_index_t
75 248538 : fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
76 : const fib_prefix_t *prefix)
77 : {
78 248538 : switch (prefix->fp_proto)
79 : {
80 191902 : case FIB_PROTOCOL_IP4:
81 191902 : return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
82 : &prefix->fp_addr.ip4,
83 191902 : prefix->fp_len));
84 55614 : case FIB_PROTOCOL_IP6:
85 55614 : return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
86 : &prefix->fp_addr.ip6,
87 55614 : 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 179498 : fib_table_lookup_exact_match (u32 fib_index,
98 : const fib_prefix_t *prefix)
99 : {
100 179498 : return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
101 179498 : prefix->fp_proto),
102 : prefix));
103 : }
104 :
105 : static fib_node_index_t
106 77296 : 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 77296 : pfx = *prefix;
112 :
113 77296 : 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 77296 : if (pfx.fp_len != 0) {
126 73348 : pfx.fp_len -= 1;
127 : }
128 :
129 77296 : return (fib_table_lookup_i(fib_table, &pfx));
130 : }
131 :
132 : fib_node_index_t
133 37049 : fib_table_get_less_specific (u32 fib_index,
134 : const fib_prefix_t *prefix)
135 : {
136 37049 : return (fib_table_get_less_specific_i(fib_table_get(fib_index,
137 37049 : prefix->fp_proto),
138 : prefix));
139 : }
140 :
141 : static void
142 30860 : 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 30860 : vlib_smp_unsafe_warning();
147 :
148 30860 : fib_table->ft_total_route_counts--;
149 :
150 30860 : switch (prefix->fp_proto)
151 : {
152 16239 : case FIB_PROTOCOL_IP4:
153 16239 : ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
154 : &prefix->fp_addr.ip4,
155 16239 : prefix->fp_len);
156 16239 : break;
157 13990 : case FIB_PROTOCOL_IP6:
158 13990 : ip6_fib_table_entry_remove(fib_table->ft_index,
159 : &prefix->fp_addr.ip6,
160 13990 : prefix->fp_len);
161 13990 : 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 30860 : fib_entry_unlock(fib_entry_index);
170 30860 : }
171 :
172 : static void
173 40878 : 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 40878 : if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
183 631 : return;
184 :
185 : /*
186 : * find the covering entry
187 : */
188 40247 : 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 40247 : if (fib_entry_cover_index != fib_entry_index)
193 : {
194 : /*
195 : * push any inherting sources from the cover onto the covered
196 : */
197 36564 : 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 36564 : if (!fib_entry_is_host(fib_entry_index))
210 : {
211 9433 : fib_entry_cover_change_notify(fib_entry_cover_index,
212 : fib_entry_index);
213 : }
214 : }
215 : }
216 :
217 : static void
218 40878 : 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 40878 : vlib_smp_unsafe_warning();
223 :
224 40878 : fib_entry_lock(fib_entry_index);
225 40878 : fib_table->ft_total_route_counts++;
226 :
227 40878 : switch (prefix->fp_proto)
228 : {
229 22420 : case FIB_PROTOCOL_IP4:
230 22420 : ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
231 : &prefix->fp_addr.ip4,
232 22420 : prefix->fp_len,
233 : fib_entry_index);
234 22420 : break;
235 17827 : case FIB_PROTOCOL_IP6:
236 17827 : ip6_fib_table_entry_insert(fib_table->ft_index,
237 : &prefix->fp_addr.ip6,
238 17827 : prefix->fp_len,
239 : fib_entry_index);
240 17827 : 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 40878 : fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
250 40878 : }
251 :
252 : void
253 40613 : fib_table_fwding_dpo_update (u32 fib_index,
254 : const fib_prefix_t *prefix,
255 : const dpo_id_t *dpo)
256 : {
257 40613 : vlib_smp_unsafe_warning();
258 :
259 40613 : switch (prefix->fp_proto)
260 : {
261 22127 : case FIB_PROTOCOL_IP4:
262 22127 : return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
263 : &prefix->fp_addr.ip4,
264 22127 : prefix->fp_len,
265 : dpo));
266 17850 : case FIB_PROTOCOL_IP6:
267 17850 : return (ip6_fib_table_fwding_dpo_update(fib_index,
268 : &prefix->fp_addr.ip6,
269 17850 : 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 30572 : fib_table_fwding_dpo_remove (u32 fib_index,
281 : const fib_prefix_t *prefix,
282 : const dpo_id_t *dpo)
283 : {
284 30572 : vlib_smp_unsafe_warning();
285 :
286 30572 : switch (prefix->fp_proto)
287 : {
288 15932 : case FIB_PROTOCOL_IP4:
289 31864 : return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
290 : &prefix->fp_addr.ip4,
291 15932 : prefix->fp_len,
292 : dpo,
293 : fib_table_get_less_specific(fib_index,
294 : prefix)));
295 14009 : case FIB_PROTOCOL_IP6:
296 14009 : return (ip6_fib_table_fwding_dpo_remove(fib_index,
297 : &prefix->fp_addr.ip6,
298 14009 : 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 45344 : fib_table_source_count_inc (fib_table_t *fib_table,
309 : fib_source_t source)
310 : {
311 45344 : vec_validate (fib_table->ft_src_route_counts, source);
312 45344 : fib_table->ft_src_route_counts[source]++;
313 45344 : }
314 :
315 : static void
316 35276 : fib_table_source_count_dec (fib_table_t *fib_table,
317 : fib_source_t source)
318 : {
319 35276 : vec_validate (fib_table->ft_src_route_counts, source);
320 35276 : fib_table->ft_src_route_counts[source]--;
321 35276 : }
322 :
323 : fib_node_index_t
324 21942 : 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 21942 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
334 21942 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
335 :
336 21942 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
337 : {
338 15854 : fib_entry_index = fib_entry_create_special(fib_index, prefix,
339 : source, flags,
340 : dpo);
341 :
342 15854 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
343 15854 : fib_table_source_count_inc(fib_table, source);
344 : }
345 : else
346 : {
347 : int was_sourced;
348 :
349 6088 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
350 6088 : fib_entry_special_add(fib_entry_index, source, flags, dpo);
351 :
352 6088 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
353 : {
354 4206 : fib_table_source_count_inc(fib_table, source);
355 : }
356 : }
357 :
358 :
359 21942 : 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 18246 : 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 18246 : dpo_id_t tmp_dpo = DPO_INVALID;
412 :
413 18246 : dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
414 :
415 18246 : fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
416 : flags, &tmp_dpo);
417 :
418 18246 : dpo_unlock(&tmp_dpo);
419 :
420 18246 : return (fib_entry_index);
421 : }
422 :
423 : void
424 12741 : 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 12741 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
438 12741 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
439 :
440 12741 : 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 10240 : fib_entry_lock(fib_entry_index);
455 10240 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
456 :
457 10240 : src_flag = fib_entry_special_remove(fib_entry_index, source);
458 :
459 10240 : if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
460 : {
461 : /*
462 : * last source gone. remove from the table
463 : */
464 8158 : 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 8158 : 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 10240 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
478 : {
479 8444 : fib_table_source_count_dec(fib_table, source);
480 : }
481 :
482 10240 : fib_entry_unlock(fib_entry_index);
483 : }
484 12741 : }
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 48552 : 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 48552 : if ((!ip46_address_is_zero(&path->frp_addr)) &&
510 44927 : (~0 == path->frp_sw_if_index) &&
511 3796 : (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 94985 : if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
517 85808 : fib_prefix_is_host(prefix) &&
518 39375 : ip46_address_is_zero(&path->frp_addr) &&
519 587 : path->frp_sw_if_index != ~0 &&
520 522 : path->frp_proto != DPO_PROTO_ETHERNET)
521 : {
522 519 : path->frp_addr = prefix->fp_addr;
523 519 : path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
524 : }
525 48033 : else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
526 9376 : !(*eflags & FIB_ENTRY_FLAG_LOCAL))
527 : {
528 4650 : if (ip46_address_is_zero(&path->frp_addr))
529 : {
530 4650 : path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
531 4650 : fib_prefix_normalize(prefix, &path->frp_connected);
532 : }
533 : }
534 43383 : else if (fib_route_path_is_attached(path))
535 : {
536 14507 : path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
537 : /*
538 : * attached prefixes are not suitable as the source of ARP requests
539 : * so don't save the prefix in the glean adj
540 : */
541 14507 : clib_memset(&path->frp_connected, 0, sizeof(path->frp_connected));
542 : }
543 48552 : if (*eflags & FIB_ENTRY_FLAG_DROP)
544 : {
545 0 : path->frp_flags |= FIB_ROUTE_PATH_DROP;
546 : }
547 48552 : if (*eflags & FIB_ENTRY_FLAG_LOCAL)
548 : {
549 7255 : path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
550 : }
551 48552 : if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
552 : {
553 406 : path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
554 : }
555 48552 : if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
556 : {
557 7258 : *eflags |= FIB_ENTRY_FLAG_LOCAL;
558 :
559 7258 : if (path->frp_sw_if_index != ~0)
560 : {
561 7256 : *eflags |= FIB_ENTRY_FLAG_CONNECTED;
562 : }
563 : }
564 48552 : }
565 :
566 : fib_node_index_t
567 9976 : fib_table_entry_path_add (u32 fib_index,
568 : const fib_prefix_t *prefix,
569 : fib_source_t source,
570 : fib_entry_flag_t flags,
571 : dpo_proto_t next_hop_proto,
572 : const ip46_address_t *next_hop,
573 : u32 next_hop_sw_if_index,
574 : u32 next_hop_fib_index,
575 : u32 next_hop_weight,
576 : fib_mpls_label_t *next_hop_labels,
577 : fib_route_path_flags_t path_flags)
578 : {
579 9976 : fib_route_path_t path = {
580 : .frp_proto = next_hop_proto,
581 : .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
582 : .frp_sw_if_index = next_hop_sw_if_index,
583 : .frp_fib_index = next_hop_fib_index,
584 : .frp_weight = next_hop_weight,
585 : .frp_flags = path_flags,
586 : .frp_rpf_id = INDEX_INVALID,
587 : .frp_label_stack = next_hop_labels,
588 : };
589 : fib_node_index_t fib_entry_index;
590 9976 : fib_route_path_t *paths = NULL;
591 :
592 9976 : vec_add1(paths, path);
593 :
594 9976 : fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
595 : source, flags, paths);
596 :
597 9976 : vec_free(paths);
598 9976 : return (fib_entry_index);
599 : }
600 :
601 : static int
602 80115 : fib_route_path_cmp_for_sort (void * v1,
603 : void * v2)
604 : {
605 80115 : return (fib_route_path_cmp(v1, v2));
606 : }
607 :
608 : fib_node_index_t
609 10069 : fib_table_entry_path_add2 (u32 fib_index,
610 : const fib_prefix_t *prefix,
611 : fib_source_t source,
612 : fib_entry_flag_t flags,
613 : fib_route_path_t *rpaths)
614 : {
615 : fib_node_index_t fib_entry_index;
616 : fib_table_t *fib_table;
617 : u32 ii;
618 :
619 10069 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
620 10069 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
621 :
622 20281 : for (ii = 0; ii < vec_len(rpaths); ii++)
623 : {
624 10212 : fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
625 : }
626 : /*
627 : * sort the paths provided by the control plane. this means
628 : * the paths and the extension on the entry will be sorted.
629 : */
630 10069 : vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
631 :
632 10069 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
633 : {
634 9712 : fib_entry_index = fib_entry_create(fib_index, prefix,
635 : source, flags,
636 : rpaths);
637 :
638 9712 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
639 9712 : fib_table_source_count_inc(fib_table, source);
640 : }
641 : else
642 : {
643 : int was_sourced;
644 :
645 357 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
646 357 : fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
647 :
648 357 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
649 : {
650 68 : fib_table_source_count_inc(fib_table, source);
651 : }
652 : }
653 :
654 10069 : return (fib_entry_index);
655 : }
656 :
657 : void
658 5598 : fib_table_entry_path_remove2 (u32 fib_index,
659 : const fib_prefix_t *prefix,
660 : fib_source_t source,
661 : fib_route_path_t *rpaths)
662 : {
663 : /*
664 : * 1 is it present
665 : * yes => remove source
666 : * 2 - is it still sourced?
667 : * no => cover walk
668 : */
669 : fib_node_index_t fib_entry_index;
670 : fib_route_path_t *rpath;
671 : fib_table_t *fib_table;
672 :
673 5598 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
674 5598 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
675 :
676 5598 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
677 : {
678 : /*
679 : * removing an etry that does not exist. i'll allow it.
680 : */
681 : }
682 : else
683 : {
684 : fib_entry_src_flag_t src_flag;
685 : int was_sourced;
686 :
687 : /*
688 : * if it's not sourced, then there's nowt to remove
689 : */
690 5597 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
691 5597 : if (!was_sourced)
692 : {
693 0 : return;
694 : }
695 :
696 : /*
697 : * don't nobody go nowhere
698 : */
699 5597 : fib_entry_lock(fib_entry_index);
700 :
701 11194 : vec_foreach(rpath, rpaths)
702 : {
703 : fib_entry_flag_t eflags;
704 :
705 5597 : eflags = fib_entry_get_flags_for_source(fib_entry_index,
706 : source);
707 5597 : fib_table_route_path_fixup(prefix, &eflags, rpath);
708 : }
709 :
710 5597 : src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
711 :
712 5597 : if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
713 : {
714 : /*
715 : * last source gone. remove from the table
716 : */
717 5472 : fib_table_entry_remove(fib_table, prefix, fib_entry_index);
718 :
719 : /*
720 : * now the entry is no longer in the table, we can
721 : * inform the entries that it covers to re-calculate their cover
722 : */
723 5472 : fib_entry_cover_change_notify(fib_entry_index,
724 : FIB_NODE_INDEX_INVALID);
725 : }
726 : /*
727 : * else
728 : * still has sources, leave it be.
729 : */
730 5597 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
731 : {
732 5581 : fib_table_source_count_dec(fib_table, source);
733 : }
734 :
735 5597 : fib_entry_unlock(fib_entry_index);
736 : }
737 : }
738 :
739 : void
740 5587 : fib_table_entry_path_remove (u32 fib_index,
741 : const fib_prefix_t *prefix,
742 : fib_source_t source,
743 : dpo_proto_t next_hop_proto,
744 : const ip46_address_t *next_hop,
745 : u32 next_hop_sw_if_index,
746 : u32 next_hop_fib_index,
747 : u32 next_hop_weight,
748 : fib_route_path_flags_t path_flags)
749 : {
750 : /*
751 : * 1 is it present
752 : * yes => remove source
753 : * 2 - is it still sourced?
754 : * no => cover walk
755 : */
756 5587 : fib_route_path_t path = {
757 : .frp_proto = next_hop_proto,
758 : .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
759 : .frp_sw_if_index = next_hop_sw_if_index,
760 : .frp_fib_index = next_hop_fib_index,
761 : .frp_weight = next_hop_weight,
762 : .frp_flags = path_flags,
763 : };
764 5587 : fib_route_path_t *paths = NULL;
765 :
766 5587 : vec_add1(paths, path);
767 :
768 5587 : fib_table_entry_path_remove2(fib_index, prefix, source, paths);
769 :
770 5587 : vec_free(paths);
771 5587 : }
772 :
773 : fib_node_index_t
774 18673 : fib_table_entry_update (u32 fib_index,
775 : const fib_prefix_t *prefix,
776 : fib_source_t source,
777 : fib_entry_flag_t flags,
778 : fib_route_path_t *paths)
779 : {
780 : fib_node_index_t fib_entry_index;
781 : fib_table_t *fib_table;
782 : u32 ii;
783 :
784 18673 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
785 18673 : fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
786 :
787 51416 : for (ii = 0; ii < vec_len(paths); ii++)
788 : {
789 32743 : fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
790 : }
791 : /*
792 : * sort the paths provided by the control plane. this means
793 : * the paths and the extension on the entry will be sorted.
794 : */
795 18673 : vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
796 :
797 18673 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
798 : {
799 15300 : fib_entry_index = fib_entry_create(fib_index, prefix,
800 : source, flags,
801 : paths);
802 :
803 15300 : fib_table_entry_insert(fib_table, prefix, fib_entry_index);
804 15300 : fib_table_source_count_inc(fib_table, source);
805 : }
806 : else
807 : {
808 : int was_sourced;
809 :
810 3373 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
811 3373 : fib_entry_update(fib_entry_index, source, flags, paths);
812 :
813 3373 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
814 : {
815 188 : fib_table_source_count_inc(fib_table, source);
816 : }
817 : }
818 :
819 18673 : return (fib_entry_index);
820 : }
821 :
822 : fib_node_index_t
823 12014 : fib_table_entry_update_one_path (u32 fib_index,
824 : const fib_prefix_t *prefix,
825 : fib_source_t source,
826 : fib_entry_flag_t flags,
827 : dpo_proto_t next_hop_proto,
828 : const ip46_address_t *next_hop,
829 : u32 next_hop_sw_if_index,
830 : u32 next_hop_fib_index,
831 : u32 next_hop_weight,
832 : fib_mpls_label_t *next_hop_labels,
833 : fib_route_path_flags_t path_flags)
834 : {
835 : fib_node_index_t fib_entry_index;
836 12014 : fib_route_path_t path = {
837 : .frp_proto = next_hop_proto,
838 : .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
839 : .frp_sw_if_index = next_hop_sw_if_index,
840 : .frp_fib_index = next_hop_fib_index,
841 : .frp_weight = next_hop_weight,
842 : .frp_flags = path_flags,
843 : .frp_label_stack = next_hop_labels,
844 : };
845 12014 : fib_route_path_t *paths = NULL;
846 :
847 12014 : vec_add1(paths, path);
848 :
849 : fib_entry_index =
850 12014 : fib_table_entry_update(fib_index, prefix, source, flags, paths);
851 :
852 12014 : vec_free(paths);
853 :
854 12014 : return (fib_entry_index);
855 : }
856 :
857 : static void
858 21293 : fib_table_entry_delete_i (u32 fib_index,
859 : fib_node_index_t fib_entry_index,
860 : const fib_prefix_t *prefix,
861 : fib_source_t source)
862 : {
863 : fib_entry_src_flag_t src_flag;
864 : fib_table_t *fib_table;
865 : int was_sourced;
866 :
867 21293 : fib_table = fib_table_get(fib_index, prefix->fp_proto);
868 21293 : was_sourced = fib_entry_is_sourced(fib_entry_index, source);
869 :
870 : /*
871 : * don't nobody go nowhere
872 : */
873 21293 : fib_entry_lock(fib_entry_index);
874 :
875 21293 : src_flag = fib_entry_delete(fib_entry_index, source);
876 :
877 21293 : if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
878 : {
879 : /*
880 : * last source gone. remove from the table
881 : */
882 17230 : fib_table_entry_remove(fib_table, prefix, fib_entry_index);
883 :
884 : /*
885 : * now the entry is no longer in the table, we can
886 : * inform the entries that it covers to re-calculate their cover
887 : */
888 17230 : fib_entry_cover_change_notify(fib_entry_index,
889 : FIB_NODE_INDEX_INVALID);
890 : }
891 : /*
892 : * else
893 : * still has sources, leave it be.
894 : */
895 21293 : if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
896 : {
897 21251 : fib_table_source_count_dec(fib_table, source);
898 : }
899 :
900 21293 : fib_entry_unlock(fib_entry_index);
901 21293 : }
902 :
903 : void
904 14851 : fib_table_entry_delete (u32 fib_index,
905 : const fib_prefix_t *prefix,
906 : fib_source_t source)
907 : {
908 : fib_node_index_t fib_entry_index;
909 :
910 14851 : fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
911 :
912 14851 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
913 : {
914 : /*
915 : * removing an etry that does not exist.
916 : * i'll allow it, but i won't like it.
917 : */
918 : if (0)
919 : clib_warning("%U not in FIB", format_fib_prefix, prefix);
920 : }
921 : else
922 : {
923 14753 : fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
924 : }
925 14851 : }
926 :
927 : void
928 6540 : fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
929 : fib_source_t source)
930 : {
931 : const fib_prefix_t *prefix;
932 :
933 6540 : prefix = fib_entry_get_prefix(fib_entry_index);
934 :
935 6540 : fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
936 : fib_entry_index, prefix, source);
937 6540 : }
938 :
939 : u32
940 159404 : fib_table_entry_get_stats_index (u32 fib_index,
941 : const fib_prefix_t *prefix)
942 : {
943 159404 : return (fib_entry_get_stats_index(
944 : fib_table_lookup_exact_match(fib_index, prefix)));
945 : }
946 :
947 : fib_node_index_t
948 141 : fib_table_entry_local_label_add (u32 fib_index,
949 : const fib_prefix_t *prefix,
950 : mpls_label_t label)
951 : {
952 : fib_node_index_t fib_entry_index;
953 :
954 141 : fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
955 :
956 282 : if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
957 141 : !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
958 : {
959 : /*
960 : * only source the prefix once. this allows the label change
961 : * operation to work
962 : */
963 140 : fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
964 : FIB_SOURCE_MPLS,
965 : FIB_ENTRY_FLAG_NONE,
966 : NULL);
967 : }
968 :
969 141 : fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
970 :
971 141 : return (fib_entry_index);
972 : }
973 :
974 : void
975 140 : fib_table_entry_local_label_remove (u32 fib_index,
976 : const fib_prefix_t *prefix,
977 : mpls_label_t label)
978 : {
979 : fib_node_index_t fib_entry_index;
980 : const void *data;
981 : mpls_label_t pl;
982 :
983 140 : fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
984 :
985 140 : if (FIB_NODE_INDEX_INVALID == fib_entry_index)
986 0 : return;
987 :
988 140 : data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
989 :
990 140 : if (NULL == data)
991 0 : return;
992 :
993 140 : pl = *(mpls_label_t*)data;
994 :
995 140 : if (pl != label)
996 0 : return;
997 :
998 140 : pl = MPLS_LABEL_INVALID;
999 :
1000 140 : fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
1001 140 : fib_table_entry_special_remove(fib_index,
1002 : prefix,
1003 : FIB_SOURCE_MPLS);
1004 : }
1005 :
1006 : u32
1007 106552 : fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
1008 : u32 sw_if_index)
1009 : {
1010 106552 : switch (proto)
1011 : {
1012 92701 : case FIB_PROTOCOL_IP4:
1013 92701 : return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
1014 13851 : case FIB_PROTOCOL_IP6:
1015 13851 : return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
1016 0 : case FIB_PROTOCOL_MPLS:
1017 0 : return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
1018 : }
1019 0 : return (~0);
1020 : }
1021 :
1022 : flow_hash_config_t
1023 40282 : fib_table_get_flow_hash_config (u32 fib_index,
1024 : fib_protocol_t proto)
1025 : {
1026 : fib_table_t *fib;
1027 :
1028 40282 : fib = fib_table_get(fib_index, proto);
1029 :
1030 40282 : return (fib->ft_flow_hash_config);
1031 : }
1032 :
1033 : flow_hash_config_t
1034 375 : fib_table_get_default_flow_hash_config (fib_protocol_t proto)
1035 : {
1036 375 : switch (proto)
1037 : {
1038 12 : case FIB_PROTOCOL_IP4:
1039 : case FIB_PROTOCOL_IP6:
1040 12 : return (IP_FLOW_HASH_DEFAULT);
1041 :
1042 363 : case FIB_PROTOCOL_MPLS:
1043 363 : return (MPLS_FLOW_HASH_DEFAULT);
1044 : }
1045 :
1046 0 : ASSERT(0);
1047 0 : return (IP_FLOW_HASH_DEFAULT);
1048 : }
1049 :
1050 : /**
1051 : * @brief Table set flow hash config context.
1052 : */
1053 : typedef struct fib_table_set_flow_hash_config_ctx_t_
1054 : {
1055 : /**
1056 : * the flow hash config to set
1057 : */
1058 : flow_hash_config_t hash_config;
1059 : } fib_table_set_flow_hash_config_ctx_t;
1060 :
1061 : static fib_table_walk_rc_t
1062 138 : fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1063 : void *arg)
1064 : {
1065 138 : fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1066 :
1067 138 : fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1068 :
1069 138 : return (FIB_TABLE_WALK_CONTINUE);
1070 : }
1071 :
1072 : void
1073 6 : fib_table_set_flow_hash_config (u32 fib_index,
1074 : fib_protocol_t proto,
1075 : flow_hash_config_t hash_config)
1076 : {
1077 6 : fib_table_set_flow_hash_config_ctx_t ctx = {
1078 : .hash_config = hash_config,
1079 : };
1080 : fib_table_t *fib;
1081 :
1082 6 : fib = fib_table_get(fib_index, proto);
1083 6 : fib->ft_flow_hash_config = hash_config;
1084 :
1085 6 : fib_table_walk(fib_index, proto,
1086 : fib_table_set_flow_hash_config_cb,
1087 : &ctx);
1088 6 : }
1089 :
1090 : u32
1091 10289 : fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1092 : u32 sw_if_index)
1093 : {
1094 : fib_table_t *fib_table;
1095 :
1096 10289 : fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1097 : proto, sw_if_index),
1098 : proto);
1099 :
1100 10289 : return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1101 : }
1102 :
1103 : u32
1104 196167 : fib_table_get_table_id (u32 fib_index,
1105 : fib_protocol_t proto)
1106 : {
1107 : fib_table_t *fib_table;
1108 :
1109 196167 : fib_table = fib_table_get(fib_index, proto);
1110 :
1111 196167 : return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1112 : }
1113 :
1114 : u32
1115 32993 : fib_table_find (fib_protocol_t proto,
1116 : u32 table_id)
1117 : {
1118 32993 : switch (proto)
1119 : {
1120 21214 : case FIB_PROTOCOL_IP4:
1121 21214 : return (ip4_fib_index_from_table_id(table_id));
1122 10767 : case FIB_PROTOCOL_IP6:
1123 10767 : return (ip6_fib_index_from_table_id(table_id));
1124 1012 : case FIB_PROTOCOL_MPLS:
1125 1012 : return (mpls_fib_index_from_table_id(table_id));
1126 : }
1127 0 : return (~0);
1128 : }
1129 :
1130 : static u32
1131 2671 : fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1132 : u32 table_id,
1133 : fib_source_t src,
1134 : const u8 *name)
1135 : {
1136 : fib_table_t *fib_table;
1137 : fib_node_index_t fi;
1138 :
1139 2671 : switch (proto)
1140 : {
1141 1686 : case FIB_PROTOCOL_IP4:
1142 1686 : fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
1143 1686 : break;
1144 787 : case FIB_PROTOCOL_IP6:
1145 787 : fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
1146 787 : break;
1147 198 : case FIB_PROTOCOL_MPLS:
1148 198 : fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
1149 198 : break;
1150 0 : default:
1151 0 : return (~0);
1152 : }
1153 :
1154 2671 : fib_table = fib_table_get(fi, proto);
1155 :
1156 2671 : if (NULL == fib_table->ft_desc)
1157 : {
1158 1611 : if (name && name[0])
1159 : {
1160 0 : fib_table->ft_desc = format(NULL, "%s", name);
1161 : }
1162 : else
1163 : {
1164 1611 : fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1165 : format_fib_protocol, proto,
1166 : table_id);
1167 : }
1168 : }
1169 :
1170 2671 : return (fi);
1171 : }
1172 :
1173 : u32
1174 2161 : fib_table_find_or_create_and_lock (fib_protocol_t proto,
1175 : u32 table_id,
1176 : fib_source_t src)
1177 : {
1178 2161 : return (fib_table_find_or_create_and_lock_i(proto, table_id,
1179 : src, NULL));
1180 : }
1181 :
1182 : u32
1183 510 : fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1184 : u32 table_id,
1185 : fib_source_t src,
1186 : const u8 *name)
1187 : {
1188 510 : return (fib_table_find_or_create_and_lock_i(proto, table_id,
1189 : src, name));
1190 : }
1191 :
1192 : u32
1193 6 : fib_table_create_and_lock (fib_protocol_t proto,
1194 : fib_source_t src,
1195 : const char *const fmt,
1196 : ...)
1197 : {
1198 : fib_table_t *fib_table;
1199 : fib_node_index_t fi;
1200 : va_list ap;
1201 :
1202 :
1203 6 : switch (proto)
1204 : {
1205 0 : case FIB_PROTOCOL_IP4:
1206 0 : fi = ip4_fib_table_create_and_lock(src);
1207 0 : break;
1208 6 : case FIB_PROTOCOL_IP6:
1209 6 : fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
1210 6 : break;
1211 0 : case FIB_PROTOCOL_MPLS:
1212 0 : fi = mpls_fib_table_create_and_lock(src);
1213 0 : break;
1214 0 : default:
1215 0 : return (~0);
1216 : }
1217 :
1218 6 : fib_table = fib_table_get(fi, proto);
1219 :
1220 6 : va_start(ap, fmt);
1221 :
1222 6 : fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1223 :
1224 6 : va_end(ap);
1225 6 : return (fi);
1226 : }
1227 :
1228 : static void
1229 2380 : fib_table_destroy (fib_table_t *fib_table)
1230 : {
1231 2380 : vec_free(fib_table->ft_desc);
1232 :
1233 2380 : switch (fib_table->ft_proto)
1234 : {
1235 265 : case FIB_PROTOCOL_IP4:
1236 265 : ip4_fib_table_destroy(fib_table->ft_index);
1237 265 : break;
1238 2066 : case FIB_PROTOCOL_IP6:
1239 2066 : ip6_fib_table_destroy(fib_table->ft_index);
1240 2066 : break;
1241 49 : case FIB_PROTOCOL_MPLS:
1242 49 : mpls_fib_table_destroy(fib_table->ft_index);
1243 49 : break;
1244 : }
1245 2380 : }
1246 :
1247 : void
1248 4489 : fib_table_walk (u32 fib_index,
1249 : fib_protocol_t proto,
1250 : fib_table_walk_fn_t fn,
1251 : void *ctx)
1252 : {
1253 4489 : switch (proto)
1254 : {
1255 2951 : case FIB_PROTOCOL_IP4:
1256 2951 : ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1257 2951 : break;
1258 1203 : case FIB_PROTOCOL_IP6:
1259 1203 : ip6_fib_table_walk(fib_index, fn, ctx);
1260 1203 : break;
1261 335 : case FIB_PROTOCOL_MPLS:
1262 335 : mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1263 335 : break;
1264 : }
1265 4489 : }
1266 :
1267 : typedef struct fib_table_walk_w_src_ctx_t_
1268 : {
1269 : fib_table_walk_fn_t fn;
1270 : void *data;
1271 : fib_source_t src;
1272 : } fib_table_walk_w_src_cxt_t;
1273 :
1274 : static fib_table_walk_rc_t
1275 40 : fib_table_walk_w_src_cb (fib_node_index_t fei,
1276 : void *arg)
1277 : {
1278 40 : fib_table_walk_w_src_cxt_t *ctx = arg;
1279 :
1280 40 : if (ctx->src == fib_entry_get_best_source(fei))
1281 : {
1282 10 : return (ctx->fn(fei, ctx->data));
1283 : }
1284 30 : return (FIB_TABLE_WALK_CONTINUE);
1285 : }
1286 :
1287 : void
1288 4 : fib_table_walk_w_src (u32 fib_index,
1289 : fib_protocol_t proto,
1290 : fib_source_t src,
1291 : fib_table_walk_fn_t fn,
1292 : void *data)
1293 : {
1294 4 : fib_table_walk_w_src_cxt_t ctx = {
1295 : .fn = fn,
1296 : .src = src,
1297 : .data = data,
1298 : };
1299 :
1300 4 : fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
1301 4 : }
1302 :
1303 : void
1304 62 : fib_table_sub_tree_walk (u32 fib_index,
1305 : fib_protocol_t proto,
1306 : const fib_prefix_t *root,
1307 : fib_table_walk_fn_t fn,
1308 : void *ctx)
1309 : {
1310 62 : switch (proto)
1311 : {
1312 56 : case FIB_PROTOCOL_IP4:
1313 56 : ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1314 56 : break;
1315 6 : case FIB_PROTOCOL_IP6:
1316 6 : ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1317 6 : break;
1318 0 : case FIB_PROTOCOL_MPLS:
1319 0 : break;
1320 : }
1321 62 : }
1322 :
1323 : static void
1324 6704 : fib_table_lock_dec (fib_table_t *fib_table,
1325 : fib_source_t source)
1326 : {
1327 6704 : vec_validate(fib_table->ft_locks, source);
1328 :
1329 6704 : ASSERT(fib_table->ft_locks[source] > 0);
1330 6704 : fib_table->ft_locks[source]--;
1331 6704 : fib_table->ft_total_locks--;
1332 6704 : }
1333 :
1334 : static void
1335 8567 : fib_table_lock_inc (fib_table_t *fib_table,
1336 : fib_source_t source)
1337 : {
1338 8567 : vec_validate(fib_table->ft_locks, source);
1339 :
1340 8567 : ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1341 8567 : fib_table->ft_locks[source]++;
1342 8567 : fib_table->ft_total_locks++;
1343 8567 : }
1344 :
1345 :
1346 : static void
1347 434 : fib_table_lock_clear (fib_table_t *fib_table,
1348 : fib_source_t source)
1349 : {
1350 434 : vec_validate(fib_table->ft_locks, source);
1351 :
1352 434 : ASSERT(fib_table->ft_locks[source] <= 1);
1353 434 : if (fib_table->ft_locks[source])
1354 : {
1355 434 : fib_table->ft_locks[source]--;
1356 434 : fib_table->ft_total_locks--;
1357 : }
1358 434 : }
1359 :
1360 : static void
1361 514 : fib_table_lock_set (fib_table_t *fib_table,
1362 : fib_source_t source)
1363 : {
1364 514 : vec_validate(fib_table->ft_locks, source);
1365 :
1366 514 : ASSERT(fib_table->ft_locks[source] <= 1);
1367 514 : ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1368 514 : if (!fib_table->ft_locks[source])
1369 : {
1370 452 : fib_table->ft_locks[source]++;
1371 452 : fib_table->ft_total_locks++;
1372 : }
1373 514 : }
1374 :
1375 : void
1376 7138 : fib_table_unlock (u32 fib_index,
1377 : fib_protocol_t proto,
1378 : fib_source_t source)
1379 : {
1380 : fib_table_t *fib_table;
1381 :
1382 7138 : fib_table = fib_table_get(fib_index, proto);
1383 :
1384 7138 : if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1385 434 : fib_table_lock_clear(fib_table, source);
1386 : else
1387 6704 : fib_table_lock_dec(fib_table, source);
1388 :
1389 7138 : if (0 == fib_table->ft_total_locks)
1390 : {
1391 : /*
1392 : * no more lock from any source - kill it
1393 : */
1394 2380 : fib_table_destroy(fib_table);
1395 : }
1396 7138 : }
1397 :
1398 : void
1399 9081 : fib_table_lock (u32 fib_index,
1400 : fib_protocol_t proto,
1401 : fib_source_t source)
1402 : {
1403 : fib_table_t *fib_table;
1404 :
1405 9081 : fib_table = fib_table_get(fib_index, proto);
1406 :
1407 9081 : if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1408 514 : fib_table_lock_set(fib_table, source);
1409 : else
1410 8567 : fib_table_lock_inc(fib_table, source);
1411 9081 : }
1412 :
1413 : u32
1414 1953 : fib_table_get_num_entries (u32 fib_index,
1415 : fib_protocol_t proto,
1416 : fib_source_t source)
1417 : {
1418 : fib_table_t *fib_table;
1419 :
1420 1953 : fib_table = fib_table_get(fib_index, proto);
1421 :
1422 1953 : return (fib_table->ft_src_route_counts[source]);
1423 : }
1424 :
1425 : u8*
1426 640 : format_fib_table_name (u8* s, va_list* ap)
1427 : {
1428 640 : fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1429 640 : fib_protocol_t proto = va_arg(*ap, int); // int promotion
1430 : fib_table_t *fib_table;
1431 :
1432 640 : fib_table = fib_table_get(fib_index, proto);
1433 :
1434 640 : s = format(s, "%v", fib_table->ft_desc);
1435 :
1436 640 : return (s);
1437 : }
1438 :
1439 : u8*
1440 572 : format_fib_table_flags (u8 *s, va_list *args)
1441 : {
1442 572 : fib_table_flags_t flags = va_arg(*args, int);
1443 : fib_table_attribute_t attr;
1444 :
1445 572 : if (!flags)
1446 : {
1447 572 : return format(s, "none");
1448 : }
1449 :
1450 0 : FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1451 0 : if (1 << attr & flags) {
1452 0 : s = format(s, "%s", fib_table_flags_strings[attr]);
1453 : }
1454 : }
1455 :
1456 0 : return (s);
1457 : }
1458 :
1459 : /**
1460 : * @brief Table flush context. Store the indicies of matching FIB entries
1461 : * that need to be removed.
1462 : */
1463 : typedef struct fib_table_flush_ctx_t_
1464 : {
1465 : /**
1466 : * The list of entries to flush
1467 : */
1468 : fib_node_index_t *ftf_entries;
1469 :
1470 : /**
1471 : * The source we are flushing
1472 : */
1473 : fib_source_t ftf_source;
1474 : } fib_table_flush_ctx_t;
1475 :
1476 : static fib_table_walk_rc_t
1477 269 : fib_table_flush_cb (fib_node_index_t fib_entry_index,
1478 : void *arg)
1479 : {
1480 269 : fib_table_flush_ctx_t *ctx = arg;
1481 :
1482 269 : if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1483 : {
1484 156 : vec_add1(ctx->ftf_entries, fib_entry_index);
1485 : }
1486 269 : return (FIB_TABLE_WALK_CONTINUE);
1487 : }
1488 :
1489 : void
1490 34 : fib_table_flush (u32 fib_index,
1491 : fib_protocol_t proto,
1492 : fib_source_t source)
1493 : {
1494 : fib_node_index_t *fib_entry_index;
1495 34 : fib_table_flush_ctx_t ctx = {
1496 : .ftf_entries = NULL,
1497 : .ftf_source = source,
1498 : };
1499 :
1500 34 : fib_table_walk(fib_index, proto,
1501 : fib_table_flush_cb,
1502 : &ctx);
1503 :
1504 190 : vec_foreach(fib_entry_index, ctx.ftf_entries)
1505 : {
1506 156 : fib_table_entry_delete_index(*fib_entry_index, source);
1507 : }
1508 :
1509 34 : vec_free(ctx.ftf_entries);
1510 34 : }
1511 :
1512 : static fib_table_walk_rc_t
1513 552 : fib_table_mark_cb (fib_node_index_t fib_entry_index,
1514 : void *arg)
1515 : {
1516 552 : fib_table_flush_ctx_t *ctx = arg;
1517 :
1518 552 : if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1519 : {
1520 468 : fib_entry_mark(fib_entry_index, ctx->ftf_source);
1521 : }
1522 552 : return (FIB_TABLE_WALK_CONTINUE);
1523 : }
1524 :
1525 : void
1526 24 : fib_table_mark (u32 fib_index,
1527 : fib_protocol_t proto,
1528 : fib_source_t source)
1529 : {
1530 24 : fib_table_flush_ctx_t ctx = {
1531 : .ftf_source = source,
1532 : };
1533 : fib_table_t *fib_table;
1534 :
1535 24 : fib_table = fib_table_get(fib_index, proto);
1536 :
1537 24 : fib_table->ft_epoch++;
1538 24 : fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1539 :
1540 24 : fib_table_walk(fib_index, proto,
1541 : fib_table_mark_cb,
1542 : &ctx);
1543 24 : }
1544 :
1545 : static fib_table_walk_rc_t
1546 552 : fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1547 : void *arg)
1548 : {
1549 552 : fib_table_flush_ctx_t *ctx = arg;
1550 :
1551 552 : if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1552 : {
1553 228 : vec_add1(ctx->ftf_entries, fib_entry_index);
1554 : }
1555 552 : return (FIB_TABLE_WALK_CONTINUE);
1556 : }
1557 :
1558 : void
1559 24 : fib_table_sweep (u32 fib_index,
1560 : fib_protocol_t proto,
1561 : fib_source_t source)
1562 : {
1563 24 : fib_table_flush_ctx_t ctx = {
1564 : .ftf_source = source,
1565 : };
1566 : fib_node_index_t *fib_entry_index;
1567 : fib_table_t *fib_table;
1568 :
1569 24 : fib_table = fib_table_get(fib_index, proto);
1570 :
1571 24 : fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1572 :
1573 24 : fib_table_walk(fib_index, proto,
1574 : fib_table_sweep_cb,
1575 : &ctx);
1576 :
1577 252 : vec_foreach(fib_entry_index, ctx.ftf_entries)
1578 : {
1579 228 : fib_table_entry_delete_index(*fib_entry_index, source);
1580 : }
1581 :
1582 24 : vec_free(ctx.ftf_entries);
1583 24 : }
1584 :
1585 : u8 *
1586 1 : format_fib_table_memory (u8 *s, va_list *args)
1587 : {
1588 1 : s = format(s, "%U", format_ip4_fib_table_memory);
1589 1 : s = format(s, "%U", format_ip6_fib_table_memory);
1590 1 : s = format(s, "%U", format_mpls_fib_table_memory);
1591 :
1592 1 : return (s);
1593 : }
|