From: Dinesh Dutt <[email protected]> Use NHT to support static routes with NH derived from protocols.
Signed-off-by: Dinesh Dutt <[email protected]> --- lib/nexthop.h | 1 + zebra/rib.h | 11 +- zebra/zebra_rib.c | 272 +++++++++++++++++++++++++++++++------- zebra/zebra_rnh.c | 348 +++++++++++++++++++++++++++++++------------------ zebra/zebra_rnh.h | 4 + zebra/zebra_rnh_null.c | 9 ++ zebra/zserv.c | 2 +- 7 files changed, 466 insertions(+), 181 deletions(-) diff --git a/lib/nexthop.h b/lib/nexthop.h index 69ebb35..2c317bf 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -64,6 +64,7 @@ struct nexthop #define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ #define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */ #define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */ +#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */ /* Nexthop address */ union g_addr gate; diff --git a/zebra/rib.h b/zebra/rib.h index 94c7d1f..f10e315 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -76,8 +76,9 @@ struct rib /* RIB internal status */ u_char status; -#define RIB_ENTRY_REMOVED (1 << 0) -#define RIB_ENTRY_CHANGED (1 << 1) +#define RIB_ENTRY_REMOVED (1 << 0) + /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */ +#define RIB_ENTRY_NEXTHOPS_CHANGED (1 << 1) /* Nexthop information. */ u_char nexthop_num; @@ -383,6 +384,7 @@ extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *, unsigned int); extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop); +extern void rib_copy_nexthops (struct rib *rib, struct nexthop *nexthop); extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); @@ -422,7 +424,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, vrf_id_t, safi_t safi); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, - int skip_bgp, struct route_node **rn_out, + struct route_node **rn_out, vrf_id_t); extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, @@ -437,6 +439,9 @@ extern void rib_close_table (struct route_table *); extern void rib_close (void); extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); +struct zebra_t; +extern void rib_queue_add (struct zebra_t *zebra, struct route_node *rn); + extern int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 474b13c..819b7bc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -120,6 +120,27 @@ rib_nexthop_add (struct rib *rib, struct nexthop *nexthop) rib->nexthop_num++; } +/** + * copy_nexthop - copy a nexthop to the rib structure. + */ +void +rib_copy_nexthops (struct rib *rib, struct nexthop *nh) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->flags = nh->flags; + nexthop->type = nh->type; + nexthop->ifindex = nh->ifindex; + if (nh->ifname) + nexthop->ifname = XSTRDUP(0, nh->ifname); + memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); + memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); + rib_nexthop_add(rib, nexthop); + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) + copy_nexthops(&nexthop->resolved, nh->resolved); +} + /* Delete specified nexthop from the list. */ static void rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop) @@ -284,8 +305,9 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, struct route_node *rn; struct rib *match; int resolved; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; struct nexthop *resolved_hop; + int recursing = 0; if (nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = 0; @@ -293,11 +315,18 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + zebra_deregister_rnh_static_nexthops (nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; rib->nexthop_mtu = 0; } + /* Skip nexthops that have been filtered out due to route-map */ + /* The nexthops are specific to this route and so the same */ + /* nexthop for a different route may not have this flag set */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED)) + return 0; + /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; @@ -329,8 +358,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (! match) { do { rn = rn->parent; @@ -365,6 +393,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); @@ -408,6 +437,57 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, rib->nexthop_mtu = match->mtu; return resolved; } + else if (rib->type == ZEBRA_ROUTE_STATIC) + { + resolved = 0; + for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); + SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); + /* If the resolving route specifies a gateway, use it */ + if (newhop->type == NEXTHOP_TYPE_IPV4 + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME) + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv4 = newhop->gate.ipv4; + + if (newhop->ifindex) + { + resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + resolved_hop->ifindex = newhop->ifindex; + } + } + + /* If the resolving route is an interface route, + * it means the gateway we are looking up is connected + * to that interface. (The actual network is _not_ onlink). + * Therefore, the resolved route should have the original + * gateway as nexthop as it is directly connected. + * + * On Linux, we have to set the onlink netlink flag because + * otherwise, the kernel won't accept the route. + */ + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + resolved_hop->gate.ipv4 = nexthop->gate.ipv4; + resolved_hop->ifindex = newhop->ifindex; + } + + nexthop_add(&nexthop->resolved, resolved_hop); + } + resolved = 1; + } + return resolved; + } else { return 0; @@ -428,7 +508,8 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, struct route_node *rn; struct rib *match; int resolved; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; + int recursing = 0; struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV6) @@ -437,10 +518,17 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + zebra_deregister_rnh_static_nexthops (nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; } + /* Skip nexthops that have been filtered out due to route-map */ + /* The nexthops are specific to this route and so the same */ + /* nexthop for a different route may not have this flag set */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED)) + return 0; + /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; @@ -472,8 +560,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (! match) { do { rn = rn->parent; @@ -509,6 +596,50 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + + resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); + SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); + /* See nexthop_active_ipv4 for a description how the + * resolved nexthop is constructed. */ + if (newhop->type == NEXTHOP_TYPE_IPV6 + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv6 = newhop->gate.ipv6; + + if (newhop->ifindex) + { + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->ifindex = newhop->ifindex; + } + } + + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->gate.ipv6 = nexthop->gate.ipv6; + resolved_hop->ifindex = newhop->ifindex; + } + + nexthop_add(&nexthop->resolved, resolved_hop); + } + resolved = 1; + } + return resolved; + } + else if (rib->type == ZEBRA_ROUTE_STATIC) + { + resolved = 0; + for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); @@ -553,7 +684,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, } struct rib * -rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, +rib_match_ipv4_safi (struct in_addr addr, safi_t safi, struct route_node **rn_out, vrf_id_t vrf_id) { struct route_table *table; @@ -584,7 +715,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, /* If there is no selected route or matched route is EGP, go up tree. */ - if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP))) + if (! match) { do { rn = rn->parent; @@ -621,29 +752,22 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, { struct rib *rib = NULL, *mrib = NULL, *urib = NULL; struct route_node *m_rn = NULL, *u_rn = NULL; - int skip_bgp = 0; /* bool */ switch (ipv4_multicast_mode) { case MCAST_MRIB_ONLY: - return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out, - vrf_id); + return rib_match_ipv4_safi (addr, SAFI_MULTICAST, rn_out, vrf_id); case MCAST_URIB_ONLY: - return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out, - vrf_id); + return rib_match_ipv4_safi (addr, SAFI_UNICAST, rn_out, vrf_id); case MCAST_NO_CONFIG: case MCAST_MIX_MRIB_FIRST: - rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, - vrf_id); + rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id); if (!mrib) - rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, - vrf_id); + rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id); break; case MCAST_MIX_DISTANCE: - mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, - vrf_id); - urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, - vrf_id); + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id); if (mrib && urib) rib = urib->distance < mrib->distance ? urib : mrib; else if (mrib) @@ -652,10 +776,8 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, rib = urib; break; case MCAST_MIX_PFXLEN: - mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, - vrf_id); - urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, - vrf_id); + mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id); + urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id); if (mrib && urib) rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; else if (mrib) @@ -727,7 +849,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) break; } - if (! match || match->type == ZEBRA_ROUTE_BGP) + if (! match) return NULL; if (match->type == ZEBRA_ROUTE_CONNECT) @@ -855,8 +977,7 @@ rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (! match) { do { rn = rn->parent; @@ -1016,10 +1137,12 @@ static int nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { struct nexthop *nexthop; - unsigned int prev_active, prev_index, new_active; + unsigned int prev_active, prev_index, new_active, old_num_nh; + + old_num_nh = rib->nexthop_active_num; rib->nexthop_active_num = 0; - UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); + UNSET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { @@ -1029,8 +1152,12 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) rib->nexthop_active_num++; if (prev_active != new_active || prev_index != nexthop->ifindex) - SET_FLAG (rib->status, RIB_ENTRY_CHANGED); + SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); } + + if (old_num_nh != rib->nexthop_active_num) + SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + return rib->nexthop_active_num; } @@ -1214,6 +1341,8 @@ rib_process (struct route_node *rn) RNODE_FOREACH_RIB_SAFE (rn, rib, next) { + UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { @@ -1240,7 +1369,14 @@ rib_process (struct route_node *rn) } /* Skip unreachable nexthop. */ - if (! nexthop_active_update (rn, rib, 0)) + /* With static routes that may have recursive nexthops, calling + * nexthop_active_update will clear the ZEBRA_FLAG_CHANGED flag + * as the top level NH may not have changed. Those flags are set + * by the NHT evaluation. So, we skip an active_update_check here + * for static routes as its job has already been done. + */ + if (rib->type != ZEBRA_ROUTE_STATIC && + ! nexthop_active_update (rn, rib, 0)) continue; /* Infinit distance. */ @@ -1303,7 +1439,7 @@ rib_process (struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "Updating existing route, select %p, fib %p", (void *)select, (void *)fib); - if (CHECK_FLAG (select->status, RIB_ENTRY_CHANGED)) + if (CHECK_FLAG (select->status, RIB_ENTRY_NEXTHOPS_CHANGED)) { if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "updating existing route"); @@ -1313,12 +1449,20 @@ rib_process (struct route_node *rn) rib_uninstall_kernel (rn, select); /* Set real nexthop. */ - nexthop_active_update (rn, select, 1); - - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select); - redistribute_add (&rn->p, select); - } + /* Need to check if any NHs are active to clear the + * the selected flag + */ + if (nexthop_active_update (rn, select, 1)) + { + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + redistribute_add (&rn->p, select); + } + else + { + UNSET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + } + } else if (! RIB_SYSTEM_ROUTE (select)) { /* Housekeeping code to deal with @@ -1374,12 +1518,13 @@ rib_process (struct route_node *rn) zfpm_trigger_update (rn, "new route selected"); /* Set real nexthop. */ - nexthop_active_update (rn, select, 1); - - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select); - SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); - redistribute_add (&rn->p, select); + if (nexthop_active_update (rn, select, 1)) + { + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, select); + } } /* FIB route was removed, should be deleted */ @@ -1515,7 +1660,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) } /* Add route_node to work queue and schedule processing */ -static void +void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { assert (zebra && rn); @@ -1729,7 +1874,8 @@ rib_unlink (struct route_node *rn, struct rib *rib) } /* free RIB and nexthops */ - nexthops_free(rib->nexthop); + zebra_deregister_rnh_static_nexthops (rib->nexthop, rn); + nexthops_free (rib->nexthop); XFREE (MTYPE_RIB, rib); } @@ -2235,6 +2381,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro struct rib *rib; struct route_node *rn; struct route_table *table; + struct prefix nh_p; /* Lookup table. */ table = zebra_vrf_table (afi, safi, si->vrf_id); @@ -2265,6 +2412,10 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro { case STATIC_IPV4_GATEWAY: rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = si->addr.ipv4; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV4_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); @@ -2274,6 +2425,10 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro break; case STATIC_IPV6_GATEWAY: rib_nexthop_ipv6_add (rib, &si->addr.ipv6); + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = si->addr.ipv6; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV6_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); @@ -2301,6 +2456,10 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro { case STATIC_IPV4_GATEWAY: rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = si->addr.ipv4; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV4_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); @@ -2310,6 +2469,10 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro break; case STATIC_IPV6_GATEWAY: rib_nexthop_ipv6_add (rib, &si->addr.ipv6); + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = si->addr.ipv6; + zebra_register_rnh_static_nh(&nh_p, rn); break; case STATIC_IPV6_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); @@ -2365,6 +2528,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ struct rib *rib; struct nexthop *nexthop; struct route_table *table; + struct prefix nh_p; /* Lookup table. */ table = zebra_vrf_table (afi, safi, si->vrf_id); @@ -2411,7 +2575,21 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); + + if (afi == AF_INET) + { + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = nexthop->gate.ipv4; + } + else + { + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = nexthop->gate.ipv6; + } rib_nexthop_delete (rib, nexthop); + zebra_deregister_rnh_static_nh(&nh_p, rn); nexthop_free (nexthop); rib_queue_add (&zebrad, rn); } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index e623409..d2061ca 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -54,8 +54,11 @@ t; \ }) -static void free_state(struct rib *rib); -static void copy_state(struct rnh *rnh, struct rib *rib); +/* Default rtm_table for all clients */ +extern struct zebra_t zebrad; + +static void rib_free_state(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, vrf_id_t vrf_id); static void print_rnh(struct route_node *rn, struct vty *vty); @@ -97,6 +100,7 @@ zebra_add_rnh (struct prefix *p, vrf_id_t vrfid) { rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); rnh->client_list = list_new(); + rnh->zebra_static_route_list = list_new(); route_lock_node (rn); rn->info = rnh; rnh->node = rn; @@ -143,7 +147,8 @@ zebra_delete_rnh (struct rnh *rnh) } list_free(rnh->client_list); - free_state(rnh->state); + list_free(rnh->zebra_static_route_list); + rib_free_state(rnh->state, rn); XFREE(MTYPE_RNH, rn->info); rn->info = NULL; route_unlock_node (rn); @@ -178,10 +183,94 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) rnh_str(rnh, buf, INET6_ADDRSTRLEN)); } listnode_delete(rnh->client_list, client); - if (list_isempty(rnh->client_list)) + if (list_isempty(rnh->client_list) && + list_isempty(rnh->zebra_static_route_list)) + zebra_delete_rnh(rnh); +} + +void +zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) +{ + struct rnh *rnh; + + rnh = zebra_add_rnh(nh, 0); + if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn)) + { + listnode_add(rnh->zebra_static_route_list, static_rn); + } +} + +void +zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn) +{ + struct rnh *rnh; + + rnh = zebra_lookup_rnh(nh, 0); + if (!rnh) + return; + + listnode_delete(rnh->zebra_static_route_list, static_rn); + + if (list_isempty(rnh->client_list) && + list_isempty(rnh->zebra_static_route_list)) zebra_delete_rnh(rnh); } +void +zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn) +{ + struct nexthop *nh; + struct prefix nh_p; + + for (nh = nexthop; nh ; nh = nh->next) + { + if (nh->type == NEXTHOP_TYPE_IPV4) + { + nh_p.family = AF_INET; + nh_p.prefixlen = IPV4_MAX_BITLEN; + nh_p.u.prefix4 = nh->gate.ipv4; + } + else if (nh->type == NEXTHOP_TYPE_IPV6) + { + nh_p.family = AF_INET6; + nh_p.prefixlen = IPV6_MAX_BITLEN; + nh_p.u.prefix6 = nh->gate.ipv6; + } + zebra_deregister_rnh_static_nh(&nh_p, rn); + } +} + +static int +zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn, + int proto) +{ + int at_least_one = 0; + int rmap_family; /* Route map has diff AF family enum */ + struct nexthop *nexthop; + int ret; + + rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6; + + if (prn && rib) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + ret = zebra_nht_route_map_check(rmap_family, proto, &prn->p, rib, + nexthop); + if (ret != RMAP_DENYMATCH) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + at_least_one++; /* at least one valid NH */ + } + else + { + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + } + } + return (at_least_one); +} + int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) { @@ -192,17 +281,14 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) struct rnh *rnh; struct zserv *client; struct listnode *node; - struct rib *rib; - int rmap_family; /* Route map has diff AF family enum */ - route_map_result_t ret = RMAP_MATCH; - struct nexthop *nexthop; + struct rib *rib, *srib; int state_changed = 0; int at_least_one = 0; char bufn[INET6_ADDRSTRLEN]; char bufp[INET6_ADDRSTRLEN]; - - rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6; - + char bufs[INET6_ADDRSTRLEN]; + struct route_node *static_rn; + struct nexthop *nexthop; ntable = lookup_rnh_table(vrfid, family); if (!ntable) { @@ -223,6 +309,8 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) continue; rnh = nrn->info; + at_least_one = 0; + prn = route_node_match(ptable, &nrn->p); if (!prn) rib = NULL; @@ -249,7 +337,10 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) if (compare_state(rib, rnh->state)) { - copy_state(rnh, rib); + if (rib) + UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + + copy_state(rnh, rib, nrn); state_changed = 1; } @@ -260,56 +351,116 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); else strcpy(bufp, "null"); + + zlog_debug("%s: State changed for %s/%s", __FUNCTION__, bufn, bufp); + } /* Notify registered clients */ + rib = rnh->state; + if (state_changed || force) - for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) - { - rib = rnh->state; - if (prn && rib) - { - at_least_one = 0; - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - { - ret = zebra_nht_route_map_check(rmap_family, client->proto, - &prn->p, rib, nexthop); - if (ret == RMAP_DENYMATCH) - { - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - } - else - { - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - at_least_one++; /* at least one valid NH */ - } - } - if (at_least_one) - rnh->filtered[client->proto] = 0; - else - rnh->filtered[client->proto] = 1; - - if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) - zlog_debug("%srnh %s resolved through route %s - sending " - "nexthop %s event to clients", - at_least_one ? "":"(filtered)", bufn, bufp, - rib ? "reachable" : "unreachable"); - - send_client(rnh, client, vrfid); /* Route-map passed */ - } - else if (state_changed) - { - if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) - zlog_debug("rnh %s resolved through route %s - sending " - "nexthop %s event to clients", bufn, bufp, - rib ? "reachable" : "unreachable"); + { + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + { + if (prn && rib) + { + at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn, + client->proto); + if (at_least_one) + rnh->filtered[client->proto] = 0; + else + rnh->filtered[client->proto] = 1; + } + else if (state_changed) rnh->filtered[client->proto] = 0; - send_client(rnh, client, vrfid); - /* We don't need to send a RNH update on force since no - * update really happened, just a route-map change. - */ - } - } + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + zlog_debug("%srnh %s resolved through route %s - sending " + "nexthop %s event to clients", + at_least_one ? "":"(filtered)", bufn, bufp, + rib ? "reachable" : "unreachable"); + + send_client(rnh, client, vrfid); /* Route-map passed */ + } + + /* Now evaluate static client */ + if (prn && rib) + { + at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn, + ZEBRA_ROUTE_STATIC); + if (at_least_one) + rnh->filtered[ZEBRA_ROUTE_STATIC] = 0; + else + rnh->filtered[ZEBRA_ROUTE_STATIC] = 1; + } + else if (state_changed) + rnh->filtered[ZEBRA_ROUTE_STATIC] = 0; + + for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node, + static_rn)) + { + RNODE_FOREACH_RIB(static_rn, srib) + { + break; /* pick the first and only(?) rib for static */ + } + + if (!srib) + { + if (IS_ZEBRA_DEBUG_NHT) + { + prefix2str(&static_rn->p, bufs, INET6_ADDRSTRLEN); + zlog_debug("%s: Unable to find RIB for static route %s, skipping NH resolution", + __FUNCTION__, bufs); + continue; + } + } + + /* Mark the appropriate static route's NH as filtered */ + for (nexthop = srib->nexthop; nexthop; nexthop = nexthop->next) + { + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + /* Don't see a use case for *_IFNAME */ + if (nexthop->gate.ipv4.s_addr == nrn->p.u.prefix4.s_addr) + { + if (at_least_one) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + else + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + /* Don't see a use case for *_IFNAME */ + if (memcmp(&nexthop->gate.ipv6,&nrn->p.u.prefix6, 16) == 0) + { + if (at_least_one) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + else + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED); + } + break; + default: + break; + } + } + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + zlog_debug("%srnh %s resolved through route %s - sending " + "nexthop %s event to zebra", + at_least_one ? "":"(filtered)", bufn, bufp, + rib ? "reachable" : "unreachable"); + + if (srib && (state_changed || force)) + { + SET_FLAG(srib->status, RIB_ENTRY_NEXTHOPS_CHANGED); + rib_queue_add(&zebrad, static_rn); + } + } + } } return 1; } @@ -401,51 +552,27 @@ zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client) * free_state - free up the rib structure associated with the rnh. */ static void -free_state (struct rib *rib) +rib_free_state (struct rib *rib, struct route_node *rn) { - struct nexthop *nexthop, *next; if (!rib) return; /* free RIB and nexthops */ - for (nexthop = rib->nexthop; nexthop; nexthop = next) - { - next = nexthop->next; - nexthop_free (nexthop); - } + zebra_deregister_rnh_static_nexthops (rib->nexthop, rn); + nexthops_free(rib->nexthop); XFREE (MTYPE_RIB, rib); } -/** - * copy_nexthop - copy a nexthop to the rib structure. - */ static void -rib_copy_nexthop (struct rib *state, struct nexthop *nh) -{ - struct nexthop *nexthop; - - nexthop = nexthop_new(); - nexthop->flags = nh->flags; - nexthop->type = nh->type; - nexthop->ifindex = nh->ifindex; - if (nh->ifname) - nexthop->ifname = XSTRDUP(0, nh->ifname); - memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); - memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); - - rib_nexthop_add(state, nexthop); -} - -static void -copy_state (struct rnh *rnh, struct rib *rib) +copy_state (struct rnh *rnh, struct rib *rib, struct route_node *rn) { struct rib *state; struct nexthop *nh; if (rnh->state) { - free_state(rnh->state); + rib_free_state(rnh->state, rn); rnh->state = NULL; } @@ -457,16 +584,13 @@ copy_state (struct rnh *rnh, struct rib *rib) state->metric = rib->metric; for (nh = rib->nexthop; nh; nh = nh->next) - rib_copy_nexthop(state, nh); + rib_copy_nexthops(state, nh); rnh->state = state; } static int compare_state (struct rib *r1, struct rib *r2) { - struct nexthop *nh1; - struct nexthop *nh2; - u_char found_nh = 0; if (!r1 && !r2) return 0; @@ -480,46 +604,8 @@ compare_state (struct rib *r1, struct rib *r2) if (r1->nexthop_num != r2->nexthop_num) return 1; - /* We need to verify that the nexthops for r1 match the nexthops for r2. - * Since it is possible for a rib entry to have the same nexthop multiple - * times (Example: [a,a]) we need to keep track of which r2 nexthops we have - * already used as a match against a r1 nexthop. We track this - * via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you - * are finished. - * - * TRUE: r1 [a,b], r2 [a,b] - * TRUE: r1 [a,b], r2 [b,a] - * FALSE: r1 [a,b], r2 [a,c] - * FALSE: r1 [a,a], r2 [a,b] - */ - for (nh1 = r1->nexthop; nh1; nh1 = nh1->next) - { - found_nh = 0; - for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) - { - if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) - continue; - - if (nexthop_same_no_recurse(nh1, nh2)) - { - SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); - found_nh = 1; - break; - } - } - - if (!found_nh) - { - for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) - if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) - UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); - return 1; - } - } - - for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) - if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) - UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); + if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED)) + return 1; return 0; } @@ -665,5 +751,7 @@ print_rnh (struct route_node *rn, struct vty *vty) for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), client->sock, rnh->filtered[client->proto] ? "(filtered)" : ""); + if (!list_isempty(rnh->zebra_static_route_list)) + vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); vty_out(vty, "%s", VTY_NEWLINE); } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 1f52cf5..77a913a 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -33,6 +33,7 @@ struct rnh #define ZEBRA_NHT_CONNECTED 0x1 struct rib *state; struct list *client_list; + struct list *zebra_static_route_list; /* static routes dependent on this NH */ struct route_node *node; int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ }; @@ -41,6 +42,9 @@ extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid); extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid); extern void zebra_delete_rnh(struct rnh *rnh); extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id_t); +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_deregister_rnh_static_nexthops (struct nexthop *, struct route_node *); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family, int force); extern int zebra_dispatch_rnh_table(vrf_id_t vrfid, int family, struct zserv *cl); diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c index f45cba3..c30e3e4 100644 --- a/zebra/zebra_rnh_null.c +++ b/zebra/zebra_rnh_null.c @@ -10,3 +10,12 @@ int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) void zebra_print_rnh_table (vrf_id_t vrfid, int family, struct vty *vty) {} + +void zebra_register_rnh_static_nh(struct prefix *p, struct route_node *rn) +{} + +void zebra_deregister_rnh_static_nh(struct prefix *p, struct route_node *rn) +{} + +void zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn) +{} diff --git a/zebra/zserv.c b/zebra/zserv.c index 8f2a3f3..f887af9 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -697,7 +697,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, NULL, vrf_id); /* Get output stream. */ s = client->obuf; -- 1.9.1 _______________________________________________ Quagga-dev mailing list [email protected] https://lists.quagga.net/mailman/listinfo/quagga-dev
