mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 02:46:26 +00:00
ospfd: Grace LSA processing
Description: 1. Grace LSA processing. 2. Validations to become a Helper. rfc3623 section 3.1 Signed-off-by: Rajesh Girada <rgirada@vmware.com>
This commit is contained in:
parent
06bc3110d3
commit
ad68699217
@ -337,6 +337,45 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr,
|
||||
SET_FLAG(new->flags, OSPF_LSA_RECEIVED);
|
||||
(void)ospf_lsa_is_self_originated(ospf, new); /* Let it set the flag */
|
||||
|
||||
/* Received Grace LSA */
|
||||
if (IS_GRACE_LSA(new)) {
|
||||
|
||||
if (IS_LSA_MAXAGE(new)) {
|
||||
|
||||
/* Handling Max age grace LSA.*/
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Received a maxage GRACE-LSA from router %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
inet_ntoa(new->data->adv_router));
|
||||
|
||||
if (current) {
|
||||
ospf_process_maxage_grace_lsa(ospf, new, nbr);
|
||||
} else {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Grace LSA doesn't exist in lsdb, so discarding grace lsa",
|
||||
__PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Received a GRACE-LSA from router %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
inet_ntoa(new->data->adv_router));
|
||||
|
||||
if (ospf_process_grace_lsa(ospf, new, nbr)
|
||||
== OSPF_GR_NOT_HELPER) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Not moving to HELPER role, So discarding grace LSA",
|
||||
__PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Install the new LSA in the link state database
|
||||
(replacing the current database copy). This may cause the
|
||||
routing table calculation to be scheduled. In addition,
|
||||
|
@ -50,6 +50,31 @@
|
||||
#include "ospfd/ospf_ism.h"
|
||||
#include "ospfd/ospf_gr_helper.h"
|
||||
|
||||
const char *ospf_exit_reason_desc[] = {
|
||||
"Unknown reason",
|
||||
"Helper inprogress",
|
||||
"Topology Change",
|
||||
"Grace timer expairy",
|
||||
"Successful graceful restart",
|
||||
};
|
||||
|
||||
const char *ospf_restart_reason_desc[] = {
|
||||
"Unknown restart",
|
||||
"Software restart",
|
||||
"Software reload/upgrade",
|
||||
"Switch to redundant control processor",
|
||||
};
|
||||
|
||||
const char *ospf_rejected_reason_desc[] = {
|
||||
"Unknown reason",
|
||||
"Helper support disabled",
|
||||
"Neighbour is not in FULL state",
|
||||
"Supports only planned restart but received for unplanned",
|
||||
"Topo change due to change in lsa rxmt list",
|
||||
"LSA age is more than Grace interval",
|
||||
};
|
||||
|
||||
static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
|
||||
|
||||
static unsigned int ospf_enable_rtr_hash_key(const void *data)
|
||||
{
|
||||
@ -105,9 +130,9 @@ void ospf_gr_helper_init(struct ospf *ospf)
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__);
|
||||
|
||||
ospf->is_helper_supported = OSPF_FALSE;
|
||||
ospf->strict_lsa_check = OSPF_TRUE;
|
||||
ospf->only_planned_restart = OSPF_FALSE;
|
||||
ospf->is_helper_supported = OSPF_GR_FALSE;
|
||||
ospf->strict_lsa_check = OSPF_GR_TRUE;
|
||||
ospf->only_planned_restart = OSPF_GR_FALSE;
|
||||
ospf->supported_grace_time = OSPF_MAX_GRACE_INTERVAL;
|
||||
ospf->last_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
|
||||
ospf->active_restarter_cnt = 0;
|
||||
@ -134,3 +159,379 @@ void ospf_gr_helper_stop(struct ospf *ospf)
|
||||
|
||||
ospf_enable_rtr_hash_destroy(ospf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extracting tlv info from GRACE LSA.
|
||||
*
|
||||
* lsa
|
||||
* ospf grace lsa
|
||||
*
|
||||
* Returns:
|
||||
* interval : grace interval.
|
||||
* addr : RESTARTER address.
|
||||
* reason : Restarting reason.
|
||||
*/
|
||||
static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
|
||||
uint32_t *interval,
|
||||
struct in_addr *addr, uint8_t *reason)
|
||||
{
|
||||
struct lsa_header *lsah = NULL;
|
||||
struct tlv_header *tlvh = NULL;
|
||||
struct grace_tlv_graceperiod *grace_period;
|
||||
struct grace_tlv_restart_reason *gr_reason;
|
||||
struct grace_tlv_restart_addr *restart_addr;
|
||||
uint16_t length = 0;
|
||||
int sum = 0;
|
||||
|
||||
lsah = (struct lsa_header *)lsa->data;
|
||||
|
||||
length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
|
||||
|
||||
for (tlvh = TLV_HDR_TOP(lsah); sum < length;
|
||||
tlvh = TLV_HDR_NEXT(tlvh)) {
|
||||
switch (ntohs(tlvh->type)) {
|
||||
case GRACE_PERIOD_TYPE:
|
||||
grace_period = (struct grace_tlv_graceperiod *)tlvh;
|
||||
*interval = ntohl(grace_period->interval);
|
||||
sum += TLV_SIZE(tlvh);
|
||||
|
||||
/* Check if grace interval is valid */
|
||||
if (*interval > OSPF_MAX_GRACE_INTERVAL
|
||||
|| *interval < OSPF_MIN_GRACE_INTERVAL)
|
||||
return OSPF_GR_FAILURE;
|
||||
break;
|
||||
case RESTART_REASON_TYPE:
|
||||
gr_reason = (struct grace_tlv_restart_reason *)tlvh;
|
||||
*reason = gr_reason->reason;
|
||||
sum += TLV_SIZE(tlvh);
|
||||
|
||||
if (*reason >= OSPF_GR_INVALID_REASON_CODE)
|
||||
return OSPF_GR_FAILURE;
|
||||
break;
|
||||
case RESTARTER_IP_ADDR_TYPE:
|
||||
restart_addr = (struct grace_tlv_restart_addr *)tlvh;
|
||||
addr->s_addr = restart_addr->addr.s_addr;
|
||||
sum += TLV_SIZE(tlvh);
|
||||
break;
|
||||
default:
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Malformed packet.Invalid TLV type:%d",
|
||||
__PRETTY_FUNCTION__, ntohs(tlvh->type));
|
||||
return OSPF_GR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return OSPF_GR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grace timer expiry handler.
|
||||
* HELPER aborts its role at grace timer expiry.
|
||||
*
|
||||
* thread
|
||||
* thread pointer
|
||||
*
|
||||
* Returns:
|
||||
* Nothing
|
||||
*/
|
||||
static int ospf_handle_grace_timer_expiry(struct thread *thread)
|
||||
{
|
||||
struct ospf_neighbor *nbr = THREAD_ARG(thread);
|
||||
|
||||
nbr->gr_helper_info.t_grace_timer = NULL;
|
||||
|
||||
ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
|
||||
return OSPF_GR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process Grace LSA.If it is eligible move to HELPER role.
|
||||
* Ref rfc3623 section 3.1
|
||||
*
|
||||
* ospf
|
||||
* Ospf pointer.
|
||||
*
|
||||
* lsa
|
||||
* Grace LSA received from RESTARTER.
|
||||
*
|
||||
* nbr
|
||||
* ospf neighbour which requets the router to act as
|
||||
* HELPER.
|
||||
*
|
||||
* Returns:
|
||||
* status.
|
||||
* If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
|
||||
* If Not supported as HELPER : OSPF_GR_HELPER_NONE
|
||||
*/
|
||||
int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
||||
struct ospf_neighbor *nbr)
|
||||
{
|
||||
struct in_addr restart_addr = {0};
|
||||
uint8_t restart_reason = 0;
|
||||
uint32_t grace_interval = 0;
|
||||
uint32_t actual_grace_interval = 0;
|
||||
struct advRtr lookup;
|
||||
struct ospf_neighbor *restarter = NULL;
|
||||
struct ospf_interface *oi = nbr->oi;
|
||||
int ret;
|
||||
|
||||
|
||||
/* Extract the grace lsa packet fields */
|
||||
ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
|
||||
&restart_reason);
|
||||
if (ret != OSPF_GR_SUCCESS) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug("%s, Wrong Grace LSA packet.",
|
||||
__PRETTY_FUNCTION__);
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Grace LSA received from %s, grace interval:%u, restartreason :%s",
|
||||
__PRETTY_FUNCTION__, inet_ntoa(restart_addr),
|
||||
grace_interval, ospf_restart_reason_desc[restart_reason]);
|
||||
|
||||
/* Incase of broadcast links, if RESTARTER is DR_OTHER,
|
||||
* grace LSA might be received from DR, so need to get
|
||||
* actual neighbour info , here RESTARTER.
|
||||
*/
|
||||
if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
|
||||
restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
|
||||
|
||||
if (!restarter) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Restarter is not a nbr(%s) for this router.",
|
||||
__PRETTY_FUNCTION__,
|
||||
inet_ntoa(restart_addr));
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
} else
|
||||
restarter = nbr;
|
||||
|
||||
/* Verify Helper enabled globally */
|
||||
if (!ospf->is_helper_supported) {
|
||||
/* Verify that Helper support is enabled for the
|
||||
* current neighbour router-id.
|
||||
*/
|
||||
lookup.advRtrAddr.s_addr = restarter->router_id.s_addr;
|
||||
|
||||
if (!hash_lookup(ospf->enable_rtr_list, &lookup)) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, HELPER support is disabled, So not a HELPER",
|
||||
__PRETTY_FUNCTION__);
|
||||
restarter->gr_helper_info.rejected_reason =
|
||||
OSPF_HELPER_SUPPORT_DISABLED;
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check neighbour is in FULL state and
|
||||
* became a adjacency.
|
||||
*/
|
||||
if (!IS_NBR_STATE_FULL(restarter)) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, This Neighbour %s is not in FULL state.",
|
||||
__PRETTY_FUNCTION__, inet_ntoa(restarter->src));
|
||||
restarter->gr_helper_info.rejected_reason =
|
||||
OSPF_HELPER_NOT_A_VALID_NEIGHBOUR;
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
|
||||
/* Based on the restart reason from grace lsa
|
||||
* check the current router is supporting or not
|
||||
*/
|
||||
if (ospf->only_planned_restart
|
||||
&& !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
|
||||
__PRETTY_FUNCTION__);
|
||||
restarter->gr_helper_info.rejected_reason =
|
||||
OSPF_HELPER_PLANNED_ONLY_RESTART;
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
|
||||
/* Check the retranmission list of this
|
||||
* neighbour, check any change in lsas.
|
||||
*/
|
||||
if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
|
||||
&& ospf_check_change_in_rxmt_list(restarter)) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Changed LSA in Rxmt list. So not Helper.",
|
||||
__PRETTY_FUNCTION__);
|
||||
restarter->gr_helper_info.rejected_reason =
|
||||
OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST;
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
|
||||
/*LSA age must be less than the grace period */
|
||||
if (ntohs(lsa->data->ls_age) >= grace_interval) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Grace LSA age(%d) is more than the graceinterval(%d)",
|
||||
__PRETTY_FUNCTION__, lsa->data->ls_age,
|
||||
grace_interval);
|
||||
restarter->gr_helper_info.rejected_reason =
|
||||
OSPF_HELPER_LSA_AGE_MORE;
|
||||
return OSPF_GR_NOT_HELPER;
|
||||
}
|
||||
|
||||
/* check supported grace period configured
|
||||
* if configured, use this to start the grace
|
||||
* timer otherwise use the interval received
|
||||
* in grace LSA packet.
|
||||
*/
|
||||
actual_grace_interval = grace_interval;
|
||||
if (grace_interval > ospf->supported_grace_time) {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Received grace period %d is larger than supported grace %d",
|
||||
__PRETTY_FUNCTION__, grace_interval,
|
||||
ospf->supported_grace_time);
|
||||
actual_grace_interval = ospf->supported_grace_time;
|
||||
}
|
||||
|
||||
if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) {
|
||||
if (restarter->gr_helper_info.t_grace_timer)
|
||||
THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
|
||||
|
||||
if (ospf->active_restarter_cnt > 0)
|
||||
ospf->active_restarter_cnt--;
|
||||
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
|
||||
__PRETTY_FUNCTION__);
|
||||
} else {
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug(
|
||||
"%s, This Router becomes a HELPER for the neighbour %s",
|
||||
__PRETTY_FUNCTION__, inet_ntoa(restarter->src));
|
||||
}
|
||||
|
||||
/* Became a Helper to the RESTART neighbour.
|
||||
* Change the helper status.
|
||||
*/
|
||||
restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER;
|
||||
restarter->gr_helper_info.recvd_grace_period = grace_interval;
|
||||
restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
|
||||
restarter->gr_helper_info.gr_restart_reason = restart_reason;
|
||||
restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
|
||||
|
||||
/* Incremnet the active restarer count */
|
||||
ospf->active_restarter_cnt++;
|
||||
|
||||
if (IS_DEBUG_OSPF_GR_HELPER)
|
||||
zlog_debug("%s, Grace timer started.interval:%d",
|
||||
__PRETTY_FUNCTION__, actual_grace_interval);
|
||||
|
||||
/* Start the grace timer */
|
||||
thread_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
|
||||
actual_grace_interval,
|
||||
&restarter->gr_helper_info.t_grace_timer);
|
||||
|
||||
return OSPF_GR_ACTIVE_HELPER;
|
||||
}
|
||||
|
||||
/*
|
||||
* API to check any change in the neighbor's
|
||||
* retransmission list.
|
||||
*
|
||||
* nbr
|
||||
* ospf neighbor
|
||||
*
|
||||
* Returns:
|
||||
* TRUE - if any change in the lsa.
|
||||
* FALSE - no change in the lsas.
|
||||
*/
|
||||
static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
|
||||
{
|
||||
struct route_node *rn;
|
||||
struct ospf_lsa *lsa;
|
||||
struct route_table *tbl;
|
||||
|
||||
tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db;
|
||||
LSDB_LOOP (tbl, rn, lsa)
|
||||
if (lsa->to_be_acknowledged)
|
||||
return OSPF_GR_TRUE;
|
||||
tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db;
|
||||
LSDB_LOOP (tbl, rn, lsa)
|
||||
if (lsa->to_be_acknowledged)
|
||||
return OSPF_GR_TRUE;
|
||||
|
||||
tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db;
|
||||
LSDB_LOOP (tbl, rn, lsa)
|
||||
if (lsa->to_be_acknowledged)
|
||||
return OSPF_GR_TRUE;
|
||||
|
||||
tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db;
|
||||
LSDB_LOOP (tbl, rn, lsa)
|
||||
if (lsa->to_be_acknowledged)
|
||||
return OSPF_GR_TRUE;
|
||||
|
||||
tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db;
|
||||
LSDB_LOOP (tbl, rn, lsa)
|
||||
if (lsa->to_be_acknowledged)
|
||||
return OSPF_GR_TRUE;
|
||||
|
||||
tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db;
|
||||
LSDB_LOOP (tbl, rn, lsa)
|
||||
if (lsa->to_be_acknowledged)
|
||||
return OSPF_GR_TRUE;
|
||||
|
||||
return OSPF_GR_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Api to exit from HELPER role to take all actions
|
||||
* required at exit.
|
||||
* Ref rfc3623 section 3.2
|
||||
*
|
||||
* ospf
|
||||
* Ospf pointer.
|
||||
*
|
||||
* nbr
|
||||
* Ospf neighbour for which it is acting as HELPER.
|
||||
*
|
||||
* reason
|
||||
* The reason for exiting from HELPER.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*/
|
||||
void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
|
||||
enum ospf_helper_exit_reason reason)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process Maxage Grace LSA.
|
||||
* It is a indication for successfull completion of GR.
|
||||
* If router acting as HELPER, It exits from helper role.
|
||||
*
|
||||
* ospf
|
||||
* Ospf pointer.
|
||||
*
|
||||
* lsa
|
||||
* Grace LSA received from RESTARTER.
|
||||
*
|
||||
* nbr
|
||||
* ospf neighbour which requets the router to act as
|
||||
* HELPER.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*/
|
||||
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
||||
struct ospf_neighbor *nbr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -154,4 +154,10 @@ struct advRtr {
|
||||
|
||||
extern void ospf_gr_helper_init(struct ospf *);
|
||||
extern void ospf_gr_helper_stop(struct ospf *ospf);
|
||||
#endif /* _ZEBRA_OSPF_GR_HELPER_H */
|
||||
extern int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
||||
struct ospf_neighbor *nbr);
|
||||
extern void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
|
||||
enum ospf_helper_exit_reason reason);
|
||||
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
||||
struct ospf_neighbor *nbr);
|
||||
#endif /* _ZEBRA_OSPF_HELPER_H */
|
||||
|
@ -119,6 +119,9 @@ struct ospf_lsa {
|
||||
|
||||
/* VRF Id */
|
||||
vrf_id_t vrf_id;
|
||||
|
||||
/*For topo chg detection in HELPER role*/
|
||||
bool to_be_acknowledged;
|
||||
};
|
||||
|
||||
/* OSPF LSA Link Type. */
|
||||
|
@ -144,7 +144,7 @@ static void nsm_timer_set(struct ospf_neighbor *nbr)
|
||||
/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
|
||||
* the given neighbour
|
||||
*/
|
||||
static int nsm_should_adj(struct ospf_neighbor *nbr)
|
||||
int nsm_should_adj(struct ospf_neighbor *nbr)
|
||||
{
|
||||
struct ospf_interface *oi = nbr->oi;
|
||||
|
||||
|
@ -81,7 +81,7 @@ extern void ospf_check_nbr_loading(struct ospf_neighbor *);
|
||||
extern int ospf_db_summary_isempty(struct ospf_neighbor *);
|
||||
extern int ospf_db_summary_count(struct ospf_neighbor *);
|
||||
extern void ospf_db_summary_clear(struct ospf_neighbor *);
|
||||
|
||||
extern int nsm_should_adj(struct ospf_neighbor *nbr);
|
||||
DECLARE_HOOK(ospf_nsm_change,
|
||||
(struct ospf_neighbor * on, int state, int oldstate),
|
||||
(on, state, oldstate))
|
||||
|
Loading…
Reference in New Issue
Block a user