mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 21:20:48 +00:00
Merge pull request #12366 from manojvn/ospfv2-flood-reduction
ospfd: Support OSPF Refresh and Flooding Reduction RFC4136.
This commit is contained in:
commit
62bd2580e3
15
lib/log.h
15
lib/log.h
@ -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 {
|
||||
|
272
ospfd/ospf_abr.c
272
ospfd/ospf_abr.c
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
406
ospfd/ospf_vty.c
406
ospfd/ospf_vty.c
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user