]> git.proxmox.com Git - mirror_frr.git/commitdiff
ospfd: Core logic implementation.
authorManoj Naragund <mnaragund@vmware.com>
Mon, 21 Nov 2022 12:50:16 +0000 (04:50 -0800)
committerManoj Naragund <mnaragund@vmware.com>
Fri, 20 Jan 2023 05:03:03 +0000 (21:03 -0800)
Description:
Code changes involves.
1. Count the no.of router LSAs received with DC options bit set,
   supporting do not age(DNA).
2. If no of router LSAs received with DC bit set is equal to total
   no of LSAs in the router lsdb, then all the routers in the
   area support do not age processing.
3. Flood the self originated LSAs with DNA flag if all routers in the area
   supports the feature.
4. Stop aging of the LSAs recived with DO_NOT_AGE bit set from
   other routers.
5. Self originated DO_NOT_AGE lsas will still be aging in their own
   database.

Signed-off-by: Manoj Naragund <mnaragund@vmware.com>
ospfd/ospf_flood.c
ospfd/ospf_flood.h
ospfd/ospf_lsa.c
ospfd/ospf_lsdb.c

index 4bbeee2d74d587aaa7e0eacc8f9ab5f93da597ee..e3896b4535bcfa1da644668a1a5600bbb65b6169 100644 (file)
 
 extern struct zclient *zclient;
 
+/** @brief Function to refresh type-5 and type-7 DNA
+ *        LSAs when we receive an indication LSA.
+ *  @param Ospf instance.
+ *  @return Void.
+ */
+void ospf_refresh_dna_type5_and_type7_lsas(struct ospf *ospf)
+{
+       struct route_node *rn;
+       struct ospf_lsa *lsa = NULL;
+
+       LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
+               if (IS_LSA_SELF(lsa) &&
+                   CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE))
+                       ospf_lsa_refresh(ospf, lsa);
+
+       LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
+               if (IS_LSA_SELF(lsa) &&
+                   CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE))
+                       ospf_lsa_refresh(ospf, lsa);
+}
+
+/** @brief Function to update area flood reduction states.
+ *  @param area pointer.
+ *  @return Void.
+ */
+void ospf_area_update_fr_state(struct ospf_area *area)
+{
+       unsigned int count_router_lsas = 0;
+
+       if (area == NULL)
+               return;
+
+       count_router_lsas =
+               (unsigned int)(ospf_lsdb_count(area->lsdb, OSPF_ROUTER_LSA) -
+                              ospf_lsdb_count_self(area->lsdb,
+                                                   OSPF_ROUTER_LSA));
+
+       if (count_router_lsas >
+           (unsigned int)area->fr_info.router_lsas_recv_dc_bit) {
+               area->fr_info.enabled = false;
+               area->fr_info.area_dc_clear = true;
+               return;
+       } else if (count_router_lsas <
+                  (unsigned int)area->fr_info.router_lsas_recv_dc_bit) {
+               /* This can never happen, total number of router lsas received
+                * can never be less than router lsas received with dc bit set
+                */
+               OSPF_LOG_ERR("%s: Counter mismatch for area %pI4", __func__,
+                            &area->area_id);
+               OSPF_LOG_ERR(
+                       "%s: router LSAs in lsdb %d router LSAs recvd with dc bit set %d",
+                       __func__, count_router_lsas,
+                       area->fr_info.router_lsas_recv_dc_bit);
+               return;
+       }
+
+       area->fr_info.area_dc_clear = false;
+
+       if (OSPF_FR_CONFIG(area->ospf, area)) {
+               if (!area->fr_info.enabled) {
+                       area->fr_info.enabled = true;
+                       area->fr_info.state_changed = true;
+               }
+       } else {
+               area->fr_info.enabled = false;
+               area->fr_info.area_dc_clear = true;
+       }
+}
+
 /* 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. */
@@ -428,6 +497,55 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr,
        if (!(new = ospf_lsa_install(ospf, oi, new)))
                return -1; /* unknown LSA type or any other error condition */
 
+       /* check if the installed LSA is an indication LSA */
+       if (ospf_check_indication_lsa(new) && !IS_LSA_SELF(new) &&
+           !IS_LSA_MAXAGE(new)) {
+               new->area->fr_info.area_ind_lsa_recvd = true;
+               /* check if there are already type 5 LSAs originated
+                * with DNA bit set, if yes reoriginate those LSAs.
+                */
+               ospf_refresh_dna_type5_and_type7_lsas(ospf);
+       }
+
+       /* Check if we recived an indication LSA flush on backbone
+        * network.
+        */
+       ospf_recv_indication_lsa_flush(new);
+
+       if (new->area && OSPF_FR_CONFIG(ospf, new->area)) {
+               struct lsa_header const *lsah = new->data;
+
+               if (!CHECK_FLAG(lsah->options, OSPF_OPTION_DC) &&
+                   !ospf_check_indication_lsa(new)) {
+
+                       new->area->fr_info.area_dc_clear = true;
+                       /* check of previously area supported flood reduction */
+                       if (new->area->fr_info.enabled) {
+                               new->area->fr_info.enabled = false;
+                               OSPF_LOG_DEBUG(
+                                       IS_DEBUG_OSPF_EVENT,
+                                       "Flood Reduction STATE on -> off by %s LSA",
+                                       dump_lsa_key(new));
+                               /* if yes update all the lsa to the area the
+                                * new LSAs will have DNA bit set to 0.
+                                */
+                               ospf_refresh_area_self_lsas(new->area);
+                       }
+               } else if (!new->area->fr_info.enabled) {
+                       /* check again after installing new LSA that area
+                        * supports flood reduction.
+                        */
+                       ospf_area_update_fr_state(new->area);
+                       if (new->area->fr_info.enabled) {
+                               OSPF_LOG_DEBUG(
+                                       IS_DEBUG_OSPF_EVENT,
+                                       "Flood Reduction STATE off -> on by %s LSA",
+                                       dump_lsa_key(new));
+                               ospf_refresh_area_self_lsas(new->area);
+                       }
+               }
+       }
+
        /* Acknowledge the receipt of the LSA by sending a Link State
           Acknowledgment packet back out the receiving interface. */
        if (lsa_ack_flag)
@@ -465,6 +583,25 @@ int ospf_flood_through_interface(struct ospf_interface *oi,
        if (!ospf_if_is_enable(oi))
                return 0;
 
+       /* If flood reduction is configured, set the DC bit on the lsa. */
+       if (IS_LSA_SELF(lsa)) {
+               if (OSPF_FR_CONFIG(oi->area->ospf, oi->area)) {
+                       if (!ospf_check_indication_lsa(lsa)) {
+                               SET_FLAG(lsa->data->options, OSPF_OPTION_DC);
+                               ospf_lsa_checksum(lsa->data);
+                       }
+               } else if (CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC)) {
+                       UNSET_FLAG(lsa->data->options, OSPF_OPTION_DC);
+                       ospf_lsa_checksum(lsa->data);
+               }
+
+               /* If flood reduction is enabled then set DNA bit on the
+                * self lsas.
+                */
+               if (oi->area->fr_info.enabled)
+                       SET_FLAG(lsa->data->ls_age, DO_NOT_AGE);
+       }
+
        /* Remember if new LSA is added to a retransmit list. */
        retx_flag = 0;
 
index 95a5b358c98370f6783ee0ad8995d546ade1fa5f..dd8b6b7fccf382579d16718bff61e394cd880519 100644 (file)
@@ -68,5 +68,7 @@ extern struct external_info *ospf_external_info_check(struct ospf *,
                                                      struct ospf_lsa *);
 
 extern void ospf_lsdb_init(struct ospf_lsdb *);
+extern void ospf_area_update_fr_state(struct ospf_area *area);
+extern void ospf_refresh_dna_type5_and_type7_lsas(struct ospf *ospf);
 
 #endif /* _ZEBRA_OSPF_FLOOD_H */
index 3e8b7b283d0df48e5c61e4b59f2677c611605bb3..b3d866f5eb4f14742256be5e002762be293f2c44 100644 (file)
@@ -85,6 +85,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 +146,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;
 }
@@ -1134,6 +1154,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);
 
@@ -1533,10 +1557,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 +1580,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);
@@ -3641,6 +3673,49 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
        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)
@@ -3976,6 +4051,7 @@ void ospf_lsa_refresh_walker(struct thread *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__);
@@ -4034,10 +4110,14 @@ void ospf_lsa_refresh_walker(struct thread *t)
        ospf->lsa_refresher_started = monotime(NULL);
 
        for (ALL_LIST_ELEMENTS(lsa_to_refresh, node, nnode, lsa)) {
-               ospf_lsa_refresh(ospf, lsa);
-               assert(lsa->lock > 0);
-               ospf_lsa_unlock(
-                       &lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/
+               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.
+                                               */
+               }
        }
 
        list_delete(&lsa_to_refresh);
index f4fb858a5f4b2fbb0ca2e7dae7e3e9a26ccea75e..d55705b7415774935bc2a4ab51f7b8a259a1841c 100644 (file)
@@ -92,6 +92,21 @@ static void ospf_lsdb_delete_entry(struct ospf_lsdb *lsdb,
        lsdb->type[lsa->data->type].count--;
        lsdb->type[lsa->data->type].checksum -= ntohs(lsa->data->checksum);
        lsdb->total--;
+
+       /* Decrement number of router LSAs received with DC bit set */
+       if (lsa->area && (lsa->area->lsdb == lsdb) && !IS_LSA_SELF(lsa) &&
+           (lsa->data->type == OSPF_ROUTER_LSA) &&
+           CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC))
+               lsa->area->fr_info.router_lsas_recv_dc_bit--;
+
+       /*
+        * If the LSA being deleted is indication LSA, then set the
+        * pointer to NULL.
+        */
+       if (lsa->area && lsa->area->fr_info.indication_lsa_self &&
+           (lsa->area->fr_info.indication_lsa_self == lsa))
+               lsa->area->fr_info.indication_lsa_self = NULL;
+
        rn->info = NULL;
        route_unlock_node(rn);
 #ifdef MONITOR_LSDB_CHANGE
@@ -128,6 +143,12 @@ void ospf_lsdb_add(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
        lsdb->type[lsa->data->type].count++;
        lsdb->total++;
 
+       /* Increment number of router LSAs received with DC bit set */
+       if (lsa->area && (lsa->area->lsdb == lsdb) && !IS_LSA_SELF(lsa) &&
+           (lsa->data->type == OSPF_ROUTER_LSA) &&
+           CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC))
+               lsa->area->fr_info.router_lsas_recv_dc_bit++;
+
 #ifdef MONITOR_LSDB_CHANGE
        if (lsdb->new_lsa_hook != NULL)
                (*lsdb->new_lsa_hook)(lsa);