diff options
Diffstat (limited to 'ripngd/ripngd.c')
-rw-r--r-- | ripngd/ripngd.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 2f6409a70..7269e7665 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -443,7 +443,10 @@ struct ripng_info *ripng_ecmp_add(struct ripng *ripng, { struct agg_node *rp = rinfo_new->rp; struct ripng_info *rinfo = NULL; + struct ripng_info *rinfo_exist = NULL; struct list *list = NULL; + struct listnode *node = NULL; + struct listnode *nnode = NULL; if (rp->info == NULL) rp->info = list_new(); @@ -454,6 +457,33 @@ struct ripng_info *ripng_ecmp_add(struct ripng *ripng, if (listcount(list) && !ripng->ecmp) return NULL; + /* Add or replace an existing ECMP path with lower neighbor IP */ + if (listcount(list) && listcount(list) >= ripng->ecmp) { + struct ripng_info *from_highest = NULL; + + /* Find the rip_info struct that has the highest nexthop IP */ + for (ALL_LIST_ELEMENTS(list, node, nnode, rinfo_exist)) + if (!from_highest || + (from_highest && + IPV6_ADDR_CMP(&rinfo_exist->from, + &from_highest->from) > 0)) { + from_highest = rinfo_exist; + } + + /* If we have a route in ECMP group, delete the old + * one that has a higher next-hop address. Lower IP is + * preferred. + */ + if (ripng->ecmp > 1 && from_highest && + IPV6_ADDR_CMP(&from_highest->from, &rinfo_new->from) > 0) { + ripng_ecmp_delete(ripng, from_highest); + goto add_or_replace; + } + + return NULL; + } + +add_or_replace: rinfo = ripng_info_new(); memcpy(rinfo, rinfo_new, sizeof(struct ripng_info)); listnode_add(list, rinfo); @@ -475,6 +505,36 @@ struct ripng_info *ripng_ecmp_add(struct ripng *ripng, return rinfo; } +/* Update ECMP routes to zebra when `allow-ecmp` changed. */ +void ripng_ecmp_change(struct ripng *ripng) +{ + struct agg_node *rp; + struct ripng_info *rinfo; + struct list *list; + struct listnode *node, *nextnode; + + for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) { + list = rp->info; + if (list && listcount(list) > 1) { + while (listcount(list) > ripng->ecmp) { + struct ripng_info *from_highest = NULL; + + for (ALL_LIST_ELEMENTS(list, node, nextnode, + rinfo)) { + if (!from_highest || + (from_highest && + IPV6_ADDR_CMP( + &rinfo->from, + &from_highest->from) > 0)) + from_highest = rinfo; + } + + ripng_ecmp_delete(ripng, from_highest); + } + } + } +} + /* Replace the ECMP list with the new route. * RETURN: the new entry added in the list */ @@ -1814,7 +1874,7 @@ struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket) "%s/timers/flush-interval", RIPNG_INSTANCE); ripng->default_metric = yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE); - ripng->ecmp = yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE); + ripng->ecmp = yang_get_default_uint8("%s/allow-ecmp", RIPNG_INSTANCE); /* Make buffer. */ ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5); |