void ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix prefix; struct ospf6_route *route; char buf[64]; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Withdraw AS-External route for %s", lsa->name); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore self-originated AS-External-LSA"); return; } memset (&prefix, 0, sizeof (struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; ospf6_prefix_in6_addr (&prefix.u.prefix6, &external->prefix); route = ospf6_route_lookup (&prefix, ospf6->route_table); if (route == NULL) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&prefix, buf, sizeof (buf)); zlog_debug ("AS-External route %s not found", buf); } return; } for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); route = ospf6_route_next (route)) { if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; 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)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("AS-External route remove: %s", buf); } ospf6_route_remove (route, ospf6->route_table); } if (route != NULL) ospf6_route_unlock (route); }
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); }
void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa) { struct ospf6_lsa_as_external *external; struct prefix dest; char buf[64]; struct ospf6_route_req request; if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Withdraw route of %s", lsa->str); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Self-originated, ignore"); return; } external = OSPF6_LSA_HEADER_END (lsa->header); memset (&dest, 0, sizeof (dest)); dest.family = AF_INET6; dest.prefixlen = external->prefix.prefix_length; memcpy (&dest.u.prefix6, (char *)(external + 1), OSPF6_PREFIX_SPACE (dest.prefixlen)); prefix2str (&dest, buf, sizeof (buf)); if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: route: %s", buf); ospf6_route_lookup (&request, &dest, ospf6->route_table); if (ospf6_route_end (&request)) { zlog_info ("ASBR: route not found"); return; } while (request.path.origin.id != lsa->header->id || request.path.origin.adv_router != lsa->header->adv_router) { if (prefix_same (&request.route.prefix, &dest) != 1) { zlog_info ("ASBR: Can't find the entry matches the origin"); return; } ospf6_route_next (&request); } assert (request.path.origin.id == lsa->header->id); assert (request.path.origin.adv_router == request.path.origin.adv_router); while (request.path.origin.id == lsa->header->id && request.path.origin.adv_router == lsa->header->adv_router && prefix_same (&request.route.prefix, &dest) == 1) { ospf6_route_remove (&request, ospf6->route_table); ospf6_route_next (&request); } }
static struct ospf6_vertex * ospf6_vertex_create (struct ospf6_lsa *lsa) { struct ospf6_vertex *v; int i; v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex)); /* type */ if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) v->type = OSPF6_VERTEX_TYPE_ROUTER; 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, &v->vertex_id); /* name */ ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name)); /* Associated LSA */ v->lsa = lsa; /* capability bits + options */ v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header)); v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1); v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2); v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3); for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_clear (&v->nexthop[i]); v->parent = NULL; v->child_list = list_new (); v->child_list->cmp = ospf6_vertex_id_cmp; return v; }
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 char * ospf6_inter_area_router_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_inter_router_lsa *router_lsa; if (lsa != NULL) { router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (buf) inet_ntop (AF_INET, &router_lsa->router_id, buf, buflen); } return (buf); }
int ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_router_lsa *router_lsa; char buf[64]; router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_options_printbuf (router_lsa->options, buf, sizeof (buf)); vty_out (vty, " Options: %s%s", buf, VNL); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (router_lsa), VNL); inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); vty_out (vty, " Destination Router ID: %s%s", buf, VNL); return 0; }
static int ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_prefix_lsa *prefix_lsa; char buf[INET6_ADDRSTRLEN]; prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (prefix_lsa), VNL); ospf6_prefix_options_printbuf (prefix_lsa->prefix.prefix_options, buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); vty_out (vty, " Prefix: %s%s", ospf6_inter_area_prefix_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL); return 0; }
/* Display functions */ static char * ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_inter_prefix_lsa *prefix_lsa; struct in6_addr in6; if (lsa != NULL) { prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); if (buf) { inet_ntop (AF_INET6, &in6, buf, buflen); sprintf (&buf[strlen(buf)], "/%d", prefix_lsa->prefix.prefix_length); } } return (buf); }
/* Display functions */ int ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_prefix_lsa *prefix_lsa; struct in6_addr in6; char buf[64]; prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (prefix_lsa), VNL); ospf6_prefix_options_printbuf (prefix_lsa->prefix.prefix_options, buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); vty_out (vty, " Prefix: %s/%d%s", buf, prefix_lsa->prefix.prefix_length, VNL); return 0; }
void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix asbr_id; struct ospf6_route *asbr_entry, *route; char buf[64]; int i; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Calculate AS-External route for %s", lsa->name); if (lsa->header->adv_router == ospf6->router_id) { /*if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore self-originated AS-External-LSA");*/ return; } if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with LSInfinity Metric"); return; } ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id); asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table); if (asbr_entry == NULL || ! CHECK_FLAG (asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&asbr_id, buf, sizeof (buf)); zlog_debug ("ASBR entry not found: %s", buf); } return; } route = ospf6_route_create (); route->type = OSPF6_DEST_TYPE_NETWORK; route->prefix.family = AF_INET6; route->prefix.prefixlen = external->prefix.prefix_length; ospf6_prefix_in6_addr (&route->prefix.u.prefix6, &external->prefix); route->path.area_id = asbr_entry->path.area_id; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.prefix_options = external->prefix.prefix_options; if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) { route->path.type = OSPF6_PATH_TYPE_EXTERNAL2; route->path.metric_type = 2; route->path.cost = asbr_entry->path.cost; route->path.cost_e2 = OSPF6_ASBR_METRIC (external); } else { route->path.type = OSPF6_PATH_TYPE_EXTERNAL1; route->path.metric_type = 1; route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external); route->path.cost_e2 = 0; } for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("AS-External route add: %s", buf); } ospf6_route_add (route, ospf6->route_table); }
/* 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); }
/* RFC 2328 16.2. Calculating the inter-area routes */ void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct prefix prefix, abr_prefix; struct ospf6_route_table *table = NULL; struct ospf6_route *range, *route, *old = NULL; struct ospf6_route *abr_entry; u_char type = 0; char options[3] = {0, 0, 0}; u_int8_t prefix_options = 0; u_int32_t cost = 0; u_char router_bits = 0; int i; char buf[64]; int is_debug = 0; struct ospf6_inter_prefix_lsa *prefix_lsa = NULL; struct ospf6_inter_router_lsa *router_lsa = NULL; memset (&prefix, 0, sizeof (prefix)); if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) { is_debug++; zlog_debug ("Examin %s in area %s", lsa->name, oa->name); } prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr (&prefix.u.prefix6, &prefix_lsa->prefix); if (is_debug) prefix2str (&prefix, buf, sizeof (buf)); table = oa->ospf6->route_table; type = OSPF6_DEST_TYPE_NETWORK; prefix_options = prefix_lsa->prefix.prefix_options; cost = OSPF6_ABR_SUMMARY_METRIC (prefix_lsa); } else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) { if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER)) { is_debug++; zlog_debug ("Examin %s in area %s", lsa->name, oa->name); } router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix); if (is_debug) inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); table = oa->ospf6->brouter_table; type = OSPF6_DEST_TYPE_ROUTER; options[0] = router_lsa->options[0]; options[1] = router_lsa->options[1]; options[2] = router_lsa->options[2]; cost = OSPF6_ABR_SUMMARY_METRIC (router_lsa); SET_FLAG (router_bits, OSPF6_ROUTER_BIT_E); } else assert (0); /* Find existing route */ route = ospf6_route_lookup (&prefix, table); if (route) ospf6_route_lock (route); while (route && ospf6_route_is_prefix (&prefix, route)) { if (route->path.area_id == oa->area_id && route->path.origin.type == lsa->header->type && route->path.origin.id == lsa->header->id && route->path.origin.adv_router == lsa->header->adv_router && ! CHECK_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED)) old = route; route = ospf6_route_next (route); } /* (1) if cost == LSInfinity or if the LSA is MaxAge */ if (cost == OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("cost is LS_INFINITY, ignore"); if (old) ospf6_route_remove (old, table); return; } if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (is_debug) zlog_debug ("LSA is MaxAge, ignore"); if (old) ospf6_route_remove (old, table); return; } /* (2) if the LSA is self-originated, ignore */ if (lsa->header->adv_router == oa->ospf6->router_id) { if (is_debug) zlog_debug ("LSA is self-originated, ignore"); if (old) ospf6_route_remove (old, table); return; } /* (3) if the prefix is equal to an active configured address range */ /* or if the NU bit is set in the prefix */ if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { range = ospf6_route_lookup (&prefix, oa->range_table); if (range) { if (is_debug) zlog_debug ("Prefix is equal to address range, ignore"); if (old) ospf6_route_remove (old, table); return; } if (CHECK_FLAG (prefix_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU) || CHECK_FLAG (prefix_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_LA)) { if (is_debug) zlog_debug ("Prefix has NU/LA bit set, ignore"); if (old) ospf6_route_remove (old, table); return; } } if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) { /* To pass test suites */ if (! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_R) || ! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_V6)) { if (is_debug) zlog_debug ("Prefix has NU/LA bit set, ignore"); if (old) ospf6_route_remove (old, table); return; } } /* (4) if the routing table entry for the ABR does not exist */ ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &abr_prefix); abr_entry = ospf6_route_lookup (&abr_prefix, oa->ospf6->brouter_table); if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id || CHECK_FLAG (abr_entry->flag, OSPF6_ROUTE_REMOVE) || ! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) { if (is_debug) zlog_debug ("ABR router entry does not exist, ignore"); if (old) ospf6_route_remove (old, table); return; } /* Check import list */ if (IMPORT_NAME (oa)) { if (IMPORT_LIST (oa) == NULL) IMPORT_LIST (oa) = access_list_lookup (AFI_IP6, IMPORT_NAME (oa)); if (IMPORT_LIST (oa)) if (access_list_apply (IMPORT_LIST (oa), &prefix) == FILTER_DENY) { if (is_debug) zlog_debug ("Prefix was denied by import-list"); if (old) ospf6_route_remove (old, table); return; } } /* Check input prefix-list */ if (PREFIX_NAME_IN (oa)) { if (PREFIX_LIST_IN (oa) == NULL) PREFIX_LIST_IN (oa) = prefix_list_lookup (AFI_IP6, PREFIX_NAME_IN (oa)); if (PREFIX_LIST_IN (oa)) if (prefix_list_apply (PREFIX_LIST_IN (oa), &prefix) != PREFIX_PERMIT) { if (is_debug) zlog_debug ("Prefix was denied by prefix-list"); if (old) ospf6_route_remove (old, table); return; } } /* (5),(6),(7) the path preference is handled by the sorting in the routing table. Always install the path by substituting old route (if any). */ if (old) route = ospf6_route_copy (old); else route = ospf6_route_create (); route->type = type; route->prefix = prefix; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.router_bits = router_bits; route->path.options[0] = options[0]; route->path.options[1] = options[1]; route->path.options[2] = options[2]; route->path.prefix_options = prefix_options; route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTER; route->path.cost = abr_entry->path.cost + cost; for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) route->nexthop[i] = abr_entry->nexthop[i]; if (is_debug) zlog_debug ("Install route: %s", buf); ospf6_route_add (route, table); }
void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa) { struct ospf6_lsa_as_external *external; struct prefix_ls asbr_id; struct ospf6_route_req asbr_entry; struct ospf6_route_req request; external = OSPF6_LSA_HEADER_END (lsa->header); if (IS_LSA_MAXAGE (lsa)) return; if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Calculate %s", lsa->str); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Self-originated, ignore"); return; } if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) { if (IS_OSPF6_DUMP_ASBR) zlog_info ("ASBR: Metric is Infinity, ignore"); return; } memset (&asbr_id, 0, sizeof (asbr_id)); asbr_id.family = AF_UNSPEC; asbr_id.prefixlen = 64; /* xxx */ asbr_id.adv_router.s_addr = lsa->header->adv_router; ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id, ospf6->topology_table); if (ospf6_route_end (&asbr_entry)) { if (IS_OSPF6_DUMP_ASBR) { char buf[64]; inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf)); zlog_info ("ASBR: ASBR %s not found, ignore", buf); } return; } memset (&request, 0, sizeof (request)); request.route.type = OSPF6_DEST_TYPE_NETWORK; request.route.prefix.family = AF_INET6; request.route.prefix.prefixlen = external->prefix.prefix_length; memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1), OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen)); request.path.area_id = asbr_entry.path.area_id; request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); request.path.origin.id = lsa->header->id; request.path.origin.adv_router = lsa->header->adv_router; if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) { request.path.type = OSPF6_PATH_TYPE_EXTERNAL2; request.path.metric_type = 2; request.path.cost = asbr_entry.path.cost; request.path.cost_e2 = OSPF6_ASBR_METRIC (external); } else { request.path.type = OSPF6_PATH_TYPE_EXTERNAL1; request.path.metric_type = 1; request.path.cost = asbr_entry.path.cost + OSPF6_ASBR_METRIC (external); request.path.cost_e2 = 0; } request.path.prefix_options = external->prefix.prefix_options; while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr == asbr_id.adv_router.s_addr && asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER) { memcpy (&request.nexthop, &asbr_entry.nexthop, sizeof (struct ospf6_nexthop)); ospf6_route_add (&request, ospf6->route_table); ospf6_route_next (&asbr_entry); } }