blob: a12edcb18670be385bca350cf60b024dc3fa261b [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/ip/format.h>
18#include <vnet/ip/lookup.h>
19#include <vnet/adj/adj.h>
20#include <vnet/dpo/load_balance.h>
21#include <vnet/dpo/drop_dpo.h>
22
23#include <vnet/fib/fib_entry.h>
24#include <vnet/fib/fib_walk.h>
25#include <vnet/fib/fib_entry_src.h>
26#include <vnet/fib/fib_entry_cover.h>
27#include <vnet/fib/fib_table.h>
28#include <vnet/fib/fib_internal.h>
29#include <vnet/fib/fib_attached_export.h>
30#include <vnet/fib/fib_path_ext.h>
31
32/*
33 * Array of strings/names for the FIB sources
34 */
35static const char *fib_source_names[] = FIB_SOURCES;
36static const char *fib_attribute_names[] = FIB_ENTRY_ATTRIBUTES;
Neale Ranns89541992017-04-06 04:41:02 -070037static const char *fib_src_attribute_names[] = FIB_ENTRY_SRC_ATTRIBUTES;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010038
39/*
40 * Pool for all fib_entries
41 */
42static fib_entry_t *fib_entry_pool;
43
44fib_entry_t *
45fib_entry_get (fib_node_index_t index)
46{
47 return (pool_elt_at_index(fib_entry_pool, index));
48}
49
50static fib_node_t *
51fib_entry_get_node (fib_node_index_t index)
52{
53 return ((fib_node_t*)fib_entry_get(index));
54}
55
56fib_node_index_t
57fib_entry_get_index (const fib_entry_t * fib_entry)
58{
59 return (fib_entry - fib_entry_pool);
60}
61
Neale Rannsda78f952017-05-24 09:15:43 -070062fib_protocol_t
Neale Ranns0bfe5d82016-08-25 15:29:12 +010063fib_entry_get_proto (const fib_entry_t * fib_entry)
64{
65 return (fib_entry->fe_prefix.fp_proto);
66}
67
Neale Rannsda78f952017-05-24 09:15:43 -070068dpo_proto_t
69fib_entry_get_dpo_proto (const fib_entry_t * fib_entry)
70{
71 return (fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto));
72}
73
Neale Ranns0bfe5d82016-08-25 15:29:12 +010074fib_forward_chain_type_t
75fib_entry_get_default_chain_type (const fib_entry_t *fib_entry)
76{
77 switch (fib_entry->fe_prefix.fp_proto)
78 {
79 case FIB_PROTOCOL_IP4:
80 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
81 case FIB_PROTOCOL_IP6:
82 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
83 case FIB_PROTOCOL_MPLS:
84 if (MPLS_EOS == fib_entry->fe_prefix.fp_eos)
Neale Ranns0f26c5a2017-03-01 15:12:11 -080085 return (FIB_FORW_CHAIN_TYPE_MPLS_EOS);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010086 else
87 return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
88 }
89
90 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
91}
92
93u8 *
Neale Ranns15002542017-09-10 04:39:11 -070094format_fib_source (u8 * s, va_list * args)
95{
96 fib_source_t source = va_arg (*args, int);
97
Neale Ranns2297af02017-09-12 09:45:04 -070098 s = format (s, "src:%s", fib_source_names[source]);
Neale Ranns15002542017-09-10 04:39:11 -070099
100 return (s);
101}
102
103u8 *
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100104format_fib_entry (u8 * s, va_list * args)
105{
Neale Ranns89541992017-04-06 04:41:02 -0700106 fib_entry_src_attribute_t sattr;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100107 fib_forward_chain_type_t fct;
108 fib_entry_attribute_t attr;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100109 fib_entry_t *fib_entry;
110 fib_entry_src_t *src;
111 fib_node_index_t fei;
112 fib_source_t source;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100113 int level;
114
115 fei = va_arg (*args, fib_node_index_t);
116 level = va_arg (*args, int);
117 fib_entry = fib_entry_get(fei);
118
119 s = format (s, "%U", format_fib_prefix, &fib_entry->fe_prefix);
120
Neale Rannsabcf3ea2018-03-26 09:10:41 -0700121 if (level >= FIB_ENTRY_FORMAT_DETAIL)
122 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100123 s = format (s, " fib:%d", fib_entry->fe_fib_index);
124 s = format (s, " index:%d", fib_entry_get_index(fib_entry));
125 s = format (s, " locks:%d", fib_entry->fe_node.fn_locks);
126
127 FOR_EACH_SRC_ADDED(fib_entry, src, source,
128 ({
Neale Ranns2297af02017-09-12 09:45:04 -0700129 s = format (s, "\n %U", format_fib_source, source);
Neale Ranns89541992017-04-06 04:41:02 -0700130 s = format (s, " refs:%d", src->fes_ref_count);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100131 if (FIB_ENTRY_FLAG_NONE != src->fes_entry_flags) {
Neale Ranns89541992017-04-06 04:41:02 -0700132 s = format(s, " entry-flags:");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100133 FOR_EACH_FIB_ATTRIBUTE(attr) {
134 if ((1<<attr) & src->fes_entry_flags) {
135 s = format (s, "%s,", fib_attribute_names[attr]);
136 }
137 }
138 }
Neale Ranns89541992017-04-06 04:41:02 -0700139 if (FIB_ENTRY_SRC_FLAG_NONE != src->fes_flags) {
140 s = format(s, " src-flags:");
141 FOR_EACH_FIB_SRC_ATTRIBUTE(sattr) {
142 if ((1<<sattr) & src->fes_flags) {
143 s = format (s, "%s,", fib_src_attribute_names[sattr]);
144 }
145 }
146 }
Neale Ranns2303cb12018-02-21 04:57:17 -0800147 s = fib_entry_src_format(fib_entry, source, s);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100148 s = format (s, "\n");
149 if (FIB_NODE_INDEX_INVALID != src->fes_pl)
150 {
151 s = fib_path_list_format(src->fes_pl, s);
152 }
Neale Ranns81424992017-05-18 03:03:22 -0700153 s = format(s, "%U", format_fib_path_ext_list, &src->fes_path_exts);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100154 }));
155
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100156 s = format (s, "\n forwarding: ");
Neale Rannsabcf3ea2018-03-26 09:10:41 -0700157 }
158 else
159 {
160 s = format (s, "\n");
161 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162
163 fct = fib_entry_get_default_chain_type(fib_entry);
164
Neale Rannsad422ed2016-11-02 14:20:04 +0000165 if (!dpo_id_is_valid(&fib_entry->fe_lb))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100166 {
167 s = format (s, " UNRESOLVED\n");
168 return (s);
169 }
170 else
171 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000172 s = format(s, " %U-chain\n %U",
173 format_fib_forw_chain_type, fct,
174 format_dpo_id,
175 &fib_entry->fe_lb,
176 2);
177 s = format(s, "\n");
178
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100179 if (level >= FIB_ENTRY_FORMAT_DETAIL2)
180 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000181 fib_entry_delegate_type_t fdt;
182 fib_entry_delegate_t *fed;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100183
Neale Ranns88fc83e2017-04-05 08:11:14 -0700184 s = format (s, " Delegates:\n");
185 FOR_EACH_DELEGATE(fib_entry, fdt, fed,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100186 {
Neale Ranns88fc83e2017-04-05 08:11:14 -0700187 s = format(s, " %U\n", format_fib_entry_deletegate, fed);
Neale Rannsad422ed2016-11-02 14:20:04 +0000188 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100189 }
190 }
191
192 if (level >= FIB_ENTRY_FORMAT_DETAIL2)
193 {
Neale Ranns88fc83e2017-04-05 08:11:14 -0700194 s = format(s, " Children:");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100195 s = fib_node_children_format(fib_entry->fe_node.fn_children, s);
196 }
197
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100198 return (s);
199}
200
201static fib_entry_t*
202fib_entry_from_fib_node (fib_node_t *node)
203{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100204 ASSERT(FIB_NODE_TYPE_ENTRY == node->fn_type);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100205 return ((fib_entry_t*)node);
206}
207
208static void
209fib_entry_last_lock_gone (fib_node_t *node)
210{
Neale Rannsad422ed2016-11-02 14:20:04 +0000211 fib_entry_delegate_type_t fdt;
212 fib_entry_delegate_t *fed;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100213 fib_entry_t *fib_entry;
214
215 fib_entry = fib_entry_from_fib_node(node);
216
Neale Ranns2303cb12018-02-21 04:57:17 -0800217 ASSERT(!dpo_id_is_valid(&fib_entry->fe_lb));
218
Neale Rannsad422ed2016-11-02 14:20:04 +0000219 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100220 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000221 dpo_reset(&fed->fd_dpo);
222 fib_entry_delegate_remove(fib_entry, fdt);
223 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100224
225 FIB_ENTRY_DBG(fib_entry, "last-lock");
226
227 fib_node_deinit(&fib_entry->fe_node);
Neale Rannsad422ed2016-11-02 14:20:04 +0000228
229 ASSERT(0 == vec_len(fib_entry->fe_delegates));
230 vec_free(fib_entry->fe_delegates);
Neale Rannsa4e77662017-12-04 20:00:30 +0000231 vec_free(fib_entry->fe_srcs);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100232 pool_put(fib_entry_pool, fib_entry);
233}
234
Neale Rannsa4e77662017-12-04 20:00:30 +0000235static fib_entry_src_t*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100236fib_entry_get_best_src_i (const fib_entry_t *fib_entry)
237{
Neale Rannsa4e77662017-12-04 20:00:30 +0000238 fib_entry_src_t *bsrc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100239
240 /*
241 * the enum of sources is deliberately arranged in priority order
242 */
Neale Rannsa4e77662017-12-04 20:00:30 +0000243 if (0 == vec_len(fib_entry->fe_srcs))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100244 {
Neale Rannsa4e77662017-12-04 20:00:30 +0000245 bsrc = NULL;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100246 }
247 else
248 {
Neale Rannsa4e77662017-12-04 20:00:30 +0000249 bsrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100250 }
251
252 return (bsrc);
253}
254
255static fib_source_t
256fib_entry_src_get_source (const fib_entry_src_t *esrc)
257{
258 if (NULL != esrc)
259 {
260 return (esrc->fes_src);
261 }
Neale Rannsa4e77662017-12-04 20:00:30 +0000262 return (FIB_SOURCE_MAX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100263}
264
265static fib_entry_flag_t
266fib_entry_src_get_flags (const fib_entry_src_t *esrc)
267{
268 if (NULL != esrc)
269 {
270 return (esrc->fes_entry_flags);
271 }
272 return (FIB_ENTRY_FLAG_NONE);
273}
274
275fib_entry_flag_t
276fib_entry_get_flags (fib_node_index_t fib_entry_index)
277{
278 return (fib_entry_get_flags_i(fib_entry_get(fib_entry_index)));
279}
280
281/*
282 * fib_entry_back_walk_notify
283 *
284 * A back walk has reach this entry.
285 */
286static fib_node_back_walk_rc_t
287fib_entry_back_walk_notify (fib_node_t *node,
288 fib_node_back_walk_ctx_t *ctx)
289{
290 fib_entry_t *fib_entry;
291
292 fib_entry = fib_entry_from_fib_node(node);
293
294 if (FIB_NODE_BW_REASON_FLAG_EVALUATE & ctx->fnbw_reason ||
295 FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason ||
Neale Rannsad95b5d2016-11-10 20:35:14 +0000296 FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason ||
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason ||
298 FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason ||
299 FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
300 {
301 fib_entry_src_action_reactivate(fib_entry,
302 fib_entry_get_best_source(
303 fib_entry_get_index(fib_entry)));
304 }
305
Neale Rannsb80c5362016-10-08 13:03:40 +0100306 /*
307 * all other walk types can be reclassifed to a re-evaluate to
308 * all recursive dependents.
309 * By reclassifying we ensure that should any of these walk types meet
310 * they can be merged.
311 */
312 ctx->fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100313
Neale Rannsb80c5362016-10-08 13:03:40 +0100314 /*
Neale Rannsad95b5d2016-11-10 20:35:14 +0000315 * ... and nothing is forced sync from now on.
316 */
317 ctx->fnbw_flags &= ~FIB_NODE_BW_FLAG_FORCE_SYNC;
318
319 /*
Neale Rannsb80c5362016-10-08 13:03:40 +0100320 * propagate the backwalk further if we haven't already reached the
321 * maximum depth.
322 */
323 fib_walk_sync(FIB_NODE_TYPE_ENTRY,
324 fib_entry_get_index(fib_entry),
325 ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100326
327 return (FIB_NODE_BACK_WALK_CONTINUE);
328}
329
Neale Ranns6c3ebcc2016-10-02 21:20:15 +0100330static void
331fib_entry_show_memory (void)
332{
333 u32 n_srcs = 0, n_exts = 0;
334 fib_entry_src_t *esrc;
335 fib_entry_t *entry;
336
337 fib_show_memory_usage("Entry",
338 pool_elts(fib_entry_pool),
339 pool_len(fib_entry_pool),
340 sizeof(fib_entry_t));
341
342 pool_foreach(entry, fib_entry_pool,
343 ({
Neale Rannsa4e77662017-12-04 20:00:30 +0000344 n_srcs += vec_len(entry->fe_srcs);
345 vec_foreach(esrc, entry->fe_srcs)
346 {
347 n_exts += fib_path_ext_list_length(&esrc->fes_path_exts);
348 }
Neale Ranns6c3ebcc2016-10-02 21:20:15 +0100349 }));
350
351 fib_show_memory_usage("Entry Source",
352 n_srcs, n_srcs, sizeof(fib_entry_src_t));
353 fib_show_memory_usage("Entry Path-Extensions",
354 n_exts, n_exts,
355 sizeof(fib_path_ext_t));
356}
357
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100358/*
359 * The FIB path-list's graph node virtual function table
360 */
361static const fib_node_vft_t fib_entry_vft = {
362 .fnv_get = fib_entry_get_node,
363 .fnv_last_lock = fib_entry_last_lock_gone,
364 .fnv_back_walk = fib_entry_back_walk_notify,
Neale Ranns6c3ebcc2016-10-02 21:20:15 +0100365 .fnv_mem_show = fib_entry_show_memory,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100366};
367
Neale Ranns3ee44042016-10-03 13:05:48 +0100368/**
369 * @brief Contribute the set of Adjacencies that this entry forwards with
370 * to build the uRPF list of its children
371 */
372void
373fib_entry_contribute_urpf (fib_node_index_t entry_index,
374 index_t urpf)
375{
376 fib_entry_t *fib_entry;
377
378 fib_entry = fib_entry_get(entry_index);
379
380 return (fib_path_list_contribute_urpf(fib_entry->fe_parent, urpf));
381}
382
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100383/*
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800384 * If the client is request a chain for multicast forwarding then swap
385 * the chain type to one that can provide such transport.
386 */
387static fib_forward_chain_type_t
388fib_entry_chain_type_mcast_to_ucast (fib_forward_chain_type_t fct)
389{
390 switch (fct)
391 {
392 case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
393 case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
394 /*
395 * we can only transport IP multicast packets if there is an
396 * LSP.
397 */
398 fct = FIB_FORW_CHAIN_TYPE_MPLS_EOS;
399 break;
400 case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
401 case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
402 case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
403 case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
404 case FIB_FORW_CHAIN_TYPE_ETHERNET:
405 case FIB_FORW_CHAIN_TYPE_NSH:
Neale Rannsd792d9c2017-10-21 10:53:20 -0700406 case FIB_FORW_CHAIN_TYPE_BIER:
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800407 break;
408 }
409
410 return (fct);
411}
412
413/*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100414 * fib_entry_contribute_forwarding
415 *
416 * Get an lock the forwarding information (DPO) contributed by the FIB entry.
417 */
418void
419fib_entry_contribute_forwarding (fib_node_index_t fib_entry_index,
Neale Rannsad422ed2016-11-02 14:20:04 +0000420 fib_forward_chain_type_t fct,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100421 dpo_id_t *dpo)
422{
Neale Rannsad422ed2016-11-02 14:20:04 +0000423 fib_entry_delegate_t *fed;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100424 fib_entry_t *fib_entry;
425
426 fib_entry = fib_entry_get(fib_entry_index);
427
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800428 /*
429 * mfib children ask for mcast chains. fix these to the appropriate ucast types.
430 */
431 fct = fib_entry_chain_type_mcast_to_ucast(fct);
432
Neale Rannsad422ed2016-11-02 14:20:04 +0000433 if (fct == fib_entry_get_default_chain_type(fib_entry))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100434 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000435 dpo_copy(dpo, &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100436 }
Neale Rannsad422ed2016-11-02 14:20:04 +0000437 else
438 {
439 fed = fib_entry_delegate_get(fib_entry,
440 fib_entry_chain_type_to_delegate_type(fct));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100441
Neale Rannsad422ed2016-11-02 14:20:04 +0000442 if (NULL == fed)
443 {
444 fed = fib_entry_delegate_find_or_add(
445 fib_entry,
446 fib_entry_chain_type_to_delegate_type(fct));
447 /*
448 * on-demand create eos/non-eos.
449 * There is no on-demand delete because:
450 * - memory versus complexity & reliability:
451 * leaving unrequired [n]eos LB arounds wastes memory, cleaning
452 * then up on the right trigger is more code. i favour the latter.
453 */
454 fib_entry_src_mk_lb(fib_entry,
455 fib_entry_get_best_src_i(fib_entry),
456 fct,
457 &fed->fd_dpo);
458 }
459
460 dpo_copy(dpo, &fed->fd_dpo);
461 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800462 /*
Neale Ranns2303cb12018-02-21 04:57:17 -0800463 * use the drop DPO is nothing else is present
464 */
465 if (!dpo_id_is_valid(dpo))
466 {
467 dpo_copy(dpo, drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
468 }
469
470 /*
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800471 * don't allow the special index indicating replicate.vs.load-balance
472 * to escape to the clients
473 */
474 dpo->dpoi_index &= ~MPLS_IS_REPLICATE;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100475}
476
477const dpo_id_t *
478fib_entry_contribute_ip_forwarding (fib_node_index_t fib_entry_index)
479{
Neale Rannsad422ed2016-11-02 14:20:04 +0000480 fib_forward_chain_type_t fct;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100481 fib_entry_t *fib_entry;
482
483 fib_entry = fib_entry_get(fib_entry_index);
Neale Rannsad422ed2016-11-02 14:20:04 +0000484 fct = fib_entry_get_default_chain_type(fib_entry);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100485
Neale Rannsad422ed2016-11-02 14:20:04 +0000486 ASSERT((fct == FIB_FORW_CHAIN_TYPE_UNICAST_IP4 ||
487 fct == FIB_FORW_CHAIN_TYPE_UNICAST_IP6));
488
Neale Ranns2303cb12018-02-21 04:57:17 -0800489 if (dpo_id_is_valid(&fib_entry->fe_lb))
490 {
491 return (&fib_entry->fe_lb);
492 }
493
494 return (drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100495}
496
497adj_index_t
498fib_entry_get_adj (fib_node_index_t fib_entry_index)
499{
500 const dpo_id_t *dpo;
501
502 dpo = fib_entry_contribute_ip_forwarding(fib_entry_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100503
Neale Rannsca193612017-06-14 06:50:08 -0700504 if (dpo_id_is_valid(dpo))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100505 {
Neale Rannsca193612017-06-14 06:50:08 -0700506 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
507
508 if (dpo_is_adj(dpo))
509 {
510 return (dpo->dpoi_index);
511 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100512 }
513 return (ADJ_INDEX_INVALID);
514}
515
516fib_node_index_t
517fib_entry_get_path_list (fib_node_index_t fib_entry_index)
518{
519 fib_entry_t *fib_entry;
520
521 fib_entry = fib_entry_get(fib_entry_index);
522
523 return (fib_entry->fe_parent);
524}
525
526u32
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100527fib_entry_child_add (fib_node_index_t fib_entry_index,
528 fib_node_type_t child_type,
529 fib_node_index_t child_index)
530{
531 return (fib_node_child_add(FIB_NODE_TYPE_ENTRY,
532 fib_entry_index,
533 child_type,
534 child_index));
535};
536
537void
538fib_entry_child_remove (fib_node_index_t fib_entry_index,
539 u32 sibling_index)
540{
541 fib_node_child_remove(FIB_NODE_TYPE_ENTRY,
542 fib_entry_index,
543 sibling_index);
Neale Rannsad422ed2016-11-02 14:20:04 +0000544
545 if (0 == fib_node_get_n_children(FIB_NODE_TYPE_ENTRY,
546 fib_entry_index))
547 {
548 /*
549 * if there are no children left then there is no reason to keep
550 * the non-default forwarding chains. those chains are built only
551 * because the children want them.
552 */
553 fib_entry_delegate_type_t fdt;
554 fib_entry_delegate_t *fed;
555 fib_entry_t *fib_entry;
556
557 fib_entry = fib_entry_get(fib_entry_index);
558
559 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
560 {
561 dpo_reset(&fed->fd_dpo);
562 fib_entry_delegate_remove(fib_entry, fdt);
563 });
564 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100565}
566
567static fib_entry_t *
568fib_entry_alloc (u32 fib_index,
569 const fib_prefix_t *prefix,
570 fib_node_index_t *fib_entry_index)
571{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100572 fib_entry_t *fib_entry;
Neale Rannsad422ed2016-11-02 14:20:04 +0000573 fib_prefix_t *fep;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100574
575 pool_get(fib_entry_pool, fib_entry);
576 memset(fib_entry, 0, sizeof(*fib_entry));
577
578 fib_node_init(&fib_entry->fe_node,
579 FIB_NODE_TYPE_ENTRY);
580
581 fib_entry->fe_fib_index = fib_index;
Neale Rannsad422ed2016-11-02 14:20:04 +0000582
583 /*
584 * the one time we need to update the const prefix is when
585 * the entry is first created
586 */
587 fep = (fib_prefix_t*)&(fib_entry->fe_prefix);
588 *fep = *prefix;
589
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100590 if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
591 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000592 fep->fp_len = 21;
593 if (MPLS_NON_EOS == fep->fp_eos)
594 {
595 fep->fp_payload_proto = DPO_PROTO_MPLS;
596 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100597 ASSERT(DPO_PROTO_NONE != fib_entry->fe_prefix.fp_payload_proto);
598 }
599
Neale Rannsad422ed2016-11-02 14:20:04 +0000600 dpo_reset(&fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100601
602 *fib_entry_index = fib_entry_get_index(fib_entry);
603
604 FIB_ENTRY_DBG(fib_entry, "alloc");
605
606 return (fib_entry);
607}
608
Neale Ranns08a70f12017-02-24 06:16:01 -0800609static fib_entry_t*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100610fib_entry_post_flag_update_actions (fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100611 fib_entry_flag_t old_flags)
612{
Neale Ranns08a70f12017-02-24 06:16:01 -0800613 fib_node_index_t fei;
614
615 /*
616 * save the index so we can recover from pool reallocs
617 */
618 fei = fib_entry_get_index(fib_entry);
619
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100620 /*
621 * handle changes to attached export for import entries
622 */
623 int is_import = (FIB_ENTRY_FLAG_IMPORT & fib_entry_get_flags_i(fib_entry));
624 int was_import = (FIB_ENTRY_FLAG_IMPORT & old_flags);
625
626 if (!was_import && is_import)
627 {
628 /*
629 * transition from not exported to exported
630 */
631
632 /*
633 * there is an assumption here that the entry resolves via only
634 * one interface and that it is the cross VRF interface.
635 */
636 u32 sw_if_index = fib_path_list_get_resolving_interface(fib_entry->fe_parent);
637
638 fib_attached_export_import(fib_entry,
639 fib_table_get_index_for_sw_if_index(
640 fib_entry_get_proto(fib_entry),
641 sw_if_index));
642 }
643 else if (was_import && !is_import)
644 {
645 /*
646 * transition from exported to not exported
647 */
648 fib_attached_export_purge(fib_entry);
649 }
650 /*
651 * else
652 * no change. nothing to do.
653 */
654
655 /*
Neale Ranns08a70f12017-02-24 06:16:01 -0800656 * reload the entry address post possible pool realloc
657 */
658 fib_entry = fib_entry_get(fei);
659
660 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100661 * handle changes to attached export for export entries
662 */
663 int is_attached = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(fib_entry));
664 int was_attached = (FIB_ENTRY_FLAG_ATTACHED & old_flags);
665
666 if (!was_attached && is_attached)
667 {
668 /*
669 * transition to attached. time to export
670 */
671 // FIXME
672 }
673 // else FIXME
Neale Ranns08a70f12017-02-24 06:16:01 -0800674
675 return (fib_entry);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100676}
677
678static void
679fib_entry_post_install_actions (fib_entry_t *fib_entry,
680 fib_source_t source,
681 fib_entry_flag_t old_flags)
682{
Neale Ranns08a70f12017-02-24 06:16:01 -0800683 fib_entry = fib_entry_post_flag_update_actions(fib_entry,
Neale Ranns08a70f12017-02-24 06:16:01 -0800684 old_flags);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100685 fib_entry_src_action_installed(fib_entry, source);
686}
687
688fib_node_index_t
689fib_entry_create (u32 fib_index,
690 const fib_prefix_t *prefix,
691 fib_source_t source,
692 fib_entry_flag_t flags,
693 const fib_route_path_t *paths)
694{
695 fib_node_index_t fib_entry_index;
696 fib_entry_t *fib_entry;
697
698 ASSERT(0 < vec_len(paths));
699
700 fib_entry = fib_entry_alloc(fib_index, prefix, &fib_entry_index);
701
702 /*
703 * since this is a new entry create, we don't need to check for winning
704 * sources - there is only one.
705 */
706 fib_entry = fib_entry_src_action_add(fib_entry, source, flags,
707 drop_dpo_get(
708 fib_proto_to_dpo(
709 fib_entry_get_proto(fib_entry))));
710 fib_entry_src_action_path_swap(fib_entry,
711 source,
712 flags,
713 paths);
714 /*
715 * handle possible realloc's by refetching the pointer
716 */
717 fib_entry = fib_entry_get(fib_entry_index);
718 fib_entry_src_action_activate(fib_entry, source);
719
720 fib_entry_post_install_actions(fib_entry, source, FIB_ENTRY_FLAG_NONE);
721
722 return (fib_entry_index);
723}
724
725fib_node_index_t
726fib_entry_create_special (u32 fib_index,
727 const fib_prefix_t *prefix,
728 fib_source_t source,
729 fib_entry_flag_t flags,
730 const dpo_id_t *dpo)
731{
732 fib_node_index_t fib_entry_index;
733 fib_entry_t *fib_entry;
734
735 /*
736 * create and initiliase the new enty
737 */
738 fib_entry = fib_entry_alloc(fib_index, prefix, &fib_entry_index);
739
740 /*
741 * create the path-list
742 */
743 fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
744 fib_entry_src_action_activate(fib_entry, source);
745
746 fib_entry_post_install_actions(fib_entry, source, FIB_ENTRY_FLAG_NONE);
747
748 return (fib_entry_index);
749}
750
751static void
752fib_entry_post_update_actions (fib_entry_t *fib_entry,
753 fib_source_t source,
754 fib_entry_flag_t old_flags)
755{
756 /*
757 * backwalk to children to inform then of the change to forwarding.
758 */
759 fib_node_back_walk_ctx_t bw_ctx = {
760 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
761 };
762
763 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_get_index(fib_entry), &bw_ctx);
764
765 /*
766 * then inform any covered prefixes
767 */
768 fib_entry_cover_update_notify(fib_entry);
769
770 fib_entry_post_install_actions(fib_entry, source, old_flags);
771}
772
Neale Ranns89541992017-04-06 04:41:02 -0700773void
Neale Ranns2303cb12018-02-21 04:57:17 -0800774fib_entry_recalculate_forwarding (fib_node_index_t fib_entry_index)
Neale Ranns948e00f2016-10-20 13:39:34 +0100775{
Neale Ranns2303cb12018-02-21 04:57:17 -0800776 fib_source_t best_source;
777 fib_entry_t *fib_entry;
778 fib_entry_src_t *bsrc;
Neale Ranns89541992017-04-06 04:41:02 -0700779
Neale Ranns2303cb12018-02-21 04:57:17 -0800780 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns89541992017-04-06 04:41:02 -0700781
Neale Ranns2303cb12018-02-21 04:57:17 -0800782 bsrc = fib_entry_get_best_src_i(fib_entry);
783 best_source = fib_entry_src_get_source(bsrc);
784
785 fib_entry_src_action_reactivate(fib_entry, best_source);
786}
787
788static void
789fib_entry_source_change_w_flags (fib_entry_t *fib_entry,
790 fib_source_t old_source,
791 fib_entry_flag_t old_flags,
792 fib_source_t new_source)
793{
Neale Ranns89541992017-04-06 04:41:02 -0700794 if (new_source < old_source)
Neale Ranns948e00f2016-10-20 13:39:34 +0100795 {
796 /*
797 * we have a new winning source.
798 */
Neale Ranns89541992017-04-06 04:41:02 -0700799 fib_entry_src_action_deactivate(fib_entry, old_source);
Neale Ranns948e00f2016-10-20 13:39:34 +0100800 fib_entry_src_action_activate(fib_entry, new_source);
801 }
Neale Ranns89541992017-04-06 04:41:02 -0700802 else if (new_source > old_source)
Neale Ranns948e00f2016-10-20 13:39:34 +0100803 {
Neale Ranns2303cb12018-02-21 04:57:17 -0800804 /*
805 * the new source loses. Re-activate the winning sources
806 * in case it is an interposer and hence relied on the losing
807 * source's path-list.
808 */
809 fib_entry_src_action_reactivate(fib_entry, old_source);
810 return;
Neale Ranns948e00f2016-10-20 13:39:34 +0100811 }
812 else
813 {
814 /*
815 * the new source is one this entry already has.
816 * But the path-list was updated, which will contribute new forwarding,
817 * so install it.
818 */
Neale Ranns89541992017-04-06 04:41:02 -0700819 fib_entry_src_action_reactivate(fib_entry, new_source);
Neale Ranns948e00f2016-10-20 13:39:34 +0100820 }
821
822 fib_entry_post_update_actions(fib_entry, new_source, old_flags);
823}
824
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100825void
Neale Ranns2303cb12018-02-21 04:57:17 -0800826fib_entry_source_change (fib_entry_t *fib_entry,
827 fib_source_t old_source,
828 fib_source_t new_source)
829{
830 fib_entry_flag_t old_flags;
831
832 old_flags = fib_entry_get_flags_for_source(
833 fib_entry_get_index(fib_entry), old_source);
834
835 return (fib_entry_source_change_w_flags(fib_entry, old_source,
836 old_flags, new_source));
837}
838
839void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100840fib_entry_special_add (fib_node_index_t fib_entry_index,
841 fib_source_t source,
842 fib_entry_flag_t flags,
843 const dpo_id_t *dpo)
844{
845 fib_source_t best_source;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100846 fib_entry_t *fib_entry;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100847
848 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns89541992017-04-06 04:41:02 -0700849 best_source = fib_entry_get_best_source(fib_entry_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100850
851 fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
Neale Ranns89541992017-04-06 04:41:02 -0700852 fib_entry_source_change(fib_entry, best_source, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100853}
854
855void
Neale Ranns948e00f2016-10-20 13:39:34 +0100856fib_entry_special_update (fib_node_index_t fib_entry_index,
857 fib_source_t source,
858 fib_entry_flag_t flags,
859 const dpo_id_t *dpo)
860{
861 fib_source_t best_source;
Neale Ranns948e00f2016-10-20 13:39:34 +0100862 fib_entry_t *fib_entry;
Neale Ranns948e00f2016-10-20 13:39:34 +0100863
864 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns89541992017-04-06 04:41:02 -0700865 best_source = fib_entry_get_best_source(fib_entry_index);
Neale Ranns948e00f2016-10-20 13:39:34 +0100866
867 fib_entry = fib_entry_src_action_update(fib_entry, source, flags, dpo);
Neale Ranns89541992017-04-06 04:41:02 -0700868 fib_entry_source_change(fib_entry, best_source, source);
Neale Ranns948e00f2016-10-20 13:39:34 +0100869}
870
871
872void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100873fib_entry_path_add (fib_node_index_t fib_entry_index,
874 fib_source_t source,
875 fib_entry_flag_t flags,
876 const fib_route_path_t *rpath)
877{
878 fib_source_t best_source;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100879 fib_entry_t *fib_entry;
Neale Rannsa4e77662017-12-04 20:00:30 +0000880 fib_entry_src_t *bsrc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100881
882 ASSERT(1 == vec_len(rpath));
883
884 fib_entry = fib_entry_get(fib_entry_index);
885 ASSERT(NULL != fib_entry);
886
887 bsrc = fib_entry_get_best_src_i(fib_entry);
888 best_source = fib_entry_src_get_source(bsrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100889
890 fib_entry = fib_entry_src_action_path_add(fib_entry, source, flags, rpath);
891
Neale Ranns2303cb12018-02-21 04:57:17 -0800892 fib_entry_source_change(fib_entry, best_source, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100893}
894
Neale Ranns89541992017-04-06 04:41:02 -0700895static fib_entry_src_flag_t
896fib_entry_src_burn_only_inherited (fib_entry_t *fib_entry)
897{
898 fib_entry_src_t *src;
899 fib_source_t source;
900 int has_only_inherited_sources = 1;
901
902 FOR_EACH_SRC_ADDED(fib_entry, src, source,
903 ({
904 if (!(src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
905 {
906 has_only_inherited_sources = 0;
907 break;
908 }
909 }));
910 if (has_only_inherited_sources)
911 {
912 FOR_EACH_SRC_ADDED(fib_entry, src, source,
913 ({
914 fib_entry_src_action_remove(fib_entry, source);
915 }));
916 return (FIB_ENTRY_SRC_FLAG_NONE);
917 }
918 else
919 {
920 return (FIB_ENTRY_SRC_FLAG_ADDED);
921 }
922}
923
924static fib_entry_src_flag_t
925fib_entry_source_removed (fib_entry_t *fib_entry,
926 fib_entry_flag_t old_flags)
927{
928 const fib_entry_src_t *bsrc;
929 fib_source_t best_source;
930
931 /*
932 * if all that is left are inherited sources, then burn them
933 */
934 fib_entry_src_burn_only_inherited(fib_entry);
935
936 bsrc = fib_entry_get_best_src_i(fib_entry);
937 best_source = fib_entry_src_get_source(bsrc);
938
Neale Ranns2303cb12018-02-21 04:57:17 -0800939 if (FIB_SOURCE_MAX == best_source)
940 {
Neale Ranns89541992017-04-06 04:41:02 -0700941 /*
942 * no more sources left. this entry is toast.
943 */
944 fib_entry = fib_entry_post_flag_update_actions(fib_entry, old_flags);
945 fib_entry_src_action_uninstall(fib_entry);
946
947 return (FIB_ENTRY_SRC_FLAG_NONE);
948 }
949 else
950 {
951 fib_entry_src_action_activate(fib_entry, best_source);
952 }
953
954 fib_entry_post_update_actions(fib_entry, best_source, old_flags);
955
956 /*
957 * still have sources
958 */
959 return (FIB_ENTRY_SRC_FLAG_ADDED);
960}
961
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100962/*
963 * fib_entry_path_remove
964 *
965 * remove a path from the entry.
966 * return the fib_entry's index if it is still present, INVALID otherwise.
967 */
968fib_entry_src_flag_t
969fib_entry_path_remove (fib_node_index_t fib_entry_index,
970 fib_source_t source,
971 const fib_route_path_t *rpath)
972{
973 fib_entry_src_flag_t sflag;
974 fib_source_t best_source;
975 fib_entry_flag_t bflags;
976 fib_entry_t *fib_entry;
Neale Rannsa4e77662017-12-04 20:00:30 +0000977 fib_entry_src_t *bsrc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100978
979 ASSERT(1 == vec_len(rpath));
980
981 fib_entry = fib_entry_get(fib_entry_index);
982 ASSERT(NULL != fib_entry);
983
984 bsrc = fib_entry_get_best_src_i(fib_entry);
985 best_source = fib_entry_src_get_source(bsrc);
986 bflags = fib_entry_src_get_flags(bsrc);
987
988 sflag = fib_entry_src_action_path_remove(fib_entry, source, rpath);
989
990 /*
991 * if the path list for the source passed is invalid,
992 * then we need to create a new one. else we are updating
993 * an existing.
994 */
Neale Ranns89541992017-04-06 04:41:02 -0700995 if (source < best_source)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100996 {
997 /*
998 * Que! removing a path from a source that is better than the
999 * one this entry is using.
1000 */
1001 ASSERT(0);
1002 }
1003 else if (source > best_source )
1004 {
1005 /*
Neale Ranns89541992017-04-06 04:41:02 -07001006 * the source is not the best. no need to update forwarding
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001007 */
Neale Ranns89541992017-04-06 04:41:02 -07001008 if (FIB_ENTRY_SRC_FLAG_ADDED & sflag)
1009 {
1010 /*
1011 * the source being removed still has paths
1012 */
1013 return (FIB_ENTRY_SRC_FLAG_ADDED);
1014 }
1015 else
1016 {
1017 /*
1018 * that was the last path from this source, check if those
1019 * that remain are non-inherited
1020 */
1021 return (fib_entry_src_burn_only_inherited(fib_entry));
1022 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001023 }
1024 else
1025 {
1026 /*
1027 * removing a path from the path-list we were using.
1028 */
1029 if (!(FIB_ENTRY_SRC_FLAG_ADDED & sflag))
1030 {
1031 /*
1032 * the last path from the source was removed.
1033 * fallback to lower source
1034 */
Neale Ranns89541992017-04-06 04:41:02 -07001035 return (fib_entry_source_removed(fib_entry, bflags));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001036 }
1037 else
1038 {
1039 /*
1040 * re-install the new forwarding information
1041 */
Neale Ranns89541992017-04-06 04:41:02 -07001042 fib_entry_src_action_reactivate(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001043 }
1044 }
1045
1046 fib_entry_post_update_actions(fib_entry, source, bflags);
1047
1048 /*
1049 * still have sources
1050 */
1051 return (FIB_ENTRY_SRC_FLAG_ADDED);
1052}
1053
1054/*
1055 * fib_entry_special_remove
1056 *
1057 * remove a special source from the entry.
1058 * return the fib_entry's index if it is still present, INVALID otherwise.
1059 */
1060fib_entry_src_flag_t
1061fib_entry_special_remove (fib_node_index_t fib_entry_index,
1062 fib_source_t source)
1063{
1064 fib_entry_src_flag_t sflag;
1065 fib_source_t best_source;
1066 fib_entry_flag_t bflags;
1067 fib_entry_t *fib_entry;
Neale Rannsa4e77662017-12-04 20:00:30 +00001068 fib_entry_src_t *bsrc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001069
1070 fib_entry = fib_entry_get(fib_entry_index);
1071 ASSERT(NULL != fib_entry);
1072
1073 bsrc = fib_entry_get_best_src_i(fib_entry);
1074 best_source = fib_entry_src_get_source(bsrc);
1075 bflags = fib_entry_src_get_flags(bsrc);
1076
Neale Ranns89541992017-04-06 04:41:02 -07001077 sflag = fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001078
1079 /*
1080 * if the path list for the source passed is invalid,
1081 * then we need to create a new one. else we are updating
1082 * an existing.
1083 */
1084 if (source < best_source )
1085 {
1086 /*
1087 * Que! removing a path from a source that is better than the
1088 * one this entry is using. This can only mean it is a source
1089 * this prefix does not have.
1090 */
1091 return (FIB_ENTRY_SRC_FLAG_ADDED);
1092 }
1093 else if (source > best_source ) {
1094 /*
Neale Ranns89541992017-04-06 04:41:02 -07001095 * the source is not the best. no need to update forwarding
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001096 */
Neale Ranns89541992017-04-06 04:41:02 -07001097 if (FIB_ENTRY_SRC_FLAG_ADDED & sflag)
1098 {
1099 /*
1100 * the source being removed still has paths
1101 */
1102 return (FIB_ENTRY_SRC_FLAG_ADDED);
1103 }
1104 else
1105 {
1106 /*
1107 * that was the last path from this source, check if those
1108 * that remain are non-inherited
1109 */
1110 if (FIB_ENTRY_SRC_FLAG_NONE == fib_entry_src_burn_only_inherited(fib_entry))
1111 {
1112 /*
1113 * no more sources left. this entry is toast.
1114 */
1115 fib_entry = fib_entry_post_flag_update_actions(fib_entry, bflags);
1116 fib_entry_src_action_uninstall(fib_entry);
1117 return (FIB_ENTRY_SRC_FLAG_NONE);
1118 }
Neale Ranns2303cb12018-02-21 04:57:17 -08001119
1120 /*
1121 * reactivate the best source so the interposer gets restacked
1122 */
1123 fib_entry_src_action_reactivate(fib_entry, best_source);
1124
Neale Ranns89541992017-04-06 04:41:02 -07001125 return (FIB_ENTRY_SRC_FLAG_ADDED);
1126 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001127 }
1128 else
1129 {
1130 if (!(FIB_ENTRY_SRC_FLAG_ADDED & sflag))
1131 {
1132 /*
1133 * the source was removed. use the next best.
1134 */
Neale Ranns89541992017-04-06 04:41:02 -07001135 return (fib_entry_source_removed(fib_entry, bflags));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001136 }
1137 else
1138 {
1139 /*
1140 * re-install the new forwarding information
1141 */
1142 fib_entry_src_action_reactivate(fib_entry, source);
1143 }
1144 }
1145
1146 fib_entry_post_update_actions(fib_entry, source, bflags);
1147
1148 /*
1149 * still have sources
1150 */
1151 return (FIB_ENTRY_SRC_FLAG_ADDED);
1152}
1153
1154/**
Neale Ranns89541992017-04-06 04:41:02 -07001155 * fib_entry_inherit
1156 *
1157 * If the source on the cover is inherting then push this source
1158 * down to the covered.
1159 */
1160void
1161fib_entry_inherit (fib_node_index_t cover,
1162 fib_node_index_t covered)
1163{
1164 fib_entry_src_inherit(fib_entry_get(cover),
1165 fib_entry_get(covered));
1166}
1167
1168/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001169 * fib_entry_delete
1170 *
1171 * The source is withdrawing all the paths it provided
1172 */
1173fib_entry_src_flag_t
1174fib_entry_delete (fib_node_index_t fib_entry_index,
1175 fib_source_t source)
1176{
1177 return (fib_entry_special_remove(fib_entry_index, source));
1178}
1179
1180/**
1181 * fib_entry_update
1182 *
1183 * The source has provided a new set of paths that will replace the old.
1184 */
1185void
1186fib_entry_update (fib_node_index_t fib_entry_index,
1187 fib_source_t source,
1188 fib_entry_flag_t flags,
1189 const fib_route_path_t *paths)
1190{
1191 fib_source_t best_source;
1192 fib_entry_flag_t bflags;
1193 fib_entry_t *fib_entry;
Neale Rannsa4e77662017-12-04 20:00:30 +00001194 fib_entry_src_t *bsrc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001195
1196 fib_entry = fib_entry_get(fib_entry_index);
1197 ASSERT(NULL != fib_entry);
1198
1199 bsrc = fib_entry_get_best_src_i(fib_entry);
1200 best_source = fib_entry_src_get_source(bsrc);
Neale Ranns2303cb12018-02-21 04:57:17 -08001201 bflags = fib_entry_get_flags_i(fib_entry);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001202
Neale Ranns2303cb12018-02-21 04:57:17 -08001203 fib_entry = fib_entry_src_action_path_swap(fib_entry,
1204 source,
1205 flags,
1206 paths);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001207
Neale Ranns2303cb12018-02-21 04:57:17 -08001208 fib_entry_source_change_w_flags(fib_entry, best_source, bflags, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001209}
1210
1211
1212/*
1213 * fib_entry_cover_changed
1214 *
1215 * this entry is tracking its cover and that cover has changed.
1216 */
1217void
1218fib_entry_cover_changed (fib_node_index_t fib_entry_index)
1219{
1220 fib_entry_src_cover_res_t res = {
1221 .install = !0,
1222 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
1223 };
Neale Ranns2303cb12018-02-21 04:57:17 -08001224 CLIB_UNUSED(fib_source_t source);
1225 fib_source_t best_source;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001226 fib_entry_flag_t bflags;
1227 fib_entry_t *fib_entry;
1228 fib_entry_src_t *esrc;
1229 u32 index;
1230
1231 bflags = FIB_ENTRY_FLAG_NONE;
1232 best_source = FIB_SOURCE_FIRST;
1233 fib_entry = fib_entry_get(fib_entry_index);
1234
1235 fib_attached_export_cover_change(fib_entry);
1236
1237 /*
1238 * propagate the notificuation to each of the added sources
1239 */
1240 index = 0;
1241 FOR_EACH_SRC_ADDED(fib_entry, esrc, source,
1242 ({
1243 if (0 == index)
1244 {
1245 /*
1246 * only the best source gets to set the back walk flags
1247 */
Neale Ranns2303cb12018-02-21 04:57:17 -08001248 res = fib_entry_src_action_cover_change(fib_entry, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001249 bflags = fib_entry_src_get_flags(esrc);
1250 best_source = fib_entry_src_get_source(esrc);
1251 }
1252 else
1253 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001254 fib_entry_src_action_cover_change(fib_entry, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001255 }
1256 index++;
1257 }));
1258
1259 if (res.install)
1260 {
1261 fib_entry_src_action_reactivate(fib_entry,
1262 fib_entry_src_get_source(
1263 fib_entry_get_best_src_i(fib_entry)));
1264 fib_entry_post_install_actions(fib_entry, best_source, bflags);
1265 }
1266 else
1267 {
1268 fib_entry_src_action_uninstall(fib_entry);
1269 }
1270
1271 if (FIB_NODE_BW_REASON_FLAG_NONE != res.bw_reason)
1272 {
1273 /*
1274 * time for walkies fido.
1275 */
1276 fib_node_back_walk_ctx_t bw_ctx = {
1277 .fnbw_reason = res.bw_reason,
1278 };
1279
1280 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_index, &bw_ctx);
1281 }
1282}
1283
1284/*
1285 * fib_entry_cover_updated
1286 *
1287 * this entry is tracking its cover and that cover has been updated
1288 * (i.e. its forwarding information has changed).
1289 */
1290void
1291fib_entry_cover_updated (fib_node_index_t fib_entry_index)
1292{
1293 fib_entry_src_cover_res_t res = {
1294 .install = !0,
1295 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
1296 };
Neale Ranns2303cb12018-02-21 04:57:17 -08001297 CLIB_UNUSED(fib_source_t source);
1298 fib_source_t best_source;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001299 fib_entry_flag_t bflags;
1300 fib_entry_t *fib_entry;
1301 fib_entry_src_t *esrc;
1302 u32 index;
1303
1304 bflags = FIB_ENTRY_FLAG_NONE;
1305 best_source = FIB_SOURCE_FIRST;
1306 fib_entry = fib_entry_get(fib_entry_index);
1307
1308 fib_attached_export_cover_update(fib_entry);
1309
1310 /*
1311 * propagate the notificuation to each of the added sources
1312 */
1313 index = 0;
1314 FOR_EACH_SRC_ADDED(fib_entry, esrc, source,
1315 ({
1316 if (0 == index)
1317 {
1318 /*
1319 * only the best source gets to set the back walk flags
1320 */
Neale Ranns2303cb12018-02-21 04:57:17 -08001321 res = fib_entry_src_action_cover_update(fib_entry, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001322 bflags = fib_entry_src_get_flags(esrc);
1323 best_source = fib_entry_src_get_source(esrc);
1324 }
1325 else
1326 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001327 fib_entry_src_action_cover_update(fib_entry, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001328 }
1329 index++;
1330 }));
1331
1332 if (res.install)
1333 {
1334 fib_entry_src_action_reactivate(fib_entry,
1335 fib_entry_src_get_source(
1336 fib_entry_get_best_src_i(fib_entry)));
1337 fib_entry_post_install_actions(fib_entry, best_source, bflags);
1338 }
1339 else
1340 {
1341 fib_entry_src_action_uninstall(fib_entry);
1342 }
1343
1344 if (FIB_NODE_BW_REASON_FLAG_NONE != res.bw_reason)
1345 {
1346 /*
1347 * time for walkies fido.
1348 */
1349 fib_node_back_walk_ctx_t bw_ctx = {
1350 .fnbw_reason = res.bw_reason,
1351 };
1352
1353 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_index, &bw_ctx);
1354 }
1355}
1356
1357int
1358fib_entry_recursive_loop_detect (fib_node_index_t entry_index,
1359 fib_node_index_t **entry_indicies)
1360{
1361 fib_entry_t *fib_entry;
1362 int was_looped, is_looped;
1363
1364 fib_entry = fib_entry_get(entry_index);
1365
1366 if (FIB_NODE_INDEX_INVALID != fib_entry->fe_parent)
1367 {
1368 fib_node_index_t *entries = *entry_indicies;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001369
1370 vec_add1(entries, entry_index);
1371 was_looped = fib_path_list_is_looped(fib_entry->fe_parent);
1372 is_looped = fib_path_list_recursive_loop_detect(fib_entry->fe_parent,
1373 &entries);
1374
1375 *entry_indicies = entries;
1376
1377 if (!!was_looped != !!is_looped)
1378 {
1379 /*
1380 * re-evaluate all the entry's forwarding
1381 * NOTE: this is an inplace modify
1382 */
Neale Rannsad422ed2016-11-02 14:20:04 +00001383 fib_entry_delegate_type_t fdt;
1384 fib_entry_delegate_t *fed;
1385
1386 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
1387 {
1388 fib_entry_src_mk_lb(fib_entry,
1389 fib_entry_get_best_src_i(fib_entry),
1390 fib_entry_delegate_type_to_chain_type(fdt),
1391 &fed->fd_dpo);
1392 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001393 }
1394 }
1395 else
1396 {
1397 /*
1398 * the entry is currently not linked to a path-list. this happens
1399 * when it is this entry that is re-linking path-lists and has thus
1400 * broken the loop
1401 */
1402 is_looped = 0;
1403 }
1404
1405 return (is_looped);
1406}
1407
1408u32
1409fib_entry_get_resolving_interface (fib_node_index_t entry_index)
1410{
Neale Rannsdf089a82016-10-02 16:39:06 +01001411 fib_entry_t *fib_entry;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001412
1413 fib_entry = fib_entry_get(entry_index);
1414
1415 return (fib_path_list_get_resolving_interface(fib_entry->fe_parent));
1416}
1417
1418fib_source_t
1419fib_entry_get_best_source (fib_node_index_t entry_index)
1420{
1421 fib_entry_t *fib_entry;
Neale Rannsa4e77662017-12-04 20:00:30 +00001422 fib_entry_src_t *bsrc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001423
1424 fib_entry = fib_entry_get(entry_index);
1425
1426 bsrc = fib_entry_get_best_src_i(fib_entry);
1427 return (fib_entry_src_get_source(bsrc));
1428}
1429
Neale Ranns88fc83e2017-04-05 08:11:14 -07001430/**
Neale Ranns56f949b2018-04-25 01:41:24 -07001431 * Return !0 is the entry represents a host prefix
1432 */
1433int
1434fib_entry_is_host (fib_node_index_t fib_entry_index)
1435{
1436 fib_prefix_t pfx;
1437
1438 fib_entry_get_prefix(fib_entry_index, &pfx);
1439
1440 return (fib_prefix_is_host(&pfx));
1441}
1442
1443/**
Neale Ranns88fc83e2017-04-05 08:11:14 -07001444 * Return !0 is the entry is reoslved, i.e. will return a valid forwarding
1445 * chain
1446 */
1447int
1448fib_entry_is_resolved (fib_node_index_t fib_entry_index)
1449{
1450 fib_entry_delegate_t *fed;
1451 fib_entry_t *fib_entry;
1452
1453 fib_entry = fib_entry_get(fib_entry_index);
1454
1455 fed = fib_entry_delegate_get(fib_entry, FIB_ENTRY_DELEGATE_BFD);
1456
1457 if (NULL == fed)
1458 {
1459 /*
Neale Ranns57b58602017-07-15 07:37:25 -07001460 * no BFD tracking - consider it resolved.
Neale Ranns88fc83e2017-04-05 08:11:14 -07001461 */
1462 return (!0);
1463 }
1464 else
1465 {
1466 /*
1467 * defer to the state of the BFD tracking
1468 */
1469 return (FIB_BFD_STATE_UP == fed->fd_bfd_state);
1470 }
1471}
1472
Neale Ranns227038a2017-04-21 01:07:59 -07001473void
1474fib_entry_set_flow_hash_config (fib_node_index_t fib_entry_index,
1475 flow_hash_config_t hash_config)
1476{
1477 fib_entry_t *fib_entry;
1478
1479 fib_entry = fib_entry_get(fib_entry_index);
1480
1481 /*
1482 * pass the hash-config on to the load-balance object where it is cached.
1483 * we can ignore LBs in the delegate chains, since they will not be of the
1484 * correct protocol type (i.e. they are not IP)
1485 * There's no way, nor need, to change the hash config for MPLS.
1486 */
1487 if (dpo_id_is_valid(&fib_entry->fe_lb))
1488 {
1489 load_balance_t *lb;
1490
1491 ASSERT(DPO_LOAD_BALANCE == fib_entry->fe_lb.dpoi_type);
1492
1493 lb = load_balance_get(fib_entry->fe_lb.dpoi_index);
1494
1495 /*
1496 * atomic update for packets in flight
1497 */
1498 lb->lb_hash_config = hash_config;
1499 }
1500}
1501
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001502static int
Neale Rannsad422ed2016-11-02 14:20:04 +00001503fib_ip4_address_compare (const ip4_address_t * a1,
1504 const ip4_address_t * a2)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001505{
1506 /*
1507 * IP addresses are unsiged ints. the return value here needs to be signed
1508 * a simple subtraction won't cut it.
1509 * If the addresses are the same, the sort order is undefiend, so phoey.
1510 */
1511 return ((clib_net_to_host_u32(a1->data_u32) >
1512 clib_net_to_host_u32(a2->data_u32) ) ?
1513 1 : -1);
1514}
1515
1516static int
Neale Rannsad422ed2016-11-02 14:20:04 +00001517fib_ip6_address_compare (const ip6_address_t * a1,
1518 const ip6_address_t * a2)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001519{
1520 int i;
1521 for (i = 0; i < ARRAY_LEN (a1->as_u16); i++)
1522 {
1523 int cmp = (clib_net_to_host_u16 (a1->as_u16[i]) -
1524 clib_net_to_host_u16 (a2->as_u16[i]));
1525 if (cmp != 0)
1526 return cmp;
1527 }
1528 return 0;
1529}
1530
1531static int
1532fib_entry_cmp (fib_node_index_t fib_entry_index1,
1533 fib_node_index_t fib_entry_index2)
1534{
1535 fib_entry_t *fib_entry1, *fib_entry2;
1536 int cmp = 0;
1537
1538 fib_entry1 = fib_entry_get(fib_entry_index1);
1539 fib_entry2 = fib_entry_get(fib_entry_index2);
1540
1541 switch (fib_entry1->fe_prefix.fp_proto)
1542 {
1543 case FIB_PROTOCOL_IP4:
1544 cmp = fib_ip4_address_compare(&fib_entry1->fe_prefix.fp_addr.ip4,
1545 &fib_entry2->fe_prefix.fp_addr.ip4);
1546 break;
1547 case FIB_PROTOCOL_IP6:
1548 cmp = fib_ip6_address_compare(&fib_entry1->fe_prefix.fp_addr.ip6,
1549 &fib_entry2->fe_prefix.fp_addr.ip6);
1550 break;
1551 case FIB_PROTOCOL_MPLS:
1552 cmp = (fib_entry1->fe_prefix.fp_label - fib_entry2->fe_prefix.fp_label);
1553
1554 if (0 == cmp)
1555 {
1556 cmp = (fib_entry1->fe_prefix.fp_eos - fib_entry2->fe_prefix.fp_eos);
1557 }
1558 break;
1559 }
1560
1561 if (0 == cmp) {
1562 cmp = (fib_entry1->fe_prefix.fp_len - fib_entry2->fe_prefix.fp_len);
1563 }
1564 return (cmp);
1565}
1566
1567int
1568fib_entry_cmp_for_sort (void *i1, void *i2)
1569{
1570 fib_node_index_t *fib_entry_index1 = i1, *fib_entry_index2 = i2;
1571
1572 return (fib_entry_cmp(*fib_entry_index1,
1573 *fib_entry_index2));
1574}
1575
1576void
1577fib_entry_lock (fib_node_index_t fib_entry_index)
1578{
1579 fib_entry_t *fib_entry;
1580
1581 fib_entry = fib_entry_get(fib_entry_index);
1582
1583 fib_node_lock(&fib_entry->fe_node);
1584}
1585
1586void
1587fib_entry_unlock (fib_node_index_t fib_entry_index)
1588{
1589 fib_entry_t *fib_entry;
1590
1591 fib_entry = fib_entry_get(fib_entry_index);
1592
1593 fib_node_unlock(&fib_entry->fe_node);
1594}
1595
1596void
1597fib_entry_module_init (void)
1598{
1599 fib_node_register_type (FIB_NODE_TYPE_ENTRY, &fib_entry_vft);
1600}
1601
1602void
Steven01b07122016-11-02 10:40:09 -07001603fib_entry_encode (fib_node_index_t fib_entry_index,
1604 fib_route_path_encode_t **api_rpaths)
1605{
1606 fib_entry_t *fib_entry;
1607
1608 fib_entry = fib_entry_get(fib_entry_index);
Neale Rannsa8d9f302017-02-20 09:17:02 -08001609 if (FIB_NODE_INDEX_INVALID != fib_entry->fe_parent)
1610 {
1611 fib_path_list_walk(fib_entry->fe_parent, fib_path_encode, api_rpaths);
1612 }
Steven01b07122016-11-02 10:40:09 -07001613}
1614
1615void
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001616fib_entry_get_prefix (fib_node_index_t fib_entry_index,
1617 fib_prefix_t *pfx)
1618{
1619 fib_entry_t *fib_entry;
1620
1621 fib_entry = fib_entry_get(fib_entry_index);
1622 *pfx = fib_entry->fe_prefix;
1623}
1624
1625u32
1626fib_entry_get_fib_index (fib_node_index_t fib_entry_index)
1627{
1628 fib_entry_t *fib_entry;
1629
1630 fib_entry = fib_entry_get(fib_entry_index);
1631
1632 return (fib_entry->fe_fib_index);
1633}
1634
1635u32
1636fib_entry_pool_size (void)
1637{
1638 return (pool_elts(fib_entry_pool));
1639}
1640
1641static clib_error_t *
1642show_fib_entry_command (vlib_main_t * vm,
1643 unformat_input_t * input,
1644 vlib_cli_command_t * cmd)
1645{
1646 fib_node_index_t fei;
1647
1648 if (unformat (input, "%d", &fei))
1649 {
1650 /*
1651 * show one in detail
1652 */
1653 if (!pool_is_free_index(fib_entry_pool, fei))
1654 {
1655 vlib_cli_output (vm, "%d@%U",
1656 fei,
1657 format_fib_entry, fei,
1658 FIB_ENTRY_FORMAT_DETAIL2);
1659 }
1660 else
1661 {
1662 vlib_cli_output (vm, "entry %d invalid", fei);
1663 }
1664 }
1665 else
1666 {
1667 /*
1668 * show all
1669 */
1670 vlib_cli_output (vm, "FIB Entries:");
1671 pool_foreach_index(fei, fib_entry_pool,
1672 ({
1673 vlib_cli_output (vm, "%d@%U",
1674 fei,
1675 format_fib_entry, fei,
1676 FIB_ENTRY_FORMAT_BRIEF);
1677 }));
1678 }
1679
1680 return (NULL);
1681}
1682
1683VLIB_CLI_COMMAND (show_fib_entry, static) = {
1684 .path = "show fib entry",
1685 .function = show_fib_entry_command,
1686 .short_help = "show fib entry",
1687};