Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ospf6d: Fix External routes ECMP #1566

Merged
merged 1 commit into from
Jan 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion ospf6d/ospf6_abr.c
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)

ospf6_route_copy_nexthops(route, abr_entry);


/* (7) If the routes are identical, copy the next hops over to existing
route. ospf6's route table implementation will otherwise string both
routes, but keep the older one as the best route since the routes
Expand All @@ -910,6 +911,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)

if (old && (ospf6_route_cmp(route, old) == 0)) {
ospf6_route_merge_nexthops(old, route);

if (is_debug)
zlog_debug("%s: Update route: %s nh count %u",
__PRETTY_FUNCTION__,
buf, listcount(route->nh_list));

/* Update RIB/FIB */
if (table->hook_add)
(*table->hook_add)(old);
Expand All @@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
ospf6_route_delete(route);
} else {
if (is_debug)
zlog_debug("Install route: %s", buf);
zlog_debug("Install route: %s nh count %u",
buf, listcount(route->nh_list));
/* ospf6_ia_add_nw_route (table, &prefix, route); */
ospf6_route_add(route, table);
}
Expand Down
4 changes: 3 additions & 1 deletion ospf6d/ospf6_area.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)

static void ospf6_area_route_hook_add(struct ospf6_route *route)
{
struct ospf6_route *copy = ospf6_route_copy(route);
struct ospf6_route *copy;

copy = ospf6_route_copy(route);
ospf6_route_add(copy, ospf6->route_table);
}

Expand Down
275 changes: 266 additions & 9 deletions ospf6d/ospf6_asbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
return ntohl(network_order);
}

void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
struct ospf6_route *route)
{
struct ospf6_route *old_route;
struct ospf6_path *ecmp_path, *o_path = NULL;
struct listnode *anode;
struct listnode *nnode, *rnode, *rnext;
struct ospf6_nexthop *nh, *rnh;
char buf[PREFIX2STR_BUFFER];
bool route_found = false;

for (old_route = old; old_route; old_route = old_route->next) {
if (ospf6_route_is_same(old_route, route) &&
(old_route->path.type == route->path.type) &&
(old_route->path.cost == route->path.cost) &&
(old_route->path.u.cost_e2 == route->path.u.cost_e2)) {

if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&old_route->prefix, buf,
sizeof(buf));
zlog_debug("%s: old route %s path cost %u [%u]",
__PRETTY_FUNCTION__, buf,
old_route->path.cost,
ospf6_route_is_same(old_route,
route));
}
route_found = true;
/* check if this path exists already in
* route->paths list, if so, replace nh_list
* from asbr_entry.
*/
for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
o_path)) {
if ((o_path->origin.id == route->path.origin.id)
&& (o_path->origin.adv_router ==
route->path.origin.adv_router))
break;
}
/* If path is not found in old_route paths's list,
* add a new path to route paths list and merge
* nexthops in route->path->nh_list.
* Otherwise replace existing path's nh_list.
*/
if (o_path == NULL) {
ecmp_path = ospf6_path_dup(&route->path);

/* Add a nh_list to new ecmp path */
ospf6_copy_nexthops(ecmp_path->nh_list,
route->nh_list);
/* Merge nexthop to existing route's nh_list */
ospf6_route_merge_nexthops(old_route, route);

/* Update RIB/FIB */
if (ospf6->route_table->hook_add)
(*ospf6->route_table->hook_add)
(old_route);

/* Add the new path to route's path list */
listnode_add_sort(old_route->paths, ecmp_path);

if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&route->prefix, buf,
sizeof(buf));
zlog_debug("%s: route %s another path added with nh %u, Paths %u",
__PRETTY_FUNCTION__, buf,
listcount(ecmp_path->nh_list),
old_route->paths ?
listcount(old_route->paths)
: 0);
}
} else {
for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
nnode, nh)) {
for (ALL_LIST_ELEMENTS(
old_route->nh_list,
rnode, rnext, rnh)) {
if (!ospf6_nexthop_is_same(rnh,
nh))
continue;

listnode_delete(
old_route->nh_list,
rnh);
ospf6_nexthop_delete(rnh);
}
}
list_delete_all_node(o_path->nh_list);
ospf6_copy_nexthops(o_path->nh_list,
route->nh_list);

/* Merge nexthop to existing route's nh_list */
ospf6_route_merge_nexthops(old_route,
route);

if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&route->prefix,
buf, sizeof(buf));
zlog_debug("%s: existing route %s with effective nh count %u",
__PRETTY_FUNCTION__, buf,
old_route->nh_list ?
listcount(old_route->nh_list)
: 0);
}

/* Update RIB/FIB */
if (ospf6->route_table->hook_add)
(*ospf6->route_table->hook_add)
(old_route);

}
/* Delete the new route its info added to existing
* route.
*/
ospf6_route_delete(route);
break;
}
}

if (!route_found) {
/* Add new route to existing node in ospf6 route table. */
ospf6_route_add(route, ospf6->route_table);
}
}

void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
{
struct ospf6_as_external_lsa *external;
struct prefix asbr_id;
struct ospf6_route *asbr_entry, *route;
struct ospf6_route *asbr_entry, *route, *old;
struct ospf6_path *path;
char buf[PREFIX2STR_BUFFER];

external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
Expand Down Expand Up @@ -245,12 +370,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)

ospf6_route_copy_nexthops(route, asbr_entry);

path = ospf6_path_dup(&route->path);
ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
listnode_add_sort(route->paths, path);


if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&route->prefix, buf, sizeof(buf));
zlog_debug("AS-External route add: %s", buf);
zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
__PRETTY_FUNCTION__,
(route->path.type == OSPF6_PATH_TYPE_EXTERNAL1)
? 1 : 2, buf, route->path.cost,
route->path.u.cost_e2,
listcount(route->nh_list));
}

old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
if (!old) {
/* Add the new route to ospf6 instance route table. */
ospf6_route_add(route, ospf6->route_table);
} else {
/* RFC 2328 16.4 (6)
* ECMP: Keep new equal preference path in current
* route's path list, update zebra with new effective
* list along with addition of ECMP path.
*/
ospf6_asbr_update_route_ecmp_path(old, route);
}

ospf6_route_add(route, ospf6->route_table);
}

void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
Expand Down Expand Up @@ -291,16 +438,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
nroute = ospf6_route_next(route);
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
if (route->path.origin.type != lsa->header->type)
continue;
if (route->path.origin.id != lsa->header->id)
continue;
if (route->path.origin.adv_router != lsa->header->adv_router)

/* Route has multiple ECMP paths remove,
* matching path and update effective route's nh list.
*/
if (listcount(route->paths) > 1) {
struct listnode *anode, *anext;
struct listnode *nnode, *rnode, *rnext;
struct ospf6_nexthop *nh, *rnh;
struct ospf6_path *o_path;
bool nh_updated = false;

/* Iterate all paths of route to find maching with LSA
* remove from route path list. If route->path is same,
* replace from paths list.
*/
for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
o_path)) {
if (o_path->origin.type != lsa->header->type)
continue;
if (o_path->origin.id != lsa->header->id)
continue;
if (o_path->origin.adv_router !=
lsa->header->adv_router)
continue;

if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&prefix, buf, sizeof(buf));
zlog_debug(
"%s: route %s path found with nh %u",
__PRETTY_FUNCTION__, buf,
listcount(o_path->nh_list));
}

/* Remove found path's nh_list from
* the route's nh_list.
*/
for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
nnode, nh)) {
for (ALL_LIST_ELEMENTS(route->nh_list,
rnode, rnext, rnh)) {
if (!ospf6_nexthop_is_same(rnh,
nh))
continue;
listnode_delete(route->nh_list,
rnh);
ospf6_nexthop_delete(rnh);
}
}
/* Delete the path from route's path list */
listnode_delete(route->paths, o_path);
ospf6_path_free(o_path);
nh_updated = true;
}

if (nh_updated) {
/* Iterate all paths and merge nexthop,
* unlesss any of the nexthop similar to
* ones deleted as part of path deletion.
*/

for (ALL_LIST_ELEMENTS(route->paths, anode,
anext, o_path)) {
ospf6_merge_nexthops(route->nh_list,
o_path->nh_list);
}

if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&route->prefix, buf,
sizeof(buf));
zlog_debug("%s: AS-External %u route %s update paths %u nh %u"
, __PRETTY_FUNCTION__,
(route->path.type ==
OSPF6_PATH_TYPE_EXTERNAL1)
? 1 : 2, buf,
listcount(route->paths),
listcount(route->nh_list));
}

/* Update RIB/FIB w/ effective nh_list */
if (ospf6->route_table->hook_add)
(*ospf6->route_table->hook_add)(route);

/* route's path is similar to lsa header,
* replace route's path with route's
* paths list head.
*/
if (route->path.origin.id == lsa->header->id &&
route->path.origin.adv_router ==
lsa->header->adv_router) {
struct ospf6_path *h_path;

h_path = (struct ospf6_path *)
listgetdata(listhead(route->paths));
route->path.origin.type =
h_path->origin.type;
route->path.origin.id =
h_path->origin.id;
route->path.origin.adv_router =
h_path->origin.adv_router;
}
}
continue;

} else {
if (route->path.origin.type != lsa->header->type)
continue;
if (route->path.origin.id != lsa->header->id)
continue;
if (route->path.origin.adv_router !=
lsa->header->adv_router)
continue;
}
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&route->prefix, buf, sizeof(buf));
zlog_debug("AS-External route remove: %s", buf);
zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u",
__PRETTY_FUNCTION__,
route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
? 1 : 2, buf, route->path.cost,
route->path.u.cost_e2,
listcount(route->nh_list));
}
ospf6_route_remove(route, ospf6->route_table);
}
Expand Down
2 changes: 2 additions & 0 deletions ospf6d/ospf6_asbr.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,7 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);

extern int config_write_ospf6_debug_asbr(struct vty *vty);
extern void install_element_ospf6_debug_asbr(void);
extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
struct ospf6_route *route);

#endif /* OSPF6_ASBR_H */
3 changes: 2 additions & 1 deletion ospf6d/ospf6_intra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)

if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
prefix2str(&route->prefix, buf, sizeof(buf));
zlog_debug(" route %s add", buf);
zlog_debug(" route %s add with nh count %u", buf,
listcount(route->nh_list));
}

ospf6_route_add(route, oa->route_table);
Expand Down
1 change: 1 addition & 0 deletions ospf6d/ospf6_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
1 change: 1 addition & 0 deletions ospf6d/ospf6_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX)
DECLARE_MTYPE(OSPF6_SPFTREE)
DECLARE_MTYPE(OSPF6_NEXTHOP)
DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
DECLARE_MTYPE(OSPF6_PATH)
DECLARE_MTYPE(OSPF6_OTHER)

#endif /* _QUAGGA_OSPF6_MEMORY_H */
Loading