blob: b2a32d0da561ffd88dfe44a84a523f3242b171a2 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vlib/vlib.h>
17#include <vnet/dpo/drop_dpo.h>
18
19#include <vnet/fib/fib_table.h>
20#include <vnet/fib/fib_entry_cover.h>
21#include <vnet/fib/fib_internal.h>
22#include <vnet/fib/ip4_fib.h>
23#include <vnet/fib/ip6_fib.h>
24#include <vnet/fib/mpls_fib.h>
25
Neale Ranns9db6ada2019-11-08 12:42:31 +000026const static char * fib_table_flags_strings[] = FIB_TABLE_ATTRIBUTES;
27
Jon Loeligerd465fd02024-03-22 12:22:36 -050028/*
29 * Default names for IP4, IP6, and MPLS FIB table index 0.
30 * Nominally like "ipv6-VRF:0", but this will override that name if set
31 * in a config section of the startup.conf file.
32 */
33char *fib_table_default_names[FIB_PROTOCOL_MAX];
34
Neale Ranns0bfe5d82016-08-25 15:29:12 +010035fib_table_t *
36fib_table_get (fib_node_index_t index,
37 fib_protocol_t proto)
38{
39 switch (proto)
40 {
41 case FIB_PROTOCOL_IP4:
42 return (pool_elt_at_index(ip4_main.fibs, index));
43 case FIB_PROTOCOL_IP6:
44 return (pool_elt_at_index(ip6_main.fibs, index));
45 case FIB_PROTOCOL_MPLS:
46 return (pool_elt_at_index(mpls_main.fibs, index));
47 }
48 ASSERT(0);
49 return (NULL);
50}
51
52static inline fib_node_index_t
53fib_table_lookup_i (fib_table_t *fib_table,
54 const fib_prefix_t *prefix)
55{
56 switch (prefix->fp_proto)
57 {
58 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -070059 return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010060 &prefix->fp_addr.ip4,
61 prefix->fp_len));
62 case FIB_PROTOCOL_IP6:
63 return (ip6_fib_table_lookup(fib_table->ft_index,
64 &prefix->fp_addr.ip6,
65 prefix->fp_len));
66 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -070067 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010068 prefix->fp_label,
69 prefix->fp_eos));
70 }
71 return (FIB_NODE_INDEX_INVALID);
72}
73
74fib_node_index_t
75fib_table_lookup (u32 fib_index,
76 const fib_prefix_t *prefix)
77{
78 return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
79}
80
81static inline fib_node_index_t
82fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
83 const fib_prefix_t *prefix)
84{
85 switch (prefix->fp_proto)
86 {
87 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -070088 return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010089 &prefix->fp_addr.ip4,
90 prefix->fp_len));
91 case FIB_PROTOCOL_IP6:
92 return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
93 &prefix->fp_addr.ip6,
94 prefix->fp_len));
95 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -070096 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010097 prefix->fp_label,
98 prefix->fp_eos));
99 }
100 return (FIB_NODE_INDEX_INVALID);
101}
102
103fib_node_index_t
104fib_table_lookup_exact_match (u32 fib_index,
105 const fib_prefix_t *prefix)
106{
107 return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
108 prefix->fp_proto),
109 prefix));
110}
111
112static fib_node_index_t
113fib_table_get_less_specific_i (fib_table_t *fib_table,
114 const fib_prefix_t *prefix)
115{
116 fib_prefix_t pfx;
117
118 pfx = *prefix;
119
120 if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
121 {
122 return (FIB_NODE_INDEX_INVALID);
123 }
124
125 /*
126 * in the absence of a tree structure for the table that allows for an O(1)
127 * parent get, a cheeky way to find the cover is to LPM for the prefix with
128 * mask-1.
129 * there should always be a cover, though it may be the default route. the
130 * default route's cover is the default route.
131 */
132 if (pfx.fp_len != 0) {
133 pfx.fp_len -= 1;
134 }
135
136 return (fib_table_lookup_i(fib_table, &pfx));
137}
138
139fib_node_index_t
140fib_table_get_less_specific (u32 fib_index,
141 const fib_prefix_t *prefix)
142{
143 return (fib_table_get_less_specific_i(fib_table_get(fib_index,
144 prefix->fp_proto),
145 prefix));
146}
147
148static void
149fib_table_entry_remove (fib_table_t *fib_table,
150 const fib_prefix_t *prefix,
151 fib_node_index_t fib_entry_index)
152{
153 vlib_smp_unsafe_warning();
154
155 fib_table->ft_total_route_counts--;
156
157 switch (prefix->fp_proto)
158 {
159 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -0700160 ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100161 &prefix->fp_addr.ip4,
162 prefix->fp_len);
163 break;
164 case FIB_PROTOCOL_IP6:
165 ip6_fib_table_entry_remove(fib_table->ft_index,
166 &prefix->fp_addr.ip6,
167 prefix->fp_len);
168 break;
169 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -0700170 mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100171 prefix->fp_label,
172 prefix->fp_eos);
173 break;
174 }
175
176 fib_entry_unlock(fib_entry_index);
177}
178
179static void
180fib_table_post_insert_actions (fib_table_t *fib_table,
181 const fib_prefix_t *prefix,
182 fib_node_index_t fib_entry_index)
183{
184 fib_node_index_t fib_entry_cover_index;
185
186 /*
187 * no cover relationships in the MPLS FIB
188 */
189 if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
190 return;
191
192 /*
Neale Ranns89541992017-04-06 04:41:02 -0700193 * find the covering entry
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100194 */
195 fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
196 /*
197 * the indicies are the same when the default route is first added
198 */
199 if (fib_entry_cover_index != fib_entry_index)
200 {
Neale Ranns89541992017-04-06 04:41:02 -0700201 /*
202 * push any inherting sources from the cover onto the covered
203 */
204 fib_entry_inherit(fib_entry_cover_index,
205 fib_entry_index);
206
207 /*
208 * inform the covering entry that a new more specific
Neale Ranns56f949b2018-04-25 01:41:24 -0700209 * has been inserted beneath it.
210 * If the prefix that has been inserted is a host route
211 * then it is not possible that it will be the cover for any
212 * other entry, so we can elide the walk. This is particularly
213 * beneficial since there are often many host entries sharing the
214 * same cover (i.e. ADJ or RR sourced entries).
Neale Ranns89541992017-04-06 04:41:02 -0700215 */
Neale Ranns56f949b2018-04-25 01:41:24 -0700216 if (!fib_entry_is_host(fib_entry_index))
217 {
218 fib_entry_cover_change_notify(fib_entry_cover_index,
219 fib_entry_index);
220 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100221 }
222}
223
224static void
225fib_table_entry_insert (fib_table_t *fib_table,
226 const fib_prefix_t *prefix,
227 fib_node_index_t fib_entry_index)
228{
229 vlib_smp_unsafe_warning();
230
231 fib_entry_lock(fib_entry_index);
232 fib_table->ft_total_route_counts++;
233
234 switch (prefix->fp_proto)
235 {
236 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -0700237 ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100238 &prefix->fp_addr.ip4,
239 prefix->fp_len,
240 fib_entry_index);
241 break;
242 case FIB_PROTOCOL_IP6:
243 ip6_fib_table_entry_insert(fib_table->ft_index,
244 &prefix->fp_addr.ip6,
245 prefix->fp_len,
246 fib_entry_index);
247 break;
248 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -0700249 mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100250 prefix->fp_label,
251 prefix->fp_eos,
252 fib_entry_index);
253 break;
254 }
255
256 fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
257}
258
259void
260fib_table_fwding_dpo_update (u32 fib_index,
261 const fib_prefix_t *prefix,
262 const dpo_id_t *dpo)
263{
264 vlib_smp_unsafe_warning();
265
266 switch (prefix->fp_proto)
267 {
268 case FIB_PROTOCOL_IP4:
269 return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
270 &prefix->fp_addr.ip4,
271 prefix->fp_len,
272 dpo));
273 case FIB_PROTOCOL_IP6:
274 return (ip6_fib_table_fwding_dpo_update(fib_index,
275 &prefix->fp_addr.ip6,
276 prefix->fp_len,
277 dpo));
278 case FIB_PROTOCOL_MPLS:
279 return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
280 prefix->fp_label,
281 prefix->fp_eos,
282 dpo));
283 }
284}
285
286void
287fib_table_fwding_dpo_remove (u32 fib_index,
288 const fib_prefix_t *prefix,
289 const dpo_id_t *dpo)
290{
291 vlib_smp_unsafe_warning();
292
293 switch (prefix->fp_proto)
294 {
295 case FIB_PROTOCOL_IP4:
296 return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
297 &prefix->fp_addr.ip4,
298 prefix->fp_len,
Neale Rannsa3af3372017-03-28 03:49:52 -0700299 dpo,
300 fib_table_get_less_specific(fib_index,
301 prefix)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100302 case FIB_PROTOCOL_IP6:
303 return (ip6_fib_table_fwding_dpo_remove(fib_index,
304 &prefix->fp_addr.ip6,
305 prefix->fp_len,
306 dpo));
307 case FIB_PROTOCOL_MPLS:
308 return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
309 prefix->fp_label,
310 prefix->fp_eos));
311 }
312}
313
Neale Ranns3bab8f92019-12-04 06:11:00 +0000314static void
315fib_table_source_count_inc (fib_table_t *fib_table,
316 fib_source_t source)
317{
318 vec_validate (fib_table->ft_src_route_counts, source);
319 fib_table->ft_src_route_counts[source]++;
320}
321
322static void
323fib_table_source_count_dec (fib_table_t *fib_table,
324 fib_source_t source)
325{
326 vec_validate (fib_table->ft_src_route_counts, source);
327 fib_table->ft_src_route_counts[source]--;
328}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100329
330fib_node_index_t
331fib_table_entry_special_dpo_add (u32 fib_index,
332 const fib_prefix_t *prefix,
333 fib_source_t source,
334 fib_entry_flag_t flags,
335 const dpo_id_t *dpo)
336{
337 fib_node_index_t fib_entry_index;
338 fib_table_t *fib_table;
339
340 fib_table = fib_table_get(fib_index, prefix->fp_proto);
341 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
342
343 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
344 {
345 fib_entry_index = fib_entry_create_special(fib_index, prefix,
346 source, flags,
347 dpo);
348
349 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000350 fib_table_source_count_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100351 }
352 else
353 {
354 int was_sourced;
355
356 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
357 fib_entry_special_add(fib_entry_index, source, flags, dpo);
358
359 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
360 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000361 fib_table_source_count_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100362 }
363 }
364
365
366 return (fib_entry_index);
367}
368
369fib_node_index_t
Neale Ranns948e00f2016-10-20 13:39:34 +0100370fib_table_entry_special_dpo_update (u32 fib_index,
371 const fib_prefix_t *prefix,
372 fib_source_t source,
373 fib_entry_flag_t flags,
374 const dpo_id_t *dpo)
375{
376 fib_node_index_t fib_entry_index;
377 fib_table_t *fib_table;
378
379 fib_table = fib_table_get(fib_index, prefix->fp_proto);
380 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
381
382 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
383 {
384 fib_entry_index = fib_entry_create_special(fib_index, prefix,
385 source, flags,
386 dpo);
387
388 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000389 fib_table_source_count_inc(fib_table, source);
Neale Ranns948e00f2016-10-20 13:39:34 +0100390 }
391 else
392 {
393 int was_sourced;
394
395 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
396
397 if (was_sourced)
398 fib_entry_special_update(fib_entry_index, source, flags, dpo);
399 else
400 fib_entry_special_add(fib_entry_index, source, flags, dpo);
401
402 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
403 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000404 fib_table_source_count_inc(fib_table, source);
Neale Ranns948e00f2016-10-20 13:39:34 +0100405 }
406 }
407
408 return (fib_entry_index);
409}
410
411fib_node_index_t
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100412fib_table_entry_special_add (u32 fib_index,
413 const fib_prefix_t *prefix,
414 fib_source_t source,
Neale Rannsa0558302017-04-13 00:44:52 -0700415 fib_entry_flag_t flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100416{
417 fib_node_index_t fib_entry_index;
Neale Ranns948e00f2016-10-20 13:39:34 +0100418 dpo_id_t tmp_dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100419
Neale Rannsa0558302017-04-13 00:44:52 -0700420 dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100421
422 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
423 flags, &tmp_dpo);
424
425 dpo_unlock(&tmp_dpo);
426
427 return (fib_entry_index);
428}
429
430void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100431fib_table_entry_special_remove (u32 fib_index,
432 const fib_prefix_t *prefix,
433 fib_source_t source)
434{
435 /*
436 * 1 is it present
437 * yes => remove source
438 * 2 - is it still sourced?
439 * no => cover walk
440 */
441 fib_node_index_t fib_entry_index;
442 fib_table_t *fib_table;
443
444 fib_table = fib_table_get(fib_index, prefix->fp_proto);
445 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
446
447 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
448 {
449 /*
450 * removing an etry that does not exist. i'll allow it.
451 */
452 }
453 else
454 {
455 fib_entry_src_flag_t src_flag;
456 int was_sourced;
457
458 /*
459 * don't nobody go nowhere
460 */
461 fib_entry_lock(fib_entry_index);
462 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
463
464 src_flag = fib_entry_special_remove(fib_entry_index, source);
465
466 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
467 {
468 /*
469 * last source gone. remove from the table
470 */
471 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
472
473 /*
474 * now the entry is no longer in the table, we can
475 * inform the entries that it covers to re-calculate their cover
476 */
477 fib_entry_cover_change_notify(fib_entry_index,
478 FIB_NODE_INDEX_INVALID);
479 }
480 /*
481 * else
482 * still has sources, leave it be.
483 */
484 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
485 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000486 fib_table_source_count_dec(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100487 }
488
489 fib_entry_unlock(fib_entry_index);
490 }
491}
492
493/**
494 * fib_table_route_path_fixup
495 *
496 * Convert attached hosts to attached next-hops.
497 *
498 * This special case is required because an attached path will link to a
499 * glean, and the FIB entry will have the interface or API/CLI source. When
500 * the ARP/ND process is completes then that source (which will provide a
501 * complete adjacency) will be lower priority and so the FIB entry will
502 * remain linked to a glean and traffic will never reach the hosts. For
503 * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
504 * adjacency.
505 */
506static void
507fib_table_route_path_fixup (const fib_prefix_t *prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700508 fib_entry_flag_t *eflags,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100509 fib_route_path_t *path)
510{
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800511 /*
512 * not all zeros next hop &&
513 * is recursive path &&
514 * nexthop is same as the route's address
515 */
516 if ((!ip46_address_is_zero(&path->frp_addr)) &&
517 (~0 == path->frp_sw_if_index) &&
518 (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
519 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000520 /* Prefix recurses via itself */
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800521 path->frp_flags |= FIB_ROUTE_PATH_DROP;
522 }
Neale Ranns097fa662018-05-01 05:17:55 -0700523 if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
524 fib_prefix_is_host(prefix) &&
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100525 ip46_address_is_zero(&path->frp_addr) &&
Neale Ranns6f631152017-10-03 08:20:21 -0700526 path->frp_sw_if_index != ~0 &&
527 path->frp_proto != DPO_PROTO_ETHERNET)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100528 {
529 path->frp_addr = prefix->fp_addr;
Neale Ranns4b919a52017-03-11 05:55:21 -0800530 path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100531 }
Neale Rannse2fe0972020-11-26 08:37:27 +0000532 else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
533 !(*eflags & FIB_ENTRY_FLAG_LOCAL))
534 {
535 if (ip46_address_is_zero(&path->frp_addr))
536 {
537 path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
538 fib_prefix_normalize(prefix, &path->frp_connected);
539 }
540 }
Neale Ranns66edaf22021-07-09 13:03:52 +0000541 else if (fib_route_path_is_attached(path))
542 {
543 path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
Neale Ranns39528792023-03-08 04:53:37 +0000544 /*
545 * attached prefixes are not suitable as the source of ARP requests
546 * so don't save the prefix in the glean adj
547 */
548 clib_memset(&path->frp_connected, 0, sizeof(path->frp_connected));
Neale Ranns66edaf22021-07-09 13:03:52 +0000549 }
Neale Ranns097fa662018-05-01 05:17:55 -0700550 if (*eflags & FIB_ENTRY_FLAG_DROP)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800551 {
552 path->frp_flags |= FIB_ROUTE_PATH_DROP;
553 }
Neale Ranns097fa662018-05-01 05:17:55 -0700554 if (*eflags & FIB_ENTRY_FLAG_LOCAL)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800555 {
556 path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
557 }
Neale Ranns097fa662018-05-01 05:17:55 -0700558 if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800559 {
560 path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
561 }
Neale Ranns097fa662018-05-01 05:17:55 -0700562 if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
563 {
564 *eflags |= FIB_ENTRY_FLAG_LOCAL;
565
566 if (path->frp_sw_if_index != ~0)
567 {
568 *eflags |= FIB_ENTRY_FLAG_CONNECTED;
569 }
570 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800571}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100572
573fib_node_index_t
574fib_table_entry_path_add (u32 fib_index,
575 const fib_prefix_t *prefix,
576 fib_source_t source,
577 fib_entry_flag_t flags,
Neale Rannsda78f952017-05-24 09:15:43 -0700578 dpo_proto_t next_hop_proto,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100579 const ip46_address_t *next_hop,
580 u32 next_hop_sw_if_index,
581 u32 next_hop_fib_index,
582 u32 next_hop_weight,
Neale Ranns31ed7442018-02-23 05:29:09 -0800583 fib_mpls_label_t *next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100584 fib_route_path_flags_t path_flags)
585{
586 fib_route_path_t path = {
587 .frp_proto = next_hop_proto,
588 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
589 .frp_sw_if_index = next_hop_sw_if_index,
590 .frp_fib_index = next_hop_fib_index,
591 .frp_weight = next_hop_weight,
592 .frp_flags = path_flags,
Neale Ranns097fa662018-05-01 05:17:55 -0700593 .frp_rpf_id = INDEX_INVALID,
Neale Rannsad422ed2016-11-02 14:20:04 +0000594 .frp_label_stack = next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100595 };
596 fib_node_index_t fib_entry_index;
597 fib_route_path_t *paths = NULL;
598
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100599 vec_add1(paths, path);
600
601 fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
602 source, flags, paths);
603
604 vec_free(paths);
605 return (fib_entry_index);
606}
607
Neale Rannsda5dedf2020-01-20 02:28:00 +0000608static int
609fib_route_path_cmp_for_sort (void * v1,
610 void * v2)
611{
612 return (fib_route_path_cmp(v1, v2));
613}
614
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100615fib_node_index_t
616fib_table_entry_path_add2 (u32 fib_index,
617 const fib_prefix_t *prefix,
618 fib_source_t source,
619 fib_entry_flag_t flags,
Neale Ranns097fa662018-05-01 05:17:55 -0700620 fib_route_path_t *rpaths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100621{
622 fib_node_index_t fib_entry_index;
623 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000624 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100625
626 fib_table = fib_table_get(fib_index, prefix->fp_proto);
627 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
628
Neale Ranns097fa662018-05-01 05:17:55 -0700629 for (ii = 0; ii < vec_len(rpaths); ii++)
Neale Rannsad422ed2016-11-02 14:20:04 +0000630 {
Neale Ranns097fa662018-05-01 05:17:55 -0700631 fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
Neale Rannsad422ed2016-11-02 14:20:04 +0000632 }
Neale Rannsda5dedf2020-01-20 02:28:00 +0000633 /*
634 * sort the paths provided by the control plane. this means
635 * the paths and the extension on the entry will be sorted.
636 */
637 vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
Neale Rannsad422ed2016-11-02 14:20:04 +0000638
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100639 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
640 {
641 fib_entry_index = fib_entry_create(fib_index, prefix,
642 source, flags,
Neale Ranns097fa662018-05-01 05:17:55 -0700643 rpaths);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100644
645 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000646 fib_table_source_count_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100647 }
648 else
649 {
650 int was_sourced;
651
652 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
Neale Ranns097fa662018-05-01 05:17:55 -0700653 fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100654
655 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
656 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000657 fib_table_source_count_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100658 }
659 }
660
661 return (fib_entry_index);
662}
663
664void
665fib_table_entry_path_remove2 (u32 fib_index,
Neale Rannsad422ed2016-11-02 14:20:04 +0000666 const fib_prefix_t *prefix,
667 fib_source_t source,
Neale Ranns097fa662018-05-01 05:17:55 -0700668 fib_route_path_t *rpaths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100669{
670 /*
671 * 1 is it present
672 * yes => remove source
673 * 2 - is it still sourced?
674 * no => cover walk
675 */
676 fib_node_index_t fib_entry_index;
Neale Ranns097fa662018-05-01 05:17:55 -0700677 fib_route_path_t *rpath;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100678 fib_table_t *fib_table;
679
680 fib_table = fib_table_get(fib_index, prefix->fp_proto);
681 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
682
683 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
684 {
685 /*
686 * removing an etry that does not exist. i'll allow it.
687 */
688 }
689 else
690 {
691 fib_entry_src_flag_t src_flag;
692 int was_sourced;
693
Neale Rannsf12a83f2017-04-18 09:09:40 -0700694 /*
695 * if it's not sourced, then there's nowt to remove
696 */
697 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
698 if (!was_sourced)
699 {
700 return;
701 }
702
703 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100704 * don't nobody go nowhere
705 */
706 fib_entry_lock(fib_entry_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100707
Neale Ranns097fa662018-05-01 05:17:55 -0700708 vec_foreach(rpath, rpaths)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800709 {
Neale Ranns097fa662018-05-01 05:17:55 -0700710 fib_entry_flag_t eflags;
711
712 eflags = fib_entry_get_flags_for_source(fib_entry_index,
713 source);
714 fib_table_route_path_fixup(prefix, &eflags, rpath);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800715 }
716
Neale Ranns097fa662018-05-01 05:17:55 -0700717 src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100718
719 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
720 {
721 /*
722 * last source gone. remove from the table
723 */
724 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
725
726 /*
727 * now the entry is no longer in the table, we can
728 * inform the entries that it covers to re-calculate their cover
729 */
730 fib_entry_cover_change_notify(fib_entry_index,
731 FIB_NODE_INDEX_INVALID);
732 }
733 /*
734 * else
735 * still has sources, leave it be.
736 */
737 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
738 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000739 fib_table_source_count_dec(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100740 }
741
742 fib_entry_unlock(fib_entry_index);
743 }
744}
745
746void
747fib_table_entry_path_remove (u32 fib_index,
748 const fib_prefix_t *prefix,
749 fib_source_t source,
Neale Rannsda78f952017-05-24 09:15:43 -0700750 dpo_proto_t next_hop_proto,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100751 const ip46_address_t *next_hop,
752 u32 next_hop_sw_if_index,
753 u32 next_hop_fib_index,
754 u32 next_hop_weight,
755 fib_route_path_flags_t path_flags)
756{
757 /*
758 * 1 is it present
759 * yes => remove source
760 * 2 - is it still sourced?
761 * no => cover walk
762 */
763 fib_route_path_t path = {
764 .frp_proto = next_hop_proto,
765 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
766 .frp_sw_if_index = next_hop_sw_if_index,
767 .frp_fib_index = next_hop_fib_index,
768 .frp_weight = next_hop_weight,
769 .frp_flags = path_flags,
770 };
771 fib_route_path_t *paths = NULL;
772
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100773 vec_add1(paths, path);
774
775 fib_table_entry_path_remove2(fib_index, prefix, source, paths);
776
777 vec_free(paths);
778}
779
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100780fib_node_index_t
781fib_table_entry_update (u32 fib_index,
782 const fib_prefix_t *prefix,
783 fib_source_t source,
784 fib_entry_flag_t flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000785 fib_route_path_t *paths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100786{
787 fib_node_index_t fib_entry_index;
788 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000789 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100790
791 fib_table = fib_table_get(fib_index, prefix->fp_proto);
792 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
793
Neale Rannsad422ed2016-11-02 14:20:04 +0000794 for (ii = 0; ii < vec_len(paths); ii++)
795 {
Neale Ranns097fa662018-05-01 05:17:55 -0700796 fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
Neale Rannsad422ed2016-11-02 14:20:04 +0000797 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100798 /*
799 * sort the paths provided by the control plane. this means
800 * the paths and the extension on the entry will be sorted.
801 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000802 vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100803
804 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
805 {
806 fib_entry_index = fib_entry_create(fib_index, prefix,
807 source, flags,
808 paths);
809
810 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000811 fib_table_source_count_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100812 }
813 else
814 {
815 int was_sourced;
816
817 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
818 fib_entry_update(fib_entry_index, source, flags, paths);
819
820 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
821 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000822 fib_table_source_count_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100823 }
824 }
825
826 return (fib_entry_index);
827}
828
829fib_node_index_t
830fib_table_entry_update_one_path (u32 fib_index,
831 const fib_prefix_t *prefix,
832 fib_source_t source,
833 fib_entry_flag_t flags,
Neale Rannsda78f952017-05-24 09:15:43 -0700834 dpo_proto_t next_hop_proto,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100835 const ip46_address_t *next_hop,
836 u32 next_hop_sw_if_index,
837 u32 next_hop_fib_index,
838 u32 next_hop_weight,
Neale Ranns31ed7442018-02-23 05:29:09 -0800839 fib_mpls_label_t *next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100840 fib_route_path_flags_t path_flags)
841{
842 fib_node_index_t fib_entry_index;
843 fib_route_path_t path = {
844 .frp_proto = next_hop_proto,
845 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
846 .frp_sw_if_index = next_hop_sw_if_index,
847 .frp_fib_index = next_hop_fib_index,
848 .frp_weight = next_hop_weight,
849 .frp_flags = path_flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000850 .frp_label_stack = next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100851 };
852 fib_route_path_t *paths = NULL;
853
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100854 vec_add1(paths, path);
855
856 fib_entry_index =
857 fib_table_entry_update(fib_index, prefix, source, flags, paths);
858
859 vec_free(paths);
860
861 return (fib_entry_index);
862}
863
864static void
865fib_table_entry_delete_i (u32 fib_index,
866 fib_node_index_t fib_entry_index,
867 const fib_prefix_t *prefix,
868 fib_source_t source)
869{
870 fib_entry_src_flag_t src_flag;
871 fib_table_t *fib_table;
872 int was_sourced;
873
874 fib_table = fib_table_get(fib_index, prefix->fp_proto);
875 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
876
877 /*
878 * don't nobody go nowhere
879 */
880 fib_entry_lock(fib_entry_index);
881
882 src_flag = fib_entry_delete(fib_entry_index, source);
883
884 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
885 {
886 /*
887 * last source gone. remove from the table
888 */
889 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
890
891 /*
892 * now the entry is no longer in the table, we can
893 * inform the entries that it covers to re-calculate their cover
894 */
895 fib_entry_cover_change_notify(fib_entry_index,
896 FIB_NODE_INDEX_INVALID);
897 }
898 /*
899 * else
900 * still has sources, leave it be.
901 */
902 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
903 {
Neale Ranns3bab8f92019-12-04 06:11:00 +0000904 fib_table_source_count_dec(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100905 }
906
907 fib_entry_unlock(fib_entry_index);
908}
909
910void
911fib_table_entry_delete (u32 fib_index,
912 const fib_prefix_t *prefix,
913 fib_source_t source)
914{
915 fib_node_index_t fib_entry_index;
916
917 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
918
919 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
920 {
921 /*
922 * removing an etry that does not exist.
923 * i'll allow it, but i won't like it.
924 */
Dave Barach59b25652017-09-10 15:04:27 -0400925 if (0)
926 clib_warning("%U not in FIB", format_fib_prefix, prefix);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100927 }
928 else
929 {
930 fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
931 }
932}
933
934void
935fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
936 fib_source_t source)
937{
Neale Rannsc5d43172018-07-30 08:04:40 -0700938 const fib_prefix_t *prefix;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100939
Neale Rannsc5d43172018-07-30 08:04:40 -0700940 prefix = fib_entry_get_prefix(fib_entry_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100941
942 fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
Neale Rannsc5d43172018-07-30 08:04:40 -0700943 fib_entry_index, prefix, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100944}
945
Neale Ranns008dbe12018-09-07 09:32:36 -0700946u32
Neale Ranns28c142e2018-09-07 09:37:07 -0700947fib_table_entry_get_stats_index (u32 fib_index,
948 const fib_prefix_t *prefix)
Neale Ranns008dbe12018-09-07 09:32:36 -0700949{
950 return (fib_entry_get_stats_index(
951 fib_table_lookup_exact_match(fib_index, prefix)));
952}
953
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100954fib_node_index_t
955fib_table_entry_local_label_add (u32 fib_index,
956 const fib_prefix_t *prefix,
957 mpls_label_t label)
958{
959 fib_node_index_t fib_entry_index;
960
Neale Ranns1357f3b2016-10-16 12:01:42 -0700961 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
962
963 if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
964 !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
965 {
966 /*
967 * only source the prefix once. this allows the label change
968 * operation to work
969 */
970 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
971 FIB_SOURCE_MPLS,
972 FIB_ENTRY_FLAG_NONE,
973 NULL);
974 }
975
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100976 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
977
978 return (fib_entry_index);
979}
980
981void
982fib_table_entry_local_label_remove (u32 fib_index,
983 const fib_prefix_t *prefix,
984 mpls_label_t label)
985{
986 fib_node_index_t fib_entry_index;
987 const void *data;
988 mpls_label_t pl;
989
990 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
991
992 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
993 return;
994
995 data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
996
997 if (NULL == data)
998 return;
999
1000 pl = *(mpls_label_t*)data;
1001
1002 if (pl != label)
1003 return;
1004
1005 pl = MPLS_LABEL_INVALID;
1006
1007 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
1008 fib_table_entry_special_remove(fib_index,
1009 prefix,
1010 FIB_SOURCE_MPLS);
1011}
1012
1013u32
1014fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
1015 u32 sw_if_index)
1016{
1017 switch (proto)
1018 {
1019 case FIB_PROTOCOL_IP4:
1020 return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
1021 case FIB_PROTOCOL_IP6:
1022 return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
1023 case FIB_PROTOCOL_MPLS:
1024 return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
1025 }
1026 return (~0);
1027}
1028
1029flow_hash_config_t
1030fib_table_get_flow_hash_config (u32 fib_index,
1031 fib_protocol_t proto)
1032{
Neale Ranns227038a2017-04-21 01:07:59 -07001033 fib_table_t *fib;
1034
1035 fib = fib_table_get(fib_index, proto);
1036
1037 return (fib->ft_flow_hash_config);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001038}
Neale Rannsd792d9c2017-10-21 10:53:20 -07001039
Neale Ranns41da54f2017-05-02 10:15:19 -07001040flow_hash_config_t
1041fib_table_get_default_flow_hash_config (fib_protocol_t proto)
1042{
1043 switch (proto)
1044 {
1045 case FIB_PROTOCOL_IP4:
1046 case FIB_PROTOCOL_IP6:
1047 return (IP_FLOW_HASH_DEFAULT);
1048
1049 case FIB_PROTOCOL_MPLS:
1050 return (MPLS_FLOW_HASH_DEFAULT);
1051 }
1052
1053 ASSERT(0);
1054 return (IP_FLOW_HASH_DEFAULT);
1055}
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001056
Neale Ranns227038a2017-04-21 01:07:59 -07001057/**
1058 * @brief Table set flow hash config context.
1059 */
1060typedef struct fib_table_set_flow_hash_config_ctx_t_
1061{
1062 /**
1063 * the flow hash config to set
1064 */
1065 flow_hash_config_t hash_config;
1066} fib_table_set_flow_hash_config_ctx_t;
1067
Neale Ranns89541992017-04-06 04:41:02 -07001068static fib_table_walk_rc_t
Neale Ranns227038a2017-04-21 01:07:59 -07001069fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1070 void *arg)
1071{
1072 fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1073
1074 fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1075
Neale Ranns89541992017-04-06 04:41:02 -07001076 return (FIB_TABLE_WALK_CONTINUE);
Neale Ranns227038a2017-04-21 01:07:59 -07001077}
1078
1079void
1080fib_table_set_flow_hash_config (u32 fib_index,
1081 fib_protocol_t proto,
1082 flow_hash_config_t hash_config)
1083{
1084 fib_table_set_flow_hash_config_ctx_t ctx = {
1085 .hash_config = hash_config,
1086 };
1087 fib_table_t *fib;
1088
1089 fib = fib_table_get(fib_index, proto);
1090 fib->ft_flow_hash_config = hash_config;
1091
1092 fib_table_walk(fib_index, proto,
1093 fib_table_set_flow_hash_config_cb,
1094 &ctx);
1095}
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001096
1097u32
1098fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1099 u32 sw_if_index)
1100{
1101 fib_table_t *fib_table;
1102
1103 fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1104 proto, sw_if_index),
1105 proto);
1106
1107 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1108}
1109
1110u32
Neale Ranns25b04942018-04-04 09:34:50 -07001111fib_table_get_table_id (u32 fib_index,
1112 fib_protocol_t proto)
1113{
1114 fib_table_t *fib_table;
1115
1116 fib_table = fib_table_get(fib_index, proto);
1117
1118 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1119}
1120
1121u32
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001122fib_table_find (fib_protocol_t proto,
1123 u32 table_id)
1124{
1125 switch (proto)
1126 {
1127 case FIB_PROTOCOL_IP4:
1128 return (ip4_fib_index_from_table_id(table_id));
1129 case FIB_PROTOCOL_IP6:
1130 return (ip6_fib_index_from_table_id(table_id));
1131 case FIB_PROTOCOL_MPLS:
1132 return (mpls_fib_index_from_table_id(table_id));
1133 }
1134 return (~0);
1135}
1136
Neale Ranns2297af02017-09-12 09:45:04 -07001137static u32
1138fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1139 u32 table_id,
1140 fib_source_t src,
1141 const u8 *name)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001142{
1143 fib_table_t *fib_table;
1144 fib_node_index_t fi;
1145
1146 switch (proto)
1147 {
1148 case FIB_PROTOCOL_IP4:
Neale Ranns15002542017-09-10 04:39:11 -07001149 fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001150 break;
1151 case FIB_PROTOCOL_IP6:
Neale Ranns15002542017-09-10 04:39:11 -07001152 fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001153 break;
1154 case FIB_PROTOCOL_MPLS:
Neale Ranns15002542017-09-10 04:39:11 -07001155 fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001156 break;
1157 default:
1158 return (~0);
1159 }
1160
1161 fib_table = fib_table_get(fi, proto);
1162
Jon Loeligerd465fd02024-03-22 12:22:36 -05001163 if (fib_table->ft_desc)
1164 return fi;
1165
1166 if (name && name[0])
Neale Ranns2297af02017-09-12 09:45:04 -07001167 {
Jon Loeligerd465fd02024-03-22 12:22:36 -05001168 fib_table->ft_desc = format(NULL, "%s", name);
1169 return fi;
Neale Ranns2297af02017-09-12 09:45:04 -07001170 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001171
Jon Loeligerd465fd02024-03-22 12:22:36 -05001172 if (table_id == 0)
1173 {
1174 char *default_name = fib_table_default_names[proto];
1175 if (default_name && default_name[0])
1176 {
1177 fib_table->ft_desc = format(NULL, "%s", default_name);
1178 return fi;
1179 }
1180 }
1181
1182 fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1183 format_fib_protocol, proto,
1184 table_id);
1185 return fi;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001186}
1187
1188u32
Neale Ranns2297af02017-09-12 09:45:04 -07001189fib_table_find_or_create_and_lock (fib_protocol_t proto,
1190 u32 table_id,
1191 fib_source_t src)
1192{
1193 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1194 src, NULL));
1195}
1196
1197u32
1198fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1199 u32 table_id,
1200 fib_source_t src,
1201 const u8 *name)
1202{
1203 return (fib_table_find_or_create_and_lock_i(proto, table_id,
1204 src, name));
1205}
1206
1207u32
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001208fib_table_create_and_lock (fib_protocol_t proto,
Neale Ranns15002542017-09-10 04:39:11 -07001209 fib_source_t src,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001210 const char *const fmt,
1211 ...)
1212{
1213 fib_table_t *fib_table;
1214 fib_node_index_t fi;
1215 va_list ap;
1216
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001217
1218 switch (proto)
1219 {
1220 case FIB_PROTOCOL_IP4:
Neale Ranns15002542017-09-10 04:39:11 -07001221 fi = ip4_fib_table_create_and_lock(src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001222 break;
1223 case FIB_PROTOCOL_IP6:
Neale Ranns53da2212018-02-24 02:11:19 -08001224 fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001225 break;
1226 case FIB_PROTOCOL_MPLS:
Neale Ranns15002542017-09-10 04:39:11 -07001227 fi = mpls_fib_table_create_and_lock(src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001228 break;
1229 default:
1230 return (~0);
1231 }
1232
1233 fib_table = fib_table_get(fi, proto);
1234
Paul Vinciguerra0c0383d2018-10-24 12:14:09 -07001235 va_start(ap, fmt);
1236
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001237 fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1238
1239 va_end(ap);
1240 return (fi);
1241}
1242
1243static void
1244fib_table_destroy (fib_table_t *fib_table)
1245{
1246 vec_free(fib_table->ft_desc);
1247
1248 switch (fib_table->ft_proto)
1249 {
1250 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -07001251 ip4_fib_table_destroy(fib_table->ft_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001252 break;
1253 case FIB_PROTOCOL_IP6:
1254 ip6_fib_table_destroy(fib_table->ft_index);
1255 break;
1256 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -07001257 mpls_fib_table_destroy(fib_table->ft_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001258 break;
1259 }
1260}
Neale Ranns5a8123b2017-01-26 01:18:23 -08001261
Neale Ranns32e1c012016-11-22 17:07:28 +00001262void
1263fib_table_walk (u32 fib_index,
1264 fib_protocol_t proto,
1265 fib_table_walk_fn_t fn,
1266 void *ctx)
1267{
1268 switch (proto)
1269 {
1270 case FIB_PROTOCOL_IP4:
1271 ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1272 break;
1273 case FIB_PROTOCOL_IP6:
1274 ip6_fib_table_walk(fib_index, fn, ctx);
1275 break;
1276 case FIB_PROTOCOL_MPLS:
1277 mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1278 break;
1279 }
1280}
1281
Neale Ranns976b2592019-12-04 06:11:00 +00001282typedef struct fib_table_walk_w_src_ctx_t_
1283{
1284 fib_table_walk_fn_t fn;
1285 void *data;
1286 fib_source_t src;
1287} fib_table_walk_w_src_cxt_t;
1288
1289static fib_table_walk_rc_t
1290fib_table_walk_w_src_cb (fib_node_index_t fei,
1291 void *arg)
1292{
1293 fib_table_walk_w_src_cxt_t *ctx = arg;
1294
1295 if (ctx->src == fib_entry_get_best_source(fei))
1296 {
1297 return (ctx->fn(fei, ctx->data));
1298 }
1299 return (FIB_TABLE_WALK_CONTINUE);
1300}
1301
1302void
1303fib_table_walk_w_src (u32 fib_index,
1304 fib_protocol_t proto,
1305 fib_source_t src,
1306 fib_table_walk_fn_t fn,
1307 void *data)
1308{
1309 fib_table_walk_w_src_cxt_t ctx = {
1310 .fn = fn,
1311 .src = src,
1312 .data = data,
1313 };
1314
1315 fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
1316}
1317
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001318void
Neale Ranns89541992017-04-06 04:41:02 -07001319fib_table_sub_tree_walk (u32 fib_index,
1320 fib_protocol_t proto,
1321 const fib_prefix_t *root,
1322 fib_table_walk_fn_t fn,
1323 void *ctx)
1324{
1325 switch (proto)
1326 {
1327 case FIB_PROTOCOL_IP4:
1328 ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1329 break;
1330 case FIB_PROTOCOL_IP6:
1331 ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1332 break;
1333 case FIB_PROTOCOL_MPLS:
1334 break;
1335 }
1336}
1337
Neale Ranns3bab8f92019-12-04 06:11:00 +00001338static void
1339fib_table_lock_dec (fib_table_t *fib_table,
1340 fib_source_t source)
1341{
1342 vec_validate(fib_table->ft_locks, source);
1343
Aloys Augustin6e4cfb52021-09-16 20:53:14 +02001344 ASSERT(fib_table->ft_locks[source] > 0);
Neale Ranns3bab8f92019-12-04 06:11:00 +00001345 fib_table->ft_locks[source]--;
1346 fib_table->ft_total_locks--;
1347}
1348
1349static void
1350fib_table_lock_inc (fib_table_t *fib_table,
1351 fib_source_t source)
1352{
1353 vec_validate(fib_table->ft_locks, source);
1354
Miklos Tirpak4a94cd22019-12-20 11:55:43 +01001355 ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
Neale Ranns3bab8f92019-12-04 06:11:00 +00001356 fib_table->ft_locks[source]++;
1357 fib_table->ft_total_locks++;
1358}
1359
Nathan Skrzypczak275bd792021-09-17 17:29:14 +02001360
1361static void
1362fib_table_lock_clear (fib_table_t *fib_table,
1363 fib_source_t source)
1364{
1365 vec_validate(fib_table->ft_locks, source);
1366
1367 ASSERT(fib_table->ft_locks[source] <= 1);
1368 if (fib_table->ft_locks[source])
1369 {
1370 fib_table->ft_locks[source]--;
1371 fib_table->ft_total_locks--;
1372 }
1373}
1374
1375static void
1376fib_table_lock_set (fib_table_t *fib_table,
1377 fib_source_t source)
1378{
1379 vec_validate(fib_table->ft_locks, source);
1380
1381 ASSERT(fib_table->ft_locks[source] <= 1);
1382 ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
1383 if (!fib_table->ft_locks[source])
1384 {
1385 fib_table->ft_locks[source]++;
1386 fib_table->ft_total_locks++;
1387 }
1388}
1389
Neale Ranns89541992017-04-06 04:41:02 -07001390void
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001391fib_table_unlock (u32 fib_index,
Neale Ranns15002542017-09-10 04:39:11 -07001392 fib_protocol_t proto,
1393 fib_source_t source)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001394{
1395 fib_table_t *fib_table;
1396
1397 fib_table = fib_table_get(fib_index, proto);
Nathan Skrzypczak275bd792021-09-17 17:29:14 +02001398
1399 if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1400 fib_table_lock_clear(fib_table, source);
1401 else
1402 fib_table_lock_dec(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001403
Neale Ranns3bab8f92019-12-04 06:11:00 +00001404 if (0 == fib_table->ft_total_locks)
Neale Ranns15002542017-09-10 04:39:11 -07001405 {
1406 /*
Aloys Augustin6e4cfb52021-09-16 20:53:14 +02001407 * no more lock from any source - kill it
Neale Ranns15002542017-09-10 04:39:11 -07001408 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001409 fib_table_destroy(fib_table);
1410 }
1411}
Neale Ranns15002542017-09-10 04:39:11 -07001412
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001413void
1414fib_table_lock (u32 fib_index,
Neale Ranns15002542017-09-10 04:39:11 -07001415 fib_protocol_t proto,
1416 fib_source_t source)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001417{
1418 fib_table_t *fib_table;
1419
1420 fib_table = fib_table_get(fib_index, proto);
Neale Ranns6fff24a2018-09-10 19:14:07 -07001421
Nathan Skrzypczak275bd792021-09-17 17:29:14 +02001422 if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
1423 fib_table_lock_set(fib_table, source);
1424 else
1425 fib_table_lock_inc(fib_table, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001426}
1427
1428u32
1429fib_table_get_num_entries (u32 fib_index,
1430 fib_protocol_t proto,
1431 fib_source_t source)
1432{
1433 fib_table_t *fib_table;
1434
1435 fib_table = fib_table_get(fib_index, proto);
1436
1437 return (fib_table->ft_src_route_counts[source]);
1438}
1439
1440u8*
Christophe Fontained3c008d2017-10-02 18:10:54 +02001441format_fib_table_name (u8* s, va_list* ap)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001442{
Christophe Fontained3c008d2017-10-02 18:10:54 +02001443 fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1444 fib_protocol_t proto = va_arg(*ap, int); // int promotion
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001445 fib_table_t *fib_table;
1446
1447 fib_table = fib_table_get(fib_index, proto);
1448
1449 s = format(s, "%v", fib_table->ft_desc);
1450
1451 return (s);
1452}
1453
Neale Ranns9db6ada2019-11-08 12:42:31 +00001454u8*
1455format_fib_table_flags (u8 *s, va_list *args)
1456{
1457 fib_table_flags_t flags = va_arg(*args, int);
1458 fib_table_attribute_t attr;
1459
1460 if (!flags)
1461 {
1462 return format(s, "none");
1463 }
1464
1465 FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1466 if (1 << attr & flags) {
1467 s = format(s, "%s", fib_table_flags_strings[attr]);
1468 }
1469 }
1470
1471 return (s);
1472}
1473
Neale Ranns32e1c012016-11-22 17:07:28 +00001474/**
1475 * @brief Table flush context. Store the indicies of matching FIB entries
1476 * that need to be removed.
1477 */
1478typedef struct fib_table_flush_ctx_t_
1479{
1480 /**
1481 * The list of entries to flush
1482 */
1483 fib_node_index_t *ftf_entries;
1484
1485 /**
1486 * The source we are flushing
1487 */
1488 fib_source_t ftf_source;
1489} fib_table_flush_ctx_t;
1490
Neale Ranns89541992017-04-06 04:41:02 -07001491static fib_table_walk_rc_t
Neale Ranns32e1c012016-11-22 17:07:28 +00001492fib_table_flush_cb (fib_node_index_t fib_entry_index,
1493 void *arg)
1494{
1495 fib_table_flush_ctx_t *ctx = arg;
1496
1497 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1498 {
1499 vec_add1(ctx->ftf_entries, fib_entry_index);
1500 }
Neale Ranns89541992017-04-06 04:41:02 -07001501 return (FIB_TABLE_WALK_CONTINUE);
Neale Ranns32e1c012016-11-22 17:07:28 +00001502}
1503
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001504void
1505fib_table_flush (u32 fib_index,
1506 fib_protocol_t proto,
1507 fib_source_t source)
1508{
Neale Ranns32e1c012016-11-22 17:07:28 +00001509 fib_node_index_t *fib_entry_index;
1510 fib_table_flush_ctx_t ctx = {
1511 .ftf_entries = NULL,
1512 .ftf_source = source,
1513 };
1514
1515 fib_table_walk(fib_index, proto,
1516 fib_table_flush_cb,
1517 &ctx);
1518
1519 vec_foreach(fib_entry_index, ctx.ftf_entries)
1520 {
Neale Rannsa8d9f302017-02-20 09:17:02 -08001521 fib_table_entry_delete_index(*fib_entry_index, source);
Neale Ranns32e1c012016-11-22 17:07:28 +00001522 }
1523
1524 vec_free(ctx.ftf_entries);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001525}
Neale Rannsc87aafa2017-11-29 00:59:31 -08001526
Neale Ranns9db6ada2019-11-08 12:42:31 +00001527static fib_table_walk_rc_t
1528fib_table_mark_cb (fib_node_index_t fib_entry_index,
1529 void *arg)
1530{
1531 fib_table_flush_ctx_t *ctx = arg;
1532
1533 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1534 {
1535 fib_entry_mark(fib_entry_index, ctx->ftf_source);
1536 }
1537 return (FIB_TABLE_WALK_CONTINUE);
1538}
1539
1540void
1541fib_table_mark (u32 fib_index,
1542 fib_protocol_t proto,
1543 fib_source_t source)
1544{
1545 fib_table_flush_ctx_t ctx = {
1546 .ftf_source = source,
1547 };
1548 fib_table_t *fib_table;
1549
1550 fib_table = fib_table_get(fib_index, proto);
1551
1552 fib_table->ft_epoch++;
1553 fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1554
1555 fib_table_walk(fib_index, proto,
1556 fib_table_mark_cb,
1557 &ctx);
1558}
1559
1560static fib_table_walk_rc_t
1561fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1562 void *arg)
1563{
1564 fib_table_flush_ctx_t *ctx = arg;
1565
1566 if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1567 {
1568 vec_add1(ctx->ftf_entries, fib_entry_index);
1569 }
1570 return (FIB_TABLE_WALK_CONTINUE);
1571}
1572
1573void
1574fib_table_sweep (u32 fib_index,
1575 fib_protocol_t proto,
1576 fib_source_t source)
1577{
1578 fib_table_flush_ctx_t ctx = {
1579 .ftf_source = source,
1580 };
1581 fib_node_index_t *fib_entry_index;
1582 fib_table_t *fib_table;
1583
1584 fib_table = fib_table_get(fib_index, proto);
1585
1586 fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1587
1588 fib_table_walk(fib_index, proto,
1589 fib_table_sweep_cb,
1590 &ctx);
1591
1592 vec_foreach(fib_entry_index, ctx.ftf_entries)
1593 {
1594 fib_table_entry_delete_index(*fib_entry_index, source);
1595 }
1596
1597 vec_free(ctx.ftf_entries);
1598}
1599
Neale Rannsc87aafa2017-11-29 00:59:31 -08001600u8 *
1601format_fib_table_memory (u8 *s, va_list *args)
1602{
1603 s = format(s, "%U", format_ip4_fib_table_memory);
1604 s = format(s, "%U", format_ip6_fib_table_memory);
1605 s = format(s, "%U", format_mpls_fib_table_memory);
1606
1607 return (s);
1608}