Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vlib/vlib.h>
17 : #include <vnet/vnet.h>
18 : #include <vnet/ip/format.h>
19 : #include <vnet/ip/ip.h>
20 : #include <vnet/dpo/drop_dpo.h>
21 : #include <vnet/dpo/receive_dpo.h>
22 : #include <vnet/dpo/load_balance_map.h>
23 : #include <vnet/dpo/lookup_dpo.h>
24 : #include <vnet/dpo/interface_rx_dpo.h>
25 : #include <vnet/dpo/mpls_disposition.h>
26 : #include <vnet/dpo/dvr_dpo.h>
27 : #include <vnet/dpo/ip_null_dpo.h>
28 : #include <vnet/dpo/classify_dpo.h>
29 : #include <vnet/dpo/pw_cw.h>
30 :
31 : #include <vnet/adj/adj.h>
32 : #include <vnet/adj/adj_mcast.h>
33 :
34 : #include <vnet/fib/fib_path.h>
35 : #include <vnet/fib/fib_node.h>
36 : #include <vnet/fib/fib_table.h>
37 : #include <vnet/fib/fib_entry.h>
38 : #include <vnet/fib/fib_path_list.h>
39 : #include <vnet/fib/fib_internal.h>
40 : #include <vnet/fib/fib_urpf_list.h>
41 : #include <vnet/fib/mpls_fib.h>
42 : #include <vnet/fib/fib_path_ext.h>
43 : #include <vnet/udp/udp_encap.h>
44 : #include <vnet/bier/bier_fmask.h>
45 : #include <vnet/bier/bier_table.h>
46 : #include <vnet/bier/bier_imp.h>
47 : #include <vnet/bier/bier_disp_table.h>
48 :
49 : /**
50 : * Enurmeration of path types
51 : */
52 : typedef enum fib_path_type_t_ {
53 : /**
54 : * Marker. Add new types after this one.
55 : */
56 : FIB_PATH_TYPE_FIRST = 0,
57 : /**
58 : * Attached-nexthop. An interface and a nexthop are known.
59 : */
60 : FIB_PATH_TYPE_ATTACHED_NEXT_HOP = FIB_PATH_TYPE_FIRST,
61 : /**
62 : * attached. Only the interface is known.
63 : */
64 : FIB_PATH_TYPE_ATTACHED,
65 : /**
66 : * recursive. Only the next-hop is known.
67 : */
68 : FIB_PATH_TYPE_RECURSIVE,
69 : /**
70 : * special. nothing is known. so we drop.
71 : */
72 : FIB_PATH_TYPE_SPECIAL,
73 : /**
74 : * exclusive. user provided adj.
75 : */
76 : FIB_PATH_TYPE_EXCLUSIVE,
77 : /**
78 : * deag. Link to a lookup adj in the next table
79 : */
80 : FIB_PATH_TYPE_DEAG,
81 : /**
82 : * interface receive.
83 : */
84 : FIB_PATH_TYPE_INTF_RX,
85 : /**
86 : * Path resolves via a UDP encap object.
87 : */
88 : FIB_PATH_TYPE_UDP_ENCAP,
89 : /**
90 : * receive. it's for-us.
91 : */
92 : FIB_PATH_TYPE_RECEIVE,
93 : /**
94 : * bier-imp. it's via a BIER imposition.
95 : */
96 : FIB_PATH_TYPE_BIER_IMP,
97 : /**
98 : * bier-fmask. it's via a BIER ECMP-table.
99 : */
100 : FIB_PATH_TYPE_BIER_TABLE,
101 : /**
102 : * bier-fmask. it's via a BIER f-mask.
103 : */
104 : FIB_PATH_TYPE_BIER_FMASK,
105 : /**
106 : * via a DVR.
107 : */
108 : FIB_PATH_TYPE_DVR,
109 : } __attribute__ ((packed)) fib_path_type_t;
110 :
111 : #define FIB_PATH_TYPES { \
112 : [FIB_PATH_TYPE_ATTACHED_NEXT_HOP] = "attached-nexthop", \
113 : [FIB_PATH_TYPE_ATTACHED] = "attached", \
114 : [FIB_PATH_TYPE_RECURSIVE] = "recursive", \
115 : [FIB_PATH_TYPE_SPECIAL] = "special", \
116 : [FIB_PATH_TYPE_EXCLUSIVE] = "exclusive", \
117 : [FIB_PATH_TYPE_DEAG] = "deag", \
118 : [FIB_PATH_TYPE_INTF_RX] = "intf-rx", \
119 : [FIB_PATH_TYPE_UDP_ENCAP] = "udp-encap", \
120 : [FIB_PATH_TYPE_RECEIVE] = "receive", \
121 : [FIB_PATH_TYPE_BIER_IMP] = "bier-imp", \
122 : [FIB_PATH_TYPE_BIER_TABLE] = "bier-table", \
123 : [FIB_PATH_TYPE_BIER_FMASK] = "bier-fmask", \
124 : [FIB_PATH_TYPE_DVR] = "dvr", \
125 : }
126 :
127 : /**
128 : * Enurmeration of path operational (i.e. derived) attributes
129 : */
130 : typedef enum fib_path_oper_attribute_t_ {
131 : /**
132 : * Marker. Add new types after this one.
133 : */
134 : FIB_PATH_OPER_ATTRIBUTE_FIRST = 0,
135 : /**
136 : * The path forms part of a recursive loop.
137 : */
138 : FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP = FIB_PATH_OPER_ATTRIBUTE_FIRST,
139 : /**
140 : * The path is resolved
141 : */
142 : FIB_PATH_OPER_ATTRIBUTE_RESOLVED,
143 : /**
144 : * The path has become a permanent drop.
145 : */
146 : FIB_PATH_OPER_ATTRIBUTE_DROP,
147 : /**
148 : * Marker. Add new types before this one, then update it.
149 : */
150 : FIB_PATH_OPER_ATTRIBUTE_LAST = FIB_PATH_OPER_ATTRIBUTE_DROP,
151 : } __attribute__ ((packed)) fib_path_oper_attribute_t;
152 :
153 : /**
154 : * The maximum number of path operational attributes
155 : */
156 : #define FIB_PATH_OPER_ATTRIBUTE_MAX (FIB_PATH_OPER_ATTRIBUTE_LAST + 1)
157 :
158 : #define FIB_PATH_OPER_ATTRIBUTES { \
159 : [FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP] = "recursive-loop", \
160 : [FIB_PATH_OPER_ATTRIBUTE_RESOLVED] = "resolved", \
161 : [FIB_PATH_OPER_ATTRIBUTE_DROP] = "drop", \
162 : }
163 :
164 : #define FOR_EACH_FIB_PATH_OPER_ATTRIBUTE(_item) \
165 : for (_item = FIB_PATH_OPER_ATTRIBUTE_FIRST; \
166 : _item <= FIB_PATH_OPER_ATTRIBUTE_LAST; \
167 : _item++)
168 :
169 : /**
170 : * Path flags from the attributes
171 : */
172 : typedef enum fib_path_oper_flags_t_ {
173 : FIB_PATH_OPER_FLAG_NONE = 0,
174 : FIB_PATH_OPER_FLAG_RECURSIVE_LOOP = (1 << FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP),
175 : FIB_PATH_OPER_FLAG_DROP = (1 << FIB_PATH_OPER_ATTRIBUTE_DROP),
176 : FIB_PATH_OPER_FLAG_RESOLVED = (1 << FIB_PATH_OPER_ATTRIBUTE_RESOLVED),
177 : } __attribute__ ((packed)) fib_path_oper_flags_t;
178 :
179 : /**
180 : * A FIB path
181 : */
182 : typedef struct fib_path_t_ {
183 : /**
184 : * A path is a node in the FIB graph.
185 : */
186 : fib_node_t fp_node;
187 :
188 : /**
189 : * The index of the path-list to which this path belongs
190 : */
191 : u32 fp_pl_index;
192 :
193 : /**
194 : * This marks the start of the memory area used to hash
195 : * the path
196 : */
197 : STRUCT_MARK(path_hash_start);
198 :
199 : /**
200 : * Configuration Flags
201 : */
202 : fib_path_cfg_flags_t fp_cfg_flags;
203 :
204 : /**
205 : * The type of the path. This is the selector for the union
206 : */
207 : fib_path_type_t fp_type;
208 :
209 : /**
210 : * The protocol of the next-hop, i.e. the address family of the
211 : * next-hop's address. We can't derive this from the address itself
212 : * since the address can be all zeros
213 : */
214 : dpo_proto_t fp_nh_proto;
215 :
216 : /**
217 : * UCMP [unnormalised] weigth
218 : */
219 : u8 fp_weight;
220 :
221 : /**
222 : * A path preference. 0 is the best.
223 : * Only paths of the best preference, that are 'up', are considered
224 : * for forwarding.
225 : */
226 : u8 fp_preference;
227 :
228 : /**
229 : * per-type union of the data required to resolve the path
230 : */
231 : union {
232 : struct {
233 : /**
234 : * The next-hop
235 : */
236 : ip46_address_t fp_nh;
237 : /**
238 : * The interface
239 : */
240 : u32 fp_interface;
241 : } attached_next_hop;
242 : struct {
243 : /**
244 : * The Connected local address
245 : */
246 : fib_prefix_t fp_connected;
247 : /**
248 : * The interface
249 : */
250 : u32 fp_interface;
251 : } attached;
252 : struct {
253 : union
254 : {
255 : /**
256 : * The next-hop
257 : */
258 : ip46_address_t fp_ip;
259 : struct {
260 : /**
261 : * The local label to resolve through.
262 : */
263 : mpls_label_t fp_local_label;
264 : /**
265 : * The EOS bit of the resolving label
266 : */
267 : mpls_eos_bit_t fp_eos;
268 : };
269 : } fp_nh;
270 : /**
271 : * The FIB table index in which to find the next-hop.
272 : */
273 : fib_node_index_t fp_tbl_id;
274 : } recursive;
275 : struct {
276 : /**
277 : * BIER FMask ID
278 : */
279 : index_t fp_bier_fmask;
280 : } bier_fmask;
281 : struct {
282 : /**
283 : * The BIER table's ID
284 : */
285 : bier_table_id_t fp_bier_tbl;
286 : } bier_table;
287 : struct {
288 : /**
289 : * The BIER imposition object
290 : * this is part of the path's key, since the index_t
291 : * of an imposition object is the object's key.
292 : */
293 : index_t fp_bier_imp;
294 : } bier_imp;
295 : struct {
296 : /**
297 : * The FIB index in which to perfom the next lookup
298 : */
299 : fib_node_index_t fp_tbl_id;
300 : /**
301 : * The RPF-ID to tag the packets with
302 : */
303 : fib_rpf_id_t fp_rpf_id;
304 : } deag;
305 : struct {
306 : } special;
307 : struct {
308 : /**
309 : * The user provided 'exclusive' DPO
310 : */
311 : dpo_id_t fp_ex_dpo;
312 : } exclusive;
313 : struct {
314 : /**
315 : * The interface on which the local address is configured
316 : */
317 : u32 fp_interface;
318 : /**
319 : * The next-hop
320 : */
321 : ip46_address_t fp_addr;
322 : } receive;
323 : struct {
324 : /**
325 : * The interface on which the packets will be input.
326 : */
327 : u32 fp_interface;
328 : } intf_rx;
329 : struct {
330 : /**
331 : * The UDP Encap object this path resolves through
332 : */
333 : u32 fp_udp_encap_id;
334 : } udp_encap;
335 : struct {
336 : /**
337 : * The UDP Encap object this path resolves through
338 : */
339 : u32 fp_classify_table_id;
340 : } classify;
341 : struct {
342 : /**
343 : * The interface
344 : */
345 : u32 fp_interface;
346 : } dvr;
347 : };
348 : STRUCT_MARK(path_hash_end);
349 :
350 : /**
351 : * Members in this last section represent information that is
352 : * dervied during resolution. It should not be copied to new paths
353 : * nor compared.
354 : */
355 :
356 : /**
357 : * Operational Flags
358 : */
359 : fib_path_oper_flags_t fp_oper_flags;
360 :
361 : union {
362 : /**
363 : * the resolving via fib. not part of the union, since it it not part
364 : * of the path's hash.
365 : */
366 : fib_node_index_t fp_via_fib;
367 : /**
368 : * the resolving bier-table
369 : */
370 : index_t fp_via_bier_tbl;
371 : /**
372 : * the resolving bier-fmask
373 : */
374 : index_t fp_via_bier_fmask;
375 : };
376 :
377 : /**
378 : * The Data-path objects through which this path resolves for IP.
379 : */
380 : dpo_id_t fp_dpo;
381 :
382 : /**
383 : * the index of this path in the parent's child list.
384 : */
385 : u32 fp_sibling;
386 : } fib_path_t;
387 :
388 : /*
389 : * Array of strings/names for the path types and attributes
390 : */
391 : static const char *fib_path_type_names[] = FIB_PATH_TYPES;
392 : static const char *fib_path_oper_attribute_names[] = FIB_PATH_OPER_ATTRIBUTES;
393 : static const char *fib_path_cfg_attribute_names[] = FIB_PATH_CFG_ATTRIBUTES;
394 :
395 : /*
396 : * The memory pool from which we allocate all the paths
397 : */
398 : static fib_path_t *fib_path_pool;
399 :
400 : /**
401 : * the logger
402 : */
403 : vlib_log_class_t fib_path_logger;
404 :
405 : /*
406 : * Debug macro
407 : */
408 : #define FIB_PATH_DBG(_p, _fmt, _args...) \
409 : { \
410 : vlib_log_debug (fib_path_logger, \
411 : "[%U]: " _fmt, \
412 : format_fib_path, fib_path_get_index(_p), 0, \
413 : FIB_PATH_FORMAT_FLAGS_ONE_LINE, \
414 : ##_args); \
415 : }
416 :
417 : static fib_path_t *
418 2723610 : fib_path_get (fib_node_index_t index)
419 : {
420 2723610 : return (pool_elt_at_index(fib_path_pool, index));
421 : }
422 :
423 : static fib_node_index_t
424 464340 : fib_path_get_index (fib_path_t *path)
425 : {
426 464340 : return (path - fib_path_pool);
427 : }
428 :
429 : static fib_node_t *
430 35998 : fib_path_get_node (fib_node_index_t index)
431 : {
432 35998 : return ((fib_node_t*)fib_path_get(index));
433 : }
434 :
435 : static fib_path_t*
436 35998 : fib_path_from_fib_node (fib_node_t *node)
437 : {
438 35998 : ASSERT(FIB_NODE_TYPE_PATH == node->fn_type);
439 35998 : return ((fib_path_t*)node);
440 : }
441 :
442 : u8 *
443 320 : format_fib_path (u8 * s, va_list * args)
444 : {
445 320 : fib_node_index_t path_index = va_arg (*args, fib_node_index_t);
446 320 : u32 indent = va_arg (*args, u32);
447 320 : fib_format_path_flags_t flags = va_arg (*args, fib_format_path_flags_t);
448 320 : vnet_main_t * vnm = vnet_get_main();
449 : fib_path_oper_attribute_t oattr;
450 : fib_path_cfg_attribute_t cattr;
451 : fib_path_t *path;
452 : const char *eol;
453 :
454 320 : if (flags & FIB_PATH_FORMAT_FLAGS_ONE_LINE)
455 : {
456 0 : eol = "";
457 : }
458 : else
459 : {
460 320 : eol = "\n";
461 : }
462 :
463 320 : path = fib_path_get(path_index);
464 :
465 320 : s = format (s, "%Upath:[%d] ", format_white_space, indent,
466 : fib_path_get_index(path));
467 320 : s = format (s, "pl-index:%d ", path->fp_pl_index);
468 320 : s = format (s, "%U ", format_dpo_proto, path->fp_nh_proto);
469 320 : s = format (s, "weight=%d ", path->fp_weight);
470 320 : s = format (s, "pref=%d ", path->fp_preference);
471 320 : s = format (s, "%s: ", fib_path_type_names[path->fp_type]);
472 320 : if (FIB_PATH_OPER_FLAG_NONE != path->fp_oper_flags) {
473 168 : s = format(s, " oper-flags:");
474 672 : FOR_EACH_FIB_PATH_OPER_ATTRIBUTE(oattr) {
475 504 : if ((1<<oattr) & path->fp_oper_flags) {
476 168 : s = format (s, "%s,", fib_path_oper_attribute_names[oattr]);
477 : }
478 : }
479 : }
480 320 : if (FIB_PATH_CFG_FLAG_NONE != path->fp_cfg_flags) {
481 304 : s = format(s, " cfg-flags:");
482 4560 : FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(cattr) {
483 4256 : if ((1<<cattr) & path->fp_cfg_flags) {
484 306 : s = format (s, "%s,", fib_path_cfg_attribute_names[cattr]);
485 : }
486 : }
487 : }
488 320 : if (!(flags & FIB_PATH_FORMAT_FLAGS_ONE_LINE))
489 320 : s = format(s, "\n%U", format_white_space, indent+2);
490 :
491 320 : switch (path->fp_type)
492 : {
493 9 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
494 9 : s = format (s, "%U", format_ip46_address,
495 : &path->attached_next_hop.fp_nh,
496 : IP46_TYPE_ANY);
497 9 : if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP)
498 : {
499 0 : s = format (s, " if_index:%d", path->attached_next_hop.fp_interface);
500 : }
501 : else
502 : {
503 9 : s = format (s, " %U",
504 : format_vnet_sw_interface_name,
505 : vnm,
506 : vnet_get_sw_interface(
507 : vnm,
508 : path->attached_next_hop.fp_interface));
509 9 : if (vnet_sw_interface_is_p2p(vnet_get_main(),
510 : path->attached_next_hop.fp_interface))
511 : {
512 0 : s = format (s, " (p2p)");
513 : }
514 : }
515 9 : if (!dpo_id_is_valid(&path->fp_dpo))
516 : {
517 0 : s = format(s, "%s%Uunresolved", eol, format_white_space, indent+2);
518 : }
519 : else
520 : {
521 9 : s = format(s, "%s%U%U", eol,
522 : format_white_space, indent,
523 : format_dpo_id,
524 : &path->fp_dpo, 13);
525 : }
526 9 : break;
527 9 : case FIB_PATH_TYPE_ATTACHED:
528 9 : if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP)
529 : {
530 0 : s = format (s, "if_index:%d", path->attached_next_hop.fp_interface);
531 : }
532 : else
533 : {
534 9 : s = format (s, " %U",
535 : format_vnet_sw_interface_name,
536 : vnm,
537 : vnet_get_sw_interface(
538 : vnm,
539 : path->attached.fp_interface));
540 : }
541 9 : break;
542 136 : case FIB_PATH_TYPE_RECURSIVE:
543 136 : if (DPO_PROTO_MPLS == path->fp_nh_proto)
544 : {
545 2 : s = format (s, "via %U %U",
546 : format_mpls_unicast_label,
547 : path->recursive.fp_nh.fp_local_label,
548 : format_mpls_eos_bit,
549 2 : path->recursive.fp_nh.fp_eos);
550 : }
551 : else
552 : {
553 134 : s = format (s, "via %U",
554 : format_ip46_address,
555 : &path->recursive.fp_nh.fp_ip,
556 : IP46_TYPE_ANY);
557 : }
558 136 : s = format (s, " in fib:%d",
559 : path->recursive.fp_tbl_id,
560 : path->fp_via_fib);
561 136 : s = format (s, " via-fib:%d", path->fp_via_fib);
562 136 : s = format (s, " via-dpo:[%U:%d]",
563 136 : format_dpo_type, path->fp_dpo.dpoi_type,
564 : path->fp_dpo.dpoi_index);
565 :
566 136 : break;
567 0 : case FIB_PATH_TYPE_UDP_ENCAP:
568 0 : s = format (s, "UDP-encap ID:%d", path->udp_encap.fp_udp_encap_id);
569 0 : break;
570 0 : case FIB_PATH_TYPE_BIER_TABLE:
571 0 : s = format (s, "via bier-table:[%U}",
572 : format_bier_table_id,
573 : &path->bier_table.fp_bier_tbl);
574 0 : s = format (s, " via-dpo:[%U:%d]",
575 0 : format_dpo_type, path->fp_dpo.dpoi_type,
576 : path->fp_dpo.dpoi_index);
577 0 : break;
578 0 : case FIB_PATH_TYPE_BIER_FMASK:
579 0 : s = format (s, "via-fmask:%d", path->bier_fmask.fp_bier_fmask);
580 0 : s = format (s, " via-dpo:[%U:%d]",
581 0 : format_dpo_type, path->fp_dpo.dpoi_type,
582 : path->fp_dpo.dpoi_index);
583 0 : break;
584 0 : case FIB_PATH_TYPE_BIER_IMP:
585 0 : s = format (s, "via %U", format_bier_imp,
586 : path->bier_imp.fp_bier_imp, 0, BIER_SHOW_BRIEF);
587 0 : break;
588 0 : case FIB_PATH_TYPE_DVR:
589 0 : s = format (s, " %U",
590 : format_vnet_sw_interface_name,
591 : vnm,
592 : vnet_get_sw_interface(
593 : vnm,
594 : path->dvr.fp_interface));
595 0 : break;
596 0 : case FIB_PATH_TYPE_DEAG:
597 0 : s = format (s, " %sfib-index:%d",
598 0 : (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ? "m" : ""),
599 : path->deag.fp_tbl_id);
600 0 : break;
601 166 : case FIB_PATH_TYPE_RECEIVE:
602 : case FIB_PATH_TYPE_INTF_RX:
603 : case FIB_PATH_TYPE_SPECIAL:
604 : case FIB_PATH_TYPE_EXCLUSIVE:
605 166 : if (dpo_id_is_valid(&path->fp_dpo))
606 : {
607 166 : s = format(s, "%U", format_dpo_id,
608 : &path->fp_dpo, indent+2);
609 : }
610 166 : break;
611 : }
612 320 : return (s);
613 : }
614 :
615 : /*
616 : * fib_path_last_lock_gone
617 : *
618 : * We don't share paths, we share path lists, so the [un]lock functions
619 : * are no-ops
620 : */
621 : static void
622 0 : fib_path_last_lock_gone (fib_node_t *node)
623 : {
624 0 : ASSERT(0);
625 0 : }
626 :
627 : static fib_path_t*
628 17482 : fib_path_attached_next_hop_get_adj (fib_path_t *path,
629 : vnet_link_t link,
630 : dpo_id_t *dpo)
631 : {
632 : fib_node_index_t fib_path_index;
633 : fib_protocol_t nh_proto;
634 : adj_index_t ai;
635 :
636 17482 : fib_path_index = fib_path_get_index(path);
637 17482 : nh_proto = dpo_proto_to_fib(path->fp_nh_proto);
638 :
639 17482 : if (vnet_sw_interface_is_p2p(vnet_get_main(),
640 : path->attached_next_hop.fp_interface))
641 : {
642 : /*
643 : * if the interface is p2p then the adj for the specific
644 : * neighbour on that link will never exist. on p2p links
645 : * the subnet address (the attached route) links to the
646 : * auto-adj (see below), we want that adj here too.
647 : */
648 247 : ai = adj_nbr_add_or_lock(nh_proto, link, &zero_addr,
649 : path->attached_next_hop.fp_interface);
650 : }
651 : else
652 : {
653 17235 : ai = adj_nbr_add_or_lock(nh_proto, link,
654 17235 : &path->attached_next_hop.fp_nh,
655 : path->attached_next_hop.fp_interface);
656 : }
657 :
658 17482 : dpo_set(dpo, DPO_ADJACENCY, vnet_link_to_dpo_proto(link), ai);
659 17482 : adj_unlock(ai);
660 :
661 17482 : return (fib_path_get(fib_path_index));
662 : }
663 :
664 : static void
665 10417 : fib_path_attached_next_hop_set (fib_path_t *path)
666 : {
667 10417 : dpo_id_t tmp = DPO_INVALID;
668 :
669 : /*
670 : * resolve directly via the adjacency discribed by the
671 : * interface and next-hop
672 : */
673 10417 : dpo_copy (&tmp, &path->fp_dpo);
674 10417 : path = fib_path_attached_next_hop_get_adj(path,
675 10417 : dpo_proto_to_link(path->fp_nh_proto),
676 : &tmp);
677 10417 : dpo_copy(&path->fp_dpo, &tmp);
678 10417 : dpo_reset(&tmp);
679 10417 : ASSERT(dpo_is_adj(&path->fp_dpo));
680 :
681 : /*
682 : * become a child of the adjacency so we receive updates
683 : * when its rewrite changes
684 : */
685 10417 : path->fp_sibling = adj_child_add(path->fp_dpo.dpoi_index,
686 : FIB_NODE_TYPE_PATH,
687 : fib_path_get_index(path));
688 :
689 10417 : if (!vnet_sw_interface_is_up(vnet_get_main(),
690 9930 : path->attached_next_hop.fp_interface) ||
691 9930 : !adj_is_up(path->fp_dpo.dpoi_index))
692 : {
693 489 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
694 : }
695 10417 : }
696 :
697 : static void
698 36521 : fib_path_attached_get_adj (fib_path_t *path,
699 : vnet_link_t link,
700 : dpo_id_t *dpo)
701 : {
702 : fib_protocol_t nh_proto;
703 :
704 36521 : nh_proto = dpo_proto_to_fib(path->fp_nh_proto);
705 :
706 36521 : if (vnet_sw_interface_is_p2p(vnet_get_main(),
707 : path->attached.fp_interface))
708 : {
709 : /*
710 : * point-2-point interfaces do not require a glean, since
711 : * there is nothing to ARP. Install a rewrite/nbr adj instead
712 : */
713 : adj_index_t ai;
714 :
715 1270 : ai = adj_nbr_add_or_lock(nh_proto, link, &zero_addr,
716 : path->attached.fp_interface);
717 :
718 1270 : dpo_set(dpo, DPO_ADJACENCY, vnet_link_to_dpo_proto(link), ai);
719 1270 : adj_unlock(ai);
720 : }
721 35251 : else if (vnet_sw_interface_is_nbma(vnet_get_main(),
722 : path->attached.fp_interface))
723 : {
724 364 : dpo_copy(dpo, drop_dpo_get(path->fp_nh_proto));
725 : }
726 : else
727 : {
728 : adj_index_t ai;
729 :
730 34887 : ai = adj_glean_add_or_lock(nh_proto, link,
731 : path->attached.fp_interface,
732 34887 : &path->attached.fp_connected);
733 34887 : dpo_set(dpo, DPO_ADJACENCY_GLEAN, vnet_link_to_dpo_proto(link), ai);
734 34887 : adj_unlock(ai);
735 : }
736 36521 : }
737 :
738 : /*
739 : * create of update the paths recursive adj
740 : */
741 : static void
742 5037 : fib_path_recursive_adj_update (fib_path_t *path,
743 : fib_forward_chain_type_t fct,
744 : dpo_id_t *dpo)
745 : {
746 5037 : dpo_id_t via_dpo = DPO_INVALID;
747 :
748 : /*
749 : * get the DPO to resolve through from the via-entry
750 : */
751 5037 : fib_entry_contribute_forwarding(path->fp_via_fib,
752 : fct,
753 : &via_dpo);
754 :
755 :
756 : /*
757 : * hope for the best - clear if restrictions apply.
758 : */
759 5037 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
760 :
761 : /*
762 : * Validate any recursion constraints and over-ride the via
763 : * adj if not met
764 : */
765 5037 : if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP)
766 : {
767 16 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
768 16 : dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto));
769 : }
770 5021 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_HOST)
771 : {
772 : /*
773 : * the via FIB must be a host route.
774 : * note the via FIB just added will always be a host route
775 : * since it is an RR source added host route. So what we need to
776 : * check is whether the route has other sources. If it does then
777 : * some other source has added it as a host route. If it doesn't
778 : * then it was added only here and inherits forwarding from a cover.
779 : * the cover is not a host route.
780 : * The RR source is the lowest priority source, so we check if it
781 : * is the best. if it is there are no other sources.
782 : */
783 1021 : if (fib_entry_get_best_source(path->fp_via_fib) >= FIB_SOURCE_RR)
784 : {
785 71 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
786 71 : dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto));
787 :
788 : /*
789 : * PIC edge trigger. let the load-balance maps know
790 : */
791 71 : load_balance_map_path_state_change(fib_path_get_index(path));
792 : }
793 : }
794 4000 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED)
795 : {
796 : /*
797 : * RR source entries inherit the flags from the cover, so
798 : * we can check the via directly
799 : */
800 1354 : if (!(FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(path->fp_via_fib)))
801 : {
802 6 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
803 6 : dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto));
804 :
805 : /*
806 : * PIC edge trigger. let the load-balance maps know
807 : */
808 6 : load_balance_map_path_state_change(fib_path_get_index(path));
809 : }
810 : }
811 : /*
812 : * check for over-riding factors on the FIB entry itself
813 : */
814 5037 : if (!fib_entry_is_resolved(path->fp_via_fib))
815 : {
816 3 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
817 3 : dpo_copy(&via_dpo, drop_dpo_get(path->fp_nh_proto));
818 :
819 : /*
820 : * PIC edge trigger. let the load-balance maps know
821 : */
822 3 : load_balance_map_path_state_change(fib_path_get_index(path));
823 : }
824 :
825 : /*
826 : * If this path is contributing a drop, then it's not resolved
827 : */
828 5037 : if (dpo_is_drop(&via_dpo) || load_balance_is_drop(&via_dpo))
829 : {
830 357 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
831 : }
832 :
833 : /*
834 : * update the path's contributed DPO
835 : */
836 5037 : dpo_copy(dpo, &via_dpo);
837 :
838 5037 : FIB_PATH_DBG(path, "recursive update:");
839 :
840 5037 : dpo_reset(&via_dpo);
841 5037 : }
842 :
843 : /*
844 : * re-evaulate the forwarding state for a via fmask path
845 : */
846 : static void
847 2669 : fib_path_bier_fmask_update (fib_path_t *path,
848 : dpo_id_t *dpo)
849 : {
850 2669 : bier_fmask_contribute_forwarding(path->bier_fmask.fp_bier_fmask, dpo);
851 :
852 : /*
853 : * if we are stakcing on the drop, then the path is not resolved
854 : */
855 2669 : if (dpo_is_drop(dpo))
856 : {
857 8 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
858 : }
859 : else
860 : {
861 2661 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
862 : }
863 2669 : }
864 :
865 : /*
866 : * fib_path_is_permanent_drop
867 : *
868 : * Return !0 if the path is configured to permanently drop,
869 : * despite other attributes.
870 : */
871 : static int
872 635038 : fib_path_is_permanent_drop (fib_path_t *path)
873 : {
874 1227920 : return ((path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DROP) ||
875 592883 : (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP));
876 : }
877 :
878 : /*
879 : * fib_path_unresolve
880 : *
881 : * Remove our dependency on the resolution target
882 : */
883 : static void
884 93267 : fib_path_unresolve (fib_path_t *path)
885 : {
886 : /*
887 : * the forced drop path does not need unresolving
888 : */
889 93267 : if (fib_path_is_permanent_drop(path))
890 : {
891 8107 : return;
892 : }
893 :
894 85160 : switch (path->fp_type)
895 : {
896 4297 : case FIB_PATH_TYPE_RECURSIVE:
897 4297 : if (FIB_NODE_INDEX_INVALID != path->fp_via_fib)
898 : {
899 2118 : fib_entry_child_remove(path->fp_via_fib,
900 : path->fp_sibling);
901 2118 : fib_table_entry_special_remove(path->recursive.fp_tbl_id,
902 : fib_entry_get_prefix(path->fp_via_fib),
903 : FIB_SOURCE_RR);
904 2118 : fib_table_unlock(path->recursive.fp_tbl_id,
905 2118 : dpo_proto_to_fib(path->fp_nh_proto),
906 : FIB_SOURCE_RR);
907 2118 : path->fp_via_fib = FIB_NODE_INDEX_INVALID;
908 : }
909 4297 : break;
910 244 : case FIB_PATH_TYPE_BIER_FMASK:
911 244 : bier_fmask_child_remove(path->fp_via_bier_fmask,
912 : path->fp_sibling);
913 244 : break;
914 6 : case FIB_PATH_TYPE_BIER_IMP:
915 6 : bier_imp_unlock(path->fp_dpo.dpoi_index);
916 6 : break;
917 160 : case FIB_PATH_TYPE_BIER_TABLE:
918 160 : bier_table_ecmp_unlock(path->fp_via_bier_tbl);
919 160 : break;
920 55604 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
921 : case FIB_PATH_TYPE_ATTACHED:
922 55604 : if (dpo_is_adj(&path->fp_dpo))
923 40849 : adj_child_remove(path->fp_dpo.dpoi_index,
924 : path->fp_sibling);
925 55604 : break;
926 11 : case FIB_PATH_TYPE_UDP_ENCAP:
927 11 : udp_encap_unlock(path->fp_dpo.dpoi_index);
928 11 : break;
929 7643 : case FIB_PATH_TYPE_EXCLUSIVE:
930 7643 : dpo_reset(&path->exclusive.fp_ex_dpo);
931 7643 : break;
932 17195 : case FIB_PATH_TYPE_SPECIAL:
933 : case FIB_PATH_TYPE_RECEIVE:
934 : case FIB_PATH_TYPE_INTF_RX:
935 : case FIB_PATH_TYPE_DEAG:
936 : case FIB_PATH_TYPE_DVR:
937 : /*
938 : * these hold only the path's DPO, which is reset below.
939 : */
940 17195 : break;
941 : }
942 :
943 : /*
944 : * release the adj we were holding and pick up the
945 : * drop just in case.
946 : */
947 85160 : dpo_reset(&path->fp_dpo);
948 85160 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
949 :
950 85160 : return;
951 : }
952 :
953 : static fib_forward_chain_type_t
954 159016 : fib_path_to_chain_type (const fib_path_t *path)
955 : {
956 159016 : if (DPO_PROTO_MPLS == path->fp_nh_proto)
957 : {
958 632 : if (FIB_PATH_TYPE_RECURSIVE == path->fp_type &&
959 46 : MPLS_EOS == path->recursive.fp_nh.fp_eos)
960 : {
961 6 : return (FIB_FORW_CHAIN_TYPE_MPLS_EOS);
962 : }
963 : else
964 : {
965 626 : return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
966 : }
967 : }
968 : else
969 : {
970 158384 : return (fib_forw_chain_type_from_dpo_proto(path->fp_nh_proto));
971 : }
972 : }
973 :
974 : /*
975 : * fib_path_back_walk_notify
976 : *
977 : * A back walk has reach this path.
978 : */
979 : static fib_node_back_walk_rc_t
980 35998 : fib_path_back_walk_notify (fib_node_t *node,
981 : fib_node_back_walk_ctx_t *ctx)
982 : {
983 : fib_path_t *path;
984 :
985 35998 : path = fib_path_from_fib_node(node);
986 :
987 35998 : FIB_PATH_DBG(path, "bw:%U",
988 : format_fib_node_bw_reason, ctx->fnbw_reason);
989 :
990 35998 : switch (path->fp_type)
991 : {
992 657 : case FIB_PATH_TYPE_RECURSIVE:
993 657 : if (FIB_NODE_BW_REASON_FLAG_EVALUATE & ctx->fnbw_reason)
994 : {
995 : /*
996 : * modify the recursive adjacency to use the new forwarding
997 : * of the via-fib.
998 : * this update is visible to packets in flight in the DP.
999 : */
1000 657 : fib_path_recursive_adj_update(
1001 : path,
1002 657 : fib_path_to_chain_type(path),
1003 : &path->fp_dpo);
1004 : }
1005 657 : if ((FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason) ||
1006 657 : (FIB_NODE_BW_REASON_FLAG_ADJ_MTU & ctx->fnbw_reason) ||
1007 657 : (FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason))
1008 : {
1009 : /*
1010 : * ADJ updates (complete<->incomplete) do not need to propagate to
1011 : * recursive entries.
1012 : * The only reason its needed as far back as here, is that the adj
1013 : * and the incomplete adj are a different DPO type, so the LBs need
1014 : * to re-stack.
1015 : * If this walk was quashed in the fib_entry, then any non-fib_path
1016 : * children (like tunnels that collapse out the LB when they stack)
1017 : * would not see the update.
1018 : */
1019 0 : return (FIB_NODE_BACK_WALK_CONTINUE);
1020 : }
1021 657 : break;
1022 77 : case FIB_PATH_TYPE_BIER_FMASK:
1023 77 : if (FIB_NODE_BW_REASON_FLAG_EVALUATE & ctx->fnbw_reason)
1024 : {
1025 : /*
1026 : * update to use the BIER fmask's new forwading
1027 : */
1028 77 : fib_path_bier_fmask_update(path, &path->fp_dpo);
1029 : }
1030 77 : if ((FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason) ||
1031 77 : (FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason))
1032 : {
1033 : /*
1034 : * ADJ updates (complete<->incomplete) do not need to propagate to
1035 : * recursive entries.
1036 : * The only reason its needed as far back as here, is that the adj
1037 : * and the incomplete adj are a different DPO type, so the LBs need
1038 : * to re-stack.
1039 : * If this walk was quashed in the fib_entry, then any non-fib_path
1040 : * children (like tunnels that collapse out the LB when they stack)
1041 : * would not see the update.
1042 : */
1043 0 : return (FIB_NODE_BACK_WALK_CONTINUE);
1044 : }
1045 77 : break;
1046 13310 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1047 : /*
1048 : FIXME comment
1049 : * ADJ_UPDATE backwalk pass silently through here and up to
1050 : * the path-list when the multipath adj collapse occurs.
1051 : * The reason we do this is that the assumtption is that VPP
1052 : * runs in an environment where the Control-Plane is remote
1053 : * and hence reacts slowly to link up down. In order to remove
1054 : * this down link from the ECMP set quickly, we back-walk.
1055 : * VPP also has dedicated CPUs, so we are not stealing resources
1056 : * from the CP to do so.
1057 : */
1058 13310 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason)
1059 : {
1060 959 : if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED)
1061 : {
1062 : /*
1063 : * alreday resolved. no need to walk back again
1064 : */
1065 486 : return (FIB_NODE_BACK_WALK_CONTINUE);
1066 : }
1067 473 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1068 : }
1069 12824 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason)
1070 : {
1071 577 : if (!(path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED))
1072 : {
1073 : /*
1074 : * alreday unresolved. no need to walk back again
1075 : */
1076 228 : return (FIB_NODE_BACK_WALK_CONTINUE);
1077 : }
1078 349 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1079 : }
1080 12596 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
1081 : {
1082 : /*
1083 : * The interface this path resolves through has been deleted.
1084 : * This will leave the path in a permanent drop state. The route
1085 : * needs to be removed and readded (and hence the path-list deleted)
1086 : * before it can forward again.
1087 : */
1088 14 : fib_path_unresolve(path);
1089 14 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_DROP;
1090 : }
1091 12596 : if (FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason)
1092 : {
1093 : /*
1094 : * restack the DPO to pick up the correct DPO sub-type
1095 : */
1096 5970 : dpo_id_t tmp = DPO_INVALID;
1097 : uword if_is_up;
1098 :
1099 5970 : if_is_up = vnet_sw_interface_is_up(
1100 : vnet_get_main(),
1101 : path->attached_next_hop.fp_interface);
1102 :
1103 5970 : dpo_copy (&tmp, &path->fp_dpo);
1104 5970 : path = fib_path_attached_next_hop_get_adj(
1105 : path,
1106 5970 : dpo_proto_to_link(path->fp_nh_proto),
1107 : &tmp);
1108 5970 : dpo_copy(&path->fp_dpo, &tmp);
1109 5970 : dpo_reset(&tmp);
1110 :
1111 5970 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1112 5970 : if (if_is_up && adj_is_up(path->fp_dpo.dpoi_index))
1113 : {
1114 2901 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1115 : }
1116 :
1117 5970 : if (!if_is_up)
1118 : {
1119 : /*
1120 : * If the interface is not up there is no reason to walk
1121 : * back to children. if we did they would only evalute
1122 : * that this path is unresolved and hence it would
1123 : * not contribute the adjacency - so it would be wasted
1124 : * CPU time.
1125 : */
1126 2964 : return (FIB_NODE_BACK_WALK_CONTINUE);
1127 : }
1128 : }
1129 9632 : if (FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason)
1130 : {
1131 5739 : if (!(path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED))
1132 : {
1133 : /*
1134 : * alreday unresolved. no need to walk back again
1135 : */
1136 155 : return (FIB_NODE_BACK_WALK_CONTINUE);
1137 : }
1138 : /*
1139 : * the adj has gone down. the path is no longer resolved.
1140 : */
1141 5584 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1142 : }
1143 9477 : break;
1144 21954 : case FIB_PATH_TYPE_ATTACHED:
1145 : case FIB_PATH_TYPE_DVR:
1146 : /*
1147 : * FIXME; this could schedule a lower priority walk, since attached
1148 : * routes are not usually in ECMP configurations so the backwalk to
1149 : * the FIB entry does not need to be high priority
1150 : */
1151 21954 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason)
1152 : {
1153 1788 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1154 : }
1155 21954 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason)
1156 : {
1157 19882 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1158 : }
1159 21954 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
1160 : {
1161 10 : fib_path_unresolve(path);
1162 10 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_DROP;
1163 : }
1164 21954 : if (FIB_NODE_BW_REASON_FLAG_INTERFACE_BIND & ctx->fnbw_reason)
1165 : {
1166 : /* bind walks should appear here and pass silently up to
1167 : * to the fib_entry */
1168 : }
1169 21954 : break;
1170 0 : case FIB_PATH_TYPE_UDP_ENCAP:
1171 : {
1172 0 : dpo_id_t via_dpo = DPO_INVALID;
1173 :
1174 : /*
1175 : * hope for the best - clear if restrictions apply.
1176 : */
1177 0 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1178 :
1179 0 : udp_encap_contribute_forwarding(path->udp_encap.fp_udp_encap_id,
1180 0 : path->fp_nh_proto,
1181 : &via_dpo);
1182 : /*
1183 : * If this path is contributing a drop, then it's not resolved
1184 : */
1185 0 : if (dpo_is_drop(&via_dpo) || load_balance_is_drop(&via_dpo))
1186 : {
1187 0 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1188 : }
1189 :
1190 : /*
1191 : * update the path's contributed DPO
1192 : */
1193 0 : dpo_copy(&path->fp_dpo, &via_dpo);
1194 0 : dpo_reset(&via_dpo);
1195 0 : break;
1196 : }
1197 0 : case FIB_PATH_TYPE_INTF_RX:
1198 0 : ASSERT(0);
1199 : case FIB_PATH_TYPE_DEAG:
1200 : /*
1201 : * FIXME When VRF delete is allowed this will need a poke.
1202 : */
1203 : case FIB_PATH_TYPE_SPECIAL:
1204 : case FIB_PATH_TYPE_RECEIVE:
1205 : case FIB_PATH_TYPE_EXCLUSIVE:
1206 : case FIB_PATH_TYPE_BIER_TABLE:
1207 : case FIB_PATH_TYPE_BIER_IMP:
1208 : /*
1209 : * these path types have no parents. so to be
1210 : * walked from one is unexpected.
1211 : */
1212 0 : ASSERT(0);
1213 0 : break;
1214 : }
1215 :
1216 : /*
1217 : * propagate the backwalk further to the path-list
1218 : */
1219 32165 : fib_path_list_back_walk(path->fp_pl_index, ctx);
1220 :
1221 32165 : return (FIB_NODE_BACK_WALK_CONTINUE);
1222 : }
1223 :
1224 : static void
1225 1 : fib_path_memory_show (void)
1226 : {
1227 1 : fib_show_memory_usage("Path",
1228 1 : pool_elts(fib_path_pool),
1229 1 : pool_len(fib_path_pool),
1230 : sizeof(fib_path_t));
1231 1 : }
1232 :
1233 : /*
1234 : * The FIB path's graph node virtual function table
1235 : */
1236 : static const fib_node_vft_t fib_path_vft = {
1237 : .fnv_get = fib_path_get_node,
1238 : .fnv_last_lock = fib_path_last_lock_gone,
1239 : .fnv_back_walk = fib_path_back_walk_notify,
1240 : .fnv_mem_show = fib_path_memory_show,
1241 : };
1242 :
1243 : static fib_path_cfg_flags_t
1244 73857 : fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
1245 : {
1246 73857 : fib_path_cfg_flags_t cfg_flags = FIB_PATH_CFG_FLAG_NONE;
1247 :
1248 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_POP_PW_CW)
1249 1 : cfg_flags |= FIB_PATH_CFG_FLAG_POP_PW_CW;
1250 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
1251 651 : cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_HOST;
1252 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
1253 268 : cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED;
1254 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_LOCAL)
1255 14020 : cfg_flags |= FIB_PATH_CFG_FLAG_LOCAL;
1256 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
1257 12847 : cfg_flags |= FIB_PATH_CFG_FLAG_ATTACHED;
1258 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_INTF_RX)
1259 7 : cfg_flags |= FIB_PATH_CFG_FLAG_INTF_RX;
1260 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_RPF_ID)
1261 15 : cfg_flags |= FIB_PATH_CFG_FLAG_RPF_ID;
1262 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_EXCLUSIVE)
1263 406 : cfg_flags |= FIB_PATH_CFG_FLAG_EXCLUSIVE;
1264 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_DROP)
1265 15 : cfg_flags |= FIB_PATH_CFG_FLAG_DROP;
1266 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_SOURCE_LOOKUP)
1267 3 : cfg_flags |= FIB_PATH_CFG_FLAG_DEAG_SRC;
1268 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_UNREACH)
1269 2 : cfg_flags |= FIB_PATH_CFG_FLAG_ICMP_UNREACH;
1270 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_ICMP_PROHIBIT)
1271 2 : cfg_flags |= FIB_PATH_CFG_FLAG_ICMP_PROHIBIT;
1272 73857 : if (rpath->frp_flags & FIB_ROUTE_PATH_GLEAN)
1273 19157 : cfg_flags |= FIB_PATH_CFG_FLAG_GLEAN;
1274 :
1275 73857 : return (cfg_flags);
1276 : }
1277 :
1278 : /*
1279 : * fib_path_create
1280 : *
1281 : * Create and initialise a new path object.
1282 : * return the index of the path.
1283 : */
1284 : fib_node_index_t
1285 73857 : fib_path_create (fib_node_index_t pl_index,
1286 : const fib_route_path_t *rpath)
1287 : {
1288 : fib_path_t *path;
1289 :
1290 73857 : pool_get(fib_path_pool, path);
1291 73857 : clib_memset(path, 0, sizeof(*path));
1292 :
1293 73857 : fib_node_init(&path->fp_node,
1294 : FIB_NODE_TYPE_PATH);
1295 :
1296 73857 : dpo_reset(&path->fp_dpo);
1297 73857 : path->fp_pl_index = pl_index;
1298 73857 : path->fp_nh_proto = rpath->frp_proto;
1299 73857 : path->fp_via_fib = FIB_NODE_INDEX_INVALID;
1300 73857 : path->fp_weight = rpath->frp_weight;
1301 73857 : if (0 == path->fp_weight)
1302 : {
1303 : /*
1304 : * a weight of 0 is a meaningless value. We could either reject it, and thus force
1305 : * clients to always use 1, or we can accept it and fixup approrpiately.
1306 : */
1307 199 : path->fp_weight = 1;
1308 : }
1309 73857 : path->fp_preference = rpath->frp_preference;
1310 73857 : path->fp_cfg_flags = fib_path_route_flags_to_cfg_flags(rpath);
1311 :
1312 : /*
1313 : * deduce the path's tpye from the parementers and save what is needed.
1314 : */
1315 73857 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_LOCAL)
1316 : {
1317 14020 : path->fp_type = FIB_PATH_TYPE_RECEIVE;
1318 14020 : path->receive.fp_interface = rpath->frp_sw_if_index;
1319 14020 : path->receive.fp_addr = rpath->frp_addr;
1320 : }
1321 59837 : else if (rpath->frp_flags & FIB_ROUTE_PATH_UDP_ENCAP)
1322 : {
1323 11 : path->fp_type = FIB_PATH_TYPE_UDP_ENCAP;
1324 11 : path->udp_encap.fp_udp_encap_id = rpath->frp_udp_encap_id;
1325 : }
1326 59826 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_INTF_RX)
1327 : {
1328 7 : path->fp_type = FIB_PATH_TYPE_INTF_RX;
1329 7 : path->intf_rx.fp_interface = rpath->frp_sw_if_index;
1330 : }
1331 59819 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID)
1332 : {
1333 15 : path->fp_type = FIB_PATH_TYPE_DEAG;
1334 15 : path->deag.fp_tbl_id = rpath->frp_fib_index;
1335 15 : path->deag.fp_rpf_id = rpath->frp_rpf_id;
1336 : }
1337 59804 : else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_FMASK)
1338 : {
1339 159 : path->fp_type = FIB_PATH_TYPE_BIER_FMASK;
1340 159 : path->bier_fmask.fp_bier_fmask = rpath->frp_bier_fmask;
1341 : }
1342 59645 : else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP)
1343 : {
1344 6 : path->fp_type = FIB_PATH_TYPE_BIER_IMP;
1345 6 : path->bier_imp.fp_bier_imp = rpath->frp_bier_imp;
1346 : }
1347 59639 : else if (rpath->frp_flags & FIB_ROUTE_PATH_BIER_TABLE)
1348 : {
1349 160 : path->fp_type = FIB_PATH_TYPE_BIER_TABLE;
1350 160 : path->bier_table.fp_bier_tbl = rpath->frp_bier_tbl;
1351 : }
1352 59479 : else if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
1353 : {
1354 62 : path->fp_type = FIB_PATH_TYPE_DEAG;
1355 62 : path->deag.fp_tbl_id = rpath->frp_fib_index;
1356 : }
1357 59417 : else if (rpath->frp_flags & FIB_ROUTE_PATH_DVR)
1358 : {
1359 8 : path->fp_type = FIB_PATH_TYPE_DVR;
1360 8 : path->dvr.fp_interface = rpath->frp_sw_if_index;
1361 : }
1362 59409 : else if (rpath->frp_flags & FIB_ROUTE_PATH_EXCLUSIVE)
1363 : {
1364 0 : path->fp_type = FIB_PATH_TYPE_EXCLUSIVE;
1365 0 : dpo_copy(&path->exclusive.fp_ex_dpo, &rpath->dpo);
1366 : }
1367 59409 : else if ((path->fp_cfg_flags & FIB_PATH_CFG_FLAG_ICMP_PROHIBIT) ||
1368 59407 : (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_ICMP_UNREACH))
1369 : {
1370 4 : path->fp_type = FIB_PATH_TYPE_SPECIAL;
1371 : }
1372 59405 : else if ((path->fp_cfg_flags & FIB_PATH_CFG_FLAG_CLASSIFY))
1373 : {
1374 0 : path->fp_type = FIB_PATH_TYPE_SPECIAL;
1375 0 : path->classify.fp_classify_table_id = rpath->frp_classify_table_id;
1376 : }
1377 59405 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_GLEAN)
1378 : {
1379 19152 : path->fp_type = FIB_PATH_TYPE_ATTACHED;
1380 19152 : path->attached.fp_interface = rpath->frp_sw_if_index;
1381 19152 : path->attached.fp_connected = rpath->frp_connected;
1382 : }
1383 40253 : else if (~0 != rpath->frp_sw_if_index)
1384 : {
1385 36356 : if (ip46_address_is_zero(&rpath->frp_addr))
1386 : {
1387 17376 : path->fp_type = FIB_PATH_TYPE_ATTACHED;
1388 17376 : path->attached.fp_interface = rpath->frp_sw_if_index;
1389 : }
1390 : else
1391 : {
1392 18980 : path->fp_type = FIB_PATH_TYPE_ATTACHED_NEXT_HOP;
1393 18980 : path->attached_next_hop.fp_interface = rpath->frp_sw_if_index;
1394 18980 : path->attached_next_hop.fp_nh = rpath->frp_addr;
1395 : }
1396 : }
1397 : else
1398 : {
1399 3897 : if (ip46_address_is_zero(&rpath->frp_addr))
1400 : {
1401 9 : if (~0 == rpath->frp_fib_index)
1402 : {
1403 0 : path->fp_type = FIB_PATH_TYPE_SPECIAL;
1404 : }
1405 : else
1406 : {
1407 9 : path->fp_type = FIB_PATH_TYPE_DEAG;
1408 9 : path->deag.fp_tbl_id = rpath->frp_fib_index;
1409 9 : path->deag.fp_rpf_id = ~0;
1410 : }
1411 : }
1412 : else
1413 : {
1414 3888 : path->fp_type = FIB_PATH_TYPE_RECURSIVE;
1415 3888 : if (DPO_PROTO_MPLS == path->fp_nh_proto)
1416 : {
1417 21 : path->recursive.fp_nh.fp_local_label = rpath->frp_local_label;
1418 21 : path->recursive.fp_nh.fp_eos = rpath->frp_eos;
1419 : }
1420 : else
1421 : {
1422 3867 : path->recursive.fp_nh.fp_ip = rpath->frp_addr;
1423 : }
1424 3888 : path->recursive.fp_tbl_id = rpath->frp_fib_index;
1425 : }
1426 : }
1427 :
1428 73857 : FIB_PATH_DBG(path, "create");
1429 :
1430 73857 : return (fib_path_get_index(path));
1431 : }
1432 :
1433 : /*
1434 : * fib_path_create_special
1435 : *
1436 : * Create and initialise a new path object.
1437 : * return the index of the path.
1438 : */
1439 : fib_node_index_t
1440 27717 : fib_path_create_special (fib_node_index_t pl_index,
1441 : dpo_proto_t nh_proto,
1442 : fib_path_cfg_flags_t flags,
1443 : const dpo_id_t *dpo)
1444 : {
1445 : fib_path_t *path;
1446 :
1447 27717 : pool_get(fib_path_pool, path);
1448 27717 : clib_memset(path, 0, sizeof(*path));
1449 :
1450 27717 : fib_node_init(&path->fp_node,
1451 : FIB_NODE_TYPE_PATH);
1452 27717 : dpo_reset(&path->fp_dpo);
1453 :
1454 27717 : path->fp_pl_index = pl_index;
1455 27717 : path->fp_weight = 1;
1456 27717 : path->fp_preference = 0;
1457 27717 : path->fp_nh_proto = nh_proto;
1458 27717 : path->fp_via_fib = FIB_NODE_INDEX_INVALID;
1459 27717 : path->fp_cfg_flags = flags;
1460 :
1461 27717 : if (FIB_PATH_CFG_FLAG_DROP & flags)
1462 : {
1463 12274 : path->fp_type = FIB_PATH_TYPE_SPECIAL;
1464 : }
1465 15443 : else if (FIB_PATH_CFG_FLAG_LOCAL & flags)
1466 : {
1467 7183 : path->fp_type = FIB_PATH_TYPE_RECEIVE;
1468 7183 : path->attached.fp_interface = FIB_NODE_INDEX_INVALID;
1469 : }
1470 : else
1471 : {
1472 8260 : path->fp_type = FIB_PATH_TYPE_EXCLUSIVE;
1473 8260 : ASSERT(NULL != dpo);
1474 8260 : dpo_copy(&path->exclusive.fp_ex_dpo, dpo);
1475 : }
1476 :
1477 27717 : return (fib_path_get_index(path));
1478 : }
1479 :
1480 : /*
1481 : * fib_path_copy
1482 : *
1483 : * Copy a path. return index of new path.
1484 : */
1485 : fib_node_index_t
1486 6346 : fib_path_copy (fib_node_index_t path_index,
1487 : fib_node_index_t path_list_index)
1488 : {
1489 : fib_path_t *path, *orig_path;
1490 :
1491 6346 : pool_get(fib_path_pool, path);
1492 :
1493 6346 : orig_path = fib_path_get(path_index);
1494 6346 : ASSERT(NULL != orig_path);
1495 :
1496 6346 : clib_memcpy(path, orig_path, sizeof(*path));
1497 :
1498 6346 : FIB_PATH_DBG(path, "create-copy:%d", path_index);
1499 :
1500 : /*
1501 : * reset the dynamic section
1502 : */
1503 6346 : fib_node_init(&path->fp_node, FIB_NODE_TYPE_PATH);
1504 6346 : path->fp_oper_flags = FIB_PATH_OPER_FLAG_NONE;
1505 6346 : path->fp_pl_index = path_list_index;
1506 6346 : path->fp_via_fib = FIB_NODE_INDEX_INVALID;
1507 6346 : clib_memset(&path->fp_dpo, 0, sizeof(path->fp_dpo));
1508 6346 : dpo_reset(&path->fp_dpo);
1509 :
1510 6346 : if (path->fp_type == FIB_PATH_TYPE_EXCLUSIVE)
1511 : {
1512 0 : clib_memset(&path->exclusive.fp_ex_dpo, 0, sizeof(dpo_id_t));
1513 0 : dpo_copy(&path->exclusive.fp_ex_dpo, &orig_path->exclusive.fp_ex_dpo);
1514 : }
1515 :
1516 6346 : return (fib_path_get_index(path));
1517 : }
1518 :
1519 : /*
1520 : * fib_path_destroy
1521 : *
1522 : * destroy a path that is no longer required
1523 : */
1524 : void
1525 93243 : fib_path_destroy (fib_node_index_t path_index)
1526 : {
1527 : fib_path_t *path;
1528 :
1529 93243 : path = fib_path_get(path_index);
1530 :
1531 93243 : ASSERT(NULL != path);
1532 93243 : FIB_PATH_DBG(path, "destroy");
1533 :
1534 93243 : fib_path_unresolve(path);
1535 :
1536 93243 : fib_node_deinit(&path->fp_node);
1537 93243 : pool_put(fib_path_pool, path);
1538 93243 : }
1539 :
1540 : /*
1541 : * fib_path_destroy
1542 : *
1543 : * destroy a path that is no longer required
1544 : */
1545 : uword
1546 190363 : fib_path_hash (fib_node_index_t path_index)
1547 : {
1548 : fib_path_t *path;
1549 :
1550 190363 : path = fib_path_get(path_index);
1551 :
1552 190363 : return (hash_memory(STRUCT_MARK_PTR(path, path_hash_start),
1553 : (STRUCT_OFFSET_OF(fib_path_t, path_hash_end) -
1554 : STRUCT_OFFSET_OF(fib_path_t, path_hash_start)),
1555 : 0));
1556 : }
1557 :
1558 : /*
1559 : * fib_path_cmp_i
1560 : *
1561 : * Compare two paths for equivalence.
1562 : */
1563 : static int
1564 86542 : fib_path_cmp_i (const fib_path_t *path1,
1565 : const fib_path_t *path2)
1566 : {
1567 : int res;
1568 :
1569 86542 : res = 1;
1570 :
1571 : /*
1572 : * paths of different types and protocol are not equal.
1573 : * different weights and/or preference only are the same path.
1574 : */
1575 86542 : if (path1->fp_type != path2->fp_type)
1576 : {
1577 9 : res = (path1->fp_type - path2->fp_type);
1578 : }
1579 86533 : else if (path1->fp_nh_proto != path2->fp_nh_proto)
1580 : {
1581 0 : res = (path1->fp_nh_proto - path2->fp_nh_proto);
1582 : }
1583 : else
1584 : {
1585 : /*
1586 : * both paths are of the same type.
1587 : * consider each type and its attributes in turn.
1588 : */
1589 86533 : switch (path1->fp_type)
1590 : {
1591 7160 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1592 7160 : res = ip46_address_cmp(&path1->attached_next_hop.fp_nh,
1593 : &path2->attached_next_hop.fp_nh);
1594 7160 : if (0 == res) {
1595 5925 : res = (path1->attached_next_hop.fp_interface -
1596 5925 : path2->attached_next_hop.fp_interface);
1597 : }
1598 7160 : break;
1599 77937 : case FIB_PATH_TYPE_ATTACHED:
1600 77937 : res = (path1->attached.fp_interface -
1601 77937 : path2->attached.fp_interface);
1602 77937 : break;
1603 1017 : case FIB_PATH_TYPE_RECURSIVE:
1604 1017 : res = ip46_address_cmp(&path1->recursive.fp_nh.fp_ip,
1605 : &path2->recursive.fp_nh.fp_ip);
1606 :
1607 1017 : if (0 == res)
1608 : {
1609 28 : res = (path1->recursive.fp_tbl_id - path2->recursive.fp_tbl_id);
1610 : }
1611 1017 : break;
1612 90 : case FIB_PATH_TYPE_BIER_FMASK:
1613 90 : res = (path1->bier_fmask.fp_bier_fmask -
1614 90 : path2->bier_fmask.fp_bier_fmask);
1615 90 : break;
1616 0 : case FIB_PATH_TYPE_BIER_IMP:
1617 0 : res = (path1->bier_imp.fp_bier_imp -
1618 0 : path2->bier_imp.fp_bier_imp);
1619 0 : break;
1620 320 : case FIB_PATH_TYPE_BIER_TABLE:
1621 320 : res = bier_table_id_cmp(&path1->bier_table.fp_bier_tbl,
1622 : &path2->bier_table.fp_bier_tbl);
1623 320 : break;
1624 8 : case FIB_PATH_TYPE_DEAG:
1625 8 : res = (path1->deag.fp_tbl_id - path2->deag.fp_tbl_id);
1626 8 : if (0 == res)
1627 : {
1628 8 : res = (path1->deag.fp_rpf_id - path2->deag.fp_rpf_id);
1629 : }
1630 8 : break;
1631 0 : case FIB_PATH_TYPE_INTF_RX:
1632 0 : res = (path1->intf_rx.fp_interface - path2->intf_rx.fp_interface);
1633 0 : break;
1634 0 : case FIB_PATH_TYPE_UDP_ENCAP:
1635 0 : res = (path1->udp_encap.fp_udp_encap_id - path2->udp_encap.fp_udp_encap_id);
1636 0 : break;
1637 1 : case FIB_PATH_TYPE_DVR:
1638 1 : res = (path1->dvr.fp_interface - path2->dvr.fp_interface);
1639 1 : break;
1640 0 : case FIB_PATH_TYPE_EXCLUSIVE:
1641 0 : res = dpo_cmp(&path1->exclusive.fp_ex_dpo, &path2->exclusive.fp_ex_dpo);
1642 0 : break;
1643 0 : case FIB_PATH_TYPE_SPECIAL:
1644 : case FIB_PATH_TYPE_RECEIVE:
1645 0 : res = 0;
1646 0 : break;
1647 : }
1648 86542 : }
1649 86542 : return (res);
1650 : }
1651 :
1652 : /*
1653 : * fib_path_cmp_for_sort
1654 : *
1655 : * Compare two paths for equivalence. Used during path sorting.
1656 : * As usual 0 means equal.
1657 : */
1658 : int
1659 81258 : fib_path_cmp_for_sort (void * v1,
1660 : void * v2)
1661 : {
1662 81258 : fib_node_index_t *pi1 = v1, *pi2 = v2;
1663 : fib_path_t *path1, *path2;
1664 :
1665 81258 : path1 = fib_path_get(*pi1);
1666 81258 : path2 = fib_path_get(*pi2);
1667 :
1668 : /*
1669 : * when sorting paths we want the highest preference paths
1670 : * first, so that the choices set built is in prefernce order
1671 : */
1672 81258 : if (path1->fp_preference != path2->fp_preference)
1673 : {
1674 1045 : return (path1->fp_preference - path2->fp_preference);
1675 : }
1676 :
1677 80213 : return (fib_path_cmp_i(path1, path2));
1678 : }
1679 :
1680 : /*
1681 : * fib_path_cmp
1682 : *
1683 : * Compare two paths for equivalence.
1684 : */
1685 : int
1686 6329 : fib_path_cmp (fib_node_index_t pi1,
1687 : fib_node_index_t pi2)
1688 : {
1689 : fib_path_t *path1, *path2;
1690 :
1691 6329 : path1 = fib_path_get(pi1);
1692 6329 : path2 = fib_path_get(pi2);
1693 :
1694 6329 : return (fib_path_cmp_i(path1, path2));
1695 : }
1696 :
1697 : int
1698 128483 : fib_path_cmp_w_route_path (fib_node_index_t path_index,
1699 : const fib_route_path_t *rpath)
1700 : {
1701 : fib_path_t *path;
1702 : int res;
1703 :
1704 128483 : path = fib_path_get(path_index);
1705 :
1706 128483 : res = 1;
1707 :
1708 128483 : if (path->fp_weight != rpath->frp_weight)
1709 : {
1710 20 : res = (path->fp_weight - rpath->frp_weight);
1711 : }
1712 : else
1713 : {
1714 : /*
1715 : * both paths are of the same type.
1716 : * consider each type and its attributes in turn.
1717 : */
1718 128463 : switch (path->fp_type)
1719 : {
1720 9876 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1721 9876 : res = ip46_address_cmp(&path->attached_next_hop.fp_nh,
1722 : &rpath->frp_addr);
1723 9876 : if (0 == res)
1724 : {
1725 9861 : res = (path->attached_next_hop.fp_interface -
1726 9861 : rpath->frp_sw_if_index);
1727 : }
1728 9876 : break;
1729 63712 : case FIB_PATH_TYPE_ATTACHED:
1730 63712 : res = (path->attached.fp_interface - rpath->frp_sw_if_index);
1731 63712 : break;
1732 222 : case FIB_PATH_TYPE_RECURSIVE:
1733 222 : if (DPO_PROTO_MPLS == path->fp_nh_proto)
1734 : {
1735 13 : res = path->recursive.fp_nh.fp_local_label - rpath->frp_local_label;
1736 :
1737 13 : if (res == 0)
1738 : {
1739 11 : res = path->recursive.fp_nh.fp_eos - rpath->frp_eos;
1740 : }
1741 : }
1742 : else
1743 : {
1744 209 : res = ip46_address_cmp(&path->recursive.fp_nh.fp_ip,
1745 : &rpath->frp_addr);
1746 : }
1747 :
1748 222 : if (0 == res)
1749 : {
1750 152 : res = (path->recursive.fp_tbl_id - rpath->frp_fib_index);
1751 : }
1752 222 : break;
1753 0 : case FIB_PATH_TYPE_BIER_FMASK:
1754 0 : res = (path->bier_fmask.fp_bier_fmask - rpath->frp_bier_fmask);
1755 0 : break;
1756 7 : case FIB_PATH_TYPE_BIER_IMP:
1757 7 : res = (path->bier_imp.fp_bier_imp - rpath->frp_bier_imp);
1758 7 : break;
1759 0 : case FIB_PATH_TYPE_BIER_TABLE:
1760 0 : res = bier_table_id_cmp(&path->bier_table.fp_bier_tbl,
1761 : &rpath->frp_bier_tbl);
1762 0 : break;
1763 0 : case FIB_PATH_TYPE_INTF_RX:
1764 0 : res = (path->intf_rx.fp_interface - rpath->frp_sw_if_index);
1765 0 : break;
1766 1 : case FIB_PATH_TYPE_UDP_ENCAP:
1767 1 : res = (path->udp_encap.fp_udp_encap_id - rpath->frp_udp_encap_id);
1768 1 : break;
1769 1 : case FIB_PATH_TYPE_DEAG:
1770 1 : res = (path->deag.fp_tbl_id - rpath->frp_fib_index);
1771 1 : if (0 == res)
1772 : {
1773 1 : res = (path->deag.fp_rpf_id - rpath->frp_rpf_id);
1774 : }
1775 1 : break;
1776 0 : case FIB_PATH_TYPE_DVR:
1777 0 : res = (path->dvr.fp_interface - rpath->frp_sw_if_index);
1778 0 : break;
1779 0 : case FIB_PATH_TYPE_EXCLUSIVE:
1780 0 : res = dpo_cmp(&path->exclusive.fp_ex_dpo, &rpath->dpo);
1781 0 : break;
1782 54644 : case FIB_PATH_TYPE_RECEIVE:
1783 54644 : if (rpath->frp_flags & FIB_ROUTE_PATH_LOCAL)
1784 : {
1785 963 : res = 0;
1786 : }
1787 : else
1788 : {
1789 53681 : res = 1;
1790 : }
1791 54644 : break;
1792 0 : case FIB_PATH_TYPE_SPECIAL:
1793 0 : res = 0;
1794 0 : break;
1795 : }
1796 128483 : }
1797 128483 : return (res);
1798 : }
1799 :
1800 : /*
1801 : * fib_path_recursive_loop_detect
1802 : *
1803 : * A forward walk of the FIB object graph to detect for a cycle/loop. This
1804 : * walk is initiated when an entry is linking to a new path list or from an old.
1805 : * The entry vector passed contains all the FIB entrys that are children of this
1806 : * path (it is all the entries encountered on the walk so far). If this vector
1807 : * contains the entry this path resolve via, then a loop is about to form.
1808 : * The loop must be allowed to form, since we need the dependencies in place
1809 : * so that we can track when the loop breaks.
1810 : * However, we MUST not produce a loop in the forwarding graph (else packets
1811 : * would loop around the switch path until the loop breaks), so we mark recursive
1812 : * paths as looped so that they do not contribute forwarding information.
1813 : * By marking the path as looped, an etry such as;
1814 : * X/Y
1815 : * via a.a.a.a (looped)
1816 : * via b.b.b.b (not looped)
1817 : * can still forward using the info provided by b.b.b.b only
1818 : */
1819 : int
1820 117614 : fib_path_recursive_loop_detect (fib_node_index_t path_index,
1821 : fib_node_index_t **entry_indicies)
1822 : {
1823 : fib_path_t *path;
1824 :
1825 117614 : path = fib_path_get(path_index);
1826 :
1827 : /*
1828 : * the forced drop path is never looped, cos it is never resolved.
1829 : */
1830 117614 : if (fib_path_is_permanent_drop(path))
1831 : {
1832 21800 : return (0);
1833 : }
1834 :
1835 95814 : switch (path->fp_type)
1836 : {
1837 7460 : case FIB_PATH_TYPE_RECURSIVE:
1838 : {
1839 : fib_node_index_t *entry_index, *entries;
1840 7460 : int looped = 0;
1841 7460 : entries = *entry_indicies;
1842 :
1843 7503 : vec_foreach(entry_index, entries) {
1844 51 : if (*entry_index == path->fp_via_fib)
1845 : {
1846 : /*
1847 : * the entry that is about to link to this path-list (or
1848 : * one of this path-list's children) is the same entry that
1849 : * this recursive path resolves through. this is a cycle.
1850 : * abort the walk.
1851 : */
1852 8 : looped = 1;
1853 8 : break;
1854 : }
1855 : }
1856 :
1857 7460 : if (looped)
1858 : {
1859 8 : FIB_PATH_DBG(path, "recursive loop formed");
1860 8 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1861 :
1862 8 : dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto));
1863 : }
1864 : else
1865 : {
1866 : /*
1867 : * no loop here yet. keep forward walking the graph.
1868 : */
1869 7452 : if (fib_entry_recursive_loop_detect(path->fp_via_fib, entry_indicies))
1870 : {
1871 12 : FIB_PATH_DBG(path, "recursive loop formed");
1872 12 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1873 : }
1874 : else
1875 : {
1876 7440 : FIB_PATH_DBG(path, "recursive loop cleared");
1877 7440 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1878 : }
1879 : }
1880 7460 : break;
1881 : }
1882 67813 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1883 : case FIB_PATH_TYPE_ATTACHED:
1884 135366 : if (dpo_is_adj(&path->fp_dpo) &&
1885 67553 : adj_recursive_loop_detect(path->fp_dpo.dpoi_index,
1886 : entry_indicies))
1887 : {
1888 1 : FIB_PATH_DBG(path, "recursive loop formed");
1889 1 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1890 : }
1891 : else
1892 : {
1893 67812 : FIB_PATH_DBG(path, "recursive loop cleared");
1894 67812 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1895 : }
1896 67813 : break;
1897 20541 : case FIB_PATH_TYPE_SPECIAL:
1898 : case FIB_PATH_TYPE_DEAG:
1899 : case FIB_PATH_TYPE_DVR:
1900 : case FIB_PATH_TYPE_RECEIVE:
1901 : case FIB_PATH_TYPE_INTF_RX:
1902 : case FIB_PATH_TYPE_UDP_ENCAP:
1903 : case FIB_PATH_TYPE_EXCLUSIVE:
1904 : case FIB_PATH_TYPE_BIER_FMASK:
1905 : case FIB_PATH_TYPE_BIER_TABLE:
1906 : case FIB_PATH_TYPE_BIER_IMP:
1907 : /*
1908 : * these path types cannot be part of a loop, since they are the leaves
1909 : * of the graph.
1910 : */
1911 20541 : break;
1912 : }
1913 :
1914 95814 : return (fib_path_is_looped(path_index));
1915 : }
1916 :
1917 : int
1918 91166 : fib_path_resolve (fib_node_index_t path_index)
1919 : {
1920 : fib_path_t *path;
1921 :
1922 91166 : path = fib_path_get(path_index);
1923 :
1924 : /*
1925 : * hope for the best.
1926 : */
1927 91166 : path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1928 :
1929 : /*
1930 : * the forced drop path resolves via the drop adj
1931 : */
1932 91166 : if (fib_path_is_permanent_drop(path))
1933 : {
1934 12284 : dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto));
1935 12284 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1936 12284 : return (fib_path_is_resolved(path_index));
1937 : }
1938 :
1939 78882 : switch (path->fp_type)
1940 : {
1941 10417 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1942 10417 : fib_path_attached_next_hop_set(path);
1943 10417 : break;
1944 36511 : case FIB_PATH_TYPE_ATTACHED:
1945 : {
1946 36511 : dpo_id_t tmp = DPO_INVALID;
1947 :
1948 : /*
1949 : * path->attached.fp_interface
1950 : */
1951 36511 : if (!vnet_sw_interface_is_up(vnet_get_main(),
1952 : path->attached.fp_interface))
1953 : {
1954 727 : path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1955 : }
1956 36511 : fib_path_attached_get_adj(path,
1957 36511 : dpo_proto_to_link(path->fp_nh_proto),
1958 : &tmp);
1959 :
1960 : /*
1961 : * re-fetch after possible mem realloc
1962 : */
1963 36511 : path = fib_path_get(path_index);
1964 36511 : dpo_copy(&path->fp_dpo, &tmp);
1965 :
1966 : /*
1967 : * become a child of the adjacency so we receive updates
1968 : * when the interface state changes
1969 : */
1970 36511 : if (dpo_is_adj(&path->fp_dpo))
1971 : {
1972 36147 : path->fp_sibling = adj_child_add(path->fp_dpo.dpoi_index,
1973 : FIB_NODE_TYPE_PATH,
1974 : fib_path_get_index(path));
1975 : }
1976 36511 : dpo_reset(&tmp);
1977 36511 : break;
1978 : }
1979 2133 : case FIB_PATH_TYPE_RECURSIVE:
1980 : {
1981 : /*
1982 : * Create a RR source entry in the table for the address
1983 : * that this path recurses through.
1984 : * This resolve action is recursive, hence we may create
1985 : * more paths in the process. more creates mean maybe realloc
1986 : * of this path.
1987 : */
1988 : fib_node_index_t fei;
1989 : fib_prefix_t pfx;
1990 :
1991 2133 : ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_fib);
1992 :
1993 2133 : if (DPO_PROTO_MPLS == path->fp_nh_proto)
1994 : {
1995 10 : fib_prefix_from_mpls_label(path->recursive.fp_nh.fp_local_label,
1996 : path->recursive.fp_nh.fp_eos,
1997 : &pfx);
1998 : }
1999 : else
2000 : {
2001 2123 : ASSERT(!ip46_address_is_zero(&path->recursive.fp_nh.fp_ip));
2002 :
2003 2123 : fib_protocol_t fp = (ip46_address_is_ip4(&path->recursive.fp_nh.fp_ip) ?
2004 2123 : FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
2005 2123 : fib_prefix_from_ip46_addr(fp, &path->recursive.fp_nh.fp_ip, &pfx);
2006 : }
2007 :
2008 2133 : fib_table_lock(path->recursive.fp_tbl_id,
2009 2133 : dpo_proto_to_fib(path->fp_nh_proto),
2010 : FIB_SOURCE_RR);
2011 2133 : fei = fib_table_entry_special_add(path->recursive.fp_tbl_id,
2012 : &pfx,
2013 : FIB_SOURCE_RR,
2014 : FIB_ENTRY_FLAG_NONE);
2015 :
2016 2133 : path = fib_path_get(path_index);
2017 2133 : path->fp_via_fib = fei;
2018 :
2019 : /*
2020 : * become a dependent child of the entry so the path is
2021 : * informed when the forwarding for the entry changes.
2022 : */
2023 2133 : path->fp_sibling = fib_entry_child_add(path->fp_via_fib,
2024 : FIB_NODE_TYPE_PATH,
2025 : fib_path_get_index(path));
2026 :
2027 : /*
2028 : * create and configure the IP DPO
2029 : */
2030 2133 : fib_path_recursive_adj_update(
2031 : path,
2032 2133 : fib_path_to_chain_type(path),
2033 : &path->fp_dpo);
2034 :
2035 2133 : break;
2036 : }
2037 87 : case FIB_PATH_TYPE_BIER_FMASK:
2038 : {
2039 : /*
2040 : * become a dependent child of the entry so the path is
2041 : * informed when the forwarding for the entry changes.
2042 : */
2043 87 : path->fp_sibling = bier_fmask_child_add(path->bier_fmask.fp_bier_fmask,
2044 : FIB_NODE_TYPE_PATH,
2045 : fib_path_get_index(path));
2046 :
2047 87 : path->fp_via_bier_fmask = path->bier_fmask.fp_bier_fmask;
2048 87 : fib_path_bier_fmask_update(path, &path->fp_dpo);
2049 :
2050 87 : break;
2051 : }
2052 6 : case FIB_PATH_TYPE_BIER_IMP:
2053 6 : bier_imp_lock(path->bier_imp.fp_bier_imp);
2054 6 : bier_imp_contribute_forwarding(path->bier_imp.fp_bier_imp,
2055 : DPO_PROTO_IP4,
2056 : &path->fp_dpo);
2057 6 : break;
2058 160 : case FIB_PATH_TYPE_BIER_TABLE:
2059 : {
2060 : /*
2061 : * Find/create the BIER table to link to
2062 : */
2063 160 : ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_bier_tbl);
2064 :
2065 160 : path->fp_via_bier_tbl =
2066 160 : bier_table_ecmp_create_and_lock(&path->bier_table.fp_bier_tbl);
2067 :
2068 160 : bier_table_contribute_forwarding(path->fp_via_bier_tbl,
2069 : &path->fp_dpo);
2070 160 : break;
2071 : }
2072 4 : case FIB_PATH_TYPE_SPECIAL:
2073 4 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_ICMP_PROHIBIT)
2074 : {
2075 2 : ip_null_dpo_add_and_lock (path->fp_nh_proto,
2076 : IP_NULL_ACTION_SEND_ICMP_PROHIBIT,
2077 : &path->fp_dpo);
2078 : }
2079 2 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_ICMP_UNREACH)
2080 : {
2081 2 : ip_null_dpo_add_and_lock (path->fp_nh_proto,
2082 : IP_NULL_ACTION_SEND_ICMP_UNREACH,
2083 : &path->fp_dpo);
2084 : }
2085 0 : else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_CLASSIFY)
2086 : {
2087 0 : dpo_set (&path->fp_dpo, DPO_CLASSIFY,
2088 0 : path->fp_nh_proto,
2089 0 : classify_dpo_create (path->fp_nh_proto,
2090 : path->classify.fp_classify_table_id));
2091 : }
2092 : else
2093 : {
2094 : /*
2095 : * Resolve via the drop
2096 : */
2097 0 : dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto));
2098 : }
2099 4 : break;
2100 76 : case FIB_PATH_TYPE_DEAG:
2101 : {
2102 76 : if (DPO_PROTO_BIER == path->fp_nh_proto)
2103 : {
2104 4 : bier_disp_table_contribute_forwarding(path->deag.fp_tbl_id,
2105 : &path->fp_dpo);
2106 : }
2107 : else
2108 : {
2109 : /*
2110 : * Resolve via a lookup DPO.
2111 : * FIXME. control plane should add routes with a table ID
2112 : */
2113 : lookup_input_t input;
2114 : lookup_cast_t cast;
2115 :
2116 72 : cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ?
2117 72 : LOOKUP_MULTICAST :
2118 : LOOKUP_UNICAST);
2119 72 : input = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DEAG_SRC ?
2120 72 : LOOKUP_INPUT_SRC_ADDR :
2121 : LOOKUP_INPUT_DST_ADDR);
2122 :
2123 72 : lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
2124 72 : path->fp_nh_proto,
2125 : cast,
2126 : input,
2127 : LOOKUP_TABLE_FROM_CONFIG,
2128 : &path->fp_dpo);
2129 : }
2130 76 : break;
2131 : }
2132 7 : case FIB_PATH_TYPE_DVR:
2133 7 : dvr_dpo_add_or_lock(path->dvr.fp_interface,
2134 7 : path->fp_nh_proto,
2135 : &path->fp_dpo);
2136 7 : break;
2137 21202 : case FIB_PATH_TYPE_RECEIVE:
2138 : /*
2139 : * Resolve via a receive DPO.
2140 : */
2141 21202 : receive_dpo_add_or_lock(path->fp_nh_proto,
2142 : path->receive.fp_interface,
2143 21202 : &path->receive.fp_addr,
2144 : &path->fp_dpo);
2145 21202 : break;
2146 11 : case FIB_PATH_TYPE_UDP_ENCAP:
2147 11 : udp_encap_lock(path->udp_encap.fp_udp_encap_id);
2148 11 : udp_encap_contribute_forwarding(path->udp_encap.fp_udp_encap_id,
2149 11 : path->fp_nh_proto,
2150 : &path->fp_dpo);
2151 11 : break;
2152 8 : case FIB_PATH_TYPE_INTF_RX: {
2153 : /*
2154 : * Resolve via a receive DPO.
2155 : */
2156 8 : interface_rx_dpo_add_or_lock(path->fp_nh_proto,
2157 : path->intf_rx.fp_interface,
2158 : &path->fp_dpo);
2159 8 : break;
2160 : }
2161 8260 : case FIB_PATH_TYPE_EXCLUSIVE:
2162 : /*
2163 : * Resolve via the user provided DPO
2164 : */
2165 8260 : dpo_copy(&path->fp_dpo, &path->exclusive.fp_ex_dpo);
2166 8260 : break;
2167 : }
2168 :
2169 78882 : return (fib_path_is_resolved(path_index));
2170 : }
2171 :
2172 : u32
2173 136478 : fib_path_get_resolving_interface (fib_node_index_t path_index)
2174 : {
2175 : fib_path_t *path;
2176 :
2177 136478 : path = fib_path_get(path_index);
2178 :
2179 136480 : switch (path->fp_type)
2180 : {
2181 91000 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
2182 91000 : return (path->attached_next_hop.fp_interface);
2183 38795 : case FIB_PATH_TYPE_ATTACHED:
2184 38795 : return (path->attached.fp_interface);
2185 2099 : case FIB_PATH_TYPE_RECEIVE:
2186 2099 : return (path->receive.fp_interface);
2187 1 : case FIB_PATH_TYPE_RECURSIVE:
2188 1 : if (fib_path_is_resolved(path_index))
2189 : {
2190 0 : return (fib_entry_get_resolving_interface(path->fp_via_fib));
2191 : }
2192 1 : break;
2193 0 : case FIB_PATH_TYPE_DVR:
2194 0 : return (path->dvr.fp_interface);
2195 4585 : case FIB_PATH_TYPE_INTF_RX:
2196 : case FIB_PATH_TYPE_UDP_ENCAP:
2197 : case FIB_PATH_TYPE_SPECIAL:
2198 : case FIB_PATH_TYPE_DEAG:
2199 : case FIB_PATH_TYPE_EXCLUSIVE:
2200 : case FIB_PATH_TYPE_BIER_FMASK:
2201 : case FIB_PATH_TYPE_BIER_TABLE:
2202 : case FIB_PATH_TYPE_BIER_IMP:
2203 4585 : break;
2204 : }
2205 4586 : return (dpo_get_urpf(&path->fp_dpo));
2206 : }
2207 :
2208 : index_t
2209 3940 : fib_path_get_resolving_index (fib_node_index_t path_index)
2210 : {
2211 : fib_path_t *path;
2212 :
2213 3940 : path = fib_path_get(path_index);
2214 :
2215 3940 : switch (path->fp_type)
2216 : {
2217 0 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
2218 : case FIB_PATH_TYPE_ATTACHED:
2219 : case FIB_PATH_TYPE_RECEIVE:
2220 : case FIB_PATH_TYPE_INTF_RX:
2221 : case FIB_PATH_TYPE_SPECIAL:
2222 : case FIB_PATH_TYPE_DEAG:
2223 : case FIB_PATH_TYPE_DVR:
2224 : case FIB_PATH_TYPE_EXCLUSIVE:
2225 0 : break;
2226 0 : case FIB_PATH_TYPE_UDP_ENCAP:
2227 0 : return (path->udp_encap.fp_udp_encap_id);
2228 0 : case FIB_PATH_TYPE_RECURSIVE:
2229 0 : return (path->fp_via_fib);
2230 180 : case FIB_PATH_TYPE_BIER_FMASK:
2231 180 : return (path->bier_fmask.fp_bier_fmask);
2232 3760 : case FIB_PATH_TYPE_BIER_TABLE:
2233 3760 : return (path->fp_via_bier_tbl);
2234 0 : case FIB_PATH_TYPE_BIER_IMP:
2235 0 : return (path->bier_imp.fp_bier_imp);
2236 : }
2237 0 : return (~0);
2238 : }
2239 :
2240 : adj_index_t
2241 5621 : fib_path_get_adj (fib_node_index_t path_index)
2242 : {
2243 : fib_path_t *path;
2244 :
2245 5621 : path = fib_path_get(path_index);
2246 :
2247 5621 : if (dpo_is_adj(&path->fp_dpo))
2248 : {
2249 5523 : return (path->fp_dpo.dpoi_index);
2250 : }
2251 98 : return (ADJ_INDEX_INVALID);
2252 : }
2253 :
2254 : u16
2255 153003 : fib_path_get_weight (fib_node_index_t path_index)
2256 : {
2257 : fib_path_t *path;
2258 :
2259 153003 : path = fib_path_get(path_index);
2260 :
2261 153003 : ASSERT(path);
2262 :
2263 153003 : return (path->fp_weight);
2264 : }
2265 :
2266 : u16
2267 80572 : fib_path_get_preference (fib_node_index_t path_index)
2268 : {
2269 : fib_path_t *path;
2270 :
2271 80572 : path = fib_path_get(path_index);
2272 :
2273 80572 : ASSERT(path);
2274 :
2275 80572 : return (path->fp_preference);
2276 : }
2277 :
2278 : u32
2279 6 : fib_path_get_rpf_id (fib_node_index_t path_index)
2280 : {
2281 : fib_path_t *path;
2282 :
2283 6 : path = fib_path_get(path_index);
2284 :
2285 6 : ASSERT(path);
2286 :
2287 6 : if (FIB_PATH_CFG_FLAG_RPF_ID & path->fp_cfg_flags)
2288 : {
2289 6 : return (path->deag.fp_rpf_id);
2290 : }
2291 :
2292 0 : return (~0);
2293 : }
2294 :
2295 : /**
2296 : * @brief Contribute the path's adjacency to the list passed.
2297 : * By calling this function over all paths, recursively, a child
2298 : * can construct its full set of forwarding adjacencies, and hence its
2299 : * uRPF list.
2300 : */
2301 : void
2302 139494 : fib_path_contribute_urpf (fib_node_index_t path_index,
2303 : index_t urpf)
2304 : {
2305 : fib_path_t *path;
2306 :
2307 139494 : path = fib_path_get(path_index);
2308 :
2309 : /*
2310 : * resolved and unresolved paths contribute to the RPF list.
2311 : */
2312 139494 : switch (path->fp_type)
2313 : {
2314 20001 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
2315 20001 : fib_urpf_list_append(urpf, path->attached_next_hop.fp_interface);
2316 20001 : break;
2317 :
2318 64626 : case FIB_PATH_TYPE_ATTACHED:
2319 64626 : fib_urpf_list_append(urpf, path->attached.fp_interface);
2320 64626 : break;
2321 :
2322 3323 : case FIB_PATH_TYPE_RECURSIVE:
2323 6645 : if (FIB_NODE_INDEX_INVALID != path->fp_via_fib &&
2324 3322 : !fib_path_is_looped(path_index))
2325 : {
2326 : /*
2327 : * there's unresolved due to constraints, and there's unresolved
2328 : * due to ain't got no via. can't do nowt w'out via.
2329 : */
2330 3306 : fib_entry_contribute_urpf(path->fp_via_fib, urpf);
2331 : }
2332 3323 : break;
2333 :
2334 20538 : case FIB_PATH_TYPE_EXCLUSIVE:
2335 : case FIB_PATH_TYPE_SPECIAL:
2336 : {
2337 : /*
2338 : * these path types may link to an adj, if that's what
2339 : * the clinet gave
2340 : */
2341 : u32 rpf_sw_if_index;
2342 :
2343 20538 : rpf_sw_if_index = dpo_get_urpf(&path->fp_dpo);
2344 :
2345 20538 : if (~0 != rpf_sw_if_index)
2346 : {
2347 16 : fib_urpf_list_append(urpf, rpf_sw_if_index);
2348 : }
2349 20538 : break;
2350 : }
2351 3 : case FIB_PATH_TYPE_DVR:
2352 3 : fib_urpf_list_append(urpf, path->dvr.fp_interface);
2353 3 : break;
2354 10 : case FIB_PATH_TYPE_UDP_ENCAP:
2355 10 : fib_urpf_list_append(urpf, path->udp_encap.fp_udp_encap_id);
2356 10 : break;
2357 30993 : case FIB_PATH_TYPE_DEAG:
2358 : case FIB_PATH_TYPE_RECEIVE:
2359 : case FIB_PATH_TYPE_INTF_RX:
2360 : case FIB_PATH_TYPE_BIER_FMASK:
2361 : case FIB_PATH_TYPE_BIER_TABLE:
2362 : case FIB_PATH_TYPE_BIER_IMP:
2363 : /*
2364 : * these path types don't link to an adj
2365 : */
2366 30993 : break;
2367 : }
2368 139494 : }
2369 :
2370 : void
2371 1735 : fib_path_stack_mpls_disp (fib_node_index_t path_index,
2372 : dpo_proto_t payload_proto,
2373 : fib_mpls_lsp_mode_t mode,
2374 : dpo_id_t *dpo)
2375 : {
2376 : fib_path_t *path;
2377 :
2378 1735 : path = fib_path_get(path_index);
2379 :
2380 1735 : ASSERT(path);
2381 :
2382 1735 : switch (path->fp_type)
2383 : {
2384 80 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
2385 : {
2386 80 : dpo_id_t tmp = DPO_INVALID;
2387 :
2388 80 : dpo_copy(&tmp, dpo);
2389 :
2390 80 : mpls_disp_dpo_create(payload_proto, ~0, mode, &tmp, dpo);
2391 80 : dpo_reset(&tmp);
2392 80 : break;
2393 : }
2394 10 : case FIB_PATH_TYPE_DEAG:
2395 : {
2396 10 : dpo_id_t tmp = DPO_INVALID;
2397 :
2398 10 : dpo_copy(&tmp, dpo);
2399 :
2400 10 : mpls_disp_dpo_create(payload_proto,
2401 : path->deag.fp_rpf_id,
2402 : mode, &tmp, dpo);
2403 10 : dpo_reset(&tmp);
2404 10 : break;
2405 : }
2406 1645 : case FIB_PATH_TYPE_RECEIVE:
2407 : case FIB_PATH_TYPE_ATTACHED:
2408 : case FIB_PATH_TYPE_RECURSIVE:
2409 : case FIB_PATH_TYPE_INTF_RX:
2410 : case FIB_PATH_TYPE_UDP_ENCAP:
2411 : case FIB_PATH_TYPE_EXCLUSIVE:
2412 : case FIB_PATH_TYPE_SPECIAL:
2413 : case FIB_PATH_TYPE_BIER_FMASK:
2414 : case FIB_PATH_TYPE_BIER_TABLE:
2415 : case FIB_PATH_TYPE_BIER_IMP:
2416 : case FIB_PATH_TYPE_DVR:
2417 1645 : break;
2418 : }
2419 :
2420 1735 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_POP_PW_CW)
2421 : {
2422 1 : dpo_id_t tmp = DPO_INVALID;
2423 :
2424 1 : dpo_copy(&tmp, dpo);
2425 :
2426 1 : pw_cw_dpo_create(&tmp, dpo);
2427 1 : dpo_reset(&tmp);
2428 : }
2429 1735 : }
2430 :
2431 : void
2432 156226 : fib_path_contribute_forwarding (fib_node_index_t path_index,
2433 : fib_forward_chain_type_t fct,
2434 : dpo_proto_t payload_proto,
2435 : dpo_id_t *dpo)
2436 : {
2437 : fib_path_t *path;
2438 :
2439 156226 : path = fib_path_get(path_index);
2440 :
2441 156226 : ASSERT(path);
2442 :
2443 : /*
2444 : * The DPO stored in the path was created when the path was resolved.
2445 : * This then represents the path's 'native' protocol; IP.
2446 : * For all others will need to go find something else.
2447 : */
2448 156226 : if (fib_path_to_chain_type(path) == fct)
2449 : {
2450 69671 : dpo_copy(dpo, &path->fp_dpo);
2451 : }
2452 : else
2453 : {
2454 86555 : switch (path->fp_type)
2455 : {
2456 1095 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
2457 1095 : switch (fct)
2458 : {
2459 67 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS: {
2460 67 : dpo_id_t tmp = DPO_INVALID;
2461 67 : dpo_copy (&tmp, dpo);
2462 67 : path = fib_path_attached_next_hop_get_adj(
2463 : path,
2464 67 : dpo_proto_to_link(payload_proto),
2465 : &tmp);
2466 67 : dpo_copy (dpo, &tmp);
2467 67 : dpo_reset(&tmp);
2468 67 : break;
2469 : }
2470 1028 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
2471 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
2472 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
2473 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
2474 : case FIB_FORW_CHAIN_TYPE_NSH:
2475 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
2476 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
2477 : {
2478 1028 : dpo_id_t tmp = DPO_INVALID;
2479 1028 : dpo_copy (&tmp, dpo);
2480 1028 : path = fib_path_attached_next_hop_get_adj(
2481 : path,
2482 1028 : fib_forw_chain_type_to_link_type(fct),
2483 : &tmp);
2484 1028 : dpo_copy (dpo, &tmp);
2485 1028 : dpo_reset(&tmp);
2486 1028 : break;
2487 : }
2488 0 : case FIB_FORW_CHAIN_TYPE_BIER:
2489 0 : break;
2490 : }
2491 1095 : break;
2492 2247 : case FIB_PATH_TYPE_RECURSIVE:
2493 2247 : switch (fct)
2494 : {
2495 2247 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
2496 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
2497 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
2498 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
2499 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
2500 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
2501 : case FIB_FORW_CHAIN_TYPE_BIER:
2502 2247 : fib_path_recursive_adj_update(path, fct, dpo);
2503 2247 : break;
2504 0 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
2505 : case FIB_FORW_CHAIN_TYPE_NSH:
2506 0 : ASSERT(0);
2507 0 : break;
2508 : }
2509 2247 : break;
2510 400 : case FIB_PATH_TYPE_BIER_TABLE:
2511 400 : switch (fct)
2512 : {
2513 400 : case FIB_FORW_CHAIN_TYPE_BIER:
2514 400 : bier_table_contribute_forwarding(path->fp_via_bier_tbl, dpo);
2515 400 : break;
2516 0 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
2517 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
2518 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
2519 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
2520 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
2521 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
2522 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
2523 : case FIB_FORW_CHAIN_TYPE_NSH:
2524 0 : ASSERT(0);
2525 0 : break;
2526 : }
2527 400 : break;
2528 2505 : case FIB_PATH_TYPE_BIER_FMASK:
2529 2505 : switch (fct)
2530 : {
2531 2505 : case FIB_FORW_CHAIN_TYPE_BIER:
2532 2505 : fib_path_bier_fmask_update(path, dpo);
2533 2505 : break;
2534 0 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
2535 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
2536 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
2537 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
2538 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
2539 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
2540 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
2541 : case FIB_FORW_CHAIN_TYPE_NSH:
2542 0 : ASSERT(0);
2543 0 : break;
2544 : }
2545 2505 : break;
2546 22 : case FIB_PATH_TYPE_BIER_IMP:
2547 22 : bier_imp_contribute_forwarding(path->bier_imp.fp_bier_imp,
2548 22 : fib_forw_chain_type_to_dpo_proto(fct),
2549 : dpo);
2550 22 : break;
2551 11 : case FIB_PATH_TYPE_DEAG:
2552 11 : switch (fct)
2553 : {
2554 2 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
2555 2 : lookup_dpo_add_or_lock_w_table_id(MPLS_FIB_DEFAULT_TABLE_ID,
2556 : DPO_PROTO_MPLS,
2557 : LOOKUP_UNICAST,
2558 : LOOKUP_INPUT_DST_ADDR,
2559 : LOOKUP_TABLE_FROM_CONFIG,
2560 : dpo);
2561 2 : break;
2562 9 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
2563 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
2564 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
2565 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
2566 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
2567 9 : dpo_copy(dpo, &path->fp_dpo);
2568 9 : break;
2569 0 : case FIB_FORW_CHAIN_TYPE_BIER:
2570 0 : break;
2571 0 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
2572 : case FIB_FORW_CHAIN_TYPE_NSH:
2573 0 : ASSERT(0);
2574 0 : break;
2575 : }
2576 11 : break;
2577 303 : case FIB_PATH_TYPE_EXCLUSIVE:
2578 303 : dpo_copy(dpo, &path->exclusive.fp_ex_dpo);
2579 303 : break;
2580 3100 : case FIB_PATH_TYPE_ATTACHED:
2581 3100 : switch (fct)
2582 : {
2583 1 : case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
2584 : /*
2585 : * End of stack traffic via an attacehd path (a glean)
2586 : * must forace an IP lookup so that the IP packet can
2587 : * match against any installed adj-fibs
2588 : */
2589 1 : lookup_dpo_add_or_lock_w_fib_index(
2590 : fib_table_get_index_for_sw_if_index(
2591 1 : dpo_proto_to_fib(payload_proto),
2592 : path->attached.fp_interface),
2593 : payload_proto,
2594 : LOOKUP_UNICAST,
2595 : LOOKUP_INPUT_DST_ADDR,
2596 : LOOKUP_TABLE_FROM_CONFIG,
2597 : dpo);
2598 1 : break;
2599 10 : case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
2600 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
2601 : case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
2602 : case FIB_FORW_CHAIN_TYPE_ETHERNET:
2603 : case FIB_FORW_CHAIN_TYPE_NSH:
2604 : case FIB_FORW_CHAIN_TYPE_BIER:
2605 10 : fib_path_attached_get_adj(path,
2606 10 : fib_forw_chain_type_to_link_type(fct),
2607 : dpo);
2608 10 : break;
2609 3089 : case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
2610 : case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
2611 : {
2612 : adj_index_t ai;
2613 :
2614 : /*
2615 : * Create the adj needed for sending IP multicast traffic
2616 : */
2617 3089 : if (vnet_sw_interface_is_p2p(vnet_get_main(),
2618 : path->attached.fp_interface))
2619 : {
2620 : /*
2621 : * point-2-point interfaces do not require a glean, since
2622 : * there is nothing to ARP. Install a rewrite/nbr adj instead
2623 : */
2624 11 : ai = adj_nbr_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto),
2625 11 : fib_forw_chain_type_to_link_type(fct),
2626 : &zero_addr,
2627 : path->attached.fp_interface);
2628 : }
2629 : else
2630 : {
2631 3078 : ai = adj_mcast_add_or_lock(dpo_proto_to_fib(path->fp_nh_proto),
2632 3078 : fib_forw_chain_type_to_link_type(fct),
2633 : path->attached.fp_interface);
2634 : }
2635 3089 : dpo_set(dpo, DPO_ADJACENCY,
2636 3089 : fib_forw_chain_type_to_dpo_proto(fct),
2637 : ai);
2638 3089 : adj_unlock(ai);
2639 : }
2640 3089 : break;
2641 : }
2642 3100 : break;
2643 21 : case FIB_PATH_TYPE_INTF_RX:
2644 : /*
2645 : * Create the adj needed for sending IP multicast traffic
2646 : */
2647 21 : interface_rx_dpo_add_or_lock(payload_proto,
2648 : path->intf_rx.fp_interface,
2649 : dpo);
2650 21 : break;
2651 2 : case FIB_PATH_TYPE_UDP_ENCAP:
2652 2 : udp_encap_contribute_forwarding(path->udp_encap.fp_udp_encap_id,
2653 2 : path->fp_nh_proto,
2654 : dpo);
2655 2 : break;
2656 76849 : case FIB_PATH_TYPE_RECEIVE:
2657 : case FIB_PATH_TYPE_SPECIAL:
2658 : case FIB_PATH_TYPE_DVR:
2659 76849 : dpo_copy(dpo, &path->fp_dpo);
2660 76849 : break;
2661 : }
2662 156226 : }
2663 156226 : }
2664 :
2665 : load_balance_path_t *
2666 3221 : fib_path_append_nh_for_multipath_hash (fib_node_index_t path_index,
2667 : fib_forward_chain_type_t fct,
2668 : dpo_proto_t payload_proto,
2669 : load_balance_path_t *hash_key)
2670 : {
2671 : load_balance_path_t *mnh;
2672 : fib_path_t *path;
2673 :
2674 3221 : path = fib_path_get(path_index);
2675 :
2676 3221 : ASSERT(path);
2677 :
2678 3221 : vec_add2(hash_key, mnh, 1);
2679 :
2680 3221 : mnh->path_weight = path->fp_weight;
2681 3221 : mnh->path_index = path_index;
2682 :
2683 3221 : if (fib_path_is_resolved(path_index))
2684 : {
2685 3221 : fib_path_contribute_forwarding(path_index, fct, payload_proto, &mnh->path_dpo);
2686 : }
2687 : else
2688 : {
2689 0 : dpo_copy(&mnh->path_dpo,
2690 0 : drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
2691 : }
2692 3221 : return (hash_key);
2693 : }
2694 :
2695 : int
2696 80572 : fib_path_is_recursive_constrained (fib_node_index_t path_index)
2697 : {
2698 : fib_path_t *path;
2699 :
2700 80572 : path = fib_path_get(path_index);
2701 :
2702 105783 : return ((FIB_PATH_TYPE_RECURSIVE == path->fp_type) &&
2703 25211 : ((path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED) ||
2704 20971 : (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_HOST)));
2705 : }
2706 :
2707 : int
2708 1667 : fib_path_is_exclusive (fib_node_index_t path_index)
2709 : {
2710 : fib_path_t *path;
2711 :
2712 1667 : path = fib_path_get(path_index);
2713 :
2714 1667 : return (FIB_PATH_TYPE_EXCLUSIVE == path->fp_type);
2715 : }
2716 :
2717 : int
2718 1379 : fib_path_is_deag (fib_node_index_t path_index)
2719 : {
2720 : fib_path_t *path;
2721 :
2722 1379 : path = fib_path_get(path_index);
2723 :
2724 1379 : return (FIB_PATH_TYPE_DEAG == path->fp_type);
2725 : }
2726 :
2727 : int
2728 396942 : fib_path_is_resolved (fib_node_index_t path_index)
2729 : {
2730 : fib_path_t *path;
2731 :
2732 396942 : path = fib_path_get(path_index);
2733 :
2734 396942 : return (dpo_id_is_valid(&path->fp_dpo) &&
2735 729902 : (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED) &&
2736 1126840 : !fib_path_is_looped(path_index) &&
2737 332991 : !fib_path_is_permanent_drop(path));
2738 : }
2739 :
2740 : int
2741 432128 : fib_path_is_looped (fib_node_index_t path_index)
2742 : {
2743 : fib_path_t *path;
2744 :
2745 432128 : path = fib_path_get(path_index);
2746 :
2747 432128 : return (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP);
2748 : }
2749 :
2750 : fib_path_list_walk_rc_t
2751 235792 : fib_path_encode (fib_node_index_t path_list_index,
2752 : fib_node_index_t path_index,
2753 : const fib_path_ext_t *path_ext,
2754 : void *args)
2755 : {
2756 235792 : fib_path_encode_ctx_t *ctx = args;
2757 : fib_route_path_t *rpath;
2758 : fib_path_t *path;
2759 :
2760 235792 : path = fib_path_get(path_index);
2761 235792 : if (!path)
2762 0 : return (FIB_PATH_LIST_WALK_CONTINUE);
2763 :
2764 235792 : vec_add2(ctx->rpaths, rpath, 1);
2765 235792 : rpath->frp_weight = path->fp_weight;
2766 235792 : rpath->frp_preference = path->fp_preference;
2767 235792 : rpath->frp_proto = path->fp_nh_proto;
2768 235792 : rpath->frp_sw_if_index = ~0;
2769 235792 : rpath->frp_fib_index = 0;
2770 :
2771 235792 : switch (path->fp_type)
2772 : {
2773 8953 : case FIB_PATH_TYPE_RECEIVE:
2774 8953 : rpath->frp_addr = path->receive.fp_addr;
2775 8953 : rpath->frp_sw_if_index = path->receive.fp_interface;
2776 8953 : rpath->frp_flags |= FIB_ROUTE_PATH_LOCAL;
2777 8953 : break;
2778 13051 : case FIB_PATH_TYPE_ATTACHED:
2779 13051 : rpath->frp_sw_if_index = path->attached.fp_interface;
2780 13051 : break;
2781 57494 : case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
2782 57494 : rpath->frp_sw_if_index = path->attached_next_hop.fp_interface;
2783 57494 : rpath->frp_addr = path->attached_next_hop.fp_nh;
2784 57494 : break;
2785 11 : case FIB_PATH_TYPE_BIER_FMASK:
2786 11 : rpath->frp_bier_fmask = path->bier_fmask.fp_bier_fmask;
2787 11 : break;
2788 28532 : case FIB_PATH_TYPE_SPECIAL:
2789 28532 : break;
2790 59 : case FIB_PATH_TYPE_DEAG:
2791 59 : rpath->frp_fib_index = path->deag.fp_tbl_id;
2792 59 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID)
2793 : {
2794 11 : rpath->frp_flags |= FIB_ROUTE_PATH_RPF_ID;
2795 : }
2796 59 : break;
2797 106523 : case FIB_PATH_TYPE_RECURSIVE:
2798 106523 : rpath->frp_addr = path->recursive.fp_nh.fp_ip;
2799 106523 : rpath->frp_fib_index = path->recursive.fp_tbl_id;
2800 106523 : break;
2801 2 : case FIB_PATH_TYPE_DVR:
2802 2 : rpath->frp_sw_if_index = path->dvr.fp_interface;
2803 2 : rpath->frp_flags |= FIB_ROUTE_PATH_DVR;
2804 2 : break;
2805 18 : case FIB_PATH_TYPE_UDP_ENCAP:
2806 18 : rpath->frp_udp_encap_id = path->udp_encap.fp_udp_encap_id;
2807 18 : rpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
2808 18 : break;
2809 7 : case FIB_PATH_TYPE_INTF_RX:
2810 7 : rpath->frp_sw_if_index = path->receive.fp_interface;
2811 7 : rpath->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
2812 7 : break;
2813 21135 : case FIB_PATH_TYPE_EXCLUSIVE:
2814 21135 : rpath->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
2815 21142 : default:
2816 21142 : break;
2817 : }
2818 :
2819 235792 : if (path_ext && path_ext->fpe_type == FIB_PATH_EXT_MPLS)
2820 : {
2821 49099 : rpath->frp_label_stack = path_ext->fpe_path.frp_label_stack;
2822 : }
2823 :
2824 235792 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DROP)
2825 28532 : rpath->frp_flags |= FIB_ROUTE_PATH_DROP;
2826 235792 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_ICMP_UNREACH)
2827 6 : rpath->frp_flags |= FIB_ROUTE_PATH_ICMP_UNREACH;
2828 235792 : if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_ICMP_PROHIBIT)
2829 2 : rpath->frp_flags |= FIB_ROUTE_PATH_ICMP_PROHIBIT;
2830 :
2831 235792 : return (FIB_PATH_LIST_WALK_CONTINUE);
2832 : }
2833 :
2834 : dpo_proto_t
2835 0 : fib_path_get_proto (fib_node_index_t path_index)
2836 : {
2837 : fib_path_t *path;
2838 :
2839 0 : path = fib_path_get(path_index);
2840 :
2841 0 : return (path->fp_nh_proto);
2842 : }
2843 :
2844 : void
2845 575 : fib_path_module_init (void)
2846 : {
2847 575 : fib_node_register_type (FIB_NODE_TYPE_PATH, &fib_path_vft);
2848 575 : fib_path_logger = vlib_log_register_class ("fib", "path");
2849 575 : }
2850 :
2851 : static clib_error_t *
2852 3 : show_fib_path_command (vlib_main_t * vm,
2853 : unformat_input_t * input,
2854 : vlib_cli_command_t * cmd)
2855 : {
2856 : fib_node_index_t pi;
2857 : fib_path_t *path;
2858 :
2859 3 : if (unformat (input, "%d", &pi))
2860 : {
2861 : /*
2862 : * show one in detail
2863 : */
2864 2 : if (!pool_is_free_index(fib_path_pool, pi))
2865 : {
2866 1 : path = fib_path_get(pi);
2867 1 : u8 *s = format(NULL, "%U", format_fib_path, pi, 1,
2868 : FIB_PATH_FORMAT_FLAGS_NONE);
2869 1 : s = format(s, "\n children:");
2870 1 : s = fib_node_children_format(path->fp_node.fn_children, s);
2871 1 : vlib_cli_output (vm, "%v", s);
2872 1 : vec_free(s);
2873 : }
2874 : else
2875 : {
2876 1 : vlib_cli_output (vm, "path %d invalid", pi);
2877 : }
2878 : }
2879 : else
2880 : {
2881 1 : vlib_cli_output (vm, "FIB Paths");
2882 14 : pool_foreach_index (pi, fib_path_pool)
2883 : {
2884 13 : vlib_cli_output (vm, "%U", format_fib_path, pi, 0,
2885 : FIB_PATH_FORMAT_FLAGS_NONE);
2886 : }
2887 : }
2888 :
2889 3 : return (NULL);
2890 : }
2891 :
2892 285289 : VLIB_CLI_COMMAND (show_fib_path, static) = {
2893 : .path = "show fib paths",
2894 : .function = show_fib_path_command,
2895 : .short_help = "show fib paths",
2896 : };
|