static void ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, caddr_t lsdesc) { int i; ifindex_t ifindex; struct ospf6_interface *oi; u_int16_t type; u_int32_t adv_router; struct ospf6_lsa *lsa; struct ospf6_link_lsa *link_lsa; char buf[64]; assert (VERTEX_IS_TYPE (ROUTER, w)); ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex : /* v is the local router & the interface_id is a local ifindex */ (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc)); assert (ifindex >= 0); oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex); return; } type = htons (OSPF6_LSTYPE_LINK); adv_router = (VERTEX_IS_TYPE (NETWORK, v) ? NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) : ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc)); i = 0; for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) { if (VERTEX_IS_TYPE (ROUTER, v) && htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id) continue; link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_SPF (PROCESS)) { inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf)); zlog_debug (" nexthop %s from %s", buf, lsa->name); } if (i < OSPF6_MULTI_PATH_LIMIT) { memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr, sizeof (struct in6_addr)); w->nexthop[i].ifindex = ifindex; i++; } } if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("No nexthop for %s found", w->name); }
static char * ospf6_lsdesc_backlink (struct ospf6_lsa *lsa, caddr_t lsdesc, struct ospf6_vertex *v) { caddr_t backlink, found = NULL; int size; size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ? sizeof (struct ospf6_router_lsdesc) : sizeof (struct ospf6_network_lsdesc)); for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4; backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size) { assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) && VERTEX_IS_TYPE (NETWORK, v))); if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) && NETWORK_LSDESC_GET_NBR_ROUTERID (backlink) == v->lsa->header->adv_router) found = backlink; else if (VERTEX_IS_TYPE (NETWORK, v) && ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) && ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) == v->lsa->header->adv_router && ROUTER_LSDESC_GET_NBR_IFID (backlink) == ntohl (v->lsa->header->id)) found = backlink; else { if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) || ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc)) continue; if (ROUTER_LSDESC_GET_NBR_IFID (backlink) != ROUTER_LSDESC_GET_IFID (lsdesc) || ROUTER_LSDESC_GET_NBR_IFID (lsdesc) != ROUTER_LSDESC_GET_IFID (backlink)) continue; if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) != v->lsa->header->adv_router || ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) != lsa->header->adv_router) continue; found = backlink; } } if (IS_OSPF6_SIBLING_DEBUG_SPF) zlog_debug (" Backlink %s", (found ? "OK" : "FAIL")); return found; }
static struct ospf6_lsa * ospf6_lsdesc_lsa(caddr_t lsdesc, struct ospf6_vertex * v) { struct ospf6_lsa *lsa; 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 = htonl (0); adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc)) { type = htons (OSPF6_LSTYPE_ROUTER); 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); id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)); adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc); } } lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb); if (IS_OSPF6_SIBLING_DEBUG_SPF) { 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", lsa->name); else zlog_debug (" Link to: [Id:%s Adv:%s] No LSA", // ospf6_lstype_name (type), ibuf, abuf); ibuf, abuf); } return lsa; }
/* RFC2740 3.8.1. Calculating the shortest path tree for an area */ void ospf6_spf_calculation(u_int32_t router_id, struct ospf6_route_table * result_table, struct ospf6_area * oa, unsigned int hostnum) { struct pqueue * candidate_list; struct ospf6_vertex * root, * v, * w; int i; int size; caddr_t lsdesc; struct ospf6_lsa * lsa; if(IS_OSPF6_SIBLING_DEBUG_SPF) { zlog_debug("Starting spf calculation..."); } /* initialize */ candidate_list = pqueue_create(); candidate_list->cmp = ospf6_vertex_cmp; 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); if (lsa == NULL) { if(IS_OSPF6_SIBLING_DEBUG_SPF) { zlog_debug("Looking for type %d from lsdb %p with router id %d", htons(OSPF6_LSTYPE_ROUTER), oa->lsdb, router_id); zlog_debug("No router LSAs present, quiting spf calculation"); } return; } root = ospf6_vertex_create (lsa); root->area = oa; root->cost = 0; root->hops = 0; root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */ inet_pton (AF_INET6, "::1", &root->nexthop[0].address); /* Actually insert root to the candidate-list as the only candidate */ pqueue_enqueue (root, candidate_list); /* Iterate until candidate-list becomes empty */ while (candidate_list->size) { /* get closest candidate from priority queue */ v = pqueue_dequeue (candidate_list); /* installing may result in merging or rejecting of the vertex */ if (ospf6_spf_install (v, result_table, hostnum) < 0) 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_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) w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc); else if (w->hops == 1 && v->hops == 0) ospf6_nexthop_calc (w, v, lsdesc); else { for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); } /* add new candidate to the candidate_list */ if (IS_OSPF6_SIBLING_DEBUG_SPF) zlog_debug (" New candidate: %s hops %d cost %d", w->name, w->hops, w->cost); pqueue_enqueue (w, candidate_list); } } pqueue_delete (candidate_list); }