summaryrefslogtreecommitdiff
path: root/ospfd/ospf_flood.c
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9 /ospfd/ospf_flood.c
Initial revision
Diffstat (limited to 'ospfd/ospf_flood.c')
-rw-r--r--ospfd/ospf_flood.c1048
1 files changed, 1048 insertions, 0 deletions
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
new file mode 100644
index 00000000..bd33c345
--- /dev/null
+++ b/ospfd/ospf_flood.c
@@ -0,0 +1,1048 @@
+/*
+ * OSPF Flooding -- RFC2328 Section 13.
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * 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 "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "command.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "zclient.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_abr.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_dump.h"
+
+extern struct zclient *zclient;
+
+/* Do the LSA acking specified in table 19, Section 13.5, row 2
+ * This get called from ospf_flood_out_interface. Declared inline
+ * for speed. */
+static void
+ospf_flood_delayed_lsa_ack (struct ospf_neighbor *inbr, struct ospf_lsa *lsa)
+{
+ /* LSA is more recent than database copy, but was not
+ flooded back out receiving interface. Delayed
+ acknowledgment sent. If interface is in Backup state
+ delayed acknowledgment sent only if advertisement
+ received from Designated Router, otherwise do nothing See
+ RFC 2328 Section 13.5 */
+
+ /* Whether LSA is more recent or not, and whether this is in
+ response to the LSA being sent out recieving interface has been
+ worked out previously */
+
+ /* Deal with router as BDR */
+ if (inbr->oi->state == ISM_Backup && ! NBR_IS_DR (inbr))
+ return;
+
+ /* Schedule a delayed LSA Ack to be sent */
+ listnode_add (inbr->oi->ls_ack, ospf_lsa_lock (lsa));
+}
+
+/* Check LSA is related to external info. */
+struct external_info *
+ospf_external_info_check (struct ospf_lsa *lsa)
+{
+ struct as_external_lsa *al;
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+ int type;
+
+ al = (struct as_external_lsa *) lsa->data;
+
+ p.family = AF_INET;
+ p.prefix = lsa->data->id;
+ p.prefixlen = ip_masklen (al->mask);
+
+ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+ {
+ int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type;
+ if (ospf_is_type_redistributed (redist_type))
+ if (EXTERNAL_INFO (type))
+ {
+ rn = route_node_lookup (EXTERNAL_INFO (type),
+ (struct prefix *) &p);
+ if (rn)
+ {
+ route_unlock_node (rn);
+ if (rn->info != NULL)
+ return (struct external_info *) rn->info;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void
+ospf_process_self_originated_lsa (struct ospf_lsa *new, struct ospf_area *area)
+{
+ struct ospf_interface *oi;
+ struct external_info *ei;
+ listnode node;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("LSA[Type%d:%s]: Process self-originated LSA",
+ new->data->type, inet_ntoa (new->data->id));
+
+ /* If we're here, we installed a self-originated LSA that we received
+ from a neighbor, i.e. it's more recent. We must see whether we want
+ to originate it.
+ If yes, we should use this LSA's sequence number and reoriginate
+ a new instance.
+ if not --- we must flush this LSA from the domain. */
+ switch (new->data->type)
+ {
+ case OSPF_ROUTER_LSA:
+ /* Originate a new instance and schedule flooding */
+ /* It shouldn't be necessary, but anyway */
+ ospf_lsa_unlock (area->router_lsa_self);
+ area->router_lsa_self = ospf_lsa_lock (new);
+
+ ospf_router_lsa_timer_add (area);
+ return;
+ case OSPF_NETWORK_LSA:
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_LINK_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+ /* We must find the interface the LSA could belong to.
+ If the interface is no more a broadcast type or we are no more
+ the DR, we flush the LSA otherwise -- create the new instance and
+ schedule flooding. */
+
+ /* Look through all interfaces, not just area, since interface
+ could be moved from one area to another. */
+ for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+ /* These are sanity check. */
+ if ((oi = getdata (node)) != NULL)
+ if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &new->data->id))
+ {
+ if (oi->area != area ||
+ oi->type != OSPF_IFTYPE_BROADCAST ||
+ !IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)))
+ {
+ ospf_schedule_lsa_flush_area (area, new);
+ return;
+ }
+
+#ifdef HAVE_OPAQUE_LSA
+ if (new->data->type == OSPF_OPAQUE_LINK_LSA)
+ {
+ ospf_opaque_lsa_refresh (new);
+ return;
+ }
+#endif /* HAVE_OPAQUE_LSA */
+
+ ospf_lsa_unlock (oi->network_lsa_self);
+ oi->network_lsa_self = ospf_lsa_lock (new);
+
+ /* Schedule network-LSA origination. */
+ ospf_network_lsa_timer_add (oi);
+ return;
+ }
+ break;
+ case OSPF_SUMMARY_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+ ospf_schedule_abr_task ();
+ break;
+ case OSPF_AS_EXTERNAL_LSA :
+#ifdef HAVE_NSSA
+ case OSPF_AS_NSSA_LSA:
+#endif /* HAVE_NSSA */
+ ei = ospf_external_info_check (new);
+ if (ei)
+ ospf_external_lsa_refresh (new, ei, LSA_REFRESH_FORCE);
+ else
+ ospf_lsa_flush_as (new);
+ break;
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_AREA_LSA:
+ ospf_opaque_lsa_refresh (new);
+ break;
+ case OSPF_OPAQUE_AS_LSA:
+ ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */
+ break;
+#endif /* HAVE_OPAQUE_LSA */
+ default:
+ break;
+ }
+}
+
+/* OSPF LSA flooding -- RFC2328 Section 13.(5). */
+
+/* Now Updated for NSSA operation, as follows:
+
+
+ Type-5's have no change. Blocked to STUB or NSSA.
+
+ Type-7's can be received, and if a DR
+ they will also flood the local NSSA Area as Type-7's
+
+ If a Self-Originated LSA (now an ASBR),
+ The LSDB will be updated as Type-5's, (for continual re-fresh)
+
+ If an NSSA-IR it is installed/flooded as Type-7, P-bit on.
+ if an NSSA-ABR it is installed/flooded as Type-7, P-bit off.
+
+ Later, during the ABR TASK, if the ABR is the Elected NSSA
+ translator, then All Type-7s (with P-bit ON) are Translated to
+ Type-5's and flooded to all non-NSSA/STUB areas.
+
+ During ASE Calculations,
+ non-ABRs calculate external routes from Type-7's
+ ABRs calculate external routes from Type-5's and non-self Type-7s
+*/
+int
+ospf_flood (struct ospf_neighbor *nbr, struct ospf_lsa *current,
+ struct ospf_lsa *new)
+{
+ struct ospf_interface *oi;
+ struct timeval now;
+ int lsa_ack_flag;
+
+ /* Type-7 LSA's will be flooded throughout their native NSSA area,
+ but will also be flooded as Type-5's into ABR capable links. */
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]",
+ inet_ntoa (nbr->router_id),
+ LOOKUP (ospf_nsm_state_msg, nbr->state),
+ current,
+ dump_lsa_key (new));
+
+ lsa_ack_flag = 0;
+ oi = nbr->oi;
+
+ /* Get current time. */
+ gettimeofday (&now, NULL);
+
+ /* If there is already a database copy, and if the
+ database copy was received via flooding and installed less
+ than MinLSArrival seconds ago, discard the new LSA
+ (without acknowledging it). */
+ if (current != NULL) /* -- endo. */
+ {
+ if (IS_LSA_SELF (current)
+ && (ntohs (current->data->ls_age) == 0
+ && ntohl (current->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER))
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("LSA[Flooding]: Got a self-originated LSA, "
+ "while local one is initial instance.");
+ ; /* Accept this LSA for quick LSDB resynchronization. */
+ }
+ else if (tv_cmp (tv_sub (now, current->tv_recv),
+ int2tv (OSPF_MIN_LS_ARRIVAL)) < 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("LSA[Flooding]: LSA is received recently.");
+ return -1;
+ }
+ }
+
+ /* Flood the new LSA out some subset of the router's interfaces.
+ In some cases (e.g., the state of the receiving interface is
+ DR and the LSA was received from a router other than the
+ Backup DR) the LSA will be flooded back out the receiving
+ interface. */
+ lsa_ack_flag = ospf_flood_through (nbr, new);
+
+#ifdef HAVE_OPAQUE_LSA
+ /* Remove the current database copy from all neighbors' Link state
+ retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ not have area ID.
+ All other (even NSSA's) do have area ID. */
+#else /* HAVE_OPAQUE_LSA */
+ /* Remove the current database copy from all neighbors' Link state
+ retransmission lists. Only AS_EXTERNAL does not have area ID.
+ All other (even NSSA's) do have area ID. */
+#endif /* HAVE_OPAQUE_LSA */
+ if (current)
+ {
+ switch (current->data->type)
+ {
+ case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+ ospf_ls_retransmit_delete_nbr_all (NULL, current);
+ break;
+ default:
+ ospf_ls_retransmit_delete_nbr_all (nbr->oi->area, current);
+ break;
+ }
+ }
+
+ /* Do some internal house keeping that is needed here */
+ SET_FLAG (new->flags, OSPF_LSA_RECEIVED);
+ ospf_lsa_is_self_originated (new); /* Let it set the flag */
+
+ /* Install the new LSA in the link state database
+ (replacing the current database copy). This may cause the
+ routing table calculation to be scheduled. In addition,
+ timestamp the new LSA with the current time. The flooding
+ procedure cannot overwrite the newly installed LSA until
+ MinLSArrival seconds have elapsed. */
+
+ new = ospf_lsa_install (nbr->oi, new);
+
+#ifdef HAVE_NSSA
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("LSA[Flooding]: Type-%d installed", new->data->type);
+
+ /* if (new->data->type == OSPF_AS_NSSA_LSA )
+ return 0; */
+#endif /* HAVE_NSSA */
+
+ /* Acknowledge the receipt of the LSA by sending a Link State
+ Acknowledgment packet back out the receiving interface. */
+ if (lsa_ack_flag)
+ ospf_flood_delayed_lsa_ack (nbr, new);
+
+ /* If this new LSA indicates that it was originated by the
+ receiving router itself, the router must take special action,
+ either updating the LSA or in some cases flushing it from
+ the routing domain. */
+ if (ospf_lsa_is_self_originated (new))
+ ospf_process_self_originated_lsa (new, oi->area);
+ else
+ /* Update statistics value for OSPF-MIB. */
+ ospf_top->rx_lsa_count++;
+
+ return 0;
+}
+
+/* OSPF LSA flooding -- RFC2328 Section 13.3. */
+int
+ospf_flood_through_interface (struct ospf_interface *oi,
+ struct ospf_neighbor *inbr,
+ struct ospf_lsa *lsa)
+{
+ struct ospf_neighbor *onbr;
+ struct route_node *rn;
+ int retx_flag;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_flood_through_interface(): "
+ "considering int %s, INBR(%s), LSA[%s]",
+ IF_NAME (oi), inbr ? inet_ntoa (inbr->router_id) : "NULL",
+ dump_lsa_key (lsa));
+
+ if (!ospf_if_is_enable (oi))
+ return 0;
+
+ /* Remember if new LSA is aded to a retransmit list. */
+ retx_flag = 0;
+
+ /* Each of the neighbors attached to this interface are examined,
+ to determine whether they must receive the new LSA. The following
+ steps are executed for each neighbor: */
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ {
+ struct ospf_lsa *ls_req;
+
+ if (rn->info == NULL)
+ continue;
+
+ onbr = rn->info;
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_flood_through_interface(): considering nbr %s (%s)",
+ inet_ntoa (onbr->router_id),
+ LOOKUP (ospf_nsm_state_msg, onbr->state));
+
+ /* If the neighbor is in a lesser state than Exchange, it
+ does not participate in flooding, and the next neighbor
+ should be examined. */
+ if (onbr->state < NSM_Exchange)
+ continue;
+
+ /* If the adjacency is not yet full (neighbor state is
+ Exchange or Loading), examine the Link state request
+ list associated with this adjacency. If there is an
+ instance of the new LSA on the list, it indicates that
+ the neighboring router has an instance of the LSA
+ already. Compare the new LSA to the neighbor's copy: */
+ if (onbr->state < NSM_Full)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_flood_through_interface(): nbr adj is not Full");
+ ls_req = ospf_ls_request_lookup (onbr, lsa);
+ if (ls_req != NULL)
+ {
+ int ret;
+
+ ret = ospf_lsa_more_recent (ls_req, lsa);
+ /* The new LSA is less recent. */
+ if (ret > 0)
+ continue;
+ /* The two copies are the same instance, then delete
+ the LSA from the Link state request list. */
+ else if (ret == 0)
+ {
+ ospf_ls_request_delete (onbr, ls_req);
+ ospf_check_nbr_loading (onbr);
+ continue;
+ }
+ /* The new LSA is more recent. Delete the LSA
+ from the Link state request list. */
+ else
+ {
+ ospf_ls_request_delete (onbr, ls_req);
+ ospf_check_nbr_loading (onbr);
+ }
+ }
+ }
+
+#ifdef HAVE_OPAQUE_LSA
+ if (IS_OPAQUE_LSA (lsa->data->type))
+ {
+ if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O))
+ {
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("Skip this neighbor: Not Opaque-capable.");
+ continue;
+ }
+
+ if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf_top->opaque)
+ && IS_LSA_SELF (lsa)
+ && onbr->state == NSM_Full)
+ {
+ /* Small attempt to reduce unnecessary retransmission. */
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("Skip this neighbor: Initial flushing done.");
+ continue;
+ }
+ }
+#endif /* HAVE_OPAQUE_LSA */
+
+ /* If the new LSA was received from this neighbor,
+ examine the next neighbor. */
+#ifdef ORIGINAL_CODING
+ if (inbr)
+ if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id))
+ continue;
+#else /* ORIGINAL_CODING */
+ if (inbr)
+ {
+ /*
+ * Triggered by LSUpd message parser "ospf_ls_upd ()".
+ * E.g., all LSAs handling here is received via network.
+ */
+ if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id))
+ {
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("Skip this neighbor: inbr == onbr");
+ continue;
+ }
+ }
+ else
+ {
+ /*
+ * Triggered by MaxAge remover, so far.
+ * NULL "inbr" means flooding starts from this node.
+ */
+ if (IPV4_ADDR_SAME (&lsa->data->adv_router, &onbr->router_id))
+ {
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("Skip this neighbor: lsah->adv_router == onbr");
+ continue;
+ }
+ }
+#endif /* ORIGINAL_CODING */
+
+ /* Add the new LSA to the Link state retransmission list
+ for the adjacency. The LSA will be retransmitted
+ at intervals until an acknowledgment is seen from
+ the neighbor. */
+ ospf_ls_retransmit_add (onbr, lsa);
+ retx_flag = 1;
+ }
+
+ /* If in the previous step, the LSA was NOT added to any of
+ the Link state retransmission lists, there is no need to
+ flood the LSA out the interface. */
+ if (retx_flag == 0)
+ {
+ return (inbr && inbr->oi == oi);
+ }
+
+ /* if we've received the lsa on this interface we need to perform
+ additional checking */
+ if (inbr && (inbr->oi == oi))
+ {
+ /* If the new LSA was received on this interface, and it was
+ received from either the Designated Router or the Backup
+ Designated Router, chances are that all the neighbors have
+ received the LSA already. */
+ if (NBR_IS_DR (inbr) || NBR_IS_BDR (inbr))
+ {
+#ifdef HAVE_NSSA
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_flood_through_interface(): "
+ "DR/BDR NOT SEND to int %s", IF_NAME (oi));
+#endif /* HAVE_NSSA */
+ return 1;
+ }
+
+ /* If the new LSA was received on this interface, and the
+ interface state is Backup, examine the next interface. The
+ Designated Router will do the flooding on this interface.
+ However, if the Designated Router fails the router will
+ end up retransmitting the updates. */
+
+ if (oi->state == ISM_Backup)
+ {
+#ifdef HAVE_NSSA
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_flood_through_interface(): "
+ "ISM_Backup NOT SEND to int %s", IF_NAME (oi));
+#endif /* HAVE_NSSA */
+ return 1;
+ }
+ }
+
+ /* The LSA must be flooded out the interface. Send a Link State
+ Update packet (including the new LSA as contents) out the
+ interface. The LSA's LS age must be incremented by InfTransDelay
+ (which must be > 0) when it is copied into the outgoing Link
+ State Update packet (until the LS age field reaches the maximum
+ value of MaxAge). */
+
+#ifdef HAVE_NSSA
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_flood_through_interface(): "
+ "DR/BDR sending upd to int %s", IF_NAME (oi));
+#else /* ! HAVE_NSSA */
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_info ("ospf_flood_through_interface(): "
+ "sending upd to int %s", IF_NAME (oi));
+#endif /* HAVE_NSSA */
+
+ /* RFC2328 Section 13.3
+ On non-broadcast networks, separate Link State Update
+ packets must be sent, as unicasts, to each adjacent neighbor
+ (i.e., those in state Exchange or greater). The destination
+ IP addresses for these packets are the neighbors' IP
+ addresses. */
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ {
+ struct route_node *rn;
+ struct ospf_neighbor *nbr;
+
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ if ((nbr = rn->info) != NULL)
+ if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
+ ospf_ls_upd_send_lsa (nbr, lsa, OSPF_SEND_PACKET_DIRECT);
+ }
+ else
+ ospf_ls_upd_send_lsa (oi->nbr_self, lsa, OSPF_SEND_PACKET_INDIRECT);
+
+ return 0;
+}
+
+int
+ospf_flood_through_area (struct ospf_area * area,struct ospf_neighbor *inbr,
+ struct ospf_lsa *lsa)
+{
+ listnode node;
+ int lsa_ack_flag = 0;
+
+ /* All other types are specific to a single area (Area A). The
+ eligible interfaces are all those interfaces attaching to the
+ Area A. If Area A is the backbone, this includes all the virtual
+ links. */
+ for (node = listhead (area->oiflist); node; nextnode (node))
+ {
+ struct ospf_interface *oi = getdata (node);
+
+ if (area->area_id.s_addr != OSPF_AREA_BACKBONE &&
+ oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ continue;
+
+#ifdef HAVE_OPAQUE_LSA
+ if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi))
+ {
+ /*
+ * Link local scoped Opaque-LSA should only be flooded
+ * for the link on which the LSA has received.
+ */
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi);
+ continue;
+ }
+#endif /* HAVE_OPAQUE_LSA */
+
+ if (ospf_flood_through_interface (oi, inbr, lsa))
+ lsa_ack_flag = 1;
+ }
+
+ return (lsa_ack_flag);
+}
+
+int
+ospf_flood_through_as (struct ospf_neighbor *inbr, struct ospf_lsa *lsa)
+{
+ listnode node;
+ int lsa_ack_flag;
+
+ lsa_ack_flag = 0;
+
+ /* The incoming LSA is type 5 or type 7 (AS-EXTERNAL or AS-NSSA )
+
+ Divert the Type-5 LSA's to all non-NSSA/STUB areas
+
+ Divert the Type-7 LSA's to all NSSA areas
+
+ AS-external-LSAs are flooded throughout the entire AS, with the
+ exception of stub areas (see Section 3.6). The eligible
+ interfaces are all the router's interfaces, excluding virtual
+ links and those interfaces attaching to stub areas. */
+
+#ifdef HAVE_NSSA
+ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) /* Translated from 7 */
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("Flood/AS: NSSA TRANSLATED LSA");
+#endif /* HAVE_NSSA */
+
+ for (node = listhead (ospf_top->areas); node; nextnode (node))
+ {
+ int continue_flag = 0;
+ struct ospf_area *area = getdata (node);
+ listnode if_node;
+
+ switch (area->external_routing)
+ {
+ /* Don't send AS externals into stub areas. Various types
+ of support for partial stub areas can be implemented
+ here. NSSA's will receive Type-7's that have areas
+ matching the originl LSA. */
+ case OSPF_AREA_NSSA: /* Sending Type 5 or 7 into NSSA area */
+#ifdef HAVE_NSSA
+ /* Type-7, flood NSSA area */
+ if (lsa->data->type == OSPF_AS_NSSA_LSA)
+ /* We will send it. */
+ continue_flag = 0;
+ else
+ continue_flag = 1; /* Skip this NSSA area for Type-5's et al */
+ break;
+#endif /* HAVE_NSSA */
+
+ case OSPF_AREA_TYPE_MAX:
+ case OSPF_AREA_STUB:
+ continue_flag = 1; /* Skip this area. */
+ break;
+
+ case OSPF_AREA_DEFAULT:
+ default:
+#ifdef HAVE_NSSA
+ /* No Type-7 into normal area */
+ if (lsa->data->type == OSPF_AS_NSSA_LSA)
+ continue_flag = 1; /* skip Type-7 */
+ else
+#endif /* HAVE_NSSA */
+ continue_flag = 0; /* Do this area. */
+ break;
+ }
+
+ /* Do continue for above switch. Saves a big if then mess */
+ if (continue_flag)
+ continue; /* main for-loop */
+
+ /* send to every interface in this area */
+
+ for (if_node = listhead (area->oiflist); if_node; nextnode (if_node))
+ {
+ struct ospf_interface *oi = getdata (if_node);
+
+ /* Skip virtual links */
+ if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ if (ospf_flood_through_interface (oi, inbr, lsa)) /* lsa */
+ lsa_ack_flag = 1;
+ }
+ } /* main area for-loop */
+
+ return (lsa_ack_flag);
+}
+
+int
+ospf_flood_through (struct ospf_neighbor *inbr, struct ospf_lsa *lsa)
+{
+ int lsa_ack_flag = 0;
+
+ /* Type-7 LSA's for NSSA are flooded throughout the AS here, and
+ upon return are updated in the LSDB for Type-7's. Later,
+ re-fresh will re-send them (and also, if ABR, packet code will
+ translate to Type-5's)
+
+ As usual, Type-5 LSA's (if not DISCARDED because we are STUB or
+ NSSA) are flooded throughout the AS, and are updated in the
+ global table. */
+#ifdef ORIGINAL_CODING
+ switch (lsa->data->type)
+ {
+ case OSPF_ROUTER_LSA:
+ case OSPF_NETWORK_LSA:
+ case OSPF_SUMMARY_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */
+ case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa);
+ break;
+ case OSPF_AS_EXTERNAL_LSA: /* Type-5 */
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+ lsa_ack_flag = ospf_flood_through_as (inbr, lsa);
+ break;
+#ifdef HAVE_NSSA
+ /* Type-7 Only received within NSSA, then flooded */
+ case OSPF_AS_NSSA_LSA:
+ /* Any P-bit was installed with the Type-7. */
+ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa);
+
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7.");
+ break;
+#endif /* HAVE_NSSA */
+ default:
+ break;
+ }
+#else /* ORIGINAL_CODING */
+ /*
+ * At the common sub-sub-function "ospf_flood_through_interface()",
+ * a parameter "inbr" will be used to distinguish the called context
+ * whether the given LSA was received from the neighbor, or the
+ * flooding for the LSA starts from this node (e.g. the LSA was self-
+ * originated, or the LSA is going to be flushed from routing domain).
+ *
+ * So, for consistency reasons, this function "ospf_flood_through()"
+ * should also allow the usage that the given "inbr" parameter to be
+ * NULL. If we do so, corresponding AREA parameter should be referred
+ * by "lsa->area", instead of "inbr->oi->area".
+ */
+ switch (lsa->data->type)
+ {
+ case OSPF_AS_EXTERNAL_LSA: /* Type-5 */
+#ifdef HAVE_OPAQUE_LSA
+ case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+ lsa_ack_flag = ospf_flood_through_as (inbr, lsa);
+ break;
+#ifdef HAVE_NSSA
+ /* Type-7 Only received within NSSA, then flooded */
+ case OSPF_AS_NSSA_LSA:
+ /* Any P-bit was installed with the Type-7. */
+
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7.");
+ /* Fallthrough */
+#endif /* HAVE_NSSA */
+ default:
+ lsa_ack_flag = ospf_flood_through_area (lsa->area, inbr, lsa);
+ break;
+ }
+#endif /* ORIGINAL_CODING */
+
+ return (lsa_ack_flag);
+}
+
+
+
+/* Management functions for neighbor's Link State Request list. */
+void
+ospf_ls_request_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ /*
+ * We cannot make use of the newly introduced callback function
+ * "lsdb->new_lsa_hook" to replace debug output below, just because
+ * it seems no simple and smart way to pass neighbor information to
+ * the common function "ospf_lsdb_add()" -- endo.
+ */
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("RqstL(%lu)++, NBR(%s), LSA[%s]",
+ ospf_ls_request_count (nbr),
+ inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+
+ ospf_lsdb_add (&nbr->ls_req, lsa);
+}
+
+unsigned long
+ospf_ls_request_count (struct ospf_neighbor *nbr)
+{
+ return ospf_lsdb_count_all (&nbr->ls_req);
+}
+
+int
+ospf_ls_request_isempty (struct ospf_neighbor *nbr)
+{
+ return ospf_lsdb_isempty (&nbr->ls_req);
+}
+
+/* Remove LSA from neighbor's ls-request list. */
+void
+ospf_ls_request_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ if (nbr->ls_req_last == lsa)
+ {
+ ospf_lsa_unlock (nbr->ls_req_last);
+ nbr->ls_req_last = NULL;
+ }
+
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */
+ zlog_info ("RqstL(%lu)--, NBR(%s), LSA[%s]",
+ ospf_ls_request_count (nbr),
+ inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+
+ ospf_lsdb_delete (&nbr->ls_req, lsa);
+}
+
+/* Remove all LSA from neighbor's ls-requenst list. */
+void
+ospf_ls_request_delete_all (struct ospf_neighbor *nbr)
+{
+ ospf_lsa_unlock (nbr->ls_req_last);
+ nbr->ls_req_last = NULL;
+ ospf_lsdb_delete_all (&nbr->ls_req);
+}
+
+/* Lookup LSA from neighbor's ls-request list. */
+struct ospf_lsa *
+ospf_ls_request_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ return ospf_lsdb_lookup (&nbr->ls_req, lsa);
+}
+
+struct ospf_lsa *
+ospf_ls_request_new (struct lsa_header *lsah)
+{
+ struct ospf_lsa *new;
+
+ new = ospf_lsa_new ();
+ new->data = ospf_lsa_data_new (OSPF_LSA_HEADER_SIZE);
+ memcpy (new->data, lsah, OSPF_LSA_HEADER_SIZE);
+
+ return new;
+}
+
+
+/* Management functions for neighbor's ls-retransmit list. */
+unsigned long
+ospf_ls_retransmit_count (struct ospf_neighbor *nbr)
+{
+ return ospf_lsdb_count_all (&nbr->ls_rxmt);
+}
+
+unsigned long
+ospf_ls_retransmit_count_self (struct ospf_neighbor *nbr, int lsa_type)
+{
+ return ospf_lsdb_count_self (&nbr->ls_rxmt, lsa_type);
+}
+
+int
+ospf_ls_retransmit_isempty (struct ospf_neighbor *nbr)
+{
+ return ospf_lsdb_isempty (&nbr->ls_rxmt);
+}
+
+/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */
+void
+ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ struct ospf_lsa *old;
+
+ old = ospf_ls_retransmit_lookup (nbr, lsa);
+
+ if (ospf_lsa_more_recent (old, lsa) < 0)
+ {
+ if (old)
+ {
+ old->retransmit_counter--;
+ ospf_lsdb_delete (&nbr->ls_rxmt, old);
+ }
+ lsa->retransmit_counter++;
+ /*
+ * We cannot make use of the newly introduced callback function
+ * "lsdb->new_lsa_hook" to replace debug output below, just because
+ * it seems no simple and smart way to pass neighbor information to
+ * the common function "ospf_lsdb_add()" -- endo.
+ */
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+ zlog_info ("RXmtL(%lu)++, NBR(%s), LSA[%s]",
+ ospf_ls_retransmit_count (nbr),
+ inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+ ospf_lsdb_add (&nbr->ls_rxmt, lsa);
+ }
+}
+
+/* Remove LSA from neibghbor's ls-retransmit list. */
+void
+ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ if (ospf_ls_retransmit_lookup (nbr, lsa))
+ {
+ lsa->retransmit_counter--;
+ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */
+ zlog_info ("RXmtL(%lu)--, NBR(%s), LSA[%s]",
+ ospf_ls_retransmit_count (nbr),
+ inet_ntoa (nbr->router_id), dump_lsa_key (lsa));
+ ospf_lsdb_delete (&nbr->ls_rxmt, lsa);
+ }
+}
+
+/* Clear neighbor's ls-retransmit list. */
+void
+ospf_ls_retransmit_clear (struct ospf_neighbor *nbr)
+{
+ struct ospf_lsdb *lsdb;
+ int i;
+
+ lsdb = &nbr->ls_rxmt;
+
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+ {
+ struct route_table *table = lsdb->type[i].db;
+ struct route_node *rn;
+ struct ospf_lsa *lsa;
+
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ if ((lsa = rn->info) != NULL)
+ ospf_ls_retransmit_delete (nbr, lsa);
+ }
+
+ ospf_lsa_unlock (nbr->ls_req_last);
+ nbr->ls_req_last = NULL;
+}
+
+/* Lookup LSA from neighbor's ls-retransmit list. */
+struct ospf_lsa *
+ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ return ospf_lsdb_lookup (&nbr->ls_rxmt, lsa);
+}
+
+/* Remove All neighbor/interface's Link State Retransmit list in area. */
+void
+ospf_ls_retransmit_delete_nbr_all (struct ospf_area *area,
+ struct ospf_lsa *lsa)
+{
+ listnode node;
+ list oiflist = area ? area->oiflist : ospf_top->oiflist;
+
+ for (node = listhead (oiflist); node; nextnode (node))
+ {
+ struct ospf_interface *oi = getdata (node);
+ struct route_node *rn;
+ struct ospf_neighbor *nbr;
+ struct ospf_lsa *lsr;
+
+ if (ospf_if_is_enable (oi))
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ /* If LSA find in LS-retransmit list, then remove it. */
+ if ((nbr = rn->info) != NULL)
+ {
+ lsr = ospf_ls_retransmit_lookup (nbr, lsa);
+
+ /* If LSA find in ls-retransmit list, remove it. */
+ if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
+ ospf_ls_retransmit_delete (nbr, lsr);
+ }
+ }
+}
+
+/* Add LSA to the current database copy of all neighbors'
+ Link state retransmission lists. */
+void
+ospf_ls_retransmit_add_nbr_all (struct ospf_interface *ospfi,
+ struct ospf_lsa *lsa)
+{
+ listnode node;
+
+ for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+ {
+ struct ospf_interface *oi = getdata (node);
+ struct route_node *rn;
+ struct ospf_neighbor *nbr;
+ struct ospf_lsa *old;
+
+ if (ospf_if_is_enable (oi))
+ if (OSPF_AREA_SAME (&ospfi->area, &oi->area))
+ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+ if ((nbr = rn->info) != NULL)
+ if (nbr->state == NSM_Full)
+ {
+ if ((old = ospf_ls_retransmit_lookup (nbr, lsa)))
+ ospf_ls_retransmit_delete (nbr, old);
+
+ ospf_ls_retransmit_add (nbr, lsa);
+ }
+ }
+}
+
+
+/* Sets ls_age to MaxAge and floods throu the area.
+ When we implement ASE routing, there will be anothe function
+ flushing an LSA from the whole domain. */
+void
+ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area)
+{
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+ ospf_flood_through_area (area, NULL, lsa);
+ ospf_lsa_maxage (lsa);
+}
+
+void
+ospf_lsa_flush_as (struct ospf_lsa *lsa)
+{
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+ ospf_flood_through_as (NULL, lsa);
+ ospf_lsa_maxage (lsa);
+}
+
+/* Flush LSA through AS -- used for AS-external-LSAs. */
+void
+ospf_flush_through_as (struct ospf_lsa *lsa)
+{
+ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+ ospf_flood_through_as (NULL, lsa);
+ ospf_lsa_maxage (lsa);
+}