summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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))