]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospfd/ospf_lsa.c
Merge pull request #13060 from opensourcerouting/feature/allow_peering_with_127.0.0.1
[mirror_frr.git] / ospfd / ospf_lsa.c
index 3e8b7b283d0df48e5c61e4b59f2677c611605bb3..82f7b96fd508049cfdf8b67011ffa7bc0c60b716 100644 (file)
@@ -1,22 +1,7 @@
+// 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>
@@ -29,7 +14,7 @@
 #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"
@@ -53,7 +38,7 @@
 #include "ospfd/ospf_abr.h"
 #include "ospfd/ospf_errors.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,
@@ -85,6 +70,16 @@ uint32_t get_metric(uint8_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)
 {
@@ -136,6 +131,16 @@ int get_age(struct ospf_lsa *lsa)
 {
        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;
 }
@@ -737,9 +742,9 @@ void ospf_router_lsa_body_set(struct stream **s, struct ospf_area *area)
        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;
 
@@ -1134,6 +1139,10 @@ static struct ospf_lsa *ospf_network_lsa_refresh(struct ospf_lsa *lsa)
                }
                return NULL;
        }
+
+       if (oi->state != ISM_DR)
+               return NULL;
+
        /* Delete LSA from neighbor retransmit-list. */
        ospf_ls_retransmit_delete_nbr_area(area, lsa);
 
@@ -1274,23 +1283,24 @@ ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
        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) {
@@ -1318,19 +1328,19 @@ static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
 
        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. */
@@ -1349,8 +1359,8 @@ struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
                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. */
@@ -1512,7 +1522,7 @@ struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
                        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. */
@@ -1533,10 +1543,15 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
        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),
@@ -1551,6 +1566,9 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
        /* 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);
@@ -3024,9 +3042,9 @@ int ospf_check_nbr_status(struct ospf *ospf)
 }
 
 
-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;
@@ -3056,7 +3074,7 @@ void ospf_maxage_lsa_remover(struct thread *thread)
                        }
 
                        /* 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(
@@ -3272,9 +3290,9 @@ static int ospf_lsa_maxage_walker_remover(struct ospf *ospf,
 }
 
 /* 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;
@@ -3634,13 +3652,56 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
         * 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)
@@ -3777,11 +3838,11 @@ struct lsa_action {
        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",
@@ -3809,7 +3870,7 @@ void ospf_schedule_lsa_flood_area(struct ospf_area *area, struct ospf_lsa *lsa)
        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)
@@ -3821,7 +3882,7 @@ 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);
 }
 
 
@@ -3968,14 +4029,15 @@ void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
        }
 }
 
-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__);
@@ -4029,15 +4091,19 @@ void ospf_lsa_refresh_walker(struct thread *t)
        }
 
        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);