]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_rnh.c
Merge branch 'cmaster' of ssh://stash.cumulusnetworks.com:7999/quag/quagga into cmaster
[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"
44#include "zebra/redistribute.h"
45#include "zebra/debug.h"
46#include "zebra/zebra_rnh.h"
47
6e26278c
DS
48/* Default rtm_table for all clients */
49extern struct zebra_t zebrad;
50
51static void free_state(struct rib *rib, struct route_node *rn);
078430f6
DS
52static void copy_state(struct rnh *rnh, struct rib *rib,
53 struct route_node *rn);
b72ede27
FL
54#define lookup_rnh_table(v, f) \
55({ \
56 struct zebra_vrf *zvrf; \
57 struct route_table *t = NULL; \
58 zvrf = zebra_vrf_lookup(v); \
59 if (zvrf) \
60 t = zvrf->rnh_table[family2afi(f)]; \
61 t; \
62})
63
fb018d25 64static int compare_state(struct rib *r1, struct rib *r2);
7076bb2f
FL
65static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
66 vrf_id_t vrf_id);
fb018d25
DS
67static void print_rnh(struct route_node *rn, struct vty *vty);
68
a50b580a
DS
69int zebra_rnh_ip_default_route = 0;
70int zebra_rnh_ipv6_default_route = 0;
71
b72ede27 72static inline struct route_table *get_rnh_table(vrf_id_t vrfid, int family,
078430f6
DS
73 rnh_type_t type)
74{
b72ede27 75 struct zebra_vrf *zvrf;
078430f6
DS
76 struct route_table *t = NULL;
77
b72ede27
FL
78 zvrf = zebra_vrf_lookup(vrfid);
79 if (zvrf)
078430f6
DS
80 switch (type)
81 {
82 case RNH_NEXTHOP_TYPE:
b72ede27 83 t = zvrf->rnh_table[family2afi(family)];
078430f6
DS
84 break;
85 case RNH_IMPORT_CHECK_TYPE:
b72ede27 86 t = zvrf->import_check_table[family2afi(family)];
078430f6
DS
87 break;
88 }
89
90 return t;
91}
92
93char *rnh_str (struct rnh *rnh, char *buf, int size)
fb018d25
DS
94{
95 prefix2str(&(rnh->node->p), buf, size);
96 return buf;
97}
98
99struct rnh *
b72ede27 100zebra_add_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
fb018d25
DS
101{
102 struct route_table *table;
103 struct route_node *rn;
104 struct rnh *rnh = NULL;
105
106 if (IS_ZEBRA_DEBUG_NHT)
107 {
4690c7d7
DS
108 char buf[PREFIX2STR_BUFFER];
109 prefix2str(p, buf, sizeof (buf));
fb018d25
DS
110 zlog_debug("add rnh %s in vrf %d", buf, vrfid);
111 }
078430f6 112 table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
fb018d25
DS
113 if (!table)
114 {
115 zlog_debug("add_rnh: rnh table not found\n");
116 return NULL;
117 }
118
119 /* Make it sure prefixlen is applied to the prefix. */
120 apply_mask (p);
121
122 /* Lookup (or add) route node.*/
123 rn = route_node_get (table, p);
124
125 if (!rn->info)
126 {
127 rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
128 rnh->client_list = list_new();
6e26278c 129 rnh->zebra_static_route_list = list_new();
fb018d25
DS
130 route_lock_node (rn);
131 rn->info = rnh;
132 rnh->node = rn;
133 }
134
135 route_unlock_node (rn);
136 return (rn->info);
137}
138
139struct rnh *
b72ede27 140zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
fb018d25
DS
141{
142 struct route_table *table;
143 struct route_node *rn;
144
078430f6 145 table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
fb018d25
DS
146 if (!table)
147 return NULL;
148
149 /* Make it sure prefixlen is applied to the prefix. */
150 apply_mask (p);
151
152 /* Lookup route node.*/
153 rn = route_node_lookup (table, p);
154 if (!rn)
155 return NULL;
156
157 route_unlock_node (rn);
158 return (rn->info);
159}
160
161void
078430f6 162zebra_delete_rnh (struct rnh *rnh, rnh_type_t type)
fb018d25
DS
163{
164 struct route_node *rn;
165
70c0f184 166 if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED) || !(rn = rnh->node))
fb018d25
DS
167 return;
168
169 if (IS_ZEBRA_DEBUG_NHT)
170 {
4690c7d7
DS
171 char buf[PREFIX2STR_BUFFER];
172 zlog_debug("delete rnh %s", rnh_str(rnh, buf, sizeof (buf)));
fb018d25
DS
173 }
174
70c0f184 175 rnh->flags |= ZEBRA_NHT_DELETED;
fb018d25 176 list_free(rnh->client_list);
6e26278c
DS
177 list_free(rnh->zebra_static_route_list);
178 free_state(rnh->state, rn);
fb018d25
DS
179 XFREE(MTYPE_RNH, rn->info);
180 rn->info = NULL;
181 route_unlock_node (rn);
182 return;
183}
184
185void
7076bb2f
FL
186zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type,
187 vrf_id_t vrf_id)
fb018d25
DS
188{
189 if (IS_ZEBRA_DEBUG_NHT)
190 {
4690c7d7 191 char buf[PREFIX2STR_BUFFER];
fb018d25
DS
192 zlog_debug("client %s registers rnh %s",
193 zebra_route_string(client->proto),
4690c7d7 194 rnh_str(rnh, buf, sizeof (buf)));
fb018d25
DS
195 }
196 if (!listnode_lookup(rnh->client_list, client))
197 {
198 listnode_add(rnh->client_list, client);
7076bb2f 199 send_client(rnh, client, type, vrf_id); // Pending: check if its needed
fb018d25
DS
200 }
201}
202
203void
078430f6 204zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
fb018d25
DS
205{
206 if (IS_ZEBRA_DEBUG_NHT)
207 {
4690c7d7 208 char buf[PREFIX2STR_BUFFER];
fb018d25
DS
209 zlog_debug("client %s unregisters rnh %s",
210 zebra_route_string(client->proto),
4690c7d7 211 rnh_str(rnh, buf, sizeof (buf)));
fb018d25
DS
212 }
213 listnode_delete(rnh->client_list, client);
6e26278c
DS
214 if (list_isempty(rnh->client_list) &&
215 list_isempty(rnh->zebra_static_route_list))
078430f6 216 zebra_delete_rnh(rnh, type);
6e26278c
DS
217}
218
219void
220zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
221{
222 struct rnh *rnh;
223
078430f6 224 rnh = zebra_add_rnh(nh, 0, RNH_NEXTHOP_TYPE);
6e26278c
DS
225 if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn))
226 {
227 listnode_add(rnh->zebra_static_route_list, static_rn);
228 }
229}
230
231void
232zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
233{
234 struct rnh *rnh;
235
078430f6 236 rnh = zebra_lookup_rnh(nh, 0, RNH_NEXTHOP_TYPE);
70c0f184 237 if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED))
6e26278c
DS
238 return;
239
240 listnode_delete(rnh->zebra_static_route_list, static_rn);
241
242 if (list_isempty(rnh->client_list) &&
243 list_isempty(rnh->zebra_static_route_list))
078430f6 244 zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
fb018d25
DS
245}
246
a399694f
DS
247void
248zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn)
249{
250 struct nexthop *nh;
251 struct prefix nh_p;
252
253 for (nh = nexthop; nh ; nh = nh->next)
254 {
255 if (nh->type == NEXTHOP_TYPE_IPV4)
256 {
257 nh_p.family = AF_INET;
258 nh_p.prefixlen = IPV4_MAX_BITLEN;
259 nh_p.u.prefix4 = nh->gate.ipv4;
260 }
261 else if (nh->type == NEXTHOP_TYPE_IPV6)
262 {
263 nh_p.family = AF_INET6;
264 nh_p.prefixlen = IPV6_MAX_BITLEN;
265 nh_p.u.prefix6 = nh->gate.ipv6;
266 }
267 zebra_deregister_rnh_static_nh(&nh_p, rn);
268 }
269}
270
6e26278c
DS
271static int
272zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn,
273 int proto)
274{
275 int at_least_one = 0;
276 int rmap_family; /* Route map has diff AF family enum */
277 struct nexthop *nexthop;
278 int ret;
279
280 rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6;
281
282 if (prn && rib)
283 {
284 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
285 {
286 ret = zebra_nht_route_map_check(rmap_family, proto, &prn->p, rib,
287 nexthop);
288 if (ret != RMAP_DENYMATCH)
289 {
290 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
291 at_least_one++; /* at least one valid NH */
292 }
293 else
294 {
295 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
296 }
297 }
298 }
299 return (at_least_one);
300}
301
fb018d25 302int
b72ede27 303zebra_evaluate_rnh (vrf_id_t vrfid, int family, int force, rnh_type_t type,
078430f6 304 struct prefix *p)
fb018d25
DS
305{
306 struct route_table *ptable;
307 struct route_table *ntable;
078430f6
DS
308 struct route_node *prn = NULL;
309 struct route_node *nrn = NULL;
fb018d25
DS
310 struct rnh *rnh;
311 struct zserv *client;
312 struct listnode *node;
6e26278c 313 struct rib *rib, *srib;
9f0ea7d4
DS
314 int state_changed = 0;
315 int at_least_one = 0;
4690c7d7
DS
316 char bufn[PREFIX2STR_BUFFER];
317 char bufp[PREFIX2STR_BUFFER];
318 char bufs[PREFIX2STR_BUFFER];
6e26278c 319 struct route_node *static_rn;
078430f6
DS
320 struct nexthop *nexthop, *tnexthop;
321 int recursing;
c5f7794f 322
078430f6 323 ntable = get_rnh_table(vrfid, family, type);
fb018d25
DS
324 if (!ntable)
325 {
326 zlog_debug("evaluate_rnh_table: rnh table not found\n");
327 return -1;
328 }
329
b72ede27 330 ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
fb018d25
DS
331 if (!ptable)
332 {
333 zlog_debug("evaluate_rnh_table: prefix table not found\n");
334 return -1;
335 }
336
078430f6
DS
337 if (p)
338 nrn = route_node_lookup(ntable, p);
339 else
340 nrn = route_top (ntable);
341
342 while (nrn != NULL)
fb018d25
DS
343 {
344 if (!nrn->info)
078430f6 345 goto loopend;
fb018d25 346
9f0ea7d4 347 rnh = nrn->info;
6e26278c
DS
348 at_least_one = 0;
349
078430f6
DS
350 /* free stale stuff first */
351 if (prn)
352 route_unlock_node(prn);
353
fb018d25 354 prn = route_node_match(ptable, &nrn->p);
078430f6
DS
355
356 /* Do not resolve over default route unless allowed &&
357 * match route to be exact if so specified
358 */
359 if (!prn)
360 rib = NULL;
361 else if ((type == RNH_NEXTHOP_TYPE) &&
18ff3edd
DS
362 (is_default_prefix (&prn->p) &&
363 !nh_resolve_via_default(prn->p.family)))
078430f6
DS
364 rib = NULL;
365 else if ((type == RNH_IMPORT_CHECK_TYPE) &&
18ff3edd 366 ((is_default_prefix(&prn->p)) ||
078430f6
DS
367 ((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) &&
368 !prefix_same(&nrn->p, &prn->p))))
fb018d25
DS
369 rib = NULL;
370 else
371 {
372 RNODE_FOREACH_RIB(prn, rib)
373 {
374 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
375 continue;
376 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
fc9a856f
DS
377 {
378 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
379 {
380 if (rib->type == ZEBRA_ROUTE_CONNECT)
381 break;
382 }
078430f6
DS
383 else if ((type == RNH_IMPORT_CHECK_TYPE) &&
384 (rib->type == ZEBRA_ROUTE_BGP))
385 continue;
fc9a856f
DS
386 else
387 break;
388 }
fb018d25
DS
389 }
390 }
391
9f0ea7d4
DS
392 state_changed = 0;
393
078430f6
DS
394 /* Handle import check first as its simpler */
395 if (type == RNH_IMPORT_CHECK_TYPE)
396 {
397 if (rib && (rnh->state == NULL))
398 {
399 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
400 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
401 {
402 state_changed = 1;
403 break;
404 }
405 }
406 else if (!rib && (rnh->state != NULL))
407 state_changed = 1;
408
409 if (compare_state(rib, rnh->state))
410 copy_state(rnh, rib, nrn);
411
412 if (state_changed || force)
413 {
414 if (IS_ZEBRA_DEBUG_NHT)
415 {
4690c7d7 416 prefix2str(&nrn->p, bufn, sizeof (bufn));
078430f6
DS
417 zlog_debug("rnh import check %s for %s, notifying clients\n",
418 rnh->state ? "passed" : "failed", bufn);
419 }
420 /* state changed, notify clients */
421 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
422 {
7076bb2f 423 send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid);
078430f6
DS
424 }
425 }
426
427 goto loopend;
428 }
429
e2ae41ad
DS
430 /* If nexthop cannot be resolved and that is also the existing state,
431 * there is nothing further to do.
432 */
433 if (!rib && rnh->state == NULL)
434 goto loopend;
435
c5f7794f
DS
436 /* Ensure prefixes we're resolving over have stayed the same */
437 if (!prefix_same(&rnh->resolved_route, &prn->p))
438 {
439 if (rib)
440 UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
441
442 if (prn)
443 prefix_copy(&rnh->resolved_route, &prn->p);
444 else
445 memset(&rnh->resolved_route, 0, sizeof(struct prefix));
446
447 copy_state(rnh, rib, nrn);
448 state_changed = 1;
449 }
450 else if (compare_state(rib, rnh->state))
fb018d25 451 {
6e26278c
DS
452 if (rib)
453 UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
454
455 copy_state(rnh, rib, nrn);
9f0ea7d4
DS
456 state_changed = 1;
457 }
458
459 if (IS_ZEBRA_DEBUG_NHT && (state_changed || force))
460 {
4690c7d7 461 prefix2str(&nrn->p, bufn, sizeof (bufn));
9f0ea7d4 462 if (prn)
4690c7d7 463 prefix2str(&prn->p, bufp, sizeof (bufp));
9f0ea7d4
DS
464 else
465 strcpy(bufp, "null");
6e26278c
DS
466
467 zlog_debug("%s: State changed for %s/%s", __FUNCTION__, bufn, bufp);
468
fb018d25 469 }
9f0ea7d4
DS
470
471 /* Notify registered clients */
6e26278c
DS
472 rib = rnh->state;
473
9f0ea7d4 474 if (state_changed || force)
6e26278c
DS
475 {
476 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
477 {
478 if (prn && rib)
479 {
480 at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn,
481 client->proto);
482 if (at_least_one)
483 rnh->filtered[client->proto] = 0;
484 else
485 rnh->filtered[client->proto] = 1;
486 }
487 else if (state_changed)
9f0ea7d4 488 rnh->filtered[client->proto] = 0;
6e26278c
DS
489
490 if (IS_ZEBRA_DEBUG_NHT && (state_changed || force))
491 zlog_debug("%srnh %s resolved through route %s - sending "
492 "nexthop %s event to clients",
493 at_least_one ? "":"(filtered)", bufn, bufp,
494 rib ? "reachable" : "unreachable");
495
7076bb2f 496 send_client(rnh, client, RNH_NEXTHOP_TYPE, vrfid); /* Route-map passed */
6e26278c
DS
497 }
498
499 /* Now evaluate static client */
500 if (prn && rib)
501 {
502 at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn,
503 ZEBRA_ROUTE_STATIC);
504 if (at_least_one)
505 rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
506 else
507 rnh->filtered[ZEBRA_ROUTE_STATIC] = 1;
508 }
509 else if (state_changed)
510 rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
511
512 for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node,
513 static_rn))
514 {
515 RNODE_FOREACH_RIB(static_rn, srib)
516 {
796c789c 517 if (srib->type == ZEBRA_ROUTE_STATIC)
518 break; /* currently works for only 1 static route. */
6e26278c
DS
519 }
520
521 if (!srib)
522 {
523 if (IS_ZEBRA_DEBUG_NHT)
524 {
4690c7d7 525 prefix2str(&static_rn->p, bufs, sizeof (bufs));
6e26278c
DS
526 zlog_debug("%s: Unable to find RIB for static route %s, skipping NH resolution",
527 __FUNCTION__, bufs);
528 continue;
529 }
530 }
531
532 /* Mark the appropriate static route's NH as filtered */
533 for (nexthop = srib->nexthop; nexthop; nexthop = nexthop->next)
534 {
535 switch (nexthop->type)
536 {
537 case NEXTHOP_TYPE_IPV4:
538 case NEXTHOP_TYPE_IPV4_IFINDEX:
539 /* Don't see a use case for *_IFNAME */
540 if (nexthop->gate.ipv4.s_addr == nrn->p.u.prefix4.s_addr)
541 {
542 if (at_least_one)
543 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
544 else
545 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
546 }
547 break;
548 case NEXTHOP_TYPE_IPV6:
549 case NEXTHOP_TYPE_IPV6_IFINDEX:
550 /* Don't see a use case for *_IFNAME */
551 if (memcmp(&nexthop->gate.ipv6,&nrn->p.u.prefix6, 16) == 0)
552 {
553 if (at_least_one)
554 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
555 else
556 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
557 }
558 break;
559 default:
560 break;
561 }
562 }
563
564 if (IS_ZEBRA_DEBUG_NHT && (state_changed || force))
565 zlog_debug("%srnh %s resolved through route %s - sending "
566 "nexthop %s event to zebra",
567 at_least_one ? "":"(filtered)", bufn, bufp,
568 rib ? "reachable" : "unreachable");
569
570 if (srib && (state_changed || force))
571 {
572 SET_FLAG(srib->flags, ZEBRA_FLAG_CHANGED);
573 SET_FLAG(srib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
574 rib_queue_add(&zebrad, static_rn);
575 }
576 }
577 }
078430f6
DS
578 loopend:
579 if (p)
580 {
581 route_unlock_node(nrn);
582 nrn = NULL;
583 }
584 else
585 {
586 /* route_next takes care of unlocking nrn */
587 nrn = route_next(nrn);
588 }
fb018d25 589 }
078430f6
DS
590
591 if (prn)
592 route_unlock_node(prn);
593
fb018d25
DS
594 return 1;
595}
596
597int
7076bb2f 598zebra_dispatch_rnh_table (vrf_id_t vrf_id, int family, struct zserv *client,
078430f6 599 rnh_type_t type)
fb018d25
DS
600{
601 struct route_table *ntable;
602 struct route_node *nrn;
603 struct rnh *rnh;
604
7076bb2f 605 ntable = get_rnh_table(vrf_id, family, type);
fb018d25
DS
606 if (!ntable)
607 {
608 zlog_debug("dispatch_rnh_table: rnh table not found\n");
609 return -1;
610 }
611
612 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
613 {
614 if (!nrn->info)
615 continue;
616
617 rnh = nrn->info;
618 if (IS_ZEBRA_DEBUG_NHT)
619 {
4690c7d7
DS
620 char bufn[PREFIX2STR_BUFFER];
621 prefix2str(&nrn->p, bufn, sizeof (bufn));
fb018d25
DS
622 zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn,
623 rnh->state ? "reachable" : "unreachable",
624 zebra_route_string(client->proto));
625 }
7076bb2f 626 send_client(rnh, client, RNH_NEXTHOP_TYPE, vrf_id);
fb018d25
DS
627 }
628 return 1;
629}
630
631void
b72ede27 632zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty, rnh_type_t type)
fb018d25
DS
633{
634 struct route_table *table;
635 struct route_node *rn;
636
078430f6 637 table = get_rnh_table(vrfid, af, type);
fb018d25
DS
638 if (!table)
639 {
640 zlog_debug("print_rnhs: rnh table not found\n");
641 return;
642 }
643
644 for (rn = route_top(table); rn; rn = route_next(rn))
645 if (rn->info)
646 print_rnh(rn, vty);
647}
648
649int
b72ede27 650zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client,
078430f6 651 rnh_type_t type)
fb018d25
DS
652{
653 struct route_table *ntable;
654 struct route_node *nrn;
655 struct rnh *rnh;
656
078430f6 657 ntable = get_rnh_table(vrfid, family, type);
fb018d25
DS
658 if (!ntable)
659 {
660 zlog_debug("cleanup_rnh_client: rnh table not found\n");
661 return -1;
662 }
663
664 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
665 {
666 if (!nrn->info)
667 continue;
668
669 rnh = nrn->info;
670 if (IS_ZEBRA_DEBUG_NHT)
671 {
4690c7d7
DS
672 char bufn[PREFIX2STR_BUFFER];
673 prefix2str(&nrn->p, bufn, sizeof (bufn));
fb018d25
DS
674 zlog_debug("rnh %s - cleaning state for client %s", bufn,
675 zebra_route_string(client->proto));
676 }
078430f6 677 zebra_remove_rnh_client(rnh, client, type);
fb018d25
DS
678 }
679 return 1;
680}
681
682/**
683 * free_state - free up the rib structure associated with the rnh.
684 */
685static void
6e26278c 686free_state (struct rib *rib, struct route_node *rn)
fb018d25 687{
fb018d25
DS
688
689 if (!rib)
690 return;
691
692 /* free RIB and nexthops */
a399694f 693 zebra_deregister_rnh_static_nexthops (rib->nexthop, rn);
b046b633 694 nexthops_free(rib->nexthop);
fb018d25
DS
695 XFREE (MTYPE_RIB, rib);
696}
697
fb018d25 698static void
6e26278c 699copy_state (struct rnh *rnh, struct rib *rib, struct route_node *rn)
fb018d25
DS
700{
701 struct rib *state;
702 struct nexthop *nh;
703
704 if (rnh->state)
705 {
6e26278c 706 free_state(rnh->state, rn);
fb018d25
DS
707 rnh->state = NULL;
708 }
709
710 if (!rib)
711 return;
712
713 state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
714 state->type = rib->type;
715 state->metric = rib->metric;
716
717 for (nh = rib->nexthop; nh; nh = nh->next)
a399694f 718 rib_copy_nexthops(state, nh);
fb018d25
DS
719 rnh->state = state;
720}
721
722static int
723compare_state (struct rib *r1, struct rib *r2)
724{
fb018d25
DS
725
726 if (!r1 && !r2)
727 return 0;
728
729 if ((!r1 && r2) || (r1 && !r2))
730 return 1;
731
732 if (r1->metric != r2->metric)
733 return 1;
734
735 if (r1->nexthop_num != r2->nexthop_num)
736 return 1;
737
6e26278c
DS
738 if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED))
739 return 1;
fb018d25
DS
740
741 return 0;
742}
743
744static int
7076bb2f 745send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vrf_id)
fb018d25
DS
746{
747 struct stream *s;
748 struct rib *rib;
749 unsigned long nump;
750 u_char num;
751 struct nexthop *nexthop;
752 struct route_node *rn;
078430f6
DS
753 int cmd = (type == RNH_IMPORT_CHECK_TYPE)
754 ? ZEBRA_IMPORT_CHECK_UPDATE : ZEBRA_NEXTHOP_UPDATE;
fb018d25
DS
755
756 rn = rnh->node;
757 rib = rnh->state;
758
759 /* Get output stream. */
760 s = client->obuf;
761 stream_reset (s);
762
7076bb2f
FL
763 zserv_create_header (s, cmd, vrf_id);
764
fb018d25 765 stream_putw(s, rn->p.family);
078430f6
DS
766 switch (rn->p.family)
767 {
768 case AF_INET:
769 stream_putc(s, rn->p.prefixlen);
770 stream_put_in_addr(s, &rn->p.u.prefix4);
771 break;
772 case AF_INET6:
773 stream_putc(s, rn->p.prefixlen);
774 stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
775 break;
776 default:
777 zlog_err("%s: Unknown family (%d) notification attempted\n",
778 __FUNCTION__, rn->p.family);
779 break;
780 }
fb018d25
DS
781 if (rib)
782 {
783 stream_putl (s, rib->metric);
784 num = 0;
785 nump = stream_get_endp(s);
786 stream_putc (s, 0);
787 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
0e5c866a
DS
788 if ((CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ||
789 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) &&
9f0ea7d4 790 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
fb018d25
DS
791 {
792 stream_putc (s, nexthop->type);
793 switch (nexthop->type)
794 {
795 case ZEBRA_NEXTHOP_IPV4:
796 stream_put_in_addr (s, &nexthop->gate.ipv4);
797 break;
798 case ZEBRA_NEXTHOP_IFINDEX:
799 case ZEBRA_NEXTHOP_IFNAME:
800 stream_putl (s, nexthop->ifindex);
801 break;
802 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
803 case ZEBRA_NEXTHOP_IPV4_IFNAME:
804 stream_put_in_addr (s, &nexthop->gate.ipv4);
805 stream_putl (s, nexthop->ifindex);
806 break;
807#ifdef HAVE_IPV6
808 case ZEBRA_NEXTHOP_IPV6:
809 stream_put (s, &nexthop->gate.ipv6, 16);
810 break;
811 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
812 case ZEBRA_NEXTHOP_IPV6_IFNAME:
813 stream_put (s, &nexthop->gate.ipv6, 16);
814 stream_putl (s, nexthop->ifindex);
815 break;
816#endif /* HAVE_IPV6 */
817 default:
818 /* do nothing */
819 break;
820 }
821 num++;
822 }
823 stream_putc_at (s, nump, num);
824 }
825 else
826 {
827 stream_putl (s, 0);
828 stream_putc (s, 0);
829 }
830 stream_putw_at (s, 0, stream_get_endp (s));
04b02fda
DS
831
832 client->nh_last_upd_time = quagga_time(NULL);
078430f6 833 client->last_write_cmd = cmd;
fb018d25
DS
834 return zebra_server_send_message(client);
835}
836
837static void
838print_nh (struct nexthop *nexthop, struct vty *vty)
839{
840 char buf[BUFSIZ];
841
842 switch (nexthop->type)
843 {
844 case NEXTHOP_TYPE_IPV4:
845 case NEXTHOP_TYPE_IPV4_IFINDEX:
846 vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
847 if (nexthop->ifindex)
848 vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
849 break;
850 case NEXTHOP_TYPE_IPV6:
851 case NEXTHOP_TYPE_IPV6_IFINDEX:
852 case NEXTHOP_TYPE_IPV6_IFNAME:
853 vty_out (vty, " %s",
854 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
855 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
856 vty_out (vty, ", %s", nexthop->ifname);
857 else if (nexthop->ifindex)
858 vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
859 break;
860 case NEXTHOP_TYPE_IFINDEX:
861 vty_out (vty, " is directly connected, %s",
862 ifindex2ifname (nexthop->ifindex));
863 break;
864 case NEXTHOP_TYPE_IFNAME:
865 vty_out (vty, " is directly connected, %s", nexthop->ifname);
866 break;
867 case NEXTHOP_TYPE_BLACKHOLE:
868 vty_out (vty, " is directly connected, Null0");
869 break;
870 default:
871 break;
872 }
873 vty_out(vty, "%s", VTY_NEWLINE);
874}
875
876static void
877print_rnh (struct route_node *rn, struct vty *vty)
878{
879 struct rnh *rnh;
880 struct nexthop *nexthop;
881 struct listnode *node;
882 struct zserv *client;
883 char buf[BUFSIZ];
884
885 rnh = rn->info;
e5cc509c
DS
886 vty_out(vty, "%s%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
887 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
fb018d25
DS
888 VTY_NEWLINE);
889 if (rnh->state)
890 {
891 vty_out(vty, " resolved via %s%s",
892 zebra_route_string(rnh->state->type), VTY_NEWLINE);
893 for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
894 print_nh(nexthop, vty);
895 }
896 else
fc9a856f
DS
897 vty_out(vty, " unresolved%s%s",
898 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
899 VTY_NEWLINE);
fb018d25
DS
900
901 vty_out(vty, " Client list:");
902 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
9f0ea7d4
DS
903 vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
904 client->sock, rnh->filtered[client->proto] ? "(filtered)" : "");
6e26278c
DS
905 if (!list_isempty(rnh->zebra_static_route_list))
906 vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
fb018d25
DS
907 vty_out(vty, "%s", VTY_NEWLINE);
908}