blob: 0497672b26811e832a2a5badcd33bda1db8126f2 [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 Ranns0bfe5d82016-08-25 15:29:12 +010026
27/*
28 * per-source type vft
29 */
30static fib_entry_src_vft_t fib_entry_src_vft[FIB_SOURCE_MAX];
31
Neale Ranns0bfe5d82016-08-25 15:29:12 +010032void
33fib_entry_src_register (fib_source_t source,
34 const fib_entry_src_vft_t *vft)
35{
36 fib_entry_src_vft[source] = *vft;
37}
38
39static int
40fib_entry_src_cmp_for_sort (void * v1,
41 void * v2)
42{
43 fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
44
45 return (esrc1->fes_src - esrc2->fes_src);
46}
47
48void
49fib_entry_src_action_init (fib_entry_t *fib_entry,
50 fib_source_t source)
51
52{
53 fib_entry_src_t esrc = {
54 .fes_pl = FIB_NODE_INDEX_INVALID,
55 .fes_flags = FIB_ENTRY_SRC_FLAG_NONE,
56 .fes_src = source,
57 };
58
59 if (NULL != fib_entry_src_vft[source].fesv_init)
60 {
61 fib_entry_src_vft[source].fesv_init(&esrc);
62 }
63
Neale Rannsa4e77662017-12-04 20:00:30 +000064 vec_add1(fib_entry->fe_srcs, esrc);
65 vec_sort_with_function(fib_entry->fe_srcs,
66 fib_entry_src_cmp_for_sort);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010067}
68
69static fib_entry_src_t *
Neale Rannsa4e77662017-12-04 20:00:30 +000070fib_entry_src_find (const fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010071 fib_source_t source,
72 u32 *index)
73
74{
75 fib_entry_src_t *esrc;
76 int ii;
77
78 ii = 0;
Neale Rannsa4e77662017-12-04 20:00:30 +000079 vec_foreach(esrc, fib_entry->fe_srcs)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010080 {
Neale Rannsa4e77662017-12-04 20:00:30 +000081 if (esrc->fes_src == source)
82 {
83 if (NULL != index)
84 {
85 *index = ii;
86 }
87 return (esrc);
88 }
89 else
90 {
91 ii++;
92 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +010093 }
94
95 return (NULL);
96}
97
98int
99fib_entry_is_sourced (fib_node_index_t fib_entry_index,
100 fib_source_t source)
101{
102 fib_entry_t *fib_entry;
103
104 fib_entry = fib_entry_get(fib_entry_index);
105
106 return (NULL != fib_entry_src_find(fib_entry, source, NULL));
107}
108
109static fib_entry_src_t *
110fib_entry_src_find_or_create (fib_entry_t *fib_entry,
Neale Ranns89541992017-04-06 04:41:02 -0700111 fib_source_t source)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100112{
113 fib_entry_src_t *esrc;
114
115 esrc = fib_entry_src_find(fib_entry, source, NULL);
116
117 if (NULL == esrc)
118 {
119 fib_entry_src_action_init(fib_entry, source);
120 }
121
122 return (fib_entry_src_find(fib_entry, source, NULL));
123}
124
125void
126fib_entry_src_action_deinit (fib_entry_t *fib_entry,
127 fib_source_t source)
128
129{
130 fib_entry_src_t *esrc;
131 u32 index = ~0;
132
133 esrc = fib_entry_src_find(fib_entry, source, &index);
134
135 ASSERT(NULL != esrc);
136
137 if (NULL != fib_entry_src_vft[source].fesv_deinit)
138 {
139 fib_entry_src_vft[source].fesv_deinit(esrc);
140 }
141
Neale Ranns81424992017-05-18 03:03:22 -0700142 fib_path_ext_list_flush(&esrc->fes_path_exts);
Neale Rannsa4e77662017-12-04 20:00:30 +0000143 vec_del1(fib_entry->fe_srcs, index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100144}
145
146fib_entry_src_cover_res_t
147fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
148 fib_source_t source)
149{
150 if (NULL != fib_entry_src_vft[source].fesv_cover_change)
151 {
152 return (fib_entry_src_vft[source].fesv_cover_change(
153 fib_entry_src_find(fib_entry, source, NULL),
154 fib_entry));
155 }
156
157 fib_entry_src_cover_res_t res = {
158 .install = !0,
159 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
160 };
161 return (res);
162}
163
164fib_entry_src_cover_res_t
165fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
166 fib_source_t source)
167{
168 if (NULL != fib_entry_src_vft[source].fesv_cover_update)
169 {
170 return (fib_entry_src_vft[source].fesv_cover_update(
171 fib_entry_src_find(fib_entry, source, NULL),
172 fib_entry));
173 }
174
175 fib_entry_src_cover_res_t res = {
176 .install = !0,
177 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
178 };
179 return (res);
180}
181
182typedef struct fib_entry_src_collect_forwarding_ctx_t_
183{
Neale Ranns81424992017-05-18 03:03:22 -0700184 load_balance_path_t *next_hops;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100185 const fib_entry_t *fib_entry;
186 const fib_entry_src_t *esrc;
187 fib_forward_chain_type_t fct;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700188 int n_recursive_constrained;
Neale Ranns57b58602017-07-15 07:37:25 -0700189 u16 preference;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100190} fib_entry_src_collect_forwarding_ctx_t;
191
192/**
193 * @brief Determine whether this FIB entry should use a load-balance MAP
194 * to support PIC edge fast convergence
195 */
196load_balance_flags_t
197fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx)
198{
199 /**
Neale Rannsf12a83f2017-04-18 09:09:40 -0700200 * We'll use a LB map if the path-list has multiple recursive paths.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100201 * recursive paths implies BGP, and hence scale.
202 */
Neale Rannsf12a83f2017-04-18 09:09:40 -0700203 if (ctx->n_recursive_constrained > 1 &&
204 fib_path_list_is_popular(ctx->esrc->fes_pl))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100205 {
206 return (LOAD_BALANCE_FLAG_USES_MAP);
207 }
208 return (LOAD_BALANCE_FLAG_NONE);
209}
210
211static int
212fib_entry_src_valid_out_label (mpls_label_t label)
213{
214 return ((MPLS_LABEL_IS_REAL(label) ||
Neale Ranns31ed7442018-02-23 05:29:09 -0800215 MPLS_LABEL_POP == label ||
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100216 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
217 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
218 MPLS_IETF_IMPLICIT_NULL_LABEL == label));
219}
220
Neale Rannsad422ed2016-11-02 14:20:04 +0000221/**
222 * @brief Turn the chain type requested by the client into the one they
223 * really wanted
224 */
225fib_forward_chain_type_t
226fib_entry_chain_type_fixup (const fib_entry_t *entry,
227 fib_forward_chain_type_t fct)
228{
Neale Rannsad422ed2016-11-02 14:20:04 +0000229 /*
230 * The EOS chain is a tricky since one cannot know the adjacency
231 * to link to without knowing what the packets payload protocol
232 * will be once the label is popped.
233 */
234 fib_forward_chain_type_t dfct;
235
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800236 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
237 {
238 return (fct);
239 }
240
Neale Rannsad422ed2016-11-02 14:20:04 +0000241 dfct = fib_entry_get_default_chain_type(entry);
242
243 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
244 {
245 /*
246 * If the entry being asked is a eos-MPLS label entry,
247 * then use the payload-protocol field, that we stashed there
248 * for just this purpose
249 */
250 return (fib_forw_chain_type_from_dpo_proto(
251 entry->fe_prefix.fp_payload_proto));
252 }
253 /*
254 * else give them what this entry would be by default. i.e. if it's a v6
255 * entry, then the label its local labelled should be carrying v6 traffic.
256 * If it's a non-EOS label entry, then there are more labels and we want
257 * a non-eos chain.
258 */
259 return (dfct);
260}
261
Neale Ranns62fe07c2017-10-31 12:28:22 -0700262static dpo_proto_t
263fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
264{
265 switch (pfx->fp_proto)
266 {
267 case FIB_PROTOCOL_IP4:
268 return (DPO_PROTO_IP4);
269 case FIB_PROTOCOL_IP6:
270 return (DPO_PROTO_IP6);
271 case FIB_PROTOCOL_MPLS:
272 return (pfx->fp_payload_proto);
273 }
274
275 ASSERT(0);
276 return (DPO_PROTO_IP4);
277}
278
Neale Ranns81424992017-05-18 03:03:22 -0700279static void
280fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
281 fib_entry_src_collect_forwarding_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282{
Neale Ranns81424992017-05-18 03:03:22 -0700283 load_balance_path_t *nh;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284
285 /*
Neale Ranns81424992017-05-18 03:03:22 -0700286 * no extension => no out-going label for this path. that's OK
287 * in the case of an IP or EOS chain, but not for non-EOS
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100288 */
Neale Ranns81424992017-05-18 03:03:22 -0700289 switch (ctx->fct)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100290 {
Neale Ranns81424992017-05-18 03:03:22 -0700291 case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
292 case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
293 case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
294 case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
Neale Rannsd792d9c2017-10-21 10:53:20 -0700295 case FIB_FORW_CHAIN_TYPE_BIER:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100296 /*
Neale Ranns81424992017-05-18 03:03:22 -0700297 * EOS traffic with no label to stack, we need the IP Adj
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298 */
Neale Ranns81424992017-05-18 03:03:22 -0700299 vec_add2(ctx->next_hops, nh, 1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100300
Neale Ranns81424992017-05-18 03:03:22 -0700301 nh->path_index = path_index;
302 nh->path_weight = fib_path_get_weight(path_index);
303 fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
304
305 break;
306 case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
307 if (fib_path_is_exclusive(path_index) ||
308 fib_path_is_deag(path_index))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100309 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100310 vec_add2(ctx->next_hops, nh, 1);
311
312 nh->path_index = path_index;
313 nh->path_weight = fib_path_get_weight(path_index);
Neale Ranns81424992017-05-18 03:03:22 -0700314 fib_path_contribute_forwarding(path_index,
315 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
316 &nh->path_dpo);
317 }
318 break;
319 case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
Neale Rannsad422ed2016-11-02 14:20:04 +0000320 {
321 /*
322 * no label. we need a chain based on the payload. fixup.
323 */
324 vec_add2(ctx->next_hops, nh, 1);
325
326 nh->path_index = path_index;
327 nh->path_weight = fib_path_get_weight(path_index);
328 fib_path_contribute_forwarding(path_index,
329 fib_entry_chain_type_fixup(ctx->fib_entry,
330 ctx->fct),
331 &nh->path_dpo);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800332 fib_path_stack_mpls_disp(path_index,
Neale Ranns62fe07c2017-10-31 12:28:22 -0700333 fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
Neale Ranns31ed7442018-02-23 05:29:09 -0800334 FIB_MPLS_LSP_MODE_PIPE,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800335 &nh->path_dpo);
Neale Rannsad422ed2016-11-02 14:20:04 +0000336
337 break;
338 }
Neale Ranns81424992017-05-18 03:03:22 -0700339 case FIB_FORW_CHAIN_TYPE_ETHERNET:
340 case FIB_FORW_CHAIN_TYPE_NSH:
341 ASSERT(0);
342 break;
343 }
344}
345
346static fib_path_list_walk_rc_t
347fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
348 fib_node_index_t path_index,
349 void *arg)
350{
351 fib_entry_src_collect_forwarding_ctx_t *ctx;
352 fib_path_ext_t *path_ext;
353
354 ctx = arg;
355
356 /*
357 * if the path is not resolved, don't include it.
358 */
359 if (!fib_path_is_resolved(path_index))
360 {
361 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100362 }
363
Neale Ranns81424992017-05-18 03:03:22 -0700364 if (fib_path_is_recursive_constrained(path_index))
365 {
366 ctx->n_recursive_constrained += 1;
367 }
Neale Ranns57b58602017-07-15 07:37:25 -0700368 if (0xffff == ctx->preference)
369 {
370 /*
371 * not set a preference yet, so the first path we encounter
372 * sets the preference we are collecting.
373 */
374 ctx->preference = fib_path_get_preference(path_index);
375 }
376 else if (ctx->preference != fib_path_get_preference(path_index))
377 {
378 /*
379 * this path does not belong to the same preference as the
380 * previous paths encountered. we are done now.
381 */
382 return (FIB_PATH_LIST_WALK_STOP);
383 }
Neale Ranns81424992017-05-18 03:03:22 -0700384
385 /*
386 * get the matching path-extension for the path being visited.
387 */
388 path_ext = fib_path_ext_list_find_by_path_index(&ctx->esrc->fes_path_exts,
389 path_index);
390
391 if (NULL != path_ext)
392 {
393 switch (path_ext->fpe_type)
394 {
395 case FIB_PATH_EXT_MPLS:
Neale Ranns31ed7442018-02-23 05:29:09 -0800396 if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0].fml_value))
Neale Ranns81424992017-05-18 03:03:22 -0700397 {
398 /*
399 * found a matching extension. stack it to obtain the forwarding
400 * info for this path.
401 */
402 ctx->next_hops =
403 fib_path_ext_stack(path_ext,
404 ctx->fct,
405 fib_entry_chain_type_fixup(ctx->fib_entry,
406 ctx->fct),
407 ctx->next_hops);
408 }
409 else
410 {
411 fib_entry_src_get_path_forwarding(path_index, ctx);
412 }
413 break;
414 case FIB_PATH_EXT_ADJ:
415 if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
416 {
417 fib_entry_src_get_path_forwarding(path_index, ctx);
418 }
419 /*
420 * else
421 * the path does not refine the cover, meaning that
422 * the adjacency doesdoes not match the sub-net on the link.
423 * So this path does not contribute forwarding.
424 */
425 break;
426 }
427 }
428 else
429 {
430 fib_entry_src_get_path_forwarding(path_index, ctx);
431 }
432
433 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100434}
435
436void
437fib_entry_src_mk_lb (fib_entry_t *fib_entry,
438 const fib_entry_src_t *esrc,
439 fib_forward_chain_type_t fct,
440 dpo_id_t *dpo_lb)
441{
442 dpo_proto_t lb_proto;
443
444 /*
445 * If the entry has path extensions then we construct a load-balance
446 * by stacking the extensions on the forwarding chains of the paths.
447 * Otherwise we use the load-balance of the path-list
448 */
449 fib_entry_src_collect_forwarding_ctx_t ctx = {
450 .esrc = esrc,
451 .fib_entry = fib_entry,
452 .next_hops = NULL,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700453 .n_recursive_constrained = 0,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 .fct = fct,
Neale Ranns57b58602017-07-15 07:37:25 -0700455 .preference = 0xffff,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100456 };
457
Neale Rannsc0790cf2017-01-05 01:01:47 -0800458 /*
459 * As an optimisation we allocate the vector of next-hops to be sized
460 * equal to the maximum nuber of paths we will need, which is also the
461 * most likely number we will need, since in most cases the paths are 'up'.
462 */
463 vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
464 vec_reset_length(ctx.next_hops);
465
Neale Rannsf12a83f2017-04-18 09:09:40 -0700466 lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100467
468 fib_path_list_walk(esrc->fes_pl,
469 fib_entry_src_collect_forwarding,
470 &ctx);
471
472 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
473 {
474 /*
475 * the client provided the DPO that the entry should link to.
476 * all entries must link to a LB, so if it is an LB already
477 * then we can use it.
478 */
479 if ((1 == vec_len(ctx.next_hops)) &&
480 (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
481 {
482 dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
483 dpo_reset(&ctx.next_hops[0].path_dpo);
484 return;
485 }
486 }
487
488 if (!dpo_id_is_valid(dpo_lb))
489 {
490 /*
491 * first time create
492 */
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800493 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
494 {
495 dpo_set(dpo_lb,
496 DPO_REPLICATE,
497 lb_proto,
498 MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
499 }
500 else
501 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700502 fib_protocol_t flow_hash_proto;
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800503 flow_hash_config_t fhc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100504
Neale Ranns41da54f2017-05-02 10:15:19 -0700505 /*
506 * if the protocol for the LB we are building does not match that
507 * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
508 * then the fib_index is not an index that relates to the table
509 * type we need. So get the default flow-hash config instead.
510 */
Neale Rannsd792d9c2017-10-21 10:53:20 -0700511 flow_hash_proto = dpo_proto_to_fib(lb_proto);
512 if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
Neale Ranns41da54f2017-05-02 10:15:19 -0700513 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700514 fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700515 }
516 else
517 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700518 fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
519 flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700520 }
Neale Rannsd792d9c2017-10-21 10:53:20 -0700521
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800522 dpo_set(dpo_lb,
523 DPO_LOAD_BALANCE,
524 lb_proto,
525 load_balance_create(0, lb_proto, fhc));
526 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100527 }
528
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800529 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
Neale Ranns3ee44042016-10-03 13:05:48 +0100530 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800531 /*
532 * MPLS multicast
533 */
534 replicate_multipath_update(dpo_lb, ctx.next_hops);
Neale Ranns3ee44042016-10-03 13:05:48 +0100535 }
536 else
537 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800538 load_balance_multipath_update(dpo_lb,
539 ctx.next_hops,
540 fib_entry_calc_lb_flags(&ctx));
541 vec_free(ctx.next_hops);
542
543 /*
544 * if this entry is sourced by the uRPF-exempt source then we
545 * append the always present local0 interface (index 0) to the
546 * uRPF list so it is not empty. that way packets pass the loose check.
547 */
548 index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
549
550 if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
551 FIB_SOURCE_URPF_EXEMPT) ||
552 (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
553 (0 == fib_urpf_check_size(ui)))
554 {
555 /*
556 * The uRPF list we get from the path-list is shared by all
557 * other users of the list, but the uRPF exemption applies
558 * only to this prefix. So we need our own list.
559 */
560 ui = fib_urpf_list_alloc_and_lock();
561 fib_urpf_list_append(ui, 0);
562 fib_urpf_list_bake(ui);
563 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
564 fib_urpf_list_unlock(ui);
565 }
566 else
567 {
568 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
569 }
570 load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
571 fib_entry_get_flags_i(fib_entry));
Neale Ranns3ee44042016-10-03 13:05:48 +0100572 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100573}
574
575void
576fib_entry_src_action_install (fib_entry_t *fib_entry,
577 fib_source_t source)
578{
579 /*
580 * Install the forwarding chain for the given source into the forwarding
581 * tables
582 */
583 fib_forward_chain_type_t fct;
584 fib_entry_src_t *esrc;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100585 int insert;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100586
587 fct = fib_entry_get_default_chain_type(fib_entry);
588 esrc = fib_entry_src_find(fib_entry, source, NULL);
589
Neale Ranns33a7dd52016-10-07 15:14:33 +0100590 /*
591 * Every entry has its own load-balance object. All changes to the entry's
592 * forwarding result in an inplace modify of the load-balance. This means
593 * the load-balance object only needs to be added to the forwarding
594 * DB once, when it is created.
595 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000596 insert = !dpo_id_is_valid(&fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100597
Neale Rannsad422ed2016-11-02 14:20:04 +0000598 fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100599
Neale Rannsad422ed2016-11-02 14:20:04 +0000600 ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
601 FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100602
603 /*
604 * insert the adj into the data-plane forwarding trie
605 */
Neale Ranns33a7dd52016-10-07 15:14:33 +0100606 if (insert)
607 {
608 fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
609 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000610 &fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100611 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100612
Neale Rannsad422ed2016-11-02 14:20:04 +0000613 /*
614 * if any of the other chain types are already created they will need
615 * updating too
616 */
617 fib_entry_delegate_type_t fdt;
618 fib_entry_delegate_t *fed;
619
620 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100621 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000622 fib_entry_src_mk_lb(fib_entry, esrc,
623 fib_entry_delegate_type_to_chain_type(fdt),
624 &fed->fd_dpo);
625 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100626}
627
628void
629fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
630{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100631 /*
Neale Ranns3ee44042016-10-03 13:05:48 +0100632 * uninstall the forwarding chain from the forwarding tables
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100633 */
634 FIB_ENTRY_DBG(fib_entry, "uninstall: %d",
635 fib_entry->fe_adj_index);
636
Neale Rannsad422ed2016-11-02 14:20:04 +0000637 if (dpo_id_is_valid(&fib_entry->fe_lb))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100639 fib_table_fwding_dpo_remove(
640 fib_entry->fe_fib_index,
641 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000642 &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100643
Neale Rannsad422ed2016-11-02 14:20:04 +0000644 dpo_reset(&fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100645 }
646}
647
648static void
649fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
650{
651 fib_node_index_t *entries = NULL;
652
653 fib_path_list_recursive_loop_detect(path_list_index, &entries);
654
655 vec_free(entries);
656}
657
Neale Ranns89541992017-04-06 04:41:02 -0700658/*
659 * fib_entry_src_action_copy
660 *
661 * copy a source data from another entry to this one
662 */
663fib_entry_t *
664fib_entry_src_action_copy (fib_entry_t *fib_entry,
665 const fib_entry_src_t *orig_src)
666{
667 fib_entry_src_t *esrc;
668
669 esrc = fib_entry_src_find_or_create(fib_entry, orig_src->fes_src);
670
671 *esrc = *orig_src;
672 esrc->fes_ref_count = 1;
673 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_INHERITED;
674 esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
675 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
676
677 /*
678 * the source owns a lock on the entry
679 */
680 fib_path_list_lock(esrc->fes_pl);
681 fib_entry_lock(fib_entry_get_index(fib_entry));
682
683 return (fib_entry);
684}
685
686/*
687 * fib_entry_src_action_update
688 *
689 * copy a source data from another entry to this one
690 */
691static fib_entry_src_t *
692fib_entry_src_action_update_from_cover (fib_entry_t *fib_entry,
693 const fib_entry_src_t *orig_src)
694{
695 fib_entry_src_t *esrc;
696
697 esrc = fib_entry_src_find_or_create(fib_entry, orig_src->fes_src);
698
699 /*
700 * the source owns a lock on the entry
701 */
702 fib_path_list_unlock(esrc->fes_pl);
703 esrc->fes_pl = orig_src->fes_pl;
704 fib_path_list_lock(esrc->fes_pl);
705
706 return (esrc);
707}
708
709static fib_table_walk_rc_t
710fib_entry_src_covered_inherit_add_i (fib_entry_t *fib_entry,
711 const fib_entry_src_t *cover_src)
712{
713 fib_entry_src_t *esrc;
714
715 esrc = fib_entry_src_find(fib_entry, cover_src->fes_src, NULL);
716
717 if (cover_src == esrc)
718 {
719 return (FIB_TABLE_WALK_CONTINUE);
720 }
721
722 if (NULL != esrc)
723 {
724 /*
725 * the covered entry already has this source.
726 */
727 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
728 {
729 /*
730 * the covered source is itself a COVERED_INHERIT, i.e.
731 * it also pushes this source down the sub-tree.
732 * We consider this more specfic covered to be the owner
733 * of the sub-tree from this point down.
734 */
735 return (FIB_TABLE_WALK_SUB_TREE_STOP);
736 }
737 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
738 {
739 /*
740 * The covered's source data has been inherited, presumably
741 * from this cover, i.e. this is a modify.
742 */
743 esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
744 fib_entry_source_change(fib_entry, esrc->fes_src, esrc->fes_src);
745 }
746 else
747 {
748 /*
749 * The covered's source was not inherited and it is also
750 * not inherting. Nevertheless, it still owns the sub-tree from
751 * this point down.
752 */
753 return (FIB_TABLE_WALK_SUB_TREE_STOP);
754 }
755 }
756 else
757 {
758 /*
759 * The covered does not have this source - add it.
760 */
761 fib_source_t best_source;
762
763 best_source = fib_entry_get_best_source(
764 fib_entry_get_index(fib_entry));
765
766 fib_entry_src_action_copy(fib_entry, cover_src);
767 fib_entry_source_change(fib_entry, best_source, cover_src->fes_src);
768
769 }
770 return (FIB_TABLE_WALK_CONTINUE);
771}
772
773static fib_table_walk_rc_t
774fib_entry_src_covered_inherit_walk_add (fib_node_index_t fei,
775 void *ctx)
776{
777 return (fib_entry_src_covered_inherit_add_i(fib_entry_get(fei), ctx));
778}
779
780static fib_table_walk_rc_t
781fib_entry_src_covered_inherit_walk_remove (fib_node_index_t fei,
782 void *ctx)
783{
784 fib_entry_src_t *cover_src, *esrc;
785 fib_entry_t *fib_entry;
786
787 fib_entry = fib_entry_get(fei);
788
789 cover_src = ctx;
790 esrc = fib_entry_src_find(fib_entry, cover_src->fes_src, NULL);
791
792 if (cover_src == esrc)
793 {
794 return (FIB_TABLE_WALK_CONTINUE);
795 }
796
797 if (NULL != esrc)
798 {
799 /*
800 * the covered entry already has this source.
801 */
802 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
803 {
804 /*
805 * the covered source is itself a COVERED_INHERIT, i.e.
806 * it also pushes this source down the sub-tree.
807 * We consider this more specfic covered to be the owner
808 * of the sub-tree from this point down.
809 */
810 return (FIB_TABLE_WALK_SUB_TREE_STOP);
811 }
812 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
813 {
814 /*
815 * The covered's source data has been inherited, presumably
816 * from this cover
817 */
818 fib_entry_src_flag_t remaining;
819
820 remaining = fib_entry_special_remove(fei, cover_src->fes_src);
821
822 ASSERT(FIB_ENTRY_SRC_FLAG_ADDED == remaining);
823 }
824 else
825 {
826 /*
827 * The covered's source was not inherited and it is also
828 * not inherting. Nevertheless, it still owns the sub-tree from
829 * this point down.
830 */
831 return (FIB_TABLE_WALK_SUB_TREE_STOP);
832 }
833 }
834 else
835 {
836 /*
837 * The covered does not have this source - that's an error,
838 * since it should have inherited, but there is nothing we can do
839 * about it now.
840 */
841 }
842 return (FIB_TABLE_WALK_CONTINUE);
843}
844
845void
846fib_entry_src_inherit (const fib_entry_t *cover,
847 fib_entry_t *covered)
848{
849 CLIB_UNUSED(fib_source_t source);
850 const fib_entry_src_t *src;
851
852 FOR_EACH_SRC_ADDED(cover, src, source,
853 ({
854 if ((src->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
855 (src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
856 {
857 fib_entry_src_covered_inherit_add_i(covered, src);
858 }
859 }))
860}
861
862static void
863fib_entry_src_covered_inherit_add (fib_entry_t *fib_entry,
864 fib_source_t source)
865
866{
867 fib_entry_src_t *esrc;
868
869 esrc = fib_entry_src_find(fib_entry, source, NULL);
870
871 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
872
873 if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
874 (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
875 {
876 fib_table_sub_tree_walk(fib_entry->fe_fib_index,
877 fib_entry->fe_prefix.fp_proto,
878 &fib_entry->fe_prefix,
879 fib_entry_src_covered_inherit_walk_add,
880 esrc);
881 }
882}
883
884static void
885fib_entry_src_covered_inherit_remove (fib_entry_t *fib_entry,
886 fib_entry_src_t *esrc)
887
888{
889 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
890
891 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
892 {
893 fib_table_sub_tree_walk(fib_entry->fe_fib_index,
894 fib_entry->fe_prefix.fp_proto,
895 &fib_entry->fe_prefix,
896 fib_entry_src_covered_inherit_walk_remove,
897 esrc);
898 }
899}
900
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100901void
902fib_entry_src_action_activate (fib_entry_t *fib_entry,
903 fib_source_t source)
904
905{
906 int houston_we_are_go_for_install;
907 fib_entry_src_t *esrc;
908
909 esrc = fib_entry_src_find(fib_entry, source, NULL);
910
911 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
912 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
913
914 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ACTIVE;
915
916 if (NULL != fib_entry_src_vft[source].fesv_activate)
917 {
918 houston_we_are_go_for_install =
919 fib_entry_src_vft[source].fesv_activate(esrc, fib_entry);
920 }
921 else
922 {
923 /*
924 * the source is not providing an activate function, we'll assume
925 * therefore it has no objection to installing the entry
926 */
927 houston_we_are_go_for_install = !0;
928 }
929
930 /*
931 * link to the path-list provided by the source, and go check
932 * if that forms any loops in the graph.
933 */
934 fib_entry->fe_parent = esrc->fes_pl;
935 fib_entry->fe_sibling =
936 fib_path_list_child_add(fib_entry->fe_parent,
937 FIB_NODE_TYPE_ENTRY,
938 fib_entry_get_index(fib_entry));
939
940 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
941
942 FIB_ENTRY_DBG(fib_entry, "activate: %d",
943 fib_entry->fe_parent);
944
Neale Ranns89541992017-04-06 04:41:02 -0700945 /*
946 * If this source should push its state to covered prefixs, do that now.
947 */
948 fib_entry_src_covered_inherit_add(fib_entry, source);
949
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100950 if (0 != houston_we_are_go_for_install)
951 {
952 fib_entry_src_action_install(fib_entry, source);
953 }
954 else
955 {
956 fib_entry_src_action_uninstall(fib_entry);
957 }
958}
959
960void
961fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
962 fib_source_t source)
963
964{
965 fib_node_index_t path_list_index;
966 fib_entry_src_t *esrc;
967
968 esrc = fib_entry_src_find(fib_entry, source, NULL);
969
970 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
971
972 if (NULL != fib_entry_src_vft[source].fesv_deactivate)
973 {
974 fib_entry_src_vft[source].fesv_deactivate(esrc, fib_entry);
975 }
976
977 esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
978
979 FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
980
981 /*
Neale Ranns89541992017-04-06 04:41:02 -0700982 * If this source should pull its state from covered prefixs, do that now.
983 * If this source also has the INHERITED flag set then it has a cover
984 * that wants to push down forwarding. We only want the covereds to see
985 * one update.
986 */
987 fib_entry_src_covered_inherit_remove(fib_entry, esrc);
988
989 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100990 * un-link from an old path-list. Check for any loops this will clear
991 */
992 path_list_index = fib_entry->fe_parent;
993 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
994
995 fib_entry_recursive_loop_detect_i(path_list_index);
996
997 /*
998 * this will unlock the path-list, so it may be invalid thereafter.
999 */
1000 fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
1001 fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
1002}
1003
Neale Rannsa4e77662017-12-04 20:00:30 +00001004static void
1005fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
1006 fib_source_t source)
1007{
1008 fib_entry_src_t *esrc;
1009
1010 vec_foreach(esrc, fib_entry->fe_srcs)
1011 {
1012 if (NULL != fib_entry_src_vft[esrc->fes_src].fesv_fwd_update)
1013 {
1014 fib_entry_src_vft[esrc->fes_src].fesv_fwd_update(esrc,
1015 fib_entry,
1016 source);
1017 }
1018 }
1019}
1020
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001021void
1022fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
1023 fib_source_t source)
1024{
1025 fib_node_index_t path_list_index;
1026 fib_entry_src_t *esrc;
1027
1028 esrc = fib_entry_src_find(fib_entry, source, NULL);
1029
1030 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1031
1032 FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
1033 fib_entry->fe_parent,
1034 esrc->fes_pl);
1035
1036 if (fib_entry->fe_parent != esrc->fes_pl)
1037 {
Neale Ranns89541992017-04-06 04:41:02 -07001038 int remain_installed;
1039
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001040 /*
1041 * un-link from an old path-list. Check for any loops this will clear
1042 */
1043 path_list_index = fib_entry->fe_parent;
1044 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1045
1046 /*
1047 * temporary lock so it doesn't get deleted when this entry is no
1048 * longer a child.
1049 */
1050 fib_path_list_lock(path_list_index);
1051
1052 /*
1053 * this entry is no longer a child. after unlinking check if any loops
1054 * were broken
1055 */
1056 fib_path_list_child_remove(path_list_index,
1057 fib_entry->fe_sibling);
1058
1059 fib_entry_recursive_loop_detect_i(path_list_index);
1060
1061 /*
1062 * link to the path-list provided by the source, and go check
1063 * if that forms any loops in the graph.
1064 */
1065 fib_entry->fe_parent = esrc->fes_pl;
1066 fib_entry->fe_sibling =
1067 fib_path_list_child_add(fib_entry->fe_parent,
1068 FIB_NODE_TYPE_ENTRY,
1069 fib_entry_get_index(fib_entry));
1070
1071 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1072 fib_path_list_unlock(path_list_index);
Neale Ranns89541992017-04-06 04:41:02 -07001073
1074 /*
1075 * call the source to reactive and get the go/no-go to remain installed
1076 */
1077 if (NULL != fib_entry_src_vft[source].fesv_reactivate)
1078 {
1079 remain_installed =
1080 fib_entry_src_vft[source].fesv_reactivate(esrc, fib_entry);
1081 }
1082 else
1083 {
1084 remain_installed = 1;
1085 }
1086
1087 /*
1088 * If this source should push its state to covered prefixs, do that now.
1089 */
1090 fib_entry_src_covered_inherit_add(fib_entry, source);
1091
1092 if (!remain_installed)
1093 {
1094 fib_entry_src_action_uninstall(fib_entry);
1095 return;
1096 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001097 }
1098 fib_entry_src_action_install(fib_entry, source);
Neale Rannsa4e77662017-12-04 20:00:30 +00001099 fib_entry_src_action_fwd_update(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001100}
1101
1102void
Neale Rannsa4e77662017-12-04 20:00:30 +00001103fib_entry_src_action_installed (const fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001104 fib_source_t source)
1105{
1106 fib_entry_src_t *esrc;
1107
1108 esrc = fib_entry_src_find(fib_entry, source, NULL);
1109
1110 if (NULL != fib_entry_src_vft[source].fesv_installed)
1111 {
1112 fib_entry_src_vft[source].fesv_installed(esrc,
1113 fib_entry);
1114 }
Neale Rannsa4e77662017-12-04 20:00:30 +00001115
1116 fib_entry_src_action_fwd_update(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001117}
1118
1119/*
1120 * fib_entry_src_action_add
1121 *
1122 * Adding a source can result in a new fib_entry being created, which
1123 * can inturn mean the pool is realloc'd and thus the entry passed as
1124 * an argument it also realloc'd
1125 * @return the original entry
1126 */
1127fib_entry_t *
1128fib_entry_src_action_add (fib_entry_t *fib_entry,
1129 fib_source_t source,
1130 fib_entry_flag_t flags,
1131 const dpo_id_t *dpo)
1132{
1133 fib_node_index_t fib_entry_index;
1134 fib_entry_src_t *esrc;
1135
Neale Ranns89541992017-04-06 04:41:02 -07001136 esrc = fib_entry_src_find_or_create(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001137
1138 esrc->fes_ref_count++;
1139
1140 if (1 != esrc->fes_ref_count)
1141 {
1142 /*
1143 * we only want to add the source on the 0->1 transition
1144 */
1145 return (fib_entry);
1146 }
1147
1148 esrc->fes_entry_flags = flags;
1149
1150 /*
1151 * save variable so we can recover from a fib_entry realloc.
1152 */
1153 fib_entry_index = fib_entry_get_index(fib_entry);
1154
1155 if (NULL != fib_entry_src_vft[source].fesv_add)
1156 {
1157 fib_entry_src_vft[source].fesv_add(esrc,
1158 fib_entry,
1159 flags,
Neale Rannsda78f952017-05-24 09:15:43 -07001160 fib_entry_get_dpo_proto(fib_entry),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001161 dpo);
1162 }
1163
1164 fib_entry = fib_entry_get(fib_entry_index);
1165
1166 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1167
1168 fib_path_list_lock(esrc->fes_pl);
1169
1170 /*
1171 * the source owns a lock on the entry
1172 */
1173 fib_entry_lock(fib_entry_get_index(fib_entry));
1174
1175 return (fib_entry);
1176}
1177
Neale Ranns948e00f2016-10-20 13:39:34 +01001178/*
1179 * fib_entry_src_action_update
1180 *
1181 * Adding a source can result in a new fib_entry being created, which
1182 * can inturn mean the pool is realloc'd and thus the entry passed as
1183 * an argument it also realloc'd
1184 * @return the original entry
1185 */
1186fib_entry_t *
1187fib_entry_src_action_update (fib_entry_t *fib_entry,
1188 fib_source_t source,
1189 fib_entry_flag_t flags,
1190 const dpo_id_t *dpo)
1191{
1192 fib_node_index_t fib_entry_index, old_path_list_index;
1193 fib_entry_src_t *esrc;
1194
Neale Ranns89541992017-04-06 04:41:02 -07001195 esrc = fib_entry_src_find_or_create(fib_entry, source);
Neale Ranns948e00f2016-10-20 13:39:34 +01001196
1197 if (NULL == esrc)
Neale Ranns89541992017-04-06 04:41:02 -07001198 {
Neale Ranns948e00f2016-10-20 13:39:34 +01001199 return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
Neale Ranns89541992017-04-06 04:41:02 -07001200 }
Neale Ranns948e00f2016-10-20 13:39:34 +01001201
1202 old_path_list_index = esrc->fes_pl;
1203 esrc->fes_entry_flags = flags;
1204
1205 /*
1206 * save variable so we can recover from a fib_entry realloc.
1207 */
1208 fib_entry_index = fib_entry_get_index(fib_entry);
1209
1210 if (NULL != fib_entry_src_vft[source].fesv_add)
1211 {
1212 fib_entry_src_vft[source].fesv_add(esrc,
1213 fib_entry,
1214 flags,
Neale Rannsda78f952017-05-24 09:15:43 -07001215 fib_entry_get_dpo_proto(fib_entry),
Neale Ranns948e00f2016-10-20 13:39:34 +01001216 dpo);
1217 }
1218
1219 fib_entry = fib_entry_get(fib_entry_index);
1220
1221 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1222
1223 fib_path_list_lock(esrc->fes_pl);
1224 fib_path_list_unlock(old_path_list_index);
1225
1226 return (fib_entry);
1227}
1228
Neale Ranns89541992017-04-06 04:41:02 -07001229fib_entry_src_flag_t
1230fib_entry_src_action_remove_or_update_inherit (fib_entry_t *fib_entry,
1231 fib_source_t source)
1232{
1233 fib_entry_src_t *esrc;
1234
1235 esrc = fib_entry_src_find(fib_entry, source, NULL);
1236
1237 if (NULL == esrc)
1238 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1239
1240 if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) &&
1241 (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
1242 {
1243 fib_entry_src_t *cover_src;
1244 fib_node_index_t coveri;
1245 fib_entry_t *cover;
1246
1247 /*
1248 * this source was pushing inherited state, but so is its
1249 * cover. Now that this source is going away, we need to
1250 * pull the covers forwarding and use it to update the covereds.
1251 * Go grab the path-list from the cover, rather than start a walk from
1252 * the cover, so we don't recursively update this entry.
1253 */
1254 coveri = fib_table_get_less_specific(fib_entry->fe_fib_index,
1255 &fib_entry->fe_prefix);
1256
1257 /*
1258 * only the default route has itself as its own cover, but the
1259 * default route cannot have inherited from something else.
1260 */
1261 ASSERT(coveri != fib_entry_get_index(fib_entry));
1262
1263 cover = fib_entry_get(coveri);
1264 cover_src = fib_entry_src_find(cover, source, NULL);
1265
1266 ASSERT(NULL != cover_src);
1267
1268 esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
1269 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
1270
1271 /*
1272 * Now push the new state from the cover down to the covereds
1273 */
1274 fib_entry_src_covered_inherit_add(fib_entry, source);
1275
1276 return (esrc->fes_flags);
1277 }
1278 else
1279 {
1280 return (fib_entry_src_action_remove(fib_entry, source));
1281 }
1282}
Neale Ranns948e00f2016-10-20 13:39:34 +01001283
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001284fib_entry_src_flag_t
1285fib_entry_src_action_remove (fib_entry_t *fib_entry,
1286 fib_source_t source)
1287
1288{
1289 fib_node_index_t old_path_list;
1290 fib_entry_src_flag_t sflags;
1291 fib_entry_src_t *esrc;
1292
1293 esrc = fib_entry_src_find(fib_entry, source, NULL);
1294
1295 if (NULL == esrc)
1296 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1297
1298 esrc->fes_ref_count--;
1299 sflags = esrc->fes_flags;
1300
1301 if (0 != esrc->fes_ref_count)
1302 {
1303 /*
1304 * only remove the source on the 1->0 transisition
1305 */
1306 return (sflags);
1307 }
1308
1309 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
1310 {
Neale Ranns89541992017-04-06 04:41:02 -07001311 fib_entry_src_action_deactivate(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001312 }
1313
1314 old_path_list = esrc->fes_pl;
1315
1316 if (NULL != fib_entry_src_vft[source].fesv_remove)
1317 {
1318 fib_entry_src_vft[source].fesv_remove(esrc);
1319 }
1320
1321 fib_path_list_unlock(old_path_list);
1322 fib_entry_unlock(fib_entry_get_index(fib_entry));
1323
1324 sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
1325 fib_entry_src_action_deinit(fib_entry, source);
1326
1327 return (sflags);
1328}
1329
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001330/*
1331 * fib_route_attached_cross_table
1332 *
1333 * Return true the the route is attached via an interface that
1334 * is not in the same table as the route
1335 */
1336static inline int
1337fib_route_attached_cross_table (const fib_entry_t *fib_entry,
1338 const fib_route_path_t *rpath)
1339{
1340 /*
1341 * - All zeros next-hop
1342 * - a valid interface
1343 * - entry's fib index not equeal to interface's index
1344 */
1345 if (ip46_address_is_zero(&rpath->frp_addr) &&
1346 (~0 != rpath->frp_sw_if_index) &&
Neale Rannseca834e2018-03-13 07:51:50 -07001347 !(rpath->frp_flags & FIB_ROUTE_PATH_DVR) &&
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001348 (fib_entry->fe_fib_index !=
1349 fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
1350 rpath->frp_sw_if_index)))
1351 {
1352 return (!0);
1353 }
1354 return (0);
1355}
1356
1357/*
Neale Ranns53da2212018-02-24 02:11:19 -08001358 * Return true if the path is attached
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001359 */
1360static inline int
1361fib_path_is_attached (const fib_route_path_t *rpath)
1362{
1363 /*
Neale Rannseca834e2018-03-13 07:51:50 -07001364 * DVR paths are not attached, since we are not playing the
1365 * L3 game with these
1366 */
1367 if (rpath->frp_flags & FIB_ROUTE_PATH_DVR)
1368 {
1369 return (0);
1370 }
1371
1372 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001373 * - All zeros next-hop
1374 * - a valid interface
1375 */
1376 if (ip46_address_is_zero(&rpath->frp_addr) &&
1377 (~0 != rpath->frp_sw_if_index))
1378 {
1379 return (!0);
1380 }
Neale Ranns4b919a52017-03-11 05:55:21 -08001381 else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
1382 {
1383 return (!0);
1384 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001385 return (0);
1386}
1387
1388fib_path_list_flags_t
1389fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
1390{
1391 fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
1392
1393 if (eflags & FIB_ENTRY_FLAG_DROP)
1394 {
1395 plf |= FIB_PATH_LIST_FLAG_DROP;
1396 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001397 if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
1398 {
1399 plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
1400 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001401 if (eflags & FIB_ENTRY_FLAG_LOCAL)
1402 {
1403 plf |= FIB_PATH_LIST_FLAG_LOCAL;
1404 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001405
1406 return (plf);
1407}
1408
1409static void
1410fib_entry_flags_update (const fib_entry_t *fib_entry,
1411 const fib_route_path_t *rpath,
1412 fib_path_list_flags_t *pl_flags,
1413 fib_entry_src_t *esrc)
1414{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001415 if ((esrc->fes_src == FIB_SOURCE_API) ||
1416 (esrc->fes_src == FIB_SOURCE_CLI))
1417 {
1418 if (fib_path_is_attached(rpath))
1419 {
1420 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1421 }
1422 else
1423 {
1424 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1425 }
Florin Coras79ae2d32017-12-16 08:31:06 -08001426 if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
1427 {
1428 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT;
1429 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001430 }
Neale Ranns53da2212018-02-24 02:11:19 -08001431 if (fib_route_attached_cross_table(fib_entry, rpath) &&
1432 !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001433 {
1434 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1435 }
1436 else
1437 {
1438 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1439 }
1440}
1441
1442/*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001443 * fib_entry_src_action_add
1444 *
1445 * Adding a source can result in a new fib_entry being created, which
1446 * can inturn mean the pool is realloc'd and thus the entry passed as
1447 * an argument it also realloc'd
1448 * @return the entry
1449 */
1450fib_entry_t*
1451fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1452 fib_source_t source,
1453 fib_entry_flag_t flags,
1454 const fib_route_path_t *rpath)
1455{
1456 fib_node_index_t old_path_list, fib_entry_index;
1457 fib_path_list_flags_t pl_flags;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001458 fib_entry_src_t *esrc;
1459
1460 /*
1461 * save variable so we can recover from a fib_entry realloc.
1462 */
1463 fib_entry_index = fib_entry_get_index(fib_entry);
1464
1465 esrc = fib_entry_src_find(fib_entry, source, NULL);
1466 if (NULL == esrc)
1467 {
1468 fib_entry =
1469 fib_entry_src_action_add(fib_entry,
1470 source,
1471 flags,
1472 drop_dpo_get(
Neale Rannsda78f952017-05-24 09:15:43 -07001473 fib_entry_get_dpo_proto(fib_entry)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001474 esrc = fib_entry_src_find(fib_entry, source, NULL);
1475 }
1476
1477 /*
1478 * we are no doubt modifying a path-list. If the path-list
1479 * is shared, and hence not modifiable, then the index returned
1480 * will be for a different path-list. This FIB entry to needs
1481 * to maintain its lock appropriately.
1482 */
1483 old_path_list = esrc->fes_pl;
1484
1485 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_add);
1486
1487 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1488 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1489
1490 fib_entry_src_vft[source].fesv_path_add(esrc, fib_entry, pl_flags, rpath);
1491 fib_entry = fib_entry_get(fib_entry_index);
1492
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001493 fib_path_list_lock(esrc->fes_pl);
1494 fib_path_list_unlock(old_path_list);
1495
1496 return (fib_entry);
1497}
1498
1499/*
1500 * fib_entry_src_action_swap
1501 *
1502 * The source is providing new paths to replace the old ones.
1503 * Adding a source can result in a new fib_entry being created, which
1504 * can inturn mean the pool is realloc'd and thus the entry passed as
1505 * an argument it also realloc'd
1506 * @return the entry
1507 */
1508fib_entry_t*
1509fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1510 fib_source_t source,
1511 fib_entry_flag_t flags,
1512 const fib_route_path_t *rpaths)
1513{
1514 fib_node_index_t old_path_list, fib_entry_index;
1515 fib_path_list_flags_t pl_flags;
1516 const fib_route_path_t *rpath;
1517 fib_entry_src_t *esrc;
1518
1519 esrc = fib_entry_src_find(fib_entry, source, NULL);
1520
1521 /*
1522 * save variable so we can recover from a fib_entry realloc.
1523 */
1524 fib_entry_index = fib_entry_get_index(fib_entry);
1525
1526 if (NULL == esrc)
1527 {
1528 fib_entry = fib_entry_src_action_add(fib_entry,
1529 source,
1530 flags,
1531 drop_dpo_get(
Neale Rannsda78f952017-05-24 09:15:43 -07001532 fib_entry_get_dpo_proto(fib_entry)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001533 esrc = fib_entry_src_find(fib_entry, source, NULL);
1534 }
Neale Ranns89541992017-04-06 04:41:02 -07001535 else
1536 {
1537 esrc->fes_entry_flags = flags;
1538 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001539
1540 /*
1541 * swapping paths may create a new path-list (or may use an existing shared)
1542 * but we are certainly getting a different one. This FIB entry to needs
1543 * to maintain its lock appropriately.
1544 */
1545 old_path_list = esrc->fes_pl;
1546
1547 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_swap);
1548
Neale Rannsdf089a82016-10-02 16:39:06 +01001549 pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1550
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001551 vec_foreach(rpath, rpaths)
1552 {
1553 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1554 }
1555
1556 fib_entry_src_vft[source].fesv_path_swap(esrc,
1557 fib_entry,
1558 pl_flags,
1559 rpaths);
1560
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001561 fib_entry = fib_entry_get(fib_entry_index);
1562
1563 fib_path_list_lock(esrc->fes_pl);
1564 fib_path_list_unlock(old_path_list);
1565
1566 return (fib_entry);
1567}
1568
1569fib_entry_src_flag_t
1570fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1571 fib_source_t source,
1572 const fib_route_path_t *rpath)
1573{
1574 fib_path_list_flags_t pl_flags;
1575 fib_node_index_t old_path_list;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001576 fib_entry_src_t *esrc;
1577
1578 esrc = fib_entry_src_find(fib_entry, source, NULL);
1579
1580 ASSERT(NULL != esrc);
1581 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1582
1583 /*
1584 * we no doubt modifying a path-list. If the path-list
1585 * is shared, and hence not modifiable, then the index returned
1586 * will be for a different path-list. This FIB entry to needs
1587 * to maintain its lock appropriately.
1588 */
1589 old_path_list = esrc->fes_pl;
1590
1591 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_remove);
1592
1593 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1594 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1595
1596 fib_entry_src_vft[source].fesv_path_remove(esrc, pl_flags, rpath);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001597
1598 /*
1599 * lock the new path-list, unlock the old if it had one
1600 */
1601 fib_path_list_unlock(old_path_list);
1602
1603 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1604 fib_path_list_lock(esrc->fes_pl);
1605 return (FIB_ENTRY_SRC_FLAG_ADDED);
1606 }
1607 else
1608 {
1609 /*
1610 * no more paths left from this source
1611 */
Neale Ranns89541992017-04-06 04:41:02 -07001612 fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001613 return (FIB_ENTRY_SRC_FLAG_NONE);
1614 }
1615}
1616
1617u8*
1618fib_entry_src_format (fib_entry_t *fib_entry,
1619 fib_source_t source,
1620 u8* s)
1621{
1622 fib_entry_src_t *esrc;
1623
1624 esrc = fib_entry_src_find(fib_entry, source, NULL);
1625
1626 if (NULL != fib_entry_src_vft[source].fesv_format)
1627 {
1628 return (fib_entry_src_vft[source].fesv_format(esrc, s));
1629 }
1630 return (s);
1631}
1632
1633adj_index_t
1634fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1635 fib_source_t source)
1636{
1637 fib_entry_t *fib_entry;
1638 fib_entry_src_t *esrc;
1639
1640 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1641 return (ADJ_INDEX_INVALID);
1642
1643 fib_entry = fib_entry_get(fib_entry_index);
1644 esrc = fib_entry_src_find(fib_entry, source, NULL);
1645
1646 if (NULL != esrc)
1647 {
1648 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1649 {
1650 return (fib_path_list_get_adj(
1651 esrc->fes_pl,
1652 fib_entry_get_default_chain_type(fib_entry)));
1653 }
1654 }
1655 return (ADJ_INDEX_INVALID);
1656}
1657
1658const int
1659fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1660 fib_source_t source,
1661 dpo_id_t *dpo)
1662{
1663 fib_entry_t *fib_entry;
1664 fib_entry_src_t *esrc;
1665
1666 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1667 return (0);
1668
1669 fib_entry = fib_entry_get(fib_entry_index);
1670 esrc = fib_entry_src_find(fib_entry, source, NULL);
1671
1672 if (NULL != esrc)
1673 {
1674 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1675 {
1676 fib_path_list_contribute_forwarding(
1677 esrc->fes_pl,
1678 fib_entry_get_default_chain_type(fib_entry),
Neale Ranns91286372017-12-05 13:24:04 -08001679 FIB_PATH_LIST_FWD_FLAG_NONE,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001680 dpo);
1681
1682 return (dpo_id_is_valid(dpo));
1683 }
1684 }
1685 return (0);
1686}
1687
Neale Rannsdf089a82016-10-02 16:39:06 +01001688u32
1689fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1690 fib_source_t source)
1691{
1692 fib_entry_t *fib_entry;
1693 fib_entry_src_t *esrc;
1694
1695 fib_entry = fib_entry_get(entry_index);
1696
1697 esrc = fib_entry_src_find(fib_entry, source, NULL);
1698
1699 if (NULL != esrc)
1700 {
1701 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1702 {
1703 return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1704 }
1705 }
1706 return (~0);
1707}
1708
1709fib_entry_flag_t
1710fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1711 fib_source_t source)
1712{
1713 fib_entry_t *fib_entry;
1714 fib_entry_src_t *esrc;
1715
1716 fib_entry = fib_entry_get(entry_index);
1717
1718 esrc = fib_entry_src_find(fib_entry, source, NULL);
1719
1720 if (NULL != esrc)
1721 {
1722 return (esrc->fes_entry_flags);
1723 }
1724
1725 return (FIB_ENTRY_FLAG_NONE);
1726}
1727
Neale Rannsa4e77662017-12-04 20:00:30 +00001728fib_entry_flag_t
1729fib_entry_get_flags_i (const fib_entry_t *fib_entry)
1730{
1731 fib_entry_flag_t flags;
1732
1733 /*
1734 * the vector of sources is deliberately arranged in priority order
1735 */
1736 if (0 == vec_len(fib_entry->fe_srcs))
1737 {
1738 flags = FIB_ENTRY_FLAG_NONE;
1739 }
1740 else
1741 {
1742 fib_entry_src_t *esrc;
1743
1744 esrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
1745 flags = esrc->fes_entry_flags;
1746 }
1747
1748 return (flags);
1749}
1750
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001751void
1752fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1753 fib_source_t source,
1754 const void *data)
1755{
1756 fib_entry_t *fib_entry;
1757 fib_entry_src_t *esrc;
1758
1759 fib_entry = fib_entry_get(fib_entry_index);
1760 esrc = fib_entry_src_find(fib_entry, source, NULL);
1761
1762 if (NULL != esrc &&
1763 NULL != fib_entry_src_vft[source].fesv_set_data)
1764 {
1765 fib_entry_src_vft[source].fesv_set_data(esrc, fib_entry, data);
1766 }
1767}
1768
1769const void*
1770fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1771 fib_source_t source)
1772{
1773 fib_entry_t *fib_entry;
1774 fib_entry_src_t *esrc;
1775
1776 fib_entry = fib_entry_get(fib_entry_index);
1777 esrc = fib_entry_src_find(fib_entry, source, NULL);
1778
1779 if (NULL != esrc &&
1780 NULL != fib_entry_src_vft[source].fesv_get_data)
1781 {
1782 return (fib_entry_src_vft[source].fesv_get_data(esrc, fib_entry));
1783 }
1784 return (NULL);
1785}
1786
1787void
1788fib_entry_src_module_init (void)
1789{
1790 fib_entry_src_rr_register();
1791 fib_entry_src_interface_register();
1792 fib_entry_src_default_route_register();
1793 fib_entry_src_special_register();
1794 fib_entry_src_api_register();
1795 fib_entry_src_adj_register();
1796 fib_entry_src_mpls_register();
1797 fib_entry_src_lisp_register();
1798}