#include "vrf.h"
#include "workqueue.h"
+#include "zebra/zebra_router.h"
#include "zebra/connected.h"
#include "zebra/debug.h"
#include "zebra/interface.h"
*/
static pthread_mutex_t dplane_mutex;
static struct thread *t_dplane;
-static struct dplane_ctx_q_s rib_dplane_q;
+static struct dplane_ctx_q rib_dplane_q;
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason))
if (newhop->ifindex) {
resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
resolved_hop->ifindex = newhop->ifindex;
- if (newhop->flags & NEXTHOP_FLAG_ONLINK)
- resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
}
break;
case NEXTHOP_TYPE_IPV6:
break;
}
+ if (newhop->flags & NEXTHOP_FLAG_ONLINK)
+ resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+
/* Copy labels of the resolved route */
if (newhop->nh_label)
nexthop_add_labels(resolved_hop, newhop->nh_label_type,
return 1;
}
-void kernel_route_rib_pass_fail(struct route_node *rn, const struct prefix *p,
- struct route_entry *re,
- enum zebra_dplane_status res)
-{
- struct nexthop *nexthop;
- char buf[PREFIX_STRLEN];
- rib_dest_t *dest;
-
- dest = rib_dest_from_rnode(rn);
-
- switch (res) {
- case ZEBRA_DPLANE_INSTALL_SUCCESS:
- dest->selected_fib = re;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- else
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_INSTALLED);
- break;
- case ZEBRA_DPLANE_INSTALL_FAILURE:
- /*
- * I am not sure this is the right thing to do here
- * but the code always set selected_fib before
- * this assignment was moved here.
- */
- dest->selected_fib = re;
-
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_FAIL_INSTALL);
- flog_err(EC_ZEBRA_DP_INSTALL_FAIL,
- "%u:%s: Route install failed", re->vrf_id,
- prefix2str(p, buf, sizeof(buf)));
- break;
- case ZEBRA_DPLANE_DELETE_SUCCESS:
- /*
- * The case where selected_fib is not re is
- * when we have received a system route
- * that is overriding our installed route
- * as such we should leave the selected_fib
- * pointer alone
- */
- if (dest->selected_fib == re)
- dest->selected_fib = NULL;
- for (ALL_NEXTHOPS(re->ng, nexthop))
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
-
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_REMOVED);
- break;
- case ZEBRA_DPLANE_DELETE_FAILURE:
- /*
- * Should we set this to NULL if the
- * delete fails?
- */
- dest->selected_fib = NULL;
- flog_err(EC_ZEBRA_DP_DELETE_FAIL,
- "%u:%s: Route Deletion failure", re->vrf_id,
- prefix2str(p, buf, sizeof(buf)));
-
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_REMOVE_FAIL);
- break;
- case ZEBRA_DPLANE_STATUS_NONE:
- break;
- }
-}
-
/* Update flag indicates whether this is a "replace" or not. Currently, this
* is only used for IPv4.
*/
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
zlog_debug(
- "%u:%s: After processing: old_selected %p "
- "new_selected %p old_fib %p new_fib %p",
+ "%u:%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
vrf_id, buf, (void *)old_selected, (void *)new_selected,
(void *)old_fib, (void *)new_fib);
}
/* Update SELECTED entry */
if (old_selected != new_selected || selected_changed) {
- if (new_selected)
- SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
-
if (new_selected && new_selected != new_fib) {
nexthop_active_update(rn, new_selected, 1);
UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED);
}
+ if (new_selected) {
+ SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
+
+ /* Special case: new route is system route, so
+ * dataplane update will not be done - ensure we
+ * redistribute the route.
+ */
+ if (RIB_SYSTEM_ROUTE(new_selected))
+ redistribute_update(p, src_p, new_selected,
+ old_selected);
+ }
+
if (old_selected) {
if (!new_selected)
redistribute_delete(p, src_p, old_selected);
* Utility to match route with dplane context data
*/
static bool rib_route_match_ctx(const struct route_entry *re,
- const dplane_ctx_h ctx, bool is_update)
+ const struct zebra_dplane_ctx *ctx,
+ bool is_update)
{
bool result = false;
}
/*
- * TODO - WIP version of route-update processing after async dataplane
- * update.
+ * Route-update results processing after async dataplane update.
*/
-static void rib_process_after(dplane_ctx_h ctx)
+static void rib_process_after(struct zebra_dplane_ctx *ctx)
{
struct route_table *table = NULL;
struct zebra_vrf *zvrf = NULL;
struct route_node *rn = NULL;
struct route_entry *re = NULL, *old_re = NULL, *rib;
bool is_update = false;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *ctx_nexthop;
char dest_str[PREFIX_STRLEN] = "";
enum dplane_op_e op;
enum zebra_dplane_result status;
dplane_ctx_get_table(ctx));
if (table == NULL) {
if (IS_ZEBRA_DEBUG_DPLANE) {
- zlog_debug("Failed to process dplane results: no table "
- "for afi %d, safi %d, vrf %u",
+ zlog_debug("Failed to process dplane results: no table for afi %d, safi %d, vrf %u",
dplane_ctx_get_afi(ctx),
dplane_ctx_get_safi(ctx),
dplane_ctx_get_vrf(ctx));
src_pfx ? (struct prefix_ipv6 *)src_pfx : NULL);
if (rn == NULL) {
if (IS_ZEBRA_DEBUG_DPLANE) {
- zlog_debug("Failed to process dplane results: no "
- "route for %u:%s",
+ zlog_debug("Failed to process dplane results: no route for %u:%s",
dplane_ctx_get_vrf(ctx), dest_str);
}
goto done;
status = dplane_ctx_get_status(ctx);
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
- zlog_debug("%u:%s Processing dplane ctx %p, op %s result %d",
+ zlog_debug("%u:%s Processing dplane ctx %p, op %s result %s",
dplane_ctx_get_vrf(ctx), dest_str, ctx,
- dplane_op2str(op), status);
+ dplane_op2str(op), dplane_res2str(status));
}
if (op == DPLANE_OP_ROUTE_DELETE) {
}
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
- /* Set nexthop FIB flags */
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ /* 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;
+ }
+
+ if (nexthop == NULL)
+ continue;
+
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ 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 (zvrf)
+ if (zvrf) {
zvrf->installs++;
+ /* Set flag for nexthop tracking processing */
+ zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED;
+ }
/* Redistribute */
/* TODO -- still calling the redist api using the route_entries,
}
/*
- * All meta queues have been processed. Trigger next-hop evaluation.
+ * Perform next-hop tracking processing after RIB updates.
*/
-static void meta_queue_process_complete(struct work_queue *dummy)
+static void do_nht_processing(void)
{
struct vrf *vrf;
struct zebra_vrf *zvrf;
if (zvrf == NULL || !(zvrf->flags & ZEBRA_VRF_RIB_SCHEDULED))
continue;
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHT)
+ zlog_debug("NHT processing check for zvrf %s",
+ 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,
}
}
+/*
+ * All meta queues have been processed. Trigger next-hop evaluation.
+ */
+static void meta_queue_process_complete(struct work_queue *dummy)
+{
+ do_nht_processing();
+}
+
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and
* data
{
struct meta_queue *mq = data;
unsigned i;
+ uint32_t queue_len, queue_limit;
+
+ /* Ensure there's room for more dataplane updates */
+ queue_limit = dplane_get_in_queue_limit();
+ queue_len = dplane_get_in_queue_len();
+ if (queue_len > queue_limit) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("rib queue: dplane queue len %u, limit %u, retrying",
+ queue_len, queue_limit);
+
+ /* Ensure that the meta-queue is actually enqueued */
+ if (work_queue_empty(zebrad.ribq))
+ work_queue_add(zebrad.ribq, zebrad.mq);
+
+ return WQ_QUEUE_BLOCKED;
+ }
for (i = 0; i < MQ_SIZE; i++)
if (process_subq(mq->subq[i], i)) {
rib_sweep_table(zvrf->table[AFI_IP6][SAFI_UNICAST]);
}
- zebra_ns_sweep_route();
+ zebra_router_sweep_route();
}
/* Remove specific by protocol routes from 'table'. */
proto, instance,
zvrf->table[AFI_IP6][SAFI_UNICAST]);
- cnt += zebra_ns_score_proto(proto, instance);
+ cnt += zebra_router_score_proto(proto, instance);
return cnt;
}
if (info->safi == SAFI_UNICAST)
hook_call(rib_update, rn, NULL);
- if (!RIB_SYSTEM_ROUTE(dest->selected_fib))
+ if (!RIB_SYSTEM_ROUTE(dest->selected_fib)) {
rib_uninstall_kernel(rn, dest->selected_fib);
+ dest->selected_fib = NULL;
+ }
}
}
}
*/
static int rib_process_dplane_results(struct thread *thread)
{
- dplane_ctx_h ctx;
+ struct zebra_dplane_ctx *ctx;
do {
/* Take lock controlling queue of results */
} while (1);
+ /* Check for nexthop tracking processing after finishing with results */
+ do_nht_processing();
+
return 0;
}
/*
* Results are returned from the dataplane subsystem, in the context of
- * the dataplane thread. We enqueue the results here for processing by
+ * the dataplane pthread. We enqueue the results here for processing by
* the main thread later.
*/
-static int rib_dplane_results(dplane_ctx_h ctx)
+static int rib_dplane_results(const struct zebra_dplane_ctx *ctx)
{
/* Take lock controlling queue of results */
pthread_mutex_lock(&dplane_mutex);