From da086a3ba69a87904f2cb10c75a16ee82b671bf4 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 17 Jan 2018 10:55:46 -0800 Subject: [PATCH] ospf6d: spf calculation w/ multiple router lsas An OSPFv3 enabled Router can originate or receive multiple Link State-IDs for Router LSAs. As per RFC 5340 A 4.3, more than one Router LSAs, from given Vertex is considered (as concatenated) single large Router LSA. Created hidden show command to simulate concatenated large LSA from advertising/self Router LSAs. Ticket:CM-19329 Reviewed By: Testing Done: Simulate 160 subinterfaces between R1 === R2--R3, This triggers R1 and R2 to generate multiple link state IDs for Router LSAs. During SPF calculation only aggregated single router LSA processed and SPF tree formed. Signed-off-by: Chirag Shah --- ospf6d/ospf6_area.c | 2 + ospf6d/ospf6_area.h | 1 + ospf6d/ospf6_lsa.c | 2 +- ospf6d/ospf6_lsa.h | 1 + ospf6d/ospf6_spf.c | 355 ++++++++++++++++++++++++++------------------ ospf6d/ospf6_spf.h | 4 + ospf6d/ospf6d.c | 44 ++++++ 7 files changed, 266 insertions(+), 143 deletions(-) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 252e4a454549..ed624c6ae414 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -221,6 +221,7 @@ struct ospf6_area *ospf6_area_create(u_int32_t area_id, struct ospf6 *o, int df) oa->lsdb->hook_add = ospf6_area_lsdb_hook_add; oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove; oa->lsdb_self = ospf6_lsdb_create(oa); + oa->temp_router_lsa_lsdb = ospf6_lsdb_create(oa); oa->spf_table = OSPF6_ROUTE_TABLE_CREATE(AREA, SPF_RESULTS); oa->spf_table->scope = oa; @@ -279,6 +280,7 @@ void ospf6_area_delete(struct ospf6_area *oa) ospf6_lsdb_delete(oa->lsdb); ospf6_lsdb_delete(oa->lsdb_self); + ospf6_lsdb_delete(oa->temp_router_lsa_lsdb); ospf6_spf_table_finish(oa->spf_table); ospf6_route_table_delete(oa->spf_table); diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index d212d9238726..b7cd9b4b09af 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -55,6 +55,7 @@ struct ospf6_area { struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; + struct ospf6_lsdb *temp_router_lsa_lsdb; struct ospf6_route_table *spf_table; struct ospf6_route_table *route_table; diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 82f75b153eb2..cca4616c1633 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -191,7 +191,7 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) /* ospf6 age functions */ /* calculate birth */ -static void ospf6_lsa_age_set(struct ospf6_lsa *lsa) +void ospf6_lsa_age_set(struct ospf6_lsa *lsa) { struct timeval now; diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 3536d33d19ab..db446a328734 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -252,5 +252,6 @@ extern void ospf6_lsa_terminate(void); extern int config_write_ospf6_debug_lsa(struct vty *vty); extern void install_element_ospf6_debug_lsa(void); +extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa); #endif /* OSPF6_LSA_H */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 6e6d8a7f0097..17ce1771e2a7 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -163,21 +163,20 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v) } static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, - struct ospf6_vertex *v, - uint32_t link_id) + struct ospf6_vertex *v) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa = NULL; u_int16_t type = 0; u_int32_t id = 0, adv_router = 0; if (VERTEX_IS_TYPE(NETWORK, v)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = link_id; + id = htonl(0); adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = link_id; + id = htonl(0); adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc); } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) { type = htons(OSPF6_LSTYPE_NETWORK); @@ -186,19 +185,22 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, } } - lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb); - + if (type == htons(OSPF6_LSTYPE_NETWORK)) + lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb); + else + lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb, + adv_router); if (IS_OSPF6_DEBUG_SPF(PROCESS)) { char ibuf[16], abuf[16]; inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf)); inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf)); if (lsa) - zlog_debug(" Link to: %s , V %s id %u", lsa->name, - v->name, link_id); + zlog_debug(" Link to: %s len %u, V %s", lsa->name, + ntohs(lsa->header->length), v->name); else - zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u", + zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s", ospf6_lstype_name(type), ibuf, abuf, - v->name, link_id); + v->name); } return lsa; @@ -461,17 +463,14 @@ void ospf6_spf_calculation(u_int32_t router_id, struct ospf6_vertex *root, *v, *w; int size; caddr_t lsdesc; - struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL; - const struct route_node *end = NULL; + struct ospf6_lsa *lsa; struct in6_addr address; - struct ospf6_lsdb *lsdb = NULL; ospf6_spf_table_finish(result_table); /* Install the calculating router itself as the root of the SPF tree */ /* construct root vertex */ - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_ROUTER), htonl(0), router_id, - oa->lsdb_self); + lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id); if (lsa == NULL) { if (IS_OSPF6_DEBUG_SPF(PROCESS)) zlog_debug("%s: No router LSA for area %s\n", __func__, @@ -479,8 +478,6 @@ 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; @@ -510,139 +507,63 @@ void ospf6_spf_calculation(u_int32_t router_id, && ospf6_router_is_stub_router(v->lsa))) continue; - 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); - } - } 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 + /* 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; - } - - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop(w->nh_list, + 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); - } + pqueue_enqueue(w, candidate_list); } } + pqueue_delete(candidate_list); + ospf6_remove_temp_router_lsa(oa); + oa->spf_calculation++; } @@ -1029,3 +950,153 @@ void ospf6_spf_init(void) install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd); install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd); } + +/* Create Aggregated Large Router-LSA from multiple Link-State IDs + * RFC 5340 A 4.3: + * When more than one router-LSA is received from a single router, + * the links are processed as if concatenated into a single LSA.*/ +struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, + struct ospf6_lsdb *lsdb, + uint32_t adv_router) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *rtr_lsa = NULL; + struct ospf6_lsa_header *lsa_header = NULL; + uint8_t *new_header = NULL; + const struct route_node *end = NULL; + uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0; + u_int16_t type = 0; + char ifbuf[16]; + uint32_t interface_id; + caddr_t lsd; + + lsa_length = sizeof(struct ospf6_lsa_header) + + sizeof(struct ospf6_router_lsa); + total_lsa_length = lsa_length; + type = htons(OSPF6_LSTYPE_ROUTER); + + /* First check Aggregated LSA formed earlier in Cache */ + lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router, + area->temp_router_lsa_lsdb); + if (lsa) + return lsa; + + inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf)); + + /* Determine total LSA length from all link state ids */ + end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa); + while (rtr_lsa) { + lsa = rtr_lsa; + if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + continue; + } + lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header; + total_lsa_length += (ntohs(lsa_header->length) + - lsa_length); + num_lsa++; + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + } + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: adv_router %s num_lsa %u to convert.", + __PRETTY_FUNCTION__, ifbuf, num_lsa); + if (num_lsa == 1) + return lsa; + + if (num_lsa == 0) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: adv_router %s not found in LSDB.", + __PRETTY_FUNCTION__, ifbuf); + return NULL; + } + + /* Allocate memory for this LSA */ + new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length); + if (!new_header) + return NULL; + + /* LSA information structure */ + lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA, + sizeof(struct ospf6_lsa)); + if (!lsa) { + free(new_header); + return NULL; + } + + lsa->header = (struct ospf6_lsa_header *)new_header; + + lsa->lsdb = area->temp_router_lsa_lsdb; + + /* Fill Larger LSA Payload */ + end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa); + if (rtr_lsa) { + if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + /* Append first Link State ID LSA */ + lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header; + memcpy(new_header, lsa_header, + ntohs(lsa_header->length)); + /* Assign new lsa length as aggregated length. */ + ((struct ospf6_lsa_header *)new_header)->length = + htons(total_lsa_length); + new_header += ntohs(lsa_header->length); + num_lsa--; + } + } + + /* Print LSA Name */ + ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name)); + + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + while (rtr_lsa) { + if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + continue; + } + + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4; + interface_id = ROUTER_LSDESC_GET_IFID(lsd); + inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf)); + zlog_debug("%s: Next Router LSA %s to aggreat with len %u interface_id %s", + __PRETTY_FUNCTION__, rtr_lsa->name, + ntohs(lsa_header->length), ifbuf); + } + + /* Append Next Link State ID LSA */ + lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header; + memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4), + (ntohs(lsa_header->length) - lsa_length)); + new_header += (ntohs(lsa_header->length) - lsa_length); + num_lsa--; + + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + } + + /* Calculate birth of this lsa */ + ospf6_lsa_age_set(lsa); + + /* Store Aggregated LSA into area temp lsdb */ + ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb); + + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u", + __PRETTY_FUNCTION__, lsa->name, + ntohl(lsa->header->id), ntohs(lsa->header->type), + ntohs(lsa->header->length), num_lsa); + + return lsa; +} + +void ospf6_remove_temp_router_lsa(struct ospf6_area *area) +{ + struct ospf6_lsa *lsa = NULL; + + for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s Remove LSA %s lsa->lock %u lsdb count %u", + __PRETTY_FUNCTION__, + lsa->name, lsa->lock, + area->temp_router_lsa_lsdb->count); + ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb); + } +} diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index dbb88d12ba00..f294b8d34f33 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -149,5 +149,9 @@ extern int config_write_ospf6_debug_spf(struct vty *vty); extern void install_element_ospf6_debug_spf(void); extern void ospf6_spf_init(void); extern void ospf6_spf_reason_string(unsigned int reason, char *buf, int size); +extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, + struct ospf6_lsdb *lsdb, + uint32_t adv_router); +extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area); #endif /* OSPF6_SPF_H */ diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index d28d9dd06417..bbc1cc18f6dd 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -360,6 +360,49 @@ DEFUN (show_ipv6_ospf6_database_router, return CMD_SUCCESS; } +DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router, + show_ipv6_ospf6_database_aggr_router_cmd, + "show ipv6 ospf6 database aggr adv-router A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Aggregated Router LSA\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n") +{ + int level = OSPF6_LSDB_SHOW_LEVEL_DETAIL; + uint16_t type = htons(OSPF6_LSTYPE_ROUTER); + int idx_ipv4 = 6; + struct listnode *i; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_lsdb *lsdb; + uint32_t adv_router = 0; + + inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router); + + for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { + if (adv_router == o->router_id) + lsdb = oa->lsdb_self; + else + lsdb = oa->lsdb; + if (ospf6_create_single_router_lsa(oa, lsdb, + adv_router) == NULL) { + vty_out(vty, "Adv router is not found in LSDB."); + return CMD_SUCCESS; + } + ospf6_lsdb_show(vty, level, &type, NULL, NULL, + oa->temp_router_lsa_lsdb); + /* Remove the temp cache */ + ospf6_remove_temp_router_lsa(oa); + } + + vty_out(vty, "\n"); + + return CMD_SUCCESS; +} + DEFUN (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd, "show ipv6 ospf6 database linkstate-id A.B.C.D []", @@ -1219,6 +1262,7 @@ void ospf6_init(void) install_element( VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd); /* Make ospf protocol socket. */ ospf6_serv_sock();