2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2021-07-02 18:01:32 +02:00
|
|
|
/*
|
|
|
|
* This is an implementation of RFC 5187 Graceful Restart.
|
|
|
|
*
|
|
|
|
* Copyright 2021 NetDEF (c), All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "memory.h"
|
|
|
|
#include "command.h"
|
|
|
|
#include "table.h"
|
|
|
|
#include "vty.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "hook.h"
|
|
|
|
#include "printfrr.h"
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
#include "lib_errors.h"
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
#include "ospf6d/ospf6_lsa.h"
|
|
|
|
#include "ospf6d/ospf6_lsdb.h"
|
|
|
|
#include "ospf6d/ospf6_route.h"
|
|
|
|
#include "ospf6d/ospf6_area.h"
|
|
|
|
#include "ospf6d/ospf6_interface.h"
|
|
|
|
#include "ospf6d/ospf6d.h"
|
|
|
|
#include "ospf6d/ospf6_asbr.h"
|
|
|
|
#include "ospf6d/ospf6_zebra.h"
|
|
|
|
#include "ospf6d/ospf6_message.h"
|
|
|
|
#include "ospf6d/ospf6_neighbor.h"
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
#include "ospf6d/ospf6_network.h"
|
2021-07-02 18:01:32 +02:00
|
|
|
#include "ospf6d/ospf6_flood.h"
|
|
|
|
#include "ospf6d/ospf6_intra.h"
|
|
|
|
#include "ospf6d/ospf6_spf.h"
|
|
|
|
#include "ospf6d/ospf6_gr.h"
|
|
|
|
#include "ospf6d/ospf6_gr_clippy.c"
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
static void ospf6_gr_grace_period_expired(struct event *thread);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
/* Originate and install Grace-LSA for a given interface. */
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
static int ospf6_gr_lsa_originate(struct ospf6_interface *oi,
|
|
|
|
enum ospf6_gr_restart_reason reason)
|
2021-07-02 18:01:32 +02:00
|
|
|
{
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
struct ospf6 *ospf6 = oi->area->ospf6;
|
|
|
|
struct ospf6_gr_info *gr_info = &ospf6->gr_info;
|
2021-07-02 18:01:32 +02:00
|
|
|
struct ospf6_lsa_header *lsa_header;
|
|
|
|
struct ospf6_grace_lsa *grace_lsa;
|
|
|
|
struct ospf6_lsa *lsa;
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
uint16_t lsa_length;
|
2021-07-02 18:01:32 +02:00
|
|
|
char buffer[OSPF6_MAX_LSASIZE];
|
|
|
|
|
|
|
|
if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
|
2021-10-09 23:59:58 +02:00
|
|
|
zlog_debug("Originate Grace-LSA for Interface %s",
|
2021-07-02 18:01:32 +02:00
|
|
|
oi->interface->name);
|
|
|
|
|
|
|
|
/* prepare buffer */
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
lsa_header = (struct ospf6_lsa_header *)buffer;
|
|
|
|
grace_lsa =
|
|
|
|
(struct ospf6_grace_lsa *)((caddr_t)lsa_header
|
|
|
|
+ sizeof(struct ospf6_lsa_header));
|
|
|
|
|
|
|
|
/* Put grace period. */
|
|
|
|
grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
|
|
|
|
grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
|
|
|
|
grace_lsa->tlv_period.interval = htonl(gr_info->grace_period);
|
|
|
|
|
|
|
|
/* Put restart reason. */
|
|
|
|
grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE);
|
|
|
|
grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
grace_lsa->tlv_reason.reason = reason;
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
/* Fill LSA Header */
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
lsa_length = sizeof(*lsa_header) + sizeof(*grace_lsa);
|
2021-07-02 18:01:32 +02:00
|
|
|
lsa_header->age = 0;
|
|
|
|
lsa_header->type = htons(OSPF6_LSTYPE_GRACE_LSA);
|
|
|
|
lsa_header->id = htonl(oi->interface->ifindex);
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
lsa_header->adv_router = ospf6->router_id;
|
2021-07-02 18:01:32 +02:00
|
|
|
lsa_header->seqnum =
|
|
|
|
ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
|
|
|
|
lsa_header->adv_router, oi->lsdb);
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
lsa_header->length = htons(lsa_length);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
/* LSA checksum */
|
|
|
|
ospf6_lsa_checksum(lsa_header);
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
if (reason == OSPF6_GR_UNKNOWN_RESTART) {
|
|
|
|
struct ospf6_header *oh;
|
|
|
|
uint32_t *uv32;
|
|
|
|
int n;
|
|
|
|
uint16_t length = OSPF6_HEADER_SIZE + 4 + lsa_length;
|
|
|
|
struct iovec iovector[2] = {};
|
|
|
|
|
|
|
|
/* Reserve space for OSPFv3 header. */
|
|
|
|
memmove(&buffer[OSPF6_HEADER_SIZE + 4], buffer, lsa_length);
|
|
|
|
|
|
|
|
/* Fill in the OSPFv3 header. */
|
|
|
|
oh = (struct ospf6_header *)buffer;
|
|
|
|
oh->version = OSPFV3_VERSION;
|
|
|
|
oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
|
|
|
|
oh->router_id = oi->area->ospf6->router_id;
|
|
|
|
oh->area_id = oi->area->area_id;
|
|
|
|
oh->instance_id = oi->instance_id;
|
|
|
|
oh->reserved = 0;
|
|
|
|
oh->length = htons(length);
|
|
|
|
|
|
|
|
/* Fill LSA header. */
|
|
|
|
uv32 = (uint32_t *)&buffer[sizeof(*oh)];
|
|
|
|
*uv32 = htonl(1);
|
|
|
|
|
|
|
|
/* Send packet. */
|
|
|
|
iovector[0].iov_base = lsa_header;
|
|
|
|
iovector[0].iov_len = length;
|
|
|
|
n = ospf6_sendmsg(oi->linklocal_addr, &allspfrouters6,
|
|
|
|
oi->interface->ifindex, iovector, ospf6->fd);
|
|
|
|
if (n != length)
|
|
|
|
flog_err(EC_LIB_DEVELOPMENT,
|
|
|
|
"%s: could not send entire message", __func__);
|
|
|
|
} else {
|
|
|
|
/* Create and install LSA. */
|
|
|
|
lsa = ospf6_lsa_create(lsa_header);
|
|
|
|
ospf6_lsa_originate_interface(lsa, oi);
|
|
|
|
}
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Flush all self-originated Grace-LSAs. */
|
|
|
|
static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
|
|
|
|
{
|
|
|
|
struct ospf6_area *area;
|
|
|
|
struct listnode *anode;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
|
|
|
|
struct ospf6_lsa *lsa;
|
|
|
|
struct ospf6_interface *oi;
|
|
|
|
struct listnode *inode;
|
|
|
|
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug(
|
|
|
|
"GR: flushing self-originated Grace-LSAs [area %pI4]",
|
|
|
|
&area->area_id);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
|
|
|
|
lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA),
|
|
|
|
htonl(oi->interface->ifindex),
|
|
|
|
oi->area->ospf6->router_id,
|
|
|
|
oi->lsdb);
|
|
|
|
if (!lsa) {
|
|
|
|
zlog_warn(
|
|
|
|
"%s: Grace-LSA not found [interface %s] [area %pI4]",
|
|
|
|
__func__, oi->interface->name,
|
|
|
|
&area->area_id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ospf6_lsa_purge(lsa);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Exit from the Graceful Restart mode. */
|
|
|
|
static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
|
|
|
|
{
|
|
|
|
struct ospf6_area *area;
|
|
|
|
struct listnode *onode, *anode;
|
2023-03-01 21:31:56 +01:00
|
|
|
struct ospf6_route *route;
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug("GR: exiting graceful restart: %s", reason);
|
|
|
|
|
|
|
|
ospf6->gr_info.restart_in_progress = false;
|
|
|
|
ospf6->gr_info.finishing_restart = true;
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
XFREE(MTYPE_TMP, ospf6->gr_info.exit_reason);
|
|
|
|
ospf6->gr_info.exit_reason = XSTRDUP(MTYPE_TMP, reason);
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(ospf6->gr_info.t_grace_period);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
|
|
|
|
struct ospf6_interface *oi;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 1) The router should reoriginate its router-LSAs for all
|
|
|
|
* attached areas in order to make sure they have the correct
|
|
|
|
* contents.
|
|
|
|
*/
|
|
|
|
OSPF6_ROUTER_LSA_EXECUTE(area);
|
|
|
|
|
2023-03-01 21:31:56 +01:00
|
|
|
/*
|
|
|
|
* Force reorigination of intra-area-prefix-LSAs to handle
|
|
|
|
* areas without any full adjacency.
|
|
|
|
*/
|
|
|
|
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(area);
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
|
2023-03-03 17:09:20 +01:00
|
|
|
/* Disable hello delay. */
|
|
|
|
if (oi->gr.hello_delay.t_grace_send) {
|
|
|
|
oi->gr.hello_delay.elapsed_seconds = 0;
|
|
|
|
EVENT_OFF(oi->gr.hello_delay.t_grace_send);
|
|
|
|
event_add_event(master, ospf6_hello_send, oi, 0,
|
|
|
|
&oi->thread_send_hello);
|
|
|
|
}
|
|
|
|
|
2023-03-01 21:31:56 +01:00
|
|
|
/* Reoriginate Link-LSA. */
|
|
|
|
if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
|
|
|
|
OSPF6_LINK_LSA_EXECUTE(oi);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 2) The router should reoriginate network-LSAs on all
|
|
|
|
* segments where it is the Designated Router.
|
|
|
|
*/
|
|
|
|
if (oi->state == OSPF6_INTERFACE_DR)
|
|
|
|
OSPF6_NETWORK_LSA_EXECUTE(oi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-01 21:31:56 +01:00
|
|
|
/*
|
|
|
|
* While all self-originated NSSA and AS-external LSAs were already
|
|
|
|
* learned from the helping neighbors, we need to reoriginate them in
|
|
|
|
* order to ensure they will be refreshed periodically.
|
|
|
|
*/
|
|
|
|
for (route = ospf6_route_head(ospf6->external_table); route;
|
|
|
|
route = ospf6_route_next(route))
|
|
|
|
ospf6_handle_external_lsa_origination(ospf6, route,
|
|
|
|
&route->prefix);
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
/*
|
|
|
|
* 3) The router reruns its OSPF routing calculations, this time
|
|
|
|
* installing the results into the system forwarding table, and
|
|
|
|
* originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
|
|
|
|
* necessary.
|
|
|
|
*
|
|
|
|
* 4) Any remnant entries in the system forwarding table that were
|
|
|
|
* installed before the restart, but that are no longer valid,
|
|
|
|
* should be removed.
|
|
|
|
*/
|
|
|
|
ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
|
|
|
|
|
|
|
|
/* 6) Any grace-LSAs that the router originated should be flushed. */
|
|
|
|
ospf6_gr_flush_grace_lsas(ospf6);
|
|
|
|
}
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
/* Enter the Graceful Restart mode. */
|
|
|
|
void ospf6_gr_restart_enter(struct ospf6 *ospf6,
|
2023-05-31 00:41:39 +02:00
|
|
|
enum ospf6_gr_restart_reason reason,
|
|
|
|
time_t timestamp)
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
{
|
|
|
|
unsigned long remaining_time;
|
|
|
|
|
|
|
|
ospf6->gr_info.restart_in_progress = true;
|
|
|
|
ospf6->gr_info.reason = reason;
|
|
|
|
|
|
|
|
/* Schedule grace period timeout. */
|
|
|
|
remaining_time = timestamp - time(NULL);
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug(
|
|
|
|
"GR: remaining time until grace period expires: %lu(s)",
|
|
|
|
remaining_time);
|
|
|
|
|
|
|
|
event_add_timer(master, ospf6_gr_grace_period_expired, ospf6,
|
|
|
|
remaining_time, &ospf6->gr_info.t_grace_period);
|
|
|
|
}
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
#define RTR_LSA_MISSING 0
|
|
|
|
#define RTR_LSA_ADJ_FOUND 1
|
|
|
|
#define RTR_LSA_ADJ_NOT_FOUND 2
|
|
|
|
|
|
|
|
/* Check if a Router-LSA exists and if it contains a given link. */
|
|
|
|
static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
|
|
|
|
in_addr_t adv_router,
|
|
|
|
in_addr_t neighbor_router_id)
|
|
|
|
{
|
|
|
|
uint16_t type;
|
|
|
|
struct ospf6_lsa *lsa;
|
|
|
|
bool empty = true;
|
|
|
|
|
|
|
|
type = ntohs(OSPF6_LSTYPE_ROUTER);
|
|
|
|
for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
|
|
|
|
struct ospf6_router_lsa *router_lsa;
|
|
|
|
char *start, *end, *current;
|
|
|
|
|
|
|
|
empty = false;
|
|
|
|
router_lsa = (struct ospf6_router_lsa
|
|
|
|
*)((char *)lsa->header
|
|
|
|
+ sizeof(struct ospf6_lsa_header));
|
|
|
|
|
|
|
|
/* Iterate over all interfaces in the Router-LSA. */
|
|
|
|
start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
|
|
|
|
end = (char *)lsa->header + ntohs(lsa->header->length);
|
|
|
|
for (current = start;
|
|
|
|
current + sizeof(struct ospf6_router_lsdesc) <= end;
|
|
|
|
current += sizeof(struct ospf6_router_lsdesc)) {
|
|
|
|
struct ospf6_router_lsdesc *lsdesc;
|
|
|
|
|
|
|
|
lsdesc = (struct ospf6_router_lsdesc *)current;
|
|
|
|
if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
|
|
|
|
continue;
|
|
|
|
|
2023-06-30 13:02:27 +02:00
|
|
|
if (lsdesc->neighbor_router_id == neighbor_router_id) {
|
2023-07-05 15:28:50 +02:00
|
|
|
ospf6_lsa_unlock(&lsa);
|
2021-07-02 18:01:32 +02:00
|
|
|
return RTR_LSA_ADJ_FOUND;
|
2023-06-30 13:02:27 +02:00
|
|
|
}
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty)
|
|
|
|
return RTR_LSA_MISSING;
|
|
|
|
|
|
|
|
return RTR_LSA_ADJ_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
|
|
|
|
struct ospf6_area *area,
|
|
|
|
struct ospf6_lsa *lsa)
|
|
|
|
{
|
|
|
|
if (lsa->header->adv_router == ospf6->router_id) {
|
|
|
|
struct ospf6_router_lsa *router_lsa;
|
|
|
|
char *start, *end, *current;
|
|
|
|
|
|
|
|
router_lsa = (struct ospf6_router_lsa
|
|
|
|
*)((char *)lsa->header
|
|
|
|
+ sizeof(struct ospf6_lsa_header));
|
|
|
|
|
|
|
|
/* Iterate over all interfaces in the Router-LSA. */
|
|
|
|
start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
|
|
|
|
end = (char *)lsa->header + ntohs(lsa->header->length);
|
|
|
|
for (current = start;
|
|
|
|
current + sizeof(struct ospf6_router_lsdesc) <= end;
|
|
|
|
current += sizeof(struct ospf6_router_lsdesc)) {
|
|
|
|
struct ospf6_router_lsdesc *lsdesc;
|
|
|
|
|
|
|
|
lsdesc = (struct ospf6_router_lsdesc *)current;
|
|
|
|
if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ospf6_router_lsa_contains_adj(
|
|
|
|
area, lsdesc->neighbor_router_id,
|
|
|
|
ospf6->router_id)
|
|
|
|
== RTR_LSA_ADJ_NOT_FOUND)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int adj1, adj2;
|
|
|
|
|
|
|
|
adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
|
|
|
|
lsa->header->adv_router);
|
|
|
|
adj2 = ospf6_router_lsa_contains_adj(
|
|
|
|
area, lsa->header->adv_router, ospf6->router_id);
|
|
|
|
if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
|
|
|
|
|| (adj1 == RTR_LSA_ADJ_NOT_FOUND
|
|
|
|
&& adj2 == RTR_LSA_ADJ_FOUND))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
|
|
|
|
* ongoing graceful restart when that's the case.
|
|
|
|
*/
|
|
|
|
void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
|
|
|
|
struct ospf6_area *area)
|
|
|
|
{
|
|
|
|
uint16_t type;
|
|
|
|
struct ospf6_lsa *lsa;
|
|
|
|
|
|
|
|
type = ntohs(OSPF6_LSTYPE_ROUTER);
|
|
|
|
for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
|
|
|
|
if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
|
|
|
|
char reason[256];
|
|
|
|
|
|
|
|
snprintfrr(reason, sizeof(reason),
|
|
|
|
"detected inconsistent LSA %s [area %pI4]",
|
|
|
|
lsa->name, &area->area_id);
|
|
|
|
ospf6_gr_restart_exit(ospf6, reason);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if there's a fully formed adjacency with the given neighbor ID. */
|
|
|
|
static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
|
|
|
|
in_addr_t neighbor_router_id)
|
|
|
|
{
|
|
|
|
struct ospf6_neighbor *nbr;
|
|
|
|
|
|
|
|
nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
|
|
|
|
if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug("GR: missing adjacency to router %pI4",
|
|
|
|
&neighbor_router_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
|
|
|
|
in_addr_t neighbor_router_id,
|
|
|
|
uint32_t neighbor_interface_id)
|
|
|
|
{
|
|
|
|
struct ospf6 *ospf6 = area->ospf6;
|
|
|
|
|
|
|
|
/* Check if we are the DR. */
|
|
|
|
if (neighbor_router_id == ospf6->router_id) {
|
|
|
|
struct ospf6_lsa *lsa;
|
|
|
|
char *start, *end, *current;
|
|
|
|
struct ospf6_network_lsa *network_lsa;
|
|
|
|
struct ospf6_network_lsdesc *lsdesc;
|
|
|
|
|
|
|
|
/* Lookup Network LSA corresponding to this interface. */
|
|
|
|
lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
|
|
|
|
neighbor_interface_id,
|
|
|
|
neighbor_router_id, area->lsdb);
|
|
|
|
if (!lsa)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Iterate over all routers present in the network. */
|
|
|
|
network_lsa = (struct ospf6_network_lsa
|
|
|
|
*)((char *)lsa->header
|
|
|
|
+ sizeof(struct ospf6_lsa_header));
|
|
|
|
start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
|
|
|
|
end = (char *)lsa->header + ntohs(lsa->header->length);
|
|
|
|
for (current = start;
|
|
|
|
current + sizeof(struct ospf6_network_lsdesc) <= end;
|
|
|
|
current += sizeof(struct ospf6_network_lsdesc)) {
|
|
|
|
lsdesc = (struct ospf6_network_lsdesc *)current;
|
|
|
|
|
|
|
|
/* Skip self in the pseudonode. */
|
|
|
|
if (lsdesc->router_id == ospf6->router_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if there's a fully formed adjacency with this
|
|
|
|
* router.
|
|
|
|
*/
|
|
|
|
if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
struct ospf6_neighbor *nbr;
|
|
|
|
|
|
|
|
/* Check if there's a fully formed adjacency with the DR. */
|
|
|
|
nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
|
|
|
|
if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug(
|
|
|
|
"GR: missing adjacency to DR router %pI4",
|
|
|
|
&neighbor_router_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
|
|
|
|
struct ospf6_lsa *lsa)
|
|
|
|
{
|
|
|
|
struct ospf6_router_lsa *router_lsa;
|
|
|
|
char *start, *end, *current;
|
|
|
|
|
|
|
|
router_lsa =
|
|
|
|
(struct ospf6_router_lsa *)((char *)lsa->header
|
|
|
|
+ sizeof(struct ospf6_lsa_header));
|
|
|
|
|
|
|
|
/* Iterate over all interfaces in the Router-LSA. */
|
|
|
|
start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
|
|
|
|
end = (char *)lsa->header + ntohs(lsa->header->length);
|
|
|
|
for (current = start;
|
|
|
|
current + sizeof(struct ospf6_router_lsdesc) <= end;
|
|
|
|
current += sizeof(struct ospf6_router_lsdesc)) {
|
|
|
|
struct ospf6_router_lsdesc *lsdesc;
|
|
|
|
|
|
|
|
lsdesc = (struct ospf6_router_lsdesc *)current;
|
|
|
|
switch (lsdesc->type) {
|
|
|
|
case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
|
|
|
|
if (!ospf6_gr_check_adj_id(area,
|
|
|
|
lsdesc->neighbor_router_id))
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
|
|
|
|
if (!ospf6_gr_check_adjs_lsa_transit(
|
|
|
|
area, lsdesc->neighbor_router_id,
|
|
|
|
lsdesc->neighbor_interface_id))
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if all adjacencies prior to the restart were reestablished.
|
|
|
|
*
|
|
|
|
* This is done using pre-restart Router LSAs and pre-restart Network LSAs
|
|
|
|
* received from the helping neighbors.
|
|
|
|
*/
|
|
|
|
static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
|
|
|
|
{
|
|
|
|
struct ospf6_area *area;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
|
|
|
|
uint16_t type;
|
|
|
|
uint32_t router;
|
|
|
|
struct ospf6_lsa *lsa_self;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
type = ntohs(OSPF6_LSTYPE_ROUTER);
|
|
|
|
router = ospf6->router_id;
|
|
|
|
for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
|
|
|
|
lsa_self)) {
|
|
|
|
found = true;
|
2023-06-30 13:02:27 +02:00
|
|
|
if (!ospf6_gr_check_adjs_lsa(area, lsa_self)) {
|
2023-07-05 15:28:50 +02:00
|
|
|
ospf6_lsa_unlock(&lsa_self);
|
2021-07-02 18:01:32 +02:00
|
|
|
return false;
|
2023-06-30 13:02:27 +02:00
|
|
|
}
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handling of grace period expiry. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void ospf6_gr_grace_period_expired(struct event *thread)
|
2021-07-02 18:01:32 +02:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct ospf6 *ospf6 = EVENT_ARG(thread);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
ospf6_gr_restart_exit(ospf6, "grace period has expired");
|
|
|
|
}
|
|
|
|
|
2023-03-03 17:09:20 +01:00
|
|
|
/* Send extra Grace-LSA out the interface (unplanned outages only). */
|
|
|
|
void ospf6_gr_iface_send_grace_lsa(struct event *thread)
|
|
|
|
{
|
|
|
|
struct ospf6_interface *oi = EVENT_ARG(thread);
|
|
|
|
|
|
|
|
ospf6_gr_lsa_originate(oi, oi->area->ospf6->gr_info.reason);
|
|
|
|
|
|
|
|
if (++oi->gr.hello_delay.elapsed_seconds < oi->gr.hello_delay.interval)
|
|
|
|
event_add_timer(master, ospf6_gr_iface_send_grace_lsa, oi, 1,
|
|
|
|
&oi->gr.hello_delay.t_grace_send);
|
|
|
|
else
|
|
|
|
event_add_event(master, ospf6_hello_send, oi, 0,
|
|
|
|
&oi->thread_send_hello);
|
|
|
|
}
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
/*
|
|
|
|
* Record in non-volatile memory that the given OSPF instance is attempting to
|
|
|
|
* perform a graceful restart.
|
|
|
|
*/
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
static void ospf6_gr_nvm_update(struct ospf6 *ospf6, bool prepare)
|
2021-07-02 18:01:32 +02:00
|
|
|
{
|
|
|
|
const char *inst_name;
|
|
|
|
json_object *json;
|
|
|
|
json_object *json_instances;
|
|
|
|
json_object *json_instance;
|
|
|
|
|
|
|
|
inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
|
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
json = frr_daemon_state_load();
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
json_object_object_get_ex(json, "instances", &json_instances);
|
|
|
|
if (!json_instances) {
|
|
|
|
json_instances = json_object_new_object();
|
|
|
|
json_object_object_add(json, "instances", json_instances);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object_object_get_ex(json_instances, inst_name, &json_instance);
|
|
|
|
if (!json_instance) {
|
|
|
|
json_instance = json_object_new_object();
|
|
|
|
json_object_object_add(json_instances, inst_name,
|
|
|
|
json_instance);
|
|
|
|
}
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
json_object_int_add(json_instance, "gracePeriod",
|
|
|
|
ospf6->gr_info.grace_period);
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
/*
|
|
|
|
* Record not only the grace period, but also a UNIX timestamp
|
|
|
|
* corresponding to the end of that period. That way, once ospf6d is
|
|
|
|
* restarted, it will be possible to take into account the time that
|
|
|
|
* passed while ospf6d wasn't running.
|
|
|
|
*/
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
if (prepare)
|
|
|
|
json_object_int_add(json_instance, "timestamp",
|
|
|
|
time(NULL) + ospf6->gr_info.grace_period);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
frr_daemon_state_save(&json);
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete GR status information about the given OSPF instance from non-volatile
|
|
|
|
* memory.
|
|
|
|
*/
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
|
2021-07-02 18:01:32 +02:00
|
|
|
{
|
|
|
|
const char *inst_name;
|
|
|
|
json_object *json;
|
|
|
|
json_object *json_instances;
|
|
|
|
|
|
|
|
inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
|
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
json = frr_daemon_state_load();
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
json_object_object_get_ex(json, "instances", &json_instances);
|
|
|
|
if (!json_instances) {
|
|
|
|
json_instances = json_object_new_object();
|
|
|
|
json_object_object_add(json, "instances", json_instances);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object_object_del(json_instances, inst_name);
|
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
frr_daemon_state_save(&json);
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch from non-volatile memory whether the given OSPF instance is performing
|
|
|
|
* a graceful shutdown or not.
|
|
|
|
*/
|
|
|
|
void ospf6_gr_nvm_read(struct ospf6 *ospf6)
|
|
|
|
{
|
|
|
|
const char *inst_name;
|
|
|
|
json_object *json;
|
|
|
|
json_object *json_instances;
|
|
|
|
json_object *json_instance;
|
|
|
|
json_object *json_timestamp;
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
json_object *json_grace_period;
|
2021-07-02 18:01:32 +02:00
|
|
|
time_t timestamp = 0;
|
|
|
|
|
|
|
|
inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
|
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
json = frr_daemon_state_load();
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
json_object_object_get_ex(json, "instances", &json_instances);
|
|
|
|
if (!json_instances) {
|
|
|
|
json_instances = json_object_new_object();
|
|
|
|
json_object_object_add(json, "instances", json_instances);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object_object_get_ex(json_instances, inst_name, &json_instance);
|
|
|
|
if (!json_instance) {
|
|
|
|
json_instance = json_object_new_object();
|
|
|
|
json_object_object_add(json_instances, inst_name,
|
|
|
|
json_instance);
|
|
|
|
}
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
json_object_object_get_ex(json_instance, "gracePeriod",
|
|
|
|
&json_grace_period);
|
2021-07-02 18:01:32 +02:00
|
|
|
json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
|
|
|
|
if (json_timestamp) {
|
|
|
|
time_t now;
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
/* Planned GR: check if the grace period has already expired. */
|
2021-07-02 18:01:32 +02:00
|
|
|
now = time(NULL);
|
|
|
|
timestamp = json_object_get_int(json_timestamp);
|
|
|
|
if (now > timestamp) {
|
|
|
|
ospf6_gr_restart_exit(
|
|
|
|
ospf6, "grace period has expired already");
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
} else
|
|
|
|
ospf6_gr_restart_enter(ospf6, OSPF6_GR_SW_RESTART,
|
|
|
|
timestamp);
|
|
|
|
} else if (json_grace_period) {
|
|
|
|
uint32_t grace_period;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unplanned GR: the Grace-LSAs will be sent later as soon as
|
|
|
|
* the interfaces are operational.
|
|
|
|
*/
|
|
|
|
grace_period = json_object_get_int(json_grace_period);
|
|
|
|
ospf6->gr_info.grace_period = grace_period;
|
|
|
|
ospf6_gr_restart_enter(ospf6, OSPF6_GR_UNKNOWN_RESTART,
|
|
|
|
time(NULL) +
|
|
|
|
ospf6->gr_info.grace_period);
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
json_object_object_del(json_instance, "gracePeriod");
|
|
|
|
json_object_object_del(json_instance, "timestamp");
|
2021-07-02 18:01:32 +02:00
|
|
|
|
2024-01-25 19:37:26 +01:00
|
|
|
frr_daemon_state_save(&json);
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
void ospf6_gr_unplanned_start_interface(struct ospf6_interface *oi)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Can't check OSPF interface state as the OSPF instance might not be
|
|
|
|
* enabled yet.
|
|
|
|
*/
|
|
|
|
if (!if_is_operative(oi->interface) || if_is_loopback(oi->interface))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Send Grace-LSA. */
|
|
|
|
ospf6_gr_lsa_originate(oi, oi->area->ospf6->gr_info.reason);
|
2023-03-03 17:09:20 +01:00
|
|
|
|
|
|
|
/* Start GR hello-delay interval. */
|
|
|
|
oi->gr.hello_delay.elapsed_seconds = 0;
|
|
|
|
event_add_timer(master, ospf6_gr_iface_send_grace_lsa, oi, 1,
|
|
|
|
&oi->gr.hello_delay.t_grace_send);
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
}
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
/* Prepare to start a Graceful Restart. */
|
|
|
|
static void ospf6_gr_prepare(void)
|
|
|
|
{
|
|
|
|
struct ospf6 *ospf6;
|
|
|
|
struct ospf6_interface *oi;
|
|
|
|
struct listnode *onode, *anode, *inode;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
|
|
|
|
struct ospf6_area *area;
|
|
|
|
|
|
|
|
if (!ospf6->gr_info.restart_support
|
|
|
|
|| ospf6->gr_info.prepare_in_progress)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug(
|
|
|
|
"GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
|
|
|
|
ospf6->gr_info.grace_period,
|
|
|
|
ospf6_vrf_id_to_name(ospf6->vrf_id));
|
|
|
|
|
|
|
|
/* Send a Grace-LSA to all neighbors. */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
|
|
|
|
if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
|
|
|
|
continue;
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
ospf6_gr_lsa_originate(oi, OSPF6_GR_SW_RESTART);
|
2021-07-02 18:01:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Record end of the grace period in non-volatile memory. */
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
ospf6_gr_nvm_update(ospf6, true);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark that a Graceful Restart preparation is in progress, to
|
|
|
|
* prevent ospf6d from flushing its self-originated LSAs on
|
|
|
|
* exit.
|
|
|
|
*/
|
|
|
|
ospf6->gr_info.prepare_in_progress = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
|
|
|
|
int prev_state)
|
|
|
|
{
|
|
|
|
struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
|
|
|
|
|
|
|
|
if (next_state == OSPF6_NEIGHBOR_FULL
|
|
|
|
&& ospf6->gr_info.restart_in_progress) {
|
|
|
|
if (ospf6_gr_check_adjs(ospf6)) {
|
|
|
|
ospf6_gr_restart_exit(
|
|
|
|
ospf6, "all adjacencies were reestablished");
|
|
|
|
} else {
|
|
|
|
if (IS_DEBUG_OSPF6_GR)
|
|
|
|
zlog_debug(
|
|
|
|
"GR: not all adjacencies were reestablished yet");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
|
|
|
|
{
|
|
|
|
if (!ospf6->gr_info.restart_support)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
|
|
|
|
vty_out(vty, " graceful-restart\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, " graceful-restart grace-period %u\n",
|
|
|
|
ospf6->gr_info.grace_period);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
|
|
|
|
"graceful-restart prepare ipv6 ospf",
|
|
|
|
"Graceful Restart commands\n"
|
|
|
|
"Prepare upcoming graceful restart\n" IPV6_STR
|
2022-03-09 21:56:53 +01:00
|
|
|
"Prepare to restart the OSPFv3 process\n")
|
2021-07-02 18:01:32 +02:00
|
|
|
{
|
|
|
|
ospf6_gr_prepare();
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
|
|
|
|
"graceful-restart [grace-period (1-1800)$grace_period]",
|
|
|
|
OSPF_GR_STR
|
|
|
|
"Maximum length of the 'grace period'\n"
|
|
|
|
"Maximum length of the 'grace period' in seconds\n")
|
|
|
|
{
|
|
|
|
VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
|
|
|
|
|
|
|
|
/* Check and get restart period if present. */
|
|
|
|
if (!grace_period_str)
|
|
|
|
grace_period = OSPF6_DFLT_GRACE_INTERVAL;
|
|
|
|
|
|
|
|
ospf6->gr_info.restart_support = true;
|
|
|
|
ospf6->gr_info.grace_period = grace_period;
|
|
|
|
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
/* Freeze OSPF routes in the RIB. */
|
|
|
|
(void)ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period);
|
|
|
|
|
|
|
|
/* Record that GR is enabled in non-volatile memory. */
|
|
|
|
ospf6_gr_nvm_update(ospf6, false);
|
|
|
|
|
2021-07-02 18:01:32 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
|
|
|
|
"no graceful-restart [period (1-1800)]",
|
|
|
|
NO_STR OSPF_GR_STR
|
|
|
|
"Maximum length of the 'grace period'\n"
|
|
|
|
"Maximum length of the 'grace period' in seconds\n")
|
|
|
|
{
|
|
|
|
VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
|
|
|
|
|
|
|
|
if (!ospf6->gr_info.restart_support)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
|
|
|
if (ospf6->gr_info.prepare_in_progress) {
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Error: Graceful Restart preparation in progress\n");
|
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
ospf6->gr_info.restart_support = false;
|
|
|
|
ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
|
ospf6d: add support for unplanned graceful restart
In practical terms, unplanned GR refers to the act of recovering
from a software crash without affecting the forwarding plane.
Unplanned GR and Planned GR work virtually the same, except for the
following difference: on planned GR, the router sends the Grace-LSAs
*before* restarting, whereas in unplanned GR the router sends the
Grace-LSAs immediately *after* restarting.
For unplanned GR to work, ospf6d was modified to send a
ZEBRA_CLIENT_GR_CAPABILITIES message to zebra as soon as GR is
enabled. This causes zebra to freeze the OSPF routes in the RIB as
soon as the ospf6d daemon dies, for as long as the configured grace
period (the defaults is 120 seconds). Similarly, ospf6d now stores in
non-volatile memory that GR is enabled as soon as GR is configured.
Those two things are no longer done during the GR preparation phase,
which only happens for planned GRs.
Unplanned GR will only take effect when the daemon is killed
abruptly (e.g. SIGSEGV, SIGKILL), otherwise all OSPF routes will be
uninstalled while ospf6d is exiting. Once ospf6d starts, it will
check whether GR is enabled and enter in the GR mode if necessary,
sending Grace-LSAs out all operational interfaces.
One disadvantage of unplanned GR is that the neighboring routers
might time out their corresponding adjacencies if ospf6d takes too
long to come back up. This is especially the case when short dead
intervals are used (or BFD). For this and other reasons, planned
GR should be preferred whenever possible.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2023-03-03 17:09:20 +01:00
|
|
|
ospf6_gr_nvm_delete(ospf6);
|
|
|
|
ospf6_zebra_gr_disable(ospf6);
|
2021-07-02 18:01:32 +02:00
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ospf6_gr_init(void)
|
|
|
|
{
|
|
|
|
hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
|
|
|
|
|
|
|
|
install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
|
|
|
|
install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
|
|
|
|
install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
|
|
|
|
}
|