summaryrefslogtreecommitdiff
path: root/zebra/zebra_rib.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r--zebra/zebra_rib.c626
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);
}
/*