diff options
author | Chirag Shah <chirag@cumulusnetworks.com> | 2017-11-13 16:24:06 +0100 |
---|---|---|
committer | Chirag Shah <chirag@cumulusnetworks.com> | 2017-11-17 19:01:04 +0100 |
commit | 26e1461672844ec1d0dd065714f740723349dd53 (patch) | |
tree | 89fd1c6f21775e92f51727810824a546d4af344d /ospf6d/ospf6_spf.c | |
parent | Merge pull request #1460 from bingen/bug_pw_conf_master (diff) | |
download | frr-26e1461672844ec1d0dd065714f740723349dd53.tar.xz frr-26e1461672844ec1d0dd065714f740723349dd53.zip |
ospf6d: SPF consider all Router LSAs
Based on RFC-5340, there could be multiple Router LSAs
associated with Same Advertising Router. During SPF calculation
ensure first Root Vertex accommodates all Link state IDs for its
originated Router LSAs push them into priority queue.
Similarly follow for other Vertexes, considering Router LSAs
with multiple Link State IDs.
Ticket: CM-18069
Testing Done:
Topology: R1 === R2 -- R3
Validated with more than 100 Subinterfaces
between R1 === R2 with broadcast links,
Validated show ipv6 ospf6 spf tree containing all graph nodes.
Validated ip -6 route at R3 and all intra prefix LSAs route
installed with ospf6 as protocol.
2) Run R1 === R2 with Point-to-Point links.
3) Perform few other abr and ospf6 test cases of LSA ageout,
route install and delete cases.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
Diffstat (limited to 'ospf6d/ospf6_spf.c')
-rw-r--r-- | ospf6d/ospf6_spf.c | 244 |
1 files changed, 175 insertions, 69 deletions
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 4276f46c3..340d90159 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -110,26 +110,30 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) sizeof(struct ospf6_vertex)); /* type */ - if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) + if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) { v->type = OSPF6_VERTEX_TYPE_ROUTER; - else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_NETWORK) + /* Router LSA use Link ID 0 as base in vertex_id */ + ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), + &v->vertex_id); + } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_NETWORK) { v->type = OSPF6_VERTEX_TYPE_NETWORK; - else - assert(0); - - /* vertex_id */ - ospf6_linkstate_prefix(lsa->header->adv_router, lsa->header->id, + /* vertex_id */ + ospf6_linkstate_prefix(lsa->header->adv_router, lsa->header->id, &v->vertex_id); + } else + assert(0); /* name */ ospf6_linkstate_prefix2str(&v->vertex_id, v->name, sizeof(v->name)); if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("%s: Creating vertex %s of type %s", __func__, - v->name, + zlog_debug("%s: Creating vertex %s of type %s (0x%04hx) lsa %s", + __func__, v->name, ((ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" - : "N/W")); + : "N/W"), ntohs(lsa->header->type), + lsa->name); + /* Associated LSA */ v->lsa = lsa; @@ -158,7 +162,8 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v) } static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, - struct ospf6_vertex *v) + struct ospf6_vertex *v, + uint32_t link_id) { struct ospf6_lsa *lsa; u_int16_t type = 0; @@ -166,12 +171,12 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, if (VERTEX_IS_TYPE(NETWORK, v)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = htonl(0); + id = link_id; adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = htonl(0); + id = link_id; adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc); } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) { type = htons(OSPF6_LSTYPE_NETWORK); @@ -187,10 +192,12 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf)); inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf)); if (lsa) - zlog_debug(" Link to: %s", lsa->name); + zlog_debug(" Link to: %s , V %s id %u", lsa->name, + v->name, link_id); else - zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA", - ospf6_lstype_name(type), ibuf, abuf); + zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u", + ospf6_lstype_name(type), ibuf, abuf, + v->name, link_id); } return lsa; @@ -308,10 +315,11 @@ static int ospf6_spf_install(struct ospf6_vertex *v, { struct ospf6_route *route, *parent_route; struct ospf6_vertex *prev; + char pbuf[PREFIX2STR_BUFFER]; if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("SPF install %s hops %d cost %d", v->name, v->hops, - v->cost); + zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v->name, + v->lsa->name, v->hops, v->cost); route = ospf6_route_lookup(&v->vertex_id, result_table); if (route && route->path.cost < v->cost) { @@ -322,16 +330,30 @@ static int ospf6_spf_install(struct ospf6_vertex *v, ospf6_vertex_delete(v); return -1; } else if (route && route->path.cost == v->cost) { - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug(" another path found, merge"); - + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + prefix2str(&route->prefix, pbuf, sizeof(pbuf)); + zlog_debug(" another path found to route %s lsa %s, merge", + pbuf, v->lsa->name); + } ospf6_spf_merge_nexthops_to_route(route, v); prev = (struct ospf6_vertex *)route->route_option; assert(prev->hops <= v->hops); - ospf6_vertex_delete(v); + if ((VERTEX_IS_TYPE(ROUTER, v) && + route->path.origin.id != v->lsa->header->id)) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + zlog_debug("%s: V lsa %s id %u, route id %u are different", + __PRETTY_FUNCTION__, v->lsa->name, + ntohl(v->lsa->header->id), + ntohl(route->path.origin.id)); + } + return 0; + } + + ospf6_vertex_delete(v); return -1; + } /* There should be no case where candidate being installed (variable @@ -438,8 +460,10 @@ void ospf6_spf_calculation(u_int32_t router_id, struct ospf6_vertex *root, *v, *w; int size; caddr_t lsdesc; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL; + const struct route_node *end = NULL; struct in6_addr address; + struct ospf6_lsdb *lsdb = NULL; ospf6_spf_table_finish(result_table); @@ -454,6 +478,8 @@ void ospf6_spf_calculation(u_int32_t router_id, return; } + self_rtr_lsa = lsa; + /* initialize */ candidate_list = pqueue_create(); candidate_list->cmp = ospf6_vertex_cmp; @@ -462,6 +488,7 @@ void ospf6_spf_calculation(u_int32_t router_id, root->area = oa; root->cost = 0; root->hops = 0; + root->link_id = lsa->header->id; inet_pton(AF_INET6, "::1", &address); /* Actually insert root to the candidate-list as the only candidate */ @@ -482,55 +509,134 @@ void ospf6_spf_calculation(u_int32_t router_id, && ospf6_router_is_stub_router(v->lsa))) continue; - /* For each LS description in the just-added vertex V's LSA */ - size = (VERTEX_IS_TYPE(ROUTER, v) - ? sizeof(struct ospf6_router_lsdesc) - : sizeof(struct ospf6_network_lsdesc)); - for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END(v->lsa->header); - lsdesc += size) { - lsa = ospf6_lsdesc_lsa(lsdesc, v); - if (lsa == NULL) - continue; - - if (OSPF6_LSA_IS_MAXAGE(lsa)) - continue; - - if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) - continue; - - w = ospf6_vertex_create(lsa); - w->area = oa; - w->parent = v; - if (VERTEX_IS_TYPE(ROUTER, v)) { - w->cost = v->cost - + ROUTER_LSDESC_GET_METRIC(lsdesc); - w->hops = - v->hops - + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1); - } else /* NETWORK */ - { - w->cost = v->cost; - w->hops = v->hops + 1; + if (VERTEX_IS_TYPE(ROUTER, v)) { + /* First fetch root Router LSAs from lsdb_self */ + if (v->lsa == self_rtr_lsa) + lsdb = oa->lsdb_self; + else + lsdb = v->area->lsdb; + + /* Iterating multiple ROUTER LSAs from same adv router + * with different Link State ID */ + end = ospf6_lsdb_head(lsdb, 2, + htons(OSPF6_LSTYPE_ROUTER), + v->lsa->header->adv_router, + &rtr_lsa); + while (rtr_lsa) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: Next LSA %s to process" + ,__PRETTY_FUNCTION__, + rtr_lsa->name); + size = sizeof(struct ospf6_router_lsdesc); + /* For each LS description in the just-added vertex V's LSA */ + for (lsdesc = OSPF6_LSA_HEADER_END( + rtr_lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END( + rtr_lsa->header); + lsdesc += size) { + lsa = ospf6_lsdesc_lsa(lsdesc, v, + rtr_lsa->header->id); + if (lsa == NULL) + continue; + + if (OSPF6_LSA_IS_MAXAGE(lsa)) + continue; + + if (!ospf6_lsdesc_backlink(lsa, + lsdesc, v)) + continue; + + w = ospf6_vertex_create(lsa); + w->area = oa; + w->parent = v; + w->link_id = rtr_lsa->header->id; + + if (VERTEX_IS_TYPE(ROUTER, v)) { + w->cost = v->cost + + ROUTER_LSDESC_GET_METRIC(lsdesc); + w->hops = + v->hops + + (VERTEX_IS_TYPE(NETWORK, w) + ? 0 : 1); + } else /* NETWORK */ { + w->cost = v->cost; + w->hops = v->hops + 1; + } + + /* nexthop calculation */ + if (w->hops == 0) + ospf6_add_nexthop(w->nh_list, + ROUTER_LSDESC_GET_IFID(lsdesc) + , NULL); + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc(w, v, lsdesc); + else { + ospf6_copy_nexthops(w->nh_list, + v->nh_list); + } + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug( + " New candidate: %s hops %d cost %d", + w->name, w->hops, + w->cost); + pqueue_enqueue(w, candidate_list); + } + /* Fetch next Link state ID Router LSA */ + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); } - - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop( - w->nh_list, + } else { + /* For each LS description in the just-added vertex V's LSA */ + size = (VERTEX_IS_TYPE(ROUTER, v) + ? sizeof(struct ospf6_router_lsdesc) + : sizeof(struct ospf6_network_lsdesc)); + for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END(v->lsa->header); + lsdesc += size) { + lsa = ospf6_lsdesc_lsa(lsdesc, v, v->link_id); + if (lsa == NULL) + continue; + + if (OSPF6_LSA_IS_MAXAGE(lsa)) + continue; + + if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) + continue; + + w = ospf6_vertex_create(lsa); + w->area = oa; + w->parent = v; + if (VERTEX_IS_TYPE(ROUTER, v)) { + w->cost = v->cost + + ROUTER_LSDESC_GET_METRIC(lsdesc); + w->hops = + v->hops + + (VERTEX_IS_TYPE(NETWORK, w) ? + 0 : 1); + } else /* NETWORK */ { + w->cost = v->cost; + w->hops = v->hops + 1; + } + + /* nexthop calculation */ + if (w->hops == 0) + ospf6_add_nexthop(w->nh_list, ROUTER_LSDESC_GET_IFID(lsdesc), NULL); - else if (w->hops == 1 && v->hops == 0) - ospf6_nexthop_calc(w, v, lsdesc); - else { - ospf6_copy_nexthops(w->nh_list, v->nh_list); - } - - /* add new candidate to the candidate_list */ - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug( + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc(w, v, lsdesc); + else { + ospf6_copy_nexthops(w->nh_list, + v->nh_list); + } + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug( " New candidate: %s hops %d cost %d", - w->name, w->hops, w->cost); - pqueue_enqueue(w, candidate_list); + w->name, w->hops, w->cost); + pqueue_enqueue(w, candidate_list); + } } } |