blob: 6dc0c73a305f2c264f24d17c51becc0d25d23551 [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) ||
215 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
216 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
217 MPLS_IETF_IMPLICIT_NULL_LABEL == label));
218}
219
Neale Rannsad422ed2016-11-02 14:20:04 +0000220/**
221 * @brief Turn the chain type requested by the client into the one they
222 * really wanted
223 */
224fib_forward_chain_type_t
225fib_entry_chain_type_fixup (const fib_entry_t *entry,
226 fib_forward_chain_type_t fct)
227{
Neale Rannsad422ed2016-11-02 14:20:04 +0000228 /*
229 * The EOS chain is a tricky since one cannot know the adjacency
230 * to link to without knowing what the packets payload protocol
231 * will be once the label is popped.
232 */
233 fib_forward_chain_type_t dfct;
234
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800235 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
236 {
237 return (fct);
238 }
239
Neale Rannsad422ed2016-11-02 14:20:04 +0000240 dfct = fib_entry_get_default_chain_type(entry);
241
242 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
243 {
244 /*
245 * If the entry being asked is a eos-MPLS label entry,
246 * then use the payload-protocol field, that we stashed there
247 * for just this purpose
248 */
249 return (fib_forw_chain_type_from_dpo_proto(
250 entry->fe_prefix.fp_payload_proto));
251 }
252 /*
253 * else give them what this entry would be by default. i.e. if it's a v6
254 * entry, then the label its local labelled should be carrying v6 traffic.
255 * If it's a non-EOS label entry, then there are more labels and we want
256 * a non-eos chain.
257 */
258 return (dfct);
259}
260
Neale Ranns62fe07c2017-10-31 12:28:22 -0700261static dpo_proto_t
262fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
263{
264 switch (pfx->fp_proto)
265 {
266 case FIB_PROTOCOL_IP4:
267 return (DPO_PROTO_IP4);
268 case FIB_PROTOCOL_IP6:
269 return (DPO_PROTO_IP6);
270 case FIB_PROTOCOL_MPLS:
271 return (pfx->fp_payload_proto);
272 }
273
274 ASSERT(0);
275 return (DPO_PROTO_IP4);
276}
277
Neale Ranns81424992017-05-18 03:03:22 -0700278static void
279fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
280 fib_entry_src_collect_forwarding_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281{
Neale Ranns81424992017-05-18 03:03:22 -0700282 load_balance_path_t *nh;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100283
284 /*
Neale Ranns81424992017-05-18 03:03:22 -0700285 * no extension => no out-going label for this path. that's OK
286 * in the case of an IP or EOS chain, but not for non-EOS
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100287 */
Neale Ranns81424992017-05-18 03:03:22 -0700288 switch (ctx->fct)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100289 {
Neale Ranns81424992017-05-18 03:03:22 -0700290 case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
291 case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
292 case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
293 case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
Neale Rannsd792d9c2017-10-21 10:53:20 -0700294 case FIB_FORW_CHAIN_TYPE_BIER:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100295 /*
Neale Ranns81424992017-05-18 03:03:22 -0700296 * EOS traffic with no label to stack, we need the IP Adj
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 */
Neale Ranns81424992017-05-18 03:03:22 -0700298 vec_add2(ctx->next_hops, nh, 1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100299
Neale Ranns81424992017-05-18 03:03:22 -0700300 nh->path_index = path_index;
301 nh->path_weight = fib_path_get_weight(path_index);
302 fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
303
304 break;
305 case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
306 if (fib_path_is_exclusive(path_index) ||
307 fib_path_is_deag(path_index))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100308 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100309 vec_add2(ctx->next_hops, nh, 1);
310
311 nh->path_index = path_index;
312 nh->path_weight = fib_path_get_weight(path_index);
Neale Ranns81424992017-05-18 03:03:22 -0700313 fib_path_contribute_forwarding(path_index,
314 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
315 &nh->path_dpo);
316 }
317 break;
318 case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
Neale Rannsad422ed2016-11-02 14:20:04 +0000319 {
320 /*
321 * no label. we need a chain based on the payload. fixup.
322 */
323 vec_add2(ctx->next_hops, nh, 1);
324
325 nh->path_index = path_index;
326 nh->path_weight = fib_path_get_weight(path_index);
327 fib_path_contribute_forwarding(path_index,
328 fib_entry_chain_type_fixup(ctx->fib_entry,
329 ctx->fct),
330 &nh->path_dpo);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800331 fib_path_stack_mpls_disp(path_index,
Neale Ranns62fe07c2017-10-31 12:28:22 -0700332 fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800333 &nh->path_dpo);
Neale Rannsad422ed2016-11-02 14:20:04 +0000334
335 break;
336 }
Neale Ranns81424992017-05-18 03:03:22 -0700337 case FIB_FORW_CHAIN_TYPE_ETHERNET:
338 case FIB_FORW_CHAIN_TYPE_NSH:
339 ASSERT(0);
340 break;
341 }
342}
343
344static fib_path_list_walk_rc_t
345fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
346 fib_node_index_t path_index,
347 void *arg)
348{
349 fib_entry_src_collect_forwarding_ctx_t *ctx;
350 fib_path_ext_t *path_ext;
351
352 ctx = arg;
353
354 /*
355 * if the path is not resolved, don't include it.
356 */
357 if (!fib_path_is_resolved(path_index))
358 {
359 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100360 }
361
Neale Ranns81424992017-05-18 03:03:22 -0700362 if (fib_path_is_recursive_constrained(path_index))
363 {
364 ctx->n_recursive_constrained += 1;
365 }
Neale Ranns57b58602017-07-15 07:37:25 -0700366 if (0xffff == ctx->preference)
367 {
368 /*
369 * not set a preference yet, so the first path we encounter
370 * sets the preference we are collecting.
371 */
372 ctx->preference = fib_path_get_preference(path_index);
373 }
374 else if (ctx->preference != fib_path_get_preference(path_index))
375 {
376 /*
377 * this path does not belong to the same preference as the
378 * previous paths encountered. we are done now.
379 */
380 return (FIB_PATH_LIST_WALK_STOP);
381 }
Neale Ranns81424992017-05-18 03:03:22 -0700382
383 /*
384 * get the matching path-extension for the path being visited.
385 */
386 path_ext = fib_path_ext_list_find_by_path_index(&ctx->esrc->fes_path_exts,
387 path_index);
388
389 if (NULL != path_ext)
390 {
391 switch (path_ext->fpe_type)
392 {
393 case FIB_PATH_EXT_MPLS:
394 if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0]))
395 {
396 /*
397 * found a matching extension. stack it to obtain the forwarding
398 * info for this path.
399 */
400 ctx->next_hops =
401 fib_path_ext_stack(path_ext,
402 ctx->fct,
403 fib_entry_chain_type_fixup(ctx->fib_entry,
404 ctx->fct),
405 ctx->next_hops);
406 }
407 else
408 {
409 fib_entry_src_get_path_forwarding(path_index, ctx);
410 }
411 break;
412 case FIB_PATH_EXT_ADJ:
413 if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
414 {
415 fib_entry_src_get_path_forwarding(path_index, ctx);
416 }
417 /*
418 * else
419 * the path does not refine the cover, meaning that
420 * the adjacency doesdoes not match the sub-net on the link.
421 * So this path does not contribute forwarding.
422 */
423 break;
424 }
425 }
426 else
427 {
428 fib_entry_src_get_path_forwarding(path_index, ctx);
429 }
430
431 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100432}
433
434void
435fib_entry_src_mk_lb (fib_entry_t *fib_entry,
436 const fib_entry_src_t *esrc,
437 fib_forward_chain_type_t fct,
438 dpo_id_t *dpo_lb)
439{
440 dpo_proto_t lb_proto;
441
442 /*
443 * If the entry has path extensions then we construct a load-balance
444 * by stacking the extensions on the forwarding chains of the paths.
445 * Otherwise we use the load-balance of the path-list
446 */
447 fib_entry_src_collect_forwarding_ctx_t ctx = {
448 .esrc = esrc,
449 .fib_entry = fib_entry,
450 .next_hops = NULL,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700451 .n_recursive_constrained = 0,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100452 .fct = fct,
Neale Ranns57b58602017-07-15 07:37:25 -0700453 .preference = 0xffff,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 };
455
Neale Rannsc0790cf2017-01-05 01:01:47 -0800456 /*
457 * As an optimisation we allocate the vector of next-hops to be sized
458 * equal to the maximum nuber of paths we will need, which is also the
459 * most likely number we will need, since in most cases the paths are 'up'.
460 */
461 vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
462 vec_reset_length(ctx.next_hops);
463
Neale Rannsf12a83f2017-04-18 09:09:40 -0700464 lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100465
466 fib_path_list_walk(esrc->fes_pl,
467 fib_entry_src_collect_forwarding,
468 &ctx);
469
470 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
471 {
472 /*
473 * the client provided the DPO that the entry should link to.
474 * all entries must link to a LB, so if it is an LB already
475 * then we can use it.
476 */
477 if ((1 == vec_len(ctx.next_hops)) &&
478 (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
479 {
480 dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
481 dpo_reset(&ctx.next_hops[0].path_dpo);
482 return;
483 }
484 }
485
486 if (!dpo_id_is_valid(dpo_lb))
487 {
488 /*
489 * first time create
490 */
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800491 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
492 {
493 dpo_set(dpo_lb,
494 DPO_REPLICATE,
495 lb_proto,
496 MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
497 }
498 else
499 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700500 fib_protocol_t flow_hash_proto;
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800501 flow_hash_config_t fhc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100502
Neale Ranns41da54f2017-05-02 10:15:19 -0700503 /*
504 * if the protocol for the LB we are building does not match that
505 * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
506 * then the fib_index is not an index that relates to the table
507 * type we need. So get the default flow-hash config instead.
508 */
Neale Rannsd792d9c2017-10-21 10:53:20 -0700509 flow_hash_proto = dpo_proto_to_fib(lb_proto);
510 if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
Neale Ranns41da54f2017-05-02 10:15:19 -0700511 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700512 fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700513 }
514 else
515 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700516 fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
517 flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700518 }
Neale Rannsd792d9c2017-10-21 10:53:20 -0700519
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800520 dpo_set(dpo_lb,
521 DPO_LOAD_BALANCE,
522 lb_proto,
523 load_balance_create(0, lb_proto, fhc));
524 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100525 }
526
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800527 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
Neale Ranns3ee44042016-10-03 13:05:48 +0100528 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800529 /*
530 * MPLS multicast
531 */
532 replicate_multipath_update(dpo_lb, ctx.next_hops);
Neale Ranns3ee44042016-10-03 13:05:48 +0100533 }
534 else
535 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800536 load_balance_multipath_update(dpo_lb,
537 ctx.next_hops,
538 fib_entry_calc_lb_flags(&ctx));
539 vec_free(ctx.next_hops);
540
541 /*
542 * if this entry is sourced by the uRPF-exempt source then we
543 * append the always present local0 interface (index 0) to the
544 * uRPF list so it is not empty. that way packets pass the loose check.
545 */
546 index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
547
548 if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
549 FIB_SOURCE_URPF_EXEMPT) ||
550 (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
551 (0 == fib_urpf_check_size(ui)))
552 {
553 /*
554 * The uRPF list we get from the path-list is shared by all
555 * other users of the list, but the uRPF exemption applies
556 * only to this prefix. So we need our own list.
557 */
558 ui = fib_urpf_list_alloc_and_lock();
559 fib_urpf_list_append(ui, 0);
560 fib_urpf_list_bake(ui);
561 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
562 fib_urpf_list_unlock(ui);
563 }
564 else
565 {
566 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
567 }
568 load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
569 fib_entry_get_flags_i(fib_entry));
Neale Ranns3ee44042016-10-03 13:05:48 +0100570 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100571}
572
573void
574fib_entry_src_action_install (fib_entry_t *fib_entry,
575 fib_source_t source)
576{
577 /*
578 * Install the forwarding chain for the given source into the forwarding
579 * tables
580 */
581 fib_forward_chain_type_t fct;
582 fib_entry_src_t *esrc;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100583 int insert;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100584
585 fct = fib_entry_get_default_chain_type(fib_entry);
586 esrc = fib_entry_src_find(fib_entry, source, NULL);
587
Neale Ranns33a7dd52016-10-07 15:14:33 +0100588 /*
589 * Every entry has its own load-balance object. All changes to the entry's
590 * forwarding result in an inplace modify of the load-balance. This means
591 * the load-balance object only needs to be added to the forwarding
592 * DB once, when it is created.
593 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000594 insert = !dpo_id_is_valid(&fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100595
Neale Rannsad422ed2016-11-02 14:20:04 +0000596 fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100597
Neale Rannsad422ed2016-11-02 14:20:04 +0000598 ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
599 FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100600
601 /*
602 * insert the adj into the data-plane forwarding trie
603 */
Neale Ranns33a7dd52016-10-07 15:14:33 +0100604 if (insert)
605 {
606 fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
607 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000608 &fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100609 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100610
Neale Rannsad422ed2016-11-02 14:20:04 +0000611 /*
612 * if any of the other chain types are already created they will need
613 * updating too
614 */
615 fib_entry_delegate_type_t fdt;
616 fib_entry_delegate_t *fed;
617
618 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100619 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000620 fib_entry_src_mk_lb(fib_entry, esrc,
621 fib_entry_delegate_type_to_chain_type(fdt),
622 &fed->fd_dpo);
623 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100624}
625
626void
627fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
628{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100629 /*
Neale Ranns3ee44042016-10-03 13:05:48 +0100630 * uninstall the forwarding chain from the forwarding tables
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100631 */
632 FIB_ENTRY_DBG(fib_entry, "uninstall: %d",
633 fib_entry->fe_adj_index);
634
Neale Rannsad422ed2016-11-02 14:20:04 +0000635 if (dpo_id_is_valid(&fib_entry->fe_lb))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637 fib_table_fwding_dpo_remove(
638 fib_entry->fe_fib_index,
639 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000640 &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641
Neale Rannsad422ed2016-11-02 14:20:04 +0000642 dpo_reset(&fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100643 }
644}
645
646static void
647fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
648{
649 fib_node_index_t *entries = NULL;
650
651 fib_path_list_recursive_loop_detect(path_list_index, &entries);
652
653 vec_free(entries);
654}
655
Neale Ranns89541992017-04-06 04:41:02 -0700656/*
657 * fib_entry_src_action_copy
658 *
659 * copy a source data from another entry to this one
660 */
661fib_entry_t *
662fib_entry_src_action_copy (fib_entry_t *fib_entry,
663 const fib_entry_src_t *orig_src)
664{
665 fib_entry_src_t *esrc;
666
667 esrc = fib_entry_src_find_or_create(fib_entry, orig_src->fes_src);
668
669 *esrc = *orig_src;
670 esrc->fes_ref_count = 1;
671 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_INHERITED;
672 esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
673 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
674
675 /*
676 * the source owns a lock on the entry
677 */
678 fib_path_list_lock(esrc->fes_pl);
679 fib_entry_lock(fib_entry_get_index(fib_entry));
680
681 return (fib_entry);
682}
683
684/*
685 * fib_entry_src_action_update
686 *
687 * copy a source data from another entry to this one
688 */
689static fib_entry_src_t *
690fib_entry_src_action_update_from_cover (fib_entry_t *fib_entry,
691 const fib_entry_src_t *orig_src)
692{
693 fib_entry_src_t *esrc;
694
695 esrc = fib_entry_src_find_or_create(fib_entry, orig_src->fes_src);
696
697 /*
698 * the source owns a lock on the entry
699 */
700 fib_path_list_unlock(esrc->fes_pl);
701 esrc->fes_pl = orig_src->fes_pl;
702 fib_path_list_lock(esrc->fes_pl);
703
704 return (esrc);
705}
706
707static fib_table_walk_rc_t
708fib_entry_src_covered_inherit_add_i (fib_entry_t *fib_entry,
709 const fib_entry_src_t *cover_src)
710{
711 fib_entry_src_t *esrc;
712
713 esrc = fib_entry_src_find(fib_entry, cover_src->fes_src, NULL);
714
715 if (cover_src == esrc)
716 {
717 return (FIB_TABLE_WALK_CONTINUE);
718 }
719
720 if (NULL != esrc)
721 {
722 /*
723 * the covered entry already has this source.
724 */
725 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
726 {
727 /*
728 * the covered source is itself a COVERED_INHERIT, i.e.
729 * it also pushes this source down the sub-tree.
730 * We consider this more specfic covered to be the owner
731 * of the sub-tree from this point down.
732 */
733 return (FIB_TABLE_WALK_SUB_TREE_STOP);
734 }
735 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
736 {
737 /*
738 * The covered's source data has been inherited, presumably
739 * from this cover, i.e. this is a modify.
740 */
741 esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
742 fib_entry_source_change(fib_entry, esrc->fes_src, esrc->fes_src);
743 }
744 else
745 {
746 /*
747 * The covered's source was not inherited and it is also
748 * not inherting. Nevertheless, it still owns the sub-tree from
749 * this point down.
750 */
751 return (FIB_TABLE_WALK_SUB_TREE_STOP);
752 }
753 }
754 else
755 {
756 /*
757 * The covered does not have this source - add it.
758 */
759 fib_source_t best_source;
760
761 best_source = fib_entry_get_best_source(
762 fib_entry_get_index(fib_entry));
763
764 fib_entry_src_action_copy(fib_entry, cover_src);
765 fib_entry_source_change(fib_entry, best_source, cover_src->fes_src);
766
767 }
768 return (FIB_TABLE_WALK_CONTINUE);
769}
770
771static fib_table_walk_rc_t
772fib_entry_src_covered_inherit_walk_add (fib_node_index_t fei,
773 void *ctx)
774{
775 return (fib_entry_src_covered_inherit_add_i(fib_entry_get(fei), ctx));
776}
777
778static fib_table_walk_rc_t
779fib_entry_src_covered_inherit_walk_remove (fib_node_index_t fei,
780 void *ctx)
781{
782 fib_entry_src_t *cover_src, *esrc;
783 fib_entry_t *fib_entry;
784
785 fib_entry = fib_entry_get(fei);
786
787 cover_src = ctx;
788 esrc = fib_entry_src_find(fib_entry, cover_src->fes_src, NULL);
789
790 if (cover_src == esrc)
791 {
792 return (FIB_TABLE_WALK_CONTINUE);
793 }
794
795 if (NULL != esrc)
796 {
797 /*
798 * the covered entry already has this source.
799 */
800 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
801 {
802 /*
803 * the covered source is itself a COVERED_INHERIT, i.e.
804 * it also pushes this source down the sub-tree.
805 * We consider this more specfic covered to be the owner
806 * of the sub-tree from this point down.
807 */
808 return (FIB_TABLE_WALK_SUB_TREE_STOP);
809 }
810 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
811 {
812 /*
813 * The covered's source data has been inherited, presumably
814 * from this cover
815 */
816 fib_entry_src_flag_t remaining;
817
818 remaining = fib_entry_special_remove(fei, cover_src->fes_src);
819
820 ASSERT(FIB_ENTRY_SRC_FLAG_ADDED == remaining);
821 }
822 else
823 {
824 /*
825 * The covered's source was not inherited and it is also
826 * not inherting. Nevertheless, it still owns the sub-tree from
827 * this point down.
828 */
829 return (FIB_TABLE_WALK_SUB_TREE_STOP);
830 }
831 }
832 else
833 {
834 /*
835 * The covered does not have this source - that's an error,
836 * since it should have inherited, but there is nothing we can do
837 * about it now.
838 */
839 }
840 return (FIB_TABLE_WALK_CONTINUE);
841}
842
843void
844fib_entry_src_inherit (const fib_entry_t *cover,
845 fib_entry_t *covered)
846{
847 CLIB_UNUSED(fib_source_t source);
848 const fib_entry_src_t *src;
849
850 FOR_EACH_SRC_ADDED(cover, src, source,
851 ({
852 if ((src->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
853 (src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
854 {
855 fib_entry_src_covered_inherit_add_i(covered, src);
856 }
857 }))
858}
859
860static void
861fib_entry_src_covered_inherit_add (fib_entry_t *fib_entry,
862 fib_source_t source)
863
864{
865 fib_entry_src_t *esrc;
866
867 esrc = fib_entry_src_find(fib_entry, source, NULL);
868
869 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
870
871 if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
872 (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
873 {
874 fib_table_sub_tree_walk(fib_entry->fe_fib_index,
875 fib_entry->fe_prefix.fp_proto,
876 &fib_entry->fe_prefix,
877 fib_entry_src_covered_inherit_walk_add,
878 esrc);
879 }
880}
881
882static void
883fib_entry_src_covered_inherit_remove (fib_entry_t *fib_entry,
884 fib_entry_src_t *esrc)
885
886{
887 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
888
889 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
890 {
891 fib_table_sub_tree_walk(fib_entry->fe_fib_index,
892 fib_entry->fe_prefix.fp_proto,
893 &fib_entry->fe_prefix,
894 fib_entry_src_covered_inherit_walk_remove,
895 esrc);
896 }
897}
898
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100899void
900fib_entry_src_action_activate (fib_entry_t *fib_entry,
901 fib_source_t source)
902
903{
904 int houston_we_are_go_for_install;
905 fib_entry_src_t *esrc;
906
907 esrc = fib_entry_src_find(fib_entry, source, NULL);
908
909 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
910 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
911
912 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ACTIVE;
913
914 if (NULL != fib_entry_src_vft[source].fesv_activate)
915 {
916 houston_we_are_go_for_install =
917 fib_entry_src_vft[source].fesv_activate(esrc, fib_entry);
918 }
919 else
920 {
921 /*
922 * the source is not providing an activate function, we'll assume
923 * therefore it has no objection to installing the entry
924 */
925 houston_we_are_go_for_install = !0;
926 }
927
928 /*
929 * link to the path-list provided by the source, and go check
930 * if that forms any loops in the graph.
931 */
932 fib_entry->fe_parent = esrc->fes_pl;
933 fib_entry->fe_sibling =
934 fib_path_list_child_add(fib_entry->fe_parent,
935 FIB_NODE_TYPE_ENTRY,
936 fib_entry_get_index(fib_entry));
937
938 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
939
940 FIB_ENTRY_DBG(fib_entry, "activate: %d",
941 fib_entry->fe_parent);
942
Neale Ranns89541992017-04-06 04:41:02 -0700943 /*
944 * If this source should push its state to covered prefixs, do that now.
945 */
946 fib_entry_src_covered_inherit_add(fib_entry, source);
947
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100948 if (0 != houston_we_are_go_for_install)
949 {
950 fib_entry_src_action_install(fib_entry, source);
951 }
952 else
953 {
954 fib_entry_src_action_uninstall(fib_entry);
955 }
956}
957
958void
959fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
960 fib_source_t source)
961
962{
963 fib_node_index_t path_list_index;
964 fib_entry_src_t *esrc;
965
966 esrc = fib_entry_src_find(fib_entry, source, NULL);
967
968 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
969
970 if (NULL != fib_entry_src_vft[source].fesv_deactivate)
971 {
972 fib_entry_src_vft[source].fesv_deactivate(esrc, fib_entry);
973 }
974
975 esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
976
977 FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
978
979 /*
Neale Ranns89541992017-04-06 04:41:02 -0700980 * If this source should pull its state from covered prefixs, do that now.
981 * If this source also has the INHERITED flag set then it has a cover
982 * that wants to push down forwarding. We only want the covereds to see
983 * one update.
984 */
985 fib_entry_src_covered_inherit_remove(fib_entry, esrc);
986
987 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100988 * un-link from an old path-list. Check for any loops this will clear
989 */
990 path_list_index = fib_entry->fe_parent;
991 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
992
993 fib_entry_recursive_loop_detect_i(path_list_index);
994
995 /*
996 * this will unlock the path-list, so it may be invalid thereafter.
997 */
998 fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
999 fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
1000}
1001
Neale Rannsa4e77662017-12-04 20:00:30 +00001002static void
1003fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
1004 fib_source_t source)
1005{
1006 fib_entry_src_t *esrc;
1007
1008 vec_foreach(esrc, fib_entry->fe_srcs)
1009 {
1010 if (NULL != fib_entry_src_vft[esrc->fes_src].fesv_fwd_update)
1011 {
1012 fib_entry_src_vft[esrc->fes_src].fesv_fwd_update(esrc,
1013 fib_entry,
1014 source);
1015 }
1016 }
1017}
1018
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001019void
1020fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
1021 fib_source_t source)
1022{
1023 fib_node_index_t path_list_index;
1024 fib_entry_src_t *esrc;
1025
1026 esrc = fib_entry_src_find(fib_entry, source, NULL);
1027
1028 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1029
1030 FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
1031 fib_entry->fe_parent,
1032 esrc->fes_pl);
1033
1034 if (fib_entry->fe_parent != esrc->fes_pl)
1035 {
Neale Ranns89541992017-04-06 04:41:02 -07001036 int remain_installed;
1037
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001038 /*
1039 * un-link from an old path-list. Check for any loops this will clear
1040 */
1041 path_list_index = fib_entry->fe_parent;
1042 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1043
1044 /*
1045 * temporary lock so it doesn't get deleted when this entry is no
1046 * longer a child.
1047 */
1048 fib_path_list_lock(path_list_index);
1049
1050 /*
1051 * this entry is no longer a child. after unlinking check if any loops
1052 * were broken
1053 */
1054 fib_path_list_child_remove(path_list_index,
1055 fib_entry->fe_sibling);
1056
1057 fib_entry_recursive_loop_detect_i(path_list_index);
1058
1059 /*
1060 * link to the path-list provided by the source, and go check
1061 * if that forms any loops in the graph.
1062 */
1063 fib_entry->fe_parent = esrc->fes_pl;
1064 fib_entry->fe_sibling =
1065 fib_path_list_child_add(fib_entry->fe_parent,
1066 FIB_NODE_TYPE_ENTRY,
1067 fib_entry_get_index(fib_entry));
1068
1069 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1070 fib_path_list_unlock(path_list_index);
Neale Ranns89541992017-04-06 04:41:02 -07001071
1072 /*
1073 * call the source to reactive and get the go/no-go to remain installed
1074 */
1075 if (NULL != fib_entry_src_vft[source].fesv_reactivate)
1076 {
1077 remain_installed =
1078 fib_entry_src_vft[source].fesv_reactivate(esrc, fib_entry);
1079 }
1080 else
1081 {
1082 remain_installed = 1;
1083 }
1084
1085 /*
1086 * If this source should push its state to covered prefixs, do that now.
1087 */
1088 fib_entry_src_covered_inherit_add(fib_entry, source);
1089
1090 if (!remain_installed)
1091 {
1092 fib_entry_src_action_uninstall(fib_entry);
1093 return;
1094 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001095 }
1096 fib_entry_src_action_install(fib_entry, source);
Neale Rannsa4e77662017-12-04 20:00:30 +00001097 fib_entry_src_action_fwd_update(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001098}
1099
1100void
Neale Rannsa4e77662017-12-04 20:00:30 +00001101fib_entry_src_action_installed (const fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001102 fib_source_t source)
1103{
1104 fib_entry_src_t *esrc;
1105
1106 esrc = fib_entry_src_find(fib_entry, source, NULL);
1107
1108 if (NULL != fib_entry_src_vft[source].fesv_installed)
1109 {
1110 fib_entry_src_vft[source].fesv_installed(esrc,
1111 fib_entry);
1112 }
Neale Rannsa4e77662017-12-04 20:00:30 +00001113
1114 fib_entry_src_action_fwd_update(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001115}
1116
1117/*
1118 * fib_entry_src_action_add
1119 *
1120 * Adding a source can result in a new fib_entry being created, which
1121 * can inturn mean the pool is realloc'd and thus the entry passed as
1122 * an argument it also realloc'd
1123 * @return the original entry
1124 */
1125fib_entry_t *
1126fib_entry_src_action_add (fib_entry_t *fib_entry,
1127 fib_source_t source,
1128 fib_entry_flag_t flags,
1129 const dpo_id_t *dpo)
1130{
1131 fib_node_index_t fib_entry_index;
1132 fib_entry_src_t *esrc;
1133
Neale Ranns89541992017-04-06 04:41:02 -07001134 esrc = fib_entry_src_find_or_create(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001135
1136 esrc->fes_ref_count++;
1137
1138 if (1 != esrc->fes_ref_count)
1139 {
1140 /*
1141 * we only want to add the source on the 0->1 transition
1142 */
1143 return (fib_entry);
1144 }
1145
1146 esrc->fes_entry_flags = flags;
1147
1148 /*
1149 * save variable so we can recover from a fib_entry realloc.
1150 */
1151 fib_entry_index = fib_entry_get_index(fib_entry);
1152
1153 if (NULL != fib_entry_src_vft[source].fesv_add)
1154 {
1155 fib_entry_src_vft[source].fesv_add(esrc,
1156 fib_entry,
1157 flags,
Neale Rannsda78f952017-05-24 09:15:43 -07001158 fib_entry_get_dpo_proto(fib_entry),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001159 dpo);
1160 }
1161
1162 fib_entry = fib_entry_get(fib_entry_index);
1163
1164 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1165
1166 fib_path_list_lock(esrc->fes_pl);
1167
1168 /*
1169 * the source owns a lock on the entry
1170 */
1171 fib_entry_lock(fib_entry_get_index(fib_entry));
1172
1173 return (fib_entry);
1174}
1175
Neale Ranns948e00f2016-10-20 13:39:34 +01001176/*
1177 * fib_entry_src_action_update
1178 *
1179 * Adding a source can result in a new fib_entry being created, which
1180 * can inturn mean the pool is realloc'd and thus the entry passed as
1181 * an argument it also realloc'd
1182 * @return the original entry
1183 */
1184fib_entry_t *
1185fib_entry_src_action_update (fib_entry_t *fib_entry,
1186 fib_source_t source,
1187 fib_entry_flag_t flags,
1188 const dpo_id_t *dpo)
1189{
1190 fib_node_index_t fib_entry_index, old_path_list_index;
1191 fib_entry_src_t *esrc;
1192
Neale Ranns89541992017-04-06 04:41:02 -07001193 esrc = fib_entry_src_find_or_create(fib_entry, source);
Neale Ranns948e00f2016-10-20 13:39:34 +01001194
1195 if (NULL == esrc)
Neale Ranns89541992017-04-06 04:41:02 -07001196 {
Neale Ranns948e00f2016-10-20 13:39:34 +01001197 return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
Neale Ranns89541992017-04-06 04:41:02 -07001198 }
Neale Ranns948e00f2016-10-20 13:39:34 +01001199
1200 old_path_list_index = esrc->fes_pl;
1201 esrc->fes_entry_flags = flags;
1202
1203 /*
1204 * save variable so we can recover from a fib_entry realloc.
1205 */
1206 fib_entry_index = fib_entry_get_index(fib_entry);
1207
1208 if (NULL != fib_entry_src_vft[source].fesv_add)
1209 {
1210 fib_entry_src_vft[source].fesv_add(esrc,
1211 fib_entry,
1212 flags,
Neale Rannsda78f952017-05-24 09:15:43 -07001213 fib_entry_get_dpo_proto(fib_entry),
Neale Ranns948e00f2016-10-20 13:39:34 +01001214 dpo);
1215 }
1216
1217 fib_entry = fib_entry_get(fib_entry_index);
1218
1219 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1220
1221 fib_path_list_lock(esrc->fes_pl);
1222 fib_path_list_unlock(old_path_list_index);
1223
1224 return (fib_entry);
1225}
1226
Neale Ranns89541992017-04-06 04:41:02 -07001227fib_entry_src_flag_t
1228fib_entry_src_action_remove_or_update_inherit (fib_entry_t *fib_entry,
1229 fib_source_t source)
1230{
1231 fib_entry_src_t *esrc;
1232
1233 esrc = fib_entry_src_find(fib_entry, source, NULL);
1234
1235 if (NULL == esrc)
1236 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1237
1238 if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) &&
1239 (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
1240 {
1241 fib_entry_src_t *cover_src;
1242 fib_node_index_t coveri;
1243 fib_entry_t *cover;
1244
1245 /*
1246 * this source was pushing inherited state, but so is its
1247 * cover. Now that this source is going away, we need to
1248 * pull the covers forwarding and use it to update the covereds.
1249 * Go grab the path-list from the cover, rather than start a walk from
1250 * the cover, so we don't recursively update this entry.
1251 */
1252 coveri = fib_table_get_less_specific(fib_entry->fe_fib_index,
1253 &fib_entry->fe_prefix);
1254
1255 /*
1256 * only the default route has itself as its own cover, but the
1257 * default route cannot have inherited from something else.
1258 */
1259 ASSERT(coveri != fib_entry_get_index(fib_entry));
1260
1261 cover = fib_entry_get(coveri);
1262 cover_src = fib_entry_src_find(cover, source, NULL);
1263
1264 ASSERT(NULL != cover_src);
1265
1266 esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
1267 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
1268
1269 /*
1270 * Now push the new state from the cover down to the covereds
1271 */
1272 fib_entry_src_covered_inherit_add(fib_entry, source);
1273
1274 return (esrc->fes_flags);
1275 }
1276 else
1277 {
1278 return (fib_entry_src_action_remove(fib_entry, source));
1279 }
1280}
Neale Ranns948e00f2016-10-20 13:39:34 +01001281
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001282fib_entry_src_flag_t
1283fib_entry_src_action_remove (fib_entry_t *fib_entry,
1284 fib_source_t source)
1285
1286{
1287 fib_node_index_t old_path_list;
1288 fib_entry_src_flag_t sflags;
1289 fib_entry_src_t *esrc;
1290
1291 esrc = fib_entry_src_find(fib_entry, source, NULL);
1292
1293 if (NULL == esrc)
1294 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1295
1296 esrc->fes_ref_count--;
1297 sflags = esrc->fes_flags;
1298
1299 if (0 != esrc->fes_ref_count)
1300 {
1301 /*
1302 * only remove the source on the 1->0 transisition
1303 */
1304 return (sflags);
1305 }
1306
1307 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
1308 {
Neale Ranns89541992017-04-06 04:41:02 -07001309 fib_entry_src_action_deactivate(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001310 }
1311
1312 old_path_list = esrc->fes_pl;
1313
1314 if (NULL != fib_entry_src_vft[source].fesv_remove)
1315 {
1316 fib_entry_src_vft[source].fesv_remove(esrc);
1317 }
1318
1319 fib_path_list_unlock(old_path_list);
1320 fib_entry_unlock(fib_entry_get_index(fib_entry));
1321
1322 sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
1323 fib_entry_src_action_deinit(fib_entry, source);
1324
1325 return (sflags);
1326}
1327
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001328/*
1329 * fib_route_attached_cross_table
1330 *
1331 * Return true the the route is attached via an interface that
1332 * is not in the same table as the route
1333 */
1334static inline int
1335fib_route_attached_cross_table (const fib_entry_t *fib_entry,
1336 const fib_route_path_t *rpath)
1337{
1338 /*
1339 * - All zeros next-hop
1340 * - a valid interface
1341 * - entry's fib index not equeal to interface's index
1342 */
1343 if (ip46_address_is_zero(&rpath->frp_addr) &&
1344 (~0 != rpath->frp_sw_if_index) &&
1345 (fib_entry->fe_fib_index !=
1346 fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
1347 rpath->frp_sw_if_index)))
1348 {
1349 return (!0);
1350 }
1351 return (0);
1352}
1353
1354/*
Neale Ranns53da2212018-02-24 02:11:19 -08001355 * Return true if the path is attached
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001356 */
1357static inline int
1358fib_path_is_attached (const fib_route_path_t *rpath)
1359{
1360 /*
1361 * - All zeros next-hop
1362 * - a valid interface
1363 */
1364 if (ip46_address_is_zero(&rpath->frp_addr) &&
1365 (~0 != rpath->frp_sw_if_index))
1366 {
1367 return (!0);
1368 }
Neale Ranns4b919a52017-03-11 05:55:21 -08001369 else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
1370 {
1371 return (!0);
1372 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001373 return (0);
1374}
1375
1376fib_path_list_flags_t
1377fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
1378{
1379 fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
1380
1381 if (eflags & FIB_ENTRY_FLAG_DROP)
1382 {
1383 plf |= FIB_PATH_LIST_FLAG_DROP;
1384 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001385 if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
1386 {
1387 plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
1388 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001389 if (eflags & FIB_ENTRY_FLAG_LOCAL)
1390 {
1391 plf |= FIB_PATH_LIST_FLAG_LOCAL;
1392 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001393
1394 return (plf);
1395}
1396
1397static void
1398fib_entry_flags_update (const fib_entry_t *fib_entry,
1399 const fib_route_path_t *rpath,
1400 fib_path_list_flags_t *pl_flags,
1401 fib_entry_src_t *esrc)
1402{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001403 if ((esrc->fes_src == FIB_SOURCE_API) ||
1404 (esrc->fes_src == FIB_SOURCE_CLI))
1405 {
1406 if (fib_path_is_attached(rpath))
1407 {
1408 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1409 }
1410 else
1411 {
1412 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1413 }
Florin Coras79ae2d32017-12-16 08:31:06 -08001414 if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
1415 {
1416 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT;
1417 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001418 }
Neale Ranns53da2212018-02-24 02:11:19 -08001419 if (fib_route_attached_cross_table(fib_entry, rpath) &&
1420 !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001421 {
1422 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1423 }
1424 else
1425 {
1426 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1427 }
1428}
1429
1430/*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001431 * fib_entry_src_action_add
1432 *
1433 * Adding a source can result in a new fib_entry being created, which
1434 * can inturn mean the pool is realloc'd and thus the entry passed as
1435 * an argument it also realloc'd
1436 * @return the entry
1437 */
1438fib_entry_t*
1439fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1440 fib_source_t source,
1441 fib_entry_flag_t flags,
1442 const fib_route_path_t *rpath)
1443{
1444 fib_node_index_t old_path_list, fib_entry_index;
1445 fib_path_list_flags_t pl_flags;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001446 fib_entry_src_t *esrc;
1447
1448 /*
1449 * save variable so we can recover from a fib_entry realloc.
1450 */
1451 fib_entry_index = fib_entry_get_index(fib_entry);
1452
1453 esrc = fib_entry_src_find(fib_entry, source, NULL);
1454 if (NULL == esrc)
1455 {
1456 fib_entry =
1457 fib_entry_src_action_add(fib_entry,
1458 source,
1459 flags,
1460 drop_dpo_get(
Neale Rannsda78f952017-05-24 09:15:43 -07001461 fib_entry_get_dpo_proto(fib_entry)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001462 esrc = fib_entry_src_find(fib_entry, source, NULL);
1463 }
1464
1465 /*
1466 * we are no doubt modifying a path-list. If the path-list
1467 * is shared, and hence not modifiable, then the index returned
1468 * will be for a different path-list. This FIB entry to needs
1469 * to maintain its lock appropriately.
1470 */
1471 old_path_list = esrc->fes_pl;
1472
1473 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_add);
1474
1475 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1476 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1477
1478 fib_entry_src_vft[source].fesv_path_add(esrc, fib_entry, pl_flags, rpath);
1479 fib_entry = fib_entry_get(fib_entry_index);
1480
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001481 fib_path_list_lock(esrc->fes_pl);
1482 fib_path_list_unlock(old_path_list);
1483
1484 return (fib_entry);
1485}
1486
1487/*
1488 * fib_entry_src_action_swap
1489 *
1490 * The source is providing new paths to replace the old ones.
1491 * Adding a source can result in a new fib_entry being created, which
1492 * can inturn mean the pool is realloc'd and thus the entry passed as
1493 * an argument it also realloc'd
1494 * @return the entry
1495 */
1496fib_entry_t*
1497fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1498 fib_source_t source,
1499 fib_entry_flag_t flags,
1500 const fib_route_path_t *rpaths)
1501{
1502 fib_node_index_t old_path_list, fib_entry_index;
1503 fib_path_list_flags_t pl_flags;
1504 const fib_route_path_t *rpath;
1505 fib_entry_src_t *esrc;
1506
1507 esrc = fib_entry_src_find(fib_entry, source, NULL);
1508
1509 /*
1510 * save variable so we can recover from a fib_entry realloc.
1511 */
1512 fib_entry_index = fib_entry_get_index(fib_entry);
1513
1514 if (NULL == esrc)
1515 {
1516 fib_entry = fib_entry_src_action_add(fib_entry,
1517 source,
1518 flags,
1519 drop_dpo_get(
Neale Rannsda78f952017-05-24 09:15:43 -07001520 fib_entry_get_dpo_proto(fib_entry)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001521 esrc = fib_entry_src_find(fib_entry, source, NULL);
1522 }
Neale Ranns89541992017-04-06 04:41:02 -07001523 else
1524 {
1525 esrc->fes_entry_flags = flags;
1526 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001527
1528 /*
1529 * swapping paths may create a new path-list (or may use an existing shared)
1530 * but we are certainly getting a different one. This FIB entry to needs
1531 * to maintain its lock appropriately.
1532 */
1533 old_path_list = esrc->fes_pl;
1534
1535 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_swap);
1536
Neale Rannsdf089a82016-10-02 16:39:06 +01001537 pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1538
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001539 vec_foreach(rpath, rpaths)
1540 {
1541 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1542 }
1543
1544 fib_entry_src_vft[source].fesv_path_swap(esrc,
1545 fib_entry,
1546 pl_flags,
1547 rpaths);
1548
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001549 fib_entry = fib_entry_get(fib_entry_index);
1550
1551 fib_path_list_lock(esrc->fes_pl);
1552 fib_path_list_unlock(old_path_list);
1553
1554 return (fib_entry);
1555}
1556
1557fib_entry_src_flag_t
1558fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1559 fib_source_t source,
1560 const fib_route_path_t *rpath)
1561{
1562 fib_path_list_flags_t pl_flags;
1563 fib_node_index_t old_path_list;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001564 fib_entry_src_t *esrc;
1565
1566 esrc = fib_entry_src_find(fib_entry, source, NULL);
1567
1568 ASSERT(NULL != esrc);
1569 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1570
1571 /*
1572 * we no doubt modifying a path-list. If the path-list
1573 * is shared, and hence not modifiable, then the index returned
1574 * will be for a different path-list. This FIB entry to needs
1575 * to maintain its lock appropriately.
1576 */
1577 old_path_list = esrc->fes_pl;
1578
1579 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_remove);
1580
1581 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1582 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1583
1584 fib_entry_src_vft[source].fesv_path_remove(esrc, pl_flags, rpath);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001585
1586 /*
1587 * lock the new path-list, unlock the old if it had one
1588 */
1589 fib_path_list_unlock(old_path_list);
1590
1591 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1592 fib_path_list_lock(esrc->fes_pl);
1593 return (FIB_ENTRY_SRC_FLAG_ADDED);
1594 }
1595 else
1596 {
1597 /*
1598 * no more paths left from this source
1599 */
Neale Ranns89541992017-04-06 04:41:02 -07001600 fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001601 return (FIB_ENTRY_SRC_FLAG_NONE);
1602 }
1603}
1604
1605u8*
1606fib_entry_src_format (fib_entry_t *fib_entry,
1607 fib_source_t source,
1608 u8* s)
1609{
1610 fib_entry_src_t *esrc;
1611
1612 esrc = fib_entry_src_find(fib_entry, source, NULL);
1613
1614 if (NULL != fib_entry_src_vft[source].fesv_format)
1615 {
1616 return (fib_entry_src_vft[source].fesv_format(esrc, s));
1617 }
1618 return (s);
1619}
1620
1621adj_index_t
1622fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1623 fib_source_t source)
1624{
1625 fib_entry_t *fib_entry;
1626 fib_entry_src_t *esrc;
1627
1628 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1629 return (ADJ_INDEX_INVALID);
1630
1631 fib_entry = fib_entry_get(fib_entry_index);
1632 esrc = fib_entry_src_find(fib_entry, source, NULL);
1633
1634 if (NULL != esrc)
1635 {
1636 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1637 {
1638 return (fib_path_list_get_adj(
1639 esrc->fes_pl,
1640 fib_entry_get_default_chain_type(fib_entry)));
1641 }
1642 }
1643 return (ADJ_INDEX_INVALID);
1644}
1645
1646const int
1647fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1648 fib_source_t source,
1649 dpo_id_t *dpo)
1650{
1651 fib_entry_t *fib_entry;
1652 fib_entry_src_t *esrc;
1653
1654 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1655 return (0);
1656
1657 fib_entry = fib_entry_get(fib_entry_index);
1658 esrc = fib_entry_src_find(fib_entry, source, NULL);
1659
1660 if (NULL != esrc)
1661 {
1662 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1663 {
1664 fib_path_list_contribute_forwarding(
1665 esrc->fes_pl,
1666 fib_entry_get_default_chain_type(fib_entry),
Neale Ranns91286372017-12-05 13:24:04 -08001667 FIB_PATH_LIST_FWD_FLAG_NONE,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001668 dpo);
1669
1670 return (dpo_id_is_valid(dpo));
1671 }
1672 }
1673 return (0);
1674}
1675
Neale Rannsdf089a82016-10-02 16:39:06 +01001676u32
1677fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1678 fib_source_t source)
1679{
1680 fib_entry_t *fib_entry;
1681 fib_entry_src_t *esrc;
1682
1683 fib_entry = fib_entry_get(entry_index);
1684
1685 esrc = fib_entry_src_find(fib_entry, source, NULL);
1686
1687 if (NULL != esrc)
1688 {
1689 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1690 {
1691 return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1692 }
1693 }
1694 return (~0);
1695}
1696
1697fib_entry_flag_t
1698fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1699 fib_source_t source)
1700{
1701 fib_entry_t *fib_entry;
1702 fib_entry_src_t *esrc;
1703
1704 fib_entry = fib_entry_get(entry_index);
1705
1706 esrc = fib_entry_src_find(fib_entry, source, NULL);
1707
1708 if (NULL != esrc)
1709 {
1710 return (esrc->fes_entry_flags);
1711 }
1712
1713 return (FIB_ENTRY_FLAG_NONE);
1714}
1715
Neale Rannsa4e77662017-12-04 20:00:30 +00001716fib_entry_flag_t
1717fib_entry_get_flags_i (const fib_entry_t *fib_entry)
1718{
1719 fib_entry_flag_t flags;
1720
1721 /*
1722 * the vector of sources is deliberately arranged in priority order
1723 */
1724 if (0 == vec_len(fib_entry->fe_srcs))
1725 {
1726 flags = FIB_ENTRY_FLAG_NONE;
1727 }
1728 else
1729 {
1730 fib_entry_src_t *esrc;
1731
1732 esrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
1733 flags = esrc->fes_entry_flags;
1734 }
1735
1736 return (flags);
1737}
1738
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001739void
1740fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1741 fib_source_t source,
1742 const void *data)
1743{
1744 fib_entry_t *fib_entry;
1745 fib_entry_src_t *esrc;
1746
1747 fib_entry = fib_entry_get(fib_entry_index);
1748 esrc = fib_entry_src_find(fib_entry, source, NULL);
1749
1750 if (NULL != esrc &&
1751 NULL != fib_entry_src_vft[source].fesv_set_data)
1752 {
1753 fib_entry_src_vft[source].fesv_set_data(esrc, fib_entry, data);
1754 }
1755}
1756
1757const void*
1758fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1759 fib_source_t source)
1760{
1761 fib_entry_t *fib_entry;
1762 fib_entry_src_t *esrc;
1763
1764 fib_entry = fib_entry_get(fib_entry_index);
1765 esrc = fib_entry_src_find(fib_entry, source, NULL);
1766
1767 if (NULL != esrc &&
1768 NULL != fib_entry_src_vft[source].fesv_get_data)
1769 {
1770 return (fib_entry_src_vft[source].fesv_get_data(esrc, fib_entry));
1771 }
1772 return (NULL);
1773}
1774
1775void
1776fib_entry_src_module_init (void)
1777{
1778 fib_entry_src_rr_register();
1779 fib_entry_src_interface_register();
1780 fib_entry_src_default_route_register();
1781 fib_entry_src_special_register();
1782 fib_entry_src_api_register();
1783 fib_entry_src_adj_register();
1784 fib_entry_src_mpls_register();
1785 fib_entry_src_lisp_register();
1786}