diff options
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 324 |
1 files changed, 169 insertions, 155 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5d6eac7533..7e4ac1ddd2 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 */ }; @@ -1870,31 +1871,6 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) 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_REMOVE_FAIL); - - 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 * routes to post-process. @@ -1954,59 +1930,92 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) goto done; } - 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)) { + switch (op) { + case DPLANE_OP_NONE: + break; + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + 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)) { - for (ALL_NEXTHOPS(re->ng, nexthop)) { - if (nexthop_same(ctx_nexthop, nexthop)) - break; + for (ALL_NEXTHOPS(re->ng, nexthop)) { + if (nexthop_same(ctx_nexthop, nexthop)) + break; + } + + if (nexthop == NULL) + continue; + + 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. + */ + 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(re, dest_pfx, + ZAPI_ROUTE_INSTALLED); - if (zvrf) { - zvrf->installs++; - /* Set flag for nexthop tracking processing */ - zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED; - } + } else { + zsend_route_notify_owner(re, dest_pfx, + ZAPI_ROUTE_FAIL_INSTALL); - /* 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. + zlog_warn("%u:%s: Route install failed", + dplane_ctx_get_vrf(ctx), + prefix2str(dest_pfx, + dest_str, sizeof(dest_str))); + } + break; + case 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. */ - 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) { + 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 { + 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; } - done: /* Return context to dataplane module */ @@ -2143,73 +2152,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 */ @@ -3194,21 +3196,34 @@ void rib_close_table(struct route_table *table) 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 */ do { + TAILQ_INIT(&ctxlist); + /* Take lock controlling queue of results */ pthread_mutex_lock(&dplane_mutex); { /* Dequeue context block */ - ctx = dplane_ctx_dequeue(&rib_dplane_q); + 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) { + rib_process_after(ctx); + + ctx = dplane_ctx_dequeue(&ctxlist); + } + } while (1); /* Check for nexthop tracking processing after finishing with results */ @@ -3222,17 +3237,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(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); @@ -3247,8 +3262,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); } /* |
