summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2015-05-22 11:15:53 +0300
committerTimo Teräs <timo.teras@iki.fi>2015-06-04 11:30:34 +0300
commit9c8af69f84623aad95b5e9be1402a9f92e0b26e9 (patch)
tree72f52100526648d4a46c9d7ce0635ae0d95e6730
parentf15d207f22922ca8b194152315459565f15ad161 (diff)
downloadquagga-tteras.tar.bz2
quagga-tteras.tar.xz
zebra: support FIB override routestteras
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>
-rw-r--r--lib/zebra.h1
-rw-r--r--zebra/rib.h1
-rw-r--r--zebra/zebra_fpm.c2
-rw-r--r--zebra/zebra_rib.c82
-rw-r--r--zebra/zebra_rnh.c2
-rw-r--r--zebra/zebra_vty.c4
6 files changed, 67 insertions, 25 deletions
diff --git a/lib/zebra.h b/lib/zebra.h
index ae4b1825..2a852e0a 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -464,6 +464,7 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_BLACKHOLE 0x04
#define ZEBRA_FLAG_IBGP 0x08
#define ZEBRA_FLAG_SELECTED 0x10
+#define ZEBRA_FLAG_FIB_OVERRIDE 0x20
#define ZEBRA_FLAG_STATIC 0x40
#define ZEBRA_FLAG_REJECT 0x80
diff --git a/zebra/rib.h b/zebra/rib.h
index 229747df..05572ea7 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -67,6 +67,7 @@ struct rib
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 896915c2..ae43bfd3 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -889,7 +889,7 @@ zfpm_route_for_update (rib_dest_t *dest)
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 ec5328e3..89b2887a 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -468,7 +468,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
{
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;
}
@@ -610,7 +610,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
{
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;
}
@@ -723,7 +723,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
{
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;
}
@@ -859,7 +859,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
{
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;
}
@@ -918,7 +918,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
{
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;
}
@@ -985,7 +985,7 @@ rib_match_ipv6 (struct in6_addr *addr)
{
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;
}
@@ -1222,7 +1222,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
{
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");
@@ -1342,6 +1342,8 @@ rib_process (struct route_node *rn)
{
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;
@@ -1358,6 +1360,11 @@ rib_process (struct route_node *rn)
/* 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;
}
@@ -1374,17 +1381,31 @@ rib_process (struct route_node *rn)
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
@@ -1392,20 +1413,15 @@ rib_process (struct route_node *rn)
{
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);
}
@@ -1429,6 +1445,26 @@ rib_process (struct route_node *rn)
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)
{
@@ -2041,7 +2077,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p)
*/
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;
@@ -2192,7 +2228,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
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)
@@ -2240,7 +2276,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
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
{
@@ -2734,7 +2770,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
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)
@@ -2783,7 +2819,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
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
{
@@ -3241,7 +3277,7 @@ rib_close_table (struct route_table *table)
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_rnh.c b/zebra/zebra_rnh.c
index a4094360..9b2f664a 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -256,7 +256,7 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
{
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))
break;
}
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index cc0eb701..bd70877f 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -720,6 +720,10 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
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))