]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_rnh.c
Merge pull request #8864 from idryzhov/fix-vtysh-vrf-change
[mirror_frr.git] / zebra / zebra_rnh.c
1 /* Zebra next hop tracking code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "table.h"
25 #include "memory.h"
26 #include "command.h"
27 #include "if.h"
28 #include "log.h"
29 #include "sockunion.h"
30 #include "linklist.h"
31 #include "thread.h"
32 #include "workqueue.h"
33 #include "prefix.h"
34 #include "routemap.h"
35 #include "stream.h"
36 #include "nexthop.h"
37 #include "vrf.h"
38
39 #include "zebra/zebra_router.h"
40 #include "zebra/rib.h"
41 #include "zebra/rt.h"
42 #include "zebra/zserv.h"
43 #include "zebra/zebra_ns.h"
44 #include "zebra/zebra_vrf.h"
45 #include "zebra/redistribute.h"
46 #include "zebra/debug.h"
47 #include "zebra/zebra_rnh.h"
48 #include "zebra/zebra_routemap.h"
49 #include "zebra/zebra_srte.h"
50 #include "zebra/interface.h"
51 #include "zebra/zebra_errors.h"
52
53 DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object");
54
55 /* UI controls whether to notify about changes that only involve backup
56 * nexthops. Default is to notify all changes.
57 */
58 static bool rnh_hide_backups;
59
60 static void free_state(vrf_id_t vrf_id, struct route_entry *re,
61 struct route_node *rn);
62 static void copy_state(struct rnh *rnh, const struct route_entry *re,
63 struct route_node *rn);
64 static bool compare_state(struct route_entry *r1, struct route_entry *r2);
65 static void print_rnh(struct route_node *rn, struct vty *vty);
66 static int zebra_client_cleanup_rnh(struct zserv *client);
67
68 void zebra_rnh_init(void)
69 {
70 hook_register(zserv_client_close, zebra_client_cleanup_rnh);
71 }
72
73 static inline struct route_table *get_rnh_table(vrf_id_t vrfid, afi_t afi,
74 enum rnh_type type)
75 {
76 struct zebra_vrf *zvrf;
77 struct route_table *t = NULL;
78
79 zvrf = zebra_vrf_lookup_by_id(vrfid);
80 if (zvrf)
81 switch (type) {
82 case RNH_NEXTHOP_TYPE:
83 t = zvrf->rnh_table[afi];
84 break;
85 case RNH_IMPORT_CHECK_TYPE:
86 t = zvrf->import_check_table[afi];
87 break;
88 }
89
90 return t;
91 }
92
93 static void zebra_rnh_remove_from_routing_table(struct rnh *rnh)
94 {
95 struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
96 struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
97 struct route_node *rn;
98 rib_dest_t *dest;
99
100 if (!table)
101 return;
102
103 rn = route_node_match(table, &rnh->resolved_route);
104 if (!rn)
105 return;
106
107 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
108 zlog_debug("%s: %s(%u):%pRN removed from tracking on %pRN",
109 __func__, VRF_LOGNAME(zvrf->vrf), rnh->vrf_id,
110 rnh->node, rn);
111
112 dest = rib_dest_from_rnode(rn);
113 rnh_list_del(&dest->nht, rnh);
114 route_unlock_node(rn);
115 }
116
117 static void zebra_rnh_store_in_routing_table(struct rnh *rnh)
118 {
119 struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
120 struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
121 struct route_node *rn;
122 rib_dest_t *dest;
123
124 rn = route_node_match(table, &rnh->resolved_route);
125 if (!rn)
126 return;
127
128 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
129 zlog_debug("%s: %s(%u):%pRN added for tracking on %pRN",
130 __func__, VRF_LOGNAME(zvrf->vrf), rnh->vrf_id,
131 rnh->node, rn);
132
133 dest = rib_dest_from_rnode(rn);
134 rnh_list_add_tail(&dest->nht, rnh);
135 route_unlock_node(rn);
136 }
137
138 struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, enum rnh_type type,
139 bool *exists)
140 {
141 struct route_table *table;
142 struct route_node *rn;
143 struct rnh *rnh = NULL;
144 afi_t afi = family2afi(p->family);
145
146 if (IS_ZEBRA_DEBUG_NHT) {
147 struct vrf *vrf = vrf_lookup_by_id(vrfid);
148
149 zlog_debug("%s(%u): Add RNH %pFX type %s", VRF_LOGNAME(vrf),
150 vrfid, p, rnh_type2str(type));
151 }
152 table = get_rnh_table(vrfid, afi, type);
153 if (!table) {
154 struct vrf *vrf = vrf_lookup_by_id(vrfid);
155
156 flog_warn(EC_ZEBRA_RNH_NO_TABLE,
157 "%s(%u): Add RNH %pFX type %s - table not found",
158 VRF_LOGNAME(vrf), vrfid, p, rnh_type2str(type));
159 *exists = false;
160 return NULL;
161 }
162
163 /* Make it sure prefixlen is applied to the prefix. */
164 apply_mask(p);
165
166 /* Lookup (or add) route node.*/
167 rn = route_node_get(table, p);
168
169 if (!rn->info) {
170 rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
171
172 /*
173 * The resolved route is already 0.0.0.0/0 or
174 * 0::0/0 due to the calloc right above, but
175 * we should set the family so that future
176 * comparisons can just be done
177 */
178 rnh->resolved_route.family = p->family;
179 rnh->client_list = list_new();
180 rnh->vrf_id = vrfid;
181 rnh->type = type;
182 rnh->seqno = 0;
183 rnh->afi = afi;
184 rnh->zebra_pseudowire_list = list_new();
185 route_lock_node(rn);
186 rn->info = rnh;
187 rnh->node = rn;
188 *exists = false;
189
190 zebra_rnh_store_in_routing_table(rnh);
191 } else
192 *exists = true;
193
194 route_unlock_node(rn);
195 return (rn->info);
196 }
197
198 struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
199 enum rnh_type type)
200 {
201 struct route_table *table;
202 struct route_node *rn;
203
204 table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type);
205 if (!table)
206 return NULL;
207
208 /* Make it sure prefixlen is applied to the prefix. */
209 apply_mask(p);
210
211 /* Lookup route node.*/
212 rn = route_node_lookup(table, p);
213 if (!rn)
214 return NULL;
215
216 route_unlock_node(rn);
217 return (rn->info);
218 }
219
220 void zebra_free_rnh(struct rnh *rnh)
221 {
222 struct zebra_vrf *zvrf;
223 struct route_table *table;
224
225 zebra_rnh_remove_from_routing_table(rnh);
226 rnh->flags |= ZEBRA_NHT_DELETED;
227 list_delete(&rnh->client_list);
228 list_delete(&rnh->zebra_pseudowire_list);
229
230 zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
231 table = zvrf->table[family2afi(rnh->resolved_route.family)][SAFI_UNICAST];
232
233 if (table) {
234 struct route_node *rern;
235
236 rern = route_node_match(table, &rnh->resolved_route);
237 if (rern) {
238 rib_dest_t *dest;
239
240 route_unlock_node(rern);
241
242 dest = rib_dest_from_rnode(rern);
243 rnh_list_del(&dest->nht, rnh);
244 }
245 }
246 free_state(rnh->vrf_id, rnh->state, rnh->node);
247 XFREE(MTYPE_RNH, rnh);
248 }
249
250 static void zebra_delete_rnh(struct rnh *rnh, enum rnh_type type)
251 {
252 struct route_node *rn;
253
254 if (!list_isempty(rnh->client_list)
255 || !list_isempty(rnh->zebra_pseudowire_list))
256 return;
257
258 if ((rnh->flags & ZEBRA_NHT_DELETED) || !(rn = rnh->node))
259 return;
260
261 if (IS_ZEBRA_DEBUG_NHT) {
262 struct vrf *vrf = vrf_lookup_by_id(rnh->vrf_id);
263
264 zlog_debug("%s(%u): Del RNH %pRN type %s", VRF_LOGNAME(vrf),
265 rnh->vrf_id, rnh->node, rnh_type2str(type));
266 }
267
268 zebra_free_rnh(rnh);
269 rn->info = NULL;
270 route_unlock_node(rn);
271 }
272
273 /*
274 * This code will send to the registering client
275 * the looked up rnh.
276 * For a rnh that was created, there is no data
277 * so it will send an empty nexthop group
278 * If rnh exists then we know it has been evaluated
279 * and as such it will have a resolved rnh.
280 */
281 void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
282 enum rnh_type type, vrf_id_t vrf_id)
283 {
284 if (IS_ZEBRA_DEBUG_NHT) {
285 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
286
287 zlog_debug("%s(%u): Client %s registers for RNH %pRN type %s",
288 VRF_LOGNAME(vrf), vrf_id,
289 zebra_route_string(client->proto), rnh->node,
290 rnh_type2str(type));
291 }
292 if (!listnode_lookup(rnh->client_list, client))
293 listnode_add(rnh->client_list, client);
294
295 /*
296 * We always need to respond with known information,
297 * currently multiple daemons expect this behavior
298 */
299 zebra_send_rnh_update(rnh, client, type, vrf_id, 0);
300 }
301
302 void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
303 enum rnh_type type)
304 {
305 if (IS_ZEBRA_DEBUG_NHT) {
306 struct vrf *vrf = vrf_lookup_by_id(rnh->vrf_id);
307
308 zlog_debug("Client %s unregisters for RNH %s(%u)%pRN type %s",
309 zebra_route_string(client->proto), VRF_LOGNAME(vrf),
310 vrf->vrf_id, rnh->node, rnh_type2str(type));
311 }
312 listnode_delete(rnh->client_list, client);
313 zebra_delete_rnh(rnh, type);
314 }
315
316 /* XXX move this utility function elsewhere? */
317 static void addr2hostprefix(int af, const union g_addr *addr,
318 struct prefix *prefix)
319 {
320 switch (af) {
321 case AF_INET:
322 prefix->family = AF_INET;
323 prefix->prefixlen = IPV4_MAX_BITLEN;
324 prefix->u.prefix4 = addr->ipv4;
325 break;
326 case AF_INET6:
327 prefix->family = AF_INET6;
328 prefix->prefixlen = IPV6_MAX_BITLEN;
329 prefix->u.prefix6 = addr->ipv6;
330 break;
331 default:
332 memset(prefix, 0, sizeof(*prefix));
333 zlog_warn("%s: unknown address family %d", __func__, af);
334 break;
335 }
336 }
337
338 void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw,
339 bool *nht_exists)
340 {
341 struct prefix nh;
342 struct rnh *rnh;
343 bool exists;
344 struct zebra_vrf *zvrf;
345
346 *nht_exists = false;
347
348 zvrf = vrf_info_lookup(vrf_id);
349 if (!zvrf)
350 return;
351
352 addr2hostprefix(pw->af, &pw->nexthop, &nh);
353 rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE, &exists);
354 if (!rnh)
355 return;
356
357 if (!listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
358 listnode_add(rnh->zebra_pseudowire_list, pw);
359 pw->rnh = rnh;
360 zebra_evaluate_rnh(zvrf, family2afi(pw->af), 1,
361 RNH_NEXTHOP_TYPE, &nh);
362 } else
363 *nht_exists = true;
364 }
365
366 void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
367 {
368 struct rnh *rnh;
369
370 rnh = pw->rnh;
371 if (!rnh)
372 return;
373
374 listnode_delete(rnh->zebra_pseudowire_list, pw);
375 pw->rnh = NULL;
376
377 zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
378 }
379
380 /* Clear the NEXTHOP_FLAG_RNH_FILTERED flags on all nexthops
381 */
382 static void zebra_rnh_clear_nexthop_rnh_filters(struct route_entry *re)
383 {
384 struct nexthop *nexthop;
385
386 if (re) {
387 for (nexthop = re->nhe->nhg.nexthop; nexthop;
388 nexthop = nexthop->next) {
389 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED);
390 }
391 }
392 }
393
394 /* Apply the NHT route-map for a client to the route (and nexthops)
395 * resolving a NH.
396 */
397 static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
398 struct route_node *prn,
399 struct route_entry *re, int proto)
400 {
401 int at_least_one = 0;
402 struct nexthop *nexthop;
403 route_map_result_t ret;
404
405 if (prn && re) {
406 for (nexthop = re->nhe->nhg.nexthop; nexthop;
407 nexthop = nexthop->next) {
408 ret = zebra_nht_route_map_check(
409 afi, proto, &prn->p, zvrf, re, nexthop);
410 if (ret != RMAP_DENYMATCH)
411 at_least_one++; /* at least one valid NH */
412 else {
413 SET_FLAG(nexthop->flags,
414 NEXTHOP_FLAG_RNH_FILTERED);
415 }
416 }
417 }
418 return (at_least_one);
419 }
420
421 /*
422 * Determine appropriate route (RE entry) resolving a tracked BGP route
423 * for BGP route for import.
424 */
425 static struct route_entry *
426 zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
427 struct route_node *nrn, struct rnh *rnh,
428 struct route_node **prn)
429 {
430 struct route_table *route_table;
431 struct route_node *rn;
432 struct route_entry *re;
433
434 *prn = NULL;
435
436 route_table = zvrf->table[afi][SAFI_UNICAST];
437 if (!route_table) // unexpected
438 return NULL;
439
440 rn = route_node_match(route_table, &nrn->p);
441 if (!rn)
442 return NULL;
443
444 /* Unlock route node - we don't need to lock when walking the tree. */
445 route_unlock_node(rn);
446
447 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)
448 && !prefix_same(&nrn->p, &rn->p))
449 return NULL;
450
451 if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
452 zlog_debug("%s: %s(%u):%pRN Resolved Import Entry to %pRN",
453 __func__, VRF_LOGNAME(zvrf->vrf), rnh->vrf_id,
454 rnh->node, rn);
455 }
456
457 /* Identify appropriate route entry. */
458 RNODE_FOREACH_RE (rn, re) {
459 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
460 && CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
461 && !CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)
462 && (re->type != ZEBRA_ROUTE_BGP))
463 break;
464 }
465
466 if (re)
467 *prn = rn;
468
469 if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED)
470 zlog_debug(" Rejected due to removed or is a bgp route");
471
472 return re;
473 }
474
475 /*
476 * See if a tracked route entry for import (by BGP) has undergone any
477 * change, and if so, notify the client.
478 */
479 static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi,
480 int force, struct route_node *nrn,
481 struct rnh *rnh,
482 struct route_node *prn,
483 struct route_entry *re)
484 {
485 int state_changed = 0;
486 struct zserv *client;
487 struct listnode *node;
488
489 zebra_rnh_remove_from_routing_table(rnh);
490 if (prn) {
491 prefix_copy(&rnh->resolved_route, &prn->p);
492 } else {
493 int family = rnh->resolved_route.family;
494
495 memset(&rnh->resolved_route.family, 0, sizeof(struct prefix));
496 rnh->resolved_route.family = family;
497 }
498 zebra_rnh_store_in_routing_table(rnh);
499
500 if (re && (rnh->state == NULL)) {
501 if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
502 state_changed = 1;
503 } else if (!re && (rnh->state != NULL))
504 state_changed = 1;
505
506 if (compare_state(re, rnh->state)) {
507 copy_state(rnh, re, nrn);
508 state_changed = 1;
509 }
510
511 if (state_changed || force) {
512 if (IS_ZEBRA_DEBUG_NHT)
513 zlog_debug("%s(%u):%pRN: Route import check %s %s",
514 VRF_LOGNAME(zvrf->vrf), zvrf->vrf->vrf_id,
515 nrn, rnh->state ? "passed" : "failed",
516 state_changed ? "(state changed)" : "");
517 /* state changed, notify clients */
518 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
519 zebra_send_rnh_update(rnh, client,
520 RNH_IMPORT_CHECK_TYPE,
521 zvrf->vrf->vrf_id, 0);
522 }
523 }
524 }
525
526 /*
527 * Notify clients registered for this nexthop about a change.
528 */
529 static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi,
530 struct route_node *nrn,
531 struct rnh *rnh,
532 struct route_node *prn,
533 struct route_entry *re)
534 {
535 struct listnode *node;
536 struct zserv *client;
537 int num_resolving_nh;
538
539 if (IS_ZEBRA_DEBUG_NHT) {
540 if (prn && re) {
541 zlog_debug("%s(%u):%pRN: NH resolved over route %pRN",
542 VRF_LOGNAME(zvrf->vrf), zvrf->vrf->vrf_id,
543 nrn, prn);
544 } else
545 zlog_debug("%s(%u):%pRN: NH has become unresolved",
546 VRF_LOGNAME(zvrf->vrf), zvrf->vrf->vrf_id,
547 nrn);
548 }
549
550 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
551 if (prn && re) {
552 /* Apply route-map for this client to route resolving
553 * this
554 * nexthop to see if it is filtered or not.
555 */
556 zebra_rnh_clear_nexthop_rnh_filters(re);
557 num_resolving_nh = zebra_rnh_apply_nht_rmap(
558 afi, zvrf, prn, re, client->proto);
559 if (num_resolving_nh)
560 rnh->filtered[client->proto] = 0;
561 else
562 rnh->filtered[client->proto] = 1;
563
564 if (IS_ZEBRA_DEBUG_NHT)
565 zlog_debug(
566 "%s(%u):%pRN: Notifying client %s about NH %s",
567 VRF_LOGNAME(zvrf->vrf),
568 zvrf->vrf->vrf_id, nrn,
569 zebra_route_string(client->proto),
570 num_resolving_nh
571 ? ""
572 : "(filtered by route-map)");
573 } else {
574 rnh->filtered[client->proto] = 0;
575 if (IS_ZEBRA_DEBUG_NHT)
576 zlog_debug(
577 "%s(%u):%pRN: Notifying client %s about NH (unreachable)",
578 VRF_LOGNAME(zvrf->vrf),
579 zvrf->vrf->vrf_id, nrn,
580 zebra_route_string(client->proto));
581 }
582
583 zebra_send_rnh_update(rnh, client, RNH_NEXTHOP_TYPE,
584 zvrf->vrf->vrf_id, 0);
585 }
586
587 if (re)
588 zebra_rnh_clear_nexthop_rnh_filters(re);
589 }
590
591 /*
592 * Utility to determine whether a candidate nexthop is useable. We make this
593 * check in a couple of places, so this is a single home for the logic we
594 * use.
595 */
596
597 static const int RNH_INVALID_NH_FLAGS = (NEXTHOP_FLAG_RECURSIVE |
598 NEXTHOP_FLAG_DUPLICATE |
599 NEXTHOP_FLAG_RNH_FILTERED);
600
601 static bool rnh_nexthop_valid(const struct route_entry *re,
602 const struct nexthop *nh)
603 {
604 return (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
605 && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)
606 && !CHECK_FLAG(nh->flags, RNH_INVALID_NH_FLAGS));
607 }
608
609 /*
610 * Determine whether an re's nexthops are valid for tracking.
611 */
612 static bool rnh_check_re_nexthops(const struct route_entry *re,
613 const struct rnh *rnh)
614 {
615 bool ret = false;
616 const struct nexthop *nexthop = NULL;
617
618 /* Check route's nexthops */
619 for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
620 if (rnh_nexthop_valid(re, nexthop))
621 break;
622 }
623
624 /* Check backup nexthops, if any. */
625 if (nexthop == NULL && re->nhe->backup_info &&
626 re->nhe->backup_info->nhe) {
627 for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg, nexthop)) {
628 if (rnh_nexthop_valid(re, nexthop))
629 break;
630 }
631 }
632
633 if (nexthop == NULL) {
634 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
635 zlog_debug(
636 " Route Entry %s no nexthops",
637 zebra_route_string(re->type));
638
639 goto done;
640 }
641
642 /* Some special checks if registration asked for them. */
643 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
644 if ((re->type == ZEBRA_ROUTE_CONNECT)
645 || (re->type == ZEBRA_ROUTE_STATIC))
646 ret = true;
647 if (re->type == ZEBRA_ROUTE_NHRP) {
648
649 for (nexthop = re->nhe->nhg.nexthop;
650 nexthop;
651 nexthop = nexthop->next)
652 if (nexthop->type == NEXTHOP_TYPE_IFINDEX)
653 break;
654 if (nexthop)
655 ret = true;
656 }
657 } else {
658 ret = true;
659 }
660
661 done:
662 return ret;
663 }
664
665 /*
666 * Determine appropriate route (route entry) resolving a tracked
667 * nexthop.
668 */
669 static struct route_entry *
670 zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
671 struct route_node *nrn, const struct rnh *rnh,
672 struct route_node **prn)
673 {
674 struct route_table *route_table;
675 struct route_node *rn;
676 struct route_entry *re;
677
678 *prn = NULL;
679
680 route_table = zvrf->table[afi][SAFI_UNICAST];
681 if (!route_table)
682 return NULL;
683
684 rn = route_node_match(route_table, &nrn->p);
685 if (!rn)
686 return NULL;
687
688 /* Unlock route node - we don't need to lock when walking the tree. */
689 route_unlock_node(rn);
690
691 /* While resolving nexthops, we may need to walk up the tree from the
692 * most-specific match. Do similar logic as in zebra_rib.c
693 */
694 while (rn) {
695 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
696 zlog_debug("%s: %s(%u):%pRN Possible Match to %pRN",
697 __func__, VRF_LOGNAME(zvrf->vrf),
698 rnh->vrf_id, rnh->node, rn);
699
700 /* Do not resolve over default route unless allowed &&
701 * match route to be exact if so specified
702 */
703 if (is_default_prefix(&rn->p)
704 && !rnh_resolve_via_default(zvrf, rn->p.family)) {
705 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
706 zlog_debug(
707 " Not allowed to resolve through default prefix");
708 return NULL;
709 }
710
711 /* Identify appropriate route entry. */
712 RNODE_FOREACH_RE (rn, re) {
713 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
714 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
715 zlog_debug(
716 " Route Entry %s removed",
717 zebra_route_string(re->type));
718 continue;
719 }
720 if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) &&
721 !CHECK_FLAG(re->flags, ZEBRA_FLAG_FIB_OVERRIDE)) {
722 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
723 zlog_debug(
724 " Route Entry %s !selected",
725 zebra_route_string(re->type));
726 continue;
727 }
728
729 if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) {
730 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
731 zlog_debug(
732 " Route Entry %s queued",
733 zebra_route_string(re->type));
734 continue;
735 }
736
737 /* Just being SELECTED isn't quite enough - must
738 * have an installed nexthop to be useful.
739 */
740 if (rnh_check_re_nexthops(re, rnh))
741 break;
742 }
743
744 /* Route entry found, we're done; else, walk up the tree. */
745 if (re) {
746 *prn = rn;
747 return re;
748 }
749
750 if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
751 rn = rn->parent;
752 else {
753 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
754 zlog_debug(
755 " Nexthop must be connected, cannot recurse up");
756 return NULL;
757 }
758 }
759
760 return NULL;
761 }
762
763 static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh)
764 {
765 struct zebra_pw *pw;
766 struct listnode *node;
767
768 for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw))
769 zebra_pw_update(pw);
770 }
771
772 /*
773 * See if a tracked nexthop entry has undergone any change, and if so,
774 * take appropriate action; this involves notifying any clients and/or
775 * scheduling dependent static routes for processing.
776 */
777 static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
778 int force, struct route_node *nrn,
779 struct rnh *rnh,
780 struct route_node *prn,
781 struct route_entry *re)
782 {
783 int state_changed = 0;
784
785 /* If we're resolving over a different route, resolution has changed or
786 * the resolving route has some change (e.g., metric), there is a state
787 * change.
788 */
789 zebra_rnh_remove_from_routing_table(rnh);
790 if (!prefix_same(&rnh->resolved_route, prn ? &prn->p : NULL)) {
791 if (prn)
792 prefix_copy(&rnh->resolved_route, &prn->p);
793 else {
794 /*
795 * Just quickly store the family of the resolved
796 * route so that we can reset it in a second here
797 */
798 int family = rnh->resolved_route.family;
799
800 memset(&rnh->resolved_route, 0, sizeof(struct prefix));
801 rnh->resolved_route.family = family;
802 }
803
804 copy_state(rnh, re, nrn);
805 state_changed = 1;
806 } else if (compare_state(re, rnh->state)) {
807 copy_state(rnh, re, nrn);
808 state_changed = 1;
809 }
810 zebra_rnh_store_in_routing_table(rnh);
811
812 if (state_changed || force) {
813 /* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
814 * rnh->state.
815 */
816 /* Notify registered protocol clients. */
817 zebra_rnh_notify_protocol_clients(zvrf, afi, nrn, rnh, prn,
818 rnh->state);
819
820 /* Process pseudowires attached to this nexthop */
821 zebra_rnh_process_pseudowires(zvrf->vrf->vrf_id, rnh);
822 }
823 }
824
825 /* Evaluate one tracked entry */
826 static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi,
827 int force, enum rnh_type type,
828 struct route_node *nrn)
829 {
830 struct rnh *rnh;
831 struct route_entry *re;
832 struct route_node *prn;
833
834 if (IS_ZEBRA_DEBUG_NHT) {
835 zlog_debug("%s(%u):%pRN: Evaluate RNH, type %s %s",
836 VRF_LOGNAME(zvrf->vrf), zvrf->vrf->vrf_id, nrn,
837 rnh_type2str(type), force ? "(force)" : "");
838 }
839
840 rnh = nrn->info;
841
842 /* Identify route entry (RE) resolving this tracked entry. */
843 if (type == RNH_IMPORT_CHECK_TYPE)
844 re = zebra_rnh_resolve_import_entry(zvrf, afi, nrn, rnh, &prn);
845 else
846 re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn);
847
848 /* If the entry cannot be resolved and that is also the existing state,
849 * there is nothing further to do.
850 */
851 if (!re && rnh->state == NULL && !force)
852 return;
853
854 /* Process based on type of entry. */
855 if (type == RNH_IMPORT_CHECK_TYPE)
856 zebra_rnh_eval_import_check_entry(zvrf, afi, force, nrn, rnh,
857 prn, re);
858 else
859 zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn,
860 re);
861 }
862
863 /*
864 * Clear the ROUTE_ENTRY_NEXTHOPS_CHANGED flag
865 * from the re entries.
866 *
867 * Please note we are doing this *after* we have
868 * notified the world about each nexthop as that
869 * we can have a situation where one re entry
870 * covers multiple nexthops we are interested in.
871 */
872 static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi,
873 enum rnh_type type, struct route_node *nrn)
874 {
875 struct rnh *rnh;
876 struct route_entry *re;
877 struct route_node *prn;
878
879 rnh = nrn->info;
880
881 /* Identify route entry (RIB) resolving this tracked entry. */
882 if (type == RNH_IMPORT_CHECK_TYPE)
883 re = zebra_rnh_resolve_import_entry(zvrf, afi, nrn, rnh,
884 &prn);
885 else
886 re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh,
887 &prn);
888
889 if (re)
890 UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
891 }
892
893 /* Evaluate all tracked entries (nexthops or routes for import into BGP)
894 * of a particular VRF and address-family or a specific prefix.
895 */
896 void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
897 enum rnh_type type, struct prefix *p)
898 {
899 struct route_table *rnh_table;
900 struct route_node *nrn;
901
902 rnh_table = get_rnh_table(zvrf->vrf->vrf_id, afi, type);
903 if (!rnh_table) // unexpected
904 return;
905
906 if (p) {
907 /* Evaluating a specific entry, make sure it exists. */
908 nrn = route_node_lookup(rnh_table, p);
909 if (nrn && nrn->info)
910 zebra_rnh_evaluate_entry(zvrf, afi, force, type, nrn);
911
912 if (nrn)
913 route_unlock_node(nrn);
914 } else {
915 /* Evaluate entire table. */
916 nrn = route_top(rnh_table);
917 while (nrn) {
918 if (nrn->info)
919 zebra_rnh_evaluate_entry(zvrf, afi, force, type,
920 nrn);
921 nrn = route_next(nrn); /* this will also unlock nrn */
922 }
923 nrn = route_top(rnh_table);
924 while (nrn) {
925 if (nrn->info)
926 zebra_rnh_clear_nhc_flag(zvrf, afi, type, nrn);
927 nrn = route_next(nrn); /* this will also unlock nrn */
928 }
929 }
930 }
931
932 void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
933 enum rnh_type type, struct prefix *p)
934 {
935 struct route_table *table;
936 struct route_node *rn;
937
938 table = get_rnh_table(vrfid, afi, type);
939 if (!table) {
940 if (IS_ZEBRA_DEBUG_NHT)
941 zlog_debug("print_rnhs: rnh table not found");
942 return;
943 }
944
945 for (rn = route_top(table); rn; rn = route_next(rn)) {
946 if (p && !prefix_match(&rn->p, p))
947 continue;
948
949 if (rn->info)
950 print_rnh(rn, vty);
951 }
952 }
953
954 /**
955 * free_state - free up the re structure associated with the rnh.
956 */
957 static void free_state(vrf_id_t vrf_id, struct route_entry *re,
958 struct route_node *rn)
959 {
960 if (!re)
961 return;
962
963 /* free RE and nexthops */
964 zebra_nhg_free(re->nhe);
965 XFREE(MTYPE_RE, re);
966 }
967
968 static void copy_state(struct rnh *rnh, const struct route_entry *re,
969 struct route_node *rn)
970 {
971 struct route_entry *state;
972
973 if (rnh->state) {
974 free_state(rnh->vrf_id, rnh->state, rn);
975 rnh->state = NULL;
976 }
977
978 if (!re)
979 return;
980
981 state = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
982 state->type = re->type;
983 state->distance = re->distance;
984 state->metric = re->metric;
985 state->vrf_id = re->vrf_id;
986 state->status = re->status;
987
988 state->nhe = zebra_nhe_copy(re->nhe, 0);
989
990 /* Copy the 'fib' nexthops also, if present - we want to capture
991 * the true installed nexthops.
992 */
993 if (re->fib_ng.nexthop)
994 nexthop_group_copy(&state->fib_ng, &re->fib_ng);
995 if (re->fib_backup_ng.nexthop)
996 nexthop_group_copy(&state->fib_backup_ng, &re->fib_backup_ng);
997
998 rnh->state = state;
999 }
1000
1001 /*
1002 * Locate the next primary nexthop, used when comparing current rnh info with
1003 * an updated route.
1004 */
1005 static struct nexthop *next_valid_primary_nh(struct route_entry *re,
1006 struct nexthop *nh)
1007 {
1008 struct nexthop_group *nhg;
1009 struct nexthop *bnh;
1010 int i, idx;
1011 bool default_path = true;
1012
1013 /* Fib backup ng present: some backups are installed,
1014 * and we're configured for special handling if there are backups.
1015 */
1016 if (rnh_hide_backups && (re->fib_backup_ng.nexthop != NULL))
1017 default_path = false;
1018
1019 /* Default path: no special handling, just using the 'installed'
1020 * primary nexthops and the common validity test.
1021 */
1022 if (default_path) {
1023 if (nh == NULL) {
1024 nhg = rib_get_fib_nhg(re);
1025 nh = nhg->nexthop;
1026 } else
1027 nh = nexthop_next(nh);
1028
1029 while (nh) {
1030 if (rnh_nexthop_valid(re, nh))
1031 break;
1032 else
1033 nh = nexthop_next(nh);
1034 }
1035
1036 return nh;
1037 }
1038
1039 /* Hide backup activation/switchover events.
1040 *
1041 * If we've had a switchover, an inactive primary won't be in
1042 * the fib list at all - the 'fib' list could even be empty
1043 * in the case where no primary is installed. But we want to consider
1044 * those primaries "valid" if they have an activated backup nh.
1045 *
1046 * The logic is something like:
1047 * if (!fib_nhg)
1048 * // then all primaries are installed
1049 * else
1050 * for each primary in re nhg
1051 * if in fib_nhg
1052 * primary is installed
1053 * else if a backup is installed
1054 * primary counts as installed
1055 * else
1056 * primary !installed
1057 */
1058
1059 /* Start with the first primary */
1060 if (nh == NULL)
1061 nh = re->nhe->nhg.nexthop;
1062 else
1063 nh = nexthop_next(nh);
1064
1065 while (nh) {
1066
1067 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1068 zlog_debug("%s: checking primary NH %pNHv",
1069 __func__, nh);
1070
1071 /* If this nexthop is in the fib list, it's installed */
1072 nhg = rib_get_fib_nhg(re);
1073
1074 for (bnh = nhg->nexthop; bnh; bnh = nexthop_next(bnh)) {
1075 if (nexthop_cmp(nh, bnh) == 0)
1076 break;
1077 }
1078
1079 if (bnh != NULL) {
1080 /* Found the match */
1081 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1082 zlog_debug("%s: NH in fib list", __func__);
1083 break;
1084 }
1085
1086 /* Else if this nexthop's backup is installed, it counts */
1087 nhg = rib_get_fib_backup_nhg(re);
1088 bnh = nhg->nexthop;
1089
1090 for (idx = 0; bnh != NULL; idx++) {
1091 /* If we find an active backup nh for this
1092 * primary, we're done;
1093 */
1094 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1095 zlog_debug("%s: checking backup %pNHv [%d]",
1096 __func__, bnh, idx);
1097
1098 if (!CHECK_FLAG(bnh->flags, NEXTHOP_FLAG_ACTIVE))
1099 continue;
1100
1101 for (i = 0; i < nh->backup_num; i++) {
1102 /* Found a matching activated backup nh */
1103 if (nh->backup_idx[i] == idx) {
1104 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1105 zlog_debug("%s: backup %d activated",
1106 __func__, i);
1107
1108 goto done;
1109 }
1110 }
1111
1112 /* Note that we're not recursing here if the
1113 * backups are recursive: the primary's index is
1114 * only valid in the top-level backup list.
1115 */
1116 bnh = bnh->next;
1117 }
1118
1119 /* Try the next primary nexthop */
1120 nh = nexthop_next(nh);
1121 }
1122
1123 done:
1124
1125 return nh;
1126 }
1127
1128 /*
1129 * Compare two route_entries' nexthops. Account for backup nexthops
1130 * and for the 'fib' nexthop lists, if present.
1131 */
1132 static bool compare_valid_nexthops(struct route_entry *r1,
1133 struct route_entry *r2)
1134 {
1135 bool matched_p = false;
1136 struct nexthop_group *nhg1, *nhg2;
1137 struct nexthop *nh1, *nh2;
1138
1139 /* Start with the primary nexthops */
1140
1141 nh1 = next_valid_primary_nh(r1, NULL);
1142 nh2 = next_valid_primary_nh(r2, NULL);
1143
1144 while (1) {
1145 /* Find any differences in the nexthop lists */
1146
1147 if (nh1 && nh2) {
1148 /* Any difference is a no-match */
1149 if (nexthop_cmp(nh1, nh2) != 0) {
1150 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1151 zlog_debug("%s: nh1: %pNHv, nh2: %pNHv differ",
1152 __func__, nh1, nh2);
1153 goto done;
1154 }
1155
1156 } else if (nh1 || nh2) {
1157 /* One list has more valid nexthops than the other */
1158 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1159 zlog_debug("%s: nh1 %s, nh2 %s", __func__,
1160 nh1 ? "non-NULL" : "NULL",
1161 nh2 ? "non-NULL" : "NULL");
1162 goto done;
1163 } else
1164 break; /* Done with both lists */
1165
1166 nh1 = next_valid_primary_nh(r1, nh1);
1167 nh2 = next_valid_primary_nh(r2, nh2);
1168 }
1169
1170 /* If configured, don't compare installed backup state - we've
1171 * accounted for that with the primaries above.
1172 *
1173 * But we do want to compare the routes' backup info,
1174 * in case the owning route has changed the backups -
1175 * that change we do want to report.
1176 */
1177 if (rnh_hide_backups) {
1178 uint32_t hash1 = 0, hash2 = 0;
1179
1180 if (r1->nhe->backup_info)
1181 hash1 = nexthop_group_hash(
1182 &r1->nhe->backup_info->nhe->nhg);
1183
1184 if (r2->nhe->backup_info)
1185 hash2 = nexthop_group_hash(
1186 &r2->nhe->backup_info->nhe->nhg);
1187
1188 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1189 zlog_debug("%s: backup hash1 %#x, hash2 %#x",
1190 __func__, hash1, hash2);
1191
1192 if (hash1 != hash2)
1193 goto done;
1194 else
1195 goto finished;
1196 }
1197
1198 /* The test for the backups is slightly different: the only installed
1199 * backups will be in the 'fib' list.
1200 */
1201 nhg1 = rib_get_fib_backup_nhg(r1);
1202 nhg2 = rib_get_fib_backup_nhg(r2);
1203
1204 nh1 = nhg1->nexthop;
1205 nh2 = nhg2->nexthop;
1206
1207 while (1) {
1208 /* Find each backup list's next valid nexthop */
1209 while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
1210 nh1 = nexthop_next(nh1);
1211
1212 while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
1213 nh2 = nexthop_next(nh2);
1214
1215 if (nh1 && nh2) {
1216 /* Any difference is a no-match */
1217 if (nexthop_cmp(nh1, nh2) != 0) {
1218 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1219 zlog_debug("%s: backup nh1: %pNHv, nh2: %pNHv differ",
1220 __func__, nh1, nh2);
1221 goto done;
1222 }
1223
1224 nh1 = nexthop_next(nh1);
1225 nh2 = nexthop_next(nh2);
1226 } else if (nh1 || nh2) {
1227 /* One list has more valid nexthops than the other */
1228 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1229 zlog_debug("%s: backup nh1 %s, nh2 %s",
1230 __func__,
1231 nh1 ? "non-NULL" : "NULL",
1232 nh2 ? "non-NULL" : "NULL");
1233 goto done;
1234 } else
1235 break; /* Done with both lists */
1236 }
1237
1238 finished:
1239
1240 /* Well, it's a match */
1241 matched_p = true;
1242
1243 done:
1244
1245 if (IS_ZEBRA_DEBUG_NHT_DETAILED)
1246 zlog_debug("%s: %smatched",
1247 __func__, (matched_p ? "" : "NOT "));
1248
1249 return matched_p;
1250 }
1251
1252 /* Returns 'false' if no difference. */
1253 static bool compare_state(struct route_entry *r1,
1254 struct route_entry *r2)
1255 {
1256 if (!r1 && !r2)
1257 return false;
1258
1259 if ((!r1 && r2) || (r1 && !r2))
1260 return true;
1261
1262 if (r1->distance != r2->distance)
1263 return true;
1264
1265 if (r1->metric != r2->metric)
1266 return true;
1267
1268 if (!compare_valid_nexthops(r1, r2))
1269 return true;
1270
1271 return false;
1272 }
1273
1274 int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
1275 enum rnh_type type, vrf_id_t vrf_id,
1276 uint32_t srte_color)
1277 {
1278 struct stream *s = NULL;
1279 struct route_entry *re;
1280 unsigned long nump;
1281 uint8_t num;
1282 struct nexthop *nh;
1283 struct route_node *rn;
1284 int ret;
1285 uint32_t message = 0;
1286 int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE
1287 : ZEBRA_NEXTHOP_UPDATE;
1288
1289 rn = rnh->node;
1290 re = rnh->state;
1291
1292 /* Get output stream. */
1293 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1294
1295 zclient_create_header(s, cmd, vrf_id);
1296
1297 /* Message flags. */
1298 if (srte_color)
1299 SET_FLAG(message, ZAPI_MESSAGE_SRTE);
1300 stream_putl(s, message);
1301
1302 stream_putw(s, rn->p.family);
1303 switch (rn->p.family) {
1304 case AF_INET:
1305 stream_putc(s, rn->p.prefixlen);
1306 stream_put_in_addr(s, &rn->p.u.prefix4);
1307 break;
1308 case AF_INET6:
1309 stream_putc(s, rn->p.prefixlen);
1310 stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
1311 break;
1312 default:
1313 flog_err(EC_ZEBRA_RNH_UNKNOWN_FAMILY,
1314 "%s: Unknown family (%d) notification attempted",
1315 __func__, rn->p.family);
1316 goto failure;
1317 }
1318 if (srte_color)
1319 stream_putl(s, srte_color);
1320
1321 if (re) {
1322 struct zapi_nexthop znh;
1323 struct nexthop_group *nhg;
1324
1325 stream_putc(s, re->type);
1326 stream_putw(s, re->instance);
1327 stream_putc(s, re->distance);
1328 stream_putl(s, re->metric);
1329 num = 0;
1330 nump = stream_get_endp(s);
1331 stream_putc(s, 0);
1332
1333 nhg = rib_get_fib_nhg(re);
1334 for (ALL_NEXTHOPS_PTR(nhg, nh))
1335 if (rnh_nexthop_valid(re, nh)) {
1336 zapi_nexthop_from_nexthop(&znh, nh);
1337 ret = zapi_nexthop_encode(s, &znh, 0, message);
1338 if (ret < 0)
1339 goto failure;
1340
1341 num++;
1342 }
1343
1344 nhg = rib_get_fib_backup_nhg(re);
1345 if (nhg) {
1346 for (ALL_NEXTHOPS_PTR(nhg, nh))
1347 if (rnh_nexthop_valid(re, nh)) {
1348 zapi_nexthop_from_nexthop(&znh, nh);
1349 ret = zapi_nexthop_encode(
1350 s, &znh, 0 /* flags */,
1351 0 /* message */);
1352 if (ret < 0)
1353 goto failure;
1354
1355 num++;
1356 }
1357 }
1358
1359 stream_putc_at(s, nump, num);
1360 } else {
1361 stream_putc(s, 0); // type
1362 stream_putw(s, 0); // instance
1363 stream_putc(s, 0); // distance
1364 stream_putl(s, 0); // metric
1365 stream_putc(s, 0); // nexthops
1366 }
1367 stream_putw_at(s, 0, stream_get_endp(s));
1368
1369 client->nh_last_upd_time = monotime(NULL);
1370 return zserv_send_message(client, s);
1371
1372 failure:
1373
1374 stream_free(s);
1375 return -1;
1376 }
1377
1378 static void print_nh(struct nexthop *nexthop, struct vty *vty)
1379 {
1380 char buf[BUFSIZ];
1381 struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
1382
1383 switch (nexthop->type) {
1384 case NEXTHOP_TYPE_IPV4:
1385 case NEXTHOP_TYPE_IPV4_IFINDEX:
1386 vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
1387 if (nexthop->ifindex)
1388 vty_out(vty, ", %s",
1389 ifindex2ifname_per_ns(zns, nexthop->ifindex));
1390 break;
1391 case NEXTHOP_TYPE_IPV6:
1392 case NEXTHOP_TYPE_IPV6_IFINDEX:
1393 vty_out(vty, " %s",
1394 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1395 if (nexthop->ifindex)
1396 vty_out(vty, ", via %s",
1397 ifindex2ifname_per_ns(zns, nexthop->ifindex));
1398 break;
1399 case NEXTHOP_TYPE_IFINDEX:
1400 vty_out(vty, " is directly connected, %s",
1401 ifindex2ifname_per_ns(zns, nexthop->ifindex));
1402 break;
1403 case NEXTHOP_TYPE_BLACKHOLE:
1404 vty_out(vty, " is directly connected, Null0");
1405 break;
1406 default:
1407 break;
1408 }
1409 vty_out(vty, "\n");
1410 }
1411
1412 static void print_rnh(struct route_node *rn, struct vty *vty)
1413 {
1414 struct rnh *rnh;
1415 struct nexthop *nexthop;
1416 struct listnode *node;
1417 struct zserv *client;
1418 char buf[BUFSIZ];
1419
1420 rnh = rn->info;
1421 vty_out(vty, "%s%s\n",
1422 inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
1423 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)"
1424 : "");
1425 if (rnh->state) {
1426 vty_out(vty, " resolved via %s\n",
1427 zebra_route_string(rnh->state->type));
1428 for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
1429 nexthop = nexthop->next)
1430 print_nh(nexthop, vty);
1431 } else
1432 vty_out(vty, " unresolved%s\n",
1433 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
1434 ? "(Connected)"
1435 : "");
1436
1437 vty_out(vty, " Client list:");
1438 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
1439 vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
1440 client->sock,
1441 rnh->filtered[client->proto] ? "(filtered)" : "");
1442 if (!list_isempty(rnh->zebra_pseudowire_list))
1443 vty_out(vty, " zebra[pseudowires]");
1444 vty_out(vty, "\n");
1445 }
1446
1447 static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi,
1448 struct zserv *client, enum rnh_type type)
1449 {
1450 struct route_table *ntable;
1451 struct route_node *nrn;
1452 struct rnh *rnh;
1453
1454 if (IS_ZEBRA_DEBUG_NHT) {
1455 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
1456
1457 zlog_debug(
1458 "%s(%u): Client %s RNH cleanup for family %s type %s",
1459 VRF_LOGNAME(vrf), vrf_id,
1460 zebra_route_string(client->proto), afi2str(afi),
1461 rnh_type2str(type));
1462 }
1463
1464 ntable = get_rnh_table(vrf_id, afi, type);
1465 if (!ntable) {
1466 zlog_debug("cleanup_rnh_client: rnh table not found");
1467 return -1;
1468 }
1469
1470 for (nrn = route_top(ntable); nrn; nrn = route_next(nrn)) {
1471 if (!nrn->info)
1472 continue;
1473
1474 rnh = nrn->info;
1475 zebra_remove_rnh_client(rnh, client, type);
1476 }
1477 return 1;
1478 }
1479
1480 /* Cleanup registered nexthops (across VRFs) upon client disconnect. */
1481 static int zebra_client_cleanup_rnh(struct zserv *client)
1482 {
1483 struct vrf *vrf;
1484 struct zebra_vrf *zvrf;
1485
1486 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
1487 zvrf = vrf->info;
1488 if (zvrf) {
1489 zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client,
1490 RNH_NEXTHOP_TYPE);
1491 zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client,
1492 RNH_NEXTHOP_TYPE);
1493 zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client,
1494 RNH_IMPORT_CHECK_TYPE);
1495 zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client,
1496 RNH_IMPORT_CHECK_TYPE);
1497 }
1498 }
1499
1500 return 0;
1501 }
1502
1503 int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family)
1504 {
1505 if (((family == AF_INET) && zvrf->zebra_rnh_ip_default_route)
1506 || ((family == AF_INET6) && zvrf->zebra_rnh_ipv6_default_route))
1507 return 1;
1508 else
1509 return 0;
1510 }
1511
1512 /*
1513 * UI control to avoid notifications if backup nexthop status changes
1514 */
1515 void rnh_set_hide_backups(bool hide_p)
1516 {
1517 rnh_hide_backups = hide_p;
1518 }
1519
1520 bool rnh_get_hide_backups(void)
1521 {
1522 return rnh_hide_backups;
1523 }