diff options
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 287 |
1 files changed, 178 insertions, 109 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 59190e9dd3..2d2be4fc78 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -316,12 +316,18 @@ static ssize_t printfrr_zebra_node(struct fbuf *buf, struct printfrr_eargs *ea, } #define rnode_debug(node, vrf_id, msg, ...) \ - zlog_debug("%s: (%u:%pZNt):%pZN: " msg, __func__, vrf_id, node, node, \ - ##__VA_ARGS__) + do { \ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); \ + zlog_debug("%s: (%s:%pZNt):%pZN: " msg, __func__, \ + VRF_LOGNAME(vrf), node, node, ##__VA_ARGS__); \ + } while (0) #define rnode_info(node, vrf_id, msg, ...) \ - zlog_info("%s: (%u:%pZNt):%pZN: " msg, __func__, vrf_id, node, node, \ - ##__VA_ARGS__) + do { \ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); \ + zlog_info("%s: (%s:%pZNt):%pZN: " msg, __func__, \ + VRF_LOGNAME(vrf), node, node, ##__VA_ARGS__); \ + } while (0) static char *_dump_re_status(const struct route_entry *re, char *buf, size_t len) @@ -605,45 +611,6 @@ struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id, return re; } -struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *match = NULL; - rib_dest_t *dest; - - /* Lookup table. */ - table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id); - if (!table) - return 0; - - rn = route_node_lookup(table, (struct prefix *)p); - - /* No route for this prefix. */ - if (!rn) - return NULL; - - /* Unlock node. */ - route_unlock_node(rn); - dest = rib_dest_from_rnode(rn); - - if (dest && dest->selected_fib - && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED)) - match = dest->selected_fib; - - if (!match) - return NULL; - - if (match->type == ZEBRA_ROUTE_CONNECT || - match->type == ZEBRA_ROUTE_LOCAL) - return match; - - if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) - return match; - - return NULL; -} - /* * Is this RIB labeled-unicast? It must be of type BGP and all paths * (nexthops) must have a label. @@ -651,8 +618,10 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) int zebra_rib_labeled_unicast(struct route_entry *re) { struct nexthop *nexthop = NULL; + struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); - if (re->type != ZEBRA_ROUTE_BGP) + if ((re->type != ZEBRA_ROUTE_BGP) && + !zvrf->zebra_mpls_fec_nexthop_resolution) return 0; for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) @@ -688,7 +657,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, /* * Install the resolved nexthop object first. */ - zebra_nhg_install_kernel(re->nhe); + zebra_nhg_install_kernel(re->nhe, re->type); /* * If this is a replace to a new RE let the originator of the RE @@ -1305,7 +1274,7 @@ static void rib_process(struct route_node *rn) */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { proto_re_changed = re; - if (!nexthop_active_update(rn, re)) { + if (!nexthop_active_update(rn, re, old_fib)) { const struct prefix *p; struct rib_table_info *info; @@ -1619,6 +1588,10 @@ static bool rib_compare_routes(const struct route_entry *re1, * v6 link-locals, and we also support multiple addresses in the same * subnet on a single interface. */ + if (re1->type == ZEBRA_ROUTE_CONNECT && + (re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex)) + return true; + if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL) return true; @@ -2863,10 +2836,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) /* 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, same_count %d", - rn, re, zebra_route_string(re->type), same, same_count); + rnode_debug(rn, re->vrf_id, + "Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d", + rn, re, zebra_route_string(re->type), + afi2str(ere->afi), safi2str(ere->safi), same, + same_count); if (IS_ZEBRA_DEBUG_RIB_DETAILED) route_entry_dump( @@ -4105,9 +4079,8 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) /* * Helper that debugs a single nexthop within a route-entry */ -static void _route_entry_dump_nh(const struct route_entry *re, - const char *straddr, - const struct nexthop *nexthop) +void route_entry_dump_nh(const struct route_entry *re, const char *straddr, + const struct vrf *re_vrf, const struct nexthop *nexthop) { char nhname[PREFIX_STRLEN]; char backup_str[50]; @@ -4161,35 +4134,32 @@ static void _route_entry_dump_nh(const struct route_entry *re, if (nexthop->weight) snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight); - zlog_debug("%s: %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s%s", - straddr, (nexthop->rparent ? " NH" : "NH"), nhname, - nexthop->ifindex, label_str, vrf ? vrf->name : "Unknown", - nexthop->vrf_id, + zlog_debug("%s(%s): %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s%s", + straddr, VRF_LOGNAME(re_vrf), + (nexthop->rparent ? " NH" : "NH"), nhname, nexthop->ifindex, + label_str, vrf ? vrf->name : "Unknown", nexthop->vrf_id, wgt_str, backup_str, - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) - ? "ACTIVE " - : ""), - (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) - ? "FIB " - : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " + : ""), + (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "FIB " : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) - ? "RECURSIVE " - : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) - ? "ONLINK " - : ""), + ? "RECURSIVE " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) ? "ONLINK " + : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE) - ? "DUPLICATE " - : ""), + ? "DUPLICATE " + : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED) - ? "FILTERED " : ""), + ? "FILTERED " + : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) - ? "BACKUP " : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE) - ? "SRTE " : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN) - ? "EVPN " : "")); - + ? "BACKUP " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE) ? "SRTE " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN) ? "EVPN " + : "")); } /* This function dumps the contents of a given RE entry into @@ -4218,32 +4188,33 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr)) : "", VRF_LOGNAME(vrf), re->vrf_id); - 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 == %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: tag == %u, nexthop_num == %u, nexthop_active_num == %u", - straddr, re->tag, nexthop_group_nexthop_num(&(re->nhe->nhg)), + zlog_debug("%s(%s): uptime == %lu, type == %u, instance == %d, table == %d", + straddr, VRF_LOGNAME(vrf), (unsigned long)re->uptime, + re->type, re->instance, re->table); + zlog_debug("%s(%s): metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s", + straddr, VRF_LOGNAME(vrf), 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(%s): tag == %u, nexthop_num == %u, nexthop_active_num == %u", + straddr, VRF_LOGNAME(vrf), re->tag, + nexthop_group_nexthop_num(&(re->nhe->nhg)), nexthop_group_active_nexthop_num(&(re->nhe->nhg))); /* Dump nexthops */ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - _route_entry_dump_nh(re, straddr, nexthop); + route_entry_dump_nh(re, straddr, vrf, nexthop); if (zebra_nhg_get_backup_nhg(re->nhe)) { - zlog_debug("%s: backup nexthops:", straddr); + zlog_debug("%s(%s): backup nexthops:", straddr, + VRF_LOGNAME(vrf)); nhg = zebra_nhg_get_backup_nhg(re->nhe); for (ALL_NEXTHOPS_PTR(nhg, nexthop)) - _route_entry_dump_nh(re, straddr, nexthop); + route_entry_dump_nh(re, straddr, vrf, nexthop); } - zlog_debug("%s: dump complete", straddr); + zlog_debug("%s(%s): dump complete", straddr, VRF_LOGNAME(vrf)); } static int rib_meta_queue_gr_run_add(struct meta_queue *mq, void *data) @@ -4264,11 +4235,14 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) listnode_add(mq->subq[META_QUEUE_EARLY_ROUTE], data); mq->size++; - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("Route %pFX(%u) (%s) queued for processing into sub-queue %s", - &ere->p, ere->re->vrf_id, + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct vrf *vrf = vrf_lookup_by_id(ere->re->vrf_id); + + zlog_debug("Route %pFX(%s) (%s) queued for processing into sub-queue %s", + &ere->p, VRF_LOGNAME(vrf), ere->deletion ? "delete" : "add", subqueue2str(META_QUEUE_EARLY_ROUTE)); + } return 0; } @@ -4370,19 +4344,55 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, return -1; /* We either need nexthop(s) or an existing nexthop id */ - if (ng == NULL && re->nhe_id == 0) + if (ng == NULL && re->nhe_id == 0) { + zebra_rib_route_entry_free(re); return -1; + } /* * Use a temporary nhe to convey info to the common/main api. */ zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL)); - if (ng) + if (ng) { nhe.nhg.nexthop = ng->nexthop; - else if (re->nhe_id > 0) + + if (re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL || + re->type == ZEBRA_ROUTE_KERNEL) + SET_FLAG(nhe.flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL); + } else if (re->nhe_id > 0) nhe.id = re->nhe_id; n = zebra_nhe_copy(&nhe, 0); + + if (re->type == ZEBRA_ROUTE_KERNEL) { + struct interface *ifp; + struct connected *connected; + + if (p->family == AF_INET6 && + IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) { + zebra_nhg_free(n); + zebra_rib_route_entry_free(re); + return -1; + } + + ifp = if_lookup_prefix(p, re->vrf_id); + if (ifp) { + connected = connected_lookup_prefix(ifp, p); + + if (connected && !CHECK_FLAG(connected->flags, + ZEBRA_IFA_NOPREFIXROUTE)) { + zebra_nhg_free(n); + zebra_rib_route_entry_free(re); + return -1; + } + + if (ng && ng->nexthop && + ifp->ifindex == ng->nexthop->ifindex) + re->type = ZEBRA_ROUTE_CONNECT; + } + } + ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup); /* In error cases, free the route also */ @@ -4393,8 +4403,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, } 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, + unsigned short instance, uint32_t flags, const struct prefix *p, + const 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) { @@ -4458,6 +4468,9 @@ static const char *rib_update_event2str(enum rib_update_event event) const char *ret = "UNKNOWN"; switch (event) { + case RIB_UPDATE_INTERFACE_DOWN: + ret = "RIB_UPDATE_INTERFACE_DOWN"; + break; case RIB_UPDATE_KERNEL: ret = "RIB_UPDATE_KERNEL"; break; @@ -4474,15 +4487,56 @@ static const char *rib_update_event2str(enum rib_update_event event) return ret; } +/* + * We now keep kernel routes, but we don't have any + * trigger events for them when they are implicitly + * deleted. Since we are already walking the + * entire table on a down event let's look at + * the few kernel routes we may have + */ +static void +rib_update_handle_kernel_route_down_possibility(struct route_node *rn, + struct route_entry *re) +{ + struct nexthop *nexthop = NULL; + bool alive = false; + + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { + struct interface *ifp = if_lookup_by_index(nexthop->ifindex, + nexthop->vrf_id); + + if (ifp && if_is_up(ifp)) { + alive = true; + break; + } + } + + if (!alive) { + struct rib_table_info *rib_table = srcdest_rnode_table_info(rn); + const struct prefix *p; + const struct prefix_ipv6 *src_p; + + srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p); + + rib_delete(rib_table->afi, rib_table->safi, re->vrf_id, + re->type, re->instance, re->flags, p, src_p, NULL, 0, + re->table, re->metric, re->distance, true); + } +} + /* Schedule route nodes to be processed if they match the type */ -static void rib_update_route_node(struct route_node *rn, int type) +static void rib_update_route_node(struct route_node *rn, int type, + enum rib_update_event event) { struct route_entry *re, *next; bool re_changed = false; RNODE_FOREACH_RE_SAFE (rn, re, next) { - if (type == ZEBRA_ROUTE_ALL || type == re->type) { + if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type && + type == ZEBRA_ROUTE_KERNEL) + rib_update_handle_kernel_route_down_possibility(rn, re); + else if (type == ZEBRA_ROUTE_ALL || type == re->type) { SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); re_changed = true; } @@ -4522,20 +4576,24 @@ void rib_update_table(struct route_table *table, enum rib_update_event event, /* * If we are looking at a route node and the node * has already been queued we don't - * need to queue it up again + * need to queue it up again, unless it is + * an interface down event as that we need + * to process this no matter what. */ - if (rn->info - && CHECK_FLAG(rib_dest_from_rnode(rn)->flags, - RIB_ROUTE_ANY_QUEUED)) + if (rn->info && + CHECK_FLAG(rib_dest_from_rnode(rn)->flags, + RIB_ROUTE_ANY_QUEUED) && + event != RIB_UPDATE_INTERFACE_DOWN) continue; switch (event) { + case RIB_UPDATE_INTERFACE_DOWN: case RIB_UPDATE_KERNEL: - rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL); + rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event); break; case RIB_UPDATE_RMAP_CHANGE: case RIB_UPDATE_OTHER: - rib_update_route_node(rn, rtype); + rib_update_route_node(rn, rtype, event); break; case RIB_UPDATE_MAX: break; @@ -4543,7 +4601,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event, } } -static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype) +void rib_update_handle_vrf_all(enum rib_update_event event, int rtype) { struct zebra_router_table *zrt; @@ -5019,6 +5077,17 @@ static int rib_dplane_results(struct dplane_ctx_list_head *ctxlist) return 0; } +uint32_t zebra_rib_dplane_results_count(void) +{ + uint32_t count; + + frr_with_mutex (&dplane_mutex) { + count = dplane_ctx_queue_count(&rib_dplane_q); + } + + return count; +} + /* * Ensure there are no empty slots in the route_info array. * Every route type in zebra should be present there. |
