/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "thread.h" #include "linklist.h" #include "vty.h" #include "ospf6d.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_spf.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" void * ospf6_get_lsa_scope (u_int16_t type, struct ospf6_neighbor *from) { void *scope = NULL; if (from == NULL) return NULL; switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_LSA_SCOPE_AS: scope = (from)->ospf6_if->area->ospf6; break; case OSPF6_LSA_SCOPE_AREA: scope = (from)->ospf6_if->area; break; case OSPF6_LSA_SCOPE_LINKLOCAL: scope = (from)->ospf6_if; break; default: break; } return scope; } struct ospf6_lsdb * ospf6_get_scoped_lsdb (u_int16_t type, void *scope) { struct ospf6_lsdb *lsdb = NULL; if (scope == NULL) return NULL; switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_LSA_SCOPE_AS: lsdb = ((struct ospf6 *)(scope))->lsdb; break; case OSPF6_LSA_SCOPE_AREA: lsdb = ((struct ospf6_area *)(scope))->lsdb; break; case OSPF6_LSA_SCOPE_LINKLOCAL: lsdb = ((struct ospf6_interface *)(scope))->lsdb; break; default: break; } return lsdb; } void ospf6_decrement_onretrans (struct ospf6_lsa *lsa) { struct ospf6_lsdb *lsdb; struct ospf6_lsa *src; lsdb = ospf6_get_scoped_lsdb (lsa->header->type, lsa->scope); if (lsdb == NULL) { zlog_warn ("Decrement onretrans: no such scope: %s", lsa->name); return; } src = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb); if (src && src != lsa) src->onretrans--; if (src->onretrans < 0) zlog_warn ("internal error: onretrans"); } void ospf6_flood_clear (struct ospf6_lsa *lsa) { struct ospf6_neighbor *on; struct ospf6_interface *oi, *ospf6_if = NULL; struct ospf6_area *oa, *area = NULL; struct ospf6 *ospf6 = NULL; u_int16_t scope_type; list scoped_interfaces; struct ospf6_lsa *rxmt; listnode i, j; scoped_interfaces = list_new (); scope_type = OSPF6_LSA_SCOPE (lsa->header->type); if (scope_type == OSPF6_LSA_SCOPE_LINKLOCAL) { ospf6_if = (struct ospf6_interface *) lsa->scope; area = ospf6_if->area; ospf6 = area->ospf6; } else if (scope_type == OSPF6_LSA_SCOPE_AREA) { area = (struct ospf6_area *) lsa->scope; ospf6 = area->ospf6; } else if (scope_type == OSPF6_LSA_SCOPE_AS) { ospf6 = (struct ospf6 *) lsa->scope; } else { zlog_warn ("Can't decide LSA scope, quit ospf6_flood_clear ()"); return; } /* Collect eligible interfaces */ for (i = listhead (ospf6->area_list); i; nextnode (i)) { oa = (struct ospf6_area *) getdata (i); if (scope_type != OSPF6_LSA_SCOPE_AS && oa != area) continue; for (j = listhead (oa->if_list); j; nextnode (j)) { oi = (struct ospf6_interface *) getdata (j); if (scope_type != OSPF6_LSA_SCOPE_AS && scope_type != OSPF6_LSA_SCOPE_AREA && oi != ospf6_if) continue; listnode_add (scoped_interfaces, oi); } } for (i = listhead (scoped_interfaces); i; nextnode (i)) { oi = (struct ospf6_interface *) getdata (i); for (j = listhead (oi->neighbor_list); j; nextnode (j)) { on = (struct ospf6_neighbor *) getdata (j); rxmt = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, on->retrans_list); if (rxmt && ! ospf6_lsa_compare (rxmt, lsa)) { if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info ("Remove %s from retrans_list of %s", rxmt->name, on->name); ospf6_decrement_onretrans (rxmt); ospf6_lsdb_remove (rxmt, on->retrans_list); } } } list_delete (scoped_interfaces); } /* RFC2328 section 13.2 Installing LSAs in the database */ void ospf6_install_lsa (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *old; if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info ("Install LSA: %s", lsa->name); /* Remove the old instance from all neighbors' Link state retransmission list (RFC2328 13.2 last paragraph) */ old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb); if (old) ospf6_flood_clear (old); /* actually install */ gettimeofday (&lsa->installed, (struct timezone *) NULL); ospf6_lsdb_add (lsa, lsdb); return; } /* RFC2328 section 13.3 Next step in the flooding procedure */ void ospf6_flood_lsa (struct ospf6_lsa *lsa, struct ospf6_neighbor *from) { struct ospf6 *scope_as = NULL; struct ospf6_area *oa, *scope_area = NULL; struct ospf6_interface *oi, *scope_linklocal = NULL; struct ospf6_neighbor *on; list eligible_interfaces; listnode i, j; u_int16_t scope_type; struct ospf6_lsa *req; int retrans_added = 0; scope_type = OSPF6_LSA_SCOPE (lsa->header->type); switch (scope_type) { case OSPF6_LSA_SCOPE_AS: scope_as = (struct ospf6 *) lsa->scope; break; case OSPF6_LSA_SCOPE_AREA: scope_as = ((struct ospf6_area *) lsa->scope)->ospf6; scope_area = (struct ospf6_area *) lsa->scope; break; case OSPF6_LSA_SCOPE_LINKLOCAL: scope_as = ((struct ospf6_interface *) lsa->scope)->area->ospf6; scope_area = ((struct ospf6_interface *) lsa->scope)->area; scope_linklocal = (struct ospf6_interface *) lsa->scope; break; default: if (IS_OSPF6_DEBUG_LSA (SEND)) zlog_info ("Can't decide LSA scope"); return; } if (IS_OSPF6_DEBUG_LSA (SEND)) zlog_info ("Flood %s", lsa->name); /* Collect eligible interfaces */ eligible_interfaces = list_new (); for (i = listhead (scope_as->area_list); i; nextnode (i)) { oa = (struct ospf6_area *) getdata (i); if (scope_type != OSPF6_LSA_SCOPE_AS && oa != scope_area) continue; for (j = listhead (oa->if_list); j; nextnode (j)) { oi = (struct ospf6_interface *) getdata (j); if (scope_type != OSPF6_LSA_SCOPE_AS && scope_type != OSPF6_LSA_SCOPE_AREA && oi != scope_linklocal) continue; listnode_add (eligible_interfaces, oi); } } /* For each eligible interface: */ for (i = listhead (eligible_interfaces); i; nextnode (i)) { oi = (struct ospf6_interface *) getdata (i); /* (1) For each neighbor */ for (j = listhead (oi->neighbor_list); j; nextnode (j)) { on = (struct ospf6_neighbor *) getdata (j); /* (a) if neighbor state < Exchange, examin next */ if (on->state < OSPF6_NEIGHBOR_EXCHANGE) continue; /* (b) if neighbor not yet Full, check request-list */ if (on->state != OSPF6_NEIGHBOR_FULL) { req = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, on->request_list); if (req) { /* If new LSA less recent, examin next neighbor */ if (ospf6_lsa_compare (lsa, req) > 0) continue; /* If the same instance, delete from request-list and examin next neighbor */ if (ospf6_lsa_compare (lsa, req) == 0) { if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info ("Remove %s from request-list of %s: " "the same instance", req->name, on->name); 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_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info ("Remove %s from request-list of %s: " "newer instance", req->name, on->name); 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) continue; /* (d) add retrans-list, schedule retransmission */ if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to retrans-list of %s", lsa->name, on->name); lsa->onretrans++; ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); if (on->thread_send_lsupdate == NULL) on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, on->ospf6_if->rxmt_interval); retrans_added++; } /* (2) examin next interface if not added to retrans-list */ if (retrans_added == 0) continue; /* (3) If the new LSA was received on this interface, and it was from DR or BDR, examin next interface */ if (from && from->ospf6_if == oi && (from->router_id == oi->drouter || from->router_id == oi->bdrouter)) continue; /* (4) If the new LSA was received on this interface, and the interface state is BDR, examin next interface */ if (from && from->ospf6_if == oi && oi->state == OSPF6_INTERFACE_BDR) continue; /* (5) flood the LSA out the interface. */ if (if_is_broadcast (oi->interface)) { if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsupdate_list of %s", lsa->name, oi->interface->name); ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list); if (oi->thread_send_lsupdate == NULL) oi->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); } else { for (j = listhead (oi->neighbor_list); j; nextnode (j)) { on = (struct ospf6_neighbor *) getdata (j); THREAD_OFF (on->thread_send_lsupdate); on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } } } list_delete (eligible_interfaces); } /* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */ static void ospf6_acknowledge_lsa_bdrouter (struct ospf6_lsa *lsa, int ismore_recent, struct ospf6_neighbor *from) { struct ospf6_interface *oi; assert (from && from->ospf6_if); oi = from->ospf6_if; /* LSA has been flood back out receiving interface. No acknowledgement sent. */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" BDR, FloodBack, No acknowledgement."); return; } /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgement sent if advertisement received from Designated Router, otherwide do nothing. */ if (ismore_recent < 0) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" BDR, Not FloodBack, MoreRecent, "); if (oi->drouter == from->router_id) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" From DR, Delayed acknowledgement."); /* Delayed acknowledgement */ if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsack_list of %s", lsa->name, oi->interface->name); ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); if (oi->thread_send_lsack == NULL) oi->thread_send_lsack = thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); } else { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" Not From DR, No acknowledgement."); } return; } /* LSA is a duplicate, and was treated as an implied acknowledgement. Delayed acknowledgement sent if advertisement received from Designated Router, otherwise do nothing */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" BDR, Duplicate, ImpliedAck, "); if (oi->drouter == from->router_id) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" From DR, Delayed acknowledgement."); /* Delayed acknowledgement */ if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsack_list of %s", lsa->name, oi->interface->name); ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); if (oi->thread_send_lsack == NULL) oi->thread_send_lsack = thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); } else { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" Not From DR, No acknowledgement."); } return; } /* LSA is a duplicate, and was not treated as an implied acknowledgement. Direct acknowledgement sent */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && ! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" BDR, Duplicate, Not ImpliedAck, Direct acknowledgement."); if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsack_list of %s", lsa->name, from->name); ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list); if (from->thread_send_lsack == NULL) from->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); return; } /* LSA's LS age is equal to Maxage, and there is no current instance of the LSA in the link state database, and none of router's neighbors are in states Exchange or Loading */ /* Direct acknowledgement sent, but this case is handled in early of ospf6_receive_lsa () */ } static void ospf6_acknowledge_lsa_allother (struct ospf6_lsa *lsa, int ismore_recent, struct ospf6_neighbor *from) { struct ospf6_interface *oi; assert (from && from->ospf6_if); oi = from->ospf6_if; /* LSA has been flood back out receiving interface. No acknowledgement sent. */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" AllOther, FloodBack, No acknowledgement."); return; } /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgement sent. */ if (ismore_recent < 0) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" AllOther, Not FloodBack, Delayed acknowledgement."); /* Delayed acknowledgement */ if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsack_list of %s", lsa->name, oi->interface->name); ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); if (oi->thread_send_lsack == NULL) oi->thread_send_lsack = thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); return; } /* LSA is a duplicate, and was treated as an implied acknowledgement. No acknowledgement sent. */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" AllOther, Duplicate, ImpliedAck, No acknowledgement."); return; } /* LSA is a duplicate, and was not treated as an implied acknowledgement. Direct acknowledgement sent */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && ! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info (" AllOther, Duplicate, Not ImpliedAck, Direct acknowledgement."); if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsack_list of %s", lsa->name, from->name); ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list); if (from->thread_send_lsack == NULL) from->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); return; } /* LSA's LS age is equal to Maxage, and there is no current instance of the LSA in the link state database, and none of router's neighbors are in states Exchange or Loading */ /* Direct acknowledgement sent, but this case is handled in early of ospf6_receive_lsa () */ } void ospf6_acknowledge_lsa (struct ospf6_lsa *lsa, int ismore_recent, struct ospf6_neighbor *from) { struct ospf6_interface *oi; assert (from && from->ospf6_if); oi = from->ospf6_if; if (oi->state == OSPF6_INTERFACE_BDR) ospf6_acknowledge_lsa_bdrouter (lsa, ismore_recent, from); else ospf6_acknowledge_lsa_allother (lsa, ismore_recent, from); } /* RFC2328 section 13 (4): if MaxAge LSA and if we have no instance, and no neighbor is in states Exchange or Loading returns 1 if match this case, else returns 0 */ static int ospf6_is_maxage_lsa_drop (struct ospf6_lsa *lsa, struct ospf6_neighbor *from) { struct ospf6_lsdb *lsdb = NULL; struct ospf6_neighbor *on; struct ospf6_interface *oi, *ospf6_if = NULL; struct ospf6_area *oa, *area = NULL; struct ospf6 *ospf6 = NULL; u_int16_t scope_type; list scoped_interfaces; listnode i, j; int count = 0; if (! OSPF6_LSA_IS_MAXAGE (lsa)) return 0; lsdb = ospf6_get_scoped_lsdb (lsa->header->type, lsa->scope); if (lsdb == NULL) { zlog_info ("Can't decide scoped LSDB"); return 0; } if (ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb)) return 0; scoped_interfaces = list_new (); scope_type = OSPF6_LSA_SCOPE (lsa->header->type); if (scope_type == OSPF6_LSA_SCOPE_LINKLOCAL) { ospf6_if = (struct ospf6_interface *) lsa->scope; area = ospf6_if->area; ospf6 = area->ospf6; } else if (scope_type == OSPF6_LSA_SCOPE_AREA) { area = (struct ospf6_area *) lsa->scope; ospf6 = area->ospf6; } else if (scope_type == OSPF6_LSA_SCOPE_AS) { ospf6 = (struct ospf6 *) lsa->scope; } else { zlog_info ("Can't decide LSA scope"); return 0; } /* Collect eligible interfaces */ for (i = listhead (ospf6->area_list); i; nextnode (i)) { oa = (struct ospf6_area *) getdata (i); if (scope_type != OSPF6_LSA_SCOPE_AS && oa != area) continue; for (j = listhead (oa->if_list); j; nextnode (j)) { oi = (struct ospf6_interface *) getdata (j); if (scope_type != OSPF6_LSA_SCOPE_AS && scope_type != OSPF6_LSA_SCOPE_AREA && oi != ospf6_if) continue; listnode_add (scoped_interfaces, oi); } } for (i = listhead (scoped_interfaces); i; nextnode (i)) { oi = (struct ospf6_interface *) getdata (i); for (j = listhead (oi->neighbor_list); j; nextnode (j)) { on = (struct ospf6_neighbor *) getdata (j); if (on->state == OSPF6_NEIGHBOR_EXCHANGE || on->state == OSPF6_NEIGHBOR_LOADING) count ++; } } list_delete (scoped_interfaces); if (count == 0) return 1; return 0; } /* RFC2328 section 13 The Flooding Procedure */ void ospf6_receive_lsa (struct ospf6_lsa_header *lsa_header, struct ospf6_neighbor *from) { struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL; int ismore_recent; unsigned short cksum; struct ospf6_lsdb *lsdb = NULL; ismore_recent = 1; /* make lsa structure for received lsa */ new = ospf6_lsa_create (lsa_header); if (IS_OSPF6_DEBUG_LSA (RECV)) { zlog_info ("LSA Receive from %s", from->name); ospf6_lsa_header_print (new); } new->scope = ospf6_get_lsa_scope (new->header->type, from); if (new->scope == NULL) { zlog_warn ("Can't decide LSA scope, ignore"); ospf6_lsa_delete (new); return; } /* (1) LSA Checksum */ cksum = ntohs (new->header->checksum); if (ntohs (ospf6_lsa_checksum (new->header)) != cksum) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("Wrong LSA Checksum"); ospf6_lsa_delete (new); return; } /* (3) Ebit Missmatch: AS-External-LSA */ if (ntohs (new->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && ospf6_area_is_stub (from->ospf6_if->area)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("AS-External-LSA in stub area"); ospf6_lsa_delete (new); return; } /* (4) if MaxAge LSA and if we have no instance, and no neighbor is in states Exchange or Loading */ if (ospf6_is_maxage_lsa_drop (new, from)) { /* log */ if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("Drop MaxAge LSA with Direct acknowledgement."); /* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */ if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add %s to lsack_list of %s", new->name, from->name); ospf6_lsdb_add (new, from->lsack_list); if (from->thread_send_lsack == NULL) from->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); /* b) Discard */ /* "new" LSA will be discarded just after the LSAck sent */ return; } /* (5) */ /* lookup the same database copy in lsdb */ lsdb = ospf6_get_scoped_lsdb (new->header->type, new->scope); if (lsdb == NULL) { zlog_warn ("Can't decide scoped LSDB, ignore"); ospf6_lsa_delete (new); return; } old = ospf6_lsdb_lookup (new->header->type, new->header->id, new->header->adv_router, lsdb); if (old) { ismore_recent = ospf6_lsa_compare (new, old); if (ntohl (new->header->seqnum) == ntohl (old->header->seqnum)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("Duplicated LSA"); SET_FLAG (new->flag, OSPF6_LSA_DUPLICATE); } } /* if no database copy or received is more recent */ if (old == NULL || ismore_recent < 0) { /* in case we have no database copy */ ismore_recent = -1; /* (a) MinLSArrival check */ if (old) { struct timeval now, res; gettimeofday (&now, (struct timezone *) NULL); timersub (&now, &old->installed, &res); if (res.tv_sec < MIN_LS_ARRIVAL) { if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (TIMER)) zlog_info ("LSA can't be updated within MinLSArrival"); ospf6_lsa_delete (new); return; /* examin next lsa */ } } /* (b) immediately flood and (c) remove from all retrans-list */ ospf6_flood_lsa (new, from); /* (d), installing lsdb, which may cause routing table calculation (replacing database copy) */ ospf6_install_lsa (new, lsdb); /* (e) possibly acknowledge */ ospf6_acknowledge_lsa (new, ismore_recent, from); /* (f) */ /* Self Originated LSA, section 13.4 */ if (new->header->adv_router == from->ospf6_if->area->ospf6->router_id && (! old || ismore_recent < 0)) { /* We have to make a new instance of the LSA or have to flush this LSA. */ if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("New instance of the self-originated LSA"); SET_FLAG (new->flag, OSPF6_LSA_REFRESH); ospf6_lsa_re_originate (new); } return; } /* (6) if there is instance on sending neighbor's request list */ if (ospf6_lsdb_lookup (new->header->type, new->header->id, new->header->adv_router, from->request_list)) { /* if no database copy, should go above state (5) */ assert (old); if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("LSA is not newer and on request-list of sending neighbor"); /* BadLSReq */ thread_add_event (master, bad_lsreq, from, 0); ospf6_lsa_delete (new); return; } /* (7) if neither one is more recent */ if (ismore_recent == 0) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("The same instance as database copy"); /* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack */ rem = ospf6_lsdb_lookup (new->header->type, new->header->id, new->header->adv_router, from->retrans_list); if (rem) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("Treat as an Implied acknowledgement"); SET_FLAG (new->flag, OSPF6_LSA_IMPLIEDACK); if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info ("Remove %s from retrans_list of %s", rem->name, from->name); ospf6_decrement_onretrans (rem); ospf6_lsdb_remove (rem, from->retrans_list); } /* (b) possibly acknowledge */ ospf6_acknowledge_lsa (new, ismore_recent, from); ospf6_lsa_delete (new); return; } /* (8) previous database copy is more recent */ { assert (old); /* If database copy is in 'Seqnumber Wrapping', simply discard the received LSA */ if (OSPF6_LSA_IS_MAXAGE (old) && old->header->seqnum == htonl (MAX_SEQUENCE_NUMBER)) { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("Database copy is in Seqnumber Wrapping"); ospf6_lsa_delete (new); return; } /* Otherwise, Send database copy of this LSA to this neighbor */ { if (IS_OSPF6_DEBUG_LSA (RECV)) zlog_info ("Database is more recent, send back directly"); /* XXX, MinLSArrival check !? RFC 2328 13 (8) */ if (IS_OSPF6_DEBUG_LSA (DATABASE)) zlog_info (" Add copy of %s to lsupdate_list of %s", old->name, from->name); ospf6_lsdb_add (ospf6_lsa_copy (old), from->lsupdate_list); if (from->thread_send_lsupdate == NULL) from->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, from, 0); ospf6_lsa_delete (new); return; } return; } }