diff options
| -rw-r--r-- | ospf6d/ospf6_flood.c | 56 | ||||
| -rw-r--r-- | ospf6d/ospf6_gr.h | 7 | ||||
| -rw-r--r-- | ospf6d/ospf6_gr_helper.c | 181 | ||||
| -rw-r--r-- | ospf6d/ospf6_interface.c | 32 | ||||
| -rw-r--r-- | ospf6d/ospf6_interface.h | 2 |
5 files changed, 265 insertions, 13 deletions
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 77c2ad1628..458b81f2ea 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -307,6 +307,22 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa) /* actually install */ lsa->installed = now; + + /* Topo change handling */ + if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))) { + + /* check if it is new lsa ? or existing lsa got modified ?*/ + if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) { + struct ospf6 *ospf6; + + ospf6 = ospf6_get_by_lsdb(lsa); + + assert(ospf6); + + ospf6_helper_handle_topo_chg(ospf6, lsa); + } + } + ospf6_lsdb_add(lsa, lsa->lsdb); if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) { @@ -1008,19 +1024,39 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, assert(ospf6); - if (IS_DEBUG_OSPF6_GR_HELPER) - zlog_debug( - "%s, Received a GraceLSA from router %d", - __PRETTY_FUNCTION__, - new->header->adv_router); + if (OSPF6_LSA_IS_MAXAGE(new)) { - if (ospf6_process_grace_lsa(ospf6, new, from) - == OSPF6_GR_NOT_HELPER) { if (IS_DEBUG_OSPF6_GR_HELPER) zlog_debug( - "%s, Not moving to HELPER role, So dicarding GraceLSA", - __PRETTY_FUNCTION__); - return; + "%s, Received a maxage GraceLSA from router %pI4", + __func__, + &new->header->adv_router); + if (old) { + ospf6_process_maxage_grace_lsa( + ospf6, new, from); + } else { + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug( + "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA", + __func__); + return; + } + } else { + + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug( + "%s, Received a GraceLSA from router %pI4", + __func__, + &new->header->adv_router); + + if (ospf6_process_grace_lsa(ospf6, new, from) + == OSPF6_GR_NOT_HELPER) { + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug( + "%s, Not moving to HELPER role, So dicarding GraceLSA", + __func__); + return; + } } } diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h index 6336363688..49fc86a4e2 100644 --- a/ospf6d/ospf6_gr.h +++ b/ospf6d/ospf6_gr.h @@ -148,6 +148,13 @@ extern const char *ospf6_rejected_reason_desc[]; extern void ospf6_gr_helper_init(struct ospf6 *ospf6); extern void ospf6_gr_helper_deinit(struct ospf6 *ospf6); +extern void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, + enum ospf6_helper_exit_reason reason); extern int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, struct ospf6_neighbor *nbr); +extern void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf, + struct ospf6_lsa *lsa, + struct ospf6_neighbor *nbr); +extern void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, + struct ospf6_lsa *lsa); #endif /* OSPF6_GR_H */ diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index d035171154..60c62a9341 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -191,7 +191,7 @@ static int ospf6_handle_grace_timer_expiry(struct thread *thread) nbr->gr_helper_info.t_grace_timer = NULL; - // ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT); + ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT); return OSPF6_SUCCESS; } @@ -403,6 +403,185 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, return OSPF6_GR_ACTIVE_HELPER; } +/* + * Api to exit from HELPER role to take all actions + * required at exit. + * Ref rfc3623 section 3. and rfc51872 + * + * ospf6 + * Ospf6 pointer. + * + * nbr + * Ospf6 neighbour for which it is acting as HELPER. + * + * reason + * The reason for exiting from HELPER. + * + * Returns: + * Nothing. + */ +void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, + enum ospf6_helper_exit_reason reason) +{ + struct ospf6_interface *oi = nbr->ospf6_if; + struct ospf6 *ospf6; + + if (!oi) + return; + + ospf6 = oi->area->ospf6; + + if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr)) + return; + + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s", + __func__, &nbr->linklocal_addr, + ospf6_exit_reason_desc[reason]); + + /* Reset helper status*/ + nbr->gr_helper_info.gr_helper_status = OSPF6_GR_NOT_HELPER; + nbr->gr_helper_info.helper_exit_reason = reason; + nbr->gr_helper_info.actual_grace_period = 0; + nbr->gr_helper_info.recvd_grace_period = 0; + nbr->gr_helper_info.gr_restart_reason = 0; + ospf6->ospf6_helper_cfg.last_exit_reason = reason; + + /* If the exit not triggered due to grace timer + * expairy , stop the grace timer. + */ + if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT) + THREAD_OFF(nbr->gr_helper_info.t_grace_timer); + + if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) { + zlog_err( + "OSPF6 GR-Helper: Number of active Restarters should be greater than zero."); + return; + } + /* Decrement active Restarter count */ + ospf6->ospf6_helper_cfg.active_restarter_cnt--; + + /* check exit triggered due to successful completion + * of graceful restart. + */ + if (reason != OSPF6_GR_HELPER_COMPLETED) { + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6", + __func__, &nbr->linklocal_addr); + } + + /*Recalculate the DR for the network segment */ + dr_election(oi); + + /* Originate a router LSA */ + OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area); + + /* Originate network lsa if it is an DR in the LAN */ + if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR) + OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if); +} + +/* + * Process Maxage Grace LSA. + * It is a indication for successfull completion of GR. + * If router acting as HELPER, It exits from helper role. + * + * ospf6 + * Ospf6 pointer. + * + * lsa + * Grace LSA received from RESTARTER. + * + * nbr + * ospf6 neighbour which requets the router to act as + * HELPER. + * + * Returns: + * Nothing. + */ +void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, + struct ospf6_neighbor *restarter) +{ + uint8_t restart_reason = 0; + uint32_t grace_interval = 0; + int ret; + + /* Extract the grace lsa packet fields */ + ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval, + &restart_reason); + if (ret != OSPF6_SUCCESS) { + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug("%s, Wrong Grace LSA packet.", + __func__); + return; + } + + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug("%s, GraceLSA received for neighbour %pI4.", + __func__, &restarter->router_id); + + ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED); +} + +/* + * Actions to be taken when topo change detected + * HELPER will be exited upon a topo change. + * + * ospf6 + * ospf6 pointer + * lsa + * topo change occured due to this lsa(type (1-5 and 7) + * + * Returns: + * Nothing + */ +void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa) +{ + struct listnode *i, *j, *k; + struct ospf6_neighbor *nbr = NULL; + struct ospf6_area *oa = NULL; + struct ospf6_interface *oi = NULL; + + if (!ospf6->ospf6_helper_cfg.active_restarter_cnt) + return; + + /* Topo change not required to be hanlded if strict + * LSA check is disbaled for this router. + */ + if (!ospf6->ospf6_helper_cfg.strict_lsa_check) + return; + + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug( + "%s, Topo change detected due to lsa details : %s", + __func__, lsa->name); + + lsa->tobe_acknowledged = OSPF6_TRUE; + + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + + /* Ref rfc3623 section 3.2.3.b and rfc5187 + * If change due to external LSA and if the area is + * stub, then it is not a topo change. Since Type-5 + * lsas will not be flooded in stub area. + */ + if (IS_AREA_STUB(oi->area) + && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL) + || (lsa->header->type == OSPF6_LSTYPE_TYPE_7) + || (lsa->header->type + == OSPF6_LSTYPE_INTER_ROUTER))) { + continue; + } + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) { + + ospf6_gr_helper_exit(nbr, + OSPF6_GR_HELPER_TOPO_CHG); + } + } +} + /* Debug commands */ DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd, diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index a169b9c60e..bbb474ba1a 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -44,9 +44,10 @@ #include "ospf6d.h" #include "ospf6_bfd.h" #include "ospf6_zebra.h" +#include "ospf6_gr.h" #include "lib/json.h" -DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names"); DEFINE_QOBJ_TYPE(ospf6_interface); DEFINE_HOOK(ospf6_interface_change, @@ -59,6 +60,22 @@ const char *const ospf6_interface_state_str[] = { "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL}; +int ospf6_interface_neighbor_count(struct ospf6_interface *oi) +{ + int count = 0; + struct ospf6_neighbor *nbr = NULL; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, nbr)) { + /* Down state is not shown. */ + if (nbr->state == OSPF6_NEIGHBOR_DOWN) + continue; + count++; + } + + return count; +} + struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) { @@ -579,7 +596,7 @@ static struct ospf6_neighbor *better_drouter(struct ospf6_neighbor *a, return a; } -static uint8_t dr_election(struct ospf6_interface *oi) +uint8_t dr_election(struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on, *drouter, *bdrouter, myself; @@ -896,6 +913,17 @@ int interface_down(struct thread *thread) /* Stop trying to set socket options. */ THREAD_OFF(oi->thread_sso); + /* Cease the HELPER role for all the neighbours + * of this interface. + */ + if (ospf6_interface_neighbor_count(oi)) { + struct listnode *ln; + struct ospf6_neighbor *nbr = NULL; + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, ln, nbr)) + ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_TOPO_CHG); + } + for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete(on); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index b5efca743e..ccdf8b1c8f 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -218,6 +218,8 @@ extern void install_element_ospf6_clear_interface(void); extern int config_write_ospf6_debug_interface(struct vty *vty); extern void install_element_ospf6_debug_interface(void); +extern int ospf6_interface_neighbor_count(struct ospf6_interface *oi); +extern uint8_t dr_election(struct ospf6_interface *oi); DECLARE_HOOK(ospf6_interface_change, (struct ospf6_interface * oi, int state, int old_state), |
