blob: 6b6cc5cb99a31a443eb4b8b417ddf34213e77af2 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vlib/vlib.h>
17#include <vnet/dpo/drop_dpo.h>
18
19#include <vnet/fib/fib_table.h>
20#include <vnet/fib/fib_entry_cover.h>
21#include <vnet/fib/fib_internal.h>
22#include <vnet/fib/ip4_fib.h>
23#include <vnet/fib/ip6_fib.h>
24#include <vnet/fib/mpls_fib.h>
25
26fib_table_t *
27fib_table_get (fib_node_index_t index,
28 fib_protocol_t proto)
29{
30 switch (proto)
31 {
32 case FIB_PROTOCOL_IP4:
33 return (pool_elt_at_index(ip4_main.fibs, index));
34 case FIB_PROTOCOL_IP6:
35 return (pool_elt_at_index(ip6_main.fibs, index));
36 case FIB_PROTOCOL_MPLS:
37 return (pool_elt_at_index(mpls_main.fibs, index));
38 }
39 ASSERT(0);
40 return (NULL);
41}
42
43static inline fib_node_index_t
44fib_table_lookup_i (fib_table_t *fib_table,
45 const fib_prefix_t *prefix)
46{
47 switch (prefix->fp_proto)
48 {
49 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -070050 return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010051 &prefix->fp_addr.ip4,
52 prefix->fp_len));
53 case FIB_PROTOCOL_IP6:
54 return (ip6_fib_table_lookup(fib_table->ft_index,
55 &prefix->fp_addr.ip6,
56 prefix->fp_len));
57 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -070058 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010059 prefix->fp_label,
60 prefix->fp_eos));
61 }
62 return (FIB_NODE_INDEX_INVALID);
63}
64
65fib_node_index_t
66fib_table_lookup (u32 fib_index,
67 const fib_prefix_t *prefix)
68{
69 return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
70}
71
72static inline fib_node_index_t
73fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
74 const fib_prefix_t *prefix)
75{
76 switch (prefix->fp_proto)
77 {
78 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -070079 return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010080 &prefix->fp_addr.ip4,
81 prefix->fp_len));
82 case FIB_PROTOCOL_IP6:
83 return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
84 &prefix->fp_addr.ip6,
85 prefix->fp_len));
86 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -070087 return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +010088 prefix->fp_label,
89 prefix->fp_eos));
90 }
91 return (FIB_NODE_INDEX_INVALID);
92}
93
94fib_node_index_t
95fib_table_lookup_exact_match (u32 fib_index,
96 const fib_prefix_t *prefix)
97{
98 return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
99 prefix->fp_proto),
100 prefix));
101}
102
103static fib_node_index_t
104fib_table_get_less_specific_i (fib_table_t *fib_table,
105 const fib_prefix_t *prefix)
106{
107 fib_prefix_t pfx;
108
109 pfx = *prefix;
110
111 if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
112 {
113 return (FIB_NODE_INDEX_INVALID);
114 }
115
116 /*
117 * in the absence of a tree structure for the table that allows for an O(1)
118 * parent get, a cheeky way to find the cover is to LPM for the prefix with
119 * mask-1.
120 * there should always be a cover, though it may be the default route. the
121 * default route's cover is the default route.
122 */
123 if (pfx.fp_len != 0) {
124 pfx.fp_len -= 1;
125 }
126
127 return (fib_table_lookup_i(fib_table, &pfx));
128}
129
130fib_node_index_t
131fib_table_get_less_specific (u32 fib_index,
132 const fib_prefix_t *prefix)
133{
134 return (fib_table_get_less_specific_i(fib_table_get(fib_index,
135 prefix->fp_proto),
136 prefix));
137}
138
139static void
140fib_table_entry_remove (fib_table_t *fib_table,
141 const fib_prefix_t *prefix,
142 fib_node_index_t fib_entry_index)
143{
144 vlib_smp_unsafe_warning();
145
146 fib_table->ft_total_route_counts--;
147
148 switch (prefix->fp_proto)
149 {
150 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -0700151 ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100152 &prefix->fp_addr.ip4,
153 prefix->fp_len);
154 break;
155 case FIB_PROTOCOL_IP6:
156 ip6_fib_table_entry_remove(fib_table->ft_index,
157 &prefix->fp_addr.ip6,
158 prefix->fp_len);
159 break;
160 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -0700161 mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162 prefix->fp_label,
163 prefix->fp_eos);
164 break;
165 }
166
167 fib_entry_unlock(fib_entry_index);
168}
169
170static void
171fib_table_post_insert_actions (fib_table_t *fib_table,
172 const fib_prefix_t *prefix,
173 fib_node_index_t fib_entry_index)
174{
175 fib_node_index_t fib_entry_cover_index;
176
177 /*
178 * no cover relationships in the MPLS FIB
179 */
180 if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
181 return;
182
183 /*
184 * find and inform the covering entry that a new more specific
185 * has been inserted beneath it
186 */
187 fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
188 /*
189 * the indicies are the same when the default route is first added
190 */
191 if (fib_entry_cover_index != fib_entry_index)
192 {
193 fib_entry_cover_change_notify(fib_entry_cover_index,
194 fib_entry_index);
195 }
196}
197
198static void
199fib_table_entry_insert (fib_table_t *fib_table,
200 const fib_prefix_t *prefix,
201 fib_node_index_t fib_entry_index)
202{
203 vlib_smp_unsafe_warning();
204
205 fib_entry_lock(fib_entry_index);
206 fib_table->ft_total_route_counts++;
207
208 switch (prefix->fp_proto)
209 {
210 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -0700211 ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100212 &prefix->fp_addr.ip4,
213 prefix->fp_len,
214 fib_entry_index);
215 break;
216 case FIB_PROTOCOL_IP6:
217 ip6_fib_table_entry_insert(fib_table->ft_index,
218 &prefix->fp_addr.ip6,
219 prefix->fp_len,
220 fib_entry_index);
221 break;
222 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -0700223 mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100224 prefix->fp_label,
225 prefix->fp_eos,
226 fib_entry_index);
227 break;
228 }
229
230 fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
231}
232
233void
234fib_table_fwding_dpo_update (u32 fib_index,
235 const fib_prefix_t *prefix,
236 const dpo_id_t *dpo)
237{
238 vlib_smp_unsafe_warning();
239
240 switch (prefix->fp_proto)
241 {
242 case FIB_PROTOCOL_IP4:
243 return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
244 &prefix->fp_addr.ip4,
245 prefix->fp_len,
246 dpo));
247 case FIB_PROTOCOL_IP6:
248 return (ip6_fib_table_fwding_dpo_update(fib_index,
249 &prefix->fp_addr.ip6,
250 prefix->fp_len,
251 dpo));
252 case FIB_PROTOCOL_MPLS:
253 return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
254 prefix->fp_label,
255 prefix->fp_eos,
256 dpo));
257 }
258}
259
260void
261fib_table_fwding_dpo_remove (u32 fib_index,
262 const fib_prefix_t *prefix,
263 const dpo_id_t *dpo)
264{
265 vlib_smp_unsafe_warning();
266
267 switch (prefix->fp_proto)
268 {
269 case FIB_PROTOCOL_IP4:
270 return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
271 &prefix->fp_addr.ip4,
272 prefix->fp_len,
Neale Rannsa3af3372017-03-28 03:49:52 -0700273 dpo,
274 fib_table_get_less_specific(fib_index,
275 prefix)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100276 case FIB_PROTOCOL_IP6:
277 return (ip6_fib_table_fwding_dpo_remove(fib_index,
278 &prefix->fp_addr.ip6,
279 prefix->fp_len,
280 dpo));
281 case FIB_PROTOCOL_MPLS:
282 return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
283 prefix->fp_label,
284 prefix->fp_eos));
285 }
286}
287
288
289fib_node_index_t
290fib_table_entry_special_dpo_add (u32 fib_index,
291 const fib_prefix_t *prefix,
292 fib_source_t source,
293 fib_entry_flag_t flags,
294 const dpo_id_t *dpo)
295{
296 fib_node_index_t fib_entry_index;
297 fib_table_t *fib_table;
298
299 fib_table = fib_table_get(fib_index, prefix->fp_proto);
300 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
301
302 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
303 {
304 fib_entry_index = fib_entry_create_special(fib_index, prefix,
305 source, flags,
306 dpo);
307
308 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
309 fib_table->ft_src_route_counts[source]++;
310 }
311 else
312 {
313 int was_sourced;
314
315 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
316 fib_entry_special_add(fib_entry_index, source, flags, dpo);
317
318 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
319 {
320 fib_table->ft_src_route_counts[source]++;
321 }
322 }
323
324
325 return (fib_entry_index);
326}
327
328fib_node_index_t
Neale Ranns948e00f2016-10-20 13:39:34 +0100329fib_table_entry_special_dpo_update (u32 fib_index,
330 const fib_prefix_t *prefix,
331 fib_source_t source,
332 fib_entry_flag_t flags,
333 const dpo_id_t *dpo)
334{
335 fib_node_index_t fib_entry_index;
336 fib_table_t *fib_table;
337
338 fib_table = fib_table_get(fib_index, prefix->fp_proto);
339 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
340
341 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
342 {
343 fib_entry_index = fib_entry_create_special(fib_index, prefix,
344 source, flags,
345 dpo);
346
347 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
348 fib_table->ft_src_route_counts[source]++;
349 }
350 else
351 {
352 int was_sourced;
353
354 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
355
356 if (was_sourced)
357 fib_entry_special_update(fib_entry_index, source, flags, dpo);
358 else
359 fib_entry_special_add(fib_entry_index, source, flags, dpo);
360
361 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
362 {
363 fib_table->ft_src_route_counts[source]++;
364 }
365 }
366
367 return (fib_entry_index);
368}
369
370fib_node_index_t
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100371fib_table_entry_special_add (u32 fib_index,
372 const fib_prefix_t *prefix,
373 fib_source_t source,
Neale Rannsa0558302017-04-13 00:44:52 -0700374 fib_entry_flag_t flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375{
376 fib_node_index_t fib_entry_index;
Neale Ranns948e00f2016-10-20 13:39:34 +0100377 dpo_id_t tmp_dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100378
Neale Rannsa0558302017-04-13 00:44:52 -0700379 dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100380
381 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
382 flags, &tmp_dpo);
383
384 dpo_unlock(&tmp_dpo);
385
386 return (fib_entry_index);
387}
388
389void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100390fib_table_entry_special_remove (u32 fib_index,
391 const fib_prefix_t *prefix,
392 fib_source_t source)
393{
394 /*
395 * 1 is it present
396 * yes => remove source
397 * 2 - is it still sourced?
398 * no => cover walk
399 */
400 fib_node_index_t fib_entry_index;
401 fib_table_t *fib_table;
402
403 fib_table = fib_table_get(fib_index, prefix->fp_proto);
404 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
405
406 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
407 {
408 /*
409 * removing an etry that does not exist. i'll allow it.
410 */
411 }
412 else
413 {
414 fib_entry_src_flag_t src_flag;
415 int was_sourced;
416
417 /*
418 * don't nobody go nowhere
419 */
420 fib_entry_lock(fib_entry_index);
421 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
422
423 src_flag = fib_entry_special_remove(fib_entry_index, source);
424
425 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
426 {
427 /*
428 * last source gone. remove from the table
429 */
430 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
431
432 /*
433 * now the entry is no longer in the table, we can
434 * inform the entries that it covers to re-calculate their cover
435 */
436 fib_entry_cover_change_notify(fib_entry_index,
437 FIB_NODE_INDEX_INVALID);
438 }
439 /*
440 * else
441 * still has sources, leave it be.
442 */
443 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
444 {
445 fib_table->ft_src_route_counts[source]--;
446 }
447
448 fib_entry_unlock(fib_entry_index);
449 }
450}
451
452/**
453 * fib_table_route_path_fixup
454 *
455 * Convert attached hosts to attached next-hops.
456 *
457 * This special case is required because an attached path will link to a
458 * glean, and the FIB entry will have the interface or API/CLI source. When
459 * the ARP/ND process is completes then that source (which will provide a
460 * complete adjacency) will be lower priority and so the FIB entry will
461 * remain linked to a glean and traffic will never reach the hosts. For
462 * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
463 * adjacency.
464 */
465static void
466fib_table_route_path_fixup (const fib_prefix_t *prefix,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800467 fib_entry_flag_t eflags,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100468 fib_route_path_t *path)
469{
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800470 /*
471 * not all zeros next hop &&
472 * is recursive path &&
473 * nexthop is same as the route's address
474 */
475 if ((!ip46_address_is_zero(&path->frp_addr)) &&
476 (~0 == path->frp_sw_if_index) &&
477 (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
478 {
479 /* Prefix recurses via itse;f */
480 path->frp_flags |= FIB_ROUTE_PATH_DROP;
481 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100482 if (fib_prefix_is_host(prefix) &&
483 ip46_address_is_zero(&path->frp_addr) &&
484 path->frp_sw_if_index != ~0)
485 {
486 path->frp_addr = prefix->fp_addr;
Neale Ranns4b919a52017-03-11 05:55:21 -0800487 path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100488 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800489 if (eflags & FIB_ENTRY_FLAG_DROP)
490 {
491 path->frp_flags |= FIB_ROUTE_PATH_DROP;
492 }
493 if (eflags & FIB_ENTRY_FLAG_LOCAL)
494 {
495 path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
496 }
497 if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
498 {
499 path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
500 }
501}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100502
503fib_node_index_t
504fib_table_entry_path_add (u32 fib_index,
505 const fib_prefix_t *prefix,
506 fib_source_t source,
507 fib_entry_flag_t flags,
Neale Rannsda78f952017-05-24 09:15:43 -0700508 dpo_proto_t next_hop_proto,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100509 const ip46_address_t *next_hop,
510 u32 next_hop_sw_if_index,
511 u32 next_hop_fib_index,
512 u32 next_hop_weight,
Neale Rannsad422ed2016-11-02 14:20:04 +0000513 mpls_label_t *next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100514 fib_route_path_flags_t path_flags)
515{
516 fib_route_path_t path = {
517 .frp_proto = next_hop_proto,
518 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
519 .frp_sw_if_index = next_hop_sw_if_index,
520 .frp_fib_index = next_hop_fib_index,
521 .frp_weight = next_hop_weight,
522 .frp_flags = path_flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000523 .frp_label_stack = next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100524 };
525 fib_node_index_t fib_entry_index;
526 fib_route_path_t *paths = NULL;
527
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100528 vec_add1(paths, path);
529
530 fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
531 source, flags, paths);
532
533 vec_free(paths);
534 return (fib_entry_index);
535}
536
537fib_node_index_t
538fib_table_entry_path_add2 (u32 fib_index,
539 const fib_prefix_t *prefix,
540 fib_source_t source,
541 fib_entry_flag_t flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000542 fib_route_path_t *rpath)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100543{
544 fib_node_index_t fib_entry_index;
545 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000546 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100547
548 fib_table = fib_table_get(fib_index, prefix->fp_proto);
549 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
550
Neale Rannsad422ed2016-11-02 14:20:04 +0000551 for (ii = 0; ii < vec_len(rpath); ii++)
552 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800553 fib_table_route_path_fixup(prefix, flags, &rpath[ii]);
Neale Rannsad422ed2016-11-02 14:20:04 +0000554 }
555
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100556 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
557 {
558 fib_entry_index = fib_entry_create(fib_index, prefix,
559 source, flags,
560 rpath);
561
562 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
563 fib_table->ft_src_route_counts[source]++;
564 }
565 else
566 {
567 int was_sourced;
568
569 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
570 fib_entry_path_add(fib_entry_index, source, flags, rpath);;
571
572 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
573 {
574 fib_table->ft_src_route_counts[source]++;
575 }
576 }
577
578 return (fib_entry_index);
579}
580
581void
582fib_table_entry_path_remove2 (u32 fib_index,
Neale Rannsad422ed2016-11-02 14:20:04 +0000583 const fib_prefix_t *prefix,
584 fib_source_t source,
585 fib_route_path_t *rpath)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100586{
587 /*
588 * 1 is it present
589 * yes => remove source
590 * 2 - is it still sourced?
591 * no => cover walk
592 */
593 fib_node_index_t fib_entry_index;
594 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000595 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100596
597 fib_table = fib_table_get(fib_index, prefix->fp_proto);
598 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
599
600 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
601 {
602 /*
603 * removing an etry that does not exist. i'll allow it.
604 */
605 }
606 else
607 {
608 fib_entry_src_flag_t src_flag;
609 int was_sourced;
610
Neale Rannsf12a83f2017-04-18 09:09:40 -0700611 /*
612 * if it's not sourced, then there's nowt to remove
613 */
614 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
615 if (!was_sourced)
616 {
617 return;
618 }
619
620 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100621 * don't nobody go nowhere
622 */
623 fib_entry_lock(fib_entry_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100624
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800625 for (ii = 0; ii < vec_len(rpath); ii++)
626 {
627 fib_table_route_path_fixup(
628 prefix,
629 fib_entry_get_flags_for_source(fib_entry_index,
630 source),
631 &rpath[ii]);
632 }
633
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100634 src_flag = fib_entry_path_remove(fib_entry_index, source, rpath);
635
636 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
637 {
638 /*
639 * last source gone. remove from the table
640 */
641 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
642
643 /*
644 * now the entry is no longer in the table, we can
645 * inform the entries that it covers to re-calculate their cover
646 */
647 fib_entry_cover_change_notify(fib_entry_index,
648 FIB_NODE_INDEX_INVALID);
649 }
650 /*
651 * else
652 * still has sources, leave it be.
653 */
654 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
655 {
656 fib_table->ft_src_route_counts[source]--;
657 }
658
659 fib_entry_unlock(fib_entry_index);
660 }
661}
662
663void
664fib_table_entry_path_remove (u32 fib_index,
665 const fib_prefix_t *prefix,
666 fib_source_t source,
Neale Rannsda78f952017-05-24 09:15:43 -0700667 dpo_proto_t next_hop_proto,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100668 const ip46_address_t *next_hop,
669 u32 next_hop_sw_if_index,
670 u32 next_hop_fib_index,
671 u32 next_hop_weight,
672 fib_route_path_flags_t path_flags)
673{
674 /*
675 * 1 is it present
676 * yes => remove source
677 * 2 - is it still sourced?
678 * no => cover walk
679 */
680 fib_route_path_t path = {
681 .frp_proto = next_hop_proto,
682 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
683 .frp_sw_if_index = next_hop_sw_if_index,
684 .frp_fib_index = next_hop_fib_index,
685 .frp_weight = next_hop_weight,
686 .frp_flags = path_flags,
687 };
688 fib_route_path_t *paths = NULL;
689
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690 vec_add1(paths, path);
691
692 fib_table_entry_path_remove2(fib_index, prefix, source, paths);
693
694 vec_free(paths);
695}
696
697static int
698fib_route_path_cmp_for_sort (void * v1,
699 void * v2)
700{
701 return (fib_route_path_cmp(v1, v2));
702}
703
704fib_node_index_t
705fib_table_entry_update (u32 fib_index,
706 const fib_prefix_t *prefix,
707 fib_source_t source,
708 fib_entry_flag_t flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000709 fib_route_path_t *paths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100710{
711 fib_node_index_t fib_entry_index;
712 fib_table_t *fib_table;
Neale Rannsad422ed2016-11-02 14:20:04 +0000713 u32 ii;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100714
715 fib_table = fib_table_get(fib_index, prefix->fp_proto);
716 fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
717
Neale Rannsad422ed2016-11-02 14:20:04 +0000718 for (ii = 0; ii < vec_len(paths); ii++)
719 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800720 fib_table_route_path_fixup(prefix, flags, &paths[ii]);
Neale Rannsad422ed2016-11-02 14:20:04 +0000721 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100722 /*
723 * sort the paths provided by the control plane. this means
724 * the paths and the extension on the entry will be sorted.
725 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000726 vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100727
728 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
729 {
730 fib_entry_index = fib_entry_create(fib_index, prefix,
731 source, flags,
732 paths);
733
734 fib_table_entry_insert(fib_table, prefix, fib_entry_index);
735 fib_table->ft_src_route_counts[source]++;
736 }
737 else
738 {
739 int was_sourced;
740
741 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
742 fib_entry_update(fib_entry_index, source, flags, paths);
743
744 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
745 {
746 fib_table->ft_src_route_counts[source]++;
747 }
748 }
749
750 return (fib_entry_index);
751}
752
753fib_node_index_t
754fib_table_entry_update_one_path (u32 fib_index,
755 const fib_prefix_t *prefix,
756 fib_source_t source,
757 fib_entry_flag_t flags,
Neale Rannsda78f952017-05-24 09:15:43 -0700758 dpo_proto_t next_hop_proto,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100759 const ip46_address_t *next_hop,
760 u32 next_hop_sw_if_index,
761 u32 next_hop_fib_index,
762 u32 next_hop_weight,
Neale Rannsad422ed2016-11-02 14:20:04 +0000763 mpls_label_t *next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100764 fib_route_path_flags_t path_flags)
765{
766 fib_node_index_t fib_entry_index;
767 fib_route_path_t path = {
768 .frp_proto = next_hop_proto,
769 .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
770 .frp_sw_if_index = next_hop_sw_if_index,
771 .frp_fib_index = next_hop_fib_index,
772 .frp_weight = next_hop_weight,
773 .frp_flags = path_flags,
Neale Rannsad422ed2016-11-02 14:20:04 +0000774 .frp_label_stack = next_hop_labels,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100775 };
776 fib_route_path_t *paths = NULL;
777
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100778 vec_add1(paths, path);
779
780 fib_entry_index =
781 fib_table_entry_update(fib_index, prefix, source, flags, paths);
782
783 vec_free(paths);
784
785 return (fib_entry_index);
786}
787
788static void
789fib_table_entry_delete_i (u32 fib_index,
790 fib_node_index_t fib_entry_index,
791 const fib_prefix_t *prefix,
792 fib_source_t source)
793{
794 fib_entry_src_flag_t src_flag;
795 fib_table_t *fib_table;
796 int was_sourced;
797
798 fib_table = fib_table_get(fib_index, prefix->fp_proto);
799 was_sourced = fib_entry_is_sourced(fib_entry_index, source);
800
801 /*
802 * don't nobody go nowhere
803 */
804 fib_entry_lock(fib_entry_index);
805
806 src_flag = fib_entry_delete(fib_entry_index, source);
807
808 if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
809 {
810 /*
811 * last source gone. remove from the table
812 */
813 fib_table_entry_remove(fib_table, prefix, fib_entry_index);
814
815 /*
816 * now the entry is no longer in the table, we can
817 * inform the entries that it covers to re-calculate their cover
818 */
819 fib_entry_cover_change_notify(fib_entry_index,
820 FIB_NODE_INDEX_INVALID);
821 }
822 /*
823 * else
824 * still has sources, leave it be.
825 */
826 if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
827 {
828 fib_table->ft_src_route_counts[source]--;
829 }
830
831 fib_entry_unlock(fib_entry_index);
832}
833
834void
835fib_table_entry_delete (u32 fib_index,
836 const fib_prefix_t *prefix,
837 fib_source_t source)
838{
839 fib_node_index_t fib_entry_index;
840
841 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
842
843 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
844 {
845 /*
846 * removing an etry that does not exist.
847 * i'll allow it, but i won't like it.
848 */
849 clib_warning("%U not in FIB", format_fib_prefix, prefix);
850 }
851 else
852 {
853 fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
854 }
855}
856
857void
858fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
859 fib_source_t source)
860{
861 fib_prefix_t prefix;
862
863 fib_entry_get_prefix(fib_entry_index, &prefix);
864
865 fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
866 fib_entry_index, &prefix, source);
867}
868
869fib_node_index_t
870fib_table_entry_local_label_add (u32 fib_index,
871 const fib_prefix_t *prefix,
872 mpls_label_t label)
873{
874 fib_node_index_t fib_entry_index;
875
Neale Ranns1357f3b2016-10-16 12:01:42 -0700876 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
877
878 if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
879 !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
880 {
881 /*
882 * only source the prefix once. this allows the label change
883 * operation to work
884 */
885 fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
886 FIB_SOURCE_MPLS,
887 FIB_ENTRY_FLAG_NONE,
888 NULL);
889 }
890
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100891 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
892
893 return (fib_entry_index);
894}
895
896void
897fib_table_entry_local_label_remove (u32 fib_index,
898 const fib_prefix_t *prefix,
899 mpls_label_t label)
900{
901 fib_node_index_t fib_entry_index;
902 const void *data;
903 mpls_label_t pl;
904
905 fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
906
907 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
908 return;
909
910 data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
911
912 if (NULL == data)
913 return;
914
915 pl = *(mpls_label_t*)data;
916
917 if (pl != label)
918 return;
919
920 pl = MPLS_LABEL_INVALID;
921
922 fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
923 fib_table_entry_special_remove(fib_index,
924 prefix,
925 FIB_SOURCE_MPLS);
926}
927
928u32
929fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
930 u32 sw_if_index)
931{
932 switch (proto)
933 {
934 case FIB_PROTOCOL_IP4:
935 return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
936 case FIB_PROTOCOL_IP6:
937 return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
938 case FIB_PROTOCOL_MPLS:
939 return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
940 }
941 return (~0);
942}
943
944flow_hash_config_t
945fib_table_get_flow_hash_config (u32 fib_index,
946 fib_protocol_t proto)
947{
Neale Ranns227038a2017-04-21 01:07:59 -0700948 fib_table_t *fib;
949
950 fib = fib_table_get(fib_index, proto);
951
952 return (fib->ft_flow_hash_config);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100953}
Neale Ranns41da54f2017-05-02 10:15:19 -0700954flow_hash_config_t
955fib_table_get_default_flow_hash_config (fib_protocol_t proto)
956{
957 switch (proto)
958 {
959 case FIB_PROTOCOL_IP4:
960 case FIB_PROTOCOL_IP6:
961 return (IP_FLOW_HASH_DEFAULT);
962
963 case FIB_PROTOCOL_MPLS:
964 return (MPLS_FLOW_HASH_DEFAULT);
965 }
966
967 ASSERT(0);
968 return (IP_FLOW_HASH_DEFAULT);
969}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100970
Neale Ranns227038a2017-04-21 01:07:59 -0700971/**
972 * @brief Table set flow hash config context.
973 */
974typedef struct fib_table_set_flow_hash_config_ctx_t_
975{
976 /**
977 * the flow hash config to set
978 */
979 flow_hash_config_t hash_config;
980} fib_table_set_flow_hash_config_ctx_t;
981
982static int
983fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
984 void *arg)
985{
986 fib_table_set_flow_hash_config_ctx_t *ctx = arg;
987
988 fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
989
990 return (1);
991}
992
993void
994fib_table_set_flow_hash_config (u32 fib_index,
995 fib_protocol_t proto,
996 flow_hash_config_t hash_config)
997{
998 fib_table_set_flow_hash_config_ctx_t ctx = {
999 .hash_config = hash_config,
1000 };
1001 fib_table_t *fib;
1002
1003 fib = fib_table_get(fib_index, proto);
1004 fib->ft_flow_hash_config = hash_config;
1005
1006 fib_table_walk(fib_index, proto,
1007 fib_table_set_flow_hash_config_cb,
1008 &ctx);
1009}
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001010
1011u32
1012fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1013 u32 sw_if_index)
1014{
1015 fib_table_t *fib_table;
1016
1017 fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1018 proto, sw_if_index),
1019 proto);
1020
1021 return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1022}
1023
1024u32
1025fib_table_find (fib_protocol_t proto,
1026 u32 table_id)
1027{
1028 switch (proto)
1029 {
1030 case FIB_PROTOCOL_IP4:
1031 return (ip4_fib_index_from_table_id(table_id));
1032 case FIB_PROTOCOL_IP6:
1033 return (ip6_fib_index_from_table_id(table_id));
1034 case FIB_PROTOCOL_MPLS:
1035 return (mpls_fib_index_from_table_id(table_id));
1036 }
1037 return (~0);
1038}
1039
1040u32
1041fib_table_find_or_create_and_lock (fib_protocol_t proto,
1042 u32 table_id)
1043{
1044 fib_table_t *fib_table;
1045 fib_node_index_t fi;
1046
1047 switch (proto)
1048 {
1049 case FIB_PROTOCOL_IP4:
1050 fi = ip4_fib_table_find_or_create_and_lock(table_id);
1051 break;
1052 case FIB_PROTOCOL_IP6:
1053 fi = ip6_fib_table_find_or_create_and_lock(table_id);
1054 break;
1055 case FIB_PROTOCOL_MPLS:
1056 fi = mpls_fib_table_find_or_create_and_lock(table_id);
1057 break;
1058 default:
1059 return (~0);
1060 }
1061
1062 fib_table = fib_table_get(fi, proto);
1063
1064 fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1065 format_fib_protocol, proto,
1066 table_id);
1067
1068 return (fi);
1069}
1070
1071u32
1072fib_table_create_and_lock (fib_protocol_t proto,
1073 const char *const fmt,
1074 ...)
1075{
1076 fib_table_t *fib_table;
1077 fib_node_index_t fi;
1078 va_list ap;
1079
1080 va_start(ap, fmt);
1081
1082 switch (proto)
1083 {
1084 case FIB_PROTOCOL_IP4:
1085 fi = ip4_fib_table_create_and_lock();
1086 break;
1087 case FIB_PROTOCOL_IP6:
1088 fi = ip6_fib_table_create_and_lock();
1089 break;
1090 case FIB_PROTOCOL_MPLS:
1091 fi = mpls_fib_table_create_and_lock();
1092 break;
1093 default:
1094 return (~0);
1095 }
1096
1097 fib_table = fib_table_get(fi, proto);
1098
1099 fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1100
1101 va_end(ap);
1102 return (fi);
1103}
1104
1105static void
1106fib_table_destroy (fib_table_t *fib_table)
1107{
1108 vec_free(fib_table->ft_desc);
1109
1110 switch (fib_table->ft_proto)
1111 {
1112 case FIB_PROTOCOL_IP4:
Neale Rannsa3af3372017-03-28 03:49:52 -07001113 ip4_fib_table_destroy(fib_table->ft_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001114 break;
1115 case FIB_PROTOCOL_IP6:
1116 ip6_fib_table_destroy(fib_table->ft_index);
1117 break;
1118 case FIB_PROTOCOL_MPLS:
Neale Rannsa3af3372017-03-28 03:49:52 -07001119 mpls_fib_table_destroy(fib_table->ft_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001120 break;
1121 }
1122}
Neale Ranns5a8123b2017-01-26 01:18:23 -08001123
Neale Ranns32e1c012016-11-22 17:07:28 +00001124void
1125fib_table_walk (u32 fib_index,
1126 fib_protocol_t proto,
1127 fib_table_walk_fn_t fn,
1128 void *ctx)
1129{
1130 switch (proto)
1131 {
1132 case FIB_PROTOCOL_IP4:
1133 ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1134 break;
1135 case FIB_PROTOCOL_IP6:
1136 ip6_fib_table_walk(fib_index, fn, ctx);
1137 break;
1138 case FIB_PROTOCOL_MPLS:
1139 mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1140 break;
1141 }
1142}
1143
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001144void
1145fib_table_unlock (u32 fib_index,
1146 fib_protocol_t proto)
1147{
1148 fib_table_t *fib_table;
1149
1150 fib_table = fib_table_get(fib_index, proto);
1151 fib_table->ft_locks--;
1152
1153 if (0 == fib_table->ft_locks)
1154 {
1155 fib_table_destroy(fib_table);
1156 }
1157}
1158void
1159fib_table_lock (u32 fib_index,
1160 fib_protocol_t proto)
1161{
1162 fib_table_t *fib_table;
1163
1164 fib_table = fib_table_get(fib_index, proto);
1165 fib_table->ft_locks++;
1166}
1167
1168u32
1169fib_table_get_num_entries (u32 fib_index,
1170 fib_protocol_t proto,
1171 fib_source_t source)
1172{
1173 fib_table_t *fib_table;
1174
1175 fib_table = fib_table_get(fib_index, proto);
1176
1177 return (fib_table->ft_src_route_counts[source]);
1178}
1179
1180u8*
1181format_fib_table_name (u8* s, va_list ap)
1182{
1183 fib_node_index_t fib_index = va_arg(ap, fib_node_index_t);
1184 fib_protocol_t proto = va_arg(ap, int); // int promotion
1185 fib_table_t *fib_table;
1186
1187 fib_table = fib_table_get(fib_index, proto);
1188
1189 s = format(s, "%v", fib_table->ft_desc);
1190
1191 return (s);
1192}
1193
Neale Ranns32e1c012016-11-22 17:07:28 +00001194/**
1195 * @brief Table flush context. Store the indicies of matching FIB entries
1196 * that need to be removed.
1197 */
1198typedef struct fib_table_flush_ctx_t_
1199{
1200 /**
1201 * The list of entries to flush
1202 */
1203 fib_node_index_t *ftf_entries;
1204
1205 /**
1206 * The source we are flushing
1207 */
1208 fib_source_t ftf_source;
1209} fib_table_flush_ctx_t;
1210
1211static int
1212fib_table_flush_cb (fib_node_index_t fib_entry_index,
1213 void *arg)
1214{
1215 fib_table_flush_ctx_t *ctx = arg;
1216
1217 if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1218 {
1219 vec_add1(ctx->ftf_entries, fib_entry_index);
1220 }
1221 return (1);
1222}
1223
1224
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001225void
1226fib_table_flush (u32 fib_index,
1227 fib_protocol_t proto,
1228 fib_source_t source)
1229{
Neale Ranns32e1c012016-11-22 17:07:28 +00001230 fib_node_index_t *fib_entry_index;
1231 fib_table_flush_ctx_t ctx = {
1232 .ftf_entries = NULL,
1233 .ftf_source = source,
1234 };
1235
1236 fib_table_walk(fib_index, proto,
1237 fib_table_flush_cb,
1238 &ctx);
1239
1240 vec_foreach(fib_entry_index, ctx.ftf_entries)
1241 {
Neale Rannsa8d9f302017-02-20 09:17:02 -08001242 fib_table_entry_delete_index(*fib_entry_index, source);
Neale Ranns32e1c012016-11-22 17:07:28 +00001243 }
1244
1245 vec_free(ctx.ftf_entries);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001246}