Zebra: Schedule RIB processing based on trigger event

Currently, when RIB processing is initiated (i.e., by calling rib_update()),
all routes are queued for processing. This is not desirable in all situations
because, sometimes the protocol may have an alternate path. In addition,
with NHT tracking nexthops, there are situations when NHT should be kicked
off first and that can trigger subsequent RIB processing.

This patch addresses this by introducing the notion of a trigger event. This
is only for the situation when the entire RIB is walked. The current triggers
- based on when rib_update() is invoked - are "interface change" and "route-
map change". In the former case, only the relevant routes are walked and
scheduled, in the latter case, currently all routes are scheduled for
processing.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by:   Donald Sharp <sharpd@cumulusnetworks.com>

Ticket: CM-7662
Reviewed By: CCR-3905

Note: The initial defect in this area was CM-7420. This was addressed in
2.5.4 with an interim change that only walked static routes upon interface
down. The change was considered a bit risky to do for interface up etc. Also,
this did not address scenarios like CM-7662. The current fix addresses CM-7662.
This commit is contained in:
vivek 2015-12-08 16:55:43 -08:00
parent 2bf26d4184
commit 1c8481370f
5 changed files with 106 additions and 67 deletions

View File

@ -215,9 +215,9 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
rib_update (ifp->vrf_id);
zlog_debug ("%u: IF %s IPv4 address add/up, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
/* Add connected IPv4 route to the interface. */
@ -334,9 +334,10 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
SAFI_MULTICAST);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update_static", __func__);
zlog_debug ("%u: IF %s IPv4 address down, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update_static (ifp->vrf_id);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
/* Delete connected IPv4 route to the interface. */
@ -359,9 +360,10 @@ connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
connected_withdraw (ifc);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update_static", __func__);
zlog_debug ("%u: IF %s IPv4 address del, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update_static(ifp->vrf_id);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
#ifdef HAVE_IPV6
@ -388,9 +390,10 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
zlog_debug ("%u: IF %s IPv6 address down, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update (ifp->vrf_id);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
/* Add connected IPv6 route to the interface. */
@ -477,9 +480,10 @@ connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
ifp->vrf_id, 0, SAFI_UNICAST);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update_static", __func__);
zlog_debug ("%u: IF %s IPv6 address down, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update_static (ifp->vrf_id);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
void
@ -501,9 +505,10 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
connected_withdraw (ifc);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update_static", __func__);
zlog_debug ("%u: IF %s IPv6 address del, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update_static(ifp->vrf_id);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
#endif /* HAVE_IPV6 */

View File

@ -639,11 +639,9 @@ if_up (struct interface *ifp)
}
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update on interface %s up", __func__,
ifp->name);
/* Examine all static routes. */
rib_update (ifp->vrf_id);
zlog_debug ("%u: IF %s up, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
/* Interface goes down. We have to manage different behavior of based
@ -675,12 +673,10 @@ if_down (struct interface *ifp)
}
}
/* Examine all static routes which direct to the interface. */
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update_static on interface %s down", __func__,
ifp->name);
rib_update_static (ifp->vrf_id);
zlog_debug ("%u: IF %s down, scheduling RIB processing",
ifp->vrf_id, ifp->name);
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp);

View File

@ -371,6 +371,14 @@ typedef struct rib_tables_iter_t_
rib_tables_iter_state_t state;
} rib_tables_iter_t;
/* Events/reasons triggering a RIB update. */
typedef enum
{
RIB_UPDATE_IF_CHANGE,
RIB_UPDATE_RMAP_CHANGE,
RIB_UPDATE_OTHER
} rib_update_event_t;
extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, unsigned int);
extern struct nexthop *rib_nexthop_ifname_add (struct rib *, char *);
extern struct nexthop *rib_nexthop_blackhole_add (struct rib *);
@ -433,8 +441,7 @@ extern struct rib *rib_match_ipv4 (struct in_addr, vrf_id_t);
extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *, vrf_id_t);
extern void rib_update (vrf_id_t);
extern void rib_update_static (vrf_id_t);
extern void rib_update (vrf_id_t, rib_update_event_t);
extern void rib_weed_tables (void);
extern void rib_sweep_route (void);
extern void rib_close_table (struct route_table *);

View File

@ -3545,56 +3545,83 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
return 1;
}
/* RIB update function. */
void
rib_update_static (vrf_id_t vrf_id)
/* Schedule routes of a particular table (address-family) based on event. */
static void
rib_update_table (struct route_table *table, rib_update_event_t event)
{
struct route_node *rn;
struct route_table *table;
struct rib *rib, *next;
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
RNODE_FOREACH_RIB_SAFE (rn, rib, next)
if (rib->type == ZEBRA_ROUTE_STATIC)
{
rib_queue_add (&zebrad, rn);
break;
}
/* Walk all routes and queue for processing, if appropriate for
* the trigger event.
*/
for (rn = route_top (table); rn; rn = route_next (rn))
{
switch (event)
{
case RIB_UPDATE_IF_CHANGE:
/* Examine all routes that won't get processed by the protocol or
* triggered by nexthop evaluation (NHT). This would be system,
* kernel and certain static routes. Note that NHT will get
* triggered upon an interface event as connected routes always
* get queued for processing.
*/
RNODE_FOREACH_RIB_SAFE (rn, rib, next)
{
if (rib->type == ZEBRA_ROUTE_OSPF ||
rib->type == ZEBRA_ROUTE_OSPF6 ||
rib->type == ZEBRA_ROUTE_BGP)
continue; /* protocol will handle. */
else if (rib->type == ZEBRA_ROUTE_STATIC)
{
struct nexthop *nh;
for (nh = rib->nexthop; nh; nh = nh->next)
if (!(nh->type == NEXTHOP_TYPE_IPV4 ||
nh->type == NEXTHOP_TYPE_IPV6))
break;
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
RNODE_FOREACH_RIB_SAFE (rn, rib, next)
if (rib->type == ZEBRA_ROUTE_STATIC)
{
/* If we only have nexthops to a gateway, NHT will
* take care.
*/
if (nh)
rib_queue_add (&zebrad, rn);
}
else
rib_queue_add (&zebrad, rn);
}
break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
/* Right now, examine all routes. Can restrict to a protocol in
* some cases (TODO).
*/
if (rnode_to_ribs (rn))
rib_queue_add (&zebrad, rn);
break;
}
break;
default:
break;
}
}
}
/* RIB update function. */
void
rib_update (vrf_id_t vrf_id)
rib_update (vrf_id_t vrf_id, rib_update_event_t event)
{
struct route_node *rn;
struct route_table *table;
/* Process routes of interested address-families. */
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
if (rnode_to_ribs (rn))
rib_queue_add (&zebrad, rn);
rib_update_table (table, event);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
if (rnode_to_ribs (rn))
rib_queue_add (&zebrad, rn);
rib_update_table (table, event);
}
/* Remove all routes which comes from non main table. */
static void
rib_weed_table (struct route_table *table)

View File

@ -784,9 +784,10 @@ DEFUN (ip_protocol,
proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
zlog_debug ("%u: IPv4 Routemap config for protocol %s, scheduling RIB processing",
VRF_DEFAULT, argv[0]);
rib_update(VRF_DEFAULT);
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
return CMD_SUCCESS;
}
@ -821,9 +822,9 @@ DEFUN (no_ip_protocol,
proto_rm[AFI_IP][i] = NULL;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
rib_update(VRF_DEFAULT);
zlog_debug ("%u: IPv4 Routemap unconfig for protocol %s, scheduling RIB processing",
VRF_DEFAULT, argv[0]);
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
}
return CMD_SUCCESS;
}
@ -896,9 +897,10 @@ DEFUN (ipv6_protocol,
proto_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
zlog_debug ("%u: IPv6 Routemap config for protocol %s, scheduling RIB processing",
VRF_DEFAULT, argv[0]);
rib_update(VRF_DEFAULT);
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
return CMD_SUCCESS;
}
@ -933,9 +935,10 @@ DEFUN (no_ipv6_protocol,
proto_rm[AFI_IP6][i] = NULL;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
zlog_debug ("%u: IPv6 Routemap unconfig for protocol %s, scheduling RIB processing",
VRF_DEFAULT, argv[0]);
rib_update(VRF_DEFAULT);
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
}
return CMD_SUCCESS;
}
@ -1611,9 +1614,10 @@ zebra_route_map_update_timer (struct thread *thread)
zlog_debug("Event driven route-map update triggered");
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%s: calling rib_update", __func__);
zlog_debug ("%u: Routemap update-timer fired, scheduling RIB processing",
VRF_DEFAULT);
rib_update(VRF_DEFAULT);
rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);