diff options
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 180 |
1 files changed, 108 insertions, 72 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0aea0b6cfa..c5d977017e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -38,6 +38,7 @@ #include "workqueue.h" #include "nexthop_group_private.h" #include "frr_pthread.h" +#include "printfrr.h" #include "zebra/zebra_router.h" #include "zebra/connected.h" @@ -148,6 +149,30 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf); } +static char *_dump_re_status(const struct route_entry *re, char *buf, + size_t len) +{ + if (re->status == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr( + buf, len, "%s%s%s%s%s%s%s", + CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) + ? "Label Changed " + : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed " + : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG) ? "Fib NHG " + : ""); + return buf; +} + #define rnode_debug(node, vrf_id, ...) \ _rnode_zlog(__func__, vrf_id, node, LOG_DEBUG, __VA_ARGS__) #define rnode_info(node, ...) \ @@ -250,8 +275,8 @@ done: return ret; } -void rib_handle_nhg_replace(struct nhg_hash_entry *old, - struct nhg_hash_entry *new) +void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, + struct nhg_hash_entry *new_entry) { struct zebra_router_table *zrt; struct route_node *rn; @@ -259,15 +284,15 @@ void rib_handle_nhg_replace(struct nhg_hash_entry *old, if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p", - __func__, new->id, new, old); + __func__, new_entry->id, new_entry, old_entry); /* We have to do them ALL */ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) { for (rn = route_top(zrt->table); rn; rn = srcdest_route_next(rn)) { RNODE_FOREACH_RE_SAFE (rn, re, next) { - if (re->nhe && re->nhe == old) - route_entry_update_nhe(re, new); + if (re->nhe && re->nhe == old_entry) + route_entry_update_nhe(re, new_entry); } } } @@ -720,7 +745,7 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) if (rnh->seqno == seq) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tNode processed and moved already"); + " Node processed and moved already"); continue; } @@ -1080,12 +1105,20 @@ static void rib_process(struct route_node *rn) } RNODE_FOREACH_RE_SAFE (rn, re, next) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + char flags_buf[128]; + char status_buf[128]; + zlog_debug( - "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d", + "%s(%u:%u):%s: Examine re %p (%s) status: %sflags: %sdist %d metric %d", VRF_LOGNAME(vrf), vrf_id, re->table, buf, re, - zebra_route_string(re->type), re->status, - re->flags, re->distance, re->metric); + zebra_route_string(re->type), + _dump_re_status(re, status_buf, + sizeof(status_buf)), + zclient_dump_route_flags(re->flags, flags_buf, + sizeof(flags_buf)), + re->distance, re->metric); + } /* Currently selected re. */ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { @@ -1107,6 +1140,9 @@ static void rib_process(struct route_node *rn) */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { if (!nexthop_active_update(rn, re)) { + const struct prefix *p; + struct rib_table_info *info; + if (re->type == ZEBRA_ROUTE_TABLE) { /* XXX: HERE BE DRAGONS!!!!! * In all honesty, I have not yet @@ -1136,6 +1172,11 @@ static void rib_process(struct route_node *rn) ROUTE_ENTRY_REMOVED); } + info = srcdest_rnode_table_info(rn); + srcdest_rnode_prefixes(rn, &p, NULL); + zsend_route_notify_owner(re, p, + ZAPI_ROUTE_FAIL_INSTALL, + info->afi, info->safi); continue; } } else { @@ -2282,14 +2323,6 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex) UNSET_FLAG(rib_dest_from_rnode(rnode)->flags, RIB_ROUTE_QUEUED(qindex)); -#if 0 - else - { - zlog_debug ("%s: called for route_node (%p, %d) with no ribs", - __func__, rnode, route_node_get_lock_count(rnode)); - zlog_backtrace(LOG_DEBUG); - } -#endif route_unlock_node(rnode); } @@ -2791,6 +2824,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, bool is_srcdst = src_p && src_p->prefixlen; char straddr[PREFIX_STRLEN]; char srcaddr[PREFIX_STRLEN]; + char flags_buf[128]; + char status_buf[128]; struct nexthop *nexthop; struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); struct nexthop_group *nhg; @@ -2804,9 +2839,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", straddr, (unsigned long)re->uptime, re->type, re->instance, re->table); - zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", - straddr, re->metric, re->mtu, re->distance, re->flags, - re->status); + zlog_debug( + "%s: metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s", + straddr, re->metric, re->mtu, re->distance, + zclient_dump_route_flags(re->flags, flags_buf, + sizeof(flags_buf)), + _dump_re_status(re, status_buf, sizeof(status_buf))); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, nexthop_group_nexthop_num(&(re->nhe->nhg)), nexthop_group_active_nexthop_num(&(re->nhe->nhg))); @@ -2941,8 +2979,10 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, struct nhg_hash_entry *nhe = NULL; struct route_table *table; struct route_node *rn; - struct route_entry *same = NULL; + struct route_entry *same = NULL, *first_same = NULL; int ret = 0; + int same_count = 0; + rib_dest_t *dest; if (!re || !re_nhe) return -1; @@ -3010,14 +3050,22 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, * for the install don't do a route replace. */ RNODE_FOREACH_RE (rn, same) { - if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) + if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) { + same_count++; continue; + } /* Compare various route_entry properties */ - if (rib_compare_routes(re, same)) - break; + if (rib_compare_routes(re, same)) { + same_count++; + + if (first_same == NULL) + first_same = same; + } } + same = first_same; + /* If this route is kernel/connected route, notify the dataplane. */ if (RIB_SYSTEM_ROUTE(re)) { /* Notify dataplane */ @@ -3027,8 +3075,9 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { rnode_debug(rn, re->vrf_id, - "Inserting route rn %p, re %p (%s) existing %p", - rn, re, zebra_route_string(re->type), same); + "Inserting route rn %p, re %p (%s) existing %p, same_count %d", + rn, re, zebra_route_string(re->type), same, + same_count); if (IS_ZEBRA_DEBUG_RIB_DETAILED) route_entry_dump(p, src_p, re); @@ -3042,6 +3091,24 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, if (same) rib_delnode(rn, same); + /* See if we can remove some RE entries that are queued for + * removal, but won't be considered in rib processing. + */ + dest = rib_dest_from_rnode(rn); + RNODE_FOREACH_RE_SAFE (rn, re, same) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { + /* If the route was used earlier, must retain it. */ + if (dest && re == dest->selected_fib) + continue; + + if (IS_ZEBRA_DEBUG_RIB) + rnode_debug(rn, re->vrf_id, "rn %p, removing unneeded re %p", + rn, re); + + rib_unlink(rn, re); + } + } + route_unlock_node(rn); return ret; } @@ -3088,7 +3155,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, uint32_t flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, - uint8_t distance, bool fromkernel, bool connected_down) + uint8_t distance, bool fromkernel) { struct route_table *table; struct route_node *rn; @@ -3294,19 +3361,6 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, rib_delnode(rn, same); } - /* - * This is to force an immediate re-eval of this particular - * node via nexthop tracking. Why? Because there are scenarios - * where the interface is flapping and the normal queuing methodology - * will cause down/up events to very very rarely be combined into - * a non-event from nexthop tracking perspective. Leading - * to some fun timing situations with upper level routing protocol - * trying to and failing to install routes during this blip. Especially - * when zebra is under load. - */ - if (connected_down) - zebra_rib_evaluate_rn_nexthops(rn, - zebra_router_get_next_sequence()); route_unlock_node(rn); return; } @@ -3391,7 +3445,8 @@ static void rib_update_route_node(struct route_node *rn, int type) } /* Schedule routes of a particular table (address-family) based on event. */ -void rib_update_table(struct route_table *table, enum rib_update_event event) +void rib_update_table(struct route_table *table, enum rib_update_event event, + int rtype) { struct route_node *rn; @@ -3404,12 +3459,12 @@ void rib_update_table(struct route_table *table, enum rib_update_event event) : NULL; vrf = zvrf ? zvrf->vrf : NULL; - zlog_debug("%s: %s VRF %s Table %u event %s", __func__, + zlog_debug("%s: %s VRF %s Table %u event %s Route type: %s", __func__, table->info ? afi2str( ((struct rib_table_info *)table->info)->afi) : "Unknown", VRF_LOGNAME(vrf), zvrf ? zvrf->table_id : 0, - rib_update_event2str(event)); + rib_update_event2str(event), zebra_route_string(rtype)); } /* Walk all routes and queue for processing, if appropriate for @@ -3432,7 +3487,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event) break; case RIB_UPDATE_RMAP_CHANGE: case RIB_UPDATE_OTHER: - rib_update_route_node(rn, ZEBRA_ROUTE_ALL); + rib_update_route_node(rn, rtype); break; default: break; @@ -3440,7 +3495,8 @@ void rib_update_table(struct route_table *table, enum rib_update_event event) } } -static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event) +static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event, + int rtype) { struct route_table *table; @@ -3451,14 +3507,14 @@ static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event) /* Process routes of interested address-families. */ table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id); if (table) - rib_update_table(table, event); + rib_update_table(table, event, rtype); table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, vrf_id); if (table) - rib_update_table(table, event); + rib_update_table(table, event, rtype); } -static void rib_update_handle_vrf_all(enum rib_update_event event) +static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype) { struct zebra_router_table *zrt; @@ -3468,7 +3524,7 @@ static void rib_update_handle_vrf_all(enum rib_update_event event) /* Just iterate over all the route tables, rather than vrf lookups */ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) - rib_update_table(zrt->table, event); + rib_update_table(zrt->table, event, rtype); } struct rib_update_ctx { @@ -3502,9 +3558,9 @@ static int rib_update_handler(struct thread *thread) ctx = THREAD_ARG(thread); if (ctx->vrf_all) - rib_update_handle_vrf_all(ctx->event); + rib_update_handle_vrf_all(ctx->event, ZEBRA_ROUTE_ALL); else - rib_update_handle_vrf(ctx->vrf_id, ctx->event); + rib_update_handle_vrf(ctx->vrf_id, ctx->event, ZEBRA_ROUTE_ALL); rib_update_ctx_fini(&ctx); @@ -3517,26 +3573,6 @@ static int rib_update_handler(struct thread *thread) */ static struct thread *t_rib_update_threads[RIB_UPDATE_MAX]; -/* Schedule a RIB update event for specific vrf */ -void rib_update_vrf(vrf_id_t vrf_id, enum rib_update_event event) -{ - struct rib_update_ctx *ctx; - - ctx = rib_update_ctx_init(vrf_id, event); - - /* Don't worry about making sure multiple rib updates for specific vrf - * are scheduled at once for now. If it becomes a problem, we can use a - * lookup of some sort to keep track of running threads via t_vrf_id - * like how we are doing it in t_rib_update_threads[]. - */ - thread_add_event(zrouter.master, rib_update_handler, ctx, 0, NULL); - - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: Scheduled VRF %s, event %s", __func__, - vrf_id_to_name(ctx->vrf_id), - rib_update_event2str(event)); -} - /* Schedule a RIB update event for all vrfs */ void rib_update(enum rib_update_event event) { |
