blob: acb8579e85ebe55395a748490e7a46bfd5205e43 [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 Ranns84517cf2017-11-25 15:20:26 -080064 if (fib_entry_has_multiple_srcs(fib_entry))
65 {
66 vec_add1(fib_entry->fe_u_src.fe_srcs, esrc);
67
68 vec_sort_with_function(fib_entry->fe_u_src.fe_srcs,
69 fib_entry_src_cmp_for_sort);
70 }
71 else
72 {
73 /*
74 * is this the very first source
75 */
76 if (FIB_SOURCE_INVALID == fib_entry->fe_u_src.fe_src.fes_src)
77 {
78 clib_memcpy(&fib_entry->fe_u_src.fe_src, &esrc, sizeof(esrc));
79 }
80 else
81 {
82 /*
83 * transitioning to multiple sources.
84 * allocate the vecotr of sources.
85 */
86 fib_entry_src_t *srcs = NULL;
87
88 vec_validate(srcs, 1);
89
90 /*
91 * sorted insert
92 */
93 if (fib_entry->fe_u_src.fe_src.fes_src < esrc.fes_src)
94 {
95 srcs[0] = fib_entry->fe_u_src.fe_src;
96 srcs[1] = esrc;
97 }
98 else
99 {
100 srcs[0] = esrc;
101 srcs[1] = fib_entry->fe_u_src.fe_src;
102 }
103 memset(&fib_entry->fe_u_src.fe_src, 0,
104 sizeof(fib_entry->fe_u_src.fe_src));
105 fib_entry->fe_u_src.fe_srcs = srcs;
106
107 fib_entry->fe_node.fn_pad |= FIB_ENTRY_NODE_FLAG_MULTIPLE_SRCS;
108 }
109 }
110}
111
112u32
113fib_entry_has_multiple_srcs(const fib_entry_t * fib_entry)
114{
115 return (fib_entry->fe_node.fn_pad & FIB_ENTRY_NODE_FLAG_MULTIPLE_SRCS);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100116}
117
118static fib_entry_src_t *
Neale Ranns84517cf2017-11-25 15:20:26 -0800119fib_entry_src_find (fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100120 fib_source_t source,
121 u32 *index)
122
123{
124 fib_entry_src_t *esrc;
125 int ii;
126
127 ii = 0;
Neale Ranns84517cf2017-11-25 15:20:26 -0800128 if (fib_entry_has_multiple_srcs(fib_entry))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100129 {
Neale Ranns84517cf2017-11-25 15:20:26 -0800130 vec_foreach(esrc, fib_entry->fe_u_src.fe_srcs)
131 {
132 if (esrc->fes_src == source)
133 {
134 if (NULL != index)
135 {
136 *index = ii;
137 }
138 return (esrc);
139 }
140 else
141 {
142 ii++;
143 }
144 }
145 }
146 else
147 {
148 esrc = &fib_entry->fe_u_src.fe_src;
149 if (esrc->fes_src == source)
150 {
151 if (NULL != index)
152 {
153 *index = -1;
154 }
155 return (esrc);
156 }
157 }
158
159 return (NULL);
160}
161
162static fib_entry_src_t *
163fib_entry_src_delete (fib_entry_t *fib_entry,
164 u32 index)
165
166{
167 if (-1 == index)
168 {
169 ASSERT(!fib_entry_has_multiple_srcs(fib_entry));
170 memset(&fib_entry->fe_u_src.fe_src, 0,
171 sizeof(fib_entry->fe_u_src.fe_src));
172 }
173 else
174 {
175 vec_del1(fib_entry->fe_u_src.fe_srcs, index);
176
177 ASSERT(vec_len(fib_entry->fe_u_src.fe_srcs));
178 if (1 == vec_len(fib_entry->fe_u_src.fe_srcs))
179 {
180 /*
181 * Is there much point in transitioning back?
182 * We've paid the cost of the malloc for the vector,
183 * why not keep it.
184 * Favour memory use. If the expectation that multiple sources
185 * is rare is correct, then we should expect this entry is
186 * unlikely to need the vector again
187 */
188 fib_entry_src_t *srcs;
189
190 srcs = fib_entry->fe_u_src.fe_srcs;
191 fib_entry->fe_node.fn_pad &= ~FIB_ENTRY_NODE_FLAG_MULTIPLE_SRCS;
192 clib_memcpy(&fib_entry->fe_u_src.fe_src,
193 &srcs[0],
194 sizeof(fib_entry->fe_u_src.fe_src));
195 vec_free(srcs);
196 }
197 else
198 {
199 vec_sort_with_function(fib_entry->fe_u_src.fe_srcs,
200 fib_entry_src_cmp_for_sort);
201 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100202 }
203
204 return (NULL);
205}
206
207int
208fib_entry_is_sourced (fib_node_index_t fib_entry_index,
209 fib_source_t source)
210{
211 fib_entry_t *fib_entry;
212
213 fib_entry = fib_entry_get(fib_entry_index);
214
215 return (NULL != fib_entry_src_find(fib_entry, source, NULL));
216}
217
218static fib_entry_src_t *
219fib_entry_src_find_or_create (fib_entry_t *fib_entry,
Neale Ranns84517cf2017-11-25 15:20:26 -0800220 fib_source_t source)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100221{
222 fib_entry_src_t *esrc;
223
224 esrc = fib_entry_src_find(fib_entry, source, NULL);
225
226 if (NULL == esrc)
227 {
228 fib_entry_src_action_init(fib_entry, source);
229 }
230
231 return (fib_entry_src_find(fib_entry, source, NULL));
232}
233
234void
235fib_entry_src_action_deinit (fib_entry_t *fib_entry,
236 fib_source_t source)
237
238{
239 fib_entry_src_t *esrc;
240 u32 index = ~0;
241
242 esrc = fib_entry_src_find(fib_entry, source, &index);
243
244 ASSERT(NULL != esrc);
245
246 if (NULL != fib_entry_src_vft[source].fesv_deinit)
247 {
248 fib_entry_src_vft[source].fesv_deinit(esrc);
249 }
250
Neale Ranns81424992017-05-18 03:03:22 -0700251 fib_path_ext_list_flush(&esrc->fes_path_exts);
Neale Ranns84517cf2017-11-25 15:20:26 -0800252 fib_entry_src_delete(fib_entry, index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100253}
254
255fib_entry_src_cover_res_t
256fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
257 fib_source_t source)
258{
259 if (NULL != fib_entry_src_vft[source].fesv_cover_change)
260 {
261 return (fib_entry_src_vft[source].fesv_cover_change(
262 fib_entry_src_find(fib_entry, source, NULL),
263 fib_entry));
264 }
265
266 fib_entry_src_cover_res_t res = {
267 .install = !0,
268 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
269 };
270 return (res);
271}
272
273fib_entry_src_cover_res_t
274fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
275 fib_source_t source)
276{
277 if (NULL != fib_entry_src_vft[source].fesv_cover_update)
278 {
279 return (fib_entry_src_vft[source].fesv_cover_update(
280 fib_entry_src_find(fib_entry, source, NULL),
281 fib_entry));
282 }
283
284 fib_entry_src_cover_res_t res = {
285 .install = !0,
286 .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
287 };
288 return (res);
289}
290
291typedef struct fib_entry_src_collect_forwarding_ctx_t_
292{
Neale Ranns81424992017-05-18 03:03:22 -0700293 load_balance_path_t *next_hops;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100294 const fib_entry_t *fib_entry;
295 const fib_entry_src_t *esrc;
296 fib_forward_chain_type_t fct;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700297 int n_recursive_constrained;
Neale Ranns57b58602017-07-15 07:37:25 -0700298 u16 preference;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100299} fib_entry_src_collect_forwarding_ctx_t;
300
301/**
302 * @brief Determine whether this FIB entry should use a load-balance MAP
303 * to support PIC edge fast convergence
304 */
305load_balance_flags_t
306fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx)
307{
308 /**
Neale Rannsf12a83f2017-04-18 09:09:40 -0700309 * We'll use a LB map if the path-list has multiple recursive paths.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100310 * recursive paths implies BGP, and hence scale.
311 */
Neale Rannsf12a83f2017-04-18 09:09:40 -0700312 if (ctx->n_recursive_constrained > 1 &&
313 fib_path_list_is_popular(ctx->esrc->fes_pl))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100314 {
315 return (LOAD_BALANCE_FLAG_USES_MAP);
316 }
317 return (LOAD_BALANCE_FLAG_NONE);
318}
319
320static int
321fib_entry_src_valid_out_label (mpls_label_t label)
322{
323 return ((MPLS_LABEL_IS_REAL(label) ||
324 MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
325 MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
326 MPLS_IETF_IMPLICIT_NULL_LABEL == label));
327}
328
Neale Rannsad422ed2016-11-02 14:20:04 +0000329/**
330 * @brief Turn the chain type requested by the client into the one they
331 * really wanted
332 */
333fib_forward_chain_type_t
334fib_entry_chain_type_fixup (const fib_entry_t *entry,
335 fib_forward_chain_type_t fct)
336{
Neale Rannsad422ed2016-11-02 14:20:04 +0000337 /*
338 * The EOS chain is a tricky since one cannot know the adjacency
339 * to link to without knowing what the packets payload protocol
340 * will be once the label is popped.
341 */
342 fib_forward_chain_type_t dfct;
343
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800344 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
345 {
346 return (fct);
347 }
348
Neale Rannsad422ed2016-11-02 14:20:04 +0000349 dfct = fib_entry_get_default_chain_type(entry);
350
351 if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
352 {
353 /*
354 * If the entry being asked is a eos-MPLS label entry,
355 * then use the payload-protocol field, that we stashed there
356 * for just this purpose
357 */
358 return (fib_forw_chain_type_from_dpo_proto(
359 entry->fe_prefix.fp_payload_proto));
360 }
361 /*
362 * else give them what this entry would be by default. i.e. if it's a v6
363 * entry, then the label its local labelled should be carrying v6 traffic.
364 * If it's a non-EOS label entry, then there are more labels and we want
365 * a non-eos chain.
366 */
367 return (dfct);
368}
369
Neale Ranns62fe07c2017-10-31 12:28:22 -0700370static dpo_proto_t
371fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
372{
373 switch (pfx->fp_proto)
374 {
375 case FIB_PROTOCOL_IP4:
376 return (DPO_PROTO_IP4);
377 case FIB_PROTOCOL_IP6:
378 return (DPO_PROTO_IP6);
379 case FIB_PROTOCOL_MPLS:
380 return (pfx->fp_payload_proto);
381 }
382
383 ASSERT(0);
384 return (DPO_PROTO_IP4);
385}
386
Neale Ranns81424992017-05-18 03:03:22 -0700387static void
388fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
389 fib_entry_src_collect_forwarding_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100390{
Neale Ranns81424992017-05-18 03:03:22 -0700391 load_balance_path_t *nh;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100392
393 /*
Neale Ranns81424992017-05-18 03:03:22 -0700394 * no extension => no out-going label for this path. that's OK
395 * in the case of an IP or EOS chain, but not for non-EOS
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100396 */
Neale Ranns81424992017-05-18 03:03:22 -0700397 switch (ctx->fct)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100398 {
Neale Ranns81424992017-05-18 03:03:22 -0700399 case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
400 case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
401 case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
402 case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
Neale Rannsd792d9c2017-10-21 10:53:20 -0700403 case FIB_FORW_CHAIN_TYPE_BIER:
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100404 /*
Neale Ranns81424992017-05-18 03:03:22 -0700405 * EOS traffic with no label to stack, we need the IP Adj
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100406 */
Neale Ranns81424992017-05-18 03:03:22 -0700407 vec_add2(ctx->next_hops, nh, 1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100408
Neale Ranns81424992017-05-18 03:03:22 -0700409 nh->path_index = path_index;
410 nh->path_weight = fib_path_get_weight(path_index);
411 fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
412
413 break;
414 case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
415 if (fib_path_is_exclusive(path_index) ||
416 fib_path_is_deag(path_index))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100418 vec_add2(ctx->next_hops, nh, 1);
419
420 nh->path_index = path_index;
421 nh->path_weight = fib_path_get_weight(path_index);
Neale Ranns81424992017-05-18 03:03:22 -0700422 fib_path_contribute_forwarding(path_index,
423 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
424 &nh->path_dpo);
425 }
426 break;
427 case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
Neale Rannsad422ed2016-11-02 14:20:04 +0000428 {
429 /*
430 * no label. we need a chain based on the payload. fixup.
431 */
432 vec_add2(ctx->next_hops, nh, 1);
433
434 nh->path_index = path_index;
435 nh->path_weight = fib_path_get_weight(path_index);
436 fib_path_contribute_forwarding(path_index,
437 fib_entry_chain_type_fixup(ctx->fib_entry,
438 ctx->fct),
439 &nh->path_dpo);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800440 fib_path_stack_mpls_disp(path_index,
Neale Ranns62fe07c2017-10-31 12:28:22 -0700441 fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800442 &nh->path_dpo);
Neale Rannsad422ed2016-11-02 14:20:04 +0000443
444 break;
445 }
Neale Ranns81424992017-05-18 03:03:22 -0700446 case FIB_FORW_CHAIN_TYPE_ETHERNET:
447 case FIB_FORW_CHAIN_TYPE_NSH:
448 ASSERT(0);
449 break;
450 }
451}
452
453static fib_path_list_walk_rc_t
454fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
455 fib_node_index_t path_index,
456 void *arg)
457{
458 fib_entry_src_collect_forwarding_ctx_t *ctx;
459 fib_path_ext_t *path_ext;
460
461 ctx = arg;
462
463 /*
464 * if the path is not resolved, don't include it.
465 */
466 if (!fib_path_is_resolved(path_index))
467 {
468 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100469 }
470
Neale Ranns81424992017-05-18 03:03:22 -0700471 if (fib_path_is_recursive_constrained(path_index))
472 {
473 ctx->n_recursive_constrained += 1;
474 }
Neale Ranns57b58602017-07-15 07:37:25 -0700475 if (0xffff == ctx->preference)
476 {
477 /*
478 * not set a preference yet, so the first path we encounter
479 * sets the preference we are collecting.
480 */
481 ctx->preference = fib_path_get_preference(path_index);
482 }
483 else if (ctx->preference != fib_path_get_preference(path_index))
484 {
485 /*
486 * this path does not belong to the same preference as the
487 * previous paths encountered. we are done now.
488 */
489 return (FIB_PATH_LIST_WALK_STOP);
490 }
Neale Ranns81424992017-05-18 03:03:22 -0700491
492 /*
493 * get the matching path-extension for the path being visited.
494 */
495 path_ext = fib_path_ext_list_find_by_path_index(&ctx->esrc->fes_path_exts,
496 path_index);
497
498 if (NULL != path_ext)
499 {
500 switch (path_ext->fpe_type)
501 {
502 case FIB_PATH_EXT_MPLS:
503 if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0]))
504 {
505 /*
506 * found a matching extension. stack it to obtain the forwarding
507 * info for this path.
508 */
509 ctx->next_hops =
510 fib_path_ext_stack(path_ext,
511 ctx->fct,
512 fib_entry_chain_type_fixup(ctx->fib_entry,
513 ctx->fct),
514 ctx->next_hops);
515 }
516 else
517 {
518 fib_entry_src_get_path_forwarding(path_index, ctx);
519 }
520 break;
521 case FIB_PATH_EXT_ADJ:
522 if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
523 {
524 fib_entry_src_get_path_forwarding(path_index, ctx);
525 }
526 /*
527 * else
528 * the path does not refine the cover, meaning that
529 * the adjacency doesdoes not match the sub-net on the link.
530 * So this path does not contribute forwarding.
531 */
532 break;
533 }
534 }
535 else
536 {
537 fib_entry_src_get_path_forwarding(path_index, ctx);
538 }
539
540 return (FIB_PATH_LIST_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100541}
542
543void
544fib_entry_src_mk_lb (fib_entry_t *fib_entry,
545 const fib_entry_src_t *esrc,
546 fib_forward_chain_type_t fct,
547 dpo_id_t *dpo_lb)
548{
549 dpo_proto_t lb_proto;
550
551 /*
552 * If the entry has path extensions then we construct a load-balance
553 * by stacking the extensions on the forwarding chains of the paths.
554 * Otherwise we use the load-balance of the path-list
555 */
556 fib_entry_src_collect_forwarding_ctx_t ctx = {
557 .esrc = esrc,
558 .fib_entry = fib_entry,
559 .next_hops = NULL,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700560 .n_recursive_constrained = 0,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100561 .fct = fct,
Neale Ranns57b58602017-07-15 07:37:25 -0700562 .preference = 0xffff,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100563 };
564
Neale Rannsc0790cf2017-01-05 01:01:47 -0800565 /*
566 * As an optimisation we allocate the vector of next-hops to be sized
567 * equal to the maximum nuber of paths we will need, which is also the
568 * most likely number we will need, since in most cases the paths are 'up'.
569 */
570 vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
571 vec_reset_length(ctx.next_hops);
572
Neale Rannsf12a83f2017-04-18 09:09:40 -0700573 lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100574
575 fib_path_list_walk(esrc->fes_pl,
576 fib_entry_src_collect_forwarding,
577 &ctx);
578
579 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
580 {
581 /*
582 * the client provided the DPO that the entry should link to.
583 * all entries must link to a LB, so if it is an LB already
584 * then we can use it.
585 */
586 if ((1 == vec_len(ctx.next_hops)) &&
587 (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
588 {
589 dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
590 dpo_reset(&ctx.next_hops[0].path_dpo);
591 return;
592 }
593 }
594
595 if (!dpo_id_is_valid(dpo_lb))
596 {
597 /*
598 * first time create
599 */
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800600 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
601 {
602 dpo_set(dpo_lb,
603 DPO_REPLICATE,
604 lb_proto,
605 MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
606 }
607 else
608 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700609 fib_protocol_t flow_hash_proto;
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800610 flow_hash_config_t fhc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100611
Neale Ranns41da54f2017-05-02 10:15:19 -0700612 /*
613 * if the protocol for the LB we are building does not match that
614 * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
615 * then the fib_index is not an index that relates to the table
616 * type we need. So get the default flow-hash config instead.
617 */
Neale Rannsd792d9c2017-10-21 10:53:20 -0700618 flow_hash_proto = dpo_proto_to_fib(lb_proto);
619 if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
Neale Ranns41da54f2017-05-02 10:15:19 -0700620 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700621 fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700622 }
623 else
624 {
Neale Rannsd792d9c2017-10-21 10:53:20 -0700625 fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
626 flow_hash_proto);
Neale Ranns41da54f2017-05-02 10:15:19 -0700627 }
Neale Rannsd792d9c2017-10-21 10:53:20 -0700628
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800629 dpo_set(dpo_lb,
630 DPO_LOAD_BALANCE,
631 lb_proto,
632 load_balance_create(0, lb_proto, fhc));
633 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100634 }
635
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800636 if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
Neale Ranns3ee44042016-10-03 13:05:48 +0100637 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800638 /*
639 * MPLS multicast
640 */
641 replicate_multipath_update(dpo_lb, ctx.next_hops);
Neale Ranns3ee44042016-10-03 13:05:48 +0100642 }
643 else
644 {
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800645 load_balance_multipath_update(dpo_lb,
646 ctx.next_hops,
647 fib_entry_calc_lb_flags(&ctx));
648 vec_free(ctx.next_hops);
649
650 /*
651 * if this entry is sourced by the uRPF-exempt source then we
652 * append the always present local0 interface (index 0) to the
653 * uRPF list so it is not empty. that way packets pass the loose check.
654 */
655 index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
656
657 if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
658 FIB_SOURCE_URPF_EXEMPT) ||
659 (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
660 (0 == fib_urpf_check_size(ui)))
661 {
662 /*
663 * The uRPF list we get from the path-list is shared by all
664 * other users of the list, but the uRPF exemption applies
665 * only to this prefix. So we need our own list.
666 */
667 ui = fib_urpf_list_alloc_and_lock();
668 fib_urpf_list_append(ui, 0);
669 fib_urpf_list_bake(ui);
670 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
671 fib_urpf_list_unlock(ui);
672 }
673 else
674 {
675 load_balance_set_urpf(dpo_lb->dpoi_index, ui);
676 }
677 load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
678 fib_entry_get_flags_i(fib_entry));
Neale Ranns3ee44042016-10-03 13:05:48 +0100679 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100680}
681
682void
683fib_entry_src_action_install (fib_entry_t *fib_entry,
684 fib_source_t source)
685{
686 /*
687 * Install the forwarding chain for the given source into the forwarding
688 * tables
689 */
690 fib_forward_chain_type_t fct;
691 fib_entry_src_t *esrc;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100692 int insert;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100693
694 fct = fib_entry_get_default_chain_type(fib_entry);
695 esrc = fib_entry_src_find(fib_entry, source, NULL);
696
Neale Ranns33a7dd52016-10-07 15:14:33 +0100697 /*
698 * Every entry has its own load-balance object. All changes to the entry's
699 * forwarding result in an inplace modify of the load-balance. This means
700 * the load-balance object only needs to be added to the forwarding
701 * DB once, when it is created.
702 */
Neale Rannsad422ed2016-11-02 14:20:04 +0000703 insert = !dpo_id_is_valid(&fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100704
Neale Rannsad422ed2016-11-02 14:20:04 +0000705 fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100706
Neale Rannsad422ed2016-11-02 14:20:04 +0000707 ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
708 FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100709
710 /*
711 * insert the adj into the data-plane forwarding trie
712 */
Neale Ranns33a7dd52016-10-07 15:14:33 +0100713 if (insert)
714 {
715 fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
716 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000717 &fib_entry->fe_lb);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100718 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100719
Neale Rannsad422ed2016-11-02 14:20:04 +0000720 /*
721 * if any of the other chain types are already created they will need
722 * updating too
723 */
724 fib_entry_delegate_type_t fdt;
725 fib_entry_delegate_t *fed;
726
727 FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100728 {
Neale Rannsad422ed2016-11-02 14:20:04 +0000729 fib_entry_src_mk_lb(fib_entry, esrc,
730 fib_entry_delegate_type_to_chain_type(fdt),
731 &fed->fd_dpo);
732 });
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100733}
734
735void
736fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
737{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100738 /*
Neale Ranns3ee44042016-10-03 13:05:48 +0100739 * uninstall the forwarding chain from the forwarding tables
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100740 */
741 FIB_ENTRY_DBG(fib_entry, "uninstall: %d",
742 fib_entry->fe_adj_index);
743
Neale Rannsad422ed2016-11-02 14:20:04 +0000744 if (dpo_id_is_valid(&fib_entry->fe_lb))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100745 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100746 fib_table_fwding_dpo_remove(
747 fib_entry->fe_fib_index,
748 &fib_entry->fe_prefix,
Neale Rannsad422ed2016-11-02 14:20:04 +0000749 &fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100750
Neale Rannsad422ed2016-11-02 14:20:04 +0000751 dpo_reset(&fib_entry->fe_lb);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100752 }
753}
754
755static void
756fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
757{
758 fib_node_index_t *entries = NULL;
759
760 fib_path_list_recursive_loop_detect(path_list_index, &entries);
761
762 vec_free(entries);
763}
764
765void
766fib_entry_src_action_activate (fib_entry_t *fib_entry,
767 fib_source_t source)
768
769{
770 int houston_we_are_go_for_install;
771 fib_entry_src_t *esrc;
772
773 esrc = fib_entry_src_find(fib_entry, source, NULL);
774
775 ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
776 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
777
778 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ACTIVE;
779
780 if (NULL != fib_entry_src_vft[source].fesv_activate)
781 {
782 houston_we_are_go_for_install =
783 fib_entry_src_vft[source].fesv_activate(esrc, fib_entry);
784 }
785 else
786 {
787 /*
788 * the source is not providing an activate function, we'll assume
789 * therefore it has no objection to installing the entry
790 */
791 houston_we_are_go_for_install = !0;
792 }
793
794 /*
795 * link to the path-list provided by the source, and go check
796 * if that forms any loops in the graph.
797 */
798 fib_entry->fe_parent = esrc->fes_pl;
799 fib_entry->fe_sibling =
800 fib_path_list_child_add(fib_entry->fe_parent,
801 FIB_NODE_TYPE_ENTRY,
802 fib_entry_get_index(fib_entry));
803
804 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
805
806 FIB_ENTRY_DBG(fib_entry, "activate: %d",
807 fib_entry->fe_parent);
808
809 if (0 != houston_we_are_go_for_install)
810 {
811 fib_entry_src_action_install(fib_entry, source);
812 }
813 else
814 {
815 fib_entry_src_action_uninstall(fib_entry);
816 }
817}
818
819void
820fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
821 fib_source_t source)
822
823{
824 fib_node_index_t path_list_index;
825 fib_entry_src_t *esrc;
826
827 esrc = fib_entry_src_find(fib_entry, source, NULL);
828
829 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
830
831 if (NULL != fib_entry_src_vft[source].fesv_deactivate)
832 {
833 fib_entry_src_vft[source].fesv_deactivate(esrc, fib_entry);
834 }
835
836 esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
837
838 FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
839
840 /*
841 * un-link from an old path-list. Check for any loops this will clear
842 */
843 path_list_index = fib_entry->fe_parent;
844 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
845
846 fib_entry_recursive_loop_detect_i(path_list_index);
847
848 /*
849 * this will unlock the path-list, so it may be invalid thereafter.
850 */
851 fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
852 fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
853}
854
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100855void
856fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
857 fib_source_t source)
858{
859 fib_node_index_t path_list_index;
860 fib_entry_src_t *esrc;
861
862 esrc = fib_entry_src_find(fib_entry, source, NULL);
863
864 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
865
866 FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
867 fib_entry->fe_parent,
868 esrc->fes_pl);
869
870 if (fib_entry->fe_parent != esrc->fes_pl)
871 {
872 /*
873 * un-link from an old path-list. Check for any loops this will clear
874 */
875 path_list_index = fib_entry->fe_parent;
876 fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
877
878 /*
879 * temporary lock so it doesn't get deleted when this entry is no
880 * longer a child.
881 */
882 fib_path_list_lock(path_list_index);
883
884 /*
885 * this entry is no longer a child. after unlinking check if any loops
886 * were broken
887 */
888 fib_path_list_child_remove(path_list_index,
889 fib_entry->fe_sibling);
890
891 fib_entry_recursive_loop_detect_i(path_list_index);
892
893 /*
894 * link to the path-list provided by the source, and go check
895 * if that forms any loops in the graph.
896 */
897 fib_entry->fe_parent = esrc->fes_pl;
898 fib_entry->fe_sibling =
899 fib_path_list_child_add(fib_entry->fe_parent,
900 FIB_NODE_TYPE_ENTRY,
901 fib_entry_get_index(fib_entry));
902
903 fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
904 fib_path_list_unlock(path_list_index);
905 }
906 fib_entry_src_action_install(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100907}
908
909void
Neale Ranns84517cf2017-11-25 15:20:26 -0800910fib_entry_src_action_installed (fib_entry_t *fib_entry,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100911 fib_source_t source)
912{
913 fib_entry_src_t *esrc;
914
915 esrc = fib_entry_src_find(fib_entry, source, NULL);
916
917 if (NULL != fib_entry_src_vft[source].fesv_installed)
918 {
919 fib_entry_src_vft[source].fesv_installed(esrc,
920 fib_entry);
921 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100922}
923
924/*
925 * fib_entry_src_action_add
926 *
927 * Adding a source can result in a new fib_entry being created, which
928 * can inturn mean the pool is realloc'd and thus the entry passed as
929 * an argument it also realloc'd
930 * @return the original entry
931 */
932fib_entry_t *
933fib_entry_src_action_add (fib_entry_t *fib_entry,
934 fib_source_t source,
935 fib_entry_flag_t flags,
936 const dpo_id_t *dpo)
937{
938 fib_node_index_t fib_entry_index;
939 fib_entry_src_t *esrc;
940
Neale Ranns84517cf2017-11-25 15:20:26 -0800941 esrc = fib_entry_src_find_or_create(fib_entry, source);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100942
943 esrc->fes_ref_count++;
944
945 if (1 != esrc->fes_ref_count)
946 {
947 /*
948 * we only want to add the source on the 0->1 transition
949 */
950 return (fib_entry);
951 }
952
953 esrc->fes_entry_flags = flags;
954
955 /*
956 * save variable so we can recover from a fib_entry realloc.
957 */
958 fib_entry_index = fib_entry_get_index(fib_entry);
959
960 if (NULL != fib_entry_src_vft[source].fesv_add)
961 {
962 fib_entry_src_vft[source].fesv_add(esrc,
963 fib_entry,
964 flags,
Neale Rannsda78f952017-05-24 09:15:43 -0700965 fib_entry_get_dpo_proto(fib_entry),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100966 dpo);
967 }
968
969 fib_entry = fib_entry_get(fib_entry_index);
970
971 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
972
973 fib_path_list_lock(esrc->fes_pl);
974
975 /*
976 * the source owns a lock on the entry
977 */
978 fib_entry_lock(fib_entry_get_index(fib_entry));
979
980 return (fib_entry);
981}
982
Neale Ranns948e00f2016-10-20 13:39:34 +0100983/*
984 * fib_entry_src_action_update
985 *
986 * Adding a source can result in a new fib_entry being created, which
987 * can inturn mean the pool is realloc'd and thus the entry passed as
988 * an argument it also realloc'd
989 * @return the original entry
990 */
991fib_entry_t *
992fib_entry_src_action_update (fib_entry_t *fib_entry,
993 fib_source_t source,
994 fib_entry_flag_t flags,
995 const dpo_id_t *dpo)
996{
997 fib_node_index_t fib_entry_index, old_path_list_index;
998 fib_entry_src_t *esrc;
999
Neale Ranns84517cf2017-11-25 15:20:26 -08001000 esrc = fib_entry_src_find_or_create(fib_entry, source);
Neale Ranns948e00f2016-10-20 13:39:34 +01001001
1002 if (NULL == esrc)
1003 return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
1004
1005 old_path_list_index = esrc->fes_pl;
1006 esrc->fes_entry_flags = flags;
1007
1008 /*
1009 * save variable so we can recover from a fib_entry realloc.
1010 */
1011 fib_entry_index = fib_entry_get_index(fib_entry);
1012
1013 if (NULL != fib_entry_src_vft[source].fesv_add)
1014 {
1015 fib_entry_src_vft[source].fesv_add(esrc,
1016 fib_entry,
1017 flags,
Neale Rannsda78f952017-05-24 09:15:43 -07001018 fib_entry_get_dpo_proto(fib_entry),
Neale Ranns948e00f2016-10-20 13:39:34 +01001019 dpo);
1020 }
1021
1022 fib_entry = fib_entry_get(fib_entry_index);
1023
1024 esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1025
1026 fib_path_list_lock(esrc->fes_pl);
1027 fib_path_list_unlock(old_path_list_index);
1028
1029 return (fib_entry);
1030}
1031
1032
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001033fib_entry_src_flag_t
1034fib_entry_src_action_remove (fib_entry_t *fib_entry,
1035 fib_source_t source)
1036
1037{
1038 fib_node_index_t old_path_list;
1039 fib_entry_src_flag_t sflags;
1040 fib_entry_src_t *esrc;
1041
1042 esrc = fib_entry_src_find(fib_entry, source, NULL);
1043
1044 if (NULL == esrc)
1045 return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1046
1047 esrc->fes_ref_count--;
1048 sflags = esrc->fes_flags;
1049
1050 if (0 != esrc->fes_ref_count)
1051 {
1052 /*
1053 * only remove the source on the 1->0 transisition
1054 */
1055 return (sflags);
1056 }
1057
1058 if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
1059 {
1060 fib_entry_src_action_deactivate(fib_entry, source);
1061 }
1062
1063 old_path_list = esrc->fes_pl;
1064
1065 if (NULL != fib_entry_src_vft[source].fesv_remove)
1066 {
1067 fib_entry_src_vft[source].fesv_remove(esrc);
1068 }
1069
1070 fib_path_list_unlock(old_path_list);
1071 fib_entry_unlock(fib_entry_get_index(fib_entry));
1072
1073 sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
1074 fib_entry_src_action_deinit(fib_entry, source);
1075
1076 return (sflags);
1077}
1078
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001079/*
1080 * fib_route_attached_cross_table
1081 *
1082 * Return true the the route is attached via an interface that
1083 * is not in the same table as the route
1084 */
1085static inline int
1086fib_route_attached_cross_table (const fib_entry_t *fib_entry,
1087 const fib_route_path_t *rpath)
1088{
1089 /*
1090 * - All zeros next-hop
1091 * - a valid interface
1092 * - entry's fib index not equeal to interface's index
1093 */
1094 if (ip46_address_is_zero(&rpath->frp_addr) &&
1095 (~0 != rpath->frp_sw_if_index) &&
1096 (fib_entry->fe_fib_index !=
1097 fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
1098 rpath->frp_sw_if_index)))
1099 {
1100 return (!0);
1101 }
1102 return (0);
1103}
1104
1105/*
1106 * fib_route_attached_cross_table
1107 *
1108 * Return true the the route is attached via an interface that
1109 * is not in the same table as the route
1110 */
1111static inline int
1112fib_path_is_attached (const fib_route_path_t *rpath)
1113{
1114 /*
1115 * - All zeros next-hop
1116 * - a valid interface
1117 */
1118 if (ip46_address_is_zero(&rpath->frp_addr) &&
1119 (~0 != rpath->frp_sw_if_index))
1120 {
1121 return (!0);
1122 }
Neale Ranns4b919a52017-03-11 05:55:21 -08001123 else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
1124 {
1125 return (!0);
1126 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001127 return (0);
1128}
1129
1130fib_path_list_flags_t
1131fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
1132{
1133 fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
1134
1135 if (eflags & FIB_ENTRY_FLAG_DROP)
1136 {
1137 plf |= FIB_PATH_LIST_FLAG_DROP;
1138 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001139 if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
1140 {
1141 plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
1142 }
Neale Ranns0f26c5a2017-03-01 15:12:11 -08001143 if (eflags & FIB_ENTRY_FLAG_LOCAL)
1144 {
1145 plf |= FIB_PATH_LIST_FLAG_LOCAL;
1146 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001147
1148 return (plf);
1149}
1150
1151static void
1152fib_entry_flags_update (const fib_entry_t *fib_entry,
1153 const fib_route_path_t *rpath,
1154 fib_path_list_flags_t *pl_flags,
1155 fib_entry_src_t *esrc)
1156{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001157 if ((esrc->fes_src == FIB_SOURCE_API) ||
1158 (esrc->fes_src == FIB_SOURCE_CLI))
1159 {
1160 if (fib_path_is_attached(rpath))
1161 {
1162 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1163 }
1164 else
1165 {
1166 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1167 }
1168 }
1169 if (fib_route_attached_cross_table(fib_entry, rpath))
1170 {
1171 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1172 }
1173 else
1174 {
1175 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1176 }
1177}
1178
1179/*
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001180 * fib_entry_src_action_add
1181 *
1182 * Adding a source can result in a new fib_entry being created, which
1183 * can inturn mean the pool is realloc'd and thus the entry passed as
1184 * an argument it also realloc'd
1185 * @return the entry
1186 */
1187fib_entry_t*
1188fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1189 fib_source_t source,
1190 fib_entry_flag_t flags,
1191 const fib_route_path_t *rpath)
1192{
1193 fib_node_index_t old_path_list, fib_entry_index;
1194 fib_path_list_flags_t pl_flags;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001195 fib_entry_src_t *esrc;
1196
1197 /*
1198 * save variable so we can recover from a fib_entry realloc.
1199 */
1200 fib_entry_index = fib_entry_get_index(fib_entry);
1201
1202 esrc = fib_entry_src_find(fib_entry, source, NULL);
1203 if (NULL == esrc)
1204 {
1205 fib_entry =
1206 fib_entry_src_action_add(fib_entry,
1207 source,
1208 flags,
1209 drop_dpo_get(
Neale Rannsda78f952017-05-24 09:15:43 -07001210 fib_entry_get_dpo_proto(fib_entry)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001211 esrc = fib_entry_src_find(fib_entry, source, NULL);
1212 }
1213
1214 /*
1215 * we are no doubt modifying a path-list. If the path-list
1216 * is shared, and hence not modifiable, then the index returned
1217 * will be for a different path-list. This FIB entry to needs
1218 * to maintain its lock appropriately.
1219 */
1220 old_path_list = esrc->fes_pl;
1221
1222 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_add);
1223
1224 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1225 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1226
1227 fib_entry_src_vft[source].fesv_path_add(esrc, fib_entry, pl_flags, rpath);
1228 fib_entry = fib_entry_get(fib_entry_index);
1229
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001230 fib_path_list_lock(esrc->fes_pl);
1231 fib_path_list_unlock(old_path_list);
1232
1233 return (fib_entry);
1234}
1235
1236/*
1237 * fib_entry_src_action_swap
1238 *
1239 * The source is providing new paths to replace the old ones.
1240 * Adding a source can result in a new fib_entry being created, which
1241 * can inturn mean the pool is realloc'd and thus the entry passed as
1242 * an argument it also realloc'd
1243 * @return the entry
1244 */
1245fib_entry_t*
1246fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1247 fib_source_t source,
1248 fib_entry_flag_t flags,
1249 const fib_route_path_t *rpaths)
1250{
1251 fib_node_index_t old_path_list, fib_entry_index;
1252 fib_path_list_flags_t pl_flags;
1253 const fib_route_path_t *rpath;
1254 fib_entry_src_t *esrc;
1255
1256 esrc = fib_entry_src_find(fib_entry, source, NULL);
1257
1258 /*
1259 * save variable so we can recover from a fib_entry realloc.
1260 */
1261 fib_entry_index = fib_entry_get_index(fib_entry);
1262
1263 if (NULL == esrc)
1264 {
1265 fib_entry = fib_entry_src_action_add(fib_entry,
1266 source,
1267 flags,
1268 drop_dpo_get(
Neale Rannsda78f952017-05-24 09:15:43 -07001269 fib_entry_get_dpo_proto(fib_entry)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001270 esrc = fib_entry_src_find(fib_entry, source, NULL);
1271 }
1272
1273 /*
1274 * swapping paths may create a new path-list (or may use an existing shared)
1275 * but we are certainly getting a different one. This FIB entry to needs
1276 * to maintain its lock appropriately.
1277 */
1278 old_path_list = esrc->fes_pl;
1279
1280 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_swap);
1281
Neale Rannsdf089a82016-10-02 16:39:06 +01001282 pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1283
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001284 vec_foreach(rpath, rpaths)
1285 {
1286 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1287 }
1288
1289 fib_entry_src_vft[source].fesv_path_swap(esrc,
1290 fib_entry,
1291 pl_flags,
1292 rpaths);
1293
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001294 fib_entry = fib_entry_get(fib_entry_index);
1295
1296 fib_path_list_lock(esrc->fes_pl);
1297 fib_path_list_unlock(old_path_list);
1298
1299 return (fib_entry);
1300}
1301
1302fib_entry_src_flag_t
1303fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1304 fib_source_t source,
1305 const fib_route_path_t *rpath)
1306{
1307 fib_path_list_flags_t pl_flags;
1308 fib_node_index_t old_path_list;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001309 fib_entry_src_t *esrc;
1310
1311 esrc = fib_entry_src_find(fib_entry, source, NULL);
1312
1313 ASSERT(NULL != esrc);
1314 ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1315
1316 /*
1317 * we no doubt modifying a path-list. If the path-list
1318 * is shared, and hence not modifiable, then the index returned
1319 * will be for a different path-list. This FIB entry to needs
1320 * to maintain its lock appropriately.
1321 */
1322 old_path_list = esrc->fes_pl;
1323
1324 ASSERT(NULL != fib_entry_src_vft[source].fesv_path_remove);
1325
1326 pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1327 fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1328
1329 fib_entry_src_vft[source].fesv_path_remove(esrc, pl_flags, rpath);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001330
1331 /*
1332 * lock the new path-list, unlock the old if it had one
1333 */
1334 fib_path_list_unlock(old_path_list);
1335
1336 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1337 fib_path_list_lock(esrc->fes_pl);
1338 return (FIB_ENTRY_SRC_FLAG_ADDED);
1339 }
1340 else
1341 {
1342 /*
1343 * no more paths left from this source
1344 */
1345 fib_entry_src_action_remove(fib_entry, source);
1346 return (FIB_ENTRY_SRC_FLAG_NONE);
1347 }
1348}
1349
1350u8*
1351fib_entry_src_format (fib_entry_t *fib_entry,
1352 fib_source_t source,
1353 u8* s)
1354{
1355 fib_entry_src_t *esrc;
1356
1357 esrc = fib_entry_src_find(fib_entry, source, NULL);
1358
1359 if (NULL != fib_entry_src_vft[source].fesv_format)
1360 {
1361 return (fib_entry_src_vft[source].fesv_format(esrc, s));
1362 }
1363 return (s);
1364}
1365
1366adj_index_t
1367fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1368 fib_source_t source)
1369{
1370 fib_entry_t *fib_entry;
1371 fib_entry_src_t *esrc;
1372
1373 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1374 return (ADJ_INDEX_INVALID);
1375
1376 fib_entry = fib_entry_get(fib_entry_index);
1377 esrc = fib_entry_src_find(fib_entry, source, NULL);
1378
1379 if (NULL != esrc)
1380 {
1381 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1382 {
1383 return (fib_path_list_get_adj(
1384 esrc->fes_pl,
1385 fib_entry_get_default_chain_type(fib_entry)));
1386 }
1387 }
1388 return (ADJ_INDEX_INVALID);
1389}
1390
1391const int
1392fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1393 fib_source_t source,
1394 dpo_id_t *dpo)
1395{
1396 fib_entry_t *fib_entry;
1397 fib_entry_src_t *esrc;
1398
1399 if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1400 return (0);
1401
1402 fib_entry = fib_entry_get(fib_entry_index);
1403 esrc = fib_entry_src_find(fib_entry, source, NULL);
1404
1405 if (NULL != esrc)
1406 {
1407 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1408 {
1409 fib_path_list_contribute_forwarding(
1410 esrc->fes_pl,
1411 fib_entry_get_default_chain_type(fib_entry),
1412 dpo);
1413
1414 return (dpo_id_is_valid(dpo));
1415 }
1416 }
1417 return (0);
1418}
1419
Neale Rannsdf089a82016-10-02 16:39:06 +01001420u32
1421fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1422 fib_source_t source)
1423{
1424 fib_entry_t *fib_entry;
1425 fib_entry_src_t *esrc;
1426
1427 fib_entry = fib_entry_get(entry_index);
1428
1429 esrc = fib_entry_src_find(fib_entry, source, NULL);
1430
1431 if (NULL != esrc)
1432 {
1433 if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1434 {
1435 return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1436 }
1437 }
1438 return (~0);
1439}
1440
1441fib_entry_flag_t
1442fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1443 fib_source_t source)
1444{
1445 fib_entry_t *fib_entry;
1446 fib_entry_src_t *esrc;
1447
1448 fib_entry = fib_entry_get(entry_index);
1449
1450 esrc = fib_entry_src_find(fib_entry, source, NULL);
1451
1452 if (NULL != esrc)
1453 {
1454 return (esrc->fes_entry_flags);
1455 }
1456
1457 return (FIB_ENTRY_FLAG_NONE);
1458}
1459
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001460void
1461fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1462 fib_source_t source,
1463 const void *data)
1464{
1465 fib_entry_t *fib_entry;
1466 fib_entry_src_t *esrc;
1467
1468 fib_entry = fib_entry_get(fib_entry_index);
1469 esrc = fib_entry_src_find(fib_entry, source, NULL);
1470
1471 if (NULL != esrc &&
1472 NULL != fib_entry_src_vft[source].fesv_set_data)
1473 {
1474 fib_entry_src_vft[source].fesv_set_data(esrc, fib_entry, data);
1475 }
1476}
1477
1478const void*
1479fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1480 fib_source_t source)
1481{
1482 fib_entry_t *fib_entry;
1483 fib_entry_src_t *esrc;
1484
1485 fib_entry = fib_entry_get(fib_entry_index);
1486 esrc = fib_entry_src_find(fib_entry, source, NULL);
1487
1488 if (NULL != esrc &&
1489 NULL != fib_entry_src_vft[source].fesv_get_data)
1490 {
1491 return (fib_entry_src_vft[source].fesv_get_data(esrc, fib_entry));
1492 }
1493 return (NULL);
1494}
1495
1496void
1497fib_entry_src_module_init (void)
1498{
1499 fib_entry_src_rr_register();
1500 fib_entry_src_interface_register();
1501 fib_entry_src_default_route_register();
1502 fib_entry_src_special_register();
1503 fib_entry_src_api_register();
1504 fib_entry_src_adj_register();
1505 fib_entry_src_mpls_register();
1506 fib_entry_src_lisp_register();
1507}