Skip to content

Commit f02d76f

Browse files
committed
zebra: Attempt to reuse NHG after interface up and route reinstall
The previous commit modified zebra to reinstall the singleton nexthops for a nexthop group when a interface event comes up. Now let's modify zebra to attempt to reuse the nexthop group when this happens and the upper level protocol resends the route down with that. Only match if the protocol is the same as well as the instance and the nexthop groups would match. Here is the new behavior: eva(config)# do show ip route 9.9.9.9/32 Routing entry for 9.9.9.9/32 Known via "static", distance 1, metric 0, best Last update 00:00:08 ago * 192.168.99.33, via dummy1, weight 1 * 192.168.100.33, via dummy2, weight 1 * 192.168.101.33, via dummy3, weight 1 * 192.168.102.33, via dummy4, weight 1 eva(config)# do show ip route nexthop-group 9.9.9.9/32 % Unknown command: do show ip route nexthop-group 9.9.9.9/32 eva(config)# do show ip route 9.9.9.9/32 nexthop-group Routing entry for 9.9.9.9/32 Known via "static", distance 1, metric 0, best Last update 00:00:54 ago Nexthop Group ID: 57 * 192.168.99.33, via dummy1, weight 1 * 192.168.100.33, via dummy2, weight 1 * 192.168.101.33, via dummy3, weight 1 * 192.168.102.33, via dummy4, weight 1 eva(config)# exit eva# conf eva(config)# int dummy3 eva(config-if)# shut eva(config-if)# no shut eva(config-if)# do show ip route 9.9.9.9/32 nexthop-group Routing entry for 9.9.9.9/32 Known via "static", distance 1, metric 0, best Last update 00:00:08 ago Nexthop Group ID: 57 * 192.168.99.33, via dummy1, weight 1 * 192.168.100.33, via dummy2, weight 1 * 192.168.101.33, via dummy3, weight 1 * 192.168.102.33, via dummy4, weight 1 eva(config-if)# exit eva(config)# exit eva# exit sharpd@eva ~/frr1 (master) [255]> ip nexthop show id 57 id 57 group 37/43/50/58 proto zebra sharpd@eva ~/frr1 (master)> ip route show 9.9.9.9/32 9.9.9.9 nhid 57 proto 196 metric 20 nexthop via 192.168.99.33 dev dummy1 weight 1 nexthop via 192.168.100.33 dev dummy2 weight 1 nexthop via 192.168.101.33 dev dummy3 weight 1 nexthop via 192.168.102.33 dev dummy4 weight 1 sharpd@eva ~/frr1 (master)> Notice that we now no longer are creating a bunch of new nexthop groups. Signed-off-by: Donald Sharp <[email protected]>
1 parent 3be8b48 commit f02d76f

File tree

3 files changed

+159
-4
lines changed

3 files changed

+159
-4
lines changed

zebra/zebra_nhg.c

Lines changed: 156 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,7 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
11031103
/*
11041104
* If I have other nhe's depending on me, or I have nothing
11051105
* I am depending on then this is a
1106-
* singleton nhe so set this nexthops flag as appropriate.
1106+
* singleton nhe so set this nexthops flag as appropriate.
11071107
*/
11081108
if (nhg_connected_tree_count(&nhe->nhg_depends) ||
11091109
nhg_connected_tree_count(&nhe->nhg_dependents) == 0) {
@@ -2924,14 +2924,163 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg)
29242924
return curr_active;
29252925
}
29262926

2927+
/*
2928+
* This function takes the start of two comparable nexthops from two different
2929+
* nexthop groups and walks them to see if they can be considered the same
2930+
* or not. This is being used to determine if zebra should reuse a nhg
2931+
* from the old_re to the new_re, when an interface goes down and the
2932+
* new nhg sent down from the upper level protocol would resolve to it
2933+
*/
2934+
static bool zebra_nhg_nexthop_compare(const struct nexthop *nhop,
2935+
const struct nexthop *old_nhop,
2936+
const struct route_node *rn)
2937+
{
2938+
bool same = true;
2939+
2940+
while (nhop && old_nhop) {
2941+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2942+
zlog_debug("%s: %pRN Comparing %pNHvv(%u) to old: %pNHvv(%u)",
2943+
__func__, rn, nhop, nhop->flags, old_nhop,
2944+
old_nhop->flags);
2945+
if (!CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE)) {
2946+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2947+
zlog_debug("%s: %pRN Old is not active going to the next one",
2948+
__func__, rn);
2949+
old_nhop = old_nhop->next;
2950+
continue;
2951+
}
2952+
2953+
if (nexthop_same(nhop, old_nhop)) {
2954+
struct nexthop *new_recursive, *old_recursive;
2955+
2956+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2957+
zlog_debug("%s: %pRN New and old are same, continuing search",
2958+
__func__, rn);
2959+
2960+
new_recursive = nhop->resolved;
2961+
old_recursive = old_nhop->resolved;
2962+
2963+
while (new_recursive && old_recursive) {
2964+
if (!nexthop_same(new_recursive, old_recursive)) {
2965+
same = false;
2966+
break;
2967+
}
2968+
2969+
new_recursive = new_recursive->next;
2970+
old_recursive = old_recursive->next;
2971+
}
2972+
2973+
if (new_recursive)
2974+
same = false;
2975+
else if (old_recursive) {
2976+
while (old_recursive) {
2977+
if (CHECK_FLAG(old_recursive->flags,
2978+
NEXTHOP_FLAG_ACTIVE))
2979+
break;
2980+
old_recursive = old_recursive->next;
2981+
}
2982+
2983+
if (old_recursive)
2984+
same = false;
2985+
}
2986+
2987+
if (!same)
2988+
break;
2989+
2990+
nhop = nhop->next;
2991+
old_nhop = old_nhop->next;
2992+
continue;
2993+
} else {
2994+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2995+
zlog_debug("%s:%pRN They are not the same, stopping using new nexthop entry",
2996+
__func__, rn);
2997+
same = false;
2998+
break;
2999+
}
3000+
}
3001+
3002+
if (nhop)
3003+
same = false;
3004+
else if (old_nhop) {
3005+
while (old_nhop) {
3006+
if (CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE))
3007+
break;
3008+
old_nhop = old_nhop->next;
3009+
}
3010+
3011+
if (old_nhop)
3012+
same = false;
3013+
}
3014+
3015+
return same;
3016+
}
3017+
3018+
static struct nhg_hash_entry *zebra_nhg_rib_compare_old_nhe(
3019+
const struct route_node *rn, const struct route_entry *re,
3020+
struct nhg_hash_entry *new_nhe, struct nhg_hash_entry *old_nhe)
3021+
{
3022+
struct nexthop *nhop, *old_nhop;
3023+
bool same = true;
3024+
struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
3025+
3026+
if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
3027+
char straddr[PREFIX_STRLEN];
3028+
3029+
prefix2str(&rn->p, straddr, sizeof(straddr));
3030+
zlog_debug("%s: %pRN new id: %u old id: %u", __func__, rn,
3031+
new_nhe->id, old_nhe->id);
3032+
zlog_debug("%s: %pRN NEW", __func__, rn);
3033+
for (ALL_NEXTHOPS(new_nhe->nhg, nhop))
3034+
route_entry_dump_nh(re, straddr, vrf, nhop);
3035+
3036+
zlog_debug("%s: %pRN OLD", __func__, rn);
3037+
for (ALL_NEXTHOPS(old_nhe->nhg, nhop))
3038+
route_entry_dump_nh(re, straddr, vrf, nhop);
3039+
}
3040+
3041+
nhop = new_nhe->nhg.nexthop;
3042+
old_nhop = old_nhe->nhg.nexthop;
3043+
3044+
same = zebra_nhg_nexthop_compare(nhop, old_nhop, rn);
3045+
3046+
if (same) {
3047+
struct nexthop_group *bnhg, *old_bnhg;
3048+
3049+
bnhg = zebra_nhg_get_backup_nhg(new_nhe);
3050+
old_bnhg = zebra_nhg_get_backup_nhg(old_nhe);
3051+
3052+
if (bnhg || old_bnhg) {
3053+
if (bnhg && !old_bnhg)
3054+
same = false;
3055+
else if (!bnhg && old_bnhg)
3056+
same = false;
3057+
else
3058+
same = zebra_nhg_nexthop_compare(bnhg->nexthop,
3059+
old_bnhg->nexthop,
3060+
rn);
3061+
}
3062+
}
3063+
3064+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3065+
zlog_debug("%s:%pRN They are %sthe same, using the %s nhg entry",
3066+
__func__, rn, same ? "" : "not ",
3067+
same ? "old" : "new");
3068+
3069+
if (same)
3070+
return old_nhe;
3071+
else
3072+
return new_nhe;
3073+
}
3074+
29273075
/*
29283076
* Iterate over all nexthops of the given RIB entry and refresh their
29293077
* ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
29303078
* the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
29313079
*
29323080
* Return value is the new number of active nexthops.
29333081
*/
2934-
int nexthop_active_update(struct route_node *rn, struct route_entry *re)
3082+
int nexthop_active_update(struct route_node *rn, struct route_entry *re,
3083+
struct route_entry *old_re)
29353084
{
29363085
struct nhg_hash_entry *curr_nhe;
29373086
uint32_t curr_active = 0, backup_active = 0;
@@ -2987,6 +3136,11 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
29873136

29883137
new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
29893138

3139+
if (old_re && old_re->type == re->type &&
3140+
old_re->instance == re->instance)
3141+
new_nhe = zebra_nhg_rib_compare_old_nhe(rn, re, new_nhe,
3142+
old_re->nhe);
3143+
29903144
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
29913145
zlog_debug(
29923146
"%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)",

zebra/zebra_nhg.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ extern void zebra_nhg_mark_keep(void);
404404

405405
/* Nexthop resolution processing */
406406
struct route_entry; /* Forward ref to avoid circular includes */
407-
extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
407+
extern int nexthop_active_update(struct route_node *rn, struct route_entry *re,
408+
struct route_entry *old_re);
408409

409410
#ifdef _FRR_ATTRIBUTE_PRINTFRR
410411
#pragma FRR printfrr_ext "%pNG" (const struct nhg_hash_entry *)

zebra/zebra_rib.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ static void rib_process(struct route_node *rn)
13131313
*/
13141314
if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
13151315
proto_re_changed = re;
1316-
if (!nexthop_active_update(rn, re)) {
1316+
if (!nexthop_active_update(rn, re, old_fib)) {
13171317
const struct prefix *p;
13181318
struct rib_table_info *info;
13191319

0 commit comments

Comments
 (0)