mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-02-01 16:49:01 +00:00
Merge pull request #6811 from rgirada/test_helper
ospfd: ospfv2 graceful restart helper support.
This commit is contained in:
commit
7fabf208b0
@ -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
|
||||
===========================
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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
964
ospfd/ospf_gr_helper.c
Normal 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
179
ospfd/ospf_gr_helper.h
Normal 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 */
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
597
ospfd/ospf_vty.c
597
ospfd/ospf_vty.c
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user