blob: 6ed13a328bdde33dd3425dd2e733afcc81d77008 [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 <vnet/adj/adj.h>
17#include <vnet/dpo/load_balance.h>
18#include <vnet/dpo/mpls_label_dpo.h>
19#include <vnet/dpo/drop_dpo.h>
Neale Ranns0f26c5a2017-03-01 15:12:11 -080020#include <vnet/dpo/replicate_dpo.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010021
Neale Ranns3ee44042016-10-03 13:05:48 +010022#include <vnet/fib/fib_entry_src.h>
23#include <vnet/fib/fib_table.h>
24#include <vnet/fib/fib_path_ext.h>
25#include <vnet/fib/fib_urpf_list.h>
Neale Ranns1f50bf82019-07-16 15:28:52 +000026#include <vnet/fib/fib_entry_delegate.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010027
28/*
29 * per-source type vft
30 */
31static fib_entry_src_vft_t fib_entry_src_vft[FIB_SOURCE_MAX];
32
Neale Ranns2303cb12018-02-21 04:57:17 -080033/**
34 * Get the VFT for a given source. This is a combination of the source
35 * enum and the interposer flags
36 */
37const fib_entry_src_vft_t*
38fib_entry_src_get_vft (const fib_entry_src_t *esrc)
39{
40 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE)
41 {
42 return (&fib_entry_src_vft[FIB_SOURCE_INTERPOSE]);
43 }
44
45 return (&fib_entry_src_vft[esrc->fes_src]);
46}
47
48static void
49fib_entry_src_copy_default (const fib_entry_src_t *orig_src,
50 const fib_entry_t *fib_entry,
51 fib_entry_src_t *copy_src)
52{
53 clib_memcpy(&copy_src->u, &orig_src->u, sizeof(copy_src->u));
54}
55
Neale Ranns0bfe5d82016-08-25 15:29:12 +010056void
57fib_entry_src_register (fib_source_t source,
58 const fib_entry_src_vft_t *vft)
59{
60 fib_entry_src_vft[source] = *vft;
Neale Ranns2303cb12018-02-21 04:57:17 -080061
62 if (NULL == fib_entry_src_vft[source].fesv_copy)
63 {
64 fib_entry_src_vft[source].fesv_copy = fib_entry_src_copy_default;
65 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +010066}
67
68static int
69fib_entry_src_cmp_for_sort (void * v1,
70 void * v2)
71{
72 fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
73
74 return (esrc1->fes_src - esrc2->fes_src);
75}
76
Neale Ranns2303cb12018-02-21 04:57:17 -080077static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +010078fib_entry_src_action_init (fib_entry_t *fib_entry,
Neale Ranns2303cb12018-02-21 04:57:17 -080079 fib_source_t source,
80 fib_entry_flag_t flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010081{
82 fib_entry_src_t esrc = {
83 .fes_pl = FIB_NODE_INDEX_INVALID,
84 .fes_flags = FIB_ENTRY_SRC_FLAG_NONE,
85 .fes_src = source,
Neale Ranns2303cb12018-02-21 04:57:17 -080086 .fes_entry_flags = flags,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010087 };
88
Neale Ranns2303cb12018-02-21 04:57:17 -080089 FIB_ENTRY_SRC_VFT_INVOKE(&esrc, fesv_init, (&esrc));
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090
Neale Rannsa4e77662017-12-04 20:00:30 +000091 vec_add1(fib_entry->fe_srcs, esrc);
92 vec_sort_with_function(fib_entry->fe_srcs,
93 fib_entry_src_cmp_for_sort);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010094}
95
96static fib_entry_src_t *
Neale Ranns2303cb12018-02-21 04:57:17 -080097fib_entry_src_find_i (const fib_entry_t *fib_entry,
98 fib_source_t source,
99 u32 *index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100100
101{
102 fib_entry_src_t *esrc;
103 int ii;
104
105 ii = 0;
Neale Rannsa4e77662017-12-04 20:00:30 +0000106 vec_foreach(esrc, fib_entry->fe_srcs)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100107 {
Neale Rannsa4e77662017-12-04 20:00:30 +0000108 if (esrc->fes_src == source)
109 {
110 if (NULL != index)
111 {
112 *index = ii;
113 }
114 return (esrc);
115 }
116 else
117 {
118 ii++;
119 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100120 }
121
122 return (NULL);
123}
124
Neale Ranns2303cb12018-02-21 04:57:17 -0800125static fib_entry_src_t *
126fib_entry_src_find (const fib_entry_t *fib_entry,
127 fib_source_t source)
128
129{
130 return (fib_entry_src_find_i(fib_entry, source, NULL));
131}
132
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100133int
134fib_entry_is_sourced (fib_node_index_t fib_entry_index,
135 fib_source_t source)
136{
137 fib_entry_t *fib_entry;
138
139 fib_entry = fib_entry_get(fib_entry_index);
140
Neale Ranns2303cb12018-02-21 04:57:17 -0800141 return (NULL != fib_entry_src_find(fib_entry, source));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100142}
143
144static fib_entry_src_t *
145fib_entry_src_find_or_create (fib_entry_t *fib_entry,
Neale Ranns2303cb12018-02-21 04:57:17 -0800146 fib_source_t source,
147 fib_entry_flag_t flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100148{
149 fib_entry_src_t *esrc;
150
Neale Ranns2303cb12018-02-21 04:57:17 -0800151 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100152
153 if (NULL == esrc)
154 {
Neale Ranns2303cb12018-02-21 04:57:17 -0800155 fib_entry_src_action_init(fib_entry, source, flags);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100156 }
157
Neale Ranns2303cb12018-02-21 04:57:17 -0800158 return (fib_entry_src_find(fib_entry, source));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100159}
160
Neale Ranns2303cb12018-02-21 04:57:17 -0800161static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162fib_entry_src_action_deinit (fib_entry_t *fib_entry,
163 fib_source_t source)
164
165{
166 fib_entry_src_t *esrc;
167 u32 index = ~0;
168
Neale Ranns2303cb12018-02-21 04:57:17 -0800169 esrc = fib_entry_src_find_i(fib_entry, source, &index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100170
171 ASSERT(NULL != esrc);
172
Neale Ranns2303cb12018-02-21 04:57:17 -0800173 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_deinit, (esrc));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100174
Neale Ranns81424992017-05-18 03:03:22 -0700175 fib_path_ext_list_flush(&esrc->fes_path_exts);
Neale Rannsa4e77662017-12-04 20:00:30 +0000176 vec_del1(fib_entry->fe_srcs, index);
Neale Ranns75b39f82018-10-26 04:17:54 -0700177 vec_sort_with_function(fib_entry->fe_srcs,
178 fib_entry_src_cmp_for_sort);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100179}
180
181fib_entry_src_cover_res_t
182fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
Neale Ranns2303cb12018-02-21 04:57:17 -0800183 fib_entry_src_t *esrc)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100184{
Neale Ranns2303cb12018-02-21 04:57:17 -0800185 FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_cover_change,
186 (esrc, fib_entry));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100187
188 fib_entry_src_cover_res_t res = {
189 .install = !0,
190 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
191 };
192 return (res);
193}
194
195fib_entry_src_cover_res_t
196fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
Neale Ranns2303cb12018-02-21 04:57:17 -0800197 fib_entry_src_t *esrc)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100198{
Neale Ranns2303cb12018-02-21 04:57:17 -0800199 FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_cover_update,
200 (esrc, fib_entry));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100201
202 fib_entry_src_cover_res_t res = {
203 .install = !0,
204 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
205 };
206 return (res);
207}
208
209typedef struct fib_entry_src_collect_forwarding_ctx_t_
210{
Neale Ranns81424992017-05-18 03:03:22 -0700211 load_balance_path_t *next_hops;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100212 const fib_entry_t *fib_entry;
213 const fib_entry_src_t *esrc;
214 fib_forward_chain_type_t fct;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700215 int n_recursive_constrained;
Neale Ranns57b58602017-07-15 07:37:25 -0700216 u16 preference;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100217} fib_entry_src_collect_forwarding_ctx_t;
218
219/**
220 * @brief Determine whether this FIB entry should use a load-balance MAP
221 * to support PIC edge fast convergence
222 */
223load_balance_flags_t
224fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx)
225{
226 /**
Neale Rannsf12a83f2017-04-18 09:09:40 -0700227 * We'll use a LB map if the path-list has multiple recursive paths.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100228 * recursive paths implies BGP, and hence scale.
229 */
Neale Rannsf12a83f2017-04-18 09:09:40 -0700230 if (ctx->n_recursive_constrained > 1 &&
231 fib_path_list_is_popular(ctx->esrc->fes_pl))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100232 {
233 return (LOAD_BALANCE_FLAG_USES_MAP);
234 }
235 return (LOAD_BALANCE_FLAG_NONE);
236}
237
238static int
239fib_entry_src_valid_out_label (mpls_label_t label)
240{
241 return ((MPLS_LABEL_IS_REAL(label) ||
Neale Ranns31ed7442018-02-23 05:29:09 -0800242 MPLS_LABEL_POP == label ||
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100243 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
244 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
245 MPLS_IETF_IMPLICIT_NULL_LABEL == label));
246}
247
Neale Rannsad422ed2016-11-02 14:20:04 +0000248/**
249 * @brief Turn the chain type requested by the client into the one they
250 * really wanted
251 */
252fib_forward_chain_type_t
253fib_entry_chain_type_fixup (const fib_entry_t *entry,
254 fib_forward_chain_type_t fct)
255{
Neale Rannsad422ed2016-11-02 14:20:04 +0000256 /*
257 * The EOS chain is a tricky since one cannot know the adjacency
258 * to link to without knowing what the packets payload protocol
259 * will be once the label is popped.
260 */
261 fib_forward_chain_type_t dfct;
262
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800263 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
264 {
265 return (fct);
266 }
267
Neale Rannsad422ed2016-11-02 14:20:04 +0000268 dfct = fib_entry_get_default_chain_type(entry);
269
270 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
271 {
272 /*
273 * If the entry being asked is a eos-MPLS label entry,
274 * then use the payload-protocol field, that we stashed there
275 * for just this purpose
276 */
277 return (fib_forw_chain_type_from_dpo_proto(
278 entry->fe_prefix.fp_payload_proto));
279 }
280 /*
281 * else give them what this entry would be by default. i.e. if it's a v6
282 * entry, then the label its local labelled should be carrying v6 traffic.
283 * If it's a non-EOS label entry, then there are more labels and we want
284 * a non-eos chain.
285 */
286 return (dfct);
287}
288
Neale Ranns62fe07c2017-10-31 12:28:22 -0700289static dpo_proto_t
290fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
291{
292 switch (pfx->fp_proto)
293 {
294 case FIB_PROTOCOL_IP4:
295 return (DPO_PROTO_IP4);
296 case FIB_PROTOCOL_IP6:
297 return (DPO_PROTO_IP6);
298 case FIB_PROTOCOL_MPLS:
299 return (pfx->fp_payload_proto);
300 }
301
302 ASSERT(0);
303 return (DPO_PROTO_IP4);
304}
305
Neale Ranns81424992017-05-18 03:03:22 -0700306static void
307fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
308 fib_entry_src_collect_forwarding_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100309{
Neale Ranns81424992017-05-18 03:03:22 -0700310 load_balance_path_t *nh;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100311
312 /*
Neale Ranns81424992017-05-18 03:03:22 -0700313 * no extension => no out-going label for this path. that's OK
314 * in the case of an IP or EOS chain, but not for non-EOS
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100315 */
Neale Ranns81424992017-05-18 03:03:22 -0700316 switch (ctx->fct)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100317 {
Neale Ranns81424992017-05-18 03:03:22 -0700318 case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
319 case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
320 case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
321 case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
Neale Rannsd792d9c2017-10-21 10:53:20 -0700322 case FIB_FORW_CHAIN_TYPE_BIER:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100323 /*
Neale Ranns81424992017-05-18 03:03:22 -0700324 * EOS traffic with no label to stack, we need the IP Adj
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100325 */
Neale Ranns81424992017-05-18 03:03:22 -0700326 vec_add2(ctx->next_hops, nh, 1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100327
Neale Ranns81424992017-05-18 03:03:22 -0700328 nh->path_index = path_index;
329 nh->path_weight = fib_path_get_weight(path_index);
330 fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
331
332 break;
333 case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
334 if (fib_path_is_exclusive(path_index) ||
335 fib_path_is_deag(path_index))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100336 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100337 vec_add2(ctx->next_hops, nh, 1);
338
339 nh->path_index = path_index;
340 nh->path_weight = fib_path_get_weight(path_index);
Neale Ranns81424992017-05-18 03:03:22 -0700341 fib_path_contribute_forwarding(path_index,
342 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
343 &nh->path_dpo);
344 }
345 break;
346 case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
Neale Rannsad422ed2016-11-02 14:20:04 +0000347 {
348 /*
349 * no label. we need a chain based on the payload. fixup.
350 */
351 vec_add2(ctx->next_hops, nh, 1);
352
353 nh->path_index = path_index;
354 nh->path_weight = fib_path_get_weight(path_index);
355 fib_path_contribute_forwarding(path_index,
356 fib_entry_chain_type_fixup(ctx->fib_entry,
357 ctx->fct),
358 &nh->path_dpo);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800359 fib_path_stack_mpls_disp(path_index,
Neale Ranns62fe07c2017-10-31 12:28:22 -0700360 fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
Neale Ranns31ed7442018-02-23 05:29:09 -0800361 FIB_MPLS_LSP_MODE_PIPE,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800362 &nh->path_dpo);
Neale Rannsad422ed2016-11-02 14:20:04 +0000363
364 break;
365 }
Neale Ranns81424992017-05-18 03:03:22 -0700366 case FIB_FORW_CHAIN_TYPE_ETHERNET:
367 case FIB_FORW_CHAIN_TYPE_NSH:
368 ASSERT(0);
369 break;
370 }
371}
372
373static fib_path_list_walk_rc_t
374fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
375 fib_node_index_t path_index,
376 void *arg)
377{
378 fib_entry_src_collect_forwarding_ctx_t *ctx;
379 fib_path_ext_t *path_ext;
Neale Ranns2303cb12018-02-21 04:57:17 -0800380 u32 n_nhs;
Neale Ranns81424992017-05-18 03:03:22 -0700381
382 ctx = arg;
Neale Ranns2303cb12018-02-21 04:57:17 -0800383 n_nhs = vec_len(ctx->next_hops);
Neale Ranns81424992017-05-18 03:03:22 -0700384
385 /*
386 * if the path is not resolved, don't include it.
387 */
388 if (!fib_path_is_resolved(path_index))
389 {
390 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100391 }
392
Neale Ranns81424992017-05-18 03:03:22 -0700393 if (fib_path_is_recursive_constrained(path_index))
394 {
395 ctx->n_recursive_constrained += 1;
396 }
Neale Ranns57b58602017-07-15 07:37:25 -0700397 if (0xffff == ctx->preference)
398 {
399 /*
400 * not set a preference yet, so the first path we encounter
401 * sets the preference we are collecting.
402 */
403 ctx->preference = fib_path_get_preference(path_index);
404 }
405 else if (ctx->preference != fib_path_get_preference(path_index))
406 {
407 /*
408 * this path does not belong to the same preference as the
409 * previous paths encountered. we are done now.
410 */
411 return (FIB_PATH_LIST_WALK_STOP);
412 }
Neale Ranns81424992017-05-18 03:03:22 -0700413
414 /*
415 * get the matching path-extension for the path being visited.
416 */
417 path_ext = fib_path_ext_list_find_by_path_index(&ctx->esrc->fes_path_exts,
418 path_index);
419
420 if (NULL != path_ext)
421 {
422 switch (path_ext->fpe_type)
423 {
424 case FIB_PATH_EXT_MPLS:
Neale Ranns31ed7442018-02-23 05:29:09 -0800425 if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0].fml_value))
Neale Ranns81424992017-05-18 03:03:22 -0700426 {
427 /*
428 * found a matching extension. stack it to obtain the forwarding
429 * info for this path.
430 */
431 ctx->next_hops =
432 fib_path_ext_stack(path_ext,
433 ctx->fct,
434 fib_entry_chain_type_fixup(ctx->fib_entry,
435 ctx->fct),
436 ctx->next_hops);
437 }
438 else
439 {
440 fib_entry_src_get_path_forwarding(path_index, ctx);
441 }
442 break;
443 case FIB_PATH_EXT_ADJ:
444 if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
445 {
446 fib_entry_src_get_path_forwarding(path_index, ctx);
447 }
448 /*
449 * else
450 * the path does not refine the cover, meaning that
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700451 * the adjacency does/does not match the sub-net on the link.
Neale Ranns81424992017-05-18 03:03:22 -0700452 * So this path does not contribute forwarding.
453 */
454 break;
455 }
456 }
457 else
458 {
459 fib_entry_src_get_path_forwarding(path_index, ctx);
460 }
461
Neale Ranns2303cb12018-02-21 04:57:17 -0800462 /*
463 * a this point 'ctx' has the DPO the path contributed, plus
464 * any labels from path extensions.
465 * check if there are any interpose sources that want to contribute
466 */
467 if (n_nhs < vec_len(ctx->next_hops))
468 {
469 /*
470 * the path contributed a new choice.
471 */
472 const fib_entry_src_vft_t *vft;
473
474 vft = fib_entry_src_get_vft(ctx->esrc);
475
476 if (NULL != vft->fesv_contribute_interpose)
477 {
478 const dpo_id_t *interposer;
479
480 interposer = vft->fesv_contribute_interpose(ctx->esrc,
481 ctx->fib_entry);
482
483 if (NULL != interposer)
484 {
485 dpo_id_t clone = DPO_INVALID;
486
487 dpo_mk_interpose(interposer,
488 &ctx->next_hops[n_nhs].path_dpo,
489 &clone);
490
491 dpo_copy(&ctx->next_hops[n_nhs].path_dpo, &clone);
492 dpo_reset(&clone);
493 }
494 }
495 }
496
Neale Ranns81424992017-05-18 03:03:22 -0700497 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100498}
499
500void
501fib_entry_src_mk_lb (fib_entry_t *fib_entry,
502 const fib_entry_src_t *esrc,
503 fib_forward_chain_type_t fct,
504 dpo_id_t *dpo_lb)
505{
506 dpo_proto_t lb_proto;
507
508 /*
509 * If the entry has path extensions then we construct a load-balance
510 * by stacking the extensions on the forwarding chains of the paths.
511 * Otherwise we use the load-balance of the path-list
512 */
513 fib_entry_src_collect_forwarding_ctx_t ctx = {
514 .esrc = esrc,
515 .fib_entry = fib_entry,
516 .next_hops = NULL,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700517 .n_recursive_constrained = 0,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100518 .fct = fct,
Neale Ranns57b58602017-07-15 07:37:25 -0700519 .preference = 0xffff,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100520 };
521
Neale Rannsc0790cf2017-01-05 01:01:47 -0800522 /*
523 * As an optimisation we allocate the vector of next-hops to be sized
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700524 * equal to the maximum number of paths we will need, which is also the
Neale Rannsc0790cf2017-01-05 01:01:47 -0800525 * most likely number we will need, since in most cases the paths are 'up'.
526 */
527 vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
528 vec_reset_length(ctx.next_hops);
529
Neale Rannsf12a83f2017-04-18 09:09:40 -0700530 lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100531
532 fib_path_list_walk(esrc->fes_pl,
533 fib_entry_src_collect_forwarding,
534 &ctx);
535
536 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
537 {
538 /*
539 * the client provided the DPO that the entry should link to.
540 * all entries must link to a LB, so if it is an LB already
541 * then we can use it.
542 */
543 if ((1 == vec_len(ctx.next_hops)) &&
544 (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
545 {
546 dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
547 dpo_reset(&ctx.next_hops[0].path_dpo);
548 return;
549 }
550 }
551
552 if (!dpo_id_is_valid(dpo_lb))
553 {
554 /*
555 * first time create
556 */
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800557 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
558 {
559 dpo_set(dpo_lb,
560 DPO_REPLICATE,
561 lb_proto,
562 MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
563 }
564 else
565 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700566 fib_protocol_t flow_hash_proto;
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800567 flow_hash_config_t fhc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100568
Neale Ranns41da54f2017-05-02 10:15:19 -0700569 /*
570 * if the protocol for the LB we are building does not match that
571 * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
572 * then the fib_index is not an index that relates to the table
573 * type we need. So get the default flow-hash config instead.
574 */
Neale Rannsd792d9c2017-10-21 10:53:20 -0700575 flow_hash_proto = dpo_proto_to_fib(lb_proto);
576 if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
Neale Ranns41da54f2017-05-02 10:15:19 -0700577 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700578 fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700579 }
580 else
581 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700582 fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
583 flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700584 }
Neale Rannsd792d9c2017-10-21 10:53:20 -0700585
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800586 dpo_set(dpo_lb,
587 DPO_LOAD_BALANCE,
588 lb_proto,
589 load_balance_create(0, lb_proto, fhc));
590 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100591 }
592
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800593 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
Neale Ranns3ee44042016-10-03 13:05:48 +0100594 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800595 /*
596 * MPLS multicast
597 */
598 replicate_multipath_update(dpo_lb, ctx.next_hops);
Neale Ranns3ee44042016-10-03 13:05:48 +0100599 }
600 else
601 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800602 load_balance_multipath_update(dpo_lb,
603 ctx.next_hops,
604 fib_entry_calc_lb_flags(&ctx));
605 vec_free(ctx.next_hops);
606
607 /*
608 * if this entry is sourced by the uRPF-exempt source then we
609 * append the always present local0 interface (index 0) to the
610 * uRPF list so it is not empty. that way packets pass the loose check.
611 */
612 index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
613
614 if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
615 FIB_SOURCE_URPF_EXEMPT) ||
616 (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
617 (0 == fib_urpf_check_size(ui)))
618 {
619 /*
620 * The uRPF list we get from the path-list is shared by all
621 * other users of the list, but the uRPF exemption applies
622 * only to this prefix. So we need our own list.
623 */
624 ui = fib_urpf_list_alloc_and_lock();
625 fib_urpf_list_append(ui, 0);
626 fib_urpf_list_bake(ui);
627 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
628 fib_urpf_list_unlock(ui);
629 }
630 else
631 {
632 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
633 }
634 load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
635 fib_entry_get_flags_i(fib_entry));
Neale Ranns3ee44042016-10-03 13:05:48 +0100636 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637}
638
639void
640fib_entry_src_action_install (fib_entry_t *fib_entry,
641 fib_source_t source)
642{
643 /*
644 * Install the forwarding chain for the given source into the forwarding
645 * tables
646 */
647 fib_forward_chain_type_t fct;
648 fib_entry_src_t *esrc;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100649 int insert;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100650
651 fct = fib_entry_get_default_chain_type(fib_entry);
Neale Ranns2303cb12018-02-21 04:57:17 -0800652 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100653
Neale Ranns33a7dd52016-10-07 15:14:33 +0100654 /*
655 * Every entry has its own load-balance object. All changes to the entry's
656 * forwarding result in an inplace modify of the load-balance. This means
657 * the load-balance object only needs to be added to the forwarding
658 * DB once, when it is created.
659 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000660 insert = !dpo_id_is_valid(&fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100661
Neale Rannsad422ed2016-11-02 14:20:04 +0000662 fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100663
Neale Rannsad422ed2016-11-02 14:20:04 +0000664 ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
665 FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100666
667 /*
668 * insert the adj into the data-plane forwarding trie
669 */
Neale Ranns33a7dd52016-10-07 15:14:33 +0100670 if (insert)
671 {
672 fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
673 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000674 &fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100675 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100676
Neale Rannsad422ed2016-11-02 14:20:04 +0000677 /*
678 * if any of the other chain types are already created they will need
679 * updating too
680 */
681 fib_entry_delegate_type_t fdt;
682 fib_entry_delegate_t *fed;
683
684 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100685 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000686 fib_entry_src_mk_lb(fib_entry, esrc,
687 fib_entry_delegate_type_to_chain_type(fdt),
688 &fed->fd_dpo);
689 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690}
691
692void
693fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
694{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100695 /*
Neale Ranns3ee44042016-10-03 13:05:48 +0100696 * uninstall the forwarding chain from the forwarding tables
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 */
Neale Ranns710071b2018-09-24 12:36:26 +0000698 FIB_ENTRY_DBG(fib_entry, "uninstall");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100699
Neale Rannsad422ed2016-11-02 14:20:04 +0000700 if (dpo_id_is_valid(&fib_entry->fe_lb))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100701 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100702 fib_table_fwding_dpo_remove(
703 fib_entry->fe_fib_index,
704 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000705 &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100706
Neale Rannsad422ed2016-11-02 14:20:04 +0000707 dpo_reset(&fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100708 }
709}
710
711static void
712fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
713{
714 fib_node_index_t *entries = NULL;
715
716 fib_path_list_recursive_loop_detect(path_list_index, &entries);
717
718 vec_free(entries);
719}
720
Neale Ranns89541992017-04-06 04:41:02 -0700721/*
722 * fib_entry_src_action_copy
723 *
724 * copy a source data from another entry to this one
725 */
Neale Ranns2303cb12018-02-21 04:57:17 -0800726static fib_entry_t *
Neale Ranns89541992017-04-06 04:41:02 -0700727fib_entry_src_action_copy (fib_entry_t *fib_entry,
728 const fib_entry_src_t *orig_src)
729{
730 fib_entry_src_t *esrc;
731
Neale Ranns2303cb12018-02-21 04:57:17 -0800732 esrc = fib_entry_src_find_or_create(fib_entry,
733 orig_src->fes_src,
734 orig_src->fes_entry_flags);
Neale Ranns89541992017-04-06 04:41:02 -0700735
Neale Ranns2303cb12018-02-21 04:57:17 -0800736 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_copy,
737 (orig_src, fib_entry, esrc));
738
739 fib_path_list_unlock(esrc->fes_pl);
740
741 /*
742 * copy over all the data ...
743 */
744 esrc->fes_flags = orig_src->fes_flags;
745 esrc->fes_pl = orig_src->fes_pl;
746
747 /*
748 * ... then update
749 */
Neale Ranns89541992017-04-06 04:41:02 -0700750 esrc->fes_ref_count = 1;
751 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_INHERITED;
Neale Ranns2303cb12018-02-21 04:57:17 -0800752 esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
753 FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
Neale Ranns89541992017-04-06 04:41:02 -0700754 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
755
756 /*
757 * the source owns a lock on the entry
758 */
759 fib_path_list_lock(esrc->fes_pl);
760 fib_entry_lock(fib_entry_get_index(fib_entry));
761
762 return (fib_entry);
763}
764
765/*
766 * fib_entry_src_action_update
767 *
768 * copy a source data from another entry to this one
769 */
770static fib_entry_src_t *
771fib_entry_src_action_update_from_cover (fib_entry_t *fib_entry,
772 const fib_entry_src_t *orig_src)
773{
774 fib_entry_src_t *esrc;
775
Neale Ranns2303cb12018-02-21 04:57:17 -0800776 esrc = fib_entry_src_find_or_create(fib_entry,
777 orig_src->fes_src,
778 orig_src->fes_entry_flags);
Neale Ranns89541992017-04-06 04:41:02 -0700779
780 /*
781 * the source owns a lock on the entry
782 */
783 fib_path_list_unlock(esrc->fes_pl);
784 esrc->fes_pl = orig_src->fes_pl;
785 fib_path_list_lock(esrc->fes_pl);
786
787 return (esrc);
788}
789
790static fib_table_walk_rc_t
791fib_entry_src_covered_inherit_add_i (fib_entry_t *fib_entry,
792 const fib_entry_src_t *cover_src)
793{
794 fib_entry_src_t *esrc;
795
Neale Ranns2303cb12018-02-21 04:57:17 -0800796 esrc = fib_entry_src_find(fib_entry, cover_src->fes_src);
Neale Ranns89541992017-04-06 04:41:02 -0700797
798 if (cover_src == esrc)
799 {
800 return (FIB_TABLE_WALK_CONTINUE);
801 }
802
803 if (NULL != esrc)
804 {
805 /*
806 * the covered entry already has this source.
807 */
808 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
809 {
810 /*
811 * the covered source is itself a COVERED_INHERIT, i.e.
812 * it also pushes this source down the sub-tree.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700813 * We consider this more specific covered to be the owner
Neale Ranns89541992017-04-06 04:41:02 -0700814 * of the sub-tree from this point down.
815 */
816 return (FIB_TABLE_WALK_SUB_TREE_STOP);
817 }
818 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
819 {
820 /*
821 * The covered's source data has been inherited, presumably
822 * from this cover, i.e. this is a modify.
823 */
824 esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
825 fib_entry_source_change(fib_entry, esrc->fes_src, esrc->fes_src);
826 }
827 else
828 {
829 /*
830 * The covered's source was not inherited and it is also
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700831 * not inheriting. Nevertheless, it still owns the sub-tree from
Neale Ranns89541992017-04-06 04:41:02 -0700832 * this point down.
833 */
834 return (FIB_TABLE_WALK_SUB_TREE_STOP);
835 }
836 }
837 else
838 {
839 /*
840 * The covered does not have this source - add it.
841 */
842 fib_source_t best_source;
843
844 best_source = fib_entry_get_best_source(
845 fib_entry_get_index(fib_entry));
846
847 fib_entry_src_action_copy(fib_entry, cover_src);
848 fib_entry_source_change(fib_entry, best_source, cover_src->fes_src);
849
850 }
851 return (FIB_TABLE_WALK_CONTINUE);
852}
853
854static fib_table_walk_rc_t
855fib_entry_src_covered_inherit_walk_add (fib_node_index_t fei,
856 void *ctx)
857{
858 return (fib_entry_src_covered_inherit_add_i(fib_entry_get(fei), ctx));
859}
860
861static fib_table_walk_rc_t
862fib_entry_src_covered_inherit_walk_remove (fib_node_index_t fei,
863 void *ctx)
864{
865 fib_entry_src_t *cover_src, *esrc;
866 fib_entry_t *fib_entry;
867
868 fib_entry = fib_entry_get(fei);
869
870 cover_src = ctx;
Neale Ranns2303cb12018-02-21 04:57:17 -0800871 esrc = fib_entry_src_find(fib_entry, cover_src->fes_src);
Neale Ranns89541992017-04-06 04:41:02 -0700872
873 if (cover_src == esrc)
874 {
875 return (FIB_TABLE_WALK_CONTINUE);
876 }
877
878 if (NULL != esrc)
879 {
880 /*
881 * the covered entry already has this source.
882 */
883 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
884 {
885 /*
886 * the covered source is itself a COVERED_INHERIT, i.e.
887 * it also pushes this source down the sub-tree.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700888 * We consider this more specific covered to be the owner
Neale Ranns89541992017-04-06 04:41:02 -0700889 * of the sub-tree from this point down.
890 */
891 return (FIB_TABLE_WALK_SUB_TREE_STOP);
892 }
893 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
894 {
895 /*
896 * The covered's source data has been inherited, presumably
897 * from this cover
898 */
899 fib_entry_src_flag_t remaining;
900
901 remaining = fib_entry_special_remove(fei, cover_src->fes_src);
902
903 ASSERT(FIB_ENTRY_SRC_FLAG_ADDED == remaining);
904 }
905 else
906 {
907 /*
908 * The covered's source was not inherited and it is also
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700909 * not inheriting. Nevertheless, it still owns the sub-tree from
Neale Ranns89541992017-04-06 04:41:02 -0700910 * this point down.
911 */
912 return (FIB_TABLE_WALK_SUB_TREE_STOP);
913 }
914 }
915 else
916 {
917 /*
918 * The covered does not have this source - that's an error,
919 * since it should have inherited, but there is nothing we can do
920 * about it now.
921 */
922 }
923 return (FIB_TABLE_WALK_CONTINUE);
924}
925
926void
927fib_entry_src_inherit (const fib_entry_t *cover,
928 fib_entry_t *covered)
929{
930 CLIB_UNUSED(fib_source_t source);
931 const fib_entry_src_t *src;
932
933 FOR_EACH_SRC_ADDED(cover, src, source,
934 ({
935 if ((src->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
936 (src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
937 {
938 fib_entry_src_covered_inherit_add_i(covered, src);
939 }
940 }))
941}
942
943static void
944fib_entry_src_covered_inherit_add (fib_entry_t *fib_entry,
945 fib_source_t source)
946
947{
948 fib_entry_src_t *esrc;
949
Neale Ranns2303cb12018-02-21 04:57:17 -0800950 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns89541992017-04-06 04:41:02 -0700951
952 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
953
954 if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
955 (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
956 {
957 fib_table_sub_tree_walk(fib_entry->fe_fib_index,
958 fib_entry->fe_prefix.fp_proto,
959 &fib_entry->fe_prefix,
960 fib_entry_src_covered_inherit_walk_add,
961 esrc);
962 }
963}
964
965static void
966fib_entry_src_covered_inherit_remove (fib_entry_t *fib_entry,
967 fib_entry_src_t *esrc)
968
969{
970 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
971
972 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
973 {
974 fib_table_sub_tree_walk(fib_entry->fe_fib_index,
975 fib_entry->fe_prefix.fp_proto,
976 &fib_entry->fe_prefix,
977 fib_entry_src_covered_inherit_walk_remove,
978 esrc);
979 }
980}
981
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100982void
983fib_entry_src_action_activate (fib_entry_t *fib_entry,
984 fib_source_t source)
985
986{
987 int houston_we_are_go_for_install;
Neale Ranns2303cb12018-02-21 04:57:17 -0800988 const fib_entry_src_vft_t *vft;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100989 fib_entry_src_t *esrc;
990
Neale Ranns2303cb12018-02-21 04:57:17 -0800991 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100992
993 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
994 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
995
Neale Ranns2303cb12018-02-21 04:57:17 -0800996 esrc->fes_flags |= (FIB_ENTRY_SRC_FLAG_ACTIVE |
997 FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
998 vft = fib_entry_src_get_vft(esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100999
Neale Ranns2303cb12018-02-21 04:57:17 -08001000 if (NULL != vft->fesv_activate)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001001 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001002 houston_we_are_go_for_install = vft->fesv_activate(esrc, fib_entry);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001003 }
1004 else
1005 {
1006 /*
1007 * the source is not providing an activate function, we'll assume
1008 * therefore it has no objection to installing the entry
1009 */
1010 houston_we_are_go_for_install = !0;
1011 }
1012
1013 /*
1014 * link to the path-list provided by the source, and go check
1015 * if that forms any loops in the graph.
1016 */
1017 fib_entry->fe_parent = esrc->fes_pl;
1018 fib_entry->fe_sibling =
1019 fib_path_list_child_add(fib_entry->fe_parent,
1020 FIB_NODE_TYPE_ENTRY,
1021 fib_entry_get_index(fib_entry));
1022
1023 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1024
1025 FIB_ENTRY_DBG(fib_entry, "activate: %d",
1026 fib_entry->fe_parent);
1027
Neale Ranns89541992017-04-06 04:41:02 -07001028 /*
1029 * If this source should push its state to covered prefixs, do that now.
1030 */
1031 fib_entry_src_covered_inherit_add(fib_entry, source);
1032
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001033 if (0 != houston_we_are_go_for_install)
1034 {
1035 fib_entry_src_action_install(fib_entry, source);
1036 }
1037 else
1038 {
1039 fib_entry_src_action_uninstall(fib_entry);
1040 }
1041}
1042
1043void
1044fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
1045 fib_source_t source)
1046
1047{
1048 fib_node_index_t path_list_index;
1049 fib_entry_src_t *esrc;
1050
Neale Ranns2303cb12018-02-21 04:57:17 -08001051 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001052
1053 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1054
Neale Ranns2303cb12018-02-21 04:57:17 -08001055 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_deactivate,
1056 (esrc, fib_entry));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001057
Neale Ranns2303cb12018-02-21 04:57:17 -08001058 esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
1059 FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001060
1061 FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
1062
1063 /*
Neale Ranns89541992017-04-06 04:41:02 -07001064 * If this source should pull its state from covered prefixs, do that now.
1065 * If this source also has the INHERITED flag set then it has a cover
1066 * that wants to push down forwarding. We only want the covereds to see
1067 * one update.
1068 */
1069 fib_entry_src_covered_inherit_remove(fib_entry, esrc);
1070
1071 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001072 * un-link from an old path-list. Check for any loops this will clear
1073 */
1074 path_list_index = fib_entry->fe_parent;
1075 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1076
1077 fib_entry_recursive_loop_detect_i(path_list_index);
1078
1079 /*
1080 * this will unlock the path-list, so it may be invalid thereafter.
1081 */
1082 fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
1083 fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
1084}
1085
Neale Rannsa4e77662017-12-04 20:00:30 +00001086static void
1087fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
1088 fib_source_t source)
1089{
1090 fib_entry_src_t *esrc;
1091
1092 vec_foreach(esrc, fib_entry->fe_srcs)
1093 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001094 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_fwd_update,
1095 (esrc, fib_entry, source));
Neale Rannsa4e77662017-12-04 20:00:30 +00001096 }
1097}
1098
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001099void
1100fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
1101 fib_source_t source)
1102{
1103 fib_node_index_t path_list_index;
Neale Ranns2303cb12018-02-21 04:57:17 -08001104 const fib_entry_src_vft_t *vft;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001105 fib_entry_src_t *esrc;
Neale Ranns2303cb12018-02-21 04:57:17 -08001106 int remain_installed;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001107
Neale Ranns2303cb12018-02-21 04:57:17 -08001108 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001109
1110 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1111
1112 FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
1113 fib_entry->fe_parent,
1114 esrc->fes_pl);
1115
Neale Ranns2303cb12018-02-21 04:57:17 -08001116 /*
1117 * call the source to reactive and get the go/no-go to remain installed
1118 */
1119 vft = fib_entry_src_get_vft(esrc);
1120
1121 if (NULL != vft->fesv_reactivate)
1122 {
1123 remain_installed = vft->fesv_reactivate(esrc, fib_entry);
1124 }
1125 else
1126 {
1127 remain_installed = 1;
1128 }
1129
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001130 if (fib_entry->fe_parent != esrc->fes_pl)
1131 {
1132 /*
1133 * un-link from an old path-list. Check for any loops this will clear
1134 */
1135 path_list_index = fib_entry->fe_parent;
1136 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1137
1138 /*
1139 * temporary lock so it doesn't get deleted when this entry is no
1140 * longer a child.
1141 */
1142 fib_path_list_lock(path_list_index);
1143
1144 /*
1145 * this entry is no longer a child. after unlinking check if any loops
1146 * were broken
1147 */
1148 fib_path_list_child_remove(path_list_index,
1149 fib_entry->fe_sibling);
1150
1151 fib_entry_recursive_loop_detect_i(path_list_index);
1152
1153 /*
1154 * link to the path-list provided by the source, and go check
1155 * if that forms any loops in the graph.
1156 */
1157 fib_entry->fe_parent = esrc->fes_pl;
1158 fib_entry->fe_sibling =
1159 fib_path_list_child_add(fib_entry->fe_parent,
1160 FIB_NODE_TYPE_ENTRY,
1161 fib_entry_get_index(fib_entry));
1162
1163 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1164 fib_path_list_unlock(path_list_index);
Neale Ranns89541992017-04-06 04:41:02 -07001165
1166 /*
Neale Ranns89541992017-04-06 04:41:02 -07001167 * If this source should push its state to covered prefixs, do that now.
1168 */
1169 fib_entry_src_covered_inherit_add(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001170 }
Neale Ranns2303cb12018-02-21 04:57:17 -08001171
1172 if (!remain_installed)
1173 {
1174 fib_entry_src_action_uninstall(fib_entry);
1175 }
1176 else
1177 {
1178 fib_entry_src_action_install(fib_entry, source);
1179 }
Neale Rannsa4e77662017-12-04 20:00:30 +00001180 fib_entry_src_action_fwd_update(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001181}
1182
1183void
Neale Rannsa4e77662017-12-04 20:00:30 +00001184fib_entry_src_action_installed (const fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001185 fib_source_t source)
1186{
1187 fib_entry_src_t *esrc;
1188
Neale Ranns2303cb12018-02-21 04:57:17 -08001189 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001190
Neale Ranns2303cb12018-02-21 04:57:17 -08001191 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_installed,
1192 (esrc, fib_entry));
Neale Rannsa4e77662017-12-04 20:00:30 +00001193
1194 fib_entry_src_action_fwd_update(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001195}
1196
1197/*
1198 * fib_entry_src_action_add
1199 *
1200 * Adding a source can result in a new fib_entry being created, which
1201 * can inturn mean the pool is realloc'd and thus the entry passed as
1202 * an argument it also realloc'd
1203 * @return the original entry
1204 */
1205fib_entry_t *
1206fib_entry_src_action_add (fib_entry_t *fib_entry,
1207 fib_source_t source,
1208 fib_entry_flag_t flags,
1209 const dpo_id_t *dpo)
1210{
1211 fib_node_index_t fib_entry_index;
1212 fib_entry_src_t *esrc;
1213
Neale Ranns2303cb12018-02-21 04:57:17 -08001214 esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001215
Neale Ranns2303cb12018-02-21 04:57:17 -08001216 ASSERT(esrc->fes_ref_count < 255);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001217 esrc->fes_ref_count++;
1218
Neale Ranns2303cb12018-02-21 04:57:17 -08001219 if (flags != esrc->fes_entry_flags)
1220 {
1221 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_flags_change,
1222 (esrc, fib_entry, flags));
1223 }
1224 esrc->fes_entry_flags = flags;
1225
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001226 if (1 != esrc->fes_ref_count)
1227 {
1228 /*
1229 * we only want to add the source on the 0->1 transition
1230 */
1231 return (fib_entry);
1232 }
1233
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001234 /*
1235 * save variable so we can recover from a fib_entry realloc.
1236 */
1237 fib_entry_index = fib_entry_get_index(fib_entry);
1238
Neale Ranns2303cb12018-02-21 04:57:17 -08001239 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_add,
1240 (esrc,
1241 fib_entry,
1242 flags,
1243 fib_entry_get_dpo_proto(fib_entry),
1244 dpo));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001245
1246 fib_entry = fib_entry_get(fib_entry_index);
1247
1248 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1249
1250 fib_path_list_lock(esrc->fes_pl);
1251
1252 /*
1253 * the source owns a lock on the entry
1254 */
1255 fib_entry_lock(fib_entry_get_index(fib_entry));
1256
1257 return (fib_entry);
1258}
1259
Neale Ranns948e00f2016-10-20 13:39:34 +01001260/*
1261 * fib_entry_src_action_update
1262 *
1263 * Adding a source can result in a new fib_entry being created, which
1264 * can inturn mean the pool is realloc'd and thus the entry passed as
1265 * an argument it also realloc'd
1266 * @return the original entry
1267 */
1268fib_entry_t *
1269fib_entry_src_action_update (fib_entry_t *fib_entry,
1270 fib_source_t source,
1271 fib_entry_flag_t flags,
1272 const dpo_id_t *dpo)
1273{
1274 fib_node_index_t fib_entry_index, old_path_list_index;
1275 fib_entry_src_t *esrc;
1276
Neale Ranns2303cb12018-02-21 04:57:17 -08001277 esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
Neale Ranns948e00f2016-10-20 13:39:34 +01001278
1279 if (NULL == esrc)
Neale Ranns89541992017-04-06 04:41:02 -07001280 {
Neale Ranns948e00f2016-10-20 13:39:34 +01001281 return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
Neale Ranns89541992017-04-06 04:41:02 -07001282 }
Neale Ranns948e00f2016-10-20 13:39:34 +01001283
1284 old_path_list_index = esrc->fes_pl;
1285 esrc->fes_entry_flags = flags;
1286
1287 /*
1288 * save variable so we can recover from a fib_entry realloc.
1289 */
1290 fib_entry_index = fib_entry_get_index(fib_entry);
1291
Neale Ranns2303cb12018-02-21 04:57:17 -08001292 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_add,
1293 (esrc,
1294 fib_entry,
1295 flags,
1296 fib_entry_get_dpo_proto(fib_entry),
1297 dpo));
Neale Ranns948e00f2016-10-20 13:39:34 +01001298
1299 fib_entry = fib_entry_get(fib_entry_index);
1300
1301 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1302
1303 fib_path_list_lock(esrc->fes_pl);
1304 fib_path_list_unlock(old_path_list_index);
1305
1306 return (fib_entry);
1307}
1308
Neale Ranns89541992017-04-06 04:41:02 -07001309fib_entry_src_flag_t
1310fib_entry_src_action_remove_or_update_inherit (fib_entry_t *fib_entry,
1311 fib_source_t source)
1312{
1313 fib_entry_src_t *esrc;
1314
Neale Ranns2303cb12018-02-21 04:57:17 -08001315 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns89541992017-04-06 04:41:02 -07001316
1317 if (NULL == esrc)
1318 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1319
1320 if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) &&
1321 (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
1322 {
1323 fib_entry_src_t *cover_src;
1324 fib_node_index_t coveri;
1325 fib_entry_t *cover;
1326
1327 /*
1328 * this source was pushing inherited state, but so is its
1329 * cover. Now that this source is going away, we need to
1330 * pull the covers forwarding and use it to update the covereds.
1331 * Go grab the path-list from the cover, rather than start a walk from
1332 * the cover, so we don't recursively update this entry.
1333 */
1334 coveri = fib_table_get_less_specific(fib_entry->fe_fib_index,
1335 &fib_entry->fe_prefix);
1336
1337 /*
1338 * only the default route has itself as its own cover, but the
1339 * default route cannot have inherited from something else.
1340 */
1341 ASSERT(coveri != fib_entry_get_index(fib_entry));
1342
1343 cover = fib_entry_get(coveri);
Neale Ranns2303cb12018-02-21 04:57:17 -08001344 cover_src = fib_entry_src_find(cover, source);
Neale Ranns89541992017-04-06 04:41:02 -07001345
1346 ASSERT(NULL != cover_src);
1347
1348 esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
1349 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
1350
1351 /*
1352 * Now push the new state from the cover down to the covereds
1353 */
1354 fib_entry_src_covered_inherit_add(fib_entry, source);
1355
1356 return (esrc->fes_flags);
1357 }
1358 else
1359 {
1360 return (fib_entry_src_action_remove(fib_entry, source));
1361 }
1362}
Neale Ranns948e00f2016-10-20 13:39:34 +01001363
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001364fib_entry_src_flag_t
1365fib_entry_src_action_remove (fib_entry_t *fib_entry,
1366 fib_source_t source)
1367
1368{
1369 fib_node_index_t old_path_list;
1370 fib_entry_src_flag_t sflags;
1371 fib_entry_src_t *esrc;
1372
Neale Ranns2303cb12018-02-21 04:57:17 -08001373 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001374
1375 if (NULL == esrc)
1376 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1377
1378 esrc->fes_ref_count--;
1379 sflags = esrc->fes_flags;
1380
1381 if (0 != esrc->fes_ref_count)
1382 {
1383 /*
1384 * only remove the source on the 1->0 transisition
1385 */
1386 return (sflags);
1387 }
1388
1389 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
1390 {
Neale Ranns89541992017-04-06 04:41:02 -07001391 fib_entry_src_action_deactivate(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001392 }
Neale Ranns2303cb12018-02-21 04:57:17 -08001393 else if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING)
1394 {
1395 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_deactivate,
1396 (esrc, fib_entry));
1397 esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_CONTRIBUTING;
1398 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001399
1400 old_path_list = esrc->fes_pl;
1401
Neale Ranns2303cb12018-02-21 04:57:17 -08001402 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_remove, (esrc));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001403
1404 fib_path_list_unlock(old_path_list);
1405 fib_entry_unlock(fib_entry_get_index(fib_entry));
1406
1407 sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
1408 fib_entry_src_action_deinit(fib_entry, source);
1409
1410 return (sflags);
1411}
1412
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001413/*
1414 * fib_route_attached_cross_table
1415 *
1416 * Return true the the route is attached via an interface that
1417 * is not in the same table as the route
1418 */
1419static inline int
1420fib_route_attached_cross_table (const fib_entry_t *fib_entry,
1421 const fib_route_path_t *rpath)
1422{
1423 /*
1424 * - All zeros next-hop
1425 * - a valid interface
1426 * - entry's fib index not equeal to interface's index
1427 */
1428 if (ip46_address_is_zero(&rpath->frp_addr) &&
1429 (~0 != rpath->frp_sw_if_index) &&
Neale Rannseca834e2018-03-13 07:51:50 -07001430 !(rpath->frp_flags & FIB_ROUTE_PATH_DVR) &&
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001431 (fib_entry->fe_fib_index !=
1432 fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
1433 rpath->frp_sw_if_index)))
1434 {
1435 return (!0);
1436 }
1437 return (0);
1438}
1439
1440/*
Neale Ranns53da2212018-02-24 02:11:19 -08001441 * Return true if the path is attached
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001442 */
1443static inline int
1444fib_path_is_attached (const fib_route_path_t *rpath)
1445{
1446 /*
Neale Rannseca834e2018-03-13 07:51:50 -07001447 * DVR paths are not attached, since we are not playing the
1448 * L3 game with these
1449 */
1450 if (rpath->frp_flags & FIB_ROUTE_PATH_DVR)
1451 {
1452 return (0);
1453 }
1454
1455 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001456 * - All zeros next-hop
1457 * - a valid interface
1458 */
1459 if (ip46_address_is_zero(&rpath->frp_addr) &&
1460 (~0 != rpath->frp_sw_if_index))
1461 {
1462 return (!0);
1463 }
Neale Ranns4b919a52017-03-11 05:55:21 -08001464 else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
1465 {
1466 return (!0);
1467 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001468 return (0);
1469}
1470
1471fib_path_list_flags_t
1472fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
1473{
1474 fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
1475
1476 if (eflags & FIB_ENTRY_FLAG_DROP)
1477 {
1478 plf |= FIB_PATH_LIST_FLAG_DROP;
1479 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001480 if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
1481 {
1482 plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
1483 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001484 if (eflags & FIB_ENTRY_FLAG_LOCAL)
1485 {
1486 plf |= FIB_PATH_LIST_FLAG_LOCAL;
1487 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001488
1489 return (plf);
1490}
1491
1492static void
1493fib_entry_flags_update (const fib_entry_t *fib_entry,
Neale Ranns097fa662018-05-01 05:17:55 -07001494 const fib_route_path_t *rpaths,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001495 fib_path_list_flags_t *pl_flags,
1496 fib_entry_src_t *esrc)
1497{
Neale Ranns097fa662018-05-01 05:17:55 -07001498 const fib_route_path_t *rpath;
1499
1500 vec_foreach(rpath, rpaths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001501 {
Neale Ranns097fa662018-05-01 05:17:55 -07001502 if ((esrc->fes_src == FIB_SOURCE_API) ||
1503 (esrc->fes_src == FIB_SOURCE_CLI))
1504 {
1505 if (fib_path_is_attached(rpath))
1506 {
1507 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1508 }
1509 else
1510 {
1511 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1512 }
1513 if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
1514 {
1515 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT;
1516 }
1517 }
1518 if (fib_route_attached_cross_table(fib_entry, rpath) &&
1519 !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT))
1520 {
1521 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1522 }
1523 else
1524 {
1525 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1526 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001527 }
1528}
1529
1530/*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001531 * fib_entry_src_action_add
1532 *
1533 * Adding a source can result in a new fib_entry being created, which
1534 * can inturn mean the pool is realloc'd and thus the entry passed as
1535 * an argument it also realloc'd
1536 * @return the entry
1537 */
1538fib_entry_t*
1539fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1540 fib_source_t source,
1541 fib_entry_flag_t flags,
Neale Ranns097fa662018-05-01 05:17:55 -07001542 const fib_route_path_t *rpaths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001543{
1544 fib_node_index_t old_path_list, fib_entry_index;
1545 fib_path_list_flags_t pl_flags;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001546 fib_entry_src_t *esrc;
1547
1548 /*
1549 * save variable so we can recover from a fib_entry realloc.
1550 */
1551 fib_entry_index = fib_entry_get_index(fib_entry);
1552
Neale Ranns2303cb12018-02-21 04:57:17 -08001553 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001554 if (NULL == esrc)
1555 {
Vijayabhaskar Katamreddy0c2319f2018-10-25 13:28:12 -07001556 const dpo_id_t *dpo;
1557
1558 if (flags == FIB_ENTRY_FLAG_EXCLUSIVE) {
Neale Ranns097fa662018-05-01 05:17:55 -07001559 dpo = &rpaths->dpo;
Vijayabhaskar Katamreddy0c2319f2018-10-25 13:28:12 -07001560 } else {
1561 dpo = drop_dpo_get(fib_entry_get_dpo_proto(fib_entry));
1562 }
1563
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001564 fib_entry =
1565 fib_entry_src_action_add(fib_entry,
1566 source,
1567 flags,
Vijayabhaskar Katamreddy0c2319f2018-10-25 13:28:12 -07001568 dpo);
Neale Ranns2303cb12018-02-21 04:57:17 -08001569 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001570 }
1571
1572 /*
1573 * we are no doubt modifying a path-list. If the path-list
1574 * is shared, and hence not modifiable, then the index returned
1575 * will be for a different path-list. This FIB entry to needs
1576 * to maintain its lock appropriately.
1577 */
1578 old_path_list = esrc->fes_pl;
1579
Neale Ranns2303cb12018-02-21 04:57:17 -08001580 ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_add));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001581
1582 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
Neale Ranns097fa662018-05-01 05:17:55 -07001583 fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001584
Neale Ranns2303cb12018-02-21 04:57:17 -08001585 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_path_add,
Neale Ranns097fa662018-05-01 05:17:55 -07001586 (esrc, fib_entry, pl_flags, rpaths));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001587 fib_entry = fib_entry_get(fib_entry_index);
1588
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001589 fib_path_list_lock(esrc->fes_pl);
1590 fib_path_list_unlock(old_path_list);
1591
1592 return (fib_entry);
1593}
1594
1595/*
1596 * fib_entry_src_action_swap
1597 *
1598 * The source is providing new paths to replace the old ones.
1599 * Adding a source can result in a new fib_entry being created, which
1600 * can inturn mean the pool is realloc'd and thus the entry passed as
1601 * an argument it also realloc'd
1602 * @return the entry
1603 */
1604fib_entry_t*
1605fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1606 fib_source_t source,
Neale Ranns2303cb12018-02-21 04:57:17 -08001607 fib_entry_flag_t flags,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001608 const fib_route_path_t *rpaths)
1609{
1610 fib_node_index_t old_path_list, fib_entry_index;
1611 fib_path_list_flags_t pl_flags;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001612 fib_entry_src_t *esrc;
1613
Neale Ranns2303cb12018-02-21 04:57:17 -08001614 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001615
1616 /*
1617 * save variable so we can recover from a fib_entry realloc.
1618 */
1619 fib_entry_index = fib_entry_get_index(fib_entry);
1620
1621 if (NULL == esrc)
1622 {
Vijayabhaskar Katamreddy0c2319f2018-10-25 13:28:12 -07001623 const dpo_id_t *dpo;
1624
1625 if (flags == FIB_ENTRY_FLAG_EXCLUSIVE) {
1626 dpo = &rpaths->dpo;
1627 } else {
1628 dpo = drop_dpo_get(fib_entry_get_dpo_proto(fib_entry));
1629 }
1630
Neale Ranns2303cb12018-02-21 04:57:17 -08001631 fib_entry = fib_entry_src_action_add(fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001632 source,
1633 flags,
Vijayabhaskar Katamreddy0c2319f2018-10-25 13:28:12 -07001634 dpo);
Neale Ranns2303cb12018-02-21 04:57:17 -08001635 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001636 }
Neale Ranns89541992017-04-06 04:41:02 -07001637 else
1638 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001639 if (flags != esrc->fes_entry_flags)
1640 {
1641 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_flags_change,
1642 (esrc, fib_entry, flags));
1643 }
Neale Ranns89541992017-04-06 04:41:02 -07001644 esrc->fes_entry_flags = flags;
1645 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001646
1647 /*
1648 * swapping paths may create a new path-list (or may use an existing shared)
1649 * but we are certainly getting a different one. This FIB entry to needs
1650 * to maintain its lock appropriately.
1651 */
1652 old_path_list = esrc->fes_pl;
1653
Neale Ranns2303cb12018-02-21 04:57:17 -08001654 ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_swap));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001655
Neale Rannsdf089a82016-10-02 16:39:06 +01001656 pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1657
Neale Rannsb5d61a92019-07-09 14:29:35 +00001658 fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001659
Neale Ranns2303cb12018-02-21 04:57:17 -08001660 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_path_swap,
1661 (esrc, fib_entry,
1662 pl_flags, rpaths));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001663
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001664 fib_entry = fib_entry_get(fib_entry_index);
1665
1666 fib_path_list_lock(esrc->fes_pl);
1667 fib_path_list_unlock(old_path_list);
1668
1669 return (fib_entry);
1670}
1671
1672fib_entry_src_flag_t
1673fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1674 fib_source_t source,
Neale Ranns097fa662018-05-01 05:17:55 -07001675 const fib_route_path_t *rpaths)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001676{
1677 fib_path_list_flags_t pl_flags;
1678 fib_node_index_t old_path_list;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001679 fib_entry_src_t *esrc;
1680
Neale Ranns2303cb12018-02-21 04:57:17 -08001681 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001682
1683 ASSERT(NULL != esrc);
1684 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1685
1686 /*
1687 * we no doubt modifying a path-list. If the path-list
1688 * is shared, and hence not modifiable, then the index returned
1689 * will be for a different path-list. This FIB entry to needs
1690 * to maintain its lock appropriately.
1691 */
1692 old_path_list = esrc->fes_pl;
1693
Neale Ranns2303cb12018-02-21 04:57:17 -08001694 ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_remove));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001695
1696 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
Neale Ranns097fa662018-05-01 05:17:55 -07001697 fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001698
Neale Ranns2303cb12018-02-21 04:57:17 -08001699 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_path_remove,
Neale Ranns097fa662018-05-01 05:17:55 -07001700 (esrc, pl_flags, rpaths));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001701
1702 /*
1703 * lock the new path-list, unlock the old if it had one
1704 */
1705 fib_path_list_unlock(old_path_list);
1706
1707 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1708 fib_path_list_lock(esrc->fes_pl);
1709 return (FIB_ENTRY_SRC_FLAG_ADDED);
1710 }
1711 else
1712 {
1713 /*
1714 * no more paths left from this source
1715 */
Neale Ranns89541992017-04-06 04:41:02 -07001716 fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001717 return (FIB_ENTRY_SRC_FLAG_NONE);
1718 }
1719}
1720
1721u8*
1722fib_entry_src_format (fib_entry_t *fib_entry,
1723 fib_source_t source,
1724 u8* s)
1725{
1726 fib_entry_src_t *esrc;
1727
Neale Ranns2303cb12018-02-21 04:57:17 -08001728 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001729
Neale Ranns2303cb12018-02-21 04:57:17 -08001730 FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_format, (esrc, s));
1731
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001732 return (s);
1733}
1734
1735adj_index_t
1736fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1737 fib_source_t source)
1738{
1739 fib_entry_t *fib_entry;
1740 fib_entry_src_t *esrc;
1741
1742 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1743 return (ADJ_INDEX_INVALID);
1744
1745 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns2303cb12018-02-21 04:57:17 -08001746 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001747
1748 if (NULL != esrc)
1749 {
1750 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1751 {
1752 return (fib_path_list_get_adj(
1753 esrc->fes_pl,
1754 fib_entry_get_default_chain_type(fib_entry)));
1755 }
1756 }
1757 return (ADJ_INDEX_INVALID);
1758}
1759
1760const int
1761fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1762 fib_source_t source,
1763 dpo_id_t *dpo)
1764{
1765 fib_entry_t *fib_entry;
1766 fib_entry_src_t *esrc;
1767
1768 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1769 return (0);
1770
1771 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns2303cb12018-02-21 04:57:17 -08001772 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001773
1774 if (NULL != esrc)
1775 {
1776 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1777 {
1778 fib_path_list_contribute_forwarding(
1779 esrc->fes_pl,
1780 fib_entry_get_default_chain_type(fib_entry),
Neale Ranns91286372017-12-05 13:24:04 -08001781 FIB_PATH_LIST_FWD_FLAG_NONE,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001782 dpo);
1783
1784 return (dpo_id_is_valid(dpo));
1785 }
1786 }
1787 return (0);
1788}
1789
Neale Rannsdf089a82016-10-02 16:39:06 +01001790u32
1791fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1792 fib_source_t source)
1793{
1794 fib_entry_t *fib_entry;
1795 fib_entry_src_t *esrc;
1796
1797 fib_entry = fib_entry_get(entry_index);
1798
Neale Ranns2303cb12018-02-21 04:57:17 -08001799 esrc = fib_entry_src_find(fib_entry, source);
Neale Rannsdf089a82016-10-02 16:39:06 +01001800
1801 if (NULL != esrc)
1802 {
1803 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1804 {
1805 return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1806 }
1807 }
1808 return (~0);
1809}
1810
1811fib_entry_flag_t
1812fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1813 fib_source_t source)
1814{
1815 fib_entry_t *fib_entry;
1816 fib_entry_src_t *esrc;
1817
1818 fib_entry = fib_entry_get(entry_index);
1819
Neale Ranns2303cb12018-02-21 04:57:17 -08001820 esrc = fib_entry_src_find(fib_entry, source);
Neale Rannsdf089a82016-10-02 16:39:06 +01001821
1822 if (NULL != esrc)
1823 {
1824 return (esrc->fes_entry_flags);
1825 }
1826
1827 return (FIB_ENTRY_FLAG_NONE);
1828}
1829
Benoît Ganne99c358d2019-07-17 14:47:23 +02001830fib_source_t
1831fib_entry_get_source_i (const fib_entry_t *fib_entry)
1832{
1833 /* the vector of sources is deliberately arranged in priority order */
1834 if (0 == vec_len(fib_entry->fe_srcs))
1835 return (FIB_SOURCE_INVALID);
1836 return (vec_elt(fib_entry->fe_srcs, 0).fes_src);
1837}
1838
Neale Rannsa4e77662017-12-04 20:00:30 +00001839fib_entry_flag_t
1840fib_entry_get_flags_i (const fib_entry_t *fib_entry)
1841{
Benoît Ganne99c358d2019-07-17 14:47:23 +02001842 /* the vector of sources is deliberately arranged in priority order */
Neale Rannsa4e77662017-12-04 20:00:30 +00001843 if (0 == vec_len(fib_entry->fe_srcs))
Benoît Ganne99c358d2019-07-17 14:47:23 +02001844 return (FIB_ENTRY_FLAG_NONE);
1845 return (vec_elt(fib_entry->fe_srcs, 0).fes_entry_flags);
Neale Rannsa4e77662017-12-04 20:00:30 +00001846}
1847
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001848void
1849fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1850 fib_source_t source,
1851 const void *data)
1852{
1853 fib_entry_t *fib_entry;
1854 fib_entry_src_t *esrc;
1855
1856 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns2303cb12018-02-21 04:57:17 -08001857 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001858
Neale Ranns2303cb12018-02-21 04:57:17 -08001859 if (NULL != esrc)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001860 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001861 FIB_ENTRY_SRC_VFT_INVOKE(esrc, fesv_set_data,
1862 (esrc, fib_entry, data));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001863 }
1864}
1865
1866const void*
1867fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1868 fib_source_t source)
1869{
1870 fib_entry_t *fib_entry;
1871 fib_entry_src_t *esrc;
1872
1873 fib_entry = fib_entry_get(fib_entry_index);
Neale Ranns2303cb12018-02-21 04:57:17 -08001874 esrc = fib_entry_src_find(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001875
Neale Ranns2303cb12018-02-21 04:57:17 -08001876 if (NULL != esrc)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001877 {
Neale Ranns2303cb12018-02-21 04:57:17 -08001878 FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_get_data,
1879 (esrc, fib_entry));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001880 }
1881 return (NULL);
1882}
1883
1884void
1885fib_entry_src_module_init (void)
1886{
1887 fib_entry_src_rr_register();
1888 fib_entry_src_interface_register();
Neale Ranns2303cb12018-02-21 04:57:17 -08001889 fib_entry_src_interpose_register();
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001890 fib_entry_src_default_route_register();
1891 fib_entry_src_special_register();
1892 fib_entry_src_api_register();
1893 fib_entry_src_adj_register();
1894 fib_entry_src_mpls_register();
1895 fib_entry_src_lisp_register();
1896}