zebra: support FIB override routes
FIB override routes are for routing protocols that establish
shortcut routes, or establish point-to-point routes that should
not be redistributed. Namely this is useful NHRP daemon to come.
Zebra is extended to select two entries from RIB the "best" entry
from routing protocols, and the FIB entry to install to kernel.
FIB override routes are never selected as best entry, and thus
are never adverticed to other routing daemons. The best FIB
override, or if it does not exist the otherwise best RIB is
selected as FIB entry to be installed.
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
diff --git a/zebra/rib.h b/zebra/rib.h
index ffe7e2f..67ffe8d 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -83,6 +83,7 @@
u_char status;
#define RIB_ENTRY_REMOVED (1 << 0)
#define RIB_ENTRY_CHANGED (1 << 1)
+#define RIB_ENTRY_SELECTED_FIB (1 << 2)
/* Nexthop information. */
u_char nexthop_num;
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 292dbb6..cb04f21 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -889,7 +889,7 @@
RIB_DEST_FOREACH_ROUTE (dest, rib)
{
- if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
continue;
return rib;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 9264087..d06382c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -387,7 +387,7 @@
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
break;
}
@@ -521,7 +521,7 @@
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
break;
}
@@ -633,7 +633,7 @@
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
break;
}
@@ -778,7 +778,7 @@
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
break;
}
@@ -838,7 +838,7 @@
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
break;
}
@@ -904,7 +904,7 @@
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
break;
}
@@ -1139,7 +1139,7 @@
{
rib_table_info_t *info = rn->table->info;
- if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
{
if (info->safi == SAFI_UNICAST)
zfpm_trigger_update (rn, "rib_uninstall");
@@ -1259,6 +1259,8 @@
{
struct rib *rib;
struct rib *next;
+ struct rib *old_selected = NULL;
+ struct rib *new_selected = NULL;
struct rib *old_fib = NULL;
struct rib *new_fib = NULL;
int installed = 0;
@@ -1275,6 +1277,11 @@
/* Currently installed rib. */
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
{
+ assert (old_selected == NULL);
+ old_selected = rib;
+ }
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
+ {
assert (old_fib == NULL);
old_fib = rib;
}
@@ -1291,17 +1298,31 @@
if (rib->distance == DISTANCE_INFINITY)
continue;
- new_fib = rib_choose_best(new_fib, rib);
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE))
+ new_fib = rib_choose_best(new_fib, rib);
+ else
+ new_selected = rib_choose_best(new_selected, rib);
} /* RNODE_FOREACH_RIB_SAFE */
+ /* If no FIB override route, use the selected route also for FIB */
+ if (new_fib == NULL)
+ new_fib = new_selected;
+
/* After the cycle is finished, the following pointers will be set:
- * old_fib --- RIB entry currently having SELECTED
- * new_fib --- RIB entry that is newly SELECTED
+ * old_selected --- RIB entry currently having SELECTED
+ * new_selected --- RIB entry that is newly SELECTED
+ * old_fib --- RIB entry currently in kernel FIB
+ * new_fib --- RIB entry that is newly to be in kernel FIB
+ *
+ * new_selected will get SELECTED flag, and is going to be redistributed
+ * the zclients. new_fib (which can be new_selected) will be installed in kernel.
*/
/* Set real nexthops. */
if (new_fib)
nexthop_active_update (rn, new_fib, 1);
+ if (new_selected && new_selected != new_fib)
+ nexthop_active_update (rn, new_selected, 1);
/* Update kernel if FIB entry has changed */
if (old_fib != new_fib
@@ -1309,20 +1330,15 @@
{
if (old_fib && old_fib != new_fib)
{
- if (! new_fib)
- redistribute_delete (&rn->p, old_fib);
-
if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib)))
rib_update_kernel (rn, old_fib, NULL);
- UNSET_FLAG (old_fib->flags, ZEBRA_FLAG_SELECTED);
+ UNSET_FLAG (old_fib->status, RIB_ENTRY_SELECTED_FIB);
}
if (new_fib)
{
/* Install new or replace existing FIB entry */
- SET_FLAG (new_fib->flags, ZEBRA_FLAG_SELECTED);
- redistribute_add (&rn->p, new_fib);
-
+ SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB);
if (! RIB_SYSTEM_ROUTE (new_fib))
rib_update_kernel (rn, old_fib, new_fib);
}
@@ -1346,6 +1362,26 @@
rib_update_kernel (rn, NULL, new_fib);
}
+ /* Redistribute SELECTED entry */
+ if (old_selected != new_selected
+ || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED)))
+ {
+ if (old_selected)
+ {
+ if (! new_selected)
+ redistribute_delete (&rn->p, old_selected);
+ if (old_selected != new_selected)
+ UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED);
+ }
+
+ if (new_selected)
+ {
+ /* Install new or replace existing redistributed entry */
+ SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED);
+ redistribute_add (&rn->p, new_selected);
+ }
+ }
+
/* Remove all RIB entries queued for removal */
RNODE_FOREACH_RIB_SAFE (rn, rib, next)
{
@@ -1947,7 +1983,7 @@
*/
RNODE_FOREACH_RIB (rn, rib)
{
- if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) &&
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) &&
! RIB_SYSTEM_ROUTE (rib))
{
changed = 1;
@@ -2098,7 +2134,7 @@
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
fib = rib;
if (rib->type != type)
@@ -2146,7 +2182,7 @@
for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
- UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+ UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
}
else
{
@@ -2675,7 +2711,7 @@
if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED))
continue;
- if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
fib = rib;
if (rib->type != type)
@@ -2724,7 +2760,7 @@
for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
- UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+ UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
}
else
{
@@ -3058,7 +3094,7 @@
for (rn = route_top (table); rn; rn = route_next (rn))
RNODE_FOREACH_RIB (rn, rib)
{
- if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
continue;
if (info->safi == SAFI_UNICAST)
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 656f55d..21b92ea 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1295,6 +1295,10 @@
vty_out (vty, ", vrf %u", rib->vrf_id);
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
vty_out (vty, ", best");
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE))
+ vty_out (vty, ", fib-override");
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
+ vty_out (vty, ", fib");
if (rib->refcnt)
vty_out (vty, ", refcnt %ld", rib->refcnt);
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 7a75ed4..600b0e5 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -397,8 +397,7 @@
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
- || nexthop_has_fib_child(nexthop))
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
{
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
@@ -504,7 +503,7 @@
* are looking up. Therefore, we will just iterate over the top
* chain of nexthops. */
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
{
stream_putc (s, nexthop->type);
switch (nexthop->type)
@@ -574,7 +573,7 @@
* are looking up. Therefore, we will just iterate over the top
* chain of nexthops. */
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
{
stream_putc (s, nexthop->type);
switch (nexthop->type)
@@ -644,7 +643,7 @@
* are looking up. Therefore, we will just iterate over the top
* chain of nexthops. */
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
{
stream_putc (s, nexthop->type);
switch (nexthop->type)
@@ -709,8 +708,7 @@
nump = stream_get_endp(s);
stream_putc (s, 0);
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
- || nexthop_has_fib_child(nexthop))
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
{
stream_putc (s, nexthop->type);
switch (nexthop->type)