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