Skip to content

Commit

Permalink
ospf6d: introduce support for Graceful Restart (restarting mode)
Browse files Browse the repository at this point in the history
RFC 5187 specifies the Graceful Restart enhancement to the OSPFv3
routing protocol. This commit implements support for the GR
restarting mode.

Here's a quick summary of how the GR restarting mode works:
* GR can be enabled on a per-instance basis using the `graceful-restart
  [grace-period (1-1800)]` command;
* To perform a graceful shutdown, the `graceful-restart prepare ipv6
  ospf` EXEC-level command needs to be issued before restarting the
  ospf6d daemon (there's no specific requirement on how the daemon
  should be restarted);
* `graceful-restart prepare ospf` will initiate the graceful restart
  for all GR-enabled instances by taking the following actions:
  o Flooding Grace-LSAs over all interfaces
  o Freezing the OSPF routes in the RIB
  o Saving the end of the grace period in non-volatile memory (a JSON
    file stored in `$frr_statedir`)
* Once ospf6d is started again, it will follow the procedures
  described in RFC 3623 until it detects it's time to exit the graceful
  restart (either successfully or unsuccessfully).

Testing done:
* New topotest featuring a multi-area OSPF topology (including stub
  and NSSA areas);
* Successful interop tests against IOS-XR routers acting as helpers.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
  • Loading branch information
rwestphal committed Sep 16, 2021
1 parent 1a89846 commit 7116509
Show file tree
Hide file tree
Showing 21 changed files with 1,032 additions and 19 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,7 @@ AC_DEFINE_UNQUOTED([LDPD_SOCKET], ["$frr_statedir%s%s/ldpd.sock"], [ldpd control
AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra api socket])
AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory])

Expand Down
23 changes: 21 additions & 2 deletions doc/user/ospf6d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,17 @@ Redistribute routes to OSPF6
argument injects the default route regardless of it being present in the
router. Metric values and route-map can also be specified optionally.

Graceful Restart Helper
=======================
Graceful Restart
================

.. clicmd:: graceful-restart [grace-period (1-1800)]


Configure Graceful Restart (RFC 5187) restarting support.
When enabled, the default grace period is 120 seconds.

To perform a graceful shutdown, the "graceful-restart prepare ipv6 ospf"
EXEC-level command needs to be issued before restarting the ospf6d daemon.

.. clicmd:: graceful-restart helper-only [A.B.C.D]

Expand Down Expand Up @@ -297,6 +306,16 @@ Graceful Restart Helper
restarts. By default, it supports both planned and
unplanned outages.

.. clicmd:: graceful-restart prepare ipv6 ospf


Initiate a graceful restart for all OSPFv3 instances configured with the
"graceful-restart" command. The ospf6d daemon should be restarted during
the instance-specific grace period, otherwise the graceful restart will fail.

This is an EXEC-level command.


.. _showing-ospf6-information:

Showing OSPF6 information
Expand Down
8 changes: 8 additions & 0 deletions ospf6d/ospf6_asbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "ospf6d.h"
#include "ospf6_spf.h"
#include "ospf6_nssa.h"
#include "ospf6_gr.h"
#include "lib/json.h"

DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
Expand Down Expand Up @@ -102,6 +103,13 @@ struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route,
struct ospf6_as_external_lsa *as_external_lsa;
caddr_t p;

if (ospf6->gr_info.restart_in_progress) {
if (IS_DEBUG_OSPF6_GR)
zlog_debug(
"Graceful Restart in progress, don't originate LSA");
return NULL;
}

if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
zlog_debug("Originate AS-External-LSA for %pFX",
&route->prefix);
Expand Down
42 changes: 30 additions & 12 deletions ospf6d/ospf6_flood.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa)
return lsdb_self;
}

void ospf6_lsa_originate(struct ospf6_lsa *lsa)
void ospf6_lsa_originate(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
{
struct ospf6_lsa *old;
struct ospf6_lsdb *lsdb_self;
Expand All @@ -106,7 +106,8 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)

/* if the new LSA does not differ from previous,
suppress this update of the LSA */
if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)) {
if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)
&& !ospf6->gr_info.finishing_restart) {
if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type))
zlog_debug("Suppress updating LSA: %s", lsa->name);
ospf6_lsa_delete(lsa);
Expand Down Expand Up @@ -134,20 +135,20 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
void ospf6_lsa_originate_process(struct ospf6_lsa *lsa, struct ospf6 *process)
{
lsa->lsdb = process->lsdb;
ospf6_lsa_originate(lsa);
ospf6_lsa_originate(process, lsa);
}

void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
{
lsa->lsdb = oa->lsdb;
ospf6_lsa_originate(lsa);
ospf6_lsa_originate(oa->ospf6, lsa);
}

void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
struct ospf6_interface *oi)
{
lsa->lsdb = oi->lsdb;
ospf6_lsa_originate(lsa);
ospf6_lsa_originate(oi->area->ospf6, lsa);
}

void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
Expand Down Expand Up @@ -326,7 +327,8 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
lsa->installed = now;

/* Topo change handling */
if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))) {
if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))
&& !CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)) {

/* check if it is new lsa ? or existing lsa got modified ?*/
if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) {
Expand Down Expand Up @@ -991,6 +993,8 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,

/* if no database copy or received is more recent */
if (old == NULL || ismore_recent < 0) {
bool self_originated;

/* in case we have no database copy */
ismore_recent = -1;

Expand Down Expand Up @@ -1029,12 +1033,13 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
reoriginated instance of the LSA not to be rejected by other
routers
due to MinLSArrival. */
if (new->header->adv_router
!= from->ospf6_if->area->ospf6->router_id)
self_originated = (new->header->adv_router
== from->ospf6_if->area->ospf6->router_id);
if (!self_originated)
ospf6_flood(from, new);

/* Received Grace-LSA */
if (IS_GRACE_LSA(new)) {
/* Received non-self-originated Grace LSA. */
if (IS_GRACE_LSA(new) && !self_originated) {
struct ospf6 *ospf6;

ospf6 = ospf6_get_by_lsdb(new);
Expand Down Expand Up @@ -1088,8 +1093,16 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
ospf6_acknowledge_lsa(new, ismore_recent, from);

/* (f) Self Originated LSA, section 13.4 */
if (new->header->adv_router
== from->ospf6_if->area->ospf6->router_id) {
if (self_originated) {
if (from->ospf6_if->area->ospf6->gr_info
.restart_in_progress) {
if (IS_DEBUG_OSPF6_GR)
zlog_debug(
"Graceful Restart in progress -- not flushing self-originated LSA: %s",
new->name);
return;
}

/* Self-originated LSA (newer than ours) is received
from
another router. We have to make a new instance of the
Expand All @@ -1105,6 +1118,11 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
&new->refresh);
}

struct ospf6 *ospf6 = from->ospf6_if->area->ospf6;
struct ospf6_area *area = from->ospf6_if->area;
if (ospf6->gr_info.restart_in_progress)
ospf6_gr_check_lsdb_consistency(ospf6, area);

return;
}

Expand Down
2 changes: 1 addition & 1 deletion ospf6d/ospf6_flood.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extern struct ospf6_lsdb *ospf6_get_scoped_lsdb(struct ospf6_lsa *lsa);
extern struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa);

/* origination & purging */
extern void ospf6_lsa_originate(struct ospf6_lsa *lsa);
extern void ospf6_lsa_originate(struct ospf6 *ospf6, struct ospf6_lsa *lsa);
extern void ospf6_lsa_originate_process(struct ospf6_lsa *lsa,
struct ospf6 *process);
extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa,
Expand Down
Loading

0 comments on commit 7116509

Please sign in to comment.