Merge pull request #12366 from manojvn/ospfv2-flood-reduction

ospfd: Support OSPF Refresh and Flooding Reduction RFC4136.
This commit is contained in:
Russ White 2023-02-21 08:03:06 -05:00 committed by GitHub
commit 62bd2580e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2774 additions and 134 deletions

View File

@ -114,6 +114,21 @@ extern int proto_redistnum(int afi, const char *s);
extern const char *zserv_command_string(unsigned int command);
#define OSPF_LOG(level, cond, fmt, ...) \
do { \
if (cond) \
zlog_##level(fmt, ##__VA_ARGS__); \
} while (0)
#define OSPF_LOG_ERR(fmt, ...) OSPF_LOG(err, true, fmt, ##__VA_ARGS__)
#define OSPF_LOG_WARN(fmt, ...) OSPF_LOG(warn, true, fmt, ##__VA_ARGS__)
#define OSPF_LOG_INFO(fmt, ...) OSPF_LOG(info, true, fmt, ##__VA_ARGS__)
#define OSPF_LOG_DEBUG(cond, fmt, ...) OSPF_LOG(debug, cond, fmt, ##__VA_ARGS__)
#define OSPF_LOG_NOTICE(fmt, ...) OSPF_LOG(notice, true, fmt, ##__VA_ARGS__)
/* structure useful for avoiding repeated rendering of the same timestamp */
struct timestamp_control {

View File

@ -1559,6 +1559,254 @@ static void ospf_abr_announce_stub_defaults(struct ospf *ospf)
zlog_debug("%s: Stop", __func__);
}
/** @brief Function to check and generate indication
* LSA for area on which we received
* indication LSA flush.
* @param Ospf instance.
* @param Area on which indication lsa flush is to be generated.
* @return Void.
*/
void ospf_generate_indication_lsa(struct ospf *ospf, struct ospf_area *area)
{
bool area_fr_not_supp = false;
/* Check if you have any area which doesn't support
* flood reduction.
*/
area_fr_not_supp = ospf_check_fr_enabled_all(ospf) ? false : true;
/* If any one of the area doestn't support FR, generate
* indication LSA on behalf of that area.
*/
if (area_fr_not_supp && !area->fr_info.area_ind_lsa_recvd &&
!area->fr_info.indication_lsa_self &&
!area->fr_info.area_dc_clear) {
struct prefix_ipv4 p;
struct ospf_lsa *new;
p.family = AF_INET;
p.prefix = ospf->router_id;
p.prefixlen = IPV4_MAX_BITLEN;
new = ospf_summary_asbr_lsa_originate(&p, OSPF_LS_INFINITY,
area);
if (!new) {
zlog_debug("%s: Indication lsa originate failed",
__func__);
return;
}
/* save the indication lsa for that area */
area->fr_info.indication_lsa_self = new;
}
}
/** @brief Function to receive and process indication LSA
* flush from area.
* @param lsa being flushed.
* @return Void.
*/
void ospf_recv_indication_lsa_flush(struct ospf_lsa *lsa)
{
if (!IS_LSA_SELF(lsa) && IS_LSA_MAXAGE(lsa) &&
ospf_check_indication_lsa(lsa)) {
lsa->area->fr_info.area_ind_lsa_recvd = false;
OSPF_LOG_INFO("%s: Received an ind lsa: %pI4 area %pI4",
__func__, &lsa->data->id, &lsa->area->area_id);
if (!IS_OSPF_ABR(lsa->area->ospf))
return;
/* If the LSA received is a indication LSA with maxage on
* the network, then check and regenerate indication
* LSA if any of our areas don't support flood reduction.
*/
ospf_generate_indication_lsa(lsa->area->ospf, lsa->area);
}
}
/** @brief Function to generate indication LSAs.
* @param Ospf instance.
* @param Area on behalf of which indication
* LSA is generated LSA.
* @return Void.
*/
void ospf_abr_generate_indication_lsa(struct ospf *ospf,
const struct ospf_area *area)
{
struct ospf_lsa *new;
struct listnode *node;
struct ospf_area *o_area;
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, o_area)) {
if (o_area == area)
continue;
if (o_area->fr_info.indication_lsa_self ||
o_area->fr_info.area_ind_lsa_recvd ||
o_area->fr_info.area_dc_clear) {
/* if the area has already received an
* indication LSA or if area already has
* LSAs with DC bit 0 other than
* indication LSA then don't generate
* indication LSA in those areas.
*/
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"Area %pI4 has LSAs with dc bit clear",
&o_area->area_id);
continue;
} else {
struct prefix_ipv4 p;
p.family = AF_INET;
p.prefix = ospf->router_id;
p.prefixlen = IPV4_MAX_BITLEN;
new = ospf_summary_asbr_lsa_originate(
&p, OSPF_LS_INFINITY, o_area);
if (!new) {
zlog_debug(
"%s: Indication lsa originate Failed",
__func__);
return;
}
/* save the indication lsa for that area */
o_area->fr_info.indication_lsa_self = new;
}
}
}
/** @brief Flush the indication LSA from all the areas
* of ospf instance.
* @param Ospf instance.
* @return Void.
*/
void ospf_flush_indication_lsas(struct ospf *ospf)
{
struct ospf_area *area;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
if (area->fr_info.indication_lsa_self) {
OSPF_LOG_INFO(
"Flushing ind lsa: %pI4 area %pI4",
&area->fr_info.indication_lsa_self->data->id,
&area->area_id);
ospf_schedule_lsa_flush_area(
area, area->fr_info.indication_lsa_self);
area->fr_info.indication_lsa_self = NULL;
}
}
}
/** @brief Check if flood reduction is enabled on
* all the areas.
* @param Ospf instance.
* @return Void.
*/
bool ospf_check_fr_enabled_all(struct ospf *ospf)
{
const struct ospf_area *area;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
if (!ospf_check_area_fr_enabled(area))
return false;
return true;
}
/** @brief Abr function to check conditions for generation
* of indication. LSAs/announcing non-DNA routers
* in the area.
* @param thread
* @return 0.
*/
static void ospf_abr_announce_non_dna_routers(struct thread *thread)
{
struct ospf_area *area;
struct listnode *node;
struct ospf *ospf = THREAD_ARG(thread);
THREAD_OFF(ospf->t_abr_fr);
if (!IS_OSPF_ABR(ospf))
return;
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "%s(): Start", __func__);
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"%s: Area %pI4 FR enabled: %d", __func__,
&area->area_id, area->fr_info.enabled);
OSPF_LOG_DEBUG(
IS_DEBUG_OSPF_EVENT,
"LSA with DC bit clear: %d Recived indication LSA: %d",
area->fr_info.area_dc_clear,
area->fr_info.area_ind_lsa_recvd);
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "FR state change: %d",
area->fr_info.state_changed);
if (!OSPF_IS_AREA_BACKBONE(area) &&
area->fr_info.area_dc_clear) {
/* rfc4136 rfc1793: Suppose if the abr is connected to
* a regular non-backbone OSPF area, Furthermore if
* the area has LSAs with the DC-bit clear, other
* than indication-LSAs. Then originate indication-LSAs
* into all other directly-connected "regular" areas,
* including the backbone area.
*/
ospf_abr_generate_indication_lsa(ospf, area);
}
if (OSPF_IS_AREA_BACKBONE(area) &&
(area->fr_info.area_dc_clear ||
area->fr_info.area_ind_lsa_recvd)) {
/* rfc4136 rfc1793: Suppose if the abr is connected to
* backbone OSPF area. Furthermore, if backbone has
* LSAs with the DC-bit clear that are either
* a) not indication-LSAs or indication-LSAs or
* b) indication-LSAs that have been originated by
* other routers,
* then originate indication-LSAs into all other
* directly-connected "regular" non-backbone areas.
*/
ospf_abr_generate_indication_lsa(ospf, area);
}
if (area->fr_info.enabled && area->fr_info.state_changed &&
area->fr_info.indication_lsa_self) {
/* Ospf area flood reduction state changed
* area now supports flood reduction.
* check if all other areas support flood reduction
* if yes then flush indication LSAs generated in
* all the areas.
*/
if (ospf_check_fr_enabled_all(ospf))
ospf_flush_indication_lsas(ospf);
area->fr_info.state_changed = false;
}
/* If previously we had generated indication lsa
* but now area has lsas with dc bit set to 0
* apart from indication lsa, we'll clear indication lsa
*/
if (area->fr_info.area_dc_clear &&
area->fr_info.indication_lsa_self) {
ospf_schedule_lsa_flush_area(
area, area->fr_info.indication_lsa_self);
area->fr_info.indication_lsa_self = NULL;
}
}
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "%s(): Stop", __func__);
}
static int ospf_abr_remove_unapproved_translates_apply(struct ospf *ospf,
struct ospf_lsa *lsa)
{
@ -1613,9 +1861,13 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf)
ospf_lsa_flush_area(lsa, area);
LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
if (ospf_lsa_is_self_originated(ospf, lsa))
if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
ospf_lsa_flush_area(lsa, area);
if (ospf_lsa_is_self_originated(ospf, lsa) &&
!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED) &&
/* Do not remove indication LSAs while
* flushing unapproved summaries.
*/
!ospf_check_indication_lsa(lsa))
ospf_lsa_flush_area(lsa, area);
}
if (IS_DEBUG_OSPF_EVENT)
@ -1778,6 +2030,20 @@ void ospf_abr_task(struct ospf *ospf)
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: announce stub defaults", __func__);
ospf_abr_announce_stub_defaults(ospf);
if (ospf->fr_configured) {
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"%s(): announce non-DNArouters",
__func__);
/*
* Schedule indication lsa generation timer,
* giving time for route synchronization in
* all the routers.
*/
thread_add_timer(
master, ospf_abr_announce_non_dna_routers, ospf,
OSPF_ABR_DNA_TIMER, &ospf->t_abr_fr);
}
}
if (IS_DEBUG_OSPF_EVENT)

View File

@ -8,6 +8,11 @@
#define _ZEBRA_OSPF_ABR_H
#define OSPF_ABR_TASK_DELAY 5
#define OSPF_ABR_DNA_TIMER 10
/* Delay in announceing Non-DNA routers
* so that LSAs are completely synced
* before generating indication LSAs.
*/
#define OSPF_AREA_RANGE_ADVERTISE (1 << 0)
#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1)
@ -69,4 +74,20 @@ extern void ospf_schedule_abr_task(struct ospf *);
extern void ospf_abr_announce_network_to_area(struct prefix_ipv4 *, uint32_t,
struct ospf_area *);
extern void ospf_abr_nssa_check_status(struct ospf *ospf);
extern void ospf_abr_generate_indication_lsa(struct ospf *ospf,
const struct ospf_area *area);
extern void ospf_flush_indication_lsas(struct ospf *ospf);
extern void ospf_generate_indication_lsa(struct ospf *ospf,
struct ospf_area *area);
extern bool ospf_check_fr_enabled_all(struct ospf *ospf);
extern void ospf_recv_indication_lsa_flush(struct ospf_lsa *lsa);
/** @brief Static inline functions.
* @param Area pointer.
* @return area Flood Reduction status.
*/
static inline bool ospf_check_area_fr_enabled(const struct ospf_area *area)
{
return area->fr_info.enabled ? true : false;
}
#endif /* _ZEBRA_OSPF_ABR_H */

View File

@ -35,6 +35,75 @@
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. */
@ -413,6 +482,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)
@ -450,6 +568,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;

View File

@ -53,5 +53,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 */

View File

@ -70,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)
{
@ -121,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;
}
@ -1119,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);
@ -1518,10 +1542,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),
@ -1536,6 +1565,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);
@ -3626,6 +3658,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)
@ -3961,6 +4036,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__);
@ -4019,10 +4095,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);

View File

@ -45,6 +45,7 @@
/* OSPF LSA header. */
struct lsa_header {
uint16_t ls_age;
#define DO_NOT_AGE 0x8000
uint8_t options;
uint8_t type;
struct in_addr id;
@ -218,6 +219,9 @@ enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
|| (type == OSPF_SUMMARY_LSA) || (type == OSPF_ASBR_SUMMARY_LSA) \
|| (type == OSPF_AS_EXTERNAL_LSA) || (type == OSPF_AS_NSSA_LSA))
#define OSPF_FR_CONFIG(o, a) \
(o->fr_configured || ((a != NULL) ? a->fr_info.configured : 0))
/* Prototypes. */
/* XXX: Eek, time functions, similar are in lib/thread.c */
extern struct timeval int2tv(int);
@ -343,4 +347,24 @@ extern void ospf_check_and_gen_init_seq_lsa(struct ospf_interface *oi,
extern void ospf_flush_lsa_from_area(struct ospf *ospf, struct in_addr area_id,
int type);
extern void ospf_maxage_lsa_remover(struct thread *thread);
extern bool ospf_check_dna_lsa(const struct ospf_lsa *lsa);
extern void ospf_refresh_area_self_lsas(struct ospf_area *area);
/** @brief Check if the LSA is an indication LSA.
* @param lsa pointer.
* @return true or false based on lsa info.
*/
static inline bool ospf_check_indication_lsa(struct ospf_lsa *lsa)
{
struct summary_lsa *sl = NULL;
if (lsa->data->type == OSPF_ASBR_SUMMARY_LSA) {
sl = (struct summary_lsa *)lsa->data;
if ((GET_METRIC(sl->metric) == OSPF_LS_INFINITY) &&
!CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC))
return true;
}
return false;
}
#endif /* _ZEBRA_OSPF_LSA_H */

View File

@ -77,6 +77,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
@ -113,6 +128,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);

View File

@ -28,6 +28,7 @@
#include "ospfd/ospf_network.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_ism.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
@ -3317,6 +3318,14 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
else
stream_putw(s, 0); /* hello-interval of 0 for fast-hellos */
/* Check if flood-reduction is enabled,
* if yes set the DC bit in the options.
*/
if (OSPF_FR_CONFIG(oi->ospf, oi->area))
SET_FLAG(OPTIONS(oi), OSPF_OPTION_DC);
else if (CHECK_FLAG(OPTIONS(oi), OSPF_OPTION_DC))
UNSET_FLAG(OPTIONS(oi), OSPF_OPTION_DC);
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: options: %x, int: %s", __func__, OPTIONS(oi),
IF_NAME(oi));
@ -3405,6 +3414,8 @@ static int ospf_make_db_desc(struct ospf_interface *oi,
options = OPTIONS(oi);
if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE))
SET_FLAG(options, OSPF_OPTION_O);
if (OSPF_FR_CONFIG(oi->ospf, oi->area))
SET_FLAG(options, OSPF_OPTION_DC);
stream_putc(s, options);
/* DD flags */

View File

@ -980,6 +980,16 @@ void ospf_prune_unreachable_routers(struct route_table *rtrs)
&or->u.std.area_id);
}
/* Unset the DNA flag on lsa, if the router
* which generated this lsa is no longer
* reachabele.
*/
(CHECK_FLAG(or->u.std.origin->ls_age,
DO_NOT_AGE))
? UNSET_FLAG(or->u.std.origin->ls_age,
DO_NOT_AGE)
: 0;
listnode_delete(paths, or);
ospf_route_free(or);
}

View File

@ -3038,6 +3038,43 @@ static void show_ip_ospf_area(struct vty *vty, struct ospf_area *area,
ospf_lsdb_checksum(area->lsdb, OSPF_OPAQUE_AREA_LSA));
}
if (area->fr_info.configured) {
if (use_json)
json_object_string_add(json_area, "areaFloodReduction",
"configured");
else
vty_out(vty, " Flood Reduction is configured.\n");
}
if (area->fr_info.enabled) {
if (use_json) {
json_object_boolean_true_add(
json_area, "areaFloodReductionEnabled");
if (area->fr_info.router_lsas_recv_dc_bit)
json_object_boolean_true_add(
json_area, "lsasRecvDCbitSet");
if (area->fr_info.area_ind_lsa_recvd)
json_object_string_add(json_area,
"areaIndicationLsaRecv",
"received");
if (area->fr_info.indication_lsa_self)
json_object_string_addf(
json_area, "areaIndicationLsa", "%pI4",
&area->fr_info.indication_lsa_self->data
->id);
} else {
vty_out(vty, " Flood Reduction is enabled.\n");
vty_out(vty, " No of LSAs rcv'd with DC bit set %d\n",
area->fr_info.router_lsas_recv_dc_bit);
if (area->fr_info.area_ind_lsa_recvd)
vty_out(vty, " Ind LSA by other abr.\n");
if (area->fr_info.indication_lsa_self)
vty_out(vty, " Ind LSA generated %pI4\n",
&area->fr_info.indication_lsa_self->data
->id);
}
}
if (use_json)
json_object_object_add(json_areas,
inet_ntop(AF_INET, &area->area_id,
@ -3273,6 +3310,14 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
: ZEBRA_OSPF_DISTANCE_DEFAULT);
}
if (ospf->fr_configured) {
if (json)
json_object_string_add(json_vrf, "floodReduction",
"configured");
else
vty_out(vty, " Flood Reduction is configured.\n");
}
/* Show ABR/ASBR flags. */
if (CHECK_FLAG(ospf->flags, OSPF_FLAG_ABR)) {
if (json)
@ -5949,118 +5994,109 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self,
struct as_external_lsa *asel;
struct prefix_ipv4 p;
if (lsa != NULL) {
/* If self option is set, check LSA self flag. */
if (self == 0 || IS_LSA_SELF(lsa)) {
if (lsa == NULL)
return 0;
if (!json_lsa) {
/* LSA common part show. */
vty_out(vty, "%-15pI4",
&lsa->data->id);
vty_out(vty, "%-15pI4 %4d 0x%08lx 0x%04x",
&lsa->data->adv_router, LS_AGE(lsa),
(unsigned long)ntohl(
lsa->data->ls_seqnum),
ntohs(lsa->data->checksum));
} else {
char seqnum[10];
char checksum[10];
/* If self option is set, check LSA self flag. */
if (self == 0 || IS_LSA_SELF(lsa)) {
snprintf(seqnum, sizeof(seqnum), "%x",
ntohl(lsa->data->ls_seqnum));
snprintf(checksum, sizeof(checksum), "%x",
ntohs(lsa->data->checksum));
json_object_string_addf(json_lsa, "lsId",
"%pI4", &lsa->data->id);
json_object_string_addf(
json_lsa, "advertisedRouter", "%pI4",
&lsa->data->adv_router);
json_object_int_add(json_lsa, "lsaAge",
LS_AGE(lsa));
json_object_string_add(
json_lsa, "sequenceNumber", seqnum);
json_object_string_add(json_lsa, "checksum",
checksum);
}
if (!json_lsa) {
/* LSA common part show. */
vty_out(vty, "%-15pI4", &lsa->data->id);
vty_out(vty, "%-15pI4 %4d 0x%08lx 0x%04x",
&lsa->data->adv_router, LS_AGE(lsa),
(unsigned long)ntohl(lsa->data->ls_seqnum),
ntohs(lsa->data->checksum));
} else {
char seqnum[10];
char checksum[10];
/* LSA specific part show. */
switch (lsa->data->type) {
case OSPF_ROUTER_LSA:
rl = (struct router_lsa *)lsa->data;
if (!json_lsa)
vty_out(vty, " %-d", ntohs(rl->links));
else
json_object_int_add(json_lsa,
"numOfRouterLinks",
ntohs(rl->links));
break;
case OSPF_SUMMARY_LSA:
sl = (struct summary_lsa *)lsa->data;
p.family = AF_INET;
p.prefix = sl->header.id;
p.prefixlen = ip_masklen(sl->mask);
apply_mask_ipv4(&p);
if (!json_lsa)
vty_out(vty, " %pFX", &p);
else {
json_object_string_addf(
json_lsa, "summaryAddress",
"%pFX", &p);
}
break;
case OSPF_AS_EXTERNAL_LSA:
case OSPF_AS_NSSA_LSA:
asel = (struct as_external_lsa *)lsa->data;
p.family = AF_INET;
p.prefix = asel->header.id;
p.prefixlen = ip_masklen(asel->mask);
apply_mask_ipv4(&p);
if (!json_lsa)
vty_out(vty, " %s %pFX [0x%lx]",
IS_EXTERNAL_METRIC(
asel->e[0].tos)
? "E2"
: "E1",
&p,
(unsigned long)ntohl(
asel->e[0].route_tag));
else {
json_object_string_add(
json_lsa, "metricType",
IS_EXTERNAL_METRIC(
asel->e[0].tos)
? "E2"
: "E1");
json_object_string_addf(
json_lsa, "route", "%pFX", &p);
json_object_int_add(
json_lsa, "tag",
(unsigned long)ntohl(
asel->e[0].route_tag));
}
break;
case OSPF_NETWORK_LSA:
case OSPF_ASBR_SUMMARY_LSA:
case OSPF_OPAQUE_LINK_LSA:
case OSPF_OPAQUE_AREA_LSA:
case OSPF_OPAQUE_AS_LSA:
default:
break;
}
if (!json_lsa)
vty_out(vty, "\n");
snprintf(seqnum, sizeof(seqnum), "%x",
ntohl(lsa->data->ls_seqnum));
snprintf(checksum, sizeof(checksum), "%x",
ntohs(lsa->data->checksum));
json_object_string_addf(json_lsa, "lsId", "%pI4",
&lsa->data->id);
json_object_string_addf(json_lsa, "advertisedRouter",
"%pI4", &lsa->data->adv_router);
json_object_int_add(json_lsa, "lsaAge", LS_AGE(lsa));
json_object_string_add(json_lsa, "sequenceNumber",
seqnum);
json_object_string_add(json_lsa, "checksum", checksum);
}
return 1;
/* LSA specific part show. */
switch (lsa->data->type) {
case OSPF_ROUTER_LSA:
rl = (struct router_lsa *)lsa->data;
if (!json_lsa)
vty_out(vty, " %-d", ntohs(rl->links));
else
json_object_int_add(json_lsa,
"numOfRouterLinks",
ntohs(rl->links));
break;
case OSPF_SUMMARY_LSA:
sl = (struct summary_lsa *)lsa->data;
p.family = AF_INET;
p.prefix = sl->header.id;
p.prefixlen = ip_masklen(sl->mask);
apply_mask_ipv4(&p);
if (!json_lsa)
vty_out(vty, " %pFX", &p);
else {
json_object_string_addf(
json_lsa, "summaryAddress", "%pFX", &p);
}
break;
case OSPF_AS_EXTERNAL_LSA:
case OSPF_AS_NSSA_LSA:
asel = (struct as_external_lsa *)lsa->data;
p.family = AF_INET;
p.prefix = asel->header.id;
p.prefixlen = ip_masklen(asel->mask);
apply_mask_ipv4(&p);
if (!json_lsa)
vty_out(vty, " %s %pFX [0x%lx]",
IS_EXTERNAL_METRIC(asel->e[0].tos)
? "E2"
: "E1",
&p,
(unsigned long)ntohl(
asel->e[0].route_tag));
else {
json_object_string_add(
json_lsa, "metricType",
IS_EXTERNAL_METRIC(asel->e[0].tos)
? "E2"
: "E1");
json_object_string_addf(json_lsa, "route",
"%pFX", &p);
json_object_int_add(
json_lsa, "tag",
(unsigned long)ntohl(
asel->e[0].route_tag));
}
break;
case OSPF_NETWORK_LSA:
case OSPF_ASBR_SUMMARY_LSA:
case OSPF_OPAQUE_LINK_LSA:
case OSPF_OPAQUE_AREA_LSA:
case OSPF_OPAQUE_AS_LSA:
default:
break;
}
if (!json_lsa)
vty_out(vty, "\n");
}
return 0;
return 1;
}
static const char *const show_database_desc[] = {
@ -6129,7 +6165,16 @@ static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa,
struct router_lsa *rlsa = (struct router_lsa *)lsa->data;
if (!json) {
vty_out(vty, " LS age: %d\n", LS_AGE(lsa));
if (IS_LSA_SELF(lsa))
vty_out(vty, " LS age: %d%s\n", LS_AGE(lsa),
CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE)
? "(S-DNA)"
: "");
else
vty_out(vty, " LS age: %d%s\n", LS_AGE(lsa),
CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE)
? "(DNA)"
: "");
vty_out(vty, " Options: 0x%-2x : %s\n", lsa->data->options,
ospf_options_dump(lsa->data->options));
vty_out(vty, " LS Flags: 0x%-2x %s\n", lsa->flags,
@ -12188,6 +12233,9 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf)
if (PREFIX_NAME_OUT(area))
vty_out(vty, " area %s filter-list prefix %s out\n",
buf, PREFIX_NAME_OUT(area));
if (area->fr_info.configured)
vty_out(vty, " area %s flood-reduction\n", buf);
}
return 0;
@ -12565,6 +12613,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
if (ospf->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
vty_out(vty, " refresh timer %d\n", ospf->lsa_refresh_interval);
if (ospf->fr_configured)
vty_out(vty, " flood-reduction\n");
/* Redistribute information print. */
config_write_ospf_redistribute(vty, ospf);
@ -12947,6 +12998,143 @@ DEFPY_HIDDEN(ospf_maxage_delay_timer, ospf_maxage_delay_timer_cmd,
return CMD_SUCCESS;
}
/*
* ------------------------------------------------------------------------*
* Following is (vty) configuration functions for flood-reduction handling.
* ------------------------------------------------------------------------
*/
DEFPY(flood_reduction, flood_reduction_cmd, "flood-reduction",
"flood reduction feature\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
struct ospf_area *area;
struct listnode *node;
/* Turn on the Flood Reduction feature for the router. */
if (!ospf->fr_configured) {
ospf->fr_configured = true;
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"Flood Reduction: OFF -> ON");
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
if (area) {
ospf_area_update_fr_state(area);
ospf_refresh_area_self_lsas(area);
}
}
}
return CMD_SUCCESS;
}
DEFPY(flood_reduction_area, flood_reduction_area_cmd,
"area <A.B.C.D|(0-4294967295)> flood-reduction",
"OSPF area parameters\n"
"OSPF area ID in IP address format\n"
"OSPF area ID as a decimal value\n"
"Enable flood reduction for area\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
struct ospf_area *oa;
int idx = 1;
int format;
int ret;
const char *areaid;
struct in_addr area_id;
areaid = argv[idx]->arg;
ret = str2area_id(areaid, &area_id, &format);
if (ret < 0) {
vty_out(vty, "Please specify area by A.B.C.D|<0-4294967295>\n");
return CMD_WARNING_CONFIG_FAILED;
}
oa = ospf_area_lookup_by_area_id(ospf, area_id);
if (!oa) {
vty_out(vty, "OSPF area ID not present\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Turn on the Flood Reduction feature for the area. */
if (!oa->fr_info.configured) {
oa->fr_info.configured = true;
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"Flood Reduction area %pI4 : OFF -> ON",
&oa->area_id);
ospf_area_update_fr_state(oa);
ospf_refresh_area_self_lsas(oa);
}
return CMD_SUCCESS;
}
DEFPY(no_flood_reduction, no_flood_reduction_cmd, "no flood-reduction",
NO_STR "flood reduction feature\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
struct listnode *node;
struct ospf_area *area;
/* Turn off the Flood Reduction feature for the router. */
if (ospf->fr_configured) {
ospf->fr_configured = false;
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"Flood Reduction: ON -> OFF");
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
if (area) {
ospf_area_update_fr_state(area);
ospf_refresh_area_self_lsas(area);
}
}
}
return CMD_SUCCESS;
}
DEFPY(no_flood_reduction_area, no_flood_reduction_area_cmd,
"no area <A.B.C.D|(0-4294967295)> flood-reduction",
NO_STR
"OSPF area parameters\n"
"OSPF area ID in IP address format\n"
"OSPF area ID as a decimal value\n"
"Disable flood reduction for area\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
struct ospf_area *oa;
int idx = 2;
int format;
int ret;
const char *areaid;
struct in_addr area_id;
areaid = argv[idx]->arg;
ret = str2area_id(areaid, &area_id, &format);
if (ret < 0) {
vty_out(vty, "Please specify area by A.B.C.D|<0-4294967295>\n");
return CMD_WARNING_CONFIG_FAILED;
}
oa = ospf_area_lookup_by_area_id(ospf, area_id);
if (!oa) {
vty_out(vty, "OSPF area ID not present\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Turn off the Flood Reduction feature for the area. */
if (oa->fr_info.configured) {
oa->fr_info.configured = false;
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"Flood Reduction area %pI4 : ON -> OFF",
&oa->area_id);
ospf_area_update_fr_state(oa);
ospf_refresh_area_self_lsas(oa);
}
return CMD_SUCCESS;
}
void ospf_vty_clear_init(void)
{
install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd);
@ -13107,6 +13295,12 @@ void ospf_vty_init(void)
install_element(OSPF_NODE, &ospf_lsa_refresh_timer_cmd);
install_element(OSPF_NODE, &ospf_maxage_delay_timer_cmd);
/* Flood Reduction commands */
install_element(OSPF_NODE, &flood_reduction_cmd);
install_element(OSPF_NODE, &no_flood_reduction_cmd);
install_element(OSPF_NODE, &flood_reduction_area_cmd);
install_element(OSPF_NODE, &no_flood_reduction_area_cmd);
/* Init interface related vty commands. */
ospf_vty_if_init();

View File

@ -452,6 +452,8 @@ static struct ospf *ospf_new(unsigned short instance, const char *name)
*/
ospf_gr_nvm_read(new);
new->fr_configured = false;
return new;
}
@ -802,6 +804,7 @@ static void ospf_finish_final(struct ospf *ospf)
THREAD_OFF(ospf->t_maxage);
THREAD_OFF(ospf->t_maxage_walker);
THREAD_OFF(ospf->t_abr_task);
THREAD_OFF(ospf->t_abr_fr);
THREAD_OFF(ospf->t_asbr_check);
THREAD_OFF(ospf->t_asbr_nssa_redist_update);
THREAD_OFF(ospf->t_distribute_update);
@ -947,6 +950,15 @@ struct ospf_area *ospf_area_new(struct ospf *ospf, struct in_addr area_id)
/* Self-originated LSAs initialize. */
new->router_lsa_self = NULL;
/* Initialize FR field */
new->fr_info.enabled = false;
new->fr_info.configured = false;
new->fr_info.state_changed = false;
new->fr_info.router_lsas_recv_dc_bit = 0;
new->fr_info.indication_lsa_self = NULL;
new->fr_info.area_ind_lsa_recvd = false;
new->fr_info.area_dc_clear = false;
ospf_opaque_type10_lsa_init(new);
new->oiflist = list_new();

View File

@ -101,7 +101,25 @@ struct ospf_redist {
struct route_map *map;
} route_map; /* +1 is for default-information */
#define ROUTEMAP_NAME(R) (R->route_map.name)
#define ROUTEMAP(R) (R->route_map.map)
#define ROUTEMAP(R) (R->route_map.map)
};
/* OSPF area flood reduction info */
struct ospf_area_fr_info {
bool enabled; /* Area support for Flood Reduction */
bool configured; /* Flood Reduction configured per area knob */
bool state_changed; /* flood reduction state change info */
int router_lsas_recv_dc_bit; /* Number of unique router lsas
* received with DC bit set.
* (excluding self)
*/
bool area_ind_lsa_recvd; /* Indication lsa received in this area */
bool area_dc_clear; /* Area has atleast one lsa with dc bit 0(
* excluding indication lsa)
*/
struct ospf_lsa *indication_lsa_self; /* Indication LSA generated
* in the area.
*/
};
/* ospf->config */
@ -240,6 +258,7 @@ struct ospf {
/* Threads. */
struct thread *t_abr_task; /* ABR task timer. */
struct thread *t_abr_fr; /* ABR FR timer. */
struct thread *t_asbr_check; /* ASBR check timer. */
struct thread *t_asbr_nssa_redist_update; /* ASBR NSSA redistribution
update timer. */
@ -391,6 +410,9 @@ struct ospf {
bool ti_lfa_enabled;
enum protection_type ti_lfa_protection_type;
/* Flood Reduction configuration state */
bool fr_configured;
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(ospf);
@ -576,6 +598,8 @@ struct ospf_area {
uint32_t act_ints; /* Active interfaces. */
uint32_t full_nbrs; /* Fully adjacent neighbors. */
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
struct ospf_area_fr_info fr_info; /* Flood reduction info. */
};
/* OSPF config network structure. */

View File

@ -8,6 +8,7 @@
import ipaddress
import sys
from copy import deepcopy
from time import sleep
# Import common_config to use commomnly used APIs
from lib.common_config import (
@ -188,6 +189,24 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf):
cmd = "no maximum-paths"
config_data.append(cmd)
# Flood reduction.
flood_data = ospf_data.setdefault("flood-reduction", {})
if flood_data:
cmd = "flood-reduction"
del_action = ospf_data.setdefault("del_flood_reduction", False)
if del_action:
cmd = "no flood-reduction"
config_data.append(cmd)
# LSA refresh timer - A hidden command.
refresh_data = ospf_data.setdefault("lsa-refresh", {})
if refresh_data:
cmd = "ospf lsa-refresh {}".format(refresh_data)
del_action = ospf_data.setdefault("del_lsa_refresh", False)
if del_action:
cmd = "no ospf lsa-refresh"
config_data.append(cmd)
# redistribute command
redistribute_data = ospf_data.setdefault("redistribute", {})
if redistribute_data:
@ -220,6 +239,9 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf):
if "type" in area:
cmd = cmd + " {}".format(area["type"])
if "flood-reduction" in area:
cmd = cmd + " flood-reduction"
del_action = area.setdefault("delete", False)
if del_action:
cmd = "no {}".format(cmd)
@ -724,9 +746,6 @@ def verify_ospf_neighbor(
return result
################################
# Verification procs
################################
@retry(retry_timeout=50)
def verify_ospf6_neighbor(tgen, topo=None, dut=None, input_dict=None, lan=False):
"""
@ -1339,8 +1358,10 @@ def verify_ospf_interface(
return result
@retry(retry_timeout=20)
def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
@retry(retry_timeout=40)
def verify_ospf_database(
tgen, topo, dut, input_dict, vrf=None, lsatype=None, rid=None, expected=True
):
"""
This API is to verify ospf lsa's by running
show ip ospf database command.
@ -1398,7 +1419,23 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
rnode = tgen.routers()[dut]
logger.info("Verifying OSPF interface on router %s:", dut)
show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json", isjson=True)
if not rid:
rid = "self-originate"
if lsatype:
if vrf is None:
command = "show ip ospf database {} {} json".format(lsatype, rid)
else:
command = "show ip ospf database {} {} vrf {} json".format(
lsatype, rid, vrf
)
else:
if vrf is None:
command = "show ip ospf database json"
else:
command = "show ip ospf database vrf {} json".format(vrf)
show_ospf_json = run_frr_cmd(rnode, command, isjson=True)
# Verifying output dictionary show_ospf_json is empty or not
if not bool(show_ospf_json):
errormsg = "OSPF is not running"
@ -1407,26 +1444,40 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
# for inter and inter lsa's
ospf_db_data = input_dict.setdefault("areas", None)
ospf_external_lsa = input_dict.setdefault("AS External Link States", None)
# import pdb; pdb.set_trace()
if ospf_db_data:
for ospf_area, area_lsa in ospf_db_data.items():
if ospf_area in show_ospf_json["areas"]:
if "Router Link States" in area_lsa:
for lsa in area_lsa["Router Link States"]:
if ospf_area in show_ospf_json["routerLinkStates"]["areas"]:
if "routerLinkStates" in area_lsa:
for lsa in area_lsa["routerLinkStates"]:
_advrtr = lsa.setdefault("advertisedRouter", None)
_options = lsa.setdefault("options", None)
if (
lsa
in show_ospf_json["areas"][ospf_area]["Router Link States"]
_options
and lsa["lsaId"]
== show_ospf_json["routerLinkStates"]["areas"][ospf_area][
0
]["linkStateId"]
and lsa["options"]
== show_ospf_json["routerLinkStates"]["areas"][ospf_area][
0
]["options"]
):
logger.info(
"[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
router,
ospf_area,
lsa,
)
result = True
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Router LSA is {}".format(router, ospf_area, lsa)
errormsg = '[DUT: {}] OSPF LSA options: expected {}, Received Options are {} lsa["options"] {} OSPF LSAID: expected lsaid {}, Received lsaid {}'.format(
dut,
show_ospf_json["routerLinkStates"]["areas"][ospf_area][
0
]["options"],
_options,
lsa["options"],
show_ospf_json["routerLinkStates"]["areas"][ospf_area][
0
]["linkStateId"],
lsa["lsaId"],
)
return errormsg
if "Net Link States" in area_lsa:
@ -2476,3 +2527,495 @@ def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
def get_ospf_database(tgen, topo, dut, input_dict, vrf=None, lsatype=None, rid=None):
"""
This API is to return ospf lsa's by running
show ip ospf database command.
Parameters
----------
* `tgen` : Topogen object
* `dut`: device under test
* `input_dict` : Input dict data, required when configuring from testcase
* `topo` : next to be verified
* `vrf` : vrf to be checked
* `lsatype` : type of lsa to be checked
* `rid` : router id for lsa to be checked
Usage
-----
input_dict = {
"areas": {
"0.0.0.0": {
"routerLinkStates": {
"100.1.1.0-100.1.1.0": {
"LSID": "100.1.1.0",
"Advertised router": "100.1.1.0",
"LSA Age": 130,
"Sequence Number": "80000006",
"Checksum": "a703",
"Router links": 3
}
},
"networkLinkStates": {
"10.0.0.2-100.1.1.1": {
"LSID": "10.0.0.2",
"Advertised router": "100.1.1.1",
"LSA Age": 137,
"Sequence Number": "80000001",
"Checksum": "9583"
}
},
},
}
}
result = get_ospf_database(tgen, topo, dut, input_dict)
Returns
-------
True or False (Error Message)
"""
result = False
router = dut
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
sleep(10)
if "ospf" not in topo["routers"][dut]:
errormsg = "[DUT: {}] OSPF is not configured on the router.".format(dut)
return errormsg
rnode = tgen.routers()[dut]
logger.info("Verifying OSPF interface on router %s:", dut)
if not rid:
rid = "self-originate"
if lsatype:
if vrf is None:
command = "show ip ospf database {} {} json".format(lsatype, rid)
else:
command = "show ip ospf database {} {} vrf {} json".format(
lsatype, rid, vrf
)
else:
if vrf is None:
command = "show ip ospf database json"
else:
command = "show ip ospf database vrf {} json".format(vrf)
show_ospf_json = run_frr_cmd(rnode, command, isjson=True)
# Verifying output dictionary show_ospf_json is empty or not
if not bool(show_ospf_json):
errormsg = "OSPF is not running"
return errormsg
# for inter and inter lsa's
ospf_db_data = input_dict.setdefault("areas", None)
ospf_external_lsa = input_dict.setdefault("asExternalLinkStates", None)
if ospf_db_data:
for ospf_area, area_lsa in ospf_db_data.items():
if "areas" in show_ospf_json and ospf_area in show_ospf_json["areas"]:
if "routerLinkStates" in area_lsa:
for lsa in area_lsa["routerLinkStates"]:
for rtrlsa in show_ospf_json["areas"][ospf_area][
"routerLinkStates"
]:
_advrtr = lsa.setdefault("advertisedRouter", None)
_options = lsa.setdefault("options", None)
if (
_advrtr
and lsa["lsaId"] == rtrlsa["lsaId"]
and lsa["advertisedRouter"]
== rtrlsa["advertisedRouter"]
):
result = True
break
if (
_options
and lsa["lsaId"] == rtrlsa["lsaId"]
and lsa["options"] == rtrlsa["options"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Router LSA is {}\n found Router LSA: {}".format(
router, ospf_area, lsa, rtrlsa
)
)
return errormsg
if "networkLinkStates" in area_lsa:
for lsa in area_lsa["networkLinkStates"]:
for netlsa in show_ospf_json["areas"][ospf_area][
"networkLinkStates"
]:
if (
lsa
in show_ospf_json["areas"][ospf_area][
"networkLinkStates"
]
):
if (
lsa["lsaId"] == netlsa["lsaId"]
and lsa["advertisedRouter"]
== netlsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Network LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "summaryLinkStates" in area_lsa:
for lsa in area_lsa["summaryLinkStates"]:
for t3lsa in show_ospf_json["areas"][ospf_area][
"summaryLinkStates"
]:
if (
lsa["lsaId"] == t3lsa["lsaId"]
and lsa["advertisedRouter"] == t3lsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Summary LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "nssaExternalLinkStates" in area_lsa:
for lsa in area_lsa["nssaExternalLinkStates"]:
for t7lsa in show_ospf_json["areas"][ospf_area][
"nssaExternalLinkStates"
]:
if (
lsa["lsaId"] == t7lsa["lsaId"]
and lsa["advertisedRouter"] == t7lsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Type7 LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "asbrSummaryLinkStates" in area_lsa:
for lsa in area_lsa["asbrSummaryLinkStates"]:
for t4lsa in show_ospf_json["areas"][ospf_area][
"asbrSummaryLinkStates"
]:
if (
lsa["lsaId"] == t4lsa["lsaId"]
and lsa["advertisedRouter"] == t4lsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
router,
ospf_area,
lsa,
)
result = True
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" ASBR Summary LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "linkLocalOpaqueLsa" in area_lsa:
for lsa in area_lsa["linkLocalOpaqueLsa"]:
try:
for lnklsa in show_ospf_json["areas"][ospf_area][
"linkLocalOpaqueLsa"
]:
if (
lsa["lsaId"] in lnklsa["lsaId"]
and "linkLocalOpaqueLsa"
in show_ospf_json["areas"][ospf_area]
):
logger.info(
(
"[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
"%s",
ospf_area,
lsa,
)
)
result = True
else:
errormsg = (
"[DUT: FRR] OSPF LSDB area: {} "
"expected Opaque-LSA is {}, Found is {}".format(
ospf_area, lsa, show_ospf_json
)
)
raise ValueError(errormsg)
return errormsg
except KeyError:
errormsg = "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
return errormsg
else:
if "routerLinkStates" in area_lsa:
for lsa in area_lsa["routerLinkStates"]:
for rtrlsa in show_ospf_json["routerLinkStates"]:
_advrtr = lsa.setdefault("advertisedRouter", None)
_options = lsa.setdefault("options", None)
_age = lsa.setdefault("lsaAge", None)
if (
_options
and lsa["options"]
== show_ospf_json["routerLinkStates"][rtrlsa][
ospf_area
][0]["options"]
):
result = True
break
if (
_age is not "get"
and lsa["lsaAge"]
== show_ospf_json["routerLinkStates"][rtrlsa][
ospf_area
][0]["lsaAge"]
):
result = True
break
if _age == "get":
return "{}".format(
show_ospf_json["routerLinkStates"][rtrlsa][
ospf_area
][0]["lsaAge"]
)
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Router LSA is {}\n found Router LSA: {}".format(
router,
ospf_area,
lsa,
show_ospf_json["routerLinkStates"],
)
)
return errormsg
if "networkLinkStates" in area_lsa:
for lsa in area_lsa["networkLinkStates"]:
for netlsa in show_ospf_json["areas"][ospf_area][
"networkLinkStates"
]:
if (
lsa
in show_ospf_json["areas"][ospf_area][
"networkLinkStates"
]
):
if (
lsa["lsaId"] == netlsa["lsaId"]
and lsa["advertisedRouter"]
== netlsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Network LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "summaryLinkStates" in area_lsa:
for lsa in area_lsa["summaryLinkStates"]:
for t3lsa in show_ospf_json["areas"][ospf_area][
"summaryLinkStates"
]:
if (
lsa["lsaId"] == t3lsa["lsaId"]
and lsa["advertisedRouter"] == t3lsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Summary LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "nssaExternalLinkStates" in area_lsa:
for lsa in area_lsa["nssaExternalLinkStates"]:
for t7lsa in show_ospf_json["areas"][ospf_area][
"nssaExternalLinkStates"
]:
if (
lsa["lsaId"] == t7lsa["lsaId"]
and lsa["advertisedRouter"] == t7lsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
router,
ospf_area,
lsa,
)
break
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" Type7 LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "asbrSummaryLinkStates" in area_lsa:
for lsa in area_lsa["asbrSummaryLinkStates"]:
for t4lsa in show_ospf_json["areas"][ospf_area][
"asbrSummaryLinkStates"
]:
if (
lsa["lsaId"] == t4lsa["lsaId"]
and lsa["advertisedRouter"] == t4lsa["advertisedRouter"]
):
result = True
break
if result:
logger.info(
"[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
router,
ospf_area,
lsa,
)
result = True
else:
errormsg = (
"[DUT: {}] OSPF LSDB area {}: expected"
" ASBR Summary LSA is {}".format(router, ospf_area, lsa)
)
return errormsg
if "linkLocalOpaqueLsa" in area_lsa:
for lsa in area_lsa["linkLocalOpaqueLsa"]:
try:
for lnklsa in show_ospf_json["areas"][ospf_area][
"linkLocalOpaqueLsa"
]:
if (
lsa["lsaId"] in lnklsa["lsaId"]
and "linkLocalOpaqueLsa"
in show_ospf_json["areas"][ospf_area]
):
logger.info(
(
"[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
"%s",
ospf_area,
lsa,
)
)
result = True
else:
errormsg = (
"[DUT: FRR] OSPF LSDB area: {} "
"expected Opaque-LSA is {}, Found is {}".format(
ospf_area, lsa, show_ospf_json
)
)
raise ValueError(errormsg)
return errormsg
except KeyError:
errormsg = "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
return errormsg
if ospf_external_lsa:
for lsa in ospf_external_lsa:
try:
for t5lsa in show_ospf_json["asExternalLinkStates"]:
if (
lsa["lsaId"] == t5lsa["lsaId"]
and lsa["advertisedRouter"] == t5lsa["advertisedRouter"]
):
result = True
break
except KeyError:
result = False
if result:
logger.info("[DUT: %s] OSPF LSDB:External LSA %s", router, lsa)
result = True
else:
errormsg = (
"[DUT: {}] OSPF LSDB : expected"
" External LSA is {}".format(router, lsa)
)
return errormsg
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result

View File

@ -0,0 +1,214 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
},
"graceful-restart": {
"helper-only": []
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.1",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3-link0": {
"ipv4": "auto",
"description": "DummyIntftoR3"
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
},
"graceful-restart": {
"helper-only": []
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.1",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4,
"network": "broadcast"
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"area": [
{
"id": "0.0.0.2",
"type": "nssa"
}
],
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
},
"graceful-restart": {
"helper-only": []
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4,
"network": "broadcast"
}
},
"r1-link0": {
"ipv4": "auto",
"description": "DummyIntftoR1",
"ospf": {
"area": "0.0.0.0"
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"area": [
{
"id": "0.0.0.2",
"type": "nssa"
}
],
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
},
"graceful-restart": {
"helper-only": []
}
}
}
}
}

File diff suppressed because it is too large Load Diff