diff options
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 626 |
1 files changed, 309 insertions, 317 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8285392527..1eda55dca0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -73,31 +73,32 @@ extern int allow_delete; static const struct { int key; int distance; + uint8_t meta_q_map; } route_info[ZEBRA_ROUTE_MAX] = { - [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0}, - [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0}, - [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0}, - [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1}, - [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120}, - [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120}, - [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110}, - [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110}, - [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115}, - [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */}, - [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255}, - [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90}, - [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10}, - [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255}, - [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255}, - [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150}, - [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150}, - [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20}, - [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20}, - [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20}, - [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20}, - [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20}, - [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100}, - [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150}, + [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 4}, + [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 0}, + [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 0}, + [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 1}, + [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 2}, + [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 2}, + [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 2}, + [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 2}, + [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 2}, + [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 3}, + [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 4}, + [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 2}, + [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 2}, + [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 4}, + [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 4}, + [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 1}, + [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 4}, + [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 3}, + [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 3}, + [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 3}, + [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 3}, + [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 3}, + [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 2}, + [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 4}, /* no entry/default: 150 */ }; @@ -276,8 +277,7 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, There was a crash because ifp here was coming to be NULL */ if (ifp) if (connected_is_unnumbered(ifp) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) { + || CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) { SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); } @@ -314,10 +314,8 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) { + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - } route_entry_nexthop_add(re, nexthop); @@ -412,7 +410,7 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static int nexthop_active(afi_t afi, struct route_entry *re, - struct nexthop *nexthop, int set, + struct nexthop *nexthop, bool set, struct route_node *top) { struct prefix p; @@ -456,8 +454,15 @@ static int nexthop_active(afi_t afi, struct route_entry *re, */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); - if ((ifp && connected_is_unnumbered(ifp)) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) { + if (!ifp) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "\t%s: Onlink and interface: %u[%u] does not exist", + __PRETTY_FUNCTION__, nexthop->ifindex, + nexthop->vrf_id); + return 0; + } + if (connected_is_unnumbered(ifp)) { if (if_is_operative(ifp)) return 1; else { @@ -467,7 +472,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, __PRETTY_FUNCTION__, ifp->name); return 0; } - } else { + } + if (!if_is_operative(ifp)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "\t%s: Interface %s is not unnumbered", @@ -565,8 +571,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; for (ALL_NEXTHOPS(match->ng, newhop)) { - if (!CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) + if (!CHECK_FLAG(match->status, + ROUTE_ENTRY_INSTALLED)) continue; if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -591,8 +597,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; for (ALL_NEXTHOPS(match->ng, newhop)) { - if (!CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) + if (!CHECK_FLAG(match->status, + ROUTE_ENTRY_INSTALLED)) continue; if (set) { @@ -636,7 +642,6 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, struct route_table *table; struct route_node *rn; struct route_entry *match = NULL; - struct nexthop *newhop; /* Lookup table. */ table = zebra_vrf_table(afi, safi, vrf_id); @@ -676,14 +681,8 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, route_lock_node(rn); } else { if (match->type != ZEBRA_ROUTE_CONNECT) { - int found = 0; - for (ALL_NEXTHOPS(match->ng, newhop)) - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) { - found = 1; - break; - } - if (!found) + if (!CHECK_FLAG(match->status, + ROUTE_ENTRY_INSTALLED)) return NULL; } @@ -773,7 +772,6 @@ 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; - struct nexthop *nexthop; rib_dest_t *dest; /* Lookup table. */ @@ -801,91 +799,12 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) if (match->type == ZEBRA_ROUTE_CONNECT) return match; - for (ALL_NEXTHOPS(match->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) - return match; + if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) + return match; return NULL; } -/* - * This clone function, unlike its original rib_lookup_ipv4(), checks - * if specified IPv4 route record (prefix/mask -> gate) exists in - * the whole RIB and has ROUTE_ENTRY_SELECTED_FIB set. - * - * Return values: - * -1: error - * 0: exact match found - * 1: a match was found with a different gate - * 2: connected route found - * 3: no matches found - */ -int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate, - vrf_id_t vrf_id) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *match = NULL; - struct nexthop *nexthop; - int nexthops_active; - rib_dest_t *dest; - - /* Lookup table. */ - table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id); - if (!table) - return ZEBRA_RIB_LOOKUP_ERROR; - - /* Scan the RIB table for exactly matching RIB entry. */ - rn = route_node_lookup(table, (struct prefix *)p); - - /* No route for this prefix. */ - if (!rn) - return ZEBRA_RIB_NOTFOUND; - - /* Unlock node. */ - route_unlock_node(rn); - dest = rib_dest_from_rnode(rn); - - /* Find out if a "selected" RR for the discovered RIB entry exists ever. - */ - if (dest && dest->selected_fib - && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED)) - match = dest->selected_fib; - - /* None such found :( */ - if (!match) - return ZEBRA_RIB_NOTFOUND; - - if (match->type == ZEBRA_ROUTE_CONNECT) - return ZEBRA_RIB_FOUND_CONNECTED; - - /* Ok, we have a cood candidate, let's check it's nexthop list... */ - nexthops_active = 0; - for (ALL_NEXTHOPS(match->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - nexthops_active = 1; - if (nexthop->gate.ipv4.s_addr == sockunion2ip(qgate)) - return ZEBRA_RIB_FOUND_EXACT; - if (IS_ZEBRA_DEBUG_RIB) { - char gate_buf[INET_ADDRSTRLEN], - qgate_buf[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &nexthop->gate.ipv4.s_addr, - gate_buf, INET_ADDRSTRLEN); - inet_ntop(AF_INET, &sockunion2ip(qgate), - qgate_buf, INET_ADDRSTRLEN); - zlog_debug("%s: qgate == %s, %s == %s", - __func__, qgate_buf, - nexthop->rparent ? "rgate" : "gate", - gate_buf); - } - } - - if (nexthops_active) - return ZEBRA_RIB_FOUND_NOGATE; - - return ZEBRA_RIB_NOTFOUND; -} - #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -904,7 +823,7 @@ int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate, static unsigned nexthop_active_check(struct route_node *rn, struct route_entry *re, - struct nexthop *nexthop, int set) + struct nexthop *nexthop, bool set) { struct interface *ifp; route_map_result_t ret = RMAP_MATCH; @@ -1031,7 +950,7 @@ static unsigned nexthop_active_check(struct route_node *rn, */ static int nexthop_active_update(struct route_node *rn, struct route_entry *re, - int set) + bool set) { struct nexthop *nexthop; union g_addr prev_src; @@ -1049,7 +968,18 @@ static int nexthop_active_update(struct route_node *rn, struct route_entry *re, prev_src = nexthop->rmap_src; prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; - if ((new_active = nexthop_active_check(rn, re, nexthop, set))) + /* + * We need to respect the multipath_num here + * as that what we should be able to install from + * a multipath perpsective should not be a data plane + * decision point. + */ + new_active = nexthop_active_check(rn, re, nexthop, set); + if (new_active && re->nexthop_active_num >= multipath_num) { + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + new_active = 0; + } + if (new_active) re->nexthop_active_num++; /* Don't allow src setting on IPv6 addr for now */ if (prev_active != new_active || prev_index != nexthop->ifindex @@ -1155,6 +1085,9 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: + SET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + if (old) + SET_FLAG(old->status, ROUTE_ENTRY_QUEUED); if (zvrf) zvrf->installs_queued++; break; @@ -1185,6 +1118,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); if (info->safi != SAFI_UNICAST) { + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (ALL_NEXTHOPS(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; @@ -1237,6 +1171,8 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) if (!RIB_SYSTEM_ROUTE(re)) rib_uninstall_kernel(rn, re); + else + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); dest->selected_fib = NULL; @@ -1322,7 +1258,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, /* Update real nexthop. This may actually determine if nexthop is active * or not. */ - if (!nexthop_active_update(rn, new, 1)) { + if (!nexthop_active_update(rn, new, true)) { UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); return; } @@ -1367,6 +1303,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); else { + UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); /* * We are setting this to NULL here * because that is what we traditionally @@ -1383,7 +1320,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, * down, causing the kernel to delete routes without sending DELROUTE * notifications */ - if (!nexthop_active_update(rn, old, 1) && + if (!nexthop_active_update(rn, old, true) && (RIB_KERNEL_ROUTE(old))) SET_FLAG(old->status, ROUTE_ENTRY_REMOVED); else @@ -1408,7 +1345,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update the nexthop; we could determine here that nexthop is * inactive. */ - if (nexthop_active_update(rn, new, 1)) + if (nexthop_active_update(rn, new, true)) nh_active = 1; /* If nexthop is active, install the selected route, if @@ -1447,6 +1384,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, rib_install_kernel(rn, new, old); } else { + UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED); /* * We do not need to install the * selected route because it @@ -1466,7 +1404,13 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (RIB_SYSTEM_ROUTE(new)) { if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); + else + UNSET_FLAG( + old->status, + ROUTE_ENTRY_INSTALLED); } else { + UNSET_FLAG(old->status, + ROUTE_ENTRY_INSTALLED); for (nexthop = old->ng.nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG(nexthop->flags, @@ -1503,8 +1447,10 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); - else + else { + UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); dest->selected_fib = NULL; + } } } else { /* @@ -1516,24 +1462,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * is ready * to add routes. */ - if (!RIB_SYSTEM_ROUTE(new)) { - bool in_fib = false; - - for (ALL_NEXTHOPS(new->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB)) { - in_fib = true; - break; - } - if (!in_fib) - rib_install_kernel(rn, new, NULL); - } + if (!RIB_SYSTEM_ROUTE(new) + && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED)) + rib_install_kernel(rn, new, NULL); } /* Update prior route. */ if (new != old) { /* Set real nexthop. */ - nexthop_active_update(rn, old, 1); + nexthop_active_update(rn, old, true); UNSET_FLAG(old->status, ROUTE_ENTRY_CHANGED); } @@ -1682,7 +1619,7 @@ static void rib_process(struct route_node *rn) * recursive NHs. */ if (!CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) - && !nexthop_active_update(rn, re, 0)) { + && !nexthop_active_update(rn, re, false)) { if (re->type == ZEBRA_ROUTE_TABLE) { /* XXX: HERE BE DRAGONS!!!!! * In all honesty, I have not yet figured out @@ -1774,7 +1711,7 @@ static void rib_process(struct route_node *rn) if (old_selected != new_selected || selected_changed) { if (new_selected && new_selected != new_fib) { - nexthop_active_update(rn, new_selected, 1); + nexthop_active_update(rn, new_selected, true); UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED); } @@ -1877,7 +1814,7 @@ done: /* * Route-update results processing after async dataplane update. */ -static void rib_process_after(struct zebra_dplane_ctx *ctx) +static void rib_process_result(struct zebra_dplane_ctx *ctx) { struct route_table *table = NULL; struct zebra_vrf *zvrf = NULL; @@ -1932,36 +1869,10 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) op = dplane_ctx_get_op(ctx); status = dplane_ctx_get_status(ctx); - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug("%u:%s Processing dplane ctx %p, op %s result %s", dplane_ctx_get_vrf(ctx), dest_str, ctx, dplane_op2str(op), dplane_res2str(status)); - } - - if (op == DPLANE_OP_ROUTE_DELETE) { - /* - * In the delete case, the zebra core datastructs were - * updated (or removed) at the time the delete was issued, - * so we're just notifying the route owner. - */ - if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { - zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED); - - if (zvrf) - zvrf->removals++; - } else { - zsend_route_notify_owner_ctx(ctx, - ZAPI_ROUTE_FAIL_INSTALL); - - zlog_warn("%u:%s: Route Deletion failure", - dplane_ctx_get_vrf(ctx), - prefix2str(dest_pfx, - dest_str, sizeof(dest_str))); - } - - /* Nothing more to do in delete case */ - goto done; - } /* * Update is a bit of a special case, where we may have both old and new @@ -1994,87 +1905,138 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) /* * Check sequence number(s) to detect stale results before continuing */ - if (re && (re->dplane_sequence != dplane_ctx_get_seq(ctx))) { - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - zlog_debug("%u:%s Stale dplane result for re %p", - dplane_ctx_get_vrf(ctx), dest_str, re); - } - re = NULL; - } + if (re) { + if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%u:%s Stale dplane result for re %p", + dplane_ctx_get_vrf(ctx), + dest_str, re); + } else + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + } + + if (old_re) { + if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%u:%s Stale dplane result for old_re %p", + dplane_ctx_get_vrf(ctx), + dest_str, old_re); + } else + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + } + + switch (op) { + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + if (re) { + UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED); + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + } + if (old_re) { + UNSET_FLAG(old_re->status, ROUTE_ENTRY_FAILED); + UNSET_FLAG(old_re->status, + ROUTE_ENTRY_INSTALLED); + } + /* Update zebra nexthop FIB flag for each + * nexthop that was installed. + */ + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), + ctx_nexthop)) { - if (old_re && - (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx))) { - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - zlog_debug("%u:%s Stale dplane result for old_re %p", - dplane_ctx_get_vrf(ctx), dest_str, old_re); - } - old_re = NULL; - } + if (!re) + continue; - /* - * Here's sort of a tough one: the route update result is stale. - * Is it better to use the context block info to generate - * redist and owner notification, or is it better to wait - * for the up-to-date result to arrive? - */ - if (re == NULL) { - /* TODO -- for now, only expose up-to-date results */ - goto done; - } + for (ALL_NEXTHOPS(re->ng, nexthop)) { + if (nexthop_same(ctx_nexthop, nexthop)) + break; + } - if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { - /* Update zebra nexthop FIB flag for each - * nexthop that was installed. - */ - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) { + if (nexthop == NULL) + continue; - for (ALL_NEXTHOPS(re->ng, nexthop)) { - if (nexthop_same(ctx_nexthop, nexthop)) - break; + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; + + if (CHECK_FLAG(ctx_nexthop->flags, + NEXTHOP_FLAG_FIB)) + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB); + else + UNSET_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB); } - if (nexthop == NULL) - continue; + if (zvrf) { + zvrf->installs++; + /* Set flag for nexthop tracking processing */ + zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED; + } - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; + /* Redistribute */ + /* + * TODO -- still calling the redist api using the + * route_entries, and there's a corner-case here: + * if there's no client for the 'new' route, a redist + * deleting the 'old' route will be sent. But if the + * 'old' context info was stale, 'old_re' will be + * NULL here and that delete will not be sent. + */ + if (re) + redistribute_update(dest_pfx, src_pfx, + re, old_re); - if (CHECK_FLAG(ctx_nexthop->flags, - NEXTHOP_FLAG_FIB)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - else - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - } + /* Notify route owner */ + zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED); - if (zvrf) { - zvrf->installs++; - /* Set flag for nexthop tracking processing */ - zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED; + } else { + if (re) + SET_FLAG(re->status, ROUTE_ENTRY_FAILED); + if (old_re) + SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED); + if (re) + zsend_route_notify_owner(re, dest_pfx, + ZAPI_ROUTE_FAIL_INSTALL); + + zlog_warn("%u:%s: Route install failed", + dplane_ctx_get_vrf(ctx), + prefix2str(dest_pfx, + dest_str, sizeof(dest_str))); } - - /* Redistribute */ - /* TODO -- still calling the redist api using the route_entries, - * and there's a corner-case here: if there's no client - * for the 'new' route, a redist deleting the 'old' route - * will be sent. But if the 'old' context info was stale, - * 'old_re' will be NULL here and that delete will not be sent. + break; + case DPLANE_OP_ROUTE_DELETE: + if (re) + SET_FLAG(re->status, ROUTE_ENTRY_FAILED); + /* + * In the delete case, the zebra core datastructs were + * updated (or removed) at the time the delete was issued, + * so we're just notifying the route owner. */ - redistribute_update(dest_pfx, src_pfx, re, old_re); - - /* Notify route owner */ - zsend_route_notify_owner(re, - dest_pfx, ZAPI_ROUTE_INSTALLED); + if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + if (re) { + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED); + } + zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED); - } else { - zsend_route_notify_owner(re, dest_pfx, - ZAPI_ROUTE_FAIL_INSTALL); + if (zvrf) + zvrf->removals++; + } else { + if (re) + SET_FLAG(re->status, ROUTE_ENTRY_FAILED); + zsend_route_notify_owner_ctx(ctx, + ZAPI_ROUTE_REMOVE_FAIL); - zlog_warn("%u:%s: Route install failed", - dplane_ctx_get_vrf(ctx), - prefix2str(dest_pfx, - dest_str, sizeof(dest_str))); + zlog_warn("%u:%s: Route Deletion failure", + dplane_ctx_get_vrf(ctx), + prefix2str(dest_pfx, + dest_str, sizeof(dest_str))); + } + break; + default: + break; } - done: /* Return context to dataplane module */ @@ -2149,11 +2111,11 @@ static void do_nht_processing(void) zvrf_name(zvrf)); zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED; - zebra_evaluate_rnh(zvrf, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, + zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_IMPORT_CHECK_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_IMPORT_CHECK_TYPE, NULL); } @@ -2211,73 +2173,66 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) return mq->size ? WQ_REQUEUE : WQ_SUCCESS; } -/* - * Map from rib types to queue type (priority) in meta queue - */ -static const uint8_t meta_queue_map[ZEBRA_ROUTE_MAX] = { - [ZEBRA_ROUTE_SYSTEM] = 4, - [ZEBRA_ROUTE_KERNEL] = 0, - [ZEBRA_ROUTE_CONNECT] = 0, - [ZEBRA_ROUTE_STATIC] = 1, - [ZEBRA_ROUTE_RIP] = 2, - [ZEBRA_ROUTE_RIPNG] = 2, - [ZEBRA_ROUTE_OSPF] = 2, - [ZEBRA_ROUTE_OSPF6] = 2, - [ZEBRA_ROUTE_ISIS] = 2, - [ZEBRA_ROUTE_BGP] = 3, - [ZEBRA_ROUTE_PIM] = 4, // Shouldn't happen but for safety - [ZEBRA_ROUTE_EIGRP] = 2, - [ZEBRA_ROUTE_NHRP] = 2, - [ZEBRA_ROUTE_HSLS] = 4, - [ZEBRA_ROUTE_OLSR] = 4, - [ZEBRA_ROUTE_TABLE] = 1, - [ZEBRA_ROUTE_LDP] = 4, - [ZEBRA_ROUTE_VNC] = 3, - [ZEBRA_ROUTE_VNC_DIRECT] = 3, - [ZEBRA_ROUTE_VNC_DIRECT_RH] = 3, - [ZEBRA_ROUTE_BGP_DIRECT] = 3, - [ZEBRA_ROUTE_BGP_DIRECT_EXT] = 3, - [ZEBRA_ROUTE_BABEL] = 2, - [ZEBRA_ROUTE_ALL] = 4, // Shouldn't happen but for safety -}; -/* Look into the RN and queue it into one or more priority queues, - * increasing the size for each data push done. +/* + * Look into the RN and queue it into the highest priority queue + * at this point in time for processing. + * + * We will enqueue a route node only once per invocation. + * + * There are two possibilities here that should be kept in mind. + * If the original invocation has not been pulled off for processing + * yet, A subsuquent invocation can have a route entry with a better + * meta queue index value and we can have a situation where + * we might have the same node enqueued 2 times. Not necessarily + * an optimal situation but it should be ok. + * + * The other possibility is that the original invocation has not + * been pulled off for processing yet, A subsusquent invocation + * doesn't have a route_entry with a better meta-queue and the + * original metaqueue index value will win and we'll end up with + * the route node enqueued once. */ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) { - struct route_entry *re; + struct route_entry *re = NULL, *curr_re = NULL; + uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE; + struct zebra_vrf *zvrf; - RNODE_FOREACH_RE (rn, re) { - uint8_t qindex = meta_queue_map[re->type]; - struct zebra_vrf *zvrf; + RNODE_FOREACH_RE (rn, curr_re) { + curr_qindex = route_info[curr_re->type].meta_q_map; - /* Invariant: at this point we always have rn->info set. */ - if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, - RIB_ROUTE_QUEUED(qindex))) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - rnode_debug( - rn, re->vrf_id, - "rn %p is already queued in sub-queue %u", - (void *)rn, qindex); - continue; + if (curr_qindex <= qindex) { + re = curr_re; + qindex = curr_qindex; } + } - SET_FLAG(rib_dest_from_rnode(rn)->flags, - RIB_ROUTE_QUEUED(qindex)); - listnode_add(mq->subq[qindex], rn); - route_lock_node(rn); - mq->size++; + if (!re) + return; + /* Invariant: at this point we always have rn->info set. */ + if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, + RIB_ROUTE_QUEUED(qindex))) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) rnode_debug(rn, re->vrf_id, - "queued rn %p into sub-queue %u", + "rn %p is already queued in sub-queue %u", (void *)rn, qindex); - - zvrf = zebra_vrf_lookup_by_id(re->vrf_id); - if (zvrf) - zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED; + return; } + + SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex)); + listnode_add(mq->subq[qindex], rn); + route_lock_node(rn); + mq->size++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u", + (void *)rn, qindex); + + zvrf = zebra_vrf_lookup_by_id(re->vrf_id); + if (zvrf) + zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED; } /* Add route_node to work queue and schedule processing */ @@ -2363,6 +2318,7 @@ static void rib_queue_init(struct zebra_t *zebra) /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; zebra->ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; + zebra->ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; if (!(zebra->mq = meta_queue_new())) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, @@ -2592,7 +2548,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) + (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "FIB " : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) @@ -2773,9 +2729,11 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, } /* If this route is kernel route, set FIB flag to the route. */ - if (RIB_SYSTEM_ROUTE(re)) + if (RIB_SYSTEM_ROUTE(re)) { + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { @@ -2912,6 +2870,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, rn, fib, fib->type); } if (allow_delete) { + UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ for (rtnh = fib->ng.nexthop; rtnh; rtnh = rtnh->next) @@ -3158,6 +3117,7 @@ void rib_sweep_table(struct route_table *table) * to a different spot (ie startup ) * this decision needs to be revisited */ + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (ALL_NEXTHOPS(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); @@ -3256,26 +3216,59 @@ void rib_close_table(struct route_table *table) } /* - * + * Handle results from the dataplane system. Dequeue update context + * structs, dispatch to appropriate internal handlers. */ static int rib_process_dplane_results(struct thread *thread) { struct zebra_dplane_ctx *ctx; + struct dplane_ctx_q ctxlist; + + /* Dequeue a list of completed updates with one lock/unlock cycle */ + + /* TODO -- dequeue a list with one lock/unlock cycle? */ do { + TAILQ_INIT(&ctxlist); + /* Take lock controlling queue of results */ pthread_mutex_lock(&dplane_mutex); { - /* Dequeue context block */ - dplane_ctx_dequeue(&rib_dplane_q, &ctx); + /* Dequeue list of context structs */ + dplane_ctx_list_append(&ctxlist, &rib_dplane_q); } pthread_mutex_unlock(&dplane_mutex); - if (ctx) - rib_process_after(ctx); - else + /* Dequeue context block */ + ctx = dplane_ctx_dequeue(&ctxlist); + + /* If we've emptied the results queue, we're done */ + if (ctx == NULL) break; + while (ctx) { + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + rib_process_result(ctx); + break; + + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + zebra_mpls_lsp_dplane_result(ctx); + break; + + default: + /* Don't expect this: just return the struct? */ + dplane_ctx_fini(&ctx); + break; + } /* Dispatch by op code */ + + ctx = dplane_ctx_dequeue(&ctxlist); + } + } while (1); /* Check for nexthop tracking processing after finishing with results */ @@ -3289,17 +3282,17 @@ static int rib_process_dplane_results(struct thread *thread) * the dataplane pthread. We enqueue the results here for processing by * the main thread later. */ -static int rib_dplane_results(const struct zebra_dplane_ctx *ctx) +static int rib_dplane_results(struct dplane_ctx_q *ctxlist) { /* Take lock controlling queue of results */ pthread_mutex_lock(&dplane_mutex); { - /* Enqueue context block */ - dplane_ctx_enqueue_tail(&rib_dplane_q, ctx); + /* Enqueue context blocks */ + dplane_ctx_list_append(&rib_dplane_q, ctxlist); } pthread_mutex_unlock(&dplane_mutex); - /* Ensure event is signalled to zebra main thread */ + /* Ensure event is signalled to zebra main pthread */ thread_add_event(zebrad.master, rib_process_dplane_results, NULL, 0, &t_dplane); @@ -3314,8 +3307,7 @@ void rib_init(void) /* Init dataplane, and register for results */ pthread_mutex_init(&dplane_mutex, NULL); TAILQ_INIT(&rib_dplane_q); - zebra_dplane_init(); - dplane_results_register(rib_dplane_results); + zebra_dplane_init(rib_dplane_results); } /* |
