summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_intra.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_intra.c')
-rw-r--r--ospf6d/ospf6_intra.c472
1 files changed, 440 insertions, 32 deletions
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 0b7755a3f4..519c5e170f 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -49,8 +49,8 @@
#include "ospf6_spf.h"
unsigned char conf_debug_ospf6_brouter = 0;
-u_int32_t conf_debug_ospf6_brouter_specific_router_id;
-u_int32_t conf_debug_ospf6_brouter_specific_area_id;
+uint32_t conf_debug_ospf6_brouter_specific_router_id;
+uint32_t conf_debug_ospf6_brouter_specific_area_id;
#define MAX_LSA_PAYLOAD (1024 + 256)
/******************************/
@@ -189,15 +189,15 @@ int ospf6_router_lsa_originate(struct thread *thread)
struct ospf6_lsa_header *lsa_header;
struct ospf6_lsa *lsa;
- u_int32_t link_state_id = 0;
+ uint32_t link_state_id = 0;
struct listnode *node, *nnode;
struct listnode *j;
struct ospf6_interface *oi;
struct ospf6_neighbor *on, *drouter = NULL;
struct ospf6_router_lsa *router_lsa;
struct ospf6_router_lsdesc *lsdesc;
- u_int16_t type;
- u_int32_t router;
+ uint16_t type;
+ uint32_t router;
int count;
oa = (struct ospf6_area *)THREAD_ARG(thread);
@@ -461,7 +461,7 @@ int ospf6_network_lsa_originate(struct thread *thread)
struct ospf6_neighbor *on;
struct ospf6_link_lsa *link_lsa;
struct listnode *i;
- u_int16_t type;
+ uint16_t type;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_network_lsa = NULL;
@@ -1142,7 +1142,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
struct ospf6_route_table *route_advertise;
struct ospf6_link_lsa *link_lsa;
char *start, *end, *current;
- u_int16_t type;
+ uint16_t type;
char buf[PREFIX2STR_BUFFER];
oi = (struct ospf6_interface *)THREAD_ARG(thread);
@@ -1314,18 +1314,253 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
return 0;
}
+void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
+ struct ospf6_route *old,
+ struct ospf6_route *route)
+{
+ struct ospf6_route *old_route;
+ struct ospf6_path *ecmp_path, *o_path = NULL;
+ struct listnode *anode, *anext;
+ struct listnode *nnode, *rnode, *rnext;
+ struct ospf6_nexthop *nh, *rnh;
+ char buf[PREFIX2STR_BUFFER];
+ bool route_found = false;
+
+ /* check for old entry match with new route origin,
+ * delete old entry.
+ */
+ for (old_route = old; old_route; old_route = old_route->next) {
+ bool route_updated = false;
+
+ if (!ospf6_route_is_same(old_route, route) ||
+ (old_route->path.type != route->path.type))
+ continue;
+
+ /* Current and New route has same origin,
+ * delete old entry.
+ */
+ for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
+ o_path)) {
+ /* Check old route path and route has same
+ * origin.
+ */
+ if (o_path->area_id != route->path.area_id ||
+ (memcmp(&(o_path)->origin, &(route)->path.origin,
+ sizeof(struct ospf6_ls_origin)) != 0))
+ continue;
+
+ /* Cost is not same then delete current path */
+ if (o_path->cost == route->path.cost)
+ continue;
+
+ if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+ prefix2str(&old_route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: route %s cost old %u new %u is not same, replace route",
+ __PRETTY_FUNCTION__, buf,
+ o_path->cost, route->path.cost);
+ }
+
+ /* Remove selected current rout path's nh from
+ * effective nh list.
+ */
+ 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);
+ route_updated = true;
+ }
+ }
+
+ listnode_delete(old_route->paths, o_path);
+ ospf6_path_free(o_path);
+
+ /* Current route's path (adv_router info) is similar
+ * to route being added.
+ * Replace current route's path with paths list head.
+ * Update FIB with effective NHs.
+ */
+ if (listcount(old_route->paths)) {
+ if (old_route->path.origin.id ==
+ route->path.origin.id &&
+ old_route->path.origin.adv_router ==
+ route->path.origin.adv_router) {
+ struct ospf6_path *h_path;
+
+ h_path = (struct ospf6_path *)
+ listgetdata(listhead(old_route->paths));
+ old_route->path.origin.type =
+ h_path->origin.type;
+ old_route->path.origin.id =
+ h_path->origin.id;
+ old_route->path.origin.adv_router =
+ h_path->origin.adv_router;
+ }
+
+ if (route_updated) {
+ for (ALL_LIST_ELEMENTS(old_route->paths,
+ anode, anext, o_path)) {
+ ospf6_merge_nexthops(
+ old_route->nh_list,
+ o_path->nh_list);
+ }
+ /* Update ospf6 route table and
+ * RIB/FIB with effective
+ * nh_list
+ */
+ if (oa->route_table->hook_add)
+ (*oa->route_table->hook_add)
+ (old_route);
+ break;
+ }
+ } else {
+ if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+ prefix2str(&old_route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.",
+ __PRETTY_FUNCTION__, buf,
+ old_route->path.cost,
+ route->path.cost);
+ }
+ ospf6_route_remove(old_route,
+ oa->route_table);
+ break;
+ }
+ }
+ if (route_updated)
+ break;
+ }
+
+ 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))
+ continue;
+
+ /* Old Route and New Route have Equal Cost, Merge NHs */
+ if (old_route->path.cost == route->path.cost) {
+ route_found = true;
+
+ /* check if this path exists already in
+ * route->paths list, if so, replace nh_list.
+ */
+ for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
+ o_path)) {
+ if (o_path->area_id == route->path.area_id &&
+ (memcmp(&(o_path)->origin,
+ &(route)->path.origin,
+ sizeof(struct ospf6_ls_origin)) == 0))
+ 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);
+ /* Add the new path to route's path list */
+ listnode_add_sort(old_route->paths, ecmp_path);
+
+ UNSET_FLAG(old_route->flag, OSPF6_ROUTE_REMOVE);
+ SET_FLAG(old_route->flag, OSPF6_ROUTE_CHANGE);
+ /* Update RIB/FIB */
+ if (oa->route_table->hook_add)
+ (*oa->route_table->hook_add)
+ (old_route);
+ if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+ prefix2str(&route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: route %s %p another path added with nh %u, effective paths %u nh %u",
+ __PRETTY_FUNCTION__, buf,
+ (void *)old_route,
+ listcount(ecmp_path->nh_list),
+ old_route->paths ?
+ listcount(old_route->paths)
+ : 0,
+ listcount(old_route->nh_list));
+ }
+ } 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(INTRA_PREFIX)) {
+ prefix2str(&route->prefix,
+ buf, sizeof(buf));
+ zlog_debug("%s: existing route %s %p with effective paths %u nh count %u",
+ __PRETTY_FUNCTION__, buf,
+ (void *)old_route,
+ listcount(old_route->paths),
+ old_route->nh_list ?
+ listcount(old_route->nh_list)
+ : 0);
+ }
+
+ UNSET_FLAG(old_route->flag, OSPF6_ROUTE_REMOVE);
+ SET_FLAG(old_route->flag, OSPF6_ROUTE_CHANGE);
+ /* Update ospf6 route table and RIB/FIB */
+ if (oa->route_table->hook_add)
+ (*oa->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, oa->route_table);
+ }
+}
+
void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
{
struct ospf6_area *oa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix ls_prefix;
- struct ospf6_route *route, *ls_entry;
+ struct ospf6_route *route, *ls_entry, *old;
int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
char buf[PREFIX2STR_BUFFER];
struct interface *ifp;
int direct_connect = 0;
+ struct ospf6_path *path;
if (OSPF6_LSA_IS_MAXAGE(lsa))
return;
@@ -1417,13 +1652,31 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
ospf6_route_copy_nexthops(route, ls_entry);
}
- if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
- prefix2str(&route->prefix, buf, sizeof(buf));
- zlog_debug(" route %s add with nh count %u", buf,
- listcount(route->nh_list));
- }
+ path = ospf6_path_dup(&route->path);
+ ospf6_copy_nexthops(path->nh_list, route->path.nh_list);
+ listnode_add_sort(route->paths, path);
- ospf6_route_add(route, oa->route_table);
+ old = ospf6_route_lookup(&route->prefix, oa->route_table);
+ if (old && (ospf6_route_cmp(route, old) == 0)) {
+ if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+ prefix2str(&route->prefix, buf, sizeof(buf));
+ zlog_debug(" Update route: %s old cost %u new cost %u nh count %u paths %u",
+ buf,
+ old->path.cost, route->path.cost,
+ listcount(route->nh_list),
+ listcount(route->paths));
+ }
+ ospf6_intra_prefix_route_ecmp_path(oa, old, route);
+ } else {
+ if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+ prefix2str(&route->prefix, buf, sizeof(buf));
+ zlog_debug(" route %s add with cost %u nh %u paths %u",
+ buf, route->path.cost,
+ listcount(route->nh_list),
+ listcount(route->paths));
+ }
+ ospf6_route_add(route, oa->route_table);
+ }
prefix_num--;
}
@@ -1436,14 +1689,15 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
struct ospf6_area *oa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix prefix;
- struct ospf6_route *route, *nroute;
+ struct ospf6_route *route, *nroute, *route_to_del;
int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
char buf[PREFIX2STR_BUFFER];
if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
- zlog_debug("%s disappearing", lsa->name);
+ zlog_debug("%s: %s disappearing", __PRETTY_FUNCTION__,
+ lsa->name);
oa = OSPF6_AREA(lsa->lsdb->data);
@@ -1463,6 +1717,22 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
break;
prefix_num--;
+ route_to_del = ospf6_route_create();
+
+ memset(&route_to_del->prefix, 0, sizeof(struct prefix));
+ route_to_del->prefix.family = AF_INET6;
+ route_to_del->prefix.prefixlen = op->prefix_length;
+ ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, op);
+
+ route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
+ route_to_del->path.origin.type = lsa->header->type;
+ route_to_del->path.origin.id = lsa->header->id;
+ route_to_del->path.origin.adv_router = lsa->header->adv_router;
+ route_to_del->path.prefix_options = op->prefix_options;
+ route_to_del->path.area_id = oa->area_id;
+ route_to_del->path.type = OSPF6_PATH_TYPE_INTRA;
+ route_to_del->path.metric_type = 1;
+
memset(&prefix, 0, sizeof(struct prefix));
prefix.family = AF_INET6;
prefix.prefixlen = op->prefix_length;
@@ -1482,20 +1752,161 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
continue;
if (route->path.type != OSPF6_PATH_TYPE_INTRA)
continue;
- if (route->path.origin.type != lsa->header->type
- || route->path.origin.id != lsa->header->id
- || route->path.origin.adv_router
- != lsa->header->adv_router)
+ /* Route has multiple ECMP paths, remove matching
+ * path. Update current route's effective nh list
+ * after removal of one of the path.
+ */
+ 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 info.
+ * 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) ||
+ (o_path->origin.adv_router !=
+ lsa->header->adv_router) ||
+ (o_path->origin.id !=
+ lsa->header->id))
+ continue;
+
+ if (IS_OSPF6_DEBUG_EXAMIN
+ (INTRA_PREFIX)) {
+ prefix2str(&prefix, buf,
+ sizeof(buf));
+ zlog_debug(
+ "%s: route %s path found with cost %u nh %u to remove.",
+ __PRETTY_FUNCTION__,
+ buf, o_path->cost,
+ listcount(
+ o_path->nh_list));
+ }
+ /* Remove old route from global
+ * ospf6 route table.
+ * nh_update section will add
+ * back with effective nh.
+ */
+ if (oa->route_table->hook_remove)
+ (*oa->route_table->hook_remove)
+ (route);
+ /* 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;
+ break;
+ }
+
+ 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(
+ INTRA_PREFIX)) {
+ prefix2str(&route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: route %s update paths %u nh %u"
+ , __PRETTY_FUNCTION__,
+ buf,
+ listcount(route->paths),
+ listcount(
+ route->nh_list));
+ }
+
+ /* route's primary path is similar
+ * to LSA, replace route's primary
+ * 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;
+ }
+
+ /* Update Global Route table and
+ * RIB/FIB with effective
+ * nh_list
+ */
+ if (oa->route_table->hook_add)
+ (*oa->route_table->hook_add)
+ (route);
+ }
continue;
- if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
- prefix2str(&route->prefix, buf, sizeof(buf));
- zlog_debug("remove %s", buf);
+ } else {
+
+ if (route->path.origin.type != lsa->header->type
+ || route->path.origin.id != lsa->header->id
+ || route->path.origin.adv_router
+ != lsa->header->adv_router)
+ continue;
+
+ if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+ prefix2str(&route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("route remove %s with path %u cost %u nh %u",
+ buf, route->path.type,
+ route->path.cost,
+ listcount(route->nh_list));
+ }
+ ospf6_route_remove(route, oa->route_table);
}
- ospf6_route_remove(route, oa->route_table);
}
if (route)
ospf6_route_unlock(route);
+
+ ospf6_route_delete(route_to_del);
}
if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
@@ -1505,7 +1916,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
void ospf6_intra_route_calculation(struct ospf6_area *oa)
{
struct ospf6_route *route, *nroute;
- u_int16_t type;
+ uint16_t type;
struct ospf6_lsa *lsa;
void (*hook_add)(struct ospf6_route *) = NULL;
void (*hook_remove)(struct ospf6_route *) = NULL;
@@ -1558,7 +1969,7 @@ void ospf6_intra_route_calculation(struct ospf6_area *oa)
static void ospf6_brouter_debug_print(struct ospf6_route *brouter)
{
- u_int32_t brouter_id;
+ uint32_t brouter_id;
char brouter_name[16];
char area_name[16];
char destination[64];
@@ -1614,7 +2025,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
struct ospf6_route *brouter, *nbrouter, *copy;
void (*hook_add)(struct ospf6_route *) = NULL;
void (*hook_remove)(struct ospf6_route *) = NULL;
- u_int32_t brouter_id;
+ uint32_t brouter_id;
char brouter_name[16];
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id))
@@ -1735,9 +2146,6 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
&& CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)) {
UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
- zlog_debug("%s: EVENT unset REOUTE_REMOVE and ROUTE_ADD brouter %s",
- __PRETTY_FUNCTION__, brouter_name);
- ospf6_brouter_debug_print(brouter);
}
if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)) {
@@ -1861,7 +2269,7 @@ DEFUN (debug_ospf6_brouter_router,
)
{
int idx_ipv4 = 4;
- u_int32_t router_id;
+ uint32_t router_id;
inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON(router_id);
return CMD_SUCCESS;
@@ -1892,7 +2300,7 @@ DEFUN (debug_ospf6_brouter_area,
)
{
int idx_ipv4 = 4;
- u_int32_t area_id;
+ uint32_t area_id;
inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id);
OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON(area_id);
return CMD_SUCCESS;