]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_rnh.c
*: split & distribute memtypes and stop (re|ab)using lib/ MTYPEs
[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 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "prefix.h"
25#include "table.h"
26#include "memory.h"
27#include "str.h"
28#include "command.h"
29#include "if.h"
30#include "log.h"
31#include "sockunion.h"
32#include "linklist.h"
33#include "thread.h"
34#include "workqueue.h"
35#include "prefix.h"
36#include "routemap.h"
37#include "stream.h"
38#include "nexthop.h"
b72ede27 39#include "vrf.h"
fb018d25
DS
40
41#include "zebra/rib.h"
42#include "zebra/rt.h"
43#include "zebra/zserv.h"
fe18ee2d 44#include "zebra/zebra_ns.h"
7c551956 45#include "zebra/zebra_vrf.h"
fb018d25
DS
46#include "zebra/redistribute.h"
47#include "zebra/debug.h"
48#include "zebra/zebra_rnh.h"
8902474b 49#include "zebra/zebra_routemap.h"
a815b788 50#include "zebra/interface.h"
4a1ab8e4 51#include "zebra/zebra_memory.h"
fb018d25 52
d82ae0de 53static void free_state(vrf_id_t vrf_id, struct rib *rib, struct route_node *rn);
078430f6
DS
54static void copy_state(struct rnh *rnh, struct rib *rib,
55 struct route_node *rn);
b72ede27
FL
56#define lookup_rnh_table(v, f) \
57({ \
58 struct zebra_vrf *zvrf; \
59 struct route_table *t = NULL; \
60 zvrf = zebra_vrf_lookup(v); \
61 if (zvrf) \
62 t = zvrf->rnh_table[family2afi(f)]; \
63 t; \
64})
65
fb018d25 66static int compare_state(struct rib *r1, struct rib *r2);
7076bb2f
FL
67static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
68 vrf_id_t vrf_id);
fb018d25
DS
69static void print_rnh(struct route_node *rn, struct vty *vty);
70
a50b580a
DS
71int zebra_rnh_ip_default_route = 0;
72int zebra_rnh_ipv6_default_route = 0;
73
b72ede27 74static inline struct route_table *get_rnh_table(vrf_id_t vrfid, int family,
078430f6
DS
75 rnh_type_t type)
76{
b72ede27 77 struct zebra_vrf *zvrf;
078430f6
DS
78 struct route_table *t = NULL;
79
b72ede27
FL
80 zvrf = zebra_vrf_lookup(vrfid);
81 if (zvrf)
078430f6
DS
82 switch (type)
83 {
84 case RNH_NEXTHOP_TYPE:
b72ede27 85 t = zvrf->rnh_table[family2afi(family)];
078430f6
DS
86 break;
87 case RNH_IMPORT_CHECK_TYPE:
b72ede27 88 t = zvrf->import_check_table[family2afi(family)];
078430f6
DS
89 break;
90 }
91
92 return t;
93}
94
95char *rnh_str (struct rnh *rnh, char *buf, int size)
fb018d25
DS
96{
97 prefix2str(&(rnh->node->p), buf, size);
98 return buf;
99}
100
101struct rnh *
b72ede27 102zebra_add_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
fb018d25
DS
103{
104 struct route_table *table;
105 struct route_node *rn;
106 struct rnh *rnh = NULL;
67cc8c5e 107 char buf[PREFIX2STR_BUFFER];
fb018d25
DS
108
109 if (IS_ZEBRA_DEBUG_NHT)
110 {
4690c7d7 111 prefix2str(p, buf, sizeof (buf));
67cc8c5e 112 zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type);
fb018d25 113 }
078430f6 114 table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
fb018d25
DS
115 if (!table)
116 {
67cc8c5e 117 prefix2str(p, buf, sizeof (buf));
118 zlog_warn("%u: Add RNH %s type %d - table not found",
119 vrfid, buf, type);
fb018d25
DS
120 return NULL;
121 }
122
123 /* Make it sure prefixlen is applied to the prefix. */
124 apply_mask (p);
125
126 /* Lookup (or add) route node.*/
127 rn = route_node_get (table, p);
128
129 if (!rn->info)
130 {
131 rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
132 rnh->client_list = list_new();
d82ae0de 133 rnh->vrf_id = vrfid;
6e26278c 134 rnh->zebra_static_route_list = list_new();
fb018d25
DS
135 route_lock_node (rn);
136 rn->info = rnh;
137 rnh->node = rn;
138 }
139
140 route_unlock_node (rn);
141 return (rn->info);
142}
143
144struct rnh *
b72ede27 145zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
fb018d25
DS
146{
147 struct route_table *table;
148 struct route_node *rn;
149
078430f6 150 table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
fb018d25
DS
151 if (!table)
152 return NULL;
153
154 /* Make it sure prefixlen is applied to the prefix. */
155 apply_mask (p);
156
157 /* Lookup route node.*/
158 rn = route_node_lookup (table, p);
159 if (!rn)
160 return NULL;
161
162 route_unlock_node (rn);
163 return (rn->info);
164}
165
166void
078430f6 167zebra_delete_rnh (struct rnh *rnh, rnh_type_t type)
fb018d25
DS
168{
169 struct route_node *rn;
170
70c0f184 171 if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED) || !(rn = rnh->node))
fb018d25
DS
172 return;
173
174 if (IS_ZEBRA_DEBUG_NHT)
175 {
4690c7d7 176 char buf[PREFIX2STR_BUFFER];
67cc8c5e 177 zlog_debug("%u: Del RNH %s type %d",
178 rnh->vrf_id, rnh_str(rnh, buf, sizeof (buf)), type);
fb018d25
DS
179 }
180
70c0f184 181 rnh->flags |= ZEBRA_NHT_DELETED;
fb018d25 182 list_free(rnh->client_list);
6e26278c 183 list_free(rnh->zebra_static_route_list);
d82ae0de 184 free_state(rnh->vrf_id, rnh->state, rn);
fb018d25
DS
185 XFREE(MTYPE_RNH, rn->info);
186 rn->info = NULL;
187 route_unlock_node (rn);
188 return;
189}
190
191void
7076bb2f
FL
192zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type,
193 vrf_id_t vrf_id)
fb018d25
DS
194{
195 if (IS_ZEBRA_DEBUG_NHT)
196 {
4690c7d7 197 char buf[PREFIX2STR_BUFFER];
67cc8c5e 198 zlog_debug("%u: Client %s registers for RNH %s type %d",
199 vrf_id, zebra_route_string(client->proto),
200 rnh_str(rnh, buf, sizeof (buf)), type);
fb018d25
DS
201 }
202 if (!listnode_lookup(rnh->client_list, client))
203 {
204 listnode_add(rnh->client_list, client);
7076bb2f 205 send_client(rnh, client, type, vrf_id); // Pending: check if its needed
fb018d25
DS
206 }
207}
208
209void
078430f6 210zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
fb018d25
DS
211{
212 if (IS_ZEBRA_DEBUG_NHT)
213 {
4690c7d7 214 char buf[PREFIX2STR_BUFFER];
67cc8c5e 215 zlog_debug("Client %s unregisters for RNH %s type %d",
fb018d25 216 zebra_route_string(client->proto),
67cc8c5e 217 rnh_str(rnh, buf, sizeof (buf)), type);
fb018d25
DS
218 }
219 listnode_delete(rnh->client_list, client);
6e26278c
DS
220 if (list_isempty(rnh->client_list) &&
221 list_isempty(rnh->zebra_static_route_list))
078430f6 222 zebra_delete_rnh(rnh, type);
6e26278c
DS
223}
224
225void
d82ae0de 226zebra_register_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
227 struct route_node *static_rn)
6e26278c
DS
228{
229 struct rnh *rnh;
230
d82ae0de 231 rnh = zebra_add_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE);
6e26278c
DS
232 if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn))
233 {
234 listnode_add(rnh->zebra_static_route_list, static_rn);
235 }
236}
237
238void
d82ae0de 239zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
240 struct route_node *static_rn)
6e26278c
DS
241{
242 struct rnh *rnh;
243
d82ae0de 244 rnh = zebra_lookup_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE);
70c0f184 245 if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED))
6e26278c
DS
246 return;
247
248 listnode_delete(rnh->zebra_static_route_list, static_rn);
249
250 if (list_isempty(rnh->client_list) &&
251 list_isempty(rnh->zebra_static_route_list))
078430f6 252 zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
fb018d25
DS
253}
254
a399694f 255void
d82ae0de 256zebra_deregister_rnh_static_nexthops (vrf_id_t vrf_id, struct nexthop *nexthop,
257 struct route_node *rn)
a399694f
DS
258{
259 struct nexthop *nh;
260 struct prefix nh_p;
261
262 for (nh = nexthop; nh ; nh = nh->next)
263 {
778cb26f
DS
264 switch (nh->type)
265 {
266 case NEXTHOP_TYPE_IPV4:
267 case NEXTHOP_TYPE_IPV4_IFINDEX:
a399694f
DS
268 nh_p.family = AF_INET;
269 nh_p.prefixlen = IPV4_MAX_BITLEN;
270 nh_p.u.prefix4 = nh->gate.ipv4;
778cb26f
DS
271 break;
272 case NEXTHOP_TYPE_IPV6:
273 case NEXTHOP_TYPE_IPV6_IFINDEX:
a399694f
DS
274 nh_p.family = AF_INET6;
275 nh_p.prefixlen = IPV6_MAX_BITLEN;
276 nh_p.u.prefix6 = nh->gate.ipv6;
778cb26f
DS
277 break;
278 /*
279 * Not sure what really to do here, we are not
280 * supposed to have either of these for NHT
281 * and the code has no way to know what prefix
282 * to use. So I'm going to just continue
283 * for the moment, which is preferable to
284 * what is currently happening which is a
285 * CRASH and BURN.
286 * Some simple testing shows that we
287 * are not leaving slag around for these
288 * skipped static routes. Since
289 * they don't appear to be installed
290 */
291 case NEXTHOP_TYPE_IFINDEX:
292 case NEXTHOP_TYPE_BLACKHOLE:
293 continue;
294 break;
295 }
d82ae0de 296 zebra_deregister_rnh_static_nh(vrf_id, &nh_p, rn);
a399694f
DS
297 }
298}
299
d50b5bdd 300/* Apply the NHT route-map for a client to the route (and nexthops)
301 * resolving a NH.
302 */
6e26278c 303static int
d50b5bdd 304zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
305 struct rib *rib, int proto)
6e26278c
DS
306{
307 int at_least_one = 0;
308 int rmap_family; /* Route map has diff AF family enum */
309 struct nexthop *nexthop;
310 int ret;
311
312 rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6;
313
314 if (prn && rib)
315 {
316 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
317 {
318 ret = zebra_nht_route_map_check(rmap_family, proto, &prn->p, rib,
319 nexthop);
320 if (ret != RMAP_DENYMATCH)
321 {
322 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
323 at_least_one++; /* at least one valid NH */
324 }
325 else
326 {
327 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
328 }
329 }
330 }
331 return (at_least_one);
332}
333
d50b5bdd 334/*
335 * Determine appropriate route (RIB entry) resolving a tracked entry
336 * (nexthop or BGP route for import).
337 */
338static struct rib *
339zebra_rnh_resolve_entry (vrf_id_t vrfid, int family, rnh_type_t type,
340 struct route_node *nrn, struct rnh *rnh,
341 struct route_node **prn)
fb018d25 342{
d50b5bdd 343 struct route_table *route_table;
344 struct route_node *rn;
345 struct rib *rib;
346
347 *prn = NULL;
348
349 route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
350 if (!route_table) // unexpected
351 return NULL;
352
353 rn = route_node_match(route_table, &nrn->p);
354 if (!rn)
355 return NULL;
356
337299a9
DW
357 /* When resolving nexthops, do not resolve via the default route unless
358 * 'ip nht resolve-via-default' is configured.
d50b5bdd 359 */
360 if ((type == RNH_NEXTHOP_TYPE) &&
361 (is_default_prefix (&rn->p) &&
362 !nh_resolve_via_default(rn->p.family)))
363 rib = NULL;
337299a9
DW
364 else if ((type == RNH_IMPORT_CHECK_TYPE) &&
365 CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) &&
366 !prefix_same(&nrn->p, &rn->p))
367 rib = NULL;
d50b5bdd 368 else
369 {
370 /* Identify appropriate route entry. */
371 RNODE_FOREACH_RIB(rn, rib)
372 {
373 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
374 continue;
375 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
376 {
377 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
378 {
379 if (rib->type == ZEBRA_ROUTE_CONNECT)
380 break;
381 }
382 else if ((type == RNH_IMPORT_CHECK_TYPE) &&
383 (rib->type == ZEBRA_ROUTE_BGP))
384 continue;
385 else
386 break;
387 }
388 }
389 }
390
391 /* Need to unlock route node */
392 route_unlock_node(rn);
393 if (rib)
394 *prn = rn;
395 return rib;
396}
397
398/*
399 * See if a tracked route entry for import (by BGP) has undergone any
400 * change, and if so, notify the client.
401 */
402static void
403zebra_rnh_eval_import_check_entry (vrf_id_t vrfid, int family, int force,
404 struct route_node *nrn, struct rnh *rnh,
405 struct rib *rib)
406{
407 int state_changed = 0;
fb018d25 408 struct zserv *client;
d50b5bdd 409 char bufn[INET6_ADDRSTRLEN];
fb018d25 410 struct listnode *node;
078430f6
DS
411 struct nexthop *nexthop, *tnexthop;
412 int recursing;
c5f7794f 413
d50b5bdd 414 if (rib && (rnh->state == NULL))
fb018d25 415 {
d50b5bdd 416 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
417 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
418 {
419 state_changed = 1;
420 break;
421 }
fb018d25 422 }
d50b5bdd 423 else if (!rib && (rnh->state != NULL))
424 state_changed = 1;
fb018d25 425
d50b5bdd 426 if (compare_state(rib, rnh->state))
427 copy_state(rnh, rib, nrn);
428
429 if (state_changed || force)
fb018d25 430 {
d50b5bdd 431 if (IS_ZEBRA_DEBUG_NHT)
432 {
433 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
434 zlog_debug("%u:%s: Route import check %s %s\n",
435 vrfid, bufn, rnh->state ? "passed" : "failed",
436 state_changed ? "(state changed)" : "");
437 }
438 /* state changed, notify clients */
439 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
440 {
441 send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid);
442 }
fb018d25 443 }
d50b5bdd 444}
fb018d25 445
d50b5bdd 446/*
447 * Notify clients registered for this nexthop about a change.
448 */
449static void
450zebra_rnh_notify_protocol_clients (vrf_id_t vrfid, int family,
451 struct route_node *nrn, struct rnh *rnh,
452 struct route_node *prn, struct rib *rib)
453{
454 struct listnode *node;
455 struct zserv *client;
456 char bufn[INET6_ADDRSTRLEN];
457 char bufp[INET6_ADDRSTRLEN];
458 int num_resolving_nh;
078430f6 459
d50b5bdd 460 if (IS_ZEBRA_DEBUG_NHT)
fb018d25 461 {
d50b5bdd 462 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
463 if (prn && rib)
464 {
465 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
466 zlog_debug("%u:%s: NH resolved over route %s", vrfid, bufn, bufp);
467 }
468 else
469 zlog_debug("%u:%s: NH has become unresolved", vrfid, bufn);
470 }
fb018d25 471
d50b5bdd 472 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
473 {
474 if (prn && rib)
475 {
476 /* Apply route-map for this client to route resolving this
477 * nexthop to see if it is filtered or not.
478 */
479 num_resolving_nh = zebra_rnh_apply_nht_rmap(family, prn, rib,
480 client->proto);
481 if (num_resolving_nh)
482 rnh->filtered[client->proto] = 0;
483 else
484 rnh->filtered[client->proto] = 1;
485
486 if (IS_ZEBRA_DEBUG_NHT)
487 zlog_debug("%u:%s: Notifying client %s about NH %s",
488 vrfid, bufn, zebra_route_string(client->proto),
489 num_resolving_nh ? "" : "(filtered by route-map)");
490 }
491 else
492 {
493 rnh->filtered[client->proto] = 0;
494 if (IS_ZEBRA_DEBUG_NHT)
495 zlog_debug("%u:%s: Notifying client %s about NH (unreachable)",
496 vrfid, bufn, zebra_route_string(client->proto));
497 }
6e26278c 498
d50b5bdd 499 send_client(rnh, client, RNH_NEXTHOP_TYPE, vrfid);
500 }
501}
078430f6 502
d50b5bdd 503static void
504zebra_rnh_process_static_routes (vrf_id_t vrfid, int family,
505 struct route_node *nrn, struct rnh *rnh,
506 struct route_node *prn, struct rib *rib)
507{
508 struct listnode *node;
509 int num_resolving_nh = 0;
510 struct route_node *static_rn;
511 struct rib *srib;
512 struct nexthop *nexthop;
513 char bufn[INET6_ADDRSTRLEN];
514 char bufp[INET6_ADDRSTRLEN];
515 char bufs[INET6_ADDRSTRLEN];
078430f6 516
d50b5bdd 517 if (IS_ZEBRA_DEBUG_NHT)
518 {
519 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
520 if (prn)
521 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
522 }
523
524 if (prn && rib)
525 {
526 /* Apply route-map for "static" to route resolving this
527 * nexthop to see if it is filtered or not.
078430f6 528 */
d50b5bdd 529 num_resolving_nh = zebra_rnh_apply_nht_rmap(family, prn, rib,
530 ZEBRA_ROUTE_STATIC);
531 if (num_resolving_nh)
532 rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
fb018d25 533 else
d50b5bdd 534 rnh->filtered[ZEBRA_ROUTE_STATIC] = 1;
535 }
536 else
537 rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
fb018d25 538
d50b5bdd 539 /* Evaluate each static route associated with this nexthop. */
540 for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node,
541 static_rn))
542 {
543 RNODE_FOREACH_RIB(static_rn, srib)
544 {
545 if (srib->type == ZEBRA_ROUTE_STATIC)
546 break; /* currently works for only 1 static route. */
547 }
9f0ea7d4 548
d50b5bdd 549 if (!srib) // unexpected
550 continue;
078430f6 551
d50b5bdd 552 /* Set the filter flag for the correct nexthop - static route may
553 * be having multiple. We care here only about registered nexthops.
554 */
555 for (nexthop = srib->nexthop; nexthop; nexthop = nexthop->next)
556 {
557 switch (nexthop->type)
558 {
559 case NEXTHOP_TYPE_IPV4:
560 case NEXTHOP_TYPE_IPV4_IFINDEX:
561 if (nexthop->gate.ipv4.s_addr == nrn->p.u.prefix4.s_addr)
562 {
563 if (num_resolving_nh)
564 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
565 else
566 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
567 }
568 break;
569 case NEXTHOP_TYPE_IPV6:
570 case NEXTHOP_TYPE_IPV6_IFINDEX:
571 if (memcmp(&nexthop->gate.ipv6,&nrn->p.u.prefix6, 16) == 0)
572 {
573 if (num_resolving_nh)
574 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
575 else
576 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
577 }
578 break;
579 default:
580 break;
581 }
582 }
078430f6 583
d50b5bdd 584 if (IS_ZEBRA_DEBUG_NHT)
585 {
586 prefix2str(&static_rn->p, bufs, INET6_ADDRSTRLEN);
587 if (prn && rib)
588 zlog_debug("%u:%s: NH change %s, scheduling static route %s",
589 vrfid, bufn, num_resolving_nh ?
590 "" : "(filtered by route-map)", bufs);
591 else
592 zlog_debug("%u:%s: NH unreachable, scheduling static route %s",
593 vrfid, bufn, bufs);
594 }
078430f6 595
2b50b603 596 SET_FLAG(srib->status, RIB_ENTRY_CHANGED);
d50b5bdd 597 SET_FLAG(srib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
44e9909d 598 rib_queue_add(static_rn);
d50b5bdd 599 }
600}
078430f6 601
d50b5bdd 602/*
603 * See if a tracked nexthop entry has undergone any change, and if so,
604 * take appropriate action; this involves notifying any clients and/or
605 * scheduling dependent static routes for processing.
606 */
607static void
608zebra_rnh_eval_nexthop_entry (vrf_id_t vrfid, int family, int force,
609 struct route_node *nrn, struct rnh *rnh,
610 struct route_node *prn, struct rib *rib)
611{
612 int state_changed = 0;
e2ae41ad 613
d50b5bdd 614 /* If we're resolving over a different route, resolution has changed or
615 * the resolving route has some change (e.g., metric), there is a state
616 * change.
617 */
618 if (!prefix_same(&rnh->resolved_route, &prn->p))
619 {
620 if (rib)
621 UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
c5f7794f 622
d50b5bdd 623 if (prn)
624 prefix_copy(&rnh->resolved_route, &prn->p);
625 else
626 memset(&rnh->resolved_route, 0, sizeof(struct prefix));
c5f7794f 627
d50b5bdd 628 copy_state(rnh, rib, nrn);
629 state_changed = 1;
630 }
631 else if (compare_state(rib, rnh->state))
632 {
633 if (rib)
634 UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
6e26278c 635
d50b5bdd 636 copy_state(rnh, rib, nrn);
637 state_changed = 1;
638 }
9f0ea7d4 639
d50b5bdd 640 if (state_changed || force)
641 {
642 /* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
643 * rnh->state.
644 */
645 /* Notify registered protocol clients. */
646 zebra_rnh_notify_protocol_clients (vrfid, family, nrn, rnh,
647 prn, rnh->state);
6e26278c 648
d50b5bdd 649 /* Process static routes attached to this nexthop */
650 zebra_rnh_process_static_routes (vrfid, family, nrn, rnh,
651 prn, rnh->state);
652 }
653}
6e26278c 654
d50b5bdd 655/* Evaluate one tracked entry */
656static void
657zebra_rnh_evaluate_entry (vrf_id_t vrfid, int family, int force, rnh_type_t type,
658 struct route_node *nrn)
659{
660 struct rnh *rnh;
661 struct rib *rib;
662 struct route_node *prn;
663 char bufn[INET6_ADDRSTRLEN];
9f0ea7d4 664
d50b5bdd 665 if (IS_ZEBRA_DEBUG_NHT)
666 {
667 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
668 zlog_debug("%u:%s: Evaluate RNH, type %d %s",
669 vrfid, bufn, type, force ? "(force)" : "");
670 }
6e26278c 671
d50b5bdd 672 rnh = nrn->info;
6e26278c 673
d50b5bdd 674 /* Identify route entry (RIB) resolving this tracked entry. */
675 rib = zebra_rnh_resolve_entry (vrfid, family, type, nrn, rnh, &prn);
6e26278c 676
d50b5bdd 677 /* If the entry cannot be resolved and that is also the existing state,
678 * there is nothing further to do.
679 */
680 if (!rib && rnh->state == NULL && !force)
681 return;
078430f6 682
d50b5bdd 683 /* Process based on type of entry. */
684 if (type == RNH_IMPORT_CHECK_TYPE)
685 zebra_rnh_eval_import_check_entry (vrfid, family, force,
686 nrn, rnh, rib);
687 else
688 zebra_rnh_eval_nexthop_entry (vrfid, family, force,
689 nrn, rnh, prn, rib);
690}
691
692
693/* Evaluate all tracked entries (nexthops or routes for import into BGP)
694 * of a particular VRF and address-family or a specific prefix.
695 */
696void
697zebra_evaluate_rnh (vrf_id_t vrfid, int family, int force, rnh_type_t type,
698 struct prefix *p)
699{
700 struct route_table *rnh_table;
701 struct route_node *nrn;
702
703 rnh_table = get_rnh_table(vrfid, family, type);
704 if (!rnh_table) // unexpected
705 return;
078430f6 706
d50b5bdd 707 if (p)
708 {
709 /* Evaluating a specific entry, make sure it exists. */
710 nrn = route_node_lookup (rnh_table, p);
711 if (nrn && nrn->info)
712 zebra_rnh_evaluate_entry (vrfid, family, force, type, nrn);
713 if (nrn)
714 route_unlock_node (nrn);
715 }
716 else
717 {
718 /* Evaluate entire table. */
719 nrn = route_top (rnh_table);
720 while (nrn)
721 {
722 if (nrn->info)
723 zebra_rnh_evaluate_entry (vrfid, family, force, type, nrn);
724 nrn = route_next(nrn); /* this will also unlock nrn */
725 }
726 }
fb018d25
DS
727}
728
fb018d25 729void
b72ede27 730zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty, rnh_type_t type)
fb018d25
DS
731{
732 struct route_table *table;
733 struct route_node *rn;
734
078430f6 735 table = get_rnh_table(vrfid, af, type);
fb018d25
DS
736 if (!table)
737 {
738 zlog_debug("print_rnhs: rnh table not found\n");
739 return;
740 }
741
742 for (rn = route_top(table); rn; rn = route_next(rn))
743 if (rn->info)
744 print_rnh(rn, vty);
745}
746
747int
67cc8c5e 748zebra_cleanup_rnh_client (vrf_id_t vrf_id, int family, struct zserv *client,
078430f6 749 rnh_type_t type)
fb018d25
DS
750{
751 struct route_table *ntable;
752 struct route_node *nrn;
753 struct rnh *rnh;
754
67cc8c5e 755 if (IS_ZEBRA_DEBUG_NHT)
756 zlog_debug("%u: Client %s RNH cleanup for family %d type %d",
757 vrf_id, zebra_route_string(client->proto), family, type);
758
759 ntable = get_rnh_table(vrf_id, family, type);
fb018d25
DS
760 if (!ntable)
761 {
762 zlog_debug("cleanup_rnh_client: rnh table not found\n");
763 return -1;
764 }
765
766 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
767 {
768 if (!nrn->info)
769 continue;
770
771 rnh = nrn->info;
078430f6 772 zebra_remove_rnh_client(rnh, client, type);
fb018d25
DS
773 }
774 return 1;
775}
776
777/**
778 * free_state - free up the rib structure associated with the rnh.
779 */
780static void
d82ae0de 781free_state (vrf_id_t vrf_id, struct rib *rib, struct route_node *rn)
fb018d25 782{
fb018d25
DS
783
784 if (!rib)
785 return;
786
787 /* free RIB and nexthops */
d82ae0de 788 zebra_deregister_rnh_static_nexthops (vrf_id, rib->nexthop, rn);
b046b633 789 nexthops_free(rib->nexthop);
fb018d25
DS
790 XFREE (MTYPE_RIB, rib);
791}
792
fb018d25 793static void
6e26278c 794copy_state (struct rnh *rnh, struct rib *rib, struct route_node *rn)
fb018d25
DS
795{
796 struct rib *state;
797 struct nexthop *nh;
798
799 if (rnh->state)
800 {
d82ae0de 801 free_state(rnh->vrf_id, rnh->state, rn);
fb018d25
DS
802 rnh->state = NULL;
803 }
804
805 if (!rib)
806 return;
807
808 state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
809 state->type = rib->type;
810 state->metric = rib->metric;
811
812 for (nh = rib->nexthop; nh; nh = nh->next)
a399694f 813 rib_copy_nexthops(state, nh);
fb018d25
DS
814 rnh->state = state;
815}
816
817static int
818compare_state (struct rib *r1, struct rib *r2)
819{
fb018d25
DS
820
821 if (!r1 && !r2)
822 return 0;
823
824 if ((!r1 && r2) || (r1 && !r2))
825 return 1;
826
827 if (r1->metric != r2->metric)
828 return 1;
829
830 if (r1->nexthop_num != r2->nexthop_num)
831 return 1;
832
6e26278c
DS
833 if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED))
834 return 1;
fb018d25
DS
835
836 return 0;
837}
838
839static int
7076bb2f 840send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vrf_id)
fb018d25
DS
841{
842 struct stream *s;
843 struct rib *rib;
844 unsigned long nump;
845 u_char num;
846 struct nexthop *nexthop;
847 struct route_node *rn;
078430f6
DS
848 int cmd = (type == RNH_IMPORT_CHECK_TYPE)
849 ? ZEBRA_IMPORT_CHECK_UPDATE : ZEBRA_NEXTHOP_UPDATE;
fb018d25
DS
850
851 rn = rnh->node;
852 rib = rnh->state;
853
854 /* Get output stream. */
855 s = client->obuf;
856 stream_reset (s);
857
7076bb2f
FL
858 zserv_create_header (s, cmd, vrf_id);
859
fb018d25 860 stream_putw(s, rn->p.family);
078430f6
DS
861 switch (rn->p.family)
862 {
863 case AF_INET:
864 stream_putc(s, rn->p.prefixlen);
865 stream_put_in_addr(s, &rn->p.u.prefix4);
866 break;
867 case AF_INET6:
868 stream_putc(s, rn->p.prefixlen);
869 stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
870 break;
871 default:
872 zlog_err("%s: Unknown family (%d) notification attempted\n",
873 __FUNCTION__, rn->p.family);
874 break;
875 }
fb018d25
DS
876 if (rib)
877 {
878 stream_putl (s, rib->metric);
879 num = 0;
880 nump = stream_get_endp(s);
881 stream_putc (s, 0);
882 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
0e5c866a
DS
883 if ((CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ||
884 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) &&
9f0ea7d4 885 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
fb018d25
DS
886 {
887 stream_putc (s, nexthop->type);
888 switch (nexthop->type)
889 {
5b30316e 890 case NEXTHOP_TYPE_IPV4:
fb018d25
DS
891 stream_put_in_addr (s, &nexthop->gate.ipv4);
892 break;
5b30316e 893 case NEXTHOP_TYPE_IFINDEX:
fb018d25
DS
894 stream_putl (s, nexthop->ifindex);
895 break;
5b30316e 896 case NEXTHOP_TYPE_IPV4_IFINDEX:
fb018d25
DS
897 stream_put_in_addr (s, &nexthop->gate.ipv4);
898 stream_putl (s, nexthop->ifindex);
899 break;
900#ifdef HAVE_IPV6
5b30316e 901 case NEXTHOP_TYPE_IPV6:
fb018d25
DS
902 stream_put (s, &nexthop->gate.ipv6, 16);
903 break;
5b30316e 904 case NEXTHOP_TYPE_IPV6_IFINDEX:
fb018d25
DS
905 stream_put (s, &nexthop->gate.ipv6, 16);
906 stream_putl (s, nexthop->ifindex);
907 break;
908#endif /* HAVE_IPV6 */
909 default:
910 /* do nothing */
911 break;
912 }
913 num++;
914 }
915 stream_putc_at (s, nump, num);
916 }
917 else
918 {
919 stream_putl (s, 0);
920 stream_putc (s, 0);
921 }
922 stream_putw_at (s, 0, stream_get_endp (s));
04b02fda 923
2176b7c3 924 client->nh_last_upd_time = quagga_monotime();
078430f6 925 client->last_write_cmd = cmd;
fb018d25
DS
926 return zebra_server_send_message(client);
927}
928
929static void
930print_nh (struct nexthop *nexthop, struct vty *vty)
931{
932 char buf[BUFSIZ];
fe18ee2d 933 struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
fb018d25
DS
934
935 switch (nexthop->type)
936 {
937 case NEXTHOP_TYPE_IPV4:
938 case NEXTHOP_TYPE_IPV4_IFINDEX:
939 vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
940 if (nexthop->ifindex)
fe18ee2d 941 vty_out (vty, ", %s", ifindex2ifname_per_ns (zns, nexthop->ifindex));
fb018d25
DS
942 break;
943 case NEXTHOP_TYPE_IPV6:
944 case NEXTHOP_TYPE_IPV6_IFINDEX:
fb018d25
DS
945 vty_out (vty, " %s",
946 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
f6b66ab3 947 if (nexthop->ifindex)
fe18ee2d 948 vty_out (vty, ", via %s", ifindex2ifname_per_ns (zns, nexthop->ifindex));
fb018d25
DS
949 break;
950 case NEXTHOP_TYPE_IFINDEX:
951 vty_out (vty, " is directly connected, %s",
fe18ee2d 952 ifindex2ifname_per_ns (zns, nexthop->ifindex));
fb018d25 953 break;
fb018d25
DS
954 case NEXTHOP_TYPE_BLACKHOLE:
955 vty_out (vty, " is directly connected, Null0");
956 break;
957 default:
958 break;
959 }
960 vty_out(vty, "%s", VTY_NEWLINE);
961}
962
963static void
964print_rnh (struct route_node *rn, struct vty *vty)
965{
966 struct rnh *rnh;
967 struct nexthop *nexthop;
968 struct listnode *node;
969 struct zserv *client;
970 char buf[BUFSIZ];
971
972 rnh = rn->info;
e5cc509c
DS
973 vty_out(vty, "%s%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
974 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
fb018d25
DS
975 VTY_NEWLINE);
976 if (rnh->state)
977 {
978 vty_out(vty, " resolved via %s%s",
979 zebra_route_string(rnh->state->type), VTY_NEWLINE);
980 for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
981 print_nh(nexthop, vty);
982 }
983 else
fc9a856f
DS
984 vty_out(vty, " unresolved%s%s",
985 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
986 VTY_NEWLINE);
fb018d25
DS
987
988 vty_out(vty, " Client list:");
989 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
9f0ea7d4
DS
990 vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
991 client->sock, rnh->filtered[client->proto] ? "(filtered)" : "");
6e26278c
DS
992 if (!list_isempty(rnh->zebra_static_route_list))
993 vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
fb018d25
DS
994 vty_out(vty, "%s", VTY_NEWLINE);
995}