summaryrefslogtreecommitdiff
path: root/zebra/zebra_rib.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r--zebra/zebra_rib.c180
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)
{