]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_rnh.c
zebra: reorganize zserv, batch i/o
[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
DS
38
39#include "zebra/rib.h"
40#include "zebra/rt.h"
41#include "zebra/zserv.h"
fe18ee2d 42#include "zebra/zebra_ns.h"
7c551956 43#include "zebra/zebra_vrf.h"
fb018d25
DS
44#include "zebra/redistribute.h"
45#include "zebra/debug.h"
46#include "zebra/zebra_rnh.h"
8902474b 47#include "zebra/zebra_routemap.h"
a815b788 48#include "zebra/interface.h"
4a1ab8e4 49#include "zebra/zebra_memory.h"
fb018d25 50
d62a17ae 51static void free_state(vrf_id_t vrf_id, struct route_entry *re,
52 struct route_node *rn);
f0f77c9a 53static void copy_state(struct rnh *rnh, struct route_entry *re,
078430f6 54 struct route_node *rn);
d62a17ae 55#define lookup_rnh_table(v, f) \
56 ({ \
57 struct zebra_vrf *zvrf; \
58 struct route_table *t = NULL; \
59 zvrf = zebra_vrf_lookup_by_id(v); \
60 if (zvrf) \
61 t = zvrf->rnh_table[family2afi(f)]; \
62 t; \
63 })
b72ede27 64
f0f77c9a 65static int compare_state(struct route_entry *r1, struct route_entry *r2);
7076bb2f 66static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
d62a17ae 67 vrf_id_t vrf_id);
fb018d25
DS
68static void print_rnh(struct route_node *rn, struct vty *vty);
69
a50b580a
DS
70int zebra_rnh_ip_default_route = 0;
71int zebra_rnh_ipv6_default_route = 0;
72
b72ede27 73static inline struct route_table *get_rnh_table(vrf_id_t vrfid, int family,
078430f6
DS
74 rnh_type_t type)
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:
83 t = zvrf->rnh_table[family2afi(family)];
84 break;
85 case RNH_IMPORT_CHECK_TYPE:
86 t = zvrf->import_check_table[family2afi(family)];
87 break;
88 }
89
90 return t;
078430f6
DS
91}
92
d62a17ae 93char *rnh_str(struct rnh *rnh, char *buf, int size)
fb018d25 94{
d62a17ae 95 prefix2str(&(rnh->node->p), buf, size);
96 return buf;
fb018d25
DS
97}
98
d62a17ae 99struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
fb018d25 100{
d62a17ae 101 struct route_table *table;
102 struct route_node *rn;
103 struct rnh *rnh = NULL;
104 char buf[PREFIX2STR_BUFFER];
105
106 if (IS_ZEBRA_DEBUG_NHT) {
107 prefix2str(p, buf, sizeof(buf));
108 zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type);
109 }
110 table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
111 if (!table) {
112 prefix2str(p, buf, sizeof(buf));
113 zlog_warn("%u: Add RNH %s type %d - table not found", vrfid,
114 buf, type);
115 return NULL;
116 }
117
118 /* Make it sure prefixlen is applied to the prefix. */
119 apply_mask(p);
120
121 /* Lookup (or add) route node.*/
122 rn = route_node_get(table, p);
123
124 if (!rn->info) {
125 rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
126 rnh->client_list = list_new();
127 rnh->vrf_id = vrfid;
128 rnh->zebra_static_route_list = list_new();
731a75fe 129 rnh->zebra_pseudowire_list = list_new();
d62a17ae 130 route_lock_node(rn);
131 rn->info = rnh;
132 rnh->node = rn;
133 }
134
135 route_unlock_node(rn);
136 return (rn->info);
fb018d25
DS
137}
138
d62a17ae 139struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
fb018d25 140{
d62a17ae 141 struct route_table *table;
142 struct route_node *rn;
fb018d25 143
d62a17ae 144 table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
145 if (!table)
146 return NULL;
fb018d25 147
d62a17ae 148 /* Make it sure prefixlen is applied to the prefix. */
149 apply_mask(p);
fb018d25 150
d62a17ae 151 /* Lookup route node.*/
152 rn = route_node_lookup(table, p);
153 if (!rn)
154 return NULL;
fb018d25 155
d62a17ae 156 route_unlock_node(rn);
157 return (rn->info);
fb018d25
DS
158}
159
d62a17ae 160void zebra_free_rnh(struct rnh *rnh)
5a8dfcd8 161{
d62a17ae 162 rnh->flags |= ZEBRA_NHT_DELETED;
acdf5e25
DS
163 list_delete_and_null(&rnh->client_list);
164 list_delete_and_null(&rnh->zebra_static_route_list);
165 list_delete_and_null(&rnh->zebra_pseudowire_list);
d62a17ae 166 free_state(rnh->vrf_id, rnh->state, rnh->node);
167 XFREE(MTYPE_RNH, rnh);
5a8dfcd8
RW
168}
169
d62a17ae 170void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
fb018d25 171{
d62a17ae 172 struct route_node *rn;
fb018d25 173
d62a17ae 174 if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED) || !(rn = rnh->node))
175 return;
fb018d25 176
d62a17ae 177 if (IS_ZEBRA_DEBUG_NHT) {
178 char buf[PREFIX2STR_BUFFER];
179 zlog_debug("%u: Del RNH %s type %d", rnh->vrf_id,
180 rnh_str(rnh, buf, sizeof(buf)), type);
181 }
fb018d25 182
d62a17ae 183 zebra_free_rnh(rnh);
184 rn->info = NULL;
185 route_unlock_node(rn);
fb018d25
DS
186}
187
d62a17ae 188void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
189 rnh_type_t type, vrf_id_t vrf_id)
fb018d25 190{
d62a17ae 191 if (IS_ZEBRA_DEBUG_NHT) {
192 char buf[PREFIX2STR_BUFFER];
193 zlog_debug("%u: Client %s registers for RNH %s type %d", vrf_id,
194 zebra_route_string(client->proto),
195 rnh_str(rnh, buf, sizeof(buf)), type);
196 }
197 if (!listnode_lookup(rnh->client_list, client)) {
198 listnode_add(rnh->client_list, client);
199 send_client(rnh, client, type,
200 vrf_id); // Pending: check if its needed
201 }
fb018d25
DS
202}
203
d62a17ae 204void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
205 rnh_type_t type)
fb018d25 206{
d62a17ae 207 if (IS_ZEBRA_DEBUG_NHT) {
208 char buf[PREFIX2STR_BUFFER];
209 zlog_debug("Client %s unregisters for RNH %s type %d",
210 zebra_route_string(client->proto),
211 rnh_str(rnh, buf, sizeof(buf)), type);
212 }
213 listnode_delete(rnh->client_list, client);
214 if (list_isempty(rnh->client_list)
731a75fe
RW
215 && list_isempty(rnh->zebra_static_route_list)
216 && list_isempty(rnh->zebra_pseudowire_list))
d62a17ae 217 zebra_delete_rnh(rnh, type);
6e26278c
DS
218}
219
d62a17ae 220void zebra_register_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
221 struct route_node *static_rn)
6e26278c 222{
d62a17ae 223 struct rnh *rnh;
6e26278c 224
d62a17ae 225 rnh = zebra_add_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE);
226 if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn)) {
227 listnode_add(rnh->zebra_static_route_list, static_rn);
228 }
6e26278c
DS
229}
230
d62a17ae 231void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
232 struct route_node *static_rn)
6e26278c 233{
d62a17ae 234 struct rnh *rnh;
6e26278c 235
d62a17ae 236 rnh = zebra_lookup_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE);
237 if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED))
238 return;
6e26278c 239
d62a17ae 240 listnode_delete(rnh->zebra_static_route_list, static_rn);
6e26278c 241
d62a17ae 242 if (list_isempty(rnh->client_list)
731a75fe
RW
243 && list_isempty(rnh->zebra_static_route_list)
244 && list_isempty(rnh->zebra_pseudowire_list))
d62a17ae 245 zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
fb018d25
DS
246}
247
d62a17ae 248void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id,
249 struct nexthop *nexthop,
250 struct route_node *rn)
a399694f 251{
d62a17ae 252 struct nexthop *nh;
253 struct prefix nh_p;
254
255 for (nh = nexthop; nh; nh = nh->next) {
256 switch (nh->type) {
257 case NEXTHOP_TYPE_IPV4:
258 case NEXTHOP_TYPE_IPV4_IFINDEX:
259 nh_p.family = AF_INET;
260 nh_p.prefixlen = IPV4_MAX_BITLEN;
261 nh_p.u.prefix4 = nh->gate.ipv4;
262 break;
263 case NEXTHOP_TYPE_IPV6:
264 case NEXTHOP_TYPE_IPV6_IFINDEX:
265 nh_p.family = AF_INET6;
266 nh_p.prefixlen = IPV6_MAX_BITLEN;
267 nh_p.u.prefix6 = nh->gate.ipv6;
268 break;
269 /*
270 * Not sure what really to do here, we are not
271 * supposed to have either of these for NHT
272 * and the code has no way to know what prefix
273 * to use. So I'm going to just continue
274 * for the moment, which is preferable to
275 * what is currently happening which is a
276 * CRASH and BURN.
277 * Some simple testing shows that we
278 * are not leaving slag around for these
279 * skipped static routes. Since
280 * they don't appear to be installed
281 */
282 case NEXTHOP_TYPE_IFINDEX:
283 case NEXTHOP_TYPE_BLACKHOLE:
284 continue;
285 break;
286 }
287 zebra_deregister_rnh_static_nh(vrf_id, &nh_p, rn);
288 }
a399694f
DS
289}
290
731a75fe
RW
291/* XXX move this utility function elsewhere? */
292static void addr2hostprefix(int af, const union g_addr *addr,
293 struct prefix *prefix)
294{
295 switch (af) {
296 case AF_INET:
297 prefix->family = AF_INET;
298 prefix->prefixlen = IPV4_MAX_BITLEN;
299 prefix->u.prefix4 = addr->ipv4;
300 break;
301 case AF_INET6:
302 prefix->family = AF_INET6;
303 prefix->prefixlen = IPV6_MAX_BITLEN;
304 prefix->u.prefix6 = addr->ipv6;
305 break;
306 default:
c31a793b 307 memset(prefix, 0, sizeof(*prefix));
731a75fe
RW
308 zlog_warn("%s: unknown address family %d", __func__, af);
309 break;
310 }
311}
312
313void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
314{
315 struct prefix nh;
316 struct rnh *rnh;
317
318 addr2hostprefix(pw->af, &pw->nexthop, &nh);
319 rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
320 if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
321 listnode_add(rnh->zebra_pseudowire_list, pw);
322 pw->rnh = rnh;
323 zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh);
324 }
325}
326
327void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
328{
329 struct rnh *rnh;
330
331 rnh = pw->rnh;
332 if (!rnh)
333 return;
334
335 listnode_delete(rnh->zebra_pseudowire_list, pw);
336 pw->rnh = NULL;
337
338 if (list_isempty(rnh->client_list)
339 && list_isempty(rnh->zebra_static_route_list)
340 && list_isempty(rnh->zebra_pseudowire_list))
341 zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
342}
343
d50b5bdd 344/* Apply the NHT route-map for a client to the route (and nexthops)
345 * resolving a NH.
346 */
d62a17ae 347static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
348 struct route_entry *re, int proto)
6e26278c 349{
d62a17ae 350 int at_least_one = 0;
351 int rmap_family; /* Route map has diff AF family enum */
352 struct nexthop *nexthop;
353 int ret;
354
355 rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6;
356
357 if (prn && re) {
7ee30f28
DS
358 for (nexthop = re->ng.nexthop; nexthop;
359 nexthop = nexthop->next) {
d62a17ae 360 ret = zebra_nht_route_map_check(rmap_family, proto,
361 &prn->p, re, nexthop);
362 if (ret != RMAP_DENYMATCH) {
363 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
364 at_least_one++; /* at least one valid NH */
365 } else {
366 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
367 }
368 }
6e26278c 369 }
d62a17ae 370 return (at_least_one);
6e26278c
DS
371}
372
d50b5bdd 373/*
fd7fd9e5
DS
374 * Determine appropriate route (RE entry) resolving a tracked BGP route
375 * for BGP route for import.
d50b5bdd 376 */
996c9314
LB
377static struct route_entry *
378zebra_rnh_resolve_import_entry(vrf_id_t vrfid, int family,
379 struct route_node *nrn, struct rnh *rnh,
380 struct route_node **prn)
fb018d25 381{
d62a17ae 382 struct route_table *route_table;
383 struct route_node *rn;
384 struct route_entry *re;
385
386 *prn = NULL;
387
388 route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
389 if (!route_table) // unexpected
390 return NULL;
391
392 rn = route_node_match(route_table, &nrn->p);
393 if (!rn)
394 return NULL;
395
fd7fd9e5
DS
396 /* Unlock route node - we don't need to lock when walking the tree. */
397 route_unlock_node(rn);
398
996c9314
LB
399 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)
400 && !prefix_same(&nrn->p, &rn->p))
fd7fd9e5 401 return NULL;
d62a17ae 402
fd7fd9e5 403 /* Identify appropriate route entry. */
996c9314
LB
404 RNODE_FOREACH_RE (rn, re) {
405 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
406 && CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
407 && (re->type != ZEBRA_ROUTE_BGP))
fd7fd9e5 408 break;
d62a17ae 409 }
410
d62a17ae 411 if (re)
412 *prn = rn;
413 return re;
d50b5bdd 414}
415
416/*
417 * See if a tracked route entry for import (by BGP) has undergone any
418 * change, and if so, notify the client.
419 */
d62a17ae 420static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family,
421 int force, struct route_node *nrn,
422 struct rnh *rnh,
423 struct route_entry *re)
d50b5bdd 424{
d62a17ae 425 int state_changed = 0;
426 struct zserv *client;
427 char bufn[INET6_ADDRSTRLEN];
428 struct listnode *node;
429 struct nexthop *nexthop;
430
431 if (re && (rnh->state == NULL)) {
7ee30f28 432 for (ALL_NEXTHOPS(re->ng, nexthop))
d62a17ae 433 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
434 state_changed = 1;
435 break;
436 }
437 } else if (!re && (rnh->state != NULL))
438 state_changed = 1;
439
440 if (compare_state(re, rnh->state))
441 copy_state(rnh, re, nrn);
442
443 if (state_changed || force) {
444 if (IS_ZEBRA_DEBUG_NHT) {
445 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
446 zlog_debug("%u:%s: Route import check %s %s\n", vrfid,
447 bufn, rnh->state ? "passed" : "failed",
448 state_changed ? "(state changed)" : "");
449 }
450 /* state changed, notify clients */
451 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
452 send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid);
453 }
454 }
d50b5bdd 455}
fb018d25 456
d50b5bdd 457/*
458 * Notify clients registered for this nexthop about a change.
459 */
d62a17ae 460static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
461 struct route_node *nrn,
462 struct rnh *rnh,
463 struct route_node *prn,
464 struct route_entry *re)
d50b5bdd 465{
d62a17ae 466 struct listnode *node;
467 struct zserv *client;
468 char bufn[INET6_ADDRSTRLEN];
469 char bufp[INET6_ADDRSTRLEN];
470 int num_resolving_nh;
471
472 if (IS_ZEBRA_DEBUG_NHT) {
473 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
474 if (prn && re) {
475 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
476 zlog_debug("%u:%s: NH resolved over route %s", vrfid,
477 bufn, bufp);
478 } else
479 zlog_debug("%u:%s: NH has become unresolved", vrfid,
480 bufn);
481 }
482
483 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
484 if (prn && re) {
485 /* Apply route-map for this client to route resolving
486 * this
487 * nexthop to see if it is filtered or not.
488 */
489 num_resolving_nh = zebra_rnh_apply_nht_rmap(
490 family, prn, re, client->proto);
491 if (num_resolving_nh)
492 rnh->filtered[client->proto] = 0;
493 else
494 rnh->filtered[client->proto] = 1;
495
496 if (IS_ZEBRA_DEBUG_NHT)
497 zlog_debug(
498 "%u:%s: Notifying client %s about NH %s",
499 vrfid, bufn,
500 zebra_route_string(client->proto),
501 num_resolving_nh
502 ? ""
503 : "(filtered by route-map)");
504 } else {
505 rnh->filtered[client->proto] = 0;
506 if (IS_ZEBRA_DEBUG_NHT)
507 zlog_debug(
508 "%u:%s: Notifying client %s about NH (unreachable)",
509 vrfid, bufn,
510 zebra_route_string(client->proto));
511 }
512
513 send_client(rnh, client, RNH_NEXTHOP_TYPE, vrfid);
514 }
d50b5bdd 515}
078430f6 516
d62a17ae 517static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
518 struct route_node *nrn,
519 struct rnh *rnh,
520 struct route_node *prn,
521 struct route_entry *re)
d50b5bdd 522{
d62a17ae 523 struct listnode *node;
524 int num_resolving_nh = 0;
525 struct route_node *static_rn;
526 struct route_entry *sre;
527 struct nexthop *nexthop;
528 char bufn[INET6_ADDRSTRLEN];
529 char bufp[INET6_ADDRSTRLEN];
530 char bufs[INET6_ADDRSTRLEN];
531
532 if (IS_ZEBRA_DEBUG_NHT) {
533 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
534 if (prn)
535 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
536 }
078430f6 537
d62a17ae 538 if (prn && re) {
539 /* Apply route-map for "static" to route resolving this
540 * nexthop to see if it is filtered or not.
541 */
542 num_resolving_nh = zebra_rnh_apply_nht_rmap(family, prn, re,
543 ZEBRA_ROUTE_STATIC);
544 if (num_resolving_nh)
545 rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
546 else
547 rnh->filtered[ZEBRA_ROUTE_STATIC] = 1;
548 } else
549 rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
550
551 /* Evaluate each static route associated with this nexthop. */
552 for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node,
553 static_rn)) {
a2addae8 554 RNODE_FOREACH_RE (static_rn, sre) {
d62a17ae 555 if (sre->type != ZEBRA_ROUTE_STATIC)
556 continue;
557
558 /* Set the filter flag for the correct nexthop - static
559 * route may
560 * be having multiple. We care here only about
561 * registered nexthops.
562 */
7ee30f28 563 for (nexthop = sre->ng.nexthop; nexthop;
d62a17ae 564 nexthop = nexthop->next) {
565 switch (nexthop->type) {
566 case NEXTHOP_TYPE_IPV4:
567 case NEXTHOP_TYPE_IPV4_IFINDEX:
568 if (nexthop->gate.ipv4.s_addr
569 == nrn->p.u.prefix4.s_addr) {
570 if (num_resolving_nh)
571 UNSET_FLAG(
572 nexthop->flags,
573 NEXTHOP_FLAG_FILTERED);
574 else
575 SET_FLAG(
576 nexthop->flags,
577 NEXTHOP_FLAG_FILTERED);
578 }
579 break;
580 case NEXTHOP_TYPE_IPV6:
581 case NEXTHOP_TYPE_IPV6_IFINDEX:
582
583 if (memcmp(&nexthop->gate.ipv6,
584 &nrn->p.u.prefix6, 16)
585 == 0) {
586 if (num_resolving_nh)
587 UNSET_FLAG(
588 nexthop->flags,
589 NEXTHOP_FLAG_FILTERED);
590 else
591 SET_FLAG(
592 nexthop->flags,
593 NEXTHOP_FLAG_FILTERED);
594 }
595 break;
596 default:
597 break;
598 }
599 }
600
601 if (IS_ZEBRA_DEBUG_NHT) {
602 prefix2str(&static_rn->p, bufs,
603 INET6_ADDRSTRLEN);
604 if (prn && re)
605 zlog_debug(
606 "%u:%s: NH change %s, scheduling static route %s",
607 vrfid, bufn,
608 num_resolving_nh
609 ? ""
610 : "(filtered by route-map)",
611 bufs);
612 else
613 zlog_debug(
614 "%u:%s: NH unreachable, scheduling static route %s",
615 vrfid, bufn, bufs);
616 }
617
618 SET_FLAG(sre->status, ROUTE_ENTRY_CHANGED);
619 SET_FLAG(sre->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
620 }
621
622 rib_queue_add(static_rn);
623 }
d50b5bdd 624}
078430f6 625
fd7fd9e5
DS
626/*
627 * Determine appropriate route (route entry) resolving a tracked
628 * nexthop.
629 */
996c9314
LB
630static struct route_entry *
631zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, int family,
632 struct route_node *nrn, struct rnh *rnh,
633 struct route_node **prn)
fd7fd9e5
DS
634{
635 struct route_table *route_table;
636 struct route_node *rn;
637 struct route_entry *re;
638
639 *prn = NULL;
640
641 route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
642 if (!route_table)
643 return NULL;
644
645 rn = route_node_match(route_table, &nrn->p);
646 if (!rn)
647 return NULL;
648
649 /* Unlock route node - we don't need to lock when walking the tree. */
650 route_unlock_node(rn);
651
652 /* While resolving nexthops, we may need to walk up the tree from the
653 * most-specific match. Do similar logic as in zebra_rib.c
654 */
655 while (rn) {
656 /* Do not resolve over default route unless allowed &&
657 * match route to be exact if so specified
658 */
996c9314
LB
659 if (is_default_prefix(&rn->p)
660 && !rnh_resolve_via_default(rn->p.family))
fd7fd9e5
DS
661 return NULL;
662
663 /* Identify appropriate route entry. */
996c9314 664 RNODE_FOREACH_RE (rn, re) {
fd7fd9e5
DS
665 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
666 continue;
667 if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
668 continue;
669
670 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
671 if ((re->type == ZEBRA_ROUTE_CONNECT)
672 || (re->type == ZEBRA_ROUTE_STATIC))
673 break;
674 if (re->type == ZEBRA_ROUTE_NHRP) {
675 struct nexthop *nexthop;
676
7ee30f28 677 for (nexthop = re->ng.nexthop; nexthop;
fd7fd9e5
DS
678 nexthop = nexthop->next)
679 if (nexthop->type
996c9314 680 == NEXTHOP_TYPE_IFINDEX)
fd7fd9e5
DS
681 break;
682 if (nexthop)
683 break;
684 }
685 } else
686 break;
687 }
688
689 /* Route entry found, we're done; else, walk up the tree. */
690 if (re) {
691 *prn = rn;
692 return re;
693 }
694
695 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
696 rn = rn->parent;
697 else
698 return NULL;
699 }
700
701 return NULL;
702}
703
731a75fe
RW
704static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh)
705{
706 struct zebra_pw *pw;
707 struct listnode *node;
708
709 for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw))
710 zebra_pw_update(pw);
711}
712
d50b5bdd 713/*
714 * See if a tracked nexthop entry has undergone any change, and if so,
715 * take appropriate action; this involves notifying any clients and/or
716 * scheduling dependent static routes for processing.
717 */
d62a17ae 718static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
719 struct route_node *nrn,
720 struct rnh *rnh,
721 struct route_node *prn,
722 struct route_entry *re)
d50b5bdd 723{
d62a17ae 724 int state_changed = 0;
725
726 /* If we're resolving over a different route, resolution has changed or
727 * the resolving route has some change (e.g., metric), there is a state
728 * change.
729 */
730 if (!prefix_same(&rnh->resolved_route, &prn->p)) {
731 if (prn)
732 prefix_copy(&rnh->resolved_route, &prn->p);
733 else
734 memset(&rnh->resolved_route, 0, sizeof(struct prefix));
735
736 copy_state(rnh, re, nrn);
737 state_changed = 1;
738 } else if (compare_state(re, rnh->state)) {
739 copy_state(rnh, re, nrn);
740 state_changed = 1;
741 }
742
743 if (state_changed || force) {
744 /* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
745 * rnh->state.
746 */
747 /* Notify registered protocol clients. */
748 zebra_rnh_notify_protocol_clients(vrfid, family, nrn, rnh, prn,
749 rnh->state);
750
751 /* Process static routes attached to this nexthop */
752 zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
753 rnh->state);
731a75fe
RW
754
755 /* Process pseudowires attached to this nexthop */
756 zebra_rnh_process_pseudowires(vrfid, rnh);
d62a17ae 757 }
d50b5bdd 758}
6e26278c 759
d50b5bdd 760/* Evaluate one tracked entry */
d62a17ae 761static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
762 rnh_type_t type, struct route_node *nrn)
d50b5bdd 763{
d62a17ae 764 struct rnh *rnh;
765 struct route_entry *re;
766 struct route_node *prn;
767 char bufn[INET6_ADDRSTRLEN];
768
769 if (IS_ZEBRA_DEBUG_NHT) {
770 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
771 zlog_debug("%u:%s: Evaluate RNH, type %d %s", vrfid, bufn, type,
772 force ? "(force)" : "");
773 }
774
775 rnh = nrn->info;
776
777 /* Identify route entry (RE) resolving this tracked entry. */
fd7fd9e5 778 if (type == RNH_IMPORT_CHECK_TYPE)
996c9314
LB
779 re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, rnh,
780 &prn);
fd7fd9e5
DS
781 else
782 re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
783 &prn);
d62a17ae 784
785 /* If the entry cannot be resolved and that is also the existing state,
786 * there is nothing further to do.
787 */
788 if (!re && rnh->state == NULL && !force)
789 return;
790
791 /* Process based on type of entry. */
792 if (type == RNH_IMPORT_CHECK_TYPE)
793 zebra_rnh_eval_import_check_entry(vrfid, family, force, nrn,
794 rnh, re);
795 else
796 zebra_rnh_eval_nexthop_entry(vrfid, family, force, nrn, rnh,
797 prn, re);
d50b5bdd 798}
799
8ce5e6a3 800/*
f0f77c9a
DS
801 * Clear the ROUTE_ENTRY_NEXTHOPS_CHANGED flag
802 * from the re entries.
8ce5e6a3
DS
803 *
804 * Please note we are doing this *after* we have
805 * notified the world about each nexthop as that
f0f77c9a 806 * we can have a situation where one re entry
8ce5e6a3
DS
807 * covers multiple nexthops we are interested in.
808 */
d62a17ae 809static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
810 rnh_type_t type, struct route_node *nrn)
8ce5e6a3 811{
d62a17ae 812 struct rnh *rnh;
813 struct route_entry *re;
814 struct route_node *prn;
8ce5e6a3 815
d62a17ae 816 rnh = nrn->info;
8ce5e6a3 817
fd7fd9e5
DS
818 /* Identify route entry (RIB) resolving this tracked entry. */
819 if (type == RNH_IMPORT_CHECK_TYPE)
996c9314
LB
820 re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, rnh,
821 &prn);
fd7fd9e5
DS
822 else
823 re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
824 &prn);
8ce5e6a3 825
332ad713 826 if (re) {
d62a17ae 827 UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
332ad713
RW
828 UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
829 }
8ce5e6a3 830}
d50b5bdd 831
832/* Evaluate all tracked entries (nexthops or routes for import into BGP)
833 * of a particular VRF and address-family or a specific prefix.
834 */
d62a17ae 835void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, rnh_type_t type,
836 struct prefix *p)
d50b5bdd 837{
d62a17ae 838 struct route_table *rnh_table;
839 struct route_node *nrn;
840
841 rnh_table = get_rnh_table(vrfid, family, type);
842 if (!rnh_table) // unexpected
843 return;
844
845 if (p) {
846 /* Evaluating a specific entry, make sure it exists. */
847 nrn = route_node_lookup(rnh_table, p);
848 if (nrn && nrn->info)
849 zebra_rnh_evaluate_entry(vrfid, family, force, type,
850 nrn);
851
852 if (nrn)
853 route_unlock_node(nrn);
854 } else {
855 /* Evaluate entire table. */
856 nrn = route_top(rnh_table);
857 while (nrn) {
858 if (nrn->info)
859 zebra_rnh_evaluate_entry(vrfid, family, force,
860 type, nrn);
861 nrn = route_next(nrn); /* this will also unlock nrn */
862 }
863 nrn = route_top(rnh_table);
864 while (nrn) {
865 if (nrn->info)
866 zebra_rnh_clear_nhc_flag(vrfid, family, type,
867 nrn);
868 nrn = route_next(nrn); /* this will also unlock nrn */
869 }
870 }
fb018d25
DS
871}
872
d62a17ae 873void zebra_print_rnh_table(vrf_id_t vrfid, int af, struct vty *vty,
874 rnh_type_t type)
fb018d25 875{
d62a17ae 876 struct route_table *table;
877 struct route_node *rn;
878
879 table = get_rnh_table(vrfid, af, type);
880 if (!table) {
881 zlog_debug("print_rnhs: rnh table not found\n");
882 return;
883 }
884
885 for (rn = route_top(table); rn; rn = route_next(rn))
886 if (rn->info)
887 print_rnh(rn, vty);
fb018d25
DS
888}
889
d62a17ae 890int zebra_cleanup_rnh_client(vrf_id_t vrf_id, int family, struct zserv *client,
891 rnh_type_t type)
fb018d25 892{
d62a17ae 893 struct route_table *ntable;
894 struct route_node *nrn;
895 struct rnh *rnh;
896
897 if (IS_ZEBRA_DEBUG_NHT)
898 zlog_debug("%u: Client %s RNH cleanup for family %d type %d",
899 vrf_id, zebra_route_string(client->proto), family,
900 type);
901
902 ntable = get_rnh_table(vrf_id, family, type);
903 if (!ntable) {
904 zlog_debug("cleanup_rnh_client: rnh table not found\n");
905 return -1;
906 }
907
908 for (nrn = route_top(ntable); nrn; nrn = route_next(nrn)) {
909 if (!nrn->info)
910 continue;
911
912 rnh = nrn->info;
913 zebra_remove_rnh_client(rnh, client, type);
914 }
915 return 1;
fb018d25
DS
916}
917
918/**
f0f77c9a 919 * free_state - free up the re structure associated with the rnh.
fb018d25 920 */
d62a17ae 921static void free_state(vrf_id_t vrf_id, struct route_entry *re,
922 struct route_node *rn)
fb018d25 923{
fb018d25 924
d62a17ae 925 if (!re)
926 return;
fb018d25 927
d62a17ae 928 /* free RE and nexthops */
7ee30f28
DS
929 zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn);
930 nexthops_free(re->ng.nexthop);
d62a17ae 931 XFREE(MTYPE_RE, re);
fb018d25
DS
932}
933
d62a17ae 934static void copy_state(struct rnh *rnh, struct route_entry *re,
935 struct route_node *rn)
fb018d25 936{
d62a17ae 937 struct route_entry *state;
fb018d25 938
d62a17ae 939 if (rnh->state) {
940 free_state(rnh->vrf_id, rnh->state, rn);
941 rnh->state = NULL;
942 }
fb018d25 943
d62a17ae 944 if (!re)
945 return;
fb018d25 946
d62a17ae 947 state = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
948 state->type = re->type;
7733c6c4 949 state->distance = re->distance;
d62a17ae 950 state->metric = re->metric;
8f43b4d8 951 state->vrf_id = re->vrf_id;
fb018d25 952
7ee30f28 953 route_entry_copy_nexthops(state, re->ng.nexthop);
d62a17ae 954 rnh->state = state;
fb018d25
DS
955}
956
d62a17ae 957static int compare_state(struct route_entry *r1, struct route_entry *r2)
fb018d25 958{
fb018d25 959
d62a17ae 960 if (!r1 && !r2)
961 return 0;
fb018d25 962
d62a17ae 963 if ((!r1 && r2) || (r1 && !r2))
964 return 1;
fb018d25 965
7733c6c4
JB
966 if (r1->distance != r2->distance)
967 return 1;
968
d62a17ae 969 if (r1->metric != r2->metric)
970 return 1;
fb018d25 971
d62a17ae 972 if (r1->nexthop_num != r2->nexthop_num)
973 return 1;
fb018d25 974
332ad713
RW
975 if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)
976 || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED))
d62a17ae 977 return 1;
fb018d25 978
d62a17ae 979 return 0;
fb018d25
DS
980}
981
d62a17ae 982static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
983 vrf_id_t vrf_id)
fb018d25 984{
d62a17ae 985 struct stream *s;
986 struct route_entry *re;
987 unsigned long nump;
988 u_char num;
989 struct nexthop *nexthop;
990 struct route_node *rn;
991 int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE
992 : ZEBRA_NEXTHOP_UPDATE;
993
994 rn = rnh->node;
995 re = rnh->state;
996
997 /* Get output stream. */
1002497a 998 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
d62a17ae 999
7cf15b25 1000 zclient_create_header(s, cmd, vrf_id);
d62a17ae 1001
1002 stream_putw(s, rn->p.family);
1003 switch (rn->p.family) {
1004 case AF_INET:
1005 stream_putc(s, rn->p.prefixlen);
1006 stream_put_in_addr(s, &rn->p.u.prefix4);
fb018d25 1007 break;
d62a17ae 1008 case AF_INET6:
1009 stream_putc(s, rn->p.prefixlen);
1010 stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
fb018d25 1011 break;
d62a17ae 1012 default:
1013 zlog_err("%s: Unknown family (%d) notification attempted\n",
1014 __FUNCTION__, rn->p.family);
fb018d25 1015 break;
d62a17ae 1016 }
1017 if (re) {
05dd5aaf
DS
1018 stream_putc(s, re->type);
1019 stream_putw(s, re->instance);
d62a17ae 1020 stream_putc(s, re->distance);
1021 stream_putl(s, re->metric);
1022 num = 0;
1023 nump = stream_get_endp(s);
1024 stream_putc(s, 0);
7ee30f28 1025 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
d62a17ae 1026 if ((CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
1027 || CHECK_FLAG(nexthop->flags,
1028 NEXTHOP_FLAG_RECURSIVE))
1029 && CHECK_FLAG(nexthop->flags,
1030 NEXTHOP_FLAG_ACTIVE)) {
1031 stream_putc(s, nexthop->type);
1032 switch (nexthop->type) {
1033 case NEXTHOP_TYPE_IPV4:
aab09c10 1034 case NEXTHOP_TYPE_IPV4_IFINDEX:
d62a17ae 1035 stream_put_in_addr(s,
1036 &nexthop->gate.ipv4);
1037 stream_putl(s, nexthop->ifindex);
1038 break;
1039 case NEXTHOP_TYPE_IFINDEX:
1040 stream_putl(s, nexthop->ifindex);
1041 break;
d62a17ae 1042 case NEXTHOP_TYPE_IPV6:
d62a17ae 1043 case NEXTHOP_TYPE_IPV6_IFINDEX:
1044 stream_put(s, &nexthop->gate.ipv6, 16);
1045 stream_putl(s, nexthop->ifindex);
1046 break;
1047 default:
1048 /* do nothing */
1049 break;
1050 }
1051 num++;
1052 }
1053 stream_putc_at(s, nump, num);
1054 } else {
05dd5aaf
DS
1055 stream_putc(s, 0); // type
1056 stream_putw(s, 0); // instance
d62a17ae 1057 stream_putc(s, 0); // distance
1058 stream_putl(s, 0); // metric
1059 stream_putc(s, 0); // nexthops
1060 }
1061 stream_putw_at(s, 0, stream_get_endp(s));
1062
1063 client->nh_last_upd_time = monotime(NULL);
1064 client->last_write_cmd = cmd;
1002497a 1065 return zebra_server_send_message(client, s);
fb018d25
DS
1066}
1067
d62a17ae 1068static void print_nh(struct nexthop *nexthop, struct vty *vty)
fb018d25 1069{
d62a17ae 1070 char buf[BUFSIZ];
1071 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1072
1073 switch (nexthop->type) {
1074 case NEXTHOP_TYPE_IPV4:
1075 case NEXTHOP_TYPE_IPV4_IFINDEX:
1076 vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
1077 if (nexthop->ifindex)
1078 vty_out(vty, ", %s",
1079 ifindex2ifname_per_ns(zns, nexthop->ifindex));
1080 break;
1081 case NEXTHOP_TYPE_IPV6:
1082 case NEXTHOP_TYPE_IPV6_IFINDEX:
1083 vty_out(vty, " %s",
1084 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
1085 if (nexthop->ifindex)
1086 vty_out(vty, ", via %s",
1087 ifindex2ifname_per_ns(zns, nexthop->ifindex));
1088 break;
1089 case NEXTHOP_TYPE_IFINDEX:
1090 vty_out(vty, " is directly connected, %s",
1091 ifindex2ifname_per_ns(zns, nexthop->ifindex));
1092 break;
1093 case NEXTHOP_TYPE_BLACKHOLE:
1094 vty_out(vty, " is directly connected, Null0");
1095 break;
1096 default:
1097 break;
1098 }
1099 vty_out(vty, "\n");
fb018d25
DS
1100}
1101
d62a17ae 1102static void print_rnh(struct route_node *rn, struct vty *vty)
fb018d25 1103{
d62a17ae 1104 struct rnh *rnh;
1105 struct nexthop *nexthop;
1106 struct listnode *node;
1107 struct zserv *client;
1108 char buf[BUFSIZ];
1109
1110 rnh = rn->info;
1111 vty_out(vty, "%s%s\n",
1112 inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
1113 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)"
1114 : "");
1115 if (rnh->state) {
1116 vty_out(vty, " resolved via %s\n",
1117 zebra_route_string(rnh->state->type));
7ee30f28 1118 for (nexthop = rnh->state->ng.nexthop; nexthop;
d62a17ae 1119 nexthop = nexthop->next)
1120 print_nh(nexthop, vty);
1121 } else
1122 vty_out(vty, " unresolved%s\n",
1123 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
1124 ? "(Connected)"
1125 : "");
1126
1127 vty_out(vty, " Client list:");
1128 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
1129 vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
1130 client->sock,
1131 rnh->filtered[client->proto] ? "(filtered)" : "");
1132 if (!list_isempty(rnh->zebra_static_route_list))
1133 vty_out(vty, " zebra%s",
1134 rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
731a75fe
RW
1135 if (!list_isempty(rnh->zebra_pseudowire_list))
1136 vty_out(vty, " zebra[pseudowires]");
d62a17ae 1137 vty_out(vty, "\n");
fb018d25 1138}