Merge pull request #6811 from rgirada/test_helper

ospfd: ospfv2 graceful restart helper support.
This commit is contained in:
Russ White 2020-10-12 10:16:27 -04:00 committed by GitHub
commit 7fabf208b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 2039 additions and 19 deletions

View File

@ -853,6 +853,50 @@ Redistribution
.. index:: no router zebra
.. clicmd:: no router zebra
Graceful Restart Helper
=======================
.. index:: graceful-restart helper-only [A.B.C.D]
.. clicmd:: graceful-restart helper-only [A.B.C.D]
.. index:: no graceful-restart helper-only [A.B.C.D]
.. clicmd:: no graceful-restart helper-only [A.B.C.D]
Configure Graceful Restart (RFC 3623) helper support.
By default, helper support is disabled for all neighbours.
This config enables/disables helper support on this router
for all neighbours.
To enable/disable helper support for a specific
neighbour, the router-id (A.B.C.D) has to be specified.
.. index:: graceful-restart helper strict-lsa-checking
.. clicmd:: graceful-restart helper strict-lsa-checking
.. index:: no graceful-restart helper strict-lsa-checking
.. clicmd:: no graceful-restart helper strict-lsa-checking
If 'strict-lsa-checking' is configured then the helper will
abort the Graceful Restart when a LSA change occurs which
affects the restarting router.
By default 'strict-lsa-checking' is enabled"
.. index:: graceful-restart helper supported-grace-time
.. clicmd:: graceful-restart helper supported-grace-time
.. index:: no graceful-restart helper supported-grace-time
.. clicmd:: no graceful-restart helper supported-grace-time
Supports as HELPER for configured grace period.
.. index:: graceful-restart helper planned-only
.. clicmd:: graceful-restart helper planned-only
.. index:: no graceful-restart helper planned-only
.. clicmd:: no graceful-restart helper planned-only
It helps to support as HELPER only for planned
restarts. By default, it supports both planned and
unplanned outages.
.. _showing-ospf-information:
@ -918,6 +962,12 @@ Showing Information
Show the OSPF routing table, as determined by the most recent SPF
calculation.
.. index:: show ip ospf graceful-restart helper [detail] [json]
.. clicmd:: show ip ospf graceful-restart helper [detail] [json]
Displays the Grcaeful Restart Helper details including helper
config changes.
.. _opaque-lsa:
Opaque LSA
@ -1218,10 +1268,17 @@ Debugging OSPF
Show debug information of ZEBRA API
.. index:: debug ospf graceful-restart helper
.. clicmd:: debug ospf graceful-restart helper
.. index:: no debug ospf graceful-restart helper
.. clicmd:: no debug ospf graceful-restart helper
Enable/disable debug information for OSPF Graceful Restart Helper
.. index:: show debugging ospf
.. clicmd:: show debugging ospf
OSPF Configuration Examples
===========================

View File

@ -41,6 +41,9 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_packet.h"
#include "ospfd/ospf_network.h"
#ifndef VTYSH_EXTRACT_PL
#include "ospfd/ospf_dump_clippy.c"
#endif
/* Configuration debug option variables. */
unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@ -55,6 +58,7 @@ unsigned long conf_debug_ospf_ext = 0;
unsigned long conf_debug_ospf_sr = 0;
unsigned long conf_debug_ospf_defaultinfo = 0;
unsigned long conf_debug_ospf_ldp_sync = 0;
unsigned long conf_debug_ospf_gr = 0;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@ -69,6 +73,7 @@ unsigned long term_debug_ospf_ext = 0;
unsigned long term_debug_ospf_sr = 0;
unsigned long term_debug_ospf_defaultinfo;
unsigned long term_debug_ospf_ldp_sync;
unsigned long term_debug_ospf_gr = 0;
const char *ospf_redist_string(unsigned int route_type)
{
@ -1501,6 +1506,26 @@ DEFUN(no_debug_ospf_ldp_sync,
if (vty->node == CONFIG_NODE)
CONF_DEBUG_OFF(ldp_sync, LDP_SYNC);
TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
return CMD_SUCCESS;
}
DEFPY (debug_ospf_gr,
debug_ospf_gr_cmd,
"[no$no] debug ospf graceful-restart helper",
NO_STR
DEBUG_STR OSPF_STR
"Gracefull restart\n"
"Helper Information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_ON(gr, GR_HELPER);
if (!no)
TERM_DEBUG_ON(gr, GR_HELPER);
else
TERM_DEBUG_OFF(gr, GR_HELPER);
return CMD_SUCCESS;
}
@ -1667,6 +1692,10 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf)
if (IS_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC)
vty_out(vty, " OSPF ldp-sync debugging is on\n");
/* Show debug status for GR helper. */
if (IS_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER)
vty_out(vty, " OSPF Graceful Restart Helper debugging is on\n");
vty_out(vty, "\n");
return CMD_SUCCESS;
@ -1853,6 +1882,13 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug ospf%s ldp-sync\n", str);
write = 1;
}
/* debug ospf gr helper */
if (IS_CONF_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER) {
vty_out(vty, "debug ospf%s graceful-restart helper\n", str);
write = 1;
}
return write;
}
@ -1882,6 +1918,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &debug_ospf_gr_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@ -1922,6 +1959,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_ospf_gr_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);

View File

@ -62,6 +62,9 @@
#define OSPF_DEBUG_DEFAULTINFO 0x20
#define OSPF_DEBUG_LDP_SYNC 0x40
#define OSPF_DEBUG_GR_HELPER 0x01
#define OSPF_DEBUG_GR 0x03
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
@ -109,6 +112,7 @@
#define IS_DEBUG_OSPF_DEFAULT_INFO IS_DEBUG_OSPF(defaultinfo, DEFAULTINFO)
#define IS_DEBUG_OSPF_LDP_SYNC IS_DEBUG_OSPF(ldp_sync, LDP_SYNC)
#define IS_DEBUG_OSPF_GR_HELPER IS_DEBUG_OSPF(gr, GR_HELPER)
#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \
(conf_debug_ospf_packet[a] & OSPF_DEBUG_##b)
@ -130,6 +134,7 @@ extern unsigned long term_debug_ospf_ext;
extern unsigned long term_debug_ospf_sr;
extern unsigned long term_debug_ospf_defaultinfo;
extern unsigned long term_debug_ospf_ldp_sync;
extern unsigned long term_debug_ospf_gr;
/* Message Strings. */
extern char *ospf_lsa_type_str[];

View File

@ -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,

964
ospfd/ospf_gr_helper.c Normal file
View File

@ -0,0 +1,964 @@
/*
* OSPF Graceful Restart helper functions.
*
* Copyright (C) 2020-21 Vmware, Inc.
* Rajesh Kumar Girada
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "thread.h"
#include "memory.h"
#include "linklist.h"
#include "prefix.h"
#include "if.h"
#include "table.h"
#include "vty.h"
#include "filter.h"
#include "log.h"
#include "jhash.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
#include "ospfd/ospf_neighbor.h"
#include "ospfd/ospf_spf.h"
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_route.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_errors.h"
#include "ospfd/ospf_nsm.h"
#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 void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa);
static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
static unsigned int ospf_enable_rtr_hash_key(const void *data)
{
const struct advRtr *rtr = data;
return jhash_1word(rtr->advRtrAddr.s_addr, 0);
}
static bool ospf_enable_rtr_hash_cmp(const void *d1, const void *d2)
{
const struct advRtr *rtr1 = (struct advRtr *)d1;
const struct advRtr *rtr2 = (struct advRtr *)d2;
return (rtr1->advRtrAddr.s_addr == rtr2->advRtrAddr.s_addr);
}
static void *ospf_enable_rtr_hash_alloc(void *p)
{
struct advRtr *rid;
rid = XCALLOC(MTYPE_OSPF_GR_HELPER, sizeof(struct advRtr));
rid->advRtrAddr.s_addr = ((struct in_addr *)p)->s_addr;
return rid;
}
static void ospf_disable_rtr_hash_free(void *rtr)
{
XFREE(MTYPE_OSPF_GR_HELPER, rtr);
}
static void ospf_enable_rtr_hash_destroy(struct ospf *ospf)
{
if (ospf->enable_rtr_list == NULL)
return;
hash_clean(ospf->enable_rtr_list, ospf_disable_rtr_hash_free);
hash_free(ospf->enable_rtr_list);
ospf->enable_rtr_list = NULL;
}
/*
* Initialize GR helper config data structures.
*
* OSPF
* OSPF pointer
*
* Returns:
* Nothing
*/
void ospf_gr_helper_init(struct ospf *ospf)
{
int rc;
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__);
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;
ospf->enable_rtr_list =
hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
"OSPF enable router hash");
rc = ospf_register_opaque_functab(
OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, show_ospf_grace_lsa_info, NULL, NULL,
NULL, NULL);
if (rc != 0) {
flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
"%s: Failed to register Grace LSA functions",
__func__);
}
}
/*
* De-Initialize GR helper config data structures.
*
* OSPF
* OSPF pointer
*
* Returns:
* Nothing
*/
void ospf_gr_helper_stop(struct ospf *ospf)
{
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, GR helper deinit.", __PRETTY_FUNCTION__);
ospf_enable_rtr_hash_destroy(ospf);
ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
}
/*
* 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;
}
/*
* Actions to be taken when topo change detected
* HELPER will exit upon topo change.
*
* ospf
* ospf pointer
* lsa
* topo change occured due to this lsa type (1 to 5 and 7)
*
* Returns:
* Nothing
*/
void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
{
struct listnode *node;
struct ospf_interface *oi;
if (!ospf->active_restarter_cnt)
return;
/* Topo change not required to be hanlded if strict
* LSA check is disbaled for this router.
*/
if (!ospf->strict_lsa_check)
return;
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Topo change detected due to lsa LSID:%s type:%d",
__PRETTY_FUNCTION__, inet_ntoa(lsa->data->id),
lsa->data->type);
lsa->to_be_acknowledged = OSPF_GR_TRUE;
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
struct route_node *rn = NULL;
if (ospf_interface_neighbor_count(oi) == 0)
continue;
/* Ref rfc3623 section 3.2.3.b
* 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 ((oi->area->external_routing == OSPF_AREA_STUB)
&& (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
continue;
}
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
struct ospf_neighbor *nbr = NULL;
if (!rn->info)
continue;
nbr = rn->info;
if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_gr_helper_exit(nbr,
OSPF_GR_HELPER_TOPO_CHG);
}
}
}
/*
* 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)
{
struct ospf_interface *oi = nbr->oi;
struct ospf *ospf = oi->ospf;
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
return;
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, Exiting from HELPER support to %s, due to %s",
__PRETTY_FUNCTION__, inet_ntoa(nbr->src),
ospf_exit_reason_desc[reason]);
/* Reset helper status*/
nbr->gr_helper_info.gr_helper_status = OSPF_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;
ospf->last_exit_reason = reason;
if (ospf->active_restarter_cnt <= 0) {
zlog_err(
"OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
return;
}
/* Decrement active Restarter count */
ospf->active_restarter_cnt--;
/* If the exit not triggered due to grace timer
* expairy , stop the grace timer.
*/
if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
/* check exit triggered due to successful completion
* of graceful restart.
* If no, bringdown the neighbour.
*/
if (reason != OSPF_GR_HELPER_COMPLETED) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Failed GR exit, so bringing down the neighbour",
__PRETTY_FUNCTION__);
OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
}
/*Recalculate the DR for the network segment */
ospf_dr_election(oi);
/* Originate a router LSA */
ospf_router_lsa_update_area(oi->area);
/* Originate network lsa if it is an DR in the LAN */
if (oi->state == ISM_DR)
ospf_network_lsa_update(oi);
}
/*
* Process Maxage Grace LSA.
* It is a indication for successful 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)
{
struct in_addr restartAddr = {0};
uint8_t restartReason = 0;
uint32_t graceInterval = 0;
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, &graceInterval, &restartAddr,
&restartReason);
if (ret != OSPF_GR_SUCCESS) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, Wrong Grace LSA packet.",
__PRETTY_FUNCTION__);
return;
}
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, GraceLSA received for neighbour %s.",
__PRETTY_FUNCTION__, inet_ntoa(restartAddr));
/* In case of broadcast links, if RESTARTER is DR_OTHER,
* grace LSA might be received from DR, so fetching the
* actual neighbour information using restarter address.
*/
if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
if (!restarter) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Restarter is not a neighbour for this router.",
__PRETTY_FUNCTION__);
return;
}
} else {
restarter = nbr;
}
ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
}
/* Configuration handlers */
/*
* Disable/Enable HELPER support on router level.
*
* ospf
* OSPFpointer.
*
* status
* TRUE/FALSE
*
* Returns:
* Nothing.
*/
void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
{
struct ospf_interface *oi;
struct listnode *node;
struct advRtr lookup;
if (ospf->is_helper_supported == support)
return;
ospf->is_helper_supported = support;
/* If helper support disabled, cease HELPER role for all
* supporting neighbors.
*/
if (support == OSPF_GR_FALSE) {
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
struct route_node *rn = NULL;
if (ospf_interface_neighbor_count(oi) == 0)
continue;
for (rn = route_top(oi->nbrs); rn;
rn = route_next(rn)) {
struct ospf_neighbor *nbr = NULL;
if (!rn->info)
continue;
nbr = rn->info;
lookup.advRtrAddr.s_addr =
nbr->router_id.s_addr;
/* check if helper support enabled for the
* correspodning routerid.If enabled, dont
* dont exit from helper role.
*/
if (hash_lookup(ospf->enable_rtr_list, &lookup))
continue;
if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_gr_helper_exit(
nbr, OSPF_GR_HELPER_TOPO_CHG);
}
}
}
}
/*
* Enable/Disable HELPER support on a specified advertagement
* router.
*
* ospf
* OSPF pointer.
*
* advRtr
* HELPER support for given Advertisement Router.
*
* support
* True - Enable Helper Support.
* False - Disable Helper Support.
*
* Returns:
* Nothing.
*/
void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
struct in_addr *advrtr,
bool support)
{
struct advRtr temp;
struct advRtr *rtr;
struct ospf_interface *oi;
struct listnode *node;
temp.advRtrAddr.s_addr = advrtr->s_addr;
if (support == OSPF_GR_FALSE) {
/*Delete the routerid from the enable router hash table */
rtr = hash_lookup(ospf->enable_rtr_list, &temp);
if (rtr) {
hash_release(ospf->enable_rtr_list, rtr);
ospf_disable_rtr_hash_free(rtr);
}
/* If helper support is enabled globally
* no action is required.
*/
if (ospf->is_helper_supported)
return;
/* Cease the HELPER role fore neighbours from the
* specified advertisement router.
*/
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
struct route_node *rn = NULL;
if (ospf_interface_neighbor_count(oi) == 0)
continue;
for (rn = route_top(oi->nbrs); rn;
rn = route_next(rn)) {
struct ospf_neighbor *nbr = NULL;
if (!rn->info)
continue;
nbr = rn->info;
if (nbr->router_id.s_addr != advrtr->s_addr)
continue;
if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_gr_helper_exit(
nbr, OSPF_GR_HELPER_TOPO_CHG);
}
}
} else {
/* Add the routerid to the enable router hash table */
hash_get(ospf->enable_rtr_list, &temp,
ospf_enable_rtr_hash_alloc);
}
}
/*
* Api to enable/disable strict lsa check on the HELPER.
*
* ospf
* OSPF pointer.
*
* enabled
* True - disable the lsa check.
* False - enable the strict lsa check.
*
* Returns:
* Nothing.
*/
void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled)
{
if (ospf->strict_lsa_check == enabled)
return;
ospf->strict_lsa_check = enabled;
}
/*
* Api to set the supported grace interval in this router.
*
* ospf
* OSPF pointer.
*
* interval
* The supported grace interval..
*
* Returns:
* Nothing.
*/
void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
uint32_t interval)
{
ospf->supported_grace_time = interval;
}
/*
* Api to set the supported restart reason.
*
* ospf
* OSPF pointer.
*
* planned_only
* True: support only planned restart.
* False: support for planned/unplanned restarts.
*
* Returns:
* Nothing.
*/
void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
bool planned_only)
{
ospf->only_planned_restart = planned_only;
}
/*
* Api to display the grace LSA information.
*
* vty
* vty pointer.
* lsa
* Grace LSA.
* json
* json object
*
* Returns:
* Nothing.
*/
static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
{
struct lsa_header *lsah = NULL;
struct tlv_header *tlvh = NULL;
struct grace_tlv_graceperiod *gracePeriod;
struct grace_tlv_restart_reason *grReason;
struct grace_tlv_restart_addr *restartAddr;
uint16_t length = 0;
int sum = 0;
lsah = (struct lsa_header *)lsa->data;
length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
vty_out(vty, " TLV info:\n");
for (tlvh = TLV_HDR_TOP(lsah); sum < length;
tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case GRACE_PERIOD_TYPE:
gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
sum += TLV_SIZE(tlvh);
vty_out(vty, " Grace period:%d\n",
ntohl(gracePeriod->interval));
break;
case RESTART_REASON_TYPE:
grReason = (struct grace_tlv_restart_reason *)tlvh;
sum += TLV_SIZE(tlvh);
vty_out(vty, " Restart reason:%s\n",
ospf_restart_reason_desc[grReason->reason]);
break;
case RESTARTER_IP_ADDR_TYPE:
restartAddr = (struct grace_tlv_restart_addr *)tlvh;
sum += TLV_SIZE(tlvh);
vty_out(vty, " Restarter address:%s\n",
inet_ntoa(restartAddr->addr));
break;
default:
break;
}
}
}

179
ospfd/ospf_gr_helper.h Normal file
View File

@ -0,0 +1,179 @@
/*
* OSPF Graceful Restart helper functions.
*
* Copyright (C) 2020-21 Vmware, Inc.
* Rajesh Kumar Girada
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ZEBRA_OSPF_GR_HELPER_H
#define _ZEBRA_OSPF_GR_HELPER_H
#define OSPF_GR_NOT_HELPER 0
#define OSPF_GR_ACTIVE_HELPER 1
#define OSPF_GR_HELPER_NO_LSACHECK 0
#define OSPF_GR_HELPER_LSACHECK 1
#define OSPF_MAX_GRACE_INTERVAL 1800
#define OSPF_MIN_GRACE_INTERVAL 1
enum ospf_helper_exit_reason {
OSPF_GR_HELPER_EXIT_NONE = 0,
OSPF_GR_HELPER_INPROGRESS,
OSPF_GR_HELPER_TOPO_CHG,
OSPF_GR_HELPER_GRACE_TIMEOUT,
OSPF_GR_HELPER_COMPLETED
};
enum ospf_gr_restart_reason {
OSPF_GR_UNKNOWN_RESTART = 0,
OSPF_GR_SW_RESTART = 1,
OSPF_GR_SW_UPGRADE = 2,
OSPF_GR_SWITCH_REDUNDANT_CARD = 3,
OSPF_GR_INVALID_REASON_CODE = 4
};
enum ospf_gr_helper_rejected_reason {
OSPF_HELPER_REJECTED_NONE,
OSPF_HELPER_SUPPORT_DISABLED,
OSPF_HELPER_NOT_A_VALID_NEIGHBOUR,
OSPF_HELPER_PLANNED_ONLY_RESTART,
OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST,
OSPF_HELPER_LSA_AGE_MORE
};
/* Ref RFC3623 appendex-A */
/* Grace period TLV */
#define GRACE_PERIOD_TYPE 1
#define GRACE_PERIOD_LENGTH 4
struct grace_tlv_graceperiod {
struct tlv_header header;
uint32_t interval;
};
/* Restart reason TLV */
#define RESTART_REASON_TYPE 2
#define RESTART_REASON_LENGTH 1
struct grace_tlv_restart_reason {
struct tlv_header header;
uint8_t reason;
uint8_t reserved[3];
};
/* Restarter ip address TLV */
#define RESTARTER_IP_ADDR_TYPE 3
#define RESTARTER_IP_ADDR_LEN 4
struct grace_tlv_restart_addr {
struct tlv_header header;
struct in_addr addr;
};
struct ospf_helper_info {
/* Grace interval received from
* Restarting Router.
*/
uint32_t recvd_grace_period;
/* Grace interval used for grace
* gracetimer.
*/
uint32_t actual_grace_period;
/* Grace timer,This Router acts as
* helper until this timer until
* this timer expires*/
struct thread *t_grace_timer;
/* Helper status */
uint32_t gr_helper_status;
/* Helper exit reason*/
enum ospf_helper_exit_reason helper_exit_reason;
/* Planned/Unplanned restart*/
enum ospf_gr_restart_reason gr_restart_reason;
/* Helper rejected reason */
enum ospf_gr_helper_rejected_reason rejected_reason;
};
struct advRtr {
struct in_addr advRtrAddr;
};
#define OSPF_HELPER_ENABLE_RTR_COUNT(ospf) (ospf->enable_rtr_list->count)
/* Check for planned restart */
#define OSPF_GR_IS_PLANNED_RESTART(reason) \
((reason == OSPF_GR_SW_RESTART) || (reason == OSPF_GR_SW_UPGRADE))
/* Check the router is HELPER for current neighbour */
#define OSPF_GR_IS_ACTIVE_HELPER(N) \
((N)->gr_helper_info.gr_helper_status == OSPF_GR_ACTIVE_HELPER)
/* Check the LSA is GRACE LSA */
#define IS_GRACE_LSA(lsa) \
((lsa->data->type == OSPF_OPAQUE_LINK_LSA) \
&& (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)) \
== OPAQUE_TYPE_GRACE_LSA))
/* Check neighbour is in FULL state */
#define IS_NBR_STATE_FULL(nbr) (nsm_should_adj(nbr) && (nbr->state == NSM_Full))
/* Check neighbour is DR_OTHER and state is 2_WAY */
#define IS_NBR_STATE_2_WAY_WITH_DROTHER(nbr) \
((ospf_get_nbr_ism_role(nbr) == ISM_DROther) \
&& (nbr->state == NSM_TwoWay))
#define OSPF_GR_FALSE false
#define OSPF_GR_TRUE true
#define OSPF_GR_SUCCESS 1
#define OSPF_GR_FAILURE 0
#define OSPF_GR_INVALID -1
extern const char *ospf_exit_reason_desc[];
extern const char *ospf_restart_reason_desc[];
extern const char *ospf_rejected_reason_desc[];
extern void ospf_gr_helper_init(struct ospf *ospf);
extern void ospf_gr_helper_stop(struct ospf *ospf);
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);
extern void ospf_process_maxage_grace_lsa(struct ospf *ospf,
struct ospf_lsa *lsa,
struct ospf_neighbor *nbr);
extern void ospf_helper_handle_topo_chg(struct ospf *ospf,
struct ospf_lsa *lsa);
extern void ospf_gr_helper_support_set(struct ospf *ospf, bool support);
extern void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
struct in_addr *rid,
bool support);
extern void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool lsacheck);
extern void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
uint32_t interval);
extern void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
bool planned_only);
#endif /* _ZEBRA_OSPF_HELPER_H */

View File

@ -796,9 +796,36 @@ int ospf_if_up(struct ospf_interface *oi)
int ospf_if_down(struct ospf_interface *oi)
{
struct ospf *ospf;
if (oi == NULL)
return 0;
ospf = oi->ospf;
/* Cease the HELPER role for all the neighbours
* of this interface.
*/
if (ospf->is_helper_supported) {
struct route_node *rn = NULL;
if (ospf_interface_neighbor_count(oi)) {
for (rn = route_top(oi->nbrs); rn;
rn = route_next(rn)) {
struct ospf_neighbor *nbr = NULL;
if (!rn->info)
continue;
nbr = rn->info;
if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_gr_helper_exit(
nbr, OSPF_GR_HELPER_TOPO_CHG);
}
}
}
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown);
/* delete position in router LSA */
oi->lsa_pos_beg = 0;

View File

@ -201,7 +201,7 @@ static void ospf_dr_change(struct ospf *ospf, struct route_table *nbrs)
}
}
static int ospf_dr_election(struct ospf_interface *oi)
int ospf_dr_election(struct ospf_interface *oi)
{
struct in_addr old_dr, old_bdr;
int old_state, new_state;

View File

@ -99,6 +99,7 @@
extern int ospf_ism_event(struct thread *);
extern void ism_change_status(struct ospf_interface *, int);
extern int ospf_hello_timer(struct thread *thread);
extern int ospf_dr_election(struct ospf_interface *oi);
DECLARE_HOOK(ospf_ism_change,
(struct ospf_interface * oi, int state, int oldstate),

View File

@ -164,6 +164,7 @@ struct ospf_lsa *ospf_lsa_new(void)
new->tv_orig = new->tv_recv;
new->refresh_list = -1;
new->vrf_id = VRF_DEFAULT;
new->to_be_acknowledged = 0;
return new;
}
@ -2578,8 +2579,19 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi,
/* Do comparision and record if recalc needed. */
rt_recalc = 0;
if (old == NULL || ospf_lsa_different(old, lsa))
if (old == NULL || ospf_lsa_different(old, lsa)) {
/* Ref rfc3623 section 3.2.3
* Installing new lsa or change in the existing LSA
* or flushing existing LSA leads to topo change
* and trigger SPF caculation.
* So, router should be aborted from HELPER role
* if it is detected as TOPO change.
*/
if (CHECK_LSA_TYPE_1_TO_5_OR_7(lsa->data->type))
ospf_helper_handle_topo_chg(ospf, lsa);
rt_recalc = 1;
}
/*
Sequence number check (Section 14.1 of rfc 2328)

View File

@ -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. */
@ -221,6 +224,11 @@ struct as_external_lsa {
if (!(T)) \
(T) = thread_add_timer(master, (F), 0, 2)
#define CHECK_LSA_TYPE_1_TO_5_OR_7(type) \
((type == OSPF_ROUTER_LSA) || (type == OSPF_NETWORK_LSA) \
|| (type == OSPF_SUMMARY_LSA) || (type == OSPF_ASBR_SUMMARY_LSA) \
|| (type == OSPF_AS_EXTERNAL_LSA) || (type == OSPF_AS_NSSA_LSA))
/* Prototypes. */
/* XXX: Eek, time functions, similar are in lib/thread.c */
extern struct timeval int2tv(int);

View File

@ -56,3 +56,4 @@ DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters")
DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters")
DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters")
DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters")
DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper")

View File

@ -55,5 +55,6 @@ DECLARE_MTYPE(OSPF_ROUTER_INFO)
DECLARE_MTYPE(OSPF_PCE_PARAMS)
DECLARE_MTYPE(OSPF_SR_PARAMS)
DECLARE_MTYPE(OSPF_EXT_PARAMS)
DECLARE_MTYPE(OSPF_GR_HELPER)
#endif /* _QUAGGA_OSPF_MEMORY_H */

View File

@ -43,6 +43,7 @@
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_gr_helper.h"
/* Fill in the the 'key' as appropriate to retrieve the entry for nbr
* from the ospf_interface's nbrs table. Indexed by interface address
@ -99,6 +100,14 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi)
nbr->crypt_seqnum = 0;
ospf_bfd_info_nbr_create(oi, nbr);
/* Initialize GR Helper info*/
nbr->gr_helper_info.recvd_grace_period = 0;
nbr->gr_helper_info.actual_grace_period = 0;
nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
nbr->gr_helper_info.helper_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
nbr->gr_helper_info.gr_restart_reason = OSPF_GR_UNKNOWN_RESTART;
return nbr;
}
@ -142,6 +151,8 @@ void ospf_nbr_free(struct ospf_neighbor *nbr)
ospf_bfd_info_free(&nbr->bfd_info);
OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer);
nbr->oi = NULL;
XFREE(MTYPE_OSPF_NEIGHBOR, nbr);
}

View File

@ -22,6 +22,7 @@
#ifndef _ZEBRA_OSPF_NEIGHBOR_H
#define _ZEBRA_OSPF_NEIGHBOR_H
#include <ospfd/ospf_gr_helper.h>
#include <ospfd/ospf_packet.h>
/* Neighbor Data Structure */
@ -88,6 +89,9 @@ struct ospf_neighbor {
/* BFD information */
void *bfd_info;
/* ospf graceful restart HELPER info */
struct ospf_helper_info gr_helper_info;
};
/* Macros. */
@ -113,5 +117,4 @@ extern struct ospf_neighbor *ospf_nbr_lookup_by_addr(struct route_table *,
extern struct ospf_neighbor *ospf_nbr_lookup_by_routerid(struct route_table *,
struct in_addr *);
extern void ospf_renegotiate_optional_capabilities(struct ospf *top);
#endif /* _ZEBRA_OSPF_NEIGHBOR_H */

View File

@ -70,7 +70,15 @@ static int ospf_inactivity_timer(struct thread *thread)
IF_NAME(nbr->oi), inet_ntoa(nbr->router_id),
ospf_get_name(nbr->oi->ospf));
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
/* Dont trigger NSM_InactivityTimer event , if the current
* router acting as HELPER for this neighbour.
*/
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
else if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Acting as HELPER for this neighbour, So inactivitytimer event will not be fired.",
__PRETTY_FUNCTION__);
return 0;
}
@ -144,7 +152,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;
@ -689,7 +697,11 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state)
lookup_msg(ospf_nsm_state_msg, old_state, NULL),
lookup_msg(ospf_nsm_state_msg, state, NULL));
ospf_router_lsa_update_area(oi->area);
/* Dont originate router LSA if the current
* router is acting as a HELPER for this neighbour.
*/
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_router_lsa_update_area(oi->area);
if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
vl_area = ospf_area_lookup_by_area_id(
@ -699,15 +711,21 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state)
ospf_router_lsa_update_area(vl_area);
}
/* Originate network-LSA. */
if (oi->state == ISM_DR) {
if (oi->network_lsa_self && oi->full_nbrs == 0) {
ospf_lsa_flush_area(oi->network_lsa_self,
oi->area);
ospf_lsa_unlock(&oi->network_lsa_self);
oi->network_lsa_self = NULL;
} else
ospf_network_lsa_update(oi);
/* Dont originate/flush network LSA if the current
* router is acting as a HELPER for this neighbour.
*/
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
/* Originate network-LSA. */
if (oi->state == ISM_DR) {
if (oi->network_lsa_self
&& oi->full_nbrs == 0) {
ospf_lsa_flush_area(
oi->network_lsa_self, oi->area);
ospf_lsa_unlock(&oi->network_lsa_self);
oi->network_lsa_self = NULL;
} else
ospf_network_lsa_update(oi);
}
}
}

View File

@ -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))

View File

@ -54,6 +54,7 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_errors.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_gr_helper.h"
/*
* OSPF Fragmentation / fragmented writes
@ -1058,7 +1059,16 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh,
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_TwoWayReceived);
nbr->options |= hello->options;
} else {
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_OneWayReceived);
/* If the router is DR_OTHER, RESTARTER will not wait
* until it receives the hello from it if it receives
* from DR and BDR.
* So, helper might receives ONW_WAY hello from
* RESTARTER. So not allowing to change the state if it
* receives one_way hellow when it acts as HELPER for
* that specific neighbor.
*/
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_OneWayReceived);
/* Set neighbor information. */
nbr->priority = hello->priority;
nbr->d_router = hello->d_router;
@ -4262,6 +4272,12 @@ void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
struct ospf_interface *oi = nbr->oi;
if (IS_GRACE_LSA(lsa)) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, Sending GRACE ACK to Restarter.",
__PRETTY_FUNCTION__);
}
if (listcount(oi->ls_ack_direct.ls_ack) == 0)
oi->ls_ack_direct.dst = nbr->address.u.prefix4;

View File

@ -5121,6 +5121,71 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
" Thread Link State Update Retransmission %s\n\n",
nbr->t_ls_upd != NULL ? "on" : "off");
if (!use_json) {
vty_out(vty, " Graceful restart Helper info:\n");
if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
vty_out(vty,
" Graceful Restart HELPER Status : Inprogress.\n");
vty_out(vty,
" Graceful Restart grace period time: %d (seconds).\n",
nbr->gr_helper_info.recvd_grace_period);
vty_out(vty, " Graceful Restart reason: %s.\n",
ospf_restart_reason_desc
[nbr->gr_helper_info
.gr_restart_reason]);
} else {
vty_out(vty,
" Graceful Restart HELPER Status : None\n");
}
if (nbr->gr_helper_info.rejected_reason
!= OSPF_HELPER_REJECTED_NONE)
vty_out(vty, " Helper rejected reason: %s.\n",
ospf_rejected_reason_desc
[nbr->gr_helper_info.rejected_reason]);
if (nbr->gr_helper_info.helper_exit_reason
!= OSPF_GR_HELPER_EXIT_NONE)
vty_out(vty, " Last helper exit reason: %s.\n\n",
ospf_exit_reason_desc
[nbr->gr_helper_info
.helper_exit_reason]);
else
vty_out(vty, "\n");
} else {
json_object_string_add(json_neigh, "grHelperStatus",
OSPF_GR_IS_ACTIVE_HELPER(nbr) ?
"Inprogress"
: "None");
if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
json_object_int_add(
json_neigh, "graceInterval",
nbr->gr_helper_info.recvd_grace_period);
json_object_string_add(
json_neigh, "grRestartReason",
ospf_restart_reason_desc
[nbr->gr_helper_info
.gr_restart_reason]);
}
if (nbr->gr_helper_info.rejected_reason
!= OSPF_HELPER_REJECTED_NONE)
json_object_string_add(
json_neigh, "helperRejectReason",
ospf_rejected_reason_desc
[nbr->gr_helper_info.rejected_reason]);
if (nbr->gr_helper_info.helper_exit_reason
!= OSPF_GR_HELPER_EXIT_NONE)
json_object_string_add(
json_neigh, "helperExitReason",
ospf_exit_reason_desc
[nbr->gr_helper_info
.helper_exit_reason]);
}
ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0);
if (use_json)
@ -8988,6 +9053,487 @@ DEFUN (no_ospf_proactive_arp,
return CMD_SUCCESS;
}
/* Graceful Restart HELPER Commands */
DEFPY(ospf_gr_helper_enable, ospf_gr_helper_enable_cmd,
"graceful-restart helper-only [A.B.C.D]",
"OSPF Graceful Restart\n"
"Enable Helper support\n"
"Advertising router id\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
struct in_addr addr;
int ret;
if (argc == 3) {
ret = inet_aton(argv[2]->arg, &addr);
if (!ret) {
vty_out(vty,
"Please specify the valid routerid address.\n");
return CMD_WARNING_CONFIG_FAILED;
}
ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE);
return CMD_SUCCESS;
}
ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE);
return CMD_SUCCESS;
}
DEFPY(no_ospf_gr_helper_enable,
no_ospf_gr_helper_enable_cmd,
"no graceful-restart helper-only [A.B.C.D]",
NO_STR
"OSPF Graceful Restart\n"
"Disable Helper support\n"
"Advertising router id\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
struct in_addr addr;
int ret;
if (argc == 4) {
ret = inet_aton(argv[3]->arg, &addr);
if (!ret) {
vty_out(vty,
"Please specify the valid routerid address.\n");
return CMD_WARNING_CONFIG_FAILED;
}
ospf_gr_helper_support_set_per_routerid(ospf, &addr,
OSPF_GR_FALSE);
return CMD_SUCCESS;
}
ospf_gr_helper_support_set(ospf, OSPF_GR_FALSE);
return CMD_SUCCESS;
}
DEFPY(ospf_gr_helper_enable_lsacheck,
ospf_gr_helper_enable_lsacheck_cmd,
"graceful-restart helper strict-lsa-checking",
"OSPF Graceful Restart\n"
"OSPF GR Helper\n"
"Enable strict LSA check\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_TRUE);
return CMD_SUCCESS;
}
DEFPY(no_ospf_gr_helper_enable_lsacheck,
no_ospf_gr_helper_enable_lsacheck_cmd,
"no graceful-restart helper strict-lsa-checking",
NO_STR
"OSPF Graceful Restart\n"
"OSPF GR Helper\n"
"Disable strict LSA check\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_FALSE);
return CMD_SUCCESS;
}
DEFPY(ospf_gr_helper_supported_grace_time,
ospf_gr_helper_supported_grace_time_cmd,
"graceful-restart helper supported-grace-time (10-1800)$interval",
"OSPF Graceful Restart\n"
"OSPF GR Helper\n"
"Supported grace timer\n"
"Grace interval(in seconds)\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf_gr_helper_supported_gracetime_set(ospf, interval);
return CMD_SUCCESS;
}
DEFPY(no_ospf_gr_helper_supported_grace_time,
no_ospf_gr_helper_supported_grace_time_cmd,
"no graceful-restart helper supported-grace-time (10-1800)$interval",
NO_STR
"OSPF Graceful Restart\n"
"OSPF GR Helper\n"
"Supported grace timer\n"
"Grace interval(in seconds)\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf_gr_helper_supported_gracetime_set(ospf, OSPF_MAX_GRACE_INTERVAL);
return CMD_SUCCESS;
}
DEFPY(ospf_gr_helper_planned_only,
ospf_gr_helper_planned_only_cmd,
"graceful-restart helper planned-only",
"OSPF Graceful Restart\n"
"OSPF GR Helper\n"
"Supported only planned restart\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_TRUE);
return CMD_SUCCESS;
}
DEFPY(no_ospf_gr_helper_planned_only,
no_ospf_gr_helper_planned_only_cmd,
"no graceful-restart helper planned-only",
NO_STR
"OSPF Graceful Restart\n"
"OSPF GR Helper\n"
"Supported only for planned restart\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_FALSE);
return CMD_SUCCESS;
}
static int ospf_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *backet,
void *arg)
{
struct advRtr *rtr = backet->data;
struct vty *vty = (struct vty *)arg;
static unsigned int count;
vty_out(vty, "%-6s,", inet_ntoa(rtr->advRtrAddr));
count++;
if (count % 5 == 0)
vty_out(vty, "\n");
return HASHWALK_CONTINUE;
}
static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf,
uint8_t use_vrf, json_object *json,
bool uj, bool detail)
{
struct listnode *node;
struct ospf_interface *oi;
json_object *json_vrf = NULL;
if (uj) {
if (use_vrf)
json_vrf = json_object_new_object();
else
json_vrf = json;
}
if (ospf->instance) {
if (uj)
json_object_int_add(json, "ospfInstance",
ospf->instance);
else
vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
}
ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
if (uj) {
if (use_vrf) {
if (ospf->vrf_id == VRF_DEFAULT)
json_object_object_add(json, "default",
json_vrf);
else
json_object_object_add(json, ospf->name,
json_vrf);
}
} else
vty_out(vty, "\n");
/* Show Router ID. */
if (uj) {
json_object_string_add(json_vrf, "routerId",
inet_ntoa(ospf->router_id));
} else {
vty_out(vty, "\n OSPF Router with ID (%s)\n\n",
inet_ntoa(ospf->router_id));
}
if (!uj) {
if (ospf->is_helper_supported)
vty_out(vty,
" Graceful restart helper support enabled.\n");
else
vty_out(vty,
" Graceful restart helper support disabled.\n");
if (ospf->strict_lsa_check)
vty_out(vty, " Strict LSA check is enabled.\n");
else
vty_out(vty, " Strict LSA check is disabled.\n");
if (ospf->only_planned_restart)
vty_out(vty,
" Helper supported for planned restarts only.\n");
else
vty_out(vty,
" Helper supported for Planned and Unplanned Restarts.\n");
vty_out(vty,
" Supported Graceful restart interval: %d(in seconds).\n",
ospf->supported_grace_time);
if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) {
vty_out(vty, " Enable Router list:\n");
vty_out(vty, " ");
hash_walk(ospf->enable_rtr_list,
ospf_print_vty_helper_dis_rtr_walkcb, vty);
vty_out(vty, "\n\n");
}
if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) {
vty_out(vty, " Last Helper exit Reason :%s\n",
ospf_exit_reason_desc[ospf->last_exit_reason]);
}
if (ospf->active_restarter_cnt)
vty_out(vty,
" Number of Active neighbours in graceful restart: %d\n",
ospf->active_restarter_cnt);
else
vty_out(vty, "\n");
} else {
json_object_string_add(
json_vrf, "helperSupport",
(ospf->is_helper_supported) ? "Enabled" : "Disabled");
json_object_string_add(json_vrf, "strictLsaCheck",
(ospf->strict_lsa_check) ? "Enabled"
: "Disabled");
json_object_string_add(
json_vrf, "restartSupoort",
(ospf->only_planned_restart)
? "Planned Restart only"
: "Planned and Unplanned Restarts");
json_object_int_add(json_vrf, "supportedGracePeriod",
ospf->supported_grace_time);
if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE)
json_object_string_add(
json_vrf, "LastExitReason",
ospf_exit_reason_desc[ospf->last_exit_reason]);
if (ospf->active_restarter_cnt)
json_object_int_add(json_vrf, "activeRestarterCnt",
ospf->active_restarter_cnt);
}
if (detail) {
int cnt = 1;
json_object *json_neighbors = NULL;
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
struct route_node *rn;
struct ospf_neighbor *nbr;
json_object *json_neigh;
if (ospf_interface_neighbor_count(oi) == 0)
continue;
if (uj) {
json_object_object_get_ex(json_vrf, "Neighbors",
&json_neighbors);
if (!json_neighbors) {
json_neighbors =
json_object_new_object();
json_object_object_add(json_vrf,
"Neighbors",
json_neighbors);
}
}
for (rn = route_top(oi->nbrs); rn;
rn = route_next(rn)) {
if (!rn->info)
continue;
nbr = rn->info;
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
continue;
if (!uj) {
vty_out(vty, " Neighbour %d :\n", cnt);
vty_out(vty, " Address : %s\n",
inet_ntoa(nbr->address.u
.prefix4));
vty_out(vty, " Routerid : %s\n",
inet_ntoa(nbr->router_id));
vty_out(vty,
" Received Grace period : %d(in seconds).\n",
nbr->gr_helper_info
.recvd_grace_period);
vty_out(vty,
" Actual Grace period : %d(in seconds)\n",
nbr->gr_helper_info
.actual_grace_period);
vty_out(vty,
" Remaining GraceTime:%ld(in seconds).\n",
thread_timer_remain_second(
nbr->gr_helper_info
.t_grace_timer));
vty_out(vty,
" Graceful Restart reason: %s.\n\n",
ospf_restart_reason_desc
[nbr->gr_helper_info
.gr_restart_reason]);
cnt++;
} else {
json_neigh = json_object_new_object();
json_object_string_add(
json_neigh, "srcAddr",
inet_ntoa(nbr->src));
json_object_string_add(
json_neigh, "routerid",
inet_ntoa(nbr->router_id));
json_object_int_add(
json_neigh,
"recvdGraceInterval",
nbr->gr_helper_info
.recvd_grace_period);
json_object_int_add(
json_neigh,
"actualGraceInterval",
nbr->gr_helper_info
.actual_grace_period);
json_object_int_add(
json_neigh, "remainGracetime",
thread_timer_remain_second(
nbr->gr_helper_info
.t_grace_timer));
json_object_string_add(
json_neigh, "restartReason",
ospf_restart_reason_desc
[nbr->gr_helper_info
.gr_restart_reason]);
json_object_object_add(
json_neighbors,
inet_ntoa(nbr->src),
json_neigh);
}
}
}
}
return CMD_SUCCESS;
}
DEFPY (show_ip_ospf_gr_helper,
show_ip_ospf_gr_helper_cmd,
"show ip ospf [vrf <NAME|all>] graceful-restart helper [detail] [json]",
SHOW_STR
IP_STR
"OSPF information\n"
VRF_CMD_HELP_STR
"All VRFs\n"
"OSPF Graceful Restart\n"
"Helper details in the router\n"
"Detailed informtion\n"
JSON_STR)
{
char *vrf_name = NULL;
bool all_vrf = false;
int ret = CMD_SUCCESS;
int idx_vrf = 0;
int idx = 0;
uint8_t use_vrf = 0;
bool uj = use_json(argc, argv);
struct ospf *ospf = NULL;
json_object *json = NULL;
struct listnode *node = NULL;
int inst = 0;
bool detail = false;
OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
if (argv_find(argv, argc, "detail", &idx))
detail = true;
if (uj)
json = json_object_new_object();
/* vrf input is provided */
if (vrf_name) {
use_vrf = 1;
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
if (!ospf->oi_running)
continue;
ret = ospf_show_gr_helper_details(
vty, ospf, use_vrf, json, uj, detail);
}
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return ret;
}
ospf = ospf_lookup_by_inst_name(inst, vrf_name);
if (ospf == NULL || !ospf->oi_running) {
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else
vty_out(vty, "%% OSPF instance not found\n");
return CMD_SUCCESS;
}
} else {
/* Default Vrf */
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else
vty_out(vty, "%% OSPF instance not found\n");
return CMD_SUCCESS;
}
ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj,
detail);
}
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
/* Graceful Restart HELPER commands end */
static void config_write_stub_router(struct vty *vty, struct ospf *ospf)
{
struct listnode *ln;
@ -10310,6 +10856,41 @@ static int config_write_ospf_redistribute(struct vty *vty, struct ospf *ospf)
return 0;
}
static int ospf_cfg_write_helper_dis_rtr_walkcb(struct hash_bucket *backet,
void *arg)
{
struct advRtr *rtr = backet->data;
struct vty *vty = (struct vty *)arg;
vty_out(vty, " graceful-restart helper-only %s\n",
inet_ntoa(rtr->advRtrAddr));
return HASHWALK_CONTINUE;
}
static int config_write_ospf_gr_helper(struct vty *vty, struct ospf *ospf)
{
if (ospf->is_helper_supported)
vty_out(vty, " graceful-restart helper-only\n");
if (!ospf->strict_lsa_check)
vty_out(vty, " no graceful-restart helper strict-lsa-checking\n");
if (ospf->only_planned_restart)
vty_out(vty, " graceful-restart helper planned-only\n");
if (ospf->supported_grace_time != OSPF_MAX_GRACE_INTERVAL)
vty_out(vty,
" graceful-restart helper supported-grace-time %d\n",
ospf->supported_grace_time);
if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) {
hash_walk(ospf->enable_rtr_list,
ospf_cfg_write_helper_dis_rtr_walkcb, vty);
}
return 0;
}
static int config_write_ospf_default_metric(struct vty *vty, struct ospf *ospf)
{
if (ospf->default_metric != -1)
@ -10477,6 +11058,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
/* Redistribute information print. */
config_write_ospf_redistribute(vty, ospf);
/* Print gr helper configs */
config_write_ospf_gr_helper(vty, ospf);
/* passive-interface print. */
if (ospf->passive_interface_default == OSPF_IF_PASSIVE)
vty_out(vty, " passive-interface default\n");
@ -10620,6 +11204,9 @@ void ospf_vty_show_init(void)
/* "show ip ospf vrfs" commands. */
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
/* "show ip ospf gr-helper details" command */
install_element(VIEW_NODE, &show_ip_ospf_gr_helper_cmd);
}
@ -10735,6 +11322,16 @@ static void ospf_vty_zebra_init(void)
install_element(OSPF_NODE, &no_ospf_distance_cmd);
install_element(OSPF_NODE, &no_ospf_distance_ospf_cmd);
install_element(OSPF_NODE, &ospf_distance_ospf_cmd);
/*Ospf garcefull restart helper configurations */
install_element(OSPF_NODE, &ospf_gr_helper_enable_cmd);
install_element(OSPF_NODE, &no_ospf_gr_helper_enable_cmd);
install_element(OSPF_NODE, &ospf_gr_helper_enable_lsacheck_cmd);
install_element(OSPF_NODE, &no_ospf_gr_helper_enable_lsacheck_cmd);
install_element(OSPF_NODE, &ospf_gr_helper_supported_grace_time_cmd);
install_element(OSPF_NODE, &no_ospf_gr_helper_supported_grace_time_cmd);
install_element(OSPF_NODE, &ospf_gr_helper_planned_only_cmd);
install_element(OSPF_NODE, &no_ospf_gr_helper_planned_only_cmd);
#if 0
install_element (OSPF_NODE, &ospf_distance_source_cmd);
install_element (OSPF_NODE, &no_ospf_distance_source_cmd);

View File

@ -59,6 +59,7 @@
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_ase.h"
#include "ospfd/ospf_ldp_sync.h"
#include "ospfd/ospf_gr_helper.h"
DEFINE_QOBJ_TYPE(ospf)
@ -309,6 +310,8 @@ static struct ospf *ospf_new(unsigned short instance, const char *name)
new->proactive_arp = OSPF_PROACTIVE_ARP_DEFAULT;
ospf_gr_helper_init(new);
QOBJ_REG(new, ospf);
new->fd = -1;
@ -766,6 +769,9 @@ static void ospf_finish_final(struct ospf *ospf)
list_delete(&ospf->areas);
list_delete(&ospf->oi_write_q);
/* Reset GR helper data structers */
ospf_gr_helper_stop(ospf);
close(ospf->fd);
stream_free(ospf->ibuf);
ospf->fd = -1;

View File

@ -319,7 +319,41 @@ struct ospf {
/* Redistributed external information. */
struct list *external[ZEBRA_ROUTE_MAX + 1];
#define EXTERNAL_INFO(E) (E->external_info)
#define EXTERNAL_INFO(E) (E->external_info)
/* Gracefull restart Helper supported configs*/
/* Supported grace interval*/
uint32_t supported_grace_time;
/* Helper support
* Supported : True
* Not Supported : False.
*/
bool is_helper_supported;
/* Support for strict LSA check.
* if it is set,Helper aborted
* upon a TOPO change.
*/
bool strict_lsa_check;
/* Support as HELPER only for
* planned restarts.
*/
bool only_planned_restart;
/* This list contains the advertisement
* routerids which are not support for HELPERs.
*/
struct hash *enable_rtr_list;
/* HELPER for number of active
* RESTARTERs.
*/
uint16_t active_restarter_cnt;
/* last HELPER exit reason */
uint32_t last_exit_reason;
/* MPLS LDP-IGP Sync */
struct ldp_sync_info_cmd ldp_sync_cmd;

View File

@ -57,6 +57,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_vty.c \
ospfd/ospf_zebra.c \
ospfd/ospfd.c \
ospfd/ospf_gr_helper.c \
# end
if OSPFD
@ -78,6 +79,7 @@ endif
clippy_scan += \
ospfd/ospf_vty.c \
ospfd/ospf_ldp_sync.c \
ospfd/ospf_dump.c \
# end
noinst_HEADERS += \
@ -102,6 +104,7 @@ noinst_HEADERS += \
ospfd/ospf_te.h \
ospfd/ospf_vty.h \
ospfd/ospf_zebra.h \
ospfd/ospf_gr_helper.h \
# end
ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM)