summaryrefslogtreecommitdiffstats
path: root/ospfd
diff options
context:
space:
mode:
authorrgirada <rgirada@vmware.com>2022-01-05 18:45:33 +0100
committerrgirada <rgirada@vmware.com>2022-01-22 13:07:59 +0100
commita8c22275fecfd10f0f2cd8d56b74f9701b6709ce (patch)
treedd8ea4414b94787908f6096dc6d5e0ffc0004e67 /ospfd
parentMerge pull request #10398 from patrasar/pim_debug_fix (diff)
downloadfrr-a8c22275fecfd10f0f2cd8d56b74f9701b6709ce.tar.xz
frr-a8c22275fecfd10f0f2cd8d56b74f9701b6709ce.zip
ospfd: Modifying LSID generation algorithm
Description: This LSID alogithm added as per rcf2328 Appendex-E recommendation. This applies only for AS-external lsas and summary lsas. As an example of the algorithm, consider its operation when the following sequence of events occurs in a single router (Router A). (1) Router A wants to originate an AS-external-LSA for [10.0.0.0,255.255.255.0]: (a) A Link State ID of 10.0.0.0 is used. (2) Router A then wants to originate an AS-external-LSA for [10.0.0.0,255.255.0.0]: (a) The LSA for [10.0.0,0,255.255.255.0] is reoriginated using a new Link State ID of 10.0.0.255. (b) A Link State ID of 10.0.0.0 is used for [10.0.0.0,255.255.0.0]. (3) Router A then wants to originate an AS-external-LSA for [10.0.0.0,255.0.0.0]: (a) The LSA for [10.0.0.0,255.255.0.0] is reoriginated using a new Link State ID of 10.0.255.255. (b) A Link State ID of 10.0.0.0 is used for [10.0.0.0,255.0.0.0]. (c) The network [10.0.0.0,255.255.255.0] keeps its Link State ID of 10.0.0.255. Signed-off-by: Rajesh Girada <rgirada@vmware.com>
Diffstat (limited to 'ospfd')
-rw-r--r--ospfd/ospf_asbr.c9
-rw-r--r--ospfd/ospf_lsa.c405
-rw-r--r--ospfd/ospf_lsa.h8
3 files changed, 321 insertions, 101 deletions
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 000c62e30..b9878ef7e 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -223,8 +223,15 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf,
id.s_addr = p->prefix.s_addr | (~mask.s_addr);
lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, id,
ospf->router_id);
- if (lsa)
+ if (lsa) {
+ if (p->prefixlen == IPV4_MAX_BITLEN) {
+ al = (struct as_external_lsa *)lsa->data;
+
+ if (mask.s_addr != al->mask.s_addr)
+ return NULL;
+ }
return lsa;
+ }
lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
p->prefix, ospf->router_id);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 6588d7020..39abf358e 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -53,6 +53,29 @@
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_errors.h"
+static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
+ struct prefix_ipv4 *p,
+ uint8_t type,
+ uint32_t metric,
+ struct in_addr old_id);
+static struct ospf_lsa *
+ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area, struct in_addr id);
+static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf,
+ struct ospf_lsa *lsa);
+static struct ospf_lsa *
+ospf_asbr_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area,
+ struct in_addr id);
+static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
+ struct ospf_lsa *lsa);
+static struct ospf_lsa *ospf_handle_exnl_lsa_lsId_chg(struct ospf *ospf,
+ struct external_info *ei,
+ struct in_addr id);
+static struct ospf_lsa *
+ospf_exnl_lsa_prepare_and_flood(struct ospf *ospf, struct external_info *ei,
+ struct in_addr id);
+
uint32_t get_metric(uint8_t *metric)
{
uint32_t m;
@@ -1221,31 +1244,11 @@ static struct ospf_lsa *ospf_summary_lsa_new(struct ospf_area *area,
}
/* Originate Summary-LSA. */
-struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
- uint32_t metric,
- struct ospf_area *area)
+static struct ospf_lsa *
+ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area, struct in_addr id)
{
struct ospf_lsa *new;
- struct in_addr id;
-
- if (area->ospf->gr_info.restart_in_progress) {
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Graceful Restart in progress, don't originate",
- OSPF_SUMMARY_LSA);
- return NULL;
- }
-
- id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p);
-
- if (id.s_addr == 0xffffffff) {
- /* Maybe Link State ID not available. */
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Link ID not available, can't originate",
- OSPF_SUMMARY_LSA);
- return NULL;
- }
/* Create new summary-LSA instance. */
if (!(new = ospf_summary_lsa_new(area, (struct prefix *)p, metric, id)))
@@ -1270,6 +1273,97 @@ struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
return new;
}
+static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
+ 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 summary_lsa *sl = NULL;
+ struct ospf_area *old_area = NULL;
+ 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,
+ ospf->router_id);
+
+ if (!lsa) {
+ flog_warn(EC_OSPF_LSA_NULL, "(%s): LSA not found", __func__);
+ return NULL;
+ }
+
+ sl = (struct summary_lsa *)lsa->data;
+
+ old_area = lsa->area;
+ old_metric = GET_METRIC(sl->metric);
+ old_prefix.prefix = sl->header.id;
+ old_prefix.prefixlen = ip_masklen(sl->mask);
+ old_prefix.family = AF_INET;
+
+
+ /* change the mask */
+ masklen2ip(p->prefixlen, &mask);
+ sl->mask.s_addr = mask.s_addr;
+
+ /* Copy the metric*/
+ metric_val = htonl(metric);
+ metric_buf = (char *)&metric_val;
+ memcpy(sl->metric, metric_buf, sizeof(metric_val));
+
+ if (type == OSPF_SUMMARY_LSA) {
+ /*Refresh the LSA with new LSA*/
+ ospf_summary_lsa_refresh(ospf, lsa);
+
+ new = 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);
+
+ new = ospf_asbr_summary_lsa_prepare_and_flood(
+ &old_prefix, old_metric, old_area, old_id);
+ }
+
+ return new;
+}
+
+/* Originate Summary-LSA. */
+struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
+ uint32_t metric,
+ struct ospf_area *area)
+{
+ struct in_addr id;
+ enum lsid_status status;
+ struct ospf_lsa *new = NULL;
+
+ status = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p,
+ &id);
+
+ if (status == LSID_CHANGE) {
+ 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);
+ return new;
+ } else if (status == LSID_NOT_AVAILABLE) {
+ /* Link State ID not available. */
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: Link ID not available, can't originate");
+
+ return NULL;
+ }
+
+ new = ospf_summary_lsa_prepare_and_flood(p, metric, area, id);
+ return new;
+}
+
static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf,
struct ospf_lsa *lsa)
{
@@ -1370,32 +1464,12 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_new(struct ospf_area *area,
}
/* Originate summary-ASBR-LSA. */
-struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
- uint32_t metric,
- struct ospf_area *area)
+static struct ospf_lsa *
+ospf_asbr_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area,
+ struct in_addr id)
{
struct ospf_lsa *new;
- struct in_addr id;
-
- if (area->ospf->gr_info.restart_in_progress) {
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Graceful Restart in progress, don't originate",
- OSPF_ASBR_SUMMARY_LSA);
- return NULL;
- }
-
- id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_ASBR_SUMMARY_LSA,
- p);
-
- if (id.s_addr == 0xffffffff) {
- /* Maybe Link State ID not available. */
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Link ID not available, can't originate",
- OSPF_ASBR_SUMMARY_LSA);
- return NULL;
- }
/* Create new summary-LSA instance. */
new = ospf_summary_asbr_lsa_new(area, (struct prefix *)p, metric, id);
@@ -1421,6 +1495,37 @@ struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
return new;
}
+struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
+ uint32_t metric,
+ struct ospf_area *area)
+{
+ struct ospf_lsa *new;
+ struct in_addr id;
+ enum lsid_status status;
+
+ status = ospf_lsa_unique_id(area->ospf, area->lsdb,
+ OSPF_ASBR_SUMMARY_LSA, p, &id);
+
+ if (status == LSID_CHANGE) {
+ 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_ASBR_SUMMARY_LSA, metric, id);
+ return new;
+ } else if (status == LSID_NOT_AVAILABLE) {
+ /* Link State ID not available. */
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: Link ID not available, can't originate");
+
+ return NULL;
+ }
+
+ new = ospf_asbr_summary_lsa_prepare_and_flood(p, metric, area, id);
+ return new;
+}
+
static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
struct ospf_lsa *lsa)
{
@@ -1612,42 +1717,15 @@ static void ospf_external_lsa_body_set(struct stream *s,
}
/* Create new external-LSA. */
-static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf,
- struct external_info *ei,
- struct in_addr *old_id)
+static struct ospf_lsa *
+ospf_exnl_lsa_prepare_and_flood(struct ospf *ospf, struct external_info *ei,
+ struct in_addr id)
{
struct stream *s;
struct lsa_header *lsah;
struct ospf_lsa *new;
- struct in_addr id;
int length;
- if (ei == NULL) {
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type5]: External info is NULL, can't originate");
- return NULL;
- }
-
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug("LSA[Type5]: Originate AS-external-LSA instance");
-
- /* If old Link State ID is specified, refresh LSA with same ID. */
- if (old_id)
- id = *old_id;
- /* Get Link State with unique ID. */
- else {
- id = ospf_lsa_unique_id(ospf, ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
- &ei->p);
- if (id.s_addr == 0xffffffff) {
- /* Maybe Link State ID not available. */
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type5]: Link ID not available, can't originate");
- return NULL;
- }
- }
-
/* Create new stream for LSA. */
s = stream_new(OSPF_MAX_LSA_SIZE);
lsah = (struct lsa_header *)STREAM_DATA(s);
@@ -1677,6 +1755,99 @@ static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf,
return new;
}
+static struct ospf_lsa *ospf_handle_exnl_lsa_lsId_chg(struct ospf *ospf,
+ struct external_info *ei,
+ struct in_addr id)
+{
+ struct ospf_lsa *lsa;
+ struct as_external_lsa *al;
+ struct in_addr mask;
+ struct ospf_lsa *new;
+ struct external_info ei_summary;
+ struct external_info *ei_old;
+
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
+ ei->p.prefix, ospf->router_id);
+
+ if (!lsa) {
+ flog_warn(EC_OSPF_LSA_NULL, "(%s): LSA not found", __func__);
+ return NULL;
+ }
+
+ ei_old = ospf_external_info_check(ospf, lsa);
+
+ al = (struct as_external_lsa *)lsa->data;
+
+ if (!ei_old) {
+ /* eii_old pointer of LSA is NULL, this
+ * must be external aggregate route.
+ */
+ ei_summary.p.family = AF_INET;
+ ei_summary.p.prefix = al->header.id;
+ ei_summary.p.prefixlen = ip_masklen(al->mask);
+ ei_summary.tag = (unsigned long)ntohl(al->e[0].route_tag);
+ ei_old = &ei_summary;
+ }
+
+ /* change the mask */
+ masklen2ip(ei->p.prefixlen, &mask);
+ al->mask.s_addr = mask.s_addr;
+
+ /*Refresh the LSA with new LSA*/
+ ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 0);
+
+ /*Originate the old LSA with changed LSID*/
+ new = ospf_exnl_lsa_prepare_and_flood(ospf, ei_old, id);
+
+ return new;
+}
+
+static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf,
+ struct external_info *ei,
+ struct in_addr *old_id)
+{
+ struct ospf_lsa *new;
+ struct in_addr id;
+ enum lsid_status status;
+
+ if (ei == NULL) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: External info is NULL, can't originate");
+ return NULL;
+ }
+
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug("LSA[Type5]: Originate AS-external-LSA instance");
+
+ /* If old Link State ID is specified, refresh LSA with same ID. */
+ if (old_id)
+ id = *old_id;
+ /* Get Link State with unique ID. */
+ else {
+ status = ospf_lsa_unique_id(ospf, ospf->lsdb,
+ OSPF_AS_EXTERNAL_LSA, &ei->p, &id);
+
+ if (status == LSID_CHANGE) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug("Link ID has to be changed.");
+
+ new = ospf_handle_exnl_lsa_lsId_chg(ospf, ei, id);
+ return new;
+ } else if (status == LSID_NOT_AVAILABLE) {
+ /* Link State ID not available. */
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: Link ID not available, can't originate");
+ return NULL;
+ }
+ }
+
+ new = ospf_exnl_lsa_prepare_and_flood(ospf, ei, id);
+
+ return new;
+}
+
/* As Type-7 */
static void ospf_install_flood_nssa(struct ospf *ospf, struct ospf_lsa *lsa,
struct external_info *ei)
@@ -3510,49 +3681,87 @@ int ospf_lsa_is_self_originated(struct ospf *ospf, struct ospf_lsa *lsa)
}
/* Get unique Link State ID. */
-struct in_addr ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb,
- uint8_t type, struct prefix_ipv4 *p)
+enum lsid_status ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb,
+ uint8_t type, struct prefix_ipv4 *p,
+ struct in_addr *id)
{
struct ospf_lsa *lsa;
- struct in_addr mask, id;
+ struct in_addr mask;
- id = p->prefix;
+ *id = p->prefix;
/* Check existence of LSA instance. */
- lsa = ospf_lsdb_lookup_by_id(lsdb, type, id, ospf->router_id);
+ lsa = ospf_lsdb_lookup_by_id(lsdb, type, *id, ospf->router_id);
if (lsa) {
struct as_external_lsa *al =
(struct as_external_lsa *)lsa->data;
+ /* Ref rfc2328,Appendex E.1
+ * If router already originated the external lsa with lsid
+ * as the current prefix, and the masklens are same then
+ * terminate the LSID algorithem.
+ */
if (ip_masklen(al->mask) == p->prefixlen) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug(
- "ospf_lsa_unique_id(): Can't get Link State ID for %pFX",
- p);
+ "%s: Can't get Link State ID for %pFX",
+ __func__, p);
/* id.s_addr = 0; */
- id.s_addr = 0xffffffff;
- return id;
- }
- /* Masklen differs, then apply wildcard mask to Link State ID.
- */
- else {
+ id->s_addr = 0xffffffff;
+ return LSID_NOT_AVAILABLE;
+ } else if (ip_masklen(al->mask) < p->prefixlen) {
+ /* Ref rfc2328,Appendex E.2
+ * the current prefix masklen is greater than the
+ * existing LSA, then generate the Link state ID,
+ * by setting all host bits in prefix addressa and
+ * originate.
+ *
+ * Eg: 1st Route : 10.0.0.0/16 - LSID:10.0.0.0
+ * 2nd Route : 10.0.0.0/24 - LSID:10.0.0.255
+ */
masklen2ip(p->prefixlen, &mask);
- id.s_addr = p->prefix.s_addr | (~mask.s_addr);
- lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, id,
+ id->s_addr = p->prefix.s_addr | (~mask.s_addr);
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, *id,
ospf->router_id);
if (lsa) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug(
- "ospf_lsa_unique_id(): Can't get Link State ID for %pFX",
- p);
- /* id.s_addr = 0; */
- id.s_addr = 0xffffffff;
- return id;
+ "%s: Can't get Link State ID for %pFX",
+ __func__, p);
+ id->s_addr = 0xffffffff;
+ return LSID_NOT_AVAILABLE;
+ }
+ } else {
+ /* Ref rfc2328,Appendex E.3
+ * the current prefix masklen is lesser than the
+ * existing LSA,then the originated LSA has to be
+ * refreshed by modifying masklen, cost and tag.
+ * Originate the old route info with new LSID by
+ * setting the host bits in prefix address.
+ *
+ * Eg: 1st Route : 10.0.0.0/24 - LSID:10.0.0.0
+ * 2nd Route : 10.0.0.0/16 - ?
+ * Since 2nd route mask len is less than firstone
+ * LSID has to be changed.
+ * 1st route LSID:10.0.0.255
+ * 2nd route LSID:10.0.0.0
+ */
+ id->s_addr = lsa->data->id.s_addr | (~al->mask.s_addr);
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, *id,
+ ospf->router_id);
+ if (lsa && (ip_masklen(al->mask) != IPV4_MAX_BITLEN)) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "%s: Can't get Link State ID for %pFX",
+ __func__, p);
+ id->s_addr = 0xffffffff;
+ return LSID_NOT_AVAILABLE;
}
+ return LSID_CHANGE;
}
}
- return id;
+ return LSID_AVAILABLE;
}
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index a97957371..d04d11841 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -208,6 +208,8 @@ struct as_external_lsa {
} e[1];
};
+enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
+
#include "ospfd/ospf_opaque.h"
/* Macros. */
@@ -317,8 +319,10 @@ extern struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *,
struct ospf_lsa *,
struct external_info *, int,
bool aggr);
-extern struct in_addr ospf_lsa_unique_id(struct ospf *, struct ospf_lsdb *,
- uint8_t, struct prefix_ipv4 *);
+extern enum lsid_status ospf_lsa_unique_id(struct ospf *ospf,
+ struct ospf_lsdb *lsdb,
+ uint8_t type, struct prefix_ipv4 *p,
+ struct in_addr *addr);
extern void ospf_schedule_lsa_flood_area(struct ospf_area *, struct ospf_lsa *);
extern void ospf_schedule_lsa_flush_area(struct ospf_area *, struct ospf_lsa *);