1 /* Zebra next hop tracking code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
4 * This file is part of GNU Zebra.
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
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.
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
29 #include "sockunion.h"
32 #include "workqueue.h"
39 #include "zebra/rib.h"
41 #include "zebra/zserv.h"
42 #include "zebra/zebra_ns.h"
43 #include "zebra/zebra_vrf.h"
44 #include "zebra/redistribute.h"
45 #include "zebra/debug.h"
46 #include "zebra/zebra_rnh.h"
47 #include "zebra/zebra_routemap.h"
48 #include "zebra/interface.h"
49 #include "zebra/zebra_memory.h"
51 static void free_state(vrf_id_t vrf_id
, struct route_entry
*re
,
52 struct route_node
*rn
);
53 static void copy_state(struct rnh
*rnh
, struct route_entry
*re
,
54 struct route_node
*rn
);
55 #define lookup_rnh_table(v, f) \
57 struct zebra_vrf *zvrf; \
58 struct route_table *t = NULL; \
59 zvrf = zebra_vrf_lookup_by_id(v); \
61 t = zvrf->rnh_table[family2afi(f)]; \
65 static int compare_state(struct route_entry
*r1
, struct route_entry
*r2
);
66 static int send_client(struct rnh
*rnh
, struct zserv
*client
, rnh_type_t type
,
68 static void print_rnh(struct route_node
*rn
, struct vty
*vty
);
69 static int zebra_client_cleanup_rnh(struct zserv
*client
);
71 int zebra_rnh_ip_default_route
= 0;
72 int zebra_rnh_ipv6_default_route
= 0;
74 void zebra_rnh_init(void)
76 hook_register(zserv_client_close
, zebra_client_cleanup_rnh
);
79 static inline struct route_table
*get_rnh_table(vrf_id_t vrfid
, int family
,
82 struct zebra_vrf
*zvrf
;
83 struct route_table
*t
= NULL
;
85 zvrf
= zebra_vrf_lookup_by_id(vrfid
);
88 case RNH_NEXTHOP_TYPE
:
89 t
= zvrf
->rnh_table
[family2afi(family
)];
91 case RNH_IMPORT_CHECK_TYPE
:
92 t
= zvrf
->import_check_table
[family2afi(family
)];
99 char *rnh_str(struct rnh
*rnh
, char *buf
, int size
)
101 prefix2str(&(rnh
->node
->p
), buf
, size
);
105 struct rnh
*zebra_add_rnh(struct prefix
*p
, vrf_id_t vrfid
, rnh_type_t type
)
107 struct route_table
*table
;
108 struct route_node
*rn
;
109 struct rnh
*rnh
= NULL
;
110 char buf
[PREFIX2STR_BUFFER
];
112 if (IS_ZEBRA_DEBUG_NHT
) {
113 prefix2str(p
, buf
, sizeof(buf
));
114 zlog_debug("%u: Add RNH %s type %d", vrfid
, buf
, type
);
116 table
= get_rnh_table(vrfid
, PREFIX_FAMILY(p
), type
);
118 prefix2str(p
, buf
, sizeof(buf
));
119 zlog_warn("%u: Add RNH %s type %d - table not found", vrfid
,
124 /* Make it sure prefixlen is applied to the prefix. */
127 /* Lookup (or add) route node.*/
128 rn
= route_node_get(table
, p
);
131 rnh
= XCALLOC(MTYPE_RNH
, sizeof(struct rnh
));
132 rnh
->client_list
= list_new();
134 rnh
->zebra_static_route_list
= list_new();
135 rnh
->zebra_pseudowire_list
= list_new();
141 route_unlock_node(rn
);
145 struct rnh
*zebra_lookup_rnh(struct prefix
*p
, vrf_id_t vrfid
, rnh_type_t type
)
147 struct route_table
*table
;
148 struct route_node
*rn
;
150 table
= get_rnh_table(vrfid
, PREFIX_FAMILY(p
), type
);
154 /* Make it sure prefixlen is applied to the prefix. */
157 /* Lookup route node.*/
158 rn
= route_node_lookup(table
, p
);
162 route_unlock_node(rn
);
166 void zebra_free_rnh(struct rnh
*rnh
)
168 rnh
->flags
|= ZEBRA_NHT_DELETED
;
169 list_delete_and_null(&rnh
->client_list
);
170 list_delete_and_null(&rnh
->zebra_static_route_list
);
171 list_delete_and_null(&rnh
->zebra_pseudowire_list
);
172 free_state(rnh
->vrf_id
, rnh
->state
, rnh
->node
);
173 XFREE(MTYPE_RNH
, rnh
);
176 void zebra_delete_rnh(struct rnh
*rnh
, rnh_type_t type
)
178 struct route_node
*rn
;
180 if (!rnh
|| (rnh
->flags
& ZEBRA_NHT_DELETED
) || !(rn
= rnh
->node
))
183 if (IS_ZEBRA_DEBUG_NHT
) {
184 char buf
[PREFIX2STR_BUFFER
];
185 zlog_debug("%u: Del RNH %s type %d", rnh
->vrf_id
,
186 rnh_str(rnh
, buf
, sizeof(buf
)), type
);
191 route_unlock_node(rn
);
194 void zebra_add_rnh_client(struct rnh
*rnh
, struct zserv
*client
,
195 rnh_type_t type
, vrf_id_t vrf_id
)
197 if (IS_ZEBRA_DEBUG_NHT
) {
198 char buf
[PREFIX2STR_BUFFER
];
199 zlog_debug("%u: Client %s registers for RNH %s type %d", vrf_id
,
200 zebra_route_string(client
->proto
),
201 rnh_str(rnh
, buf
, sizeof(buf
)), type
);
203 if (!listnode_lookup(rnh
->client_list
, client
)) {
204 listnode_add(rnh
->client_list
, client
);
205 send_client(rnh
, client
, type
,
206 vrf_id
); // Pending: check if its needed
210 void zebra_remove_rnh_client(struct rnh
*rnh
, struct zserv
*client
,
213 if (IS_ZEBRA_DEBUG_NHT
) {
214 char buf
[PREFIX2STR_BUFFER
];
215 zlog_debug("Client %s unregisters for RNH %s type %d",
216 zebra_route_string(client
->proto
),
217 rnh_str(rnh
, buf
, sizeof(buf
)), type
);
219 listnode_delete(rnh
->client_list
, client
);
220 if (list_isempty(rnh
->client_list
)
221 && list_isempty(rnh
->zebra_static_route_list
)
222 && list_isempty(rnh
->zebra_pseudowire_list
))
223 zebra_delete_rnh(rnh
, type
);
226 void zebra_register_rnh_static_nh(vrf_id_t vrf_id
, struct prefix
*nh
,
227 struct route_node
*static_rn
)
231 rnh
= zebra_add_rnh(nh
, vrf_id
, RNH_NEXTHOP_TYPE
);
232 if (rnh
&& !listnode_lookup(rnh
->zebra_static_route_list
, static_rn
)) {
233 listnode_add(rnh
->zebra_static_route_list
, static_rn
);
237 void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id
, struct prefix
*nh
,
238 struct route_node
*static_rn
)
242 rnh
= zebra_lookup_rnh(nh
, vrf_id
, RNH_NEXTHOP_TYPE
);
243 if (!rnh
|| (rnh
->flags
& ZEBRA_NHT_DELETED
))
246 listnode_delete(rnh
->zebra_static_route_list
, static_rn
);
248 if (list_isempty(rnh
->client_list
)
249 && list_isempty(rnh
->zebra_static_route_list
)
250 && list_isempty(rnh
->zebra_pseudowire_list
))
251 zebra_delete_rnh(rnh
, RNH_NEXTHOP_TYPE
);
254 void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id
,
255 struct nexthop
*nexthop
,
256 struct route_node
*rn
)
261 for (nh
= nexthop
; nh
; nh
= nh
->next
) {
263 case NEXTHOP_TYPE_IPV4
:
264 case NEXTHOP_TYPE_IPV4_IFINDEX
:
265 nh_p
.family
= AF_INET
;
266 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
267 nh_p
.u
.prefix4
= nh
->gate
.ipv4
;
269 case NEXTHOP_TYPE_IPV6
:
270 case NEXTHOP_TYPE_IPV6_IFINDEX
:
271 nh_p
.family
= AF_INET6
;
272 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
273 nh_p
.u
.prefix6
= nh
->gate
.ipv6
;
276 * Not sure what really to do here, we are not
277 * supposed to have either of these for NHT
278 * and the code has no way to know what prefix
279 * to use. So I'm going to just continue
280 * for the moment, which is preferable to
281 * what is currently happening which is a
283 * Some simple testing shows that we
284 * are not leaving slag around for these
285 * skipped static routes. Since
286 * they don't appear to be installed
288 case NEXTHOP_TYPE_IFINDEX
:
289 case NEXTHOP_TYPE_BLACKHOLE
:
293 zebra_deregister_rnh_static_nh(vrf_id
, &nh_p
, rn
);
297 /* XXX move this utility function elsewhere? */
298 static void addr2hostprefix(int af
, const union g_addr
*addr
,
299 struct prefix
*prefix
)
303 prefix
->family
= AF_INET
;
304 prefix
->prefixlen
= IPV4_MAX_BITLEN
;
305 prefix
->u
.prefix4
= addr
->ipv4
;
308 prefix
->family
= AF_INET6
;
309 prefix
->prefixlen
= IPV6_MAX_BITLEN
;
310 prefix
->u
.prefix6
= addr
->ipv6
;
313 memset(prefix
, 0, sizeof(*prefix
));
314 zlog_warn("%s: unknown address family %d", __func__
, af
);
319 void zebra_register_rnh_pseudowire(vrf_id_t vrf_id
, struct zebra_pw
*pw
)
324 addr2hostprefix(pw
->af
, &pw
->nexthop
, &nh
);
325 rnh
= zebra_add_rnh(&nh
, vrf_id
, RNH_NEXTHOP_TYPE
);
326 if (rnh
&& !listnode_lookup(rnh
->zebra_pseudowire_list
, pw
)) {
327 listnode_add(rnh
->zebra_pseudowire_list
, pw
);
329 zebra_evaluate_rnh(vrf_id
, pw
->af
, 1, RNH_NEXTHOP_TYPE
, &nh
);
333 void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id
, struct zebra_pw
*pw
)
341 listnode_delete(rnh
->zebra_pseudowire_list
, pw
);
344 if (list_isempty(rnh
->client_list
)
345 && list_isempty(rnh
->zebra_static_route_list
)
346 && list_isempty(rnh
->zebra_pseudowire_list
))
347 zebra_delete_rnh(rnh
, RNH_NEXTHOP_TYPE
);
350 /* Apply the NHT route-map for a client to the route (and nexthops)
353 static int zebra_rnh_apply_nht_rmap(int family
, struct route_node
*prn
,
354 struct route_entry
*re
, int proto
)
356 int at_least_one
= 0;
357 int rmap_family
; /* Route map has diff AF family enum */
358 struct nexthop
*nexthop
;
361 rmap_family
= (family
== AF_INET
) ? AFI_IP
: AFI_IP6
;
364 for (nexthop
= re
->ng
.nexthop
; nexthop
;
365 nexthop
= nexthop
->next
) {
366 ret
= zebra_nht_route_map_check(rmap_family
, proto
,
367 &prn
->p
, re
, nexthop
);
368 if (ret
!= RMAP_DENYMATCH
) {
369 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
370 at_least_one
++; /* at least one valid NH */
372 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
376 return (at_least_one
);
380 * Determine appropriate route (RE entry) resolving a tracked BGP route
381 * for BGP route for import.
383 static struct route_entry
*
384 zebra_rnh_resolve_import_entry(vrf_id_t vrfid
, int family
,
385 struct route_node
*nrn
, struct rnh
*rnh
,
386 struct route_node
**prn
)
388 struct route_table
*route_table
;
389 struct route_node
*rn
;
390 struct route_entry
*re
;
394 route_table
= zebra_vrf_table(family2afi(family
), SAFI_UNICAST
, vrfid
);
395 if (!route_table
) // unexpected
398 rn
= route_node_match(route_table
, &nrn
->p
);
402 /* Unlock route node - we don't need to lock when walking the tree. */
403 route_unlock_node(rn
);
405 if (CHECK_FLAG(rnh
->flags
, ZEBRA_NHT_EXACT_MATCH
)
406 && !prefix_same(&nrn
->p
, &rn
->p
))
409 /* Identify appropriate route entry. */
410 RNODE_FOREACH_RE (rn
, re
) {
411 if (!CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
)
412 && CHECK_FLAG(re
->flags
, ZEBRA_FLAG_SELECTED
)
413 && (re
->type
!= ZEBRA_ROUTE_BGP
))
423 * See if a tracked route entry for import (by BGP) has undergone any
424 * change, and if so, notify the client.
426 static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid
, int family
,
427 int force
, struct route_node
*nrn
,
429 struct route_entry
*re
)
431 int state_changed
= 0;
432 struct zserv
*client
;
433 char bufn
[INET6_ADDRSTRLEN
];
434 struct listnode
*node
;
435 struct nexthop
*nexthop
;
437 if (re
&& (rnh
->state
== NULL
)) {
438 for (ALL_NEXTHOPS(re
->ng
, nexthop
))
439 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
)) {
443 } else if (!re
&& (rnh
->state
!= NULL
))
446 if (compare_state(re
, rnh
->state
))
447 copy_state(rnh
, re
, nrn
);
449 if (state_changed
|| force
) {
450 if (IS_ZEBRA_DEBUG_NHT
) {
451 prefix2str(&nrn
->p
, bufn
, INET6_ADDRSTRLEN
);
452 zlog_debug("%u:%s: Route import check %s %s\n", vrfid
,
453 bufn
, rnh
->state
? "passed" : "failed",
454 state_changed
? "(state changed)" : "");
456 /* state changed, notify clients */
457 for (ALL_LIST_ELEMENTS_RO(rnh
->client_list
, node
, client
)) {
458 send_client(rnh
, client
, RNH_IMPORT_CHECK_TYPE
, vrfid
);
464 * Notify clients registered for this nexthop about a change.
466 static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid
, int family
,
467 struct route_node
*nrn
,
469 struct route_node
*prn
,
470 struct route_entry
*re
)
472 struct listnode
*node
;
473 struct zserv
*client
;
474 char bufn
[INET6_ADDRSTRLEN
];
475 char bufp
[INET6_ADDRSTRLEN
];
476 int num_resolving_nh
;
478 if (IS_ZEBRA_DEBUG_NHT
) {
479 prefix2str(&nrn
->p
, bufn
, INET6_ADDRSTRLEN
);
481 prefix2str(&prn
->p
, bufp
, INET6_ADDRSTRLEN
);
482 zlog_debug("%u:%s: NH resolved over route %s", vrfid
,
485 zlog_debug("%u:%s: NH has become unresolved", vrfid
,
489 for (ALL_LIST_ELEMENTS_RO(rnh
->client_list
, node
, client
)) {
491 /* Apply route-map for this client to route resolving
493 * nexthop to see if it is filtered or not.
495 num_resolving_nh
= zebra_rnh_apply_nht_rmap(
496 family
, prn
, re
, client
->proto
);
497 if (num_resolving_nh
)
498 rnh
->filtered
[client
->proto
] = 0;
500 rnh
->filtered
[client
->proto
] = 1;
502 if (IS_ZEBRA_DEBUG_NHT
)
504 "%u:%s: Notifying client %s about NH %s",
506 zebra_route_string(client
->proto
),
509 : "(filtered by route-map)");
511 rnh
->filtered
[client
->proto
] = 0;
512 if (IS_ZEBRA_DEBUG_NHT
)
514 "%u:%s: Notifying client %s about NH (unreachable)",
516 zebra_route_string(client
->proto
));
519 send_client(rnh
, client
, RNH_NEXTHOP_TYPE
, vrfid
);
523 static void zebra_rnh_process_pbr_tables(int family
,
524 struct route_node
*nrn
,
526 struct route_node
*prn
,
527 struct route_entry
*re
)
529 struct zebra_ns_table
*znst
;
530 struct route_entry
*o_re
;
531 struct route_node
*o_rn
;
532 struct listnode
*node
;
533 struct zserv
*client
;
534 struct zebra_ns
*zns
;
537 if (family
== AF_INET6
)
541 * We are only concerned about nexthops that change for
544 for (ALL_LIST_ELEMENTS_RO(rnh
->client_list
, node
, client
)) {
545 if (client
->proto
== ZEBRA_ROUTE_PBR
)
552 zns
= zebra_ns_lookup(NS_DEFAULT
);
553 RB_FOREACH (znst
, zebra_ns_table_head
, &zns
->ns_tables
) {
554 if (afi
!= znst
->afi
)
557 for (o_rn
= route_top(znst
->table
);
558 o_rn
; o_rn
= srcdest_route_next(o_rn
)) {
559 RNODE_FOREACH_RE (o_rn
, o_re
) {
560 if (o_re
->type
== ZEBRA_ROUTE_PBR
)
566 * If we have a PBR route and a nexthop changes
567 * just rethink it. Yes this is a hammer, but
571 SET_FLAG(o_re
->status
, ROUTE_ENTRY_CHANGED
);
578 static void zebra_rnh_process_static_routes(vrf_id_t vrfid
, int family
,
579 struct route_node
*nrn
,
581 struct route_node
*prn
,
582 struct route_entry
*re
)
584 struct listnode
*node
;
585 int num_resolving_nh
= 0;
586 struct route_node
*static_rn
;
587 struct route_entry
*sre
;
588 struct nexthop
*nexthop
;
589 char bufn
[INET6_ADDRSTRLEN
];
590 char bufp
[INET6_ADDRSTRLEN
];
591 char bufs
[INET6_ADDRSTRLEN
];
593 if (IS_ZEBRA_DEBUG_NHT
) {
594 prefix2str(&nrn
->p
, bufn
, INET6_ADDRSTRLEN
);
596 prefix2str(&prn
->p
, bufp
, INET6_ADDRSTRLEN
);
600 /* Apply route-map for "static" to route resolving this
601 * nexthop to see if it is filtered or not.
603 num_resolving_nh
= zebra_rnh_apply_nht_rmap(family
, prn
, re
,
605 if (num_resolving_nh
)
606 rnh
->filtered
[ZEBRA_ROUTE_STATIC
] = 0;
608 rnh
->filtered
[ZEBRA_ROUTE_STATIC
] = 1;
610 rnh
->filtered
[ZEBRA_ROUTE_STATIC
] = 0;
612 /* Evaluate each static route associated with this nexthop. */
613 for (ALL_LIST_ELEMENTS_RO(rnh
->zebra_static_route_list
, node
,
615 RNODE_FOREACH_RE (static_rn
, sre
) {
616 if (sre
->type
!= ZEBRA_ROUTE_STATIC
)
619 /* Set the filter flag for the correct nexthop - static
621 * be having multiple. We care here only about
622 * registered nexthops.
624 for (nexthop
= sre
->ng
.nexthop
; nexthop
;
625 nexthop
= nexthop
->next
) {
626 switch (nexthop
->type
) {
627 case NEXTHOP_TYPE_IPV4
:
628 case NEXTHOP_TYPE_IPV4_IFINDEX
:
629 if (nexthop
->gate
.ipv4
.s_addr
630 == nrn
->p
.u
.prefix4
.s_addr
) {
631 if (num_resolving_nh
)
634 NEXTHOP_FLAG_FILTERED
);
638 NEXTHOP_FLAG_FILTERED
);
641 case NEXTHOP_TYPE_IPV6
:
642 case NEXTHOP_TYPE_IPV6_IFINDEX
:
644 if (memcmp(&nexthop
->gate
.ipv6
,
645 &nrn
->p
.u
.prefix6
, 16)
647 if (num_resolving_nh
)
650 NEXTHOP_FLAG_FILTERED
);
654 NEXTHOP_FLAG_FILTERED
);
662 if (IS_ZEBRA_DEBUG_NHT
) {
663 prefix2str(&static_rn
->p
, bufs
,
667 "%u:%s: NH change %s, scheduling static route %s",
671 : "(filtered by route-map)",
675 "%u:%s: NH unreachable, scheduling static route %s",
679 SET_FLAG(sre
->status
, ROUTE_ENTRY_CHANGED
);
680 SET_FLAG(sre
->status
, ROUTE_ENTRY_NEXTHOPS_CHANGED
);
683 rib_queue_add(static_rn
);
688 * Determine appropriate route (route entry) resolving a tracked
691 static struct route_entry
*
692 zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid
, int family
,
693 struct route_node
*nrn
, struct rnh
*rnh
,
694 struct route_node
**prn
)
696 struct route_table
*route_table
;
697 struct route_node
*rn
;
698 struct route_entry
*re
;
702 route_table
= zebra_vrf_table(family2afi(family
), SAFI_UNICAST
, vrfid
);
706 rn
= route_node_match(route_table
, &nrn
->p
);
710 /* Unlock route node - we don't need to lock when walking the tree. */
711 route_unlock_node(rn
);
713 /* While resolving nexthops, we may need to walk up the tree from the
714 * most-specific match. Do similar logic as in zebra_rib.c
717 /* Do not resolve over default route unless allowed &&
718 * match route to be exact if so specified
720 if (is_default_prefix(&rn
->p
)
721 && !rnh_resolve_via_default(rn
->p
.family
))
724 /* Identify appropriate route entry. */
725 RNODE_FOREACH_RE (rn
, re
) {
726 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
))
728 if (!CHECK_FLAG(re
->flags
, ZEBRA_FLAG_SELECTED
))
731 if (CHECK_FLAG(rnh
->flags
, ZEBRA_NHT_CONNECTED
)) {
732 if ((re
->type
== ZEBRA_ROUTE_CONNECT
)
733 || (re
->type
== ZEBRA_ROUTE_STATIC
))
735 if (re
->type
== ZEBRA_ROUTE_NHRP
) {
736 struct nexthop
*nexthop
;
738 for (nexthop
= re
->ng
.nexthop
; nexthop
;
739 nexthop
= nexthop
->next
)
741 == NEXTHOP_TYPE_IFINDEX
)
750 /* Route entry found, we're done; else, walk up the tree. */
756 if (CHECK_FLAG(rnh
->flags
, ZEBRA_NHT_CONNECTED
))
765 static void zebra_rnh_process_pseudowires(vrf_id_t vrfid
, struct rnh
*rnh
)
768 struct listnode
*node
;
770 for (ALL_LIST_ELEMENTS_RO(rnh
->zebra_pseudowire_list
, node
, pw
))
775 * See if a tracked nexthop entry has undergone any change, and if so,
776 * take appropriate action; this involves notifying any clients and/or
777 * scheduling dependent static routes for processing.
779 static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid
, int family
, int force
,
780 struct route_node
*nrn
,
782 struct route_node
*prn
,
783 struct route_entry
*re
)
785 int state_changed
= 0;
787 /* If we're resolving over a different route, resolution has changed or
788 * the resolving route has some change (e.g., metric), there is a state
791 if (!prefix_same(&rnh
->resolved_route
, &prn
->p
)) {
793 prefix_copy(&rnh
->resolved_route
, &prn
->p
);
795 memset(&rnh
->resolved_route
, 0, sizeof(struct prefix
));
797 copy_state(rnh
, re
, nrn
);
799 } else if (compare_state(re
, rnh
->state
)) {
800 copy_state(rnh
, re
, nrn
);
804 if (state_changed
|| force
) {
805 /* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
808 /* Notify registered protocol clients. */
809 zebra_rnh_notify_protocol_clients(vrfid
, family
, nrn
, rnh
, prn
,
812 /* Process static routes attached to this nexthop */
813 zebra_rnh_process_static_routes(vrfid
, family
, nrn
, rnh
, prn
,
816 zebra_rnh_process_pbr_tables(family
, nrn
, rnh
, prn
,
819 /* Process pseudowires attached to this nexthop */
820 zebra_rnh_process_pseudowires(vrfid
, rnh
);
824 /* Evaluate one tracked entry */
825 static void zebra_rnh_evaluate_entry(vrf_id_t vrfid
, int family
, int force
,
826 rnh_type_t type
, struct route_node
*nrn
)
829 struct route_entry
*re
;
830 struct route_node
*prn
;
831 char bufn
[INET6_ADDRSTRLEN
];
833 if (IS_ZEBRA_DEBUG_NHT
) {
834 prefix2str(&nrn
->p
, bufn
, INET6_ADDRSTRLEN
);
835 zlog_debug("%u:%s: Evaluate RNH, type %d %s", vrfid
, bufn
, type
,
836 force
? "(force)" : "");
841 /* Identify route entry (RE) resolving this tracked entry. */
842 if (type
== RNH_IMPORT_CHECK_TYPE
)
843 re
= zebra_rnh_resolve_import_entry(vrfid
, family
, nrn
, rnh
,
846 re
= zebra_rnh_resolve_nexthop_entry(vrfid
, family
, nrn
, rnh
,
849 /* If the entry cannot be resolved and that is also the existing state,
850 * there is nothing further to do.
852 if (!re
&& rnh
->state
== NULL
&& !force
)
855 /* Process based on type of entry. */
856 if (type
== RNH_IMPORT_CHECK_TYPE
)
857 zebra_rnh_eval_import_check_entry(vrfid
, family
, force
, nrn
,
860 zebra_rnh_eval_nexthop_entry(vrfid
, family
, force
, nrn
, rnh
,
865 * Clear the ROUTE_ENTRY_NEXTHOPS_CHANGED flag
866 * from the re entries.
868 * Please note we are doing this *after* we have
869 * notified the world about each nexthop as that
870 * we can have a situation where one re entry
871 * covers multiple nexthops we are interested in.
873 static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid
, int family
,
874 rnh_type_t type
, struct route_node
*nrn
)
877 struct route_entry
*re
;
878 struct route_node
*prn
;
882 /* Identify route entry (RIB) resolving this tracked entry. */
883 if (type
== RNH_IMPORT_CHECK_TYPE
)
884 re
= zebra_rnh_resolve_import_entry(vrfid
, family
, nrn
, rnh
,
887 re
= zebra_rnh_resolve_nexthop_entry(vrfid
, family
, nrn
, rnh
,
891 UNSET_FLAG(re
->status
, ROUTE_ENTRY_NEXTHOPS_CHANGED
);
892 UNSET_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
);
896 /* Evaluate all tracked entries (nexthops or routes for import into BGP)
897 * of a particular VRF and address-family or a specific prefix.
899 void zebra_evaluate_rnh(vrf_id_t vrfid
, int family
, int force
, rnh_type_t type
,
902 struct route_table
*rnh_table
;
903 struct route_node
*nrn
;
905 rnh_table
= get_rnh_table(vrfid
, family
, type
);
906 if (!rnh_table
) // unexpected
910 /* Evaluating a specific entry, make sure it exists. */
911 nrn
= route_node_lookup(rnh_table
, p
);
912 if (nrn
&& nrn
->info
)
913 zebra_rnh_evaluate_entry(vrfid
, family
, force
, type
,
917 route_unlock_node(nrn
);
919 /* Evaluate entire table. */
920 nrn
= route_top(rnh_table
);
923 zebra_rnh_evaluate_entry(vrfid
, family
, force
,
925 nrn
= route_next(nrn
); /* this will also unlock nrn */
927 nrn
= route_top(rnh_table
);
930 zebra_rnh_clear_nhc_flag(vrfid
, family
, type
,
932 nrn
= route_next(nrn
); /* this will also unlock nrn */
937 void zebra_print_rnh_table(vrf_id_t vrfid
, int af
, struct vty
*vty
,
940 struct route_table
*table
;
941 struct route_node
*rn
;
943 table
= get_rnh_table(vrfid
, af
, type
);
945 zlog_debug("print_rnhs: rnh table not found\n");
949 for (rn
= route_top(table
); rn
; rn
= route_next(rn
))
955 * free_state - free up the re structure associated with the rnh.
957 static void free_state(vrf_id_t vrf_id
, struct route_entry
*re
,
958 struct route_node
*rn
)
964 /* free RE and nexthops */
965 zebra_deregister_rnh_static_nexthops(vrf_id
, re
->ng
.nexthop
, rn
);
966 nexthops_free(re
->ng
.nexthop
);
970 static void copy_state(struct rnh
*rnh
, struct route_entry
*re
,
971 struct route_node
*rn
)
973 struct route_entry
*state
;
976 free_state(rnh
->vrf_id
, rnh
->state
, rn
);
983 state
= XCALLOC(MTYPE_RE
, sizeof(struct route_entry
));
984 state
->type
= re
->type
;
985 state
->distance
= re
->distance
;
986 state
->metric
= re
->metric
;
987 state
->vrf_id
= re
->vrf_id
;
989 route_entry_copy_nexthops(state
, re
->ng
.nexthop
);
993 static int compare_state(struct route_entry
*r1
, struct route_entry
*r2
)
999 if ((!r1
&& r2
) || (r1
&& !r2
))
1002 if (r1
->distance
!= r2
->distance
)
1005 if (r1
->metric
!= r2
->metric
)
1008 if (r1
->nexthop_num
!= r2
->nexthop_num
)
1011 if (CHECK_FLAG(r1
->status
, ROUTE_ENTRY_NEXTHOPS_CHANGED
)
1012 || CHECK_FLAG(r1
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
1018 static int send_client(struct rnh
*rnh
, struct zserv
*client
, rnh_type_t type
,
1022 struct route_entry
*re
;
1026 struct route_node
*rn
;
1027 int cmd
= (type
== RNH_IMPORT_CHECK_TYPE
) ? ZEBRA_IMPORT_CHECK_UPDATE
1028 : ZEBRA_NEXTHOP_UPDATE
;
1033 /* Get output stream. */
1034 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1036 zclient_create_header(s
, cmd
, vrf_id
);
1038 stream_putw(s
, rn
->p
.family
);
1039 switch (rn
->p
.family
) {
1041 stream_putc(s
, rn
->p
.prefixlen
);
1042 stream_put_in_addr(s
, &rn
->p
.u
.prefix4
);
1045 stream_putc(s
, rn
->p
.prefixlen
);
1046 stream_put(s
, &rn
->p
.u
.prefix6
, IPV6_MAX_BYTELEN
);
1049 zlog_err("%s: Unknown family (%d) notification attempted\n",
1050 __FUNCTION__
, rn
->p
.family
);
1054 stream_putc(s
, re
->type
);
1055 stream_putw(s
, re
->instance
);
1056 stream_putc(s
, re
->distance
);
1057 stream_putl(s
, re
->metric
);
1059 nump
= stream_get_endp(s
);
1061 for (nh
= re
->ng
.nexthop
; nh
; nh
= nh
->next
)
1062 if ((CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_FIB
)
1063 || CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1064 && CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
1065 stream_putc(s
, nh
->type
);
1067 case NEXTHOP_TYPE_IPV4
:
1068 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1069 stream_put_in_addr(s
, &nh
->gate
.ipv4
);
1070 stream_putl(s
, nh
->ifindex
);
1072 case NEXTHOP_TYPE_IFINDEX
:
1073 stream_putl(s
, nh
->ifindex
);
1075 case NEXTHOP_TYPE_IPV6
:
1076 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1077 stream_put(s
, &nh
->gate
.ipv6
, 16);
1078 stream_putl(s
, nh
->ifindex
);
1086 nh
->nh_label
->num_labels
);
1087 if (nh
->nh_label
->num_labels
)
1090 &nh
->nh_label
->label
[0],
1091 nh
->nh_label
->num_labels
1092 * sizeof(mpls_label_t
));
1097 stream_putc_at(s
, nump
, num
);
1099 stream_putc(s
, 0); // type
1100 stream_putw(s
, 0); // instance
1101 stream_putc(s
, 0); // distance
1102 stream_putl(s
, 0); // metric
1103 stream_putc(s
, 0); // nexthops
1105 stream_putw_at(s
, 0, stream_get_endp(s
));
1107 client
->nh_last_upd_time
= monotime(NULL
);
1108 client
->last_write_cmd
= cmd
;
1109 return zserv_send_message(client
, s
);
1112 static void print_nh(struct nexthop
*nexthop
, struct vty
*vty
)
1115 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
1117 switch (nexthop
->type
) {
1118 case NEXTHOP_TYPE_IPV4
:
1119 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1120 vty_out(vty
, " via %s", inet_ntoa(nexthop
->gate
.ipv4
));
1121 if (nexthop
->ifindex
)
1122 vty_out(vty
, ", %s",
1123 ifindex2ifname_per_ns(zns
, nexthop
->ifindex
));
1125 case NEXTHOP_TYPE_IPV6
:
1126 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1128 inet_ntop(AF_INET6
, &nexthop
->gate
.ipv6
, buf
, BUFSIZ
));
1129 if (nexthop
->ifindex
)
1130 vty_out(vty
, ", via %s",
1131 ifindex2ifname_per_ns(zns
, nexthop
->ifindex
));
1133 case NEXTHOP_TYPE_IFINDEX
:
1134 vty_out(vty
, " is directly connected, %s",
1135 ifindex2ifname_per_ns(zns
, nexthop
->ifindex
));
1137 case NEXTHOP_TYPE_BLACKHOLE
:
1138 vty_out(vty
, " is directly connected, Null0");
1146 static void print_rnh(struct route_node
*rn
, struct vty
*vty
)
1149 struct nexthop
*nexthop
;
1150 struct listnode
*node
;
1151 struct zserv
*client
;
1155 vty_out(vty
, "%s%s\n",
1156 inet_ntop(rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
1157 CHECK_FLAG(rnh
->flags
, ZEBRA_NHT_CONNECTED
) ? "(Connected)"
1160 vty_out(vty
, " resolved via %s\n",
1161 zebra_route_string(rnh
->state
->type
));
1162 for (nexthop
= rnh
->state
->ng
.nexthop
; nexthop
;
1163 nexthop
= nexthop
->next
)
1164 print_nh(nexthop
, vty
);
1166 vty_out(vty
, " unresolved%s\n",
1167 CHECK_FLAG(rnh
->flags
, ZEBRA_NHT_CONNECTED
)
1171 vty_out(vty
, " Client list:");
1172 for (ALL_LIST_ELEMENTS_RO(rnh
->client_list
, node
, client
))
1173 vty_out(vty
, " %s(fd %d)%s", zebra_route_string(client
->proto
),
1175 rnh
->filtered
[client
->proto
] ? "(filtered)" : "");
1176 if (!list_isempty(rnh
->zebra_static_route_list
))
1177 vty_out(vty
, " zebra%s",
1178 rnh
->filtered
[ZEBRA_ROUTE_STATIC
] ? "(filtered)" : "");
1179 if (!list_isempty(rnh
->zebra_pseudowire_list
))
1180 vty_out(vty
, " zebra[pseudowires]");
1184 static int zebra_cleanup_rnh_client(vrf_id_t vrf_id
, int family
,
1185 struct zserv
*client
, rnh_type_t type
)
1187 struct route_table
*ntable
;
1188 struct route_node
*nrn
;
1191 if (IS_ZEBRA_DEBUG_NHT
)
1192 zlog_debug("%u: Client %s RNH cleanup for family %d type %d",
1193 vrf_id
, zebra_route_string(client
->proto
), family
,
1196 ntable
= get_rnh_table(vrf_id
, family
, type
);
1198 zlog_debug("cleanup_rnh_client: rnh table not found\n");
1202 for (nrn
= route_top(ntable
); nrn
; nrn
= route_next(nrn
)) {
1207 zebra_remove_rnh_client(rnh
, client
, type
);
1212 /* Cleanup registered nexthops (across VRFs) upon client disconnect. */
1213 static int zebra_client_cleanup_rnh(struct zserv
*client
)
1216 struct zebra_vrf
*zvrf
;
1218 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
) {
1221 zebra_cleanup_rnh_client(zvrf_id(zvrf
), AF_INET
, client
,
1223 zebra_cleanup_rnh_client(zvrf_id(zvrf
), AF_INET6
,
1224 client
, RNH_NEXTHOP_TYPE
);
1225 zebra_cleanup_rnh_client(zvrf_id(zvrf
), AF_INET
, client
,
1226 RNH_IMPORT_CHECK_TYPE
);
1227 zebra_cleanup_rnh_client(zvrf_id(zvrf
), AF_INET6
,
1228 client
, RNH_IMPORT_CHECK_TYPE
);
1229 if (client
->proto
== ZEBRA_ROUTE_LDP
) {
1230 hash_iterate(zvrf
->lsp_table
,
1231 mpls_ldp_lsp_uninstall_all
,
1233 mpls_ldp_ftn_uninstall_all(zvrf
, AFI_IP
);
1234 mpls_ldp_ftn_uninstall_all(zvrf
, AFI_IP6
);