+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OSPF Link State Advertisement
* 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 this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "memory.h"
#include "stream.h"
#include "log.h"
-#include "thread.h"
+#include "frrevent.h"
#include "hash.h"
#include "sockunion.h" /* for inet_aton() */
#include "checksum.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_errors.h"
-#include "ospfd/ospf_te.h"
-#include "ospfd/ospf_orr.h"
-static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
+static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf_area *area,
struct prefix_ipv4 *p,
uint8_t type,
uint32_t metric,
return m;
}
+/** @brief The Function checks self generated DoNotAge.
+ * @param lsa pointer.
+ * @return true or false.
+ */
+bool ospf_check_dna_lsa(const struct ospf_lsa *lsa)
+{
+ return ((IS_LSA_SELF(lsa) && CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE))
+ ? true
+ : false);
+}
struct timeval int2tv(int a)
{
{
struct timeval rel;
+ /* As per rfc4136, the self-originated LSAs in their
+ * own database keep aging, however rfc doesn't tell
+ * till how long the LSA should be aged, as of now
+ * we are capping it for OSPF_LSA_MAXAGE.
+ */
+
+ /* If LSA is marked as donotage */
+ if (CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE) && !IS_LSA_SELF(lsa))
+ return ntohs(lsa->data->ls_age);
+
monotime_since(&lsa->tv_recv, &rel);
return ntohs(lsa->data->ls_age) + rel.tv_sec;
}
/* PtoP link must have only 1 neighbor. */
if (ospf_nbr_count(oi, 0) > 1)
- flog_warn(EC_OSPF_PTP_NEIGHBOR,
- "Point-to-Point link has more than 1 neighobrs.");
+ flog_warn(
+ EC_OSPF_PTP_NEIGHBOR,
+ "Point-to-Point link on interface %s has more than 1 neighbor.",
+ oi->ifp->name);
return nbr;
}
stream_putw_at(*s, putp, cnt);
}
-static void ospf_stub_router_timer(struct thread *t)
+static void ospf_stub_router_timer(struct event *t)
{
- struct ospf_area *area = THREAD_ARG(t);
+ struct ospf_area *area = EVENT_ARG(t);
area->t_stub_router = NULL;
}
return NULL;
}
+
+ if (oi->state != ISM_DR)
+ return NULL;
+
/* Delete LSA from neighbor retransmit-list. */
ospf_ls_retransmit_delete_nbr_area(area, lsa);
return new;
}
-static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
+static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf_area *area,
struct prefix_ipv4 *p,
uint8_t type,
uint32_t metric,
struct in_addr old_id)
{
struct ospf_lsa *lsa = NULL;
- struct ospf_lsa *new = NULL;
+ struct ospf_lsa *summary_lsa = NULL;
struct summary_lsa *sl = NULL;
struct ospf_area *old_area = NULL;
+ struct ospf *ospf = area->ospf;
struct prefix_ipv4 old_prefix;
uint32_t old_metric;
struct in_addr mask;
uint32_t metric_val;
char *metric_buf;
- lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, p->prefix,
+ lsa = ospf_lsdb_lookup_by_id(area->lsdb, type, p->prefix,
ospf->router_id);
if (!lsa) {
if (type == OSPF_SUMMARY_LSA) {
/*Refresh the LSA with new LSA*/
- ospf_summary_lsa_refresh(ospf, lsa);
+ summary_lsa = ospf_summary_lsa_refresh(ospf, lsa);
- new = ospf_summary_lsa_prepare_and_flood(
- &old_prefix, old_metric, old_area, old_id);
+ ospf_summary_lsa_prepare_and_flood(&old_prefix, old_metric,
+ old_area, old_id);
} else {
/*Refresh the LSA with new LSA*/
- ospf_summary_asbr_lsa_refresh(ospf, lsa);
+ summary_lsa = ospf_summary_asbr_lsa_refresh(ospf, lsa);
- new = ospf_asbr_summary_lsa_prepare_and_flood(
- &old_prefix, old_metric, old_area, old_id);
+ ospf_asbr_summary_lsa_prepare_and_flood(&old_prefix, old_metric,
+ old_area, old_id);
}
- return new;
+ return summary_lsa;
}
/* Originate Summary-LSA. */
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("Link ID has to be changed.");
- new = ospf_handle_summarylsa_lsId_chg(
- area->ospf, p, OSPF_SUMMARY_LSA, metric, id);
+ new = ospf_handle_summarylsa_lsId_chg(area, p, OSPF_SUMMARY_LSA,
+ metric, id);
return new;
} else if (status == LSID_NOT_AVAILABLE) {
/* Link State ID not available. */
zlog_debug("Link ID has to be changed.");
new = ospf_handle_summarylsa_lsId_chg(
- area->ospf, p, OSPF_ASBR_SUMMARY_LSA, metric, id);
+ area, p, OSPF_ASBR_SUMMARY_LSA, metric, id);
return new;
} else if (status == LSID_NOT_AVAILABLE) {
/* Link State ID not available. */
struct ospf_lsa *new;
struct summary_lsa *sl;
struct prefix p;
+ bool ind_lsa = false;
/* Sanity check. */
assert(lsa->data);
+ if (lsa->area->fr_info.indication_lsa_self &&
+ (lsa->area->fr_info.indication_lsa_self == lsa))
+ ind_lsa = true;
+
sl = (struct summary_lsa *)lsa->data;
p.prefixlen = ip_masklen(sl->mask);
new = ospf_summary_asbr_lsa_new(lsa->area, &p, GET_METRIC(sl->metric),
/* Flood LSA through area. */
ospf_flood_through_area(new->area, NULL, new);
+ if (ind_lsa)
+ new->area->fr_info.indication_lsa_self = new;
+
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
zlog_debug("LSA[Type%d:%pI4]: summary-ASBR-LSA refresh",
new->data->type, &new->data->id);
ospf_refresher_register_lsa(ospf, new);
}
- /* For BGP ORR SPF should be calculated from specified root(s) */
- else if (ospf->orr_spf_request) {
- ospf_lsa_unlock(&area->router_lsa_rcvd);
- area->router_lsa_rcvd = ospf_lsa_lock(new);
- ospf_orr_root_update_rcvd_lsa(area->router_lsa_rcvd);
- }
-
if (rt_recalc)
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL);
return new;
struct ospf_lsa *new,
int rt_recalc)
{
+
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
The entire routing table must be recalculated, starting with
the shortest path calculations for each area (not just the
}
-void ospf_maxage_lsa_remover(struct thread *thread)
+void ospf_maxage_lsa_remover(struct event *thread)
{
- struct ospf *ospf = THREAD_ARG(thread);
+ struct ospf *ospf = EVENT_ARG(thread);
struct ospf_lsa *lsa, *old;
struct route_node *rn;
int reschedule = 0;
}
/* TODO: maybe convert this function to a work-queue */
- if (thread_should_yield(thread)) {
+ if (event_should_yield(thread)) {
OSPF_TIMER_ON(ospf->t_maxage,
ospf_maxage_lsa_remover, 0);
route_unlock_node(
}
/* Periodical check of MaxAge LSA. */
-void ospf_lsa_maxage_walker(struct thread *thread)
+void ospf_lsa_maxage_walker(struct event *thread)
{
- struct ospf *ospf = THREAD_ARG(thread);
+ struct ospf *ospf = EVENT_ARG(thread);
struct route_node *rn;
struct ospf_lsa *lsa;
struct ospf_area *area;
return NULL;
}
-struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
- uint32_t type, struct in_addr id)
-{
- struct ospf_lsa *lsa = NULL;
- struct route_node *rn = NULL;
-
- switch (type) {
- case OSPF_ROUTER_LSA:
- for (rn = route_top(ROUTER_LSDB(area)); rn;
- rn = route_next(rn)) {
- lsa = rn->info;
- if (lsa) {
- if (IPV4_ADDR_SAME(&lsa->data->adv_router,
- &id)) {
- route_unlock_node(rn);
- return lsa;
- }
- }
- }
- break;
- case OSPF_NETWORK_LSA:
- case OSPF_SUMMARY_LSA:
- case OSPF_ASBR_SUMMARY_LSA:
- case OSPF_AS_EXTERNAL_LSA:
- case OSPF_AS_NSSA_LSA:
- case OSPF_OPAQUE_LINK_LSA:
- case OSPF_OPAQUE_AREA_LSA:
- case OSPF_OPAQUE_AS_LSA:
- /* Currently not used. */
- break;
- default:
- break;
- }
-
- return NULL;
-}
-
-struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
- uint32_t type,
- struct in_addr id)
-{
- struct ospf_lsa *lsa = NULL;
- struct route_node *rn = NULL;
- struct lsa_header *lsah = NULL;
- uint32_t lsid;
- uint8_t opaque_type;
- struct tlv_header *tlvh = NULL;
- struct te_tlv_router_addr *router_addr = NULL;
-
- if (type != OSPF_OPAQUE_AREA_LSA)
- return NULL;
-
- for (rn = route_top(OPAQUE_AREA_LSDB(area)); rn; rn = route_next(rn)) {
- lsa = rn->info;
- if (lsa) {
- lsah = lsa->data;
- lsid = ntohl(lsah->id.s_addr);
- opaque_type = GET_OPAQUE_TYPE(lsid);
- if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
- continue;
-
- tlvh = TLV_HDR_TOP(lsah);
- if (!tlvh ||
- (ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
- (ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
- continue;
- router_addr = (struct te_tlv_router_addr *)tlvh;
- if (IPV4_ADDR_SAME(&router_addr->value, &id)) {
- route_unlock_node(rn);
- return lsa;
- }
- }
- }
- return NULL;
-}
-
struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area,
struct lsa_header *lsah)
{
* without conflicting to other threads.
*/
if (ospf->t_maxage != NULL) {
- THREAD_OFF(ospf->t_maxage);
- thread_execute(master, ospf_maxage_lsa_remover, ospf, 0);
+ EVENT_OFF(ospf->t_maxage);
+ event_execute(master, ospf_maxage_lsa_remover, ospf, 0);
}
return;
}
+/** @brief Function to refresh all the self originated
+ * LSAs for area, when FR state change happens.
+ * @param area pointer.
+ * @return Void.
+ */
+void ospf_refresh_area_self_lsas(struct ospf_area *area)
+{
+ struct listnode *node2;
+ struct listnode *nnode2;
+ struct ospf_interface *oi;
+ struct route_node *rn;
+ struct ospf_lsa *lsa;
+
+ if (!area)
+ return;
+
+ if (area->router_lsa_self)
+ ospf_lsa_refresh(area->ospf, area->router_lsa_self);
+
+ for (ALL_LIST_ELEMENTS(area->oiflist, node2, nnode2, oi))
+ if (oi->network_lsa_self)
+ ospf_lsa_refresh(oi->ospf, oi->network_lsa_self);
+
+ LSDB_LOOP (SUMMARY_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (OPAQUE_LINK_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (EXTERNAL_LSDB(area->ospf), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (OPAQUE_AS_LSDB(area->ospf), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+}
+
/* If there is self-originated LSA, then return 1, otherwise return 0. */
/* An interface-independent version of ospf_lsa_is_self_originated */
int ospf_lsa_is_self_originated(struct ospf *ospf, struct ospf_lsa *lsa)
struct ospf_lsa *lsa;
};
-static void ospf_lsa_action(struct thread *t)
+static void ospf_lsa_action(struct event *t)
{
struct lsa_action *data;
- data = THREAD_ARG(t);
+ data = EVENT_ARG(t);
if (IS_DEBUG_OSPF(lsa, LSA) == OSPF_DEBUG_LSA)
zlog_debug("LSA[Action]: Performing scheduled LSA action: %d",
data->area = area;
data->lsa = ospf_lsa_lock(lsa); /* Message / Flood area */
- thread_add_event(master, ospf_lsa_action, data, 0, NULL);
+ event_add_event(master, ospf_lsa_action, data, 0, NULL);
}
void ospf_schedule_lsa_flush_area(struct ospf_area *area, struct ospf_lsa *lsa)
data->area = area;
data->lsa = ospf_lsa_lock(lsa); /* Message / Flush area */
- thread_add_event(master, ospf_lsa_action, data, 0, NULL);
+ event_add_event(master, ospf_lsa_action, data, 0, NULL);
}
struct as_external_lsa *al;
struct prefix_ipv4 p;
- if (!CHECK_FLAG(lsa->flags, OSPF_LSA_SELF) && !IS_LSA_SELF(lsa) &&
- !IS_LSA_ORR(lsa))
- return NULL;
+ assert(CHECK_FLAG(lsa->flags, OSPF_LSA_SELF));
+ assert(IS_LSA_SELF(lsa));
assert(lsa->lock > 0);
switch (lsa->data->type) {
uint16_t index, current_index;
assert(lsa->lock > 0);
- if (!IS_LSA_SELF(lsa) && !IS_LSA_ORR(lsa))
- return;
+ assert(IS_LSA_SELF(lsa));
if (lsa->refresh_list < 0) {
int delay;
void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
{
assert(lsa->lock > 0);
- if (!IS_LSA_SELF(lsa) || !IS_LSA_ORR(lsa))
- return;
+ assert(IS_LSA_SELF(lsa));
if (lsa->refresh_list >= 0) {
struct list *refresh_list =
ospf->lsa_refresh_queue.qs[lsa->refresh_list];
}
}
-void ospf_lsa_refresh_walker(struct thread *t)
+void ospf_lsa_refresh_walker(struct event *t)
{
struct list *refresh_list;
struct listnode *node, *nnode;
- struct ospf *ospf = THREAD_ARG(t);
+ struct ospf *ospf = EVENT_ARG(t);
struct ospf_lsa *lsa;
int i;
struct list *lsa_to_refresh = list_new();
+ bool dna_lsa;
if (IS_DEBUG_OSPF(lsa, LSA_REFRESH))
zlog_debug("LSA[Refresh]: %s: start", __func__);
}
ospf->t_lsa_refresher = NULL;
- thread_add_timer(master, ospf_lsa_refresh_walker, ospf,
- ospf->lsa_refresh_interval, &ospf->t_lsa_refresher);
+ event_add_timer(master, ospf_lsa_refresh_walker, ospf,
+ ospf->lsa_refresh_interval, &ospf->t_lsa_refresher);
ospf->lsa_refresher_started = monotime(NULL);
for (ALL_LIST_ELEMENTS(lsa_to_refresh, node, nnode, lsa)) {
- ospf_lsa_refresh(ospf, lsa);
+ dna_lsa = ospf_check_dna_lsa(lsa);
+ if (!dna_lsa) { /* refresh only non-DNA LSAs */
+ ospf_lsa_refresh(ospf, lsa);
+ }
assert(lsa->lock > 0);
- ospf_lsa_unlock(
- &lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/
+ ospf_lsa_unlock(&lsa); /* lsa_refresh_queue & temp for
+ * lsa_to_refresh.
+ */
}
list_delete(&lsa_to_refresh);