diff options
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 487 |
1 files changed, 286 insertions, 201 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c2fa33f57d..e0bf1a58f2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -56,7 +56,6 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_dplane.h" -#include "zebra/zebra_nhg.h" DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object"); @@ -79,34 +78,35 @@ static const struct { uint8_t distance; uint8_t meta_q_map; } route_info[ZEBRA_ROUTE_MAX] = { - [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}, - [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 4}, - [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 4}, - [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 2}, - [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 4} + [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Uneeded for nhg's */, 0}, + [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 5}, + [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 1}, + [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 1}, + [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 2}, + [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 3}, + [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 3}, + [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 3}, + [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 3}, + [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 3}, + [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 4}, + [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 5}, + [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 3}, + [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 3}, + [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 5}, + [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 5}, + [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 2}, + [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 5}, + [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 4}, + [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 4}, + [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 4}, + [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 4}, + [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 4}, + [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 3}, + [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 5}, + [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 5}, + [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 5}, + [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 3}, + [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 5} /* Any new route type added to zebra, should be mirrored here */ /* no entry/default: 150 */ @@ -196,8 +196,7 @@ int zebra_check_addr(const struct prefix *p) /* Add nexthop to the end of a rib node's nexthop list */ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) { - _nexthop_group_add_sorted(&re->ng, nexthop); - re->nexthop_num++; + _nexthop_group_add_sorted(re->ng, nexthop); } @@ -206,10 +205,8 @@ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) */ void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh) { - assert(!re->ng.nexthop); - copy_nexthops(&re->ng.nexthop, nh, NULL); - for (struct nexthop *nexthop = nh; nexthop; nexthop = nexthop->next) - re->nexthop_num++; + assert(!re->ng->nexthop); + copy_nexthops(&re->ng->nexthop, nh, NULL); } /* Delete specified nexthop from the list. */ @@ -220,8 +217,7 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop) if (nexthop->prev) nexthop->prev->next = nexthop->next; else - re->ng.nexthop = nexthop->next; - re->nexthop_num--; + re->ng->nexthop = nexthop->next; } @@ -505,7 +501,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re) if (re->type != ZEBRA_ROUTE_BGP) return 0; - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) if (!nexthop->nh_label || !nexthop->nh_label->num_labels) return 0; @@ -529,26 +525,17 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; - } else { - struct nexthop *prev; - - for (ALL_NEXTHOPS(re->ng, nexthop)) { - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE); - for (ALL_NEXTHOPS(re->ng, prev)) { - if (prev == nexthop) - break; - if (nexthop_same_firsthop(nexthop, prev)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_DUPLICATE); - break; - } - } - } } + + /* + * Install the resolved nexthop object first. + */ + zebra_nhg_install_kernel(zebra_nhg_lookup_id(re->nhe_id)); + /* * If this is a replace to a new RE let the originator of the RE * know that they've lost @@ -586,7 +573,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, if (!RIB_SYSTEM_ROUTE(old)) { /* Clear old route's FIB flags */ - for (ALL_NEXTHOPS(old->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(old->ng, nexthop)) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -624,7 +611,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) if (info->safi != SAFI_UNICAST) { UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -684,7 +671,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) re->fib_ng.nexthop = NULL; } - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -860,7 +847,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_group_active_nexthop_num(&new->ng)) { + if (!nexthop_group_active_nexthop_num(new->ng)) { UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); return; } @@ -929,7 +916,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update the nexthop; we could determine here that nexthop is * inactive. */ - if (nexthop_group_active_nexthop_num(&new->ng)) + if (nexthop_group_active_nexthop_num(new->ng)) nh_active = 1; /* If nexthop is active, install the selected route, if @@ -1047,7 +1034,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, /* both are connected. are either loop or vrf? */ struct nexthop *nexthop = NULL; - for (ALL_NEXTHOPS(alternate->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(alternate->ng, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, alternate->vrf_id); @@ -1055,7 +1042,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return alternate; } - for (ALL_NEXTHOPS(current->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(current->ng, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, current->vrf_id); @@ -1086,6 +1073,12 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return current; } +/* Core function for processing nexthop group contexts's off metaq */ +static void rib_nhg_process(struct nhg_ctx *ctx) +{ + nhg_ctx_process(ctx); +} + /* Core function for processing routing information base. */ static void rib_process(struct route_node *rn) { @@ -1380,7 +1373,7 @@ static void zebra_rib_fixup_system(struct route_node *rn) SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); - for (ALL_NEXTHOPS(re->ng, nhop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nhop)) { if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1428,76 +1421,20 @@ static bool rib_update_re_from_ctx(struct route_entry *re, * status. */ - /* - * First check the fib nexthop-group, if it's present. The comparison - * here is quite strict: we require that the fib sets match exactly. + /* Check both fib group and notif group for equivalence. + * + * Let's assume the nexthops are ordered here to save time. */ - matched = false; - do { - if (re->fib_ng.nexthop == NULL) - break; - - matched = true; - - /* First check the route's fib nexthops */ - for (ALL_NEXTHOPS(re->fib_ng, nexthop)) { - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - ctx_nexthop = NULL; - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), - ctx_nexthop)) { - if (nexthop_same(ctx_nexthop, nexthop)) - break; - } - - if (ctx_nexthop == NULL) { - /* Nexthop not in the new installed set */ - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - nexthop2str(nexthop, nh_str, - sizeof(nh_str)); - zlog_debug("update_from_ctx: no match for fib nh %s", - nh_str); - } - - matched = false; - break; - } - } - - if (!matched) - break; - - /* Check the new installed set */ - ctx_nexthop = NULL; - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) { - - if (CHECK_FLAG(ctx_nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) - continue; - - /* Compare with the current group's nexthops */ - nexthop = NULL; - for (ALL_NEXTHOPS(re->fib_ng, nexthop)) { - if (nexthop_same(nexthop, ctx_nexthop)) - break; - } - - if (nexthop == NULL) { - /* Nexthop not in the old installed set */ - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - nexthop2str(ctx_nexthop, nh_str, - sizeof(nh_str)); - zlog_debug("update_from_ctx: no fib match for notif nh %s", - nh_str); - } - matched = false; - break; - } + if (nexthop_group_equal(&re->fib_ng, dplane_ctx_get_ng(ctx)) == false) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + zlog_debug( + "%u:%s update_from_ctx: notif nh and fib nh mismatch", + re->vrf_id, dest_str); } - } while (0); + matched = false; + } else + matched = true; /* If the new FIB set matches the existing FIB set, we're done. */ if (matched) { @@ -1530,9 +1467,22 @@ static bool rib_update_re_from_ctx(struct route_entry *re, * walk the RIB group, looking for the 'installable' candidate * nexthops, and then check those against the set * that is actually installed. + * + * Assume nexthops are ordered here as well. */ matched = true; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + + ctx_nexthop = dplane_ctx_get_ng(ctx)->nexthop; + + /* Get the first `installed` one to check against. + * If the dataplane doesn't set these to be what was actually installed, + * it will just be whatever was in re->ng? + */ + if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE) + || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop); + + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1541,20 +1491,15 @@ static bool rib_update_re_from_ctx(struct route_entry *re, continue; /* Check for a FIB nexthop corresponding to the RIB nexthop */ - ctx_nexthop = NULL; - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) { - if (nexthop_same(ctx_nexthop, nexthop)) - break; - } - - /* If the FIB doesn't know about the nexthop, - * it's not installed - */ - if (ctx_nexthop == NULL) { + if (nexthop_same(ctx_nexthop, nexthop) == false) { + /* If the FIB doesn't know about the nexthop, + * it's not installed + */ if (IS_ZEBRA_DEBUG_RIB_DETAILED) { nexthop2str(nexthop, nh_str, sizeof(nh_str)); - zlog_debug("update_from_ctx: no notif match for rib nh %s", - nh_str); + zlog_debug( + "update_from_ctx: no notif match for rib nh %s", + nh_str); } matched = false; @@ -1578,6 +1523,8 @@ static bool rib_update_re_from_ctx(struct route_entry *re, UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } + + ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop); } /* If all nexthops were processed, we're done */ @@ -2062,19 +2009,28 @@ done: dplane_ctx_fini(&ctx); } -/* Take a list of route_node structs and return 1, if there was a record - * picked from it and processed by rib_process(). Don't process more, - * than one RN record; operate only in the specified sub-queue. - */ -static unsigned int process_subq(struct list *subq, uint8_t qindex) +static void process_subq_nhg(struct listnode *lnode) { - struct listnode *lnode = listhead(subq); - struct route_node *rnode; - rib_dest_t *dest; - struct zebra_vrf *zvrf = NULL; + struct nhg_ctx *ctx = NULL; + uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; - if (!lnode) - return 0; + ctx = listgetdata(lnode); + + if (!ctx) + return; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("NHG Context id=%u dequeued from sub-queue %u", + ctx->id, qindex); + + rib_nhg_process(ctx); +} + +static void process_subq_route(struct listnode *lnode, uint8_t qindex) +{ + struct route_node *rnode = NULL; + rib_dest_t *dest = NULL; + struct zebra_vrf *zvrf = NULL; rnode = listgetdata(lnode); dest = rib_dest_from_rnode(rnode); @@ -2104,7 +2060,26 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) } #endif route_unlock_node(rnode); +} + +/* Take a list of route_node structs and return 1, if there was a record + * picked from it and processed by rib_process(). Don't process more, + * than one RN record; operate only in the specified sub-queue. + */ +static unsigned int process_subq(struct list *subq, uint8_t qindex) +{ + struct listnode *lnode = listhead(subq); + + if (!lnode) + return 0; + + if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map) + process_subq_nhg(lnode); + else + process_subq_route(lnode, qindex); + list_delete_node(subq, lnode); + return 1; } @@ -2162,11 +2137,14 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) * 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) +static int rib_meta_queue_add(struct meta_queue *mq, void *data) { + struct route_node *rn = NULL; struct route_entry *re = NULL, *curr_re = NULL; uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE; + rn = (struct route_node *)data; + RNODE_FOREACH_RE (rn, curr_re) { curr_qindex = route_info[curr_re->type].meta_q_map; @@ -2177,7 +2155,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) } if (!re) - return; + return -1; /* Invariant: at this point we always have rn->info set. */ if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, @@ -2186,7 +2164,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) rnode_debug(rn, re->vrf_id, "rn %p is already queued in sub-queue %u", (void *)rn, qindex); - return; + return -1; } SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex)); @@ -2197,26 +2175,37 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_DETAILED) rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u", (void *)rn, qindex); + + return 0; } -/* Add route_node to work queue and schedule processing */ -void rib_queue_add(struct route_node *rn) +static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) { - assert(rn); + struct nhg_ctx *ctx = NULL; + uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; - /* Pointless to queue a route_node with no RIB entries to add or remove - */ - if (!rnode_to_ribs(rn)) { - zlog_debug("%s: called for route_node (%p, %d) with no ribs", - __func__, (void *)rn, rn->lock); - zlog_backtrace(LOG_DEBUG); - return; - } + ctx = (struct nhg_ctx *)data; + + if (!ctx) + return -1; + listnode_add(mq->subq[qindex], ctx); + mq->size++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("NHG Context id=%u queued into sub-queue %u", + ctx->id, qindex); + + return 0; +} + +static int mq_add_handler(void *data, + int (*mq_add_func)(struct meta_queue *mq, void *data)) +{ if (zrouter.ribq == NULL) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: work_queue does not exist!", __func__); - return; + return -1; } /* @@ -2230,9 +2219,31 @@ void rib_queue_add(struct route_node *rn) if (work_queue_empty(zrouter.ribq)) work_queue_add(zrouter.ribq, zrouter.mq); - rib_meta_queue_add(zrouter.mq, rn); + return mq_add_func(zrouter.mq, data); +} - return; +/* Add route_node to work queue and schedule processing */ +int rib_queue_add(struct route_node *rn) +{ + assert(rn); + + /* Pointless to queue a route_node with no RIB entries to add or remove + */ + if (!rnode_to_ribs(rn)) { + zlog_debug("%s: called for route_node (%p, %d) with no ribs", + __func__, (void *)rn, rn->lock); + zlog_backtrace(LOG_DEBUG); + return -1; + } + + return mq_add_handler(rn, &rib_meta_queue_add); +} + +int rib_queue_nhg_add(struct nhg_ctx *ctx) +{ + assert(ctx); + + return mq_add_handler(ctx, &rib_meta_queue_nhg_add); } /* Create new meta queue. @@ -2400,6 +2411,7 @@ static void rib_addnode(struct route_node *rn, void rib_unlink(struct route_node *rn, struct route_entry *re) { rib_dest_t *dest; + struct nhg_hash_entry *nhe = NULL; assert(rn && re); @@ -2414,7 +2426,13 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - nexthops_free(re->ng.nexthop); + if (re->nhe_id) { + nhe = zebra_nhg_lookup_id(re->nhe_id); + if (nhe) + zebra_nhg_decrement_ref(nhe); + } else if (re->ng) + nexthop_group_delete(&re->ng); + nexthops_free(re->fib_ng.nexthop); XFREE(MTYPE_RE, re); @@ -2480,9 +2498,10 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, "%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: nexthop_num == %u, nexthop_active_num == %u", straddr, - re->nexthop_num, re->nexthop_active_num); + nexthop_group_nexthop_num(re->ng), + nexthop_group_active_nexthop_num(re->ng)); - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -2633,6 +2652,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id) int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re) { + struct nhg_hash_entry *nhe = NULL; struct route_table *table; struct route_node *rn; struct route_entry *same = NULL; @@ -2646,10 +2666,58 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { + if (re->ng) + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return 0; } + if (re->nhe_id) { + nhe = zebra_nhg_lookup_id(re->nhe_id); + + if (!nhe) { + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find the nexthop hash entry for id=%u in a route entry", + re->nhe_id); + XFREE(MTYPE_RE, re); + return -1; + } + } else { + nhe = zebra_nhg_rib_find(0, re->ng, afi); + + /* + * The nexthops got copied over into an nhe, + * so free them now. + */ + nexthop_group_delete(&re->ng); + + if (!nhe) { + char buf[PREFIX_STRLEN] = ""; + char buf2[PREFIX_STRLEN] = ""; + + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find or create a nexthop hash entry for %s%s%s", + prefix2str(p, buf, sizeof(buf)), + src_p ? " from " : "", + src_p ? prefix2str(src_p, buf2, sizeof(buf2)) + : ""); + + XFREE(MTYPE_RE, re); + return -1; + } + } + + /* + * Attach the re to the nhe's nexthop group. + * + * TODO: This will need to change when we start getting IDs from upper + * level protocols, as the refcnt might be wrong, since it checks + * if old_id != new_id. + */ + zebra_nhg_re_update_ref(re, nhe); + /* Make it sure prefixlen is applied to the prefix. */ apply_mask(p); if (src_p) @@ -2726,8 +2794,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, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, - uint32_t table_id, uint32_t metric, uint8_t distance, - bool fromkernel) + uint32_t nhe_id, uint32_t table_id, uint32_t metric, + uint8_t distance, bool fromkernel) { struct route_table *table; struct route_node *rn; @@ -2790,31 +2858,37 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop) + if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng->nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; same = re; break; } + /* Make sure that the route found has the same gateway. */ - else { - if (nh == NULL) { + if (nhe_id && re->nhe_id == nhe_id) { + same = re; + break; + } + + if (nh == NULL) { + same = re; + break; + } + for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) { + /* + * No guarantee all kernel send nh with labels + * on delete. + */ + if (nexthop_same_no_labels(rtnh, nh)) { same = re; break; } - for (ALL_NEXTHOPS(re->ng, rtnh)) - /* - * No guarantee all kernel send nh with labels - * on delete. - */ - if (nexthop_same_no_labels(rtnh, nh)) { - same = re; - break; - } - if (same) - break; } + + if (same) + break; } /* If same type of route can't be found and this message is from kernel. */ @@ -2844,7 +2918,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (allow_delete) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ - for (rtnh = fib->ng.nexthop; rtnh; + for (rtnh = fib->ng->nexthop; rtnh; rtnh = rtnh->next) UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); @@ -2900,7 +2974,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; - for (ALL_NEXTHOPS(re->ng, tmp_nh)) { + for (ALL_NEXTHOPS_PTR(re->ng, tmp_nh)) { struct ipaddr vtep_ip; memset(&vtep_ip, 0, sizeof(struct ipaddr)); @@ -2935,11 +3009,11 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, - uint32_t table_id, uint32_t metric, uint32_t mtu, uint8_t distance, - route_tag_t tag) + uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint32_t mtu, + uint8_t distance, route_tag_t tag) { - struct route_entry *re; - struct nexthop *nexthop; + struct route_entry *re = NULL; + struct nexthop *nexthop = NULL; /* Allocate new route_entry structure. */ re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); @@ -2951,14 +3025,18 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->mtu = mtu; re->table = table_id; re->vrf_id = vrf_id; - re->nexthop_num = 0; re->uptime = monotime(NULL); re->tag = tag; + re->nhe_id = nhe_id; - /* Add nexthop. */ - nexthop = nexthop_new(); - *nexthop = *nh; - route_entry_nexthop_add(re, nexthop); + if (!nhe_id) { + re->ng = nexthop_group_new(); + + /* Add nexthop. */ + nexthop = nexthop_new(); + *nexthop = *nh; + route_entry_nexthop_add(re, nexthop); + } return rib_add_multipath(afi, safi, p, src_p, re); } @@ -3218,7 +3296,7 @@ void rib_sweep_table(struct route_table *table) * this decision needs to be revisited */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); rib_uninstall_kernel(rn, re); @@ -3242,6 +3320,7 @@ int rib_sweep_route(struct thread *t) } zebra_router_sweep_route(); + zebra_router_sweep_nhgs(); return 0; } @@ -3412,6 +3491,12 @@ static int rib_process_dplane_results(struct thread *thread) rib_process_dplane_notify(ctx); break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_NH_DELETE: + zebra_nhg_dplane_result(ctx); + break; + case DPLANE_OP_LSP_INSTALL: case DPLANE_OP_LSP_UPDATE: case DPLANE_OP_LSP_DELETE: |
