1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051 |
- /*
- * 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 <zebra.h>
- #include "log.h"
- #include "thread.h"
- #include "linklist.h"
- #include "vty.h"
- #include "command.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"
- #include "ospf6_flood.h"
- unsigned char conf_debug_ospf6_flooding;
- struct ospf6_lsdb *
- ospf6_get_scoped_lsdb (struct ospf6_lsa *lsa)
- {
- struct ospf6_lsdb *lsdb = NULL;
- switch (OSPF6_LSA_SCOPE (lsa->header->type))
- {
- case OSPF6_SCOPE_LINKLOCAL:
- lsdb = OSPF6_INTERFACE (lsa->lsdb->data)->lsdb;
- break;
- case OSPF6_SCOPE_AREA:
- lsdb = OSPF6_AREA (lsa->lsdb->data)->lsdb;
- break;
- case OSPF6_SCOPE_AS:
- lsdb = OSPF6_PROCESS (lsa->lsdb->data)->lsdb;
- break;
- default:
- assert (0);
- break;
- }
- return lsdb;
- }
- struct ospf6_lsdb *
- ospf6_get_scoped_lsdb_self (struct ospf6_lsa *lsa)
- {
- struct ospf6_lsdb *lsdb_self = NULL;
- switch (OSPF6_LSA_SCOPE (lsa->header->type))
- {
- case OSPF6_SCOPE_LINKLOCAL:
- lsdb_self = OSPF6_INTERFACE (lsa->lsdb->data)->lsdb_self;
- break;
- case OSPF6_SCOPE_AREA:
- lsdb_self = OSPF6_AREA (lsa->lsdb->data)->lsdb_self;
- break;
- case OSPF6_SCOPE_AS:
- lsdb_self = OSPF6_PROCESS (lsa->lsdb->data)->lsdb_self;
- break;
- default:
- assert (0);
- break;
- }
- return lsdb_self;
- }
- void
- ospf6_lsa_originate (struct ospf6_lsa *lsa)
- {
- struct ospf6_lsa *old;
- struct ospf6_lsdb *lsdb_self;
- /* find previous LSA */
- old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
- lsa->header->adv_router, lsa->lsdb);
- /* if the new LSA does not differ from previous,
- suppress this update of the LSA */
- if (old && ! OSPF6_LSA_IS_DIFFER (lsa, old))
- {
- if (IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type))
- zlog_debug ("Suppress updating LSA: %s", lsa->name);
- ospf6_lsa_delete (lsa);
- return;
- }
- /* store it in the LSDB for self-originated LSAs */
- lsdb_self = ospf6_get_scoped_lsdb_self (lsa);
- ospf6_lsdb_add (ospf6_lsa_copy (lsa), lsdb_self);
- lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
- OSPF_LS_REFRESH_TIME);
- if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) ||
- IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type))
- {
- zlog_debug ("LSA Originate:");
- ospf6_lsa_header_print (lsa);
- }
- ospf6_install_lsa (lsa);
- ospf6_flood (NULL, lsa);
- }
- void
- ospf6_lsa_originate_process (struct ospf6_lsa *lsa,
- struct ospf6 *process)
- {
- lsa->lsdb = process->lsdb;
- ospf6_lsa_originate (lsa);
- }
- void
- ospf6_lsa_originate_area (struct ospf6_lsa *lsa,
- struct ospf6_area *oa)
- {
- lsa->lsdb = oa->lsdb;
- ospf6_lsa_originate (lsa);
- }
- void
- ospf6_lsa_originate_interface (struct ospf6_lsa *lsa,
- struct ospf6_interface *oi)
- {
- lsa->lsdb = oi->lsdb;
- ospf6_lsa_originate (lsa);
- }
- void
- ospf6_lsa_purge (struct ospf6_lsa *lsa)
- {
- struct ospf6_lsa *self;
- struct ospf6_lsdb *lsdb_self;
- /* remove it from the LSDB for self-originated LSAs */
- lsdb_self = ospf6_get_scoped_lsdb_self (lsa);
- self = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
- lsa->header->adv_router, lsdb_self);
- if (self)
- {
- THREAD_OFF (self->expire);
- THREAD_OFF (self->refresh);
- ospf6_lsdb_remove (self, lsdb_self);
- }
- ospf6_lsa_premature_aging (lsa);
- }
- void
- ospf6_increment_retrans_count (struct ospf6_lsa *lsa)
- {
- /* The LSA must be the original one (see the description
- in ospf6_decrement_retrans_count () below) */
- lsa->retrans_count++;
- }
- void
- ospf6_decrement_retrans_count (struct ospf6_lsa *lsa)
- {
- struct ospf6_lsdb *lsdb;
- struct ospf6_lsa *orig;
- /* The LSA must be on the retrans-list of a neighbor. It means
- the "lsa" is a copied one, and we have to decrement the
- retransmission count of the original one (instead of this "lsa"'s).
- In order to find the original LSA, first we have to find
- appropriate LSDB that have the original LSA. */
- lsdb = ospf6_get_scoped_lsdb (lsa);
- /* Find the original LSA of which the retrans_count should be decremented */
- orig = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
- lsa->header->adv_router, lsdb);
- if (orig)
- {
- orig->retrans_count--;
- assert (orig->retrans_count >= 0);
- }
- }
- /* RFC2328 section 13.2 Installing LSAs in the database */
- void
- ospf6_install_lsa (struct ospf6_lsa *lsa)
- {
- struct timeval now;
- struct ospf6_lsa *old;
- if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) ||
- IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type))
- zlog_debug ("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, lsa->lsdb);
- if (old)
- {
- THREAD_OFF (old->expire);
- THREAD_OFF (old->refresh);
- ospf6_flood_clear (old);
- }
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
- if (! OSPF6_LSA_IS_MAXAGE (lsa))
- lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
- OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec);
- else
- lsa->expire = NULL;
- if (OSPF6_LSA_IS_SEQWRAP(lsa) &&
- ! (CHECK_FLAG(lsa->flag,OSPF6_LSA_SEQWRAPPED) &&
- lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)))
- {
- if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type))
- zlog_debug("lsa install wrapping: sequence 0x%x",
- ntohl(lsa->header->seqnum));
- SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
- /* in lieu of premature_aging, since we do not want to recreate this lsa
- * and/or mess with timers etc, we just want to wrap the sequence number
- * and reflood the lsa before continuing.
- * NOTE: Flood needs to be called right after this function call, by the
- * caller
- */
- lsa->header->seqnum = htonl (OSPF_MAX_SEQUENCE_NUMBER);
- lsa->header->age = htons (OSPF_LSA_MAXAGE);
- ospf6_lsa_checksum (lsa->header);
- }
- /* actually install */
- lsa->installed = now;
- ospf6_lsdb_add (lsa, lsa->lsdb);
- return;
- }
- /* RFC2740 section 3.5.2. Sending Link State Update packets */
- /* RFC2328 section 13.3 Next step in the flooding procedure */
- static void
- ospf6_flood_interface (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;
- 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 */
- if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
- {
- if (is_debug)
- zlog_debug ("Neighbor state less than ExChange, next neighbor");
- continue;
- }
- /* (b) if neighbor not yet Full, check request-list */
- if (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 older, 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");
- if (req == on->last_ls_req)
- {
- ospf6_lsa_unlock (req);
- on->last_ls_req = NULL;
- }
- ospf6_lsdb_remove (req, on->request_list);
- ospf6_check_nbr_loading (on);
- 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");
- if (req == on->last_ls_req)
- {
- ospf6_lsa_unlock (req);
- on->last_ls_req = NULL;
- }
- ospf6_lsdb_remove (req, on->request_list);
- ospf6_check_nbr_loading (on);
- /* fall through */
- }
- }
- }
- /* (c) If the new LSA was received from this neighbor,
- examin next neighbor */
- if (from == on)
- {
- if (is_debug)
- zlog_debug ("Received is from the neighbor, next neighbor");
- continue;
- }
- /* (d) add retrans-list, schedule retransmission */
- if (is_debug)
- zlog_debug ("Add retrans-list of this neighbor");
- ospf6_increment_retrans_count (lsa);
- ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list);
- if (on->thread_send_lsupdate == NULL)
- on->thread_send_lsupdate =
- thread_add_timer (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)
- {
- if (is_debug)
- zlog_debug ("No retransmission scheduled, next interface");
- return;
- }
- /* (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))
- {
- if (is_debug)
- zlog_debug ("Received is from the I/F's DR or BDR, next interface");
- return;
- }
- /* (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)
- {
- if (oi->state == OSPF6_INTERFACE_BDR)
- {
- if (is_debug)
- zlog_debug ("Received is from the I/F, itself BDR, next interface");
- return;
- }
- SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK);
- }
- /* (5) flood the LSA out the interface. */
- if (is_debug)
- zlog_debug ("Schedule flooding for the interface");
- if ((oi->type == OSPF_IFTYPE_BROADCAST) ||
- (oi->type == OSPF_IFTYPE_POINTOPOINT))
- {
- 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
- {
- /* reschedule retransmissions to all neighbors */
- for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on))
- {
- THREAD_OFF (on->thread_send_lsupdate);
- on->thread_send_lsupdate =
- thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0);
- }
- }
- }
- static void
- ospf6_flood_area (struct ospf6_neighbor *from,
- struct ospf6_lsa *lsa, struct ospf6_area *oa)
- {
- struct listnode *node, *nnode;
- struct ospf6_interface *oi;
- for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
- {
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL &&
- oi != OSPF6_INTERFACE (lsa->lsdb->data))
- continue;
- #if 0
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS &&
- ospf6_is_interface_virtual_link (oi))
- continue;
- #endif/*0*/
- ospf6_flood_interface (from, lsa, oi);
- }
- }
- static void
- ospf6_flood_process (struct ospf6_neighbor *from,
- struct ospf6_lsa *lsa, struct ospf6 *process)
- {
- struct listnode *node, *nnode;
- struct ospf6_area *oa;
- for (ALL_LIST_ELEMENTS (process->area_list, node, nnode, oa))
- {
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AREA &&
- oa != OSPF6_AREA (lsa->lsdb->data))
- continue;
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL &&
- oa != OSPF6_INTERFACE (lsa->lsdb->data)->area)
- continue;
- if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL &&
- IS_AREA_STUB (oa))
- continue;
- ospf6_flood_area (from, lsa, oa);
- }
- }
- void
- ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa)
- {
- ospf6_flood_process (from, lsa, ospf6);
- }
- static void
- ospf6_flood_clear_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi)
- {
- struct listnode *node, *nnode;
- struct ospf6_neighbor *on;
- struct ospf6_lsa *rem;
- for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on))
- {
- rem = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
- lsa->header->adv_router, on->retrans_list);
- if (rem && ! ospf6_lsa_compare (rem, lsa))
- {
- if (IS_OSPF6_DEBUG_FLOODING ||
- IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type))
- zlog_debug ("Remove %s from retrans_list of %s",
- rem->name, on->name);
- ospf6_decrement_retrans_count (rem);
- ospf6_lsdb_remove (rem, on->retrans_list);
- }
- }
- }
- static void
- ospf6_flood_clear_area (struct ospf6_lsa *lsa, struct ospf6_area *oa)
- {
- struct listnode *node, *nnode;
- struct ospf6_interface *oi;
- for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
- {
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL &&
- oi != OSPF6_INTERFACE (lsa->lsdb->data))
- continue;
- #if 0
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS &&
- ospf6_is_interface_virtual_link (oi))
- continue;
- #endif/*0*/
- ospf6_flood_clear_interface (lsa, oi);
- }
- }
- static void
- ospf6_flood_clear_process (struct ospf6_lsa *lsa, struct ospf6 *process)
- {
- struct listnode *node, *nnode;
- struct ospf6_area *oa;
- for (ALL_LIST_ELEMENTS (process->area_list, node, nnode, oa))
- {
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AREA &&
- oa != OSPF6_AREA (lsa->lsdb->data))
- continue;
- if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL &&
- oa != OSPF6_INTERFACE (lsa->lsdb->data)->area)
- continue;
- if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL &&
- IS_AREA_STUB (oa))
- continue;
- ospf6_flood_clear_area (lsa, oa);
- }
- }
- void
- ospf6_flood_clear (struct ospf6_lsa *lsa)
- {
- ospf6_flood_clear_process (lsa, ospf6);
- }
- /* 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;
- int is_debug = 0;
- if (IS_OSPF6_DEBUG_FLOODING ||
- IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type))
- is_debug++;
- assert (from && from->ospf6_if);
- oi = from->ospf6_if;
- /* 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 (oi->drouter == from->router_id)
- {
- if (is_debug)
- zlog_debug ("Delayed acknowledgement (BDR & MoreRecent & from DR)");
- /* Delayed acknowledgement */
- 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_debug)
- zlog_debug ("No acknowledgement (BDR & MoreRecent & ! from DR)");
- }
- 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 (oi->drouter == from->router_id)
- {
- if (is_debug)
- zlog_debug ("Delayed acknowledgement (BDR & Duplicate & ImpliedAck & from DR)");
- /* Delayed acknowledgement */
- 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_debug)
- zlog_debug ("No acknowledgement (BDR & Duplicate & ImpliedAck & ! from DR)");
- }
- 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_debug)
- zlog_debug ("Direct acknowledgement (BDR & Duplicate)");
- 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;
- int is_debug = 0;
- if (IS_OSPF6_DEBUG_FLOODING ||
- IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type))
- is_debug++;
- 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_debug)
- zlog_debug ("No acknowledgement (AllOther & FloodBack)");
- 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_debug)
- zlog_debug ("Delayed acknowledgement (AllOther & MoreRecent)");
- /* Delayed acknowledgement */
- 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_debug)
- zlog_debug ("No acknowledgement (AllOther & Duplicate & ImpliedAck)");
- 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_debug)
- zlog_debug ("Direct acknowledgement (AllOther & Duplicate)");
- 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 (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_neighbor *on;
- struct ospf6_interface *oi;
- struct ospf6_area *oa;
- struct ospf6 *process = NULL;
- struct listnode *i, *j, *k;
- int count = 0;
- if (! OSPF6_LSA_IS_MAXAGE (lsa))
- return 0;
- if (ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
- lsa->header->adv_router, lsa->lsdb))
- return 0;
- process = from->ospf6_if->area->ospf6;
- for (ALL_LIST_ELEMENTS_RO (process->area_list, i, oa))
- for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi))
- for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on))
- if (on->state == OSPF6_NEIGHBOR_EXCHANGE ||
- on->state == OSPF6_NEIGHBOR_LOADING)
- count++;
- if (count == 0)
- return 1;
- return 0;
- }
- /* RFC2328 section 13 The Flooding Procedure */
- void
- ospf6_receive_lsa (struct ospf6_neighbor *from,
- struct ospf6_lsa_header *lsa_header)
- {
- struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL;
- int ismore_recent;
- int is_debug = 0;
- ismore_recent = 1;
- assert (from);
- /* make lsa structure for received lsa */
- new = ospf6_lsa_create (lsa_header);
- if (IS_OSPF6_DEBUG_FLOODING ||
- IS_OSPF6_DEBUG_FLOOD_TYPE (new->header->type))
- {
- is_debug++;
- zlog_debug ("LSA Receive from %s", from->name);
- ospf6_lsa_header_print (new);
- }
- /* (1) LSA Checksum */
- if (! ospf6_lsa_checksum_valid (new->header))
- {
- if (is_debug)
- zlog_debug ("Wrong LSA Checksum, discard");
- ospf6_lsa_delete (new);
- return;
- }
- /* (2) Examine the LSA's LS type.
- RFC2470 3.5.1. Receiving Link State Update packets */
- if (IS_AREA_STUB (from->ospf6_if->area) &&
- OSPF6_LSA_SCOPE (new->header->type) == OSPF6_SCOPE_AS)
- {
- if (is_debug)
- zlog_debug ("AS-External-LSA (or AS-scope LSA) in stub area, discard");
- ospf6_lsa_delete (new);
- return;
- }
- /* (3) LSA which have reserved scope is discarded
- RFC2470 3.5.1. Receiving Link State Update packets */
- /* Flooding scope check. LSAs with unknown scope are discarded here.
- Set appropriate LSDB for the LSA */
- switch (OSPF6_LSA_SCOPE (new->header->type))
- {
- case OSPF6_SCOPE_LINKLOCAL:
- new->lsdb = from->ospf6_if->lsdb;
- break;
- case OSPF6_SCOPE_AREA:
- new->lsdb = from->ospf6_if->area->lsdb;
- break;
- case OSPF6_SCOPE_AS:
- new->lsdb = from->ospf6_if->area->ospf6->lsdb;
- break;
- default:
- if (is_debug)
- zlog_debug ("LSA has reserved scope, discard");
- 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_debug)
- zlog_debug ("Drop MaxAge LSA with direct acknowledgement.");
- /* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */
- ospf6_lsdb_add (ospf6_lsa_copy (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 */
- ospf6_lsa_delete (new);
- return;
- }
- /* (5) */
- /* lookup the same database copy in lsdb */
- old = ospf6_lsdb_lookup (new->header->type, new->header->id,
- new->header->adv_router, new->lsdb);
- if (old)
- {
- ismore_recent = ospf6_lsa_compare (new, old);
- if (ntohl (new->header->seqnum) == ntohl (old->header->seqnum))
- {
- if (is_debug)
- zlog_debug ("Received is 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;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
- timersub (&now, &old->installed, &res);
- if (res.tv_sec < (OSPF_MIN_LS_ARRIVAL / 1000))
- {
- if (is_debug)
- zlog_debug ("LSA can't be updated within MinLSArrival, discard");
- ospf6_lsa_delete (new);
- return; /* examin next lsa */
- }
- }
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received);
- if (is_debug)
- zlog_debug ("Install, Flood, Possibly acknowledge the received LSA");
- /* Remove older copies of this LSA from retx lists */
- if (old)
- ospf6_flood_clear (old);
- /* (b) immediately flood and (c) remove from all retrans-list */
- /* Prevent self-originated LSA to be flooded. this is to make
- reoriginated instance of the LSA not to be rejected by other routers
- due to MinLSArrival. */
- if (new->header->adv_router != from->ospf6_if->area->ospf6->router_id)
- ospf6_flood (from, new);
- /* (d), installing lsdb, which may cause routing
- table calculation (replacing database copy) */
- ospf6_install_lsa (new);
- /* (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)
- {
- /* Self-originated LSA (newer than ours) is received from
- another router. We have to make a new instance of the LSA
- or have to flush this LSA. */
- if (is_debug)
- {
- zlog_debug ("Newer instance of the self-originated LSA");
- zlog_debug ("Schedule reorigination");
- }
- new->refresh = thread_add_event (master, ospf6_lsa_refresh, new, 0);
- }
- 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_debug)
- {
- zlog_debug ("Received is not newer, on the neighbor's request-list");
- zlog_debug ("BadLSReq, discard the received LSA");
- }
- /* 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_debug)
- zlog_debug ("The same instance as database copy (neither recent)");
- /* (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_debug)
- {
- zlog_debug ("It is on the neighbor's retrans-list.");
- zlog_debug ("Treat as an Implied acknowledgement");
- }
- SET_FLAG (new->flag, OSPF6_LSA_IMPLIEDACK);
- ospf6_decrement_retrans_count (rem);
- ospf6_lsdb_remove (rem, from->retrans_list);
- }
- if (is_debug)
- zlog_debug ("Possibly acknowledge and then discard");
- /* (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 (OSPF_MAX_SEQUENCE_NUMBER))
- {
- if (is_debug)
- {
- zlog_debug ("The LSA is in Seqnumber Wrapping");
- zlog_debug ("MaxAge & MaxSeqNum, discard");
- }
- ospf6_lsa_delete (new);
- return;
- }
- /* Otherwise, Send database copy of this LSA to this neighbor */
- {
- if (is_debug)
- {
- zlog_debug ("Database copy is more recent.");
- zlog_debug ("Send back directly and then discard");
- }
- /* XXX, MinLSArrival check !? RFC 2328 13 (8) */
- 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;
- }
- }
- DEFUN (debug_ospf6_flooding,
- debug_ospf6_flooding_cmd,
- "debug ospf6 flooding",
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 flooding function\n"
- )
- {
- OSPF6_DEBUG_FLOODING_ON ();
- return CMD_SUCCESS;
- }
- DEFUN (no_debug_ospf6_flooding,
- no_debug_ospf6_flooding_cmd,
- "no debug ospf6 flooding",
- NO_STR
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 flooding function\n"
- )
- {
- OSPF6_DEBUG_FLOODING_OFF ();
- return CMD_SUCCESS;
- }
- int
- config_write_ospf6_debug_flood (struct vty *vty)
- {
- if (IS_OSPF6_DEBUG_FLOODING)
- vty_out (vty, "debug ospf6 flooding%s", VNL);
- return 0;
- }
- void
- install_element_ospf6_debug_flood (void)
- {
- install_element (ENABLE_NODE, &debug_ospf6_flooding_cmd);
- install_element (ENABLE_NODE, &no_debug_ospf6_flooding_cmd);
- install_element (CONFIG_NODE, &debug_ospf6_flooding_cmd);
- install_element (CONFIG_NODE, &no_debug_ospf6_flooding_cmd);
- }
|