mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 16:04:49 +00:00
Merge pull request #1566 from chiragshah6/ospfv3_dev
ospf6d: Fix External routes ECMP
This commit is contained in:
commit
0c6a8fb9ec
@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
|||||||
|
|
||||||
ospf6_route_copy_nexthops(route, abr_entry);
|
ospf6_route_copy_nexthops(route, abr_entry);
|
||||||
|
|
||||||
|
|
||||||
/* (7) If the routes are identical, copy the next hops over to existing
|
/* (7) If the routes are identical, copy the next hops over to existing
|
||||||
route. ospf6's route table implementation will otherwise string both
|
route. ospf6's route table implementation will otherwise string both
|
||||||
routes, but keep the older one as the best route since the routes
|
routes, but keep the older one as the best route since the routes
|
||||||
@ -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)) {
|
if (old && (ospf6_route_cmp(route, old) == 0)) {
|
||||||
ospf6_route_merge_nexthops(old, route);
|
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 */
|
/* Update RIB/FIB */
|
||||||
if (table->hook_add)
|
if (table->hook_add)
|
||||||
(*table->hook_add)(old);
|
(*table->hook_add)(old);
|
||||||
@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
|||||||
ospf6_route_delete(route);
|
ospf6_route_delete(route);
|
||||||
} else {
|
} else {
|
||||||
if (is_debug)
|
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_ia_add_nw_route (table, &prefix, route); */
|
||||||
ospf6_route_add(route, table);
|
ospf6_route_add(route, table);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
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);
|
ospf6_route_add(copy, ospf6->route_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,11 +173,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
|
|||||||
return ntohl(network_order);
|
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)
|
void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
|
||||||
{
|
{
|
||||||
struct ospf6_as_external_lsa *external;
|
struct ospf6_as_external_lsa *external;
|
||||||
struct prefix asbr_id;
|
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];
|
char buf[PREFIX2STR_BUFFER];
|
||||||
|
|
||||||
external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
|
external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
|
||||||
@ -245,12 +370,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
|
|||||||
|
|
||||||
ospf6_route_copy_nexthops(route, asbr_entry);
|
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)) {
|
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
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)
|
void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
|
||||||
@ -291,16 +438,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
|
|||||||
nroute = ospf6_route_next(route);
|
nroute = ospf6_route_next(route);
|
||||||
if (route->type != OSPF6_DEST_TYPE_NETWORK)
|
if (route->type != OSPF6_DEST_TYPE_NETWORK)
|
||||||
continue;
|
continue;
|
||||||
if (route->path.origin.type != lsa->header->type)
|
|
||||||
continue;
|
/* Route has multiple ECMP paths remove,
|
||||||
if (route->path.origin.id != lsa->header->id)
|
* matching path and update effective route's nh list.
|
||||||
continue;
|
*/
|
||||||
if (route->path.origin.adv_router != lsa->header->adv_router)
|
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;
|
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)) {
|
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
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);
|
ospf6_route_remove(route, ospf6->route_table);
|
||||||
}
|
}
|
||||||
|
@ -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 int config_write_ospf6_debug_asbr(struct vty *vty);
|
||||||
extern void install_element_ospf6_debug_asbr(void);
|
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 */
|
#endif /* OSPF6_ASBR_H */
|
||||||
|
@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
|
|||||||
|
|
||||||
if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
|
if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
|
||||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
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);
|
ospf6_route_add(route, oa->route_table);
|
||||||
|
@ -41,4 +41,5 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
|
|||||||
DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
|
DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
|
||||||
DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
|
DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
|
||||||
DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
|
DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
|
||||||
|
DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
|
||||||
DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
|
DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
|
||||||
|
@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX)
|
|||||||
DECLARE_MTYPE(OSPF6_SPFTREE)
|
DECLARE_MTYPE(OSPF6_SPFTREE)
|
||||||
DECLARE_MTYPE(OSPF6_NEXTHOP)
|
DECLARE_MTYPE(OSPF6_NEXTHOP)
|
||||||
DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
|
DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
|
||||||
|
DECLARE_MTYPE(OSPF6_PATH)
|
||||||
DECLARE_MTYPE(OSPF6_OTHER)
|
DECLARE_MTYPE(OSPF6_OTHER)
|
||||||
|
|
||||||
#endif /* _QUAGGA_OSPF6_MEMORY_H */
|
#endif /* _QUAGGA_OSPF6_MEMORY_H */
|
||||||
|
@ -215,7 +215,7 @@ void ospf6_copy_nexthops(struct list *dst, struct list *src)
|
|||||||
if (ospf6_nexthop_is_set(nh)) {
|
if (ospf6_nexthop_is_set(nh)) {
|
||||||
nh_new = ospf6_nexthop_create();
|
nh_new = ospf6_nexthop_create();
|
||||||
ospf6_nexthop_copy(nh_new, nh);
|
ospf6_nexthop_copy(nh_new, nh);
|
||||||
listnode_add(dst, nh_new);
|
listnode_add_sort(dst, nh_new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +231,7 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
|
|||||||
if (!ospf6_route_find_nexthop(dst, nh)) {
|
if (!ospf6_route_find_nexthop(dst, nh)) {
|
||||||
nh_new = ospf6_nexthop_create();
|
nh_new = ospf6_nexthop_create();
|
||||||
ospf6_nexthop_copy(nh_new, nh);
|
ospf6_nexthop_copy(nh_new, nh);
|
||||||
listnode_add(dst, nh_new);
|
listnode_add_sort(dst, nh_new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
|
int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
|
||||||
{
|
{
|
||||||
if (a->ifindex < b->ifindex)
|
if (a->ifindex < b->ifindex)
|
||||||
return -1;
|
return -1;
|
||||||
@ -351,6 +351,36 @@ static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b)
|
||||||
|
{
|
||||||
|
if (a->origin.adv_router < b->origin.adv_router)
|
||||||
|
return -1;
|
||||||
|
else if (a->origin.adv_router > b->origin.adv_router)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf6_path_free(struct ospf6_path *op)
|
||||||
|
{
|
||||||
|
if (op->nh_list)
|
||||||
|
list_delete_and_null(&op->nh_list);
|
||||||
|
XFREE(MTYPE_OSPF6_PATH, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ospf6_path *ospf6_path_dup(struct ospf6_path *path)
|
||||||
|
{
|
||||||
|
struct ospf6_path *new;
|
||||||
|
|
||||||
|
new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path));
|
||||||
|
memcpy(new, path, sizeof(struct ospf6_path));
|
||||||
|
new->nh_list = list_new();
|
||||||
|
new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
||||||
|
new->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
struct ospf6_route *ospf6_route_create(void)
|
struct ospf6_route *ospf6_route_create(void)
|
||||||
{
|
{
|
||||||
struct ospf6_route *route;
|
struct ospf6_route *route;
|
||||||
@ -358,6 +388,9 @@ struct ospf6_route *ospf6_route_create(void)
|
|||||||
route->nh_list = list_new();
|
route->nh_list = list_new();
|
||||||
route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
||||||
route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
||||||
|
route->paths = list_new();
|
||||||
|
route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
|
||||||
|
route->paths->del = (void (*)(void *))ospf6_path_free;
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +399,8 @@ void ospf6_route_delete(struct ospf6_route *route)
|
|||||||
if (route) {
|
if (route) {
|
||||||
if (route->nh_list)
|
if (route->nh_list)
|
||||||
list_delete_and_null(&route->nh_list);
|
list_delete_and_null(&route->nh_list);
|
||||||
|
if (route->paths)
|
||||||
|
list_delete_and_null(&route->paths);
|
||||||
XFREE(MTYPE_OSPF6_ROUTE, route);
|
XFREE(MTYPE_OSPF6_ROUTE, route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,7 +499,13 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
|
|||||||
|
|
||||||
for (target = ospf6_route_lookup(&route->prefix, table); target;
|
for (target = ospf6_route_lookup(&route->prefix, table); target;
|
||||||
target = target->next) {
|
target = target->next) {
|
||||||
if (ospf6_route_is_identical(target, route))
|
if (target->type == route->type &&
|
||||||
|
(memcmp(&target->prefix, &route->prefix,
|
||||||
|
sizeof(struct prefix)) == 0) &&
|
||||||
|
target->path.type == route->path.type &&
|
||||||
|
target->path.cost == route->path.cost &&
|
||||||
|
target->path.u.cost_e2 == route->path.u.cost_e2 &&
|
||||||
|
ospf6_route_cmp_nexthops(target, route) == 0)
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1083,6 +1124,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
|
|||||||
vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
|
vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
|
||||||
route->path.u.cost_e2);
|
route->path.u.cost_e2);
|
||||||
|
|
||||||
|
vty_out(vty, "Paths count: %u\n", route->paths->count);
|
||||||
vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
|
vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
|
||||||
/* Nexthops */
|
/* Nexthops */
|
||||||
vty_out(vty, "Nexthop:\n");
|
vty_out(vty, "Nexthop:\n");
|
||||||
|
@ -96,6 +96,9 @@ struct ospf6_path {
|
|||||||
u_int32_t cost_config;
|
u_int32_t cost_config;
|
||||||
} u;
|
} u;
|
||||||
u_int32_t tag;
|
u_int32_t tag;
|
||||||
|
|
||||||
|
/* nh list for this path */
|
||||||
|
struct list *nh_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OSPF6_PATH_TYPE_NONE 0
|
#define OSPF6_PATH_TYPE_NONE 0
|
||||||
@ -149,6 +152,9 @@ struct ospf6_route {
|
|||||||
/* path */
|
/* path */
|
||||||
struct ospf6_path path;
|
struct ospf6_path path;
|
||||||
|
|
||||||
|
/* List of Paths. */
|
||||||
|
struct list *paths;
|
||||||
|
|
||||||
/* nexthop */
|
/* nexthop */
|
||||||
struct list *nh_list;
|
struct list *nh_list;
|
||||||
};
|
};
|
||||||
@ -256,6 +262,7 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf,
|
|||||||
int size);
|
int size);
|
||||||
|
|
||||||
extern struct ospf6_nexthop *ospf6_nexthop_create(void);
|
extern struct ospf6_nexthop *ospf6_nexthop_create(void);
|
||||||
|
extern int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b);
|
||||||
extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh);
|
extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh);
|
||||||
extern void ospf6_clear_nexthops(struct list *nh_list);
|
extern void ospf6_clear_nexthops(struct list *nh_list);
|
||||||
extern int ospf6_num_nexthops(struct list *nh_list);
|
extern int ospf6_num_nexthops(struct list *nh_list);
|
||||||
@ -331,5 +338,7 @@ extern int config_write_ospf6_debug_route(struct vty *vty);
|
|||||||
extern void install_element_ospf6_debug_route(void);
|
extern void install_element_ospf6_debug_route(void);
|
||||||
extern void ospf6_route_init(void);
|
extern void ospf6_route_init(void);
|
||||||
extern void ospf6_clean(void);
|
extern void ospf6_clean(void);
|
||||||
|
extern void ospf6_path_free(struct ospf6_path *op);
|
||||||
|
extern struct ospf6_path *ospf6_path_dup(struct ospf6_path *path);
|
||||||
|
|
||||||
#endif /* OSPF6_ROUTE_H */
|
#endif /* OSPF6_ROUTE_H */
|
||||||
|
@ -145,6 +145,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa)
|
|||||||
v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
|
v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
|
||||||
|
|
||||||
v->nh_list = list_new();
|
v->nh_list = list_new();
|
||||||
|
v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
||||||
v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
||||||
|
|
||||||
v->parent = NULL;
|
v->parent = NULL;
|
||||||
|
@ -95,6 +95,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
|
|||||||
|
|
||||||
static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
|
static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
|
||||||
{
|
{
|
||||||
|
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||||
|
char buf[PREFIX2STR_BUFFER];
|
||||||
|
|
||||||
|
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||||
|
zlog_debug("%s: brouter %s add with nh count %u",
|
||||||
|
__PRETTY_FUNCTION__, buf, listcount(route->nh_list));
|
||||||
|
}
|
||||||
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
|
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
|
||||||
ospf6_asbr_lsentry_add(route);
|
ospf6_asbr_lsentry_add(route);
|
||||||
ospf6_abr_originate_summary(route);
|
ospf6_abr_originate_summary(route);
|
||||||
@ -102,6 +109,13 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
|
|||||||
|
|
||||||
static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
|
static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
|
||||||
{
|
{
|
||||||
|
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||||
|
char buf[PREFIX2STR_BUFFER];
|
||||||
|
|
||||||
|
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||||
|
zlog_debug("%s: brouter %s del with nh count %u",
|
||||||
|
__PRETTY_FUNCTION__, buf, listcount(route->nh_list));
|
||||||
|
}
|
||||||
route->flag |= OSPF6_ROUTE_REMOVE;
|
route->flag |= OSPF6_ROUTE_REMOVE;
|
||||||
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
|
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
|
||||||
ospf6_asbr_lsentry_remove(route);
|
ospf6_asbr_lsentry_remove(route);
|
||||||
|
Loading…
Reference in New Issue
Block a user