From: Donald Sharp Date: Wed, 20 May 2015 01:04:20 +0000 (-0700) Subject: bgpd-nht-import-check-fix.patch X-Git-Tag: frr-2.0-rc1~1394 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=078430f609ecd4a4e3d9690662a396c36bff53f7;p=mirror%2Ffrr.git bgpd-nht-import-check-fix.patch BGP: Fix network import check use with NHT instead of scanner When next hop tracking was implemented and the bgp scanner was eliminated, the "network import-check" command got broken. This patch fixes that issue. NHT is used to not just track nexthops, but also the static routes that are announced as part of BGP's network command. The routes are registered only when import-check is enabled. To optimize performance, we register static routes only when import-check is enabled. Signed-off-by: Dinesh G Dutt --- diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 850ea91e99..cdbc5cc384 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -48,11 +48,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* Route table for next-hop lookup cache. */ struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; -static struct bgp_table *cache1_table[AFI_MAX]; /* Route table for connected route. */ static struct bgp_table *bgp_connected_table[AFI_MAX]; +/* Route table for import-check */ +struct bgp_table *bgp_import_check_table[AFI_MAX]; char * bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) @@ -571,15 +572,14 @@ DEFUN (show_ip_bgp_nexthop_detail, void bgp_scan_init (void) { - cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); - bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP]; - + bgp_nexthop_cache_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); + bgp_import_check_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); #ifdef HAVE_IPV6 - cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); - bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; + bgp_nexthop_cache_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); + bgp_import_check_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); #endif /* HAVE_IPV6 */ } @@ -599,20 +599,26 @@ bgp_scan_finish (void) /* Only the current one needs to be reset. */ bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]); - bgp_table_unlock (cache1_table[AFI_IP]); - cache1_table[AFI_IP] = NULL; + bgp_table_unlock (bgp_nexthop_cache_table[AFI_IP]); + bgp_nexthop_cache_table[AFI_IP] = NULL; bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; + bgp_table_unlock (bgp_import_check_table[AFI_IP]); + bgp_import_check_table[AFI_IP] = NULL; + #ifdef HAVE_IPV6 /* Only the current one needs to be reset. */ bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]); - bgp_table_unlock (cache1_table[AFI_IP6]); - cache1_table[AFI_IP6] = NULL; + bgp_table_unlock (bgp_nexthop_cache_table[AFI_IP6]); + bgp_nexthop_cache_table[AFI_IP6] = NULL; bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; + + bgp_table_unlock (bgp_import_check_table[AFI_IP6]); + bgp_import_check_table[AFI_IP6] = NULL; #endif /* HAVE_IPV6 */ } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index cee967303f..9c9f909625 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -41,6 +41,8 @@ struct bgp_nexthop_cache #define BGP_NEXTHOP_REGISTERED (1 << 1) #define BGP_NEXTHOP_CONNECTED (1 << 2) #define BGP_NEXTHOP_PEER_NOTIFIED (1 << 3) +#define BGP_STATIC_ROUTE (1 << 4) +#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5) u_int16_t change_flags; diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index b76cf0248b..061746fc42 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -41,9 +41,12 @@ extern struct zclient *zclient; extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; +extern struct bgp_table *bgp_import_check_table[AFI_MAX]; -static void register_nexthop(struct bgp_nexthop_cache *bnc); -static void unregister_nexthop (struct bgp_nexthop_cache *bnc); +static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, + int is_bgp_static_route); +static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, + int is_bgp_static_route); static void evaluate_paths(struct bgp_nexthop_cache *bnc); static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p); static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, @@ -81,7 +84,7 @@ bgp_unlink_nexthop (struct bgp_info *path) zlog_debug("bgp_unlink_nexthop: freeing bnc %s", bnc_str(bnc, buf, INET6_ADDRSTRLEN)); } - unregister_nexthop(bnc); + unregister_zebra_rnh(bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); bnc->node->info = NULL; bgp_unlock_node(bnc->node); bnc_free(bnc); @@ -95,12 +98,15 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri, struct bgp_node *rn; struct bgp_nexthop_cache *bnc; struct prefix p; + int is_bgp_static_route = 0; if (ri) { /* This will return TRUE if the global IPv6 NH is a link local addr */ if (make_prefix(afi, ri, &p) < 0) return 1; + is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) && + (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0; } else if (peer) { @@ -133,7 +139,10 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri, else return 0; - rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); + if (is_bgp_static_route) + rn = bgp_node_get (bgp_import_check_table[afi], &p); + else + rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); if (!rn->info) { @@ -142,13 +151,11 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri, bnc->node = rn; bnc->bgp = bgp; bgp_lock_node(rn); - if (connected) - SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; - zlog_debug("Allocated bnc %s peer %p", + zlog_debug("Allocated bnc %s peer %p", bnc_str(bnc, buf, INET6_ADDRSTRLEN), peer); } } @@ -156,8 +163,41 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri, bnc = rn->info; bgp_unlock_node (rn); + if (is_bgp_static_route) + { + SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); + + /* If we're toggling the type, re-register */ + if ((bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) && + !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) + { + SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + } + else if ((!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) && + CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) + { + UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + } + } + else if (connected && ! CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + { + SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + } + else if (!connected && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + { + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + } + if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) - register_nexthop(bnc); + register_zebra_rnh(bnc, is_bgp_static_route); if (ri) { @@ -231,7 +271,7 @@ bgp_delete_connected_nexthop (afi_t afi, struct peer *peer) if (BGP_DEBUG(nht, NHT)) zlog_debug("Freeing connected NHT node %p for peer %s", bnc, peer->host); - unregister_nexthop(bnc); + unregister_zebra_rnh(bnc, 0); bnc->node->info = NULL; bgp_unlock_node(bnc->node); bnc_free(bnc); @@ -239,7 +279,7 @@ bgp_delete_connected_nexthop (afi_t afi, struct peer *peer) } void -bgp_parse_nexthop_update (void) +bgp_parse_nexthop_update (int command) { struct stream *s; struct bgp_node *rn; @@ -270,7 +310,11 @@ bgp_parse_nexthop_update (void) break; } - rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p); + if (command == ZEBRA_NEXTHOP_UPDATE) + rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p); + else if (command == ZEBRA_IMPORT_CHECK_UPDATE) + rn = bgp_node_lookup(bgp_import_check_table[family2afi(p.family)], &p); + if (!rn || !rn->info) { if (BGP_DEBUG(nht, NHT)) @@ -398,13 +442,25 @@ bgp_parse_nexthop_update (void) static int make_prefix (int afi, struct bgp_info *ri, struct prefix *p) { + + int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP) && + (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0; + memset (p, 0, sizeof (struct prefix)); switch (afi) { case AFI_IP: p->family = AF_INET; - p->prefixlen = IPV4_MAX_BITLEN; - p->u.prefix4 = ri->attr->nexthop; + if (is_bgp_static) + { + p->u.prefix4 = ri->net->p.u.prefix4; + p->prefixlen = ri->net->p.prefixlen; + } + else + { + p->u.prefix4 = ri->attr->nexthop; + p->prefixlen = IPV4_MAX_BITLEN; + } break; #ifdef HAVE_IPV6 case AFI_IP6: @@ -414,8 +470,17 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p) return -1; p->family = AF_INET6; - p->prefixlen = IPV6_MAX_BITLEN; - p->u.prefix6 = ri->attr->extra->mp_nexthop_global; + + if (is_bgp_static) + { + p->u.prefix6 = ri->net->p.u.prefix6; + p->prefixlen = ri->net->p.prefixlen; + } + else + { + p->u.prefix6 = ri->attr->extra->mp_nexthop_global; + p->prefixlen = IPV6_MAX_BITLEN; + } break; #endif default: @@ -430,16 +495,16 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p) } /** - * sendmsg_nexthop -- Format and send a nexthop register/Unregister + * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister * command to Zebra. * ARGUMENTS: * struct bgp_nexthop_cache *bnc -- the nexthop structure. - * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER + * int command -- command to send to zebra * RETURNS: * void. */ static void -sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) +sendmsg_zebra_rnh (struct bgp_nexthop_cache *bnc, int command) { struct stream *s; struct prefix *p; @@ -457,7 +522,8 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) s = zclient->obuf; stream_reset (s); zclient_create_header (s, command); - if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) || + CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) stream_putc(s, 1); else stream_putc(s, 0); @@ -484,45 +550,53 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) if (ret < 0) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); - if (command == ZEBRA_NEXTHOP_REGISTER) + if ((command == ZEBRA_NEXTHOP_REGISTER) || + (command == ZEBRA_IMPORT_ROUTE_REGISTER)) SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); - else if (command == ZEBRA_NEXTHOP_UNREGISTER) + else if ((command == ZEBRA_NEXTHOP_UNREGISTER) || + (command == ZEBRA_IMPORT_ROUTE_UNREGISTER)) UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); return; } /** - * register_nexthop - register a nexthop with Zebra for notification - * when the route to the nexthop changes. + * register_zebra_rnh - register a NH/route with Zebra for notification + * when the route or the route to the nexthop changes. * ARGUMENTS: - * struct bgp_nexthop_cache *bnc -- the nexthop structure. + * struct bgp_nexthop_cache *bnc * RETURNS: * void. */ static void -register_nexthop (struct bgp_nexthop_cache *bnc) +register_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route) { /* Check if we have already registered */ if (bnc->flags & BGP_NEXTHOP_REGISTERED) return; - sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER); + if (is_bgp_import_route) + sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER); + else + sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); } /** - * unregister_nexthop -- Unregister the nexthop from Zebra. + * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra. * ARGUMENTS: - * struct bgp_nexthop_cache *bnc -- the nexthop structure. + * struct bgp_nexthop_cache *bnc * RETURNS: * void. */ static void -unregister_nexthop (struct bgp_nexthop_cache *bnc) +unregister_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route) { /* Check if we have already registered */ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) return; - sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER); + if (is_bgp_import_route) + sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER); + else + sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); } /** @@ -544,7 +618,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) LIST_FOREACH(path, &(bnc->paths), nh_thread) { if (!(path->type == ZEBRA_ROUTE_BGP && - path->sub_type == BGP_ROUTE_NORMAL)) + (path->sub_type == BGP_ROUTE_NORMAL) || + (path->sub_type == BGP_ROUTE_STATIC))) continue; rn = path->net; diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 963dd00f27..952268789f 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -25,7 +25,7 @@ /** * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra. */ -extern void bgp_parse_nexthop_update(); +extern void bgp_parse_nexthop_update(int command); /** * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b29d6ea884..55c2f13927 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4461,7 +4461,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, if (ri) { if (attrhash_cmp (ri->attr, attr_new) && - !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) && + !bgp_flag_check(bgp, BGP_FLAG_FORCE_STATIC_PROCESS)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); @@ -4491,13 +4492,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, (const void *)&attr_new->nexthop, - buf1, INET6_ADDRSTRLEN); - zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + inet_ntop (p->family, &p->u.prefix, buf1, + INET6_ADDRSTRLEN); + zlog_debug("%s(%s): Route not in table, not advertising", + __FUNCTION__, buf1); } bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } } + else + { + /* Delete the NHT structure if any, if we're toggling between + * enabling/disabling import check. We deregister the route + * from NHT to avoid overloading NHT and the process interaction + */ + bgp_unlink_nexthop(ri); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + } /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); @@ -4520,15 +4531,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, (const void *)&attr_new->nexthop, - buf1, INET6_ADDRSTRLEN); - zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + inet_ntop(p->family, &p->u.prefix, buf1, + INET6_ADDRSTRLEN); + zlog_debug("%s(%s): Route not in table, not advertising", __FUNCTION__, + buf1); } bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } } else - bgp_info_set_flag (rn, new, BGP_INFO_VALID); + { + /* Delete the NHT structure if any, if we're toggling between + * enabling/disabling import check. We deregister the route + * from NHT to avoid overloading NHT and the process interaction + */ + bgp_unlink_nexthop(new); + bgp_info_set_flag (rn, new, BGP_INFO_VALID); + } /* Register new BGP information. */ bgp_info_add (rn, new); @@ -4608,7 +4627,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (ri) { if (attrhash_cmp (ri->attr, attr_new) && - !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) && + !bgp_flag_check(bgp, BGP_FLAG_FORCE_STATIC_PROCESS)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); @@ -4640,13 +4660,23 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, (const void *)&attr_new->nexthop, - buf1, INET6_ADDRSTRLEN); - zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + inet_ntop(p->family, &p->u.prefix, buf1, + INET6_ADDRSTRLEN); + zlog_debug("%s(%s): Route not in table, not advertising", + __FUNCTION__, buf1); } bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } } + else + { + /* Delete the NHT structure if any, if we're toggling between + * enabling/disabling import check. We deregister the route + * from NHT to avoid overloading NHT and the process interaction + */ + bgp_unlink_nexthop(ri); + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + } /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); @@ -4670,15 +4700,24 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, + inet_ntop(p->family, &p->u.prefix, buf1, INET6_ADDRSTRLEN); - zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); + zlog_debug("%s(%s): Route not in table, not advertising", + __FUNCTION__, buf1); } bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } } else - bgp_info_set_flag (rn, new, BGP_INFO_VALID); + { + /* Delete the NHT structure if any, if we're toggling between + * enabling/disabling import check. We deregister the route + * from NHT to avoid overloading NHT and the process interaction + */ + bgp_unlink_nexthop(new); + + bgp_info_set_flag (rn, new, BGP_INFO_VALID); + } /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); @@ -5005,6 +5044,29 @@ bgp_static_delete (struct bgp *bgp) } } +void +bgp_static_redo_import_check (struct bgp *bgp) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_table *table; + struct bgp_static *bgp_static; + + /* Use this flag to force reprocessing of the route */ + bgp_flag_set(bgp, BGP_FLAG_FORCE_STATIC_PROCESS); + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) + if (rn->info != NULL) + { + bgp_static = rn->info; + bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); + } + bgp_flag_unset(bgp, BGP_FLAG_FORCE_STATIC_PROCESS); +} + int bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, const char *tag_str) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index d771458051..c15b824061 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -250,6 +250,7 @@ extern void bgp_redistribute_delete (struct prefix *, u_char, u_short); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int, u_short); extern void bgp_static_delete (struct bgp *); +extern void bgp_static_redo_import_check (struct bgp *); extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *, afi_t, safi_t); extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 7852371fc3..4152b8cd2e 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2114,21 +2114,45 @@ DEFUN (bgp_default_ipv4_unicast, /* "bgp import-check" configuration. */ DEFUN (bgp_network_import_check, bgp_network_import_check_cmd, - "bgp network import-check", + "bgp network import-check {exact}", "BGP specific commands\n" "BGP network command\n" - "Check BGP network route exists in IGP\n") + "Check BGP network route exists in IGP\n" + "Match route precisely") { struct bgp *bgp; + int trigger = 0; bgp = vty->index; - bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); + if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) + { + bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); + trigger = 1; + } + + if (argv[0] != NULL) + { + if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) + { + bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH); + trigger = 1; + } + } + else if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) + { + bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH); + trigger = 1; + } + + if (trigger) + bgp_static_redo_import_check(bgp); + return CMD_SUCCESS; } DEFUN (no_bgp_network_import_check, no_bgp_network_import_check_cmd, - "no bgp network import-check", + "no bgp network import-check {exact}", NO_STR "BGP specific commands\n" "BGP network command\n" @@ -2137,7 +2161,12 @@ DEFUN (no_bgp_network_import_check, struct bgp *bgp; bgp = vty->index; - bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); + if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) + { + bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); + bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH); + bgp_static_redo_import_check(bgp); + } return CMD_SUCCESS; } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 16f61d03fa..2983024d57 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -119,7 +119,15 @@ static int bgp_read_nexthop_update (int command, struct zclient *zclient, zebra_size_t length) { - bgp_parse_nexthop_update(); + bgp_parse_nexthop_update(command); + return 0; +} + +static int +bgp_read_import_check_update(int command, struct zclient *zclient, + zebra_size_t length) +{ + bgp_parse_nexthop_update(command); return 0; } @@ -1665,6 +1673,7 @@ bgp_zebra_init (void) zclient->ipv6_route_delete = zebra_read_ipv6; #endif /* HAVE_IPV6 */ zclient->nexthop_update = bgp_read_nexthop_update; + zclient->import_check_update = bgp_read_import_check_update; /* Interface related init. */ if_init (); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index dce10886bb..eb61d8b401 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6408,7 +6408,9 @@ bgp_config_write (struct vty *vty) } /* BGP network import check. */ - if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) + vty_out (vty, " bgp network import-check exact%s", VTY_NEWLINE); + else if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); /* BGP flag dampening. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index ed555051b5..fc8683f2bd 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -239,6 +239,8 @@ struct bgp #define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15) #define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 16) #define BGP_FLAG_MULTIPATH_RELAX_NO_AS_SET (1 << 17) +#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 18) +#define BGP_FLAG_IMPORT_CHECK_EXACT_MATCH (1 << 19) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; diff --git a/lib/log.c b/lib/log.c index 4acc0cab83..e15f3d50df 100644 --- a/lib/log.c +++ b/lib/log.c @@ -835,6 +835,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE), DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_ADD), DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE), + DESC_ENTRY (ZEBRA_IMPORT_CHECK_UPDATE), }; #undef DESC_ENTRY diff --git a/lib/zclient.c b/lib/zclient.c index 29f568f2ad..f6ac924573 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -134,42 +134,6 @@ redist_del_instance (struct redist_proto *red, u_short instance) } } -/* Initialize zebra client. Argument redist_default is unwanted - redistribute route type. */ -void -zclient_init (struct zclient *zclient, int redist_default, u_short instance) -{ - int afi, i; - - /* Enable zebra client connection by default. */ - zclient->enable = 1; - - /* Set -1 to the default socket value. */ - zclient->sock = -1; - - /* Clear redistribution flags. */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - memset(&zclient->redist[afi][i], 0, sizeof(struct redist_proto)); - - /* Set unwanted redistribute route. bgpd does not need BGP route - redistribution. */ - zclient->redist_default = redist_default; - zclient->instance = instance; - /* Pending: make afi(s) an arg. */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - redist_add_instance (&zclient->redist[afi][redist_default], instance); - - /* Set default-information redistribute to zero. */ - zclient->default_information = 0; - - /* Schedule first zclient connection. */ - if (zclient_debug) - zlog_debug ("zclient start scheduled"); - - zclient_event (ZCLIENT_SCHEDULE, zclient); -} - /* Stop zebra client services. */ void zclient_stop (struct zclient *zclient) @@ -405,13 +369,6 @@ zclient_start (struct zclient *zclient) int i; afi_t afi; - if (zclient_debug) - zlog_debug ("zclient_start is called"); - - /* zclient is disabled. */ - if (! zclient->enable) - return 0; - /* If already connected to the zebra. */ if (zclient->sock >= 0) return 0; @@ -420,34 +377,6 @@ zclient_start (struct zclient *zclient) if (zclient->t_connect) return 0; - if (zclient_socket_connect(zclient) < 0) - { - if (zclient_debug) - zlog_debug ("zclient connection fail"); - zclient->fail++; - zclient_event (ZCLIENT_CONNECT, zclient); - return -1; - } - - if (set_nonblocking(zclient->sock) < 0) - zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock); - - /* Clear fail count. */ - zclient->fail = 0; - if (zclient_debug) - zlog_debug ("zclient connect success with socket [%d]", zclient->sock); - - /* Create read thread. */ - zclient_event (ZCLIENT_READ, zclient); - - zebra_hello_send (zclient); - - /* We need router-id information. */ - zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD); - - /* We need interface information. */ - zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); - /* Flush all redistribute request. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) @@ -484,6 +413,73 @@ zclient_connect (struct thread *t) return zclient_start (zclient); } +/* Initialize zebra client. Argument redist_default is unwanted + redistribute route type. */ +void +zclient_init (struct zclient *zclient, int redist_default, u_short instance) +{ + int afi, i; + + /* Enable zebra client connection by default. */ + zclient->enable = 1; + + /* Set -1 to the default socket value. */ + zclient->sock = -1; + + /* Clear redistribution flags. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + memset(&zclient->redist[afi][i], 0, sizeof(struct redist_proto)); + + /* Set unwanted redistribute route. bgpd does not need BGP route + redistribution. */ + zclient->redist_default = redist_default; + zclient->instance = instance; + /* Pending: make afi(s) an arg. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + redist_add_instance (&zclient->redist[afi][redist_default], instance); + + /* Set default-information redistribute to zero. */ + zclient->default_information = 0; + + if (zclient_debug) + zlog_debug ("zclient_start is called"); + + /* zclient is disabled. */ + if (! zclient->enable) + return; + + if (zclient_socket_connect(zclient) < 0) + { + if (zclient_debug) + zlog_debug ("zclient connection fail"); + zclient->fail++; + zclient_event (ZCLIENT_CONNECT, zclient); + return; + } + + if (set_nonblocking(zclient->sock) < 0) + zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock); + + /* Clear fail count. */ + zclient->fail = 0; + if (zclient_debug) + zlog_debug ("zclient connect success with socket [%d]", zclient->sock); + + /* Create read thread. */ + zclient_event (ZCLIENT_READ, zclient); + + zebra_hello_send (zclient); + + /* We need router-id information. */ + zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD); + + /* We need interface information. */ + zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); + + zclient_event (ZCLIENT_SCHEDULE, zclient); +} + /* * "xdr_encode"-like interface that allows daemon (client) to send * a message to zebra server for a route that needs to be @@ -1212,6 +1208,12 @@ zclient_read (struct thread *thread) if (zclient->nexthop_update) (*zclient->nexthop_update) (command, zclient, length); break; + case ZEBRA_IMPORT_CHECK_UPDATE: + if (zclient_debug) + zlog_debug("zclient rcvd import check update\n"); + if (zclient->import_check_update) + (*zclient->import_check_update) (command, zclient, length); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index f73145db00..bb8a87b145 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -93,6 +93,7 @@ struct zclient int (*ipv6_route_add) (int, struct zclient *, uint16_t); int (*ipv6_route_delete) (int, struct zclient *, uint16_t); int (*nexthop_update) (int, struct zclient *, uint16_t); + int (*import_check_update) (int, struct zclient *, uint16_t); }; /* Zebra API message flag. */ diff --git a/lib/zebra.h b/lib/zebra.h index 8b0248a3b6..05e7013c56 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -430,7 +430,10 @@ struct in_pktinfo #define ZEBRA_INTERFACE_NBR_ADDRESS_ADD 27 #define ZEBRA_INTERFACE_NBR_ADDRESS_DELETE 28 #define ZEBRA_INTERFACE_BFD_DEST_DOWN 29 -#define ZEBRA_MESSAGE_MAX 30 +#define ZEBRA_IMPORT_ROUTE_REGISTER 30 +#define ZEBRA_IMPORT_ROUTE_UNREGISTER 31 +#define ZEBRA_IMPORT_CHECK_UPDATE 32 +#define ZEBRA_MESSAGE_MAX 33 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new diff --git a/zebra/rib.h b/zebra/rib.h index 58d3315a9e..038fe44756 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -301,6 +301,9 @@ struct vrf /* Recursive Nexthop table */ struct route_table *rnh_table[AFI_MAX]; + /* Import check table (used mostly by BGP */ + struct route_table *import_check_table[AFI_MAX]; + /* Routing tables off of main table for redistribute table */ struct route_table *other_table[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; }; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 76c26c19ba..f1a44fdda2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -123,6 +123,9 @@ vrf_alloc (const char *name) vrf->rnh_table[AFI_IP] = route_table_init(); vrf->rnh_table[AFI_IP6] = route_table_init(); + vrf->import_check_table[AFI_IP] = route_table_init(); + vrf->import_check_table[AFI_IP6] = route_table_init(); + return vrf; } @@ -1753,9 +1756,11 @@ process_subq (struct list * subq, u_char qindex) static void meta_queue_process_complete (struct work_queue *dummy) { - zebra_evaluate_rnh_table(0, AF_INET, 0); + zebra_evaluate_rnh(0, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(0, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, NULL); #ifdef HAVE_IPV6 - zebra_evaluate_rnh_table(0, AF_INET6, 0); + zebra_evaluate_rnh(0, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(0, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, NULL); #endif /* HAVE_IPV6 */ } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index f698e62e9c..7d9c958f64 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -44,37 +44,48 @@ #include "zebra/debug.h" #include "zebra/zebra_rnh.h" -#define lookup_rnh_table(v, f) \ -({ \ - struct vrf *vrf; \ - struct route_table *t = NULL; \ - vrf = vrf_lookup(v); \ - if (vrf) \ - t = vrf->rnh_table[family2afi(f)]; \ - t; \ -}) - /* Default rtm_table for all clients */ extern struct zebra_t zebrad; static void free_state(struct rib *rib, struct route_node *rn); -static void copy_state(struct rnh *rnh, struct rib *rib, struct route_node *rn); +static void copy_state(struct rnh *rnh, struct rib *rib, + struct route_node *rn); static int compare_state(struct rib *r1, struct rib *r2); -static int send_client(struct rnh *rnh, struct zserv *client); +static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type); static void print_rnh(struct route_node *rn, struct vty *vty); int zebra_rnh_ip_default_route = 0; int zebra_rnh_ipv6_default_route = 0; -char * -rnh_str (struct rnh *rnh, char *buf, int size) +static inline struct route_table *get_rnh_table(int vrfid, int family, + rnh_type_t type) +{ + struct vrf *vrf; + struct route_table *t = NULL; + + vrf = vrf_lookup(vrfid); + if (vrf) + switch (type) + { + case RNH_NEXTHOP_TYPE: + t = vrf->rnh_table[family2afi(family)]; + break; + case RNH_IMPORT_CHECK_TYPE: + t = vrf->import_check_table[family2afi(family)]; + break; + } + + return t; +} + +char *rnh_str (struct rnh *rnh, char *buf, int size) { prefix2str(&(rnh->node->p), buf, size); return buf; } struct rnh * -zebra_add_rnh (struct prefix *p, u_int32_t vrfid) +zebra_add_rnh (struct prefix *p, u_int32_t vrfid, rnh_type_t type) { struct route_table *table; struct route_node *rn; @@ -86,7 +97,7 @@ zebra_add_rnh (struct prefix *p, u_int32_t vrfid) prefix2str(p, buf, INET6_ADDRSTRLEN); zlog_debug("add rnh %s in vrf %d", buf, vrfid); } - table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); + table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type); if (!table) { zlog_debug("add_rnh: rnh table not found\n"); @@ -114,12 +125,12 @@ zebra_add_rnh (struct prefix *p, u_int32_t vrfid) } struct rnh * -zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid) +zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid, rnh_type_t type) { struct route_table *table; struct route_node *rn; - table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); + table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type); if (!table) return NULL; @@ -136,7 +147,7 @@ zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid) } void -zebra_delete_rnh (struct rnh *rnh) +zebra_delete_rnh (struct rnh *rnh, rnh_type_t type) { struct route_node *rn; @@ -160,7 +171,7 @@ zebra_delete_rnh (struct rnh *rnh) } void -zebra_add_rnh_client (struct rnh *rnh, struct zserv *client) +zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type) { if (IS_ZEBRA_DEBUG_NHT) { @@ -172,12 +183,11 @@ zebra_add_rnh_client (struct rnh *rnh, struct zserv *client) if (!listnode_lookup(rnh->client_list, client)) { listnode_add(rnh->client_list, client); - send_client(rnh, client); } } void -zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) +zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type) { if (IS_ZEBRA_DEBUG_NHT) { @@ -189,7 +199,7 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) listnode_delete(rnh->client_list, client); if (list_isempty(rnh->client_list) && list_isempty(rnh->zebra_static_route_list)) - zebra_delete_rnh(rnh); + zebra_delete_rnh(rnh, type); } void @@ -197,7 +207,7 @@ zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) { struct rnh *rnh; - rnh = zebra_add_rnh(nh, 0); + rnh = zebra_add_rnh(nh, 0, RNH_NEXTHOP_TYPE); if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn)) { listnode_add(rnh->zebra_static_route_list, static_rn); @@ -209,7 +219,7 @@ zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) { struct rnh *rnh; - rnh = zebra_lookup_rnh(nh, 0); + rnh = zebra_lookup_rnh(nh, 0, RNH_NEXTHOP_TYPE); if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED)) return; @@ -217,7 +227,7 @@ zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) if (list_isempty(rnh->client_list) && list_isempty(rnh->zebra_static_route_list)) - zebra_delete_rnh(rnh); + zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); } static inline int @@ -276,12 +286,13 @@ zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn, } int -zebra_evaluate_rnh_table (int vrfid, int family, int force) +zebra_evaluate_rnh (int vrfid, int family, int force, rnh_type_t type, + struct prefix *p) { struct route_table *ptable; struct route_table *ntable; - struct route_node *prn; - struct route_node *nrn; + struct route_node *prn = NULL; + struct route_node *nrn = NULL; struct rnh *rnh; struct zserv *client; struct listnode *node; @@ -292,9 +303,10 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) char bufp[INET6_ADDRSTRLEN]; char bufs[INET6_ADDRSTRLEN]; struct route_node *static_rn; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; - ntable = lookup_rnh_table(vrfid, family); + ntable = get_rnh_table(vrfid, family, type); if (!ntable) { zlog_debug("evaluate_rnh_table: rnh table not found\n"); @@ -308,17 +320,38 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) return -1; } - for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) + if (p) + nrn = route_node_lookup(ntable, p); + else + nrn = route_top (ntable); + + while (nrn != NULL) { if (!nrn->info) - continue; + goto loopend; rnh = nrn->info; at_least_one = 0; + /* free stale stuff first */ + if (prn) + route_unlock_node(prn); + prn = route_node_match(ptable, &nrn->p); - if (!prn || (zebra_rnh_is_default_route(&prn->p) && - !zebra_rnh_resolve_via_default(prn->p.family))) + + /* Do not resolve over default route unless allowed && + * match route to be exact if so specified + */ + if (!prn) + rib = NULL; + else if ((type == RNH_NEXTHOP_TYPE) && + (zebra_rnh_is_default_route(&prn->p) && + !zebra_rnh_resolve_via_default(prn->p.family))) + rib = NULL; + else if ((type == RNH_IMPORT_CHECK_TYPE) && + ((zebra_rnh_is_default_route(&prn->p)) || + ((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) && + !prefix_same(&nrn->p, &prn->p)))) rib = NULL; else { @@ -333,6 +366,9 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) if (rib->type == ZEBRA_ROUTE_CONNECT) break; } + else if ((type == RNH_IMPORT_CHECK_TYPE) && + (rib->type == ZEBRA_ROUTE_BGP)) + continue; else break; } @@ -341,6 +377,42 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) state_changed = 0; + /* Handle import check first as its simpler */ + if (type == RNH_IMPORT_CHECK_TYPE) + { + if (rib && (rnh->state == NULL)) + { + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + state_changed = 1; + break; + } + } + else if (!rib && (rnh->state != NULL)) + state_changed = 1; + + if (compare_state(rib, rnh->state)) + copy_state(rnh, rib, nrn); + + if (state_changed || force) + { + if (IS_ZEBRA_DEBUG_NHT) + { + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + zlog_debug("rnh import check %s for %s, notifying clients\n", + rnh->state ? "passed" : "failed", bufn); + } + /* state changed, notify clients */ + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + { + send_client(rnh, client, RNH_IMPORT_CHECK_TYPE); + } + } + + goto loopend; + } + /* Ensure prefixes we're resolving over have stayed the same */ if (!prefix_same(&rnh->resolved_route, &prn->p)) { @@ -401,7 +473,7 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) at_least_one ? "":"(filtered)", bufn, bufp, rib ? "reachable" : "unreachable"); - send_client(rnh, client); /* Route-map passed */ + send_client(rnh, client, RNH_NEXTHOP_TYPE); /* Route-map passed */ } /* Now evaluate static client */ @@ -482,18 +554,34 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force) } } } + loopend: + if (p) + { + route_unlock_node(nrn); + nrn = NULL; + } + else + { + /* route_next takes care of unlocking nrn */ + nrn = route_next(nrn); + } } + + if (prn) + route_unlock_node(prn); + return 1; } int -zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client) +zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client, + rnh_type_t type) { struct route_table *ntable; struct route_node *nrn; struct rnh *rnh; - ntable = lookup_rnh_table(vrfid, family); + ntable = get_rnh_table(vrfid, family, type); if (!ntable) { zlog_debug("dispatch_rnh_table: rnh table not found\n"); @@ -514,18 +602,18 @@ zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client) rnh->state ? "reachable" : "unreachable", zebra_route_string(client->proto)); } - send_client(rnh, client); + send_client(rnh, client, RNH_NEXTHOP_TYPE); } return 1; } void -zebra_print_rnh_table (int vrfid, int af, struct vty *vty) +zebra_print_rnh_table (int vrfid, int af, struct vty *vty, rnh_type_t type) { struct route_table *table; struct route_node *rn; - table = lookup_rnh_table(vrfid, af); + table = get_rnh_table(vrfid, af, type); if (!table) { zlog_debug("print_rnhs: rnh table not found\n"); @@ -538,13 +626,14 @@ zebra_print_rnh_table (int vrfid, int af, struct vty *vty) } int -zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client) +zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client, + rnh_type_t type) { struct route_table *ntable; struct route_node *nrn; struct rnh *rnh; - ntable = lookup_rnh_table(vrfid, family); + ntable = get_rnh_table(vrfid, family, type); if (!ntable) { zlog_debug("cleanup_rnh_client: rnh table not found\n"); @@ -564,7 +653,7 @@ zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client) zlog_debug("rnh %s - cleaning state for client %s", bufn, zebra_route_string(client->proto)); } - zebra_remove_rnh_client(rnh, client); + zebra_remove_rnh_client(rnh, client, type); } return 1; } @@ -631,7 +720,7 @@ compare_state (struct rib *r1, struct rib *r2) } static int -send_client (struct rnh *rnh, struct zserv *client) +send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type) { struct stream *s; struct rib *rib; @@ -639,6 +728,8 @@ send_client (struct rnh *rnh, struct zserv *client) u_char num; struct nexthop *nexthop; struct route_node *rn; + int cmd = (type == RNH_IMPORT_CHECK_TYPE) + ? ZEBRA_IMPORT_CHECK_UPDATE : ZEBRA_NEXTHOP_UPDATE; rn = rnh->node; rib = rnh->state; @@ -647,11 +738,23 @@ send_client (struct rnh *rnh, struct zserv *client) s = client->obuf; stream_reset (s); - zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE); - + zserv_create_header (s, cmd); stream_putw(s, rn->p.family); - stream_put_prefix (s, &rn->p); - + switch (rn->p.family) + { + case AF_INET: + stream_putc(s, rn->p.prefixlen); + stream_put_in_addr(s, &rn->p.u.prefix4); + break; + case AF_INET6: + stream_putc(s, rn->p.prefixlen); + stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN); + break; + default: + zlog_err("%s: Unknown family (%d) notification attempted\n", + __FUNCTION__, rn->p.family); + break; + } if (rib) { stream_putl (s, rib->metric); @@ -704,7 +807,7 @@ send_client (struct rnh *rnh, struct zserv *client) stream_putw_at (s, 0, stream_get_endp (s)); client->nh_last_upd_time = quagga_time(NULL); - client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE; + client->last_write_cmd = cmd; return zebra_server_send_message(client); } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 2ef16bdf80..494be8366c 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -30,8 +30,11 @@ struct rnh { u_char flags; + #define ZEBRA_NHT_CONNECTED 0x1 #define ZEBRA_NHT_DELETED 0x2 +#define ZEBRA_NHT_EXACT_MATCH 0x4 + struct rib *state; struct prefix resolved_route; struct list *client_list; @@ -40,19 +43,30 @@ struct rnh int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ }; +typedef enum + { + RNH_NEXTHOP_TYPE, + RNH_IMPORT_CHECK_TYPE + } rnh_type_t; + extern int zebra_rnh_ip_default_route; extern int zebra_rnh_ipv6_default_route; -extern struct rnh *zebra_add_rnh(struct prefix *p, u_int32_t vrfid); -extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid); -extern void zebra_delete_rnh(struct rnh *rnh); -extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client); +extern struct rnh *zebra_add_rnh(struct prefix *p, u_int32_t vrfid, + rnh_type_t type); +extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid, + rnh_type_t type); +extern void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type); +extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type); extern void zebra_register_rnh_static_nh(struct prefix *, struct route_node *); extern void zebra_deregister_rnh_static_nh(struct prefix *, struct route_node *); -extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); -extern int zebra_evaluate_rnh_table(int vrfid, int family, int force); -extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl); -extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty); +extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, + rnh_type_t type); +extern int zebra_evaluate_rnh(int vrfid, int family, int force, rnh_type_t type, + struct prefix *p); +extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl, rnh_type_t); +extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty, rnh_type_t); extern char *rnh_str(struct rnh *rnh, char *buf, int size); -extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client); +extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client, + rnh_type_t type); #endif /*_ZEBRA_RNH_H */ diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c index 205382b482..5bd00a3ecd 100644 --- a/zebra/zebra_rnh_null.c +++ b/zebra/zebra_rnh_null.c @@ -6,10 +6,12 @@ int zebra_rnh_ip_default_route = 0; int zebra_rnh_ipv6_default_route = 0; -int zebra_evaluate_rnh_table (int vrfid, int family, int force) +int zebra_evaluate_rnh (int vrfid, int family, int force, rnh_type_t type, + struct prefix *p) { return 0; } -void zebra_print_rnh_table (int vrfid, int family, struct vty *vty) +void zebra_print_rnh_table (int vrfid, int family, struct vty *vty, + rnh_type_t type) {} void zebra_register_rnh_static_nh(struct prefix *p, struct route_node *rn) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 6ec28d73a8..8ac08960a6 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -846,7 +846,7 @@ DEFUN (ip_protocol_nht_rmap, } nht_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); - zebra_evaluate_rnh_table(0, AF_INET, 1); + zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -879,7 +879,7 @@ DEFUN (no_ip_protocol_nht_rmap, { XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]); nht_rm[AFI_IP][i] = NULL; - zebra_evaluate_rnh_table(0, AF_INET, 1); + zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); } return CMD_SUCCESS; } @@ -944,7 +944,7 @@ DEFUN (ipv6_protocol_nht_rmap, if (nht_rm[AFI_IP6][i]) XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]); nht_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); - zebra_evaluate_rnh_table(0, AF_INET6, 1); + zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -977,7 +977,7 @@ DEFUN (no_ipv6_protocol_nht_rmap, { XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]); nht_rm[AFI_IP6][i] = NULL; - zebra_evaluate_rnh_table(0, AF_INET6, 1); + zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); } return CMD_SUCCESS; @@ -1446,8 +1446,8 @@ zebra_route_map_update_timer (struct thread *thread) zlog_debug("Event driven route-map update triggered"); rib_update(); - zebra_evaluate_rnh_table(0, AF_INET, 1); - zebra_evaluate_rnh_table(0, AF_INET6, 1); + zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return (0); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 3c80c9ffab..ab6e5ec7b5 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1180,7 +1180,7 @@ DEFUN (show_ip_nht, IP_STR "IP nexthop tracking table\n") { - zebra_print_rnh_table(0, AF_INET, vty); + zebra_print_rnh_table(0, AF_INET, vty, RNH_NEXTHOP_TYPE); return CMD_SUCCESS; } @@ -1191,7 +1191,7 @@ DEFUN (show_ipv6_nht, IP_STR "IPv6 nexthop tracking table\n") { - zebra_print_rnh_table(0, AF_INET6, vty); + zebra_print_rnh_table(0, AF_INET6, vty, RNH_NEXTHOP_TYPE); return CMD_SUCCESS; } @@ -1206,7 +1206,7 @@ DEFUN (ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 1; - zebra_evaluate_rnh_table(0, AF_INET, 1); + zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1222,7 +1222,7 @@ DEFUN (no_ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 0; - zebra_evaluate_rnh_table(0, AF_INET, 1); + zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1237,7 +1237,7 @@ DEFUN (ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 1; - zebra_evaluate_rnh_table(0, AF_INET6, 1); + zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1253,7 +1253,7 @@ DEFUN (no_ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 0; - zebra_evaluate_rnh_table(0, AF_INET6, 1); + zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } diff --git a/zebra/zserv.c b/zebra/zserv.c index 960514319f..fb138c11bb 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -786,69 +786,114 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) /* Nexthop register */ static int -zserv_nexthop_register (struct zserv *client, int sock, u_short length) +zserv_rnh_register (struct zserv *client, int sock, u_short length, + rnh_type_t type) { struct rnh *rnh; struct stream *s; struct prefix p; u_short l = 0; - u_char connected; + u_char flags = 0; if (IS_ZEBRA_DEBUG_NHT) - zlog_debug("nexthop_register msg from client %s: length=%d\n", - zebra_route_string(client->proto), length); + zlog_debug("rnh_register msg from client %s: length=%d, type=%s\n", + zebra_route_string(client->proto), length, + (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route"); s = client->ibuf; + client->nh_reg_time = quagga_time(NULL); + while (l < length) { - connected = stream_getc(s); + flags = stream_getc(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); l += 4; - stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); - l += PSIZE(p.prefixlen); - rnh = zebra_add_rnh(&p, 0); - if (connected) - SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); - - client->nh_reg_time = quagga_time(NULL); - zebra_add_rnh_client(rnh, client); + if (p.family == AF_INET) + { + p.u.prefix4.s_addr = stream_get_ipv4(s); + l += IPV4_MAX_BYTELEN; + } + else if (p.family == AF_INET6) + { + stream_get(&p.u.prefix6, s, IPV6_MAX_BYTELEN); + l += IPV6_MAX_BYTELEN; + } + else + { + zlog_err("rnh_register: Received unknown family type %d\n", + p.family); + return -1; + } + rnh = zebra_add_rnh(&p, 0, type); + if (type == RNH_NEXTHOP_TYPE) + { + if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + else if (!flags && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + } + else if (type == RNH_IMPORT_CHECK_TYPE) + { + if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) + SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); + else if (!flags && CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) + UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); + } + + zebra_add_rnh_client(rnh, client, type); + /* Anything not AF_INET/INET6 has been filtered out above */ + zebra_evaluate_rnh(0, p.family, 1, type, &p); } - zebra_evaluate_rnh_table(0, AF_INET, 0); - zebra_evaluate_rnh_table(0, AF_INET6, 0); return 0; } /* Nexthop register */ static int -zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) +zserv_rnh_unregister (struct zserv *client, int sock, u_short length, + rnh_type_t type) { struct rnh *rnh; struct stream *s; struct prefix p; u_short l = 0; - u_char connected; + u_char flags; + u_char exact_match; if (IS_ZEBRA_DEBUG_NHT) - zlog_debug("nexthop_unregister msg from client %s: length=%d\n", + zlog_debug("rnh_unregister msg from client %s: length=%d\n", zebra_route_string(client->proto), length); s = client->ibuf; while (l < length) { - connected = stream_getc(s); + flags = stream_getc(s); p.family = stream_getw(s); p.prefixlen = stream_getc(s); l += 4; - stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); - l += PSIZE(p.prefixlen); - rnh = zebra_lookup_rnh(&p, 0); + if (p.family == AF_INET) + { + p.u.prefix4.s_addr = stream_get_ipv4(s); + l += IPV4_MAX_BYTELEN; + } + else if (p.family == AF_INET6) + { + stream_get(&p.u.prefix6, s, IPV6_MAX_BYTELEN); + l += IPV6_MAX_BYTELEN; + } + else + { + zlog_err("rnh_register: Received unknown family type %d\n", + p.family); + return -1; + } + rnh = zebra_lookup_rnh(&p, 0, type); if (rnh) { client->nh_dereg_time = quagga_time(NULL); - zebra_remove_rnh_client(rnh, client); + zebra_remove_rnh_client(rnh, client, type); } } return 0; @@ -1496,8 +1541,10 @@ zread_hello (struct zserv *client) static void zebra_client_close (struct zserv *client) { - zebra_cleanup_rnh_client(0, AF_INET, client); - zebra_cleanup_rnh_client(0, AF_INET6, client); + zebra_cleanup_rnh_client(0, AF_INET, client, RNH_NEXTHOP_TYPE); + zebra_cleanup_rnh_client(0, AF_INET6, client, RNH_NEXTHOP_TYPE); + zebra_cleanup_rnh_client(0, AF_INET, client, RNH_IMPORT_CHECK_TYPE); + zebra_cleanup_rnh_client(0, AF_INET6, client, RNH_IMPORT_CHECK_TYPE); /* Close file descriptor. */ if (client->sock) @@ -1721,10 +1768,16 @@ zebra_client_read (struct thread *thread) zread_hello (client); break; case ZEBRA_NEXTHOP_REGISTER: - zserv_nexthop_register(client, sock, length); + zserv_rnh_register(client, sock, length, RNH_NEXTHOP_TYPE); break; case ZEBRA_NEXTHOP_UNREGISTER: - zserv_nexthop_unregister(client, sock, length); + zserv_rnh_unregister(client, sock, length, RNH_NEXTHOP_TYPE); + break; + case ZEBRA_IMPORT_ROUTE_REGISTER: + zserv_rnh_register(client, sock, length, RNH_IMPORT_CHECK_TYPE); + break; + case ZEBRA_IMPORT_ROUTE_UNREGISTER: + zserv_rnh_unregister(client, sock, length, RNH_IMPORT_CHECK_TYPE); break; default: zlog_info ("Zebra received unknown command %d", command);