void ospf6_abr_disable_area (struct ospf6_area *area) { struct ospf6_area *oa; struct ospf6_route *ro; struct ospf6_lsa *old; struct listnode *node, *nnode; /* Withdraw all summary prefixes previously originated */ for (ro = ospf6_route_head (area->summary_prefix); ro; ro = ospf6_route_next (ro)) { old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) ospf6_lsa_purge (old); ospf6_route_remove (ro, area->summary_prefix); } /* Withdraw all summary router-routes previously originated */ for (ro = ospf6_route_head (area->summary_router); ro; ro = ospf6_route_next (ro)) { old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) ospf6_lsa_purge (old); ospf6_route_remove (ro, area->summary_router); } /* Schedule Router-LSA for each area (ABR status may change) */ for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) /* update B bit for each area */ OSPF6_ROUTER_LSA_SCHEDULE (oa); }
void ospf6_lsdb_show (struct vty *vty, int level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL; if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) showfunc = ospf6_lsa_show_summary; else if (level == OSPF6_LSDB_SHOW_LEVEL_DETAIL) showfunc = ospf6_lsa_show; else if (level == OSPF6_LSDB_SHOW_LEVEL_INTERNAL) showfunc = ospf6_lsa_show_internal; else if (level == OSPF6_LSDB_SHOW_LEVEL_DUMP) showfunc = ospf6_lsa_show_dump; if (type && id && adv_router) { lsa = ospf6_lsdb_lookup (*type, *id, *adv_router, lsdb); if (lsa) { if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) ospf6_lsa_show (vty, lsa); else (*showfunc) (vty, lsa); } return; } if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) ospf6_lsa_show_summary_header (vty); if (type && adv_router) lsa = ospf6_lsdb_type_router_head (*type, *adv_router, lsdb); else if (type) lsa = ospf6_lsdb_type_head (*type, lsdb); else lsa = ospf6_lsdb_head (lsdb); while (lsa) { if ((! adv_router || lsa->header->adv_router == *adv_router) && (! id || lsa->header->id == *id)) (*showfunc) (vty, lsa); if (type && adv_router) lsa = ospf6_lsdb_type_router_next (*type, *adv_router, lsa); else if (type) lsa = ospf6_lsdb_type_next (*type, lsa); else lsa = ospf6_lsdb_next (lsa); } }
/* Decide new LS sequence number to originate. note return value is network byte order */ u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; signed long seqnum = 0; /* if current database copy not found, return InitialSequenceNumber */ lsa = ospf6_lsdb_lookup (type, id, adv_router, lsdb); if (lsa == NULL) seqnum = INITIAL_SEQUENCE_NUMBER; else seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; return ((u_int32_t) htonl (seqnum)); }
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; }
static u_char * ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; struct in_addr area_id; u_int16_t type; struct in_addr id; struct in_addr adv_router; int len; oid *offset; int offsetlen; char a[16], b[16], c[16]; struct ospf6_area *oa; struct listnode *node; memset (&area_id, 0, sizeof (struct in_addr)); type = 0; memset (&id, 0, sizeof (struct in_addr)); memset (&adv_router, 0, sizeof (struct in_addr)); /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; #define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET \ (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) if (exact && offsetlen != OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET) return NULL; /* Parse area-id */ len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); if (len) oid2in_addr (offset, len, &area_id); offset += len; offsetlen -= len; /* Parse type */ len = (offsetlen < 1 ? offsetlen : 1); if (len) type = htons (*offset); offset += len; offsetlen -= len; /* Parse Router-ID */ len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); if (len) oid2in_addr (offset, len, &adv_router); offset += len; offsetlen -= len; /* Parse LS-ID */ len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); if (len) oid2in_addr (offset, len, &id); offset += len; offsetlen -= len; ospf6_id2str (area_id.s_addr, a, sizeof (a)); ospf6_id2str (adv_router.s_addr, b, sizeof (b)); ospf6_id2str (id.s_addr, c, sizeof (c)); zlog_debug ("SNMP access by lsdb: area=%s exact=%d length=%lu magic=%d" " type=%#x adv_router=%s id=%s", a, exact, (u_long)*length, v->magic, ntohs (type), b, c); if (exact) { oa = ospf6_area_lookup (area_id.s_addr, ospf6); lsa = ospf6_lsdb_lookup (type, id.s_addr, adv_router.s_addr, oa->lsdb); } else { for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { if (lsa) continue; if (ntohl (oa->area_id) < ntohl (area_id.s_addr)) continue; lsa = ospf6_lsdb_lookup_next (type, id.s_addr, adv_router.s_addr, oa->lsdb); if (! lsa) { type = 0; memset (&id, 0, sizeof (struct in_addr)); memset (&adv_router, 0, sizeof (struct in_addr)); } } } if (! lsa) { zlog_debug ("SNMP respond: No LSA to return"); return NULL; } oa = OSPF6_AREA (lsa->lsdb->data); zlog_debug ("SNMP respond: area: %s lsa: %s", oa->name, lsa->name); /* Add Index (AreaId, Type, RouterId, Lsid) */ *length = v->namelen + OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET; offset = name + v->namelen; oid_copy_addr (offset, (struct in_addr *) &oa->area_id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; *offset = ntohs (lsa->header->type); offset++; oid_copy_addr (offset, (struct in_addr *) &lsa->header->adv_router, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; oid_copy_addr (offset, (struct in_addr *) &lsa->header->id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; /* Return the current value of the variable */ switch (v->magic) { case OSPFv3AREALSDBAREAID: /* 1 */ area_id.s_addr = OSPF6_AREA (lsa->lsdb->data)->area_id; return SNMP_IPADDRESS (area_id); break; case OSPFv3AREALSDBTYPE: /* 2 */ return SNMP_INTEGER (ntohs (lsa->header->type)); break; case OSPFv3AREALSDBROUTERID: /* 3 */ adv_router.s_addr = lsa->header->adv_router; return SNMP_IPADDRESS (adv_router); break; case OSPFv3AREALSDBLSID: /* 4 */ id.s_addr = lsa->header->id; return SNMP_IPADDRESS (id); break; case OSPFv3AREALSDBSEQUENCE: /* 5 */ return SNMP_INTEGER (lsa->header->seqnum); break; case OSPFv3AREALSDBAGE: /* 6 */ ospf6_lsa_age_current (lsa); return SNMP_INTEGER (lsa->header->age); break; case OSPFv3AREALSDBCHECKSUM: /* 7 */ return SNMP_INTEGER (lsa->header->checksum); break; case OSPFv3AREALSDBADVERTISEMENT: /* 8 */ *var_len = ntohs (lsa->header->length); return (u_char *) lsa->header; break; case OSPFv3AREALSDBTYPEKNOWN: /* 9 */ return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ? SNMP_TRUE : SNMP_FALSE); break; default: return NULL; break; } return NULL; }
int ospf6_flood_interface_mdr (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; struct ospf6_lsa *req; int retrans_added = 0; int is_debug = 0; struct list *flood_neighbors = list_new (); bool flood_lsa = true; if (IS_OSPF6_DEBUG_FLOODING || IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) { is_debug++; zlog_debug ("Flooding on %s: %s", oi->interface->name, lsa->name); } /* (1) For each neighbor */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { if (is_debug) zlog_debug ("To neighbor %s", on->name); /* (a) if neighbor state < Exchange, examin next */ // Consider adjacent and (backup) dependent neighbors. // Require all bidirectional neighbors to be covered if (on->state < OSPF6_NEIGHBOR_TWOWAY) { if (is_debug) zlog_debug ("Neighbor state less than TwoWay, next neighbor"); continue; } if (on->state > OSPF6_NEIGHBOR_TWOWAY && on->state < OSPF6_NEIGHBOR_FULL && !need_adjacency (on)) { if (is_debug) zlog_debug ("No longer need adjacency with neighbor %s: " "scheduling AdjOK?", on->name); ospf6_neighbor_schedule_adjok (on); continue; } /* (b) if neighbor not yet Full, check request-list */ if (on->state >= OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_FULL) { if (is_debug) zlog_debug ("Neighbor not yet Full"); req = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, on->request_list); if (req == NULL) { if (is_debug) zlog_debug ("Not on request-list for this neighbor"); /* fall through */ } else { /* If new LSA less recent, examin next neighbor */ if (ospf6_lsa_compare (lsa, req) > 0) { if (is_debug) zlog_debug ("Requesting is newer, next neighbor"); continue; } /* If the same instance, delete from request-list and examin next neighbor */ if (ospf6_lsa_compare (lsa, req) == 0) { if (is_debug) zlog_debug ("Requesting the same, remove it, next neighbor"); ospf6_lsdb_remove (req, on->request_list); continue; } /* If the new LSA is more recent, delete from request-list */ if (ospf6_lsa_compare (lsa, req) < 0) { if (is_debug) zlog_debug ("Received is newer, remove requesting"); ospf6_lsdb_remove (req, on->request_list); /* fall through */ } } } /* (c) If the new LSA was received from this neighbor, examin next neighbor */ if (from == on) { if (is_debug) zlog_debug ("LSA was received from neighbor %s, next neighbor", on->name); continue; } //Ogierv3 Section 6 Par 3 /* At this point, we are not positive that the neighbor has an up-to-date instance of this new LSA */ /* However, in the MANET case, we need to: i) check whether neighbor sent a multicast ACK for it already ii) whether I am an active relay for this originator */ /* Has LSA been acked previously with multicast ack? */ if (ospf6_mdr_neighbor_has_acked (on, lsa)) { //Don't add LSA to neighbor's retransmission list if (is_debug) zlog_debug ("Existing multicast ACK from neighbor %s found " "for LSA, next neighbor", on->name); continue; // examine next neighbor: neighbor already acked } /* Here, checking for coverage of this neighbor on the sender's RNL. If not present, I add this to the flood_neighbors list. If LSA was received as a unicast, however, can't assume that neighbor "on" was covered by the transmission, so still need to add to flood_neighbors regardless of from->rnl */ if (from) { if (!from->mdr.Report2Hop || (!CHECK_FLAG (lsa->flag, OSPF6_LSA_RECVMCAST)) || !ospf6_mdr_lookup_neighbor (from->mdr.rnl, on->router_id)) { listnode_add (flood_neighbors, on); } } // Retransmit only to adjacent neighbors. if (on->state < OSPF6_NEIGHBOR_EXCHANGE) continue; /* (d) add retrans-list, schedule retransmission */ if (is_debug) zlog_debug ("Add retrans-list of this neighbor"); ospf6_increment_retrans_count (lsa); quagga_gettime (QUAGGA_CLK_MONOTONIC, &lsa->rxmt_time); ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); on->thread_send_lsupdate = ospf6_send_lsupdate_delayed_msec (master, ospf6_lsupdate_send_neighbor, on, oi->rxmt_interval * 1000, on->thread_send_lsupdate); retrans_added++; } /* (2) examin next interface if not added to retrans-list */ // MDRs can flood an LSA without adding it to the retrans-list if (!from && retrans_added == 0) { /* this LSA is self-originated but there are no adjacent neighbors */ flood_lsa = false; if (is_debug) zlog_debug ("Self-originated LSA and no adjacent neighbors"); } //Ogierv3 Section 6 - Remove (3) and (4) //Ogierv3 Section 6 - Replace (5) //Ogierv3 Forwarding Procedure bullet(a) if (from && oi->mdr.mdr_level == OSPF6_MDR) { //Flood the LSA unless all neighbors are already covered if (flood_neighbors->count == 0) { flood_lsa = false; if (is_debug) zlog_debug ("All neighbors covered"); } else if (oi->mdr.nonflooding_mdr) { // Non-flooding MDR acts like a BMDR. for (ALL_LIST_ELEMENTS (flood_neighbors, node, nnode, on)) ospf6_backupwait_lsa_add (lsa, on); flood_lsa = false; if (is_debug) zlog_debug ("Router is a non-flooding MDR"); } } //Ogierv3 Forwarding Procedure bullet(c) else if (from && oi->mdr.mdr_level == OSPF6_BMDR)
void ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) { struct ospf6_route *match; struct ospf6_external_info *info = NULL; struct route_node *node; struct ospf6_lsa *lsa; struct prefix prefix_id; char pbuf[64], ibuf[16]; struct listnode *lnode, *lnnode; struct ospf6_area *oa; match = ospf6_route_lookup (prefix, ospf6->external_table); if (match == NULL) { if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); zlog_debug ("No such route %s to withdraw", pbuf); } return; } info = match->route_option; assert (info); if (info->type != type) { if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); zlog_debug ("Original protocol mismatch: %s", pbuf); } return; } if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); zlog_debug ("Withdraw %s (AS-External Id:%s)", pbuf, ibuf); } lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), htonl (info->id), ospf6->router_id, ospf6->lsdb); if (lsa) ospf6_lsa_purge (lsa); /* remove binding in external_id_table */ prefix_id.family = AF_INET; prefix_id.prefixlen = 32; prefix_id.u.prefix4.s_addr = htonl (info->id); node = route_node_lookup (ospf6->external_id_table, &prefix_id); assert (node); node->info = NULL; route_unlock_node (node); ospf6_route_remove (match, ospf6->external_table); XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info); /* Router-Bit (ASBR Flag) may have to be updated */ for (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) OSPF6_ROUTER_LSA_SCHEDULE (oa); }
/* AS External LSA origination */ static void ospf6_as_external_lsa_originate (struct ospf6_route *route) { char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *old, *lsa; struct ospf6_external_info *info = route->route_option; struct ospf6_as_external_lsa *as_external_lsa; char buf[64]; caddr_t p; /*restarter 不产生 lsa*/ if(ospf6->restart) { return ; } /* find previous LSA */ old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), route->path.origin.id, ospf6->router_id, ospf6->lsdb); if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("Originate AS-External-LSA for %s", buf); } /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; as_external_lsa = (struct ospf6_as_external_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) ((caddr_t) as_external_lsa + sizeof (struct ospf6_as_external_lsa)); /* Fill AS-External-LSA */ /* Metric type */ if (route->path.metric_type == 2) SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); else UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); /* forwarding address */ if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); else UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); /* external route tag */ UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); /* Set metric */ OSPF6_ASBR_METRIC_SET (as_external_lsa, route->path.cost); /* prefixlen */ as_external_lsa->prefix.prefix_length = route->prefix.prefixlen; /* PrefixOptions */ as_external_lsa->prefix.prefix_options = route->path.prefix_options; /* don't use refer LS-type */ as_external_lsa->prefix.prefix_refer_lstype = htons (0); /* set Prefix */ memcpy (p, &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); ospf6_prefix_apply_mask (&as_external_lsa->prefix); p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); /* Forwarding address */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) { memcpy (p, &info->forwarding, sizeof (struct in6_addr)); p += sizeof (struct in6_addr); } /* External Route Tag */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) { /* xxx */ } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_AS_EXTERNAL); lsa_header->id = route->path.origin.id; lsa_header->adv_router = ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, ospf6->lsdb); lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_process (lsa, ospf6); }
/* 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 12.4.3. Summary-LSAs */ void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area) { struct ospf6_lsa *lsa, *old = NULL; struct ospf6_interface *oi; struct ospf6_route *summary, *range = NULL; struct ospf6_area *route_area; char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; caddr_t p; struct ospf6_inter_prefix_lsa *prefix_lsa; struct ospf6_inter_router_lsa *router_lsa; struct ospf6_route_table *summary_table = NULL; u_int16_t type; char buf[64]; int is_debug = 0; if (route->type == OSPF6_DEST_TYPE_ROUTER) { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER)) { is_debug++; inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof (buf)); zlog_debug ("Originating summary in area %s for ASBR %s", area->name, buf); } summary_table = area->summary_router; } else { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_PREFIX)) { is_debug++; prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("Originating summary in area %s for %s", area->name, buf); } summary_table = area->summary_prefix; } summary = ospf6_route_lookup (&route->prefix, summary_table); if (summary) old = ospf6_lsdb_lookup (summary->path.origin.type, summary->path.origin.id, area->ospf6->router_id, area->lsdb); /* if this route has just removed, remove corresponding LSA */ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) { if (is_debug) zlog_debug ("The route has just removed, purge previous LSA"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Only destination type network, range or ASBR are considered */ if (route->type != OSPF6_DEST_TYPE_NETWORK && route->type != OSPF6_DEST_TYPE_RANGE && (route->type != OSPF6_DEST_TYPE_ROUTER || ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) { if (is_debug) zlog_debug ("Route type is none of network, range nor ASBR, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* AS External routes are never considered */ if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (is_debug) zlog_debug ("Path type is external, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the path's area is the same as target area */ if (route->path.area_id == area->area_id) { if (is_debug) zlog_debug ("The route is in the area itself, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the nexthops belongs to the target area */ oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex); if (oi && oi->area && oi->area == area) { if (is_debug) zlog_debug ("The route's nexthop is in the same area, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the route cost is greater or equal to LSInfinity */ if (route->path.cost >= OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("The cost exceeds LSInfinity, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* if this is a route to ASBR */ if (route->type == OSPF6_DEST_TYPE_ROUTER) { /* Only the prefered best path is considered */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)) { if (is_debug) zlog_debug ("This is the secondary path to the ASBR, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Do not generate if the area is stub */ /* XXX */ } /* if this is an intra-area route, this may be suppressed by aggregation */ if (route->type == OSPF6_DEST_TYPE_NETWORK && route->path.type == OSPF6_PATH_TYPE_INTRA) { /* search for configured address range for the route's area */ route_area = ospf6_area_lookup (route->path.area_id, area->ospf6); assert (route_area); range = ospf6_route_lookup_bestmatch (&route->prefix, route_area->range_table); /* ranges are ignored when originate backbone routes to transit area. Otherwise, if ranges are configured, the route is suppressed. */ if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) && (route->path.area_id != OSPF_AREA_BACKBONE || ! IS_AREA_TRANSIT (area))) { if (is_debug) { prefix2str (&range->prefix, buf, sizeof (buf)); zlog_debug ("Suppressed by range %s of area %s", buf, route_area->name); } if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } } /* If this is a configured address range */ if (route->type == OSPF6_DEST_TYPE_RANGE) { /* If DoNotAdvertise is set */ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) { if (is_debug) zlog_debug ("This is the range with DoNotAdvertise set. ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Whether the route have active longer prefix */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) { if (is_debug) zlog_debug ("The range is not active. withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } } /* Check export list */ if (EXPORT_NAME (area)) { if (EXPORT_LIST (area) == NULL) EXPORT_LIST (area) = access_list_lookup (AFI_IP6, EXPORT_NAME (area)); if (EXPORT_LIST (area)) if (access_list_apply (EXPORT_LIST (area), &route->prefix) == FILTER_DENY) { if (is_debug) { inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof(buf)); zlog_debug ("prefix %s was denied by export list", buf); } return; } } /* Check filter-list */ if (PREFIX_NAME_OUT (area)) { if (PREFIX_LIST_OUT (area) == NULL) PREFIX_LIST_OUT (area) = prefix_list_lookup(AFI_IP6, PREFIX_NAME_OUT (area)); if (PREFIX_LIST_OUT (area)) if (prefix_list_apply (PREFIX_LIST_OUT (area), &route->prefix) != PREFIX_PERMIT) { if (is_debug) { inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof (buf)); zlog_debug ("prefix %s was denied by filter-list out", buf); } return; } } /* the route is going to be originated. store it in area's summary_table */ if (summary == NULL) { summary = ospf6_route_copy (route); if (route->type == OSPF6_DEST_TYPE_NETWORK || route->type == OSPF6_DEST_TYPE_RANGE) summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); else summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); summary->path.origin.adv_router = area->ospf6->router_id; summary->path.origin.id = ospf6_new_ls_id (summary->path.origin.type, summary->path.origin.adv_router, area->lsdb); summary = ospf6_route_add (summary, summary_table); } else { summary->type = route->type; quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed); } summary->path.router_bits = route->path.router_bits; summary->path.options[0] = route->path.options[0]; summary->path.options[1] = route->path.options[1]; summary->path.options[2] = route->path.options[2]; summary->path.prefix_options = route->path.prefix_options; summary->path.area_id = area->area_id; summary->path.type = OSPF6_PATH_TYPE_INTER; summary->path.cost = route->path.cost; summary->nexthop[0] = route->nexthop[0]; /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; if (route->type == OSPF6_DEST_TYPE_ROUTER) { router_lsa = (struct ospf6_inter_router_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa); /* Fill Inter-Area-Router-LSA */ router_lsa->options[0] = route->path.options[0]; router_lsa->options[1] = route->path.options[1]; router_lsa->options[2] = route->path.options[2]; OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost); router_lsa->router_id = ADV_ROUTER_IN_PREFIX (&route->prefix); type = htons (OSPF6_LSTYPE_INTER_ROUTER); } else { prefix_lsa = (struct ospf6_inter_prefix_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa); /* Fill Inter-Area-Prefix-LSA */ OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost); prefix_lsa->prefix.prefix_length = route->prefix.prefixlen; prefix_lsa->prefix.prefix_options = route->path.prefix_options; /* set Prefix */ memcpy (p, &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); ospf6_prefix_apply_mask (&prefix_lsa->prefix); p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); type = htons (OSPF6_LSTYPE_INTER_PREFIX); } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = type; lsa_header->id = summary->path.origin.id; lsa_header->adv_router = area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, area->lsdb); lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, area); }
static u_char * ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; u_int32_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; int offsetlen; char a[16], b[16], c[16]; struct ospf6_area *oa; struct listnode *node; struct interface *iif; struct ospf6_interface *oi = NULL; struct list *ifslist; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; instid = ifindex = area_id = type = id = adv_router = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && (v->magic & OSPFv3WWASTABLE) && offsetlen != 3) return NULL; if (exact && (v->magic & OSPFv3WWAREATABLE) && offsetlen != 4) return NULL; if (exact && (v->magic & OSPFv3WWLINKTABLE) && offsetlen != 5) return NULL; if (v->magic & OSPFv3WWLINKTABLE) { /* Parse ifindex */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; } else if (v->magic & OSPFv3WWAREATABLE) { /* Parse area-id */ len = (offsetlen < 1 ? 0 : 1); if (len) area_id = htonl (*offset); offset += len; offsetlen -= len; } /* Parse type */ len = (offsetlen < 1 ? 0 : 1); if (len) type = htons (*offset); offset += len; offsetlen -= len; /* Parse Router-ID */ len = (offsetlen < 1 ? 0 : 1); if (len) adv_router = htonl (*offset); offset += len; offsetlen -= len; /* Parse LS-ID */ len = (offsetlen < 1 ? 0 : 1); if (len) id = htonl (*offset); offset += len; offsetlen -= len; if (exact) { if (v->magic & OSPFv3WWASTABLE) { lsa = ospf6_lsdb_lookup (type, id, adv_router, ospf6->lsdb); } else if (v->magic & OSPFv3WWAREATABLE) { oa = ospf6_area_lookup (area_id, ospf6); if (!oa) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); } else if (v->magic & OSPFv3WWLINKTABLE) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oi->lsdb); } } else { if (v->magic & OSPFv3WWASTABLE) { if (ospf6->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, ospf6->lsdb); } else if (v->magic & OSPFv3WWAREATABLE) for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { if (oa->area_id < area_id) continue; if (oa->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oa->lsdb); if (lsa) break; type = 0; id = 0; adv_router = 0; } else if (v->magic & OSPFv3WWLINKTABLE) { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, node, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, node, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; if (iif->ifindex < ifindex) continue; if (oi->instance_id < instid) continue; if (oi->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oi->lsdb); if (lsa) break; type = 0; id = 0; adv_router = 0; oi = NULL; } list_delete_all_node (ifslist); }