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. */
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)
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;
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 */
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;
}
}
return NULL;
}
+
+ if (oi->state != ISM_DR)
+ return NULL;
+
/* Delete LSA from neighbor retransmit-list. */
ospf_ls_retransmit_delete_nbr_area(area, lsa);
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);
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;
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->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);
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
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);