mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 19:35:13 +00:00
ospfd: 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 ospfd daemon dies, for as long as the configured grace period (the defaults is 120 seconds). Similarly, ospfd 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 ospfd is exiting. Once ospfd 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 ospfd 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>
This commit is contained in:
parent
cf0d1e8c25
commit
ab749e7eea
@ -770,6 +770,10 @@ Graceful Restart
|
||||
To perform a graceful shutdown, the "graceful-restart prepare ip ospf"
|
||||
EXEC-level command needs to be issued before restarting the ospfd daemon.
|
||||
|
||||
When Graceful Restart is enabled and the ospfd daemon crashes or is killed
|
||||
abruptely (e.g. SIGKILL), it will attempt an unplanned Graceful Restart once
|
||||
it restarts.
|
||||
|
||||
.. clicmd:: graceful-restart helper enable [A.B.C.D]
|
||||
|
||||
|
||||
|
@ -615,6 +615,7 @@ static void ospf_ase_calculate_timer(struct event *t)
|
||||
*/
|
||||
if (ospf->gr_info.finishing_restart) {
|
||||
ospf_zebra_gr_disable(ospf);
|
||||
ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period);
|
||||
ospf->gr_info.finishing_restart = false;
|
||||
}
|
||||
}
|
||||
|
172
ospfd/ospf_gr.c
172
ospfd/ospf_gr.c
@ -33,7 +33,7 @@
|
||||
#include "ospfd/ospf_dump.h"
|
||||
#include "ospfd/ospf_gr_clippy.c"
|
||||
|
||||
static void ospf_gr_nvm_delete(struct ospf *ospf);
|
||||
static void ospf_gr_grace_period_expired(struct event *thread);
|
||||
|
||||
/* Lookup self-originated Grace-LSA in the LSDB. */
|
||||
static struct ospf_lsa *ospf_gr_lsa_lookup(struct ospf *ospf,
|
||||
@ -53,7 +53,9 @@ static struct ospf_lsa *ospf_gr_lsa_lookup(struct ospf *ospf,
|
||||
|
||||
/* Fill in fields of the Grace-LSA that is being originated. */
|
||||
static void ospf_gr_lsa_body_set(struct ospf_gr_info *gr_info,
|
||||
struct ospf_interface *oi, struct stream *s)
|
||||
struct ospf_interface *oi,
|
||||
enum ospf_gr_restart_reason reason,
|
||||
struct stream *s)
|
||||
{
|
||||
struct grace_tlv_graceperiod tlv_period = {};
|
||||
struct grace_tlv_restart_reason tlv_reason = {};
|
||||
@ -68,10 +70,7 @@ static void ospf_gr_lsa_body_set(struct ospf_gr_info *gr_info,
|
||||
/* Put restart reason. */
|
||||
tlv_reason.header.type = htons(RESTART_REASON_TYPE);
|
||||
tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
|
||||
if (gr_info->restart_support)
|
||||
tlv_reason.reason = OSPF_GR_SW_RESTART;
|
||||
else
|
||||
tlv_reason.reason = OSPF_GR_UNKNOWN_RESTART;
|
||||
tlv_reason.reason = reason;
|
||||
stream_put(s, &tlv_reason, sizeof(tlv_reason));
|
||||
|
||||
/* Put IP address. */
|
||||
@ -85,7 +84,8 @@ static void ospf_gr_lsa_body_set(struct ospf_gr_info *gr_info,
|
||||
}
|
||||
|
||||
/* Generate Grace-LSA for a given interface. */
|
||||
static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi)
|
||||
static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi,
|
||||
enum ospf_gr_restart_reason reason)
|
||||
{
|
||||
struct stream *s;
|
||||
struct lsa_header *lsah;
|
||||
@ -112,7 +112,7 @@ static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi)
|
||||
lsa_header_set(s, options, lsa_type, lsa_id, oi->ospf->router_id);
|
||||
|
||||
/* Set opaque-LSA body fields. */
|
||||
ospf_gr_lsa_body_set(&oi->ospf->gr_info, oi, s);
|
||||
ospf_gr_lsa_body_set(&oi->ospf->gr_info, oi, reason, s);
|
||||
|
||||
/* Set length. */
|
||||
length = stream_get_endp(s);
|
||||
@ -135,15 +135,20 @@ static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi)
|
||||
}
|
||||
|
||||
/* Originate and install Grace-LSA for a given interface. */
|
||||
static void ospf_gr_lsa_originate(struct ospf_interface *oi, bool maxage)
|
||||
static void ospf_gr_lsa_originate(struct ospf_interface *oi,
|
||||
enum ospf_gr_restart_reason reason,
|
||||
bool maxage)
|
||||
{
|
||||
struct ospf_lsa *lsa, *old;
|
||||
|
||||
if (ospf_interface_neighbor_count(oi) == 0)
|
||||
/* Skip originating a Grace-LSA when not necessary. */
|
||||
if (!if_is_operative(oi->ifp) || if_is_loopback(oi->ifp) ||
|
||||
(reason != OSPF_GR_UNKNOWN_RESTART &&
|
||||
ospf_interface_neighbor_count(oi) == 0))
|
||||
return;
|
||||
|
||||
/* Create new Grace-LSA. */
|
||||
lsa = ospf_gr_lsa_new(oi);
|
||||
lsa = ospf_gr_lsa_new(oi, reason);
|
||||
if (!lsa) {
|
||||
zlog_warn("%s: ospf_gr_lsa_new() failed", __func__);
|
||||
return;
|
||||
@ -157,18 +162,36 @@ static void ospf_gr_lsa_originate(struct ospf_interface *oi, bool maxage)
|
||||
if (old)
|
||||
lsa->data->ls_seqnum = lsa_seqnum_increment(old);
|
||||
|
||||
/* Install this LSA into LSDB. */
|
||||
if (ospf_lsa_install(oi->ospf, oi, lsa) == NULL) {
|
||||
zlog_warn("%s: ospf_lsa_install() failed", __func__);
|
||||
ospf_lsa_unlock(&lsa);
|
||||
return;
|
||||
if (!maxage && reason == OSPF_GR_UNKNOWN_RESTART) {
|
||||
struct list *update;
|
||||
struct in_addr addr;
|
||||
|
||||
/*
|
||||
* When performing an unplanned restart, send a handcrafted
|
||||
* Grace-LSA since the interface isn't fully initialized yet.
|
||||
*/
|
||||
ospf_lsa_checksum(lsa->data);
|
||||
ospf_lsa_lock(lsa);
|
||||
update = list_new();
|
||||
listnode_add(update, lsa);
|
||||
addr.s_addr = htonl(OSPF_ALLSPFROUTERS);
|
||||
ospf_ls_upd_queue_send(oi, update, addr, true);
|
||||
list_delete(&update);
|
||||
ospf_lsa_discard(lsa);
|
||||
} else {
|
||||
/* Install this LSA into LSDB. */
|
||||
if (ospf_lsa_install(oi->ospf, oi, lsa) == NULL) {
|
||||
zlog_warn("%s: ospf_lsa_install() failed", __func__);
|
||||
ospf_lsa_unlock(&lsa);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Flood the LSA through out the interface */
|
||||
ospf_flood_through_interface(oi, NULL, lsa);
|
||||
}
|
||||
|
||||
/* Update new LSA origination count. */
|
||||
oi->ospf->lsa_originate_count++;
|
||||
|
||||
/* Flood the LSA through out the interface */
|
||||
ospf_flood_through_interface(oi, NULL, lsa);
|
||||
}
|
||||
|
||||
/* Flush all self-originated Grace-LSAs. */
|
||||
@ -181,13 +204,14 @@ static void ospf_gr_flush_grace_lsas(struct ospf *ospf)
|
||||
struct ospf_interface *oi;
|
||||
struct listnode *inode;
|
||||
|
||||
if (IS_DEBUG_OSPF_GR)
|
||||
zlog_debug(
|
||||
"GR: flushing self-originated Grace-LSAs [area %pI4]",
|
||||
&area->area_id);
|
||||
for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi)) {
|
||||
if (IS_DEBUG_OSPF_GR)
|
||||
zlog_debug(
|
||||
"GR: flushing self-originated Grace-LSA [area %pI4] [interface %s]",
|
||||
&area->area_id, oi->ifp->name);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi))
|
||||
ospf_gr_lsa_originate(oi, true);
|
||||
ospf_gr_lsa_originate(oi, ospf->gr_info.reason, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,9 +227,6 @@ static void ospf_gr_restart_exit(struct ospf *ospf, const char *reason)
|
||||
ospf->gr_info.restart_in_progress = false;
|
||||
EVENT_OFF(ospf->gr_info.t_grace_period);
|
||||
|
||||
/* Record in non-volatile memory that the restart is complete. */
|
||||
ospf_gr_nvm_delete(ospf);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->areas, onode, area)) {
|
||||
struct ospf_interface *oi;
|
||||
|
||||
@ -242,12 +263,34 @@ static void ospf_gr_restart_exit(struct ospf *ospf, const char *reason)
|
||||
* should be removed.
|
||||
*/
|
||||
ospf->gr_info.finishing_restart = true;
|
||||
XFREE(MTYPE_TMP, ospf->gr_info.exit_reason);
|
||||
ospf->gr_info.exit_reason = XSTRDUP(MTYPE_TMP, reason);
|
||||
ospf_spf_calculate_schedule(ospf, SPF_FLAG_GR_FINISH);
|
||||
|
||||
/* 6) Any grace-LSAs that the router originated should be flushed. */
|
||||
ospf_gr_flush_grace_lsas(ospf);
|
||||
}
|
||||
|
||||
/* Enter the Graceful Restart mode. */
|
||||
void ospf_gr_restart_enter(struct ospf *ospf,
|
||||
enum ospf_gr_restart_reason reason, int timestamp)
|
||||
{
|
||||
unsigned long remaining_time;
|
||||
|
||||
ospf->gr_info.restart_in_progress = true;
|
||||
ospf->gr_info.reason = reason;
|
||||
|
||||
/* Schedule grace period timeout. */
|
||||
remaining_time = timestamp - time(NULL);
|
||||
if (IS_DEBUG_OSPF_GR)
|
||||
zlog_debug(
|
||||
"GR: remaining time until grace period expires: %lu(s)",
|
||||
remaining_time);
|
||||
|
||||
event_add_timer(master, ospf_gr_grace_period_expired, ospf,
|
||||
remaining_time, &ospf->gr_info.t_grace_period);
|
||||
}
|
||||
|
||||
/* Check if a Router-LSA contains a given link. */
|
||||
static bool ospf_router_lsa_contains_adj(struct ospf_lsa *lsa,
|
||||
struct in_addr *id)
|
||||
@ -522,7 +565,7 @@ static char *ospf_gr_nvm_filepath(struct ospf *ospf)
|
||||
* Record in non-volatile memory that the given OSPF instance is attempting to
|
||||
* perform a graceful restart.
|
||||
*/
|
||||
static void ospf_gr_nvm_update(struct ospf *ospf)
|
||||
static void ospf_gr_nvm_update(struct ospf *ospf, bool prepare)
|
||||
{
|
||||
char *filepath;
|
||||
const char *inst_name;
|
||||
@ -550,16 +593,18 @@ static void ospf_gr_nvm_update(struct ospf *ospf)
|
||||
json_instance);
|
||||
}
|
||||
|
||||
json_object_int_add(json_instance, "gracePeriod",
|
||||
ospf->gr_info.grace_period);
|
||||
|
||||
/*
|
||||
* Record not only the grace period, but also a UNIX timestamp
|
||||
* corresponding to the end of that period. That way, once ospfd is
|
||||
* restarted, it will be possible to take into account the time that
|
||||
* passed while ospfd wasn't running.
|
||||
*/
|
||||
json_object_int_add(json_instance, "gracePeriod",
|
||||
ospf->gr_info.grace_period);
|
||||
json_object_int_add(json_instance, "timestamp",
|
||||
time(NULL) + ospf->gr_info.grace_period);
|
||||
if (prepare)
|
||||
json_object_int_add(json_instance, "timestamp",
|
||||
time(NULL) + ospf->gr_info.grace_period);
|
||||
|
||||
json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
|
||||
json_object_free(json);
|
||||
@ -569,7 +614,7 @@ static void ospf_gr_nvm_update(struct ospf *ospf)
|
||||
* Delete GR status information about the given OSPF instance from non-volatile
|
||||
* memory.
|
||||
*/
|
||||
static void ospf_gr_nvm_delete(struct ospf *ospf)
|
||||
void ospf_gr_nvm_delete(struct ospf *ospf)
|
||||
{
|
||||
char *filepath;
|
||||
const char *inst_name;
|
||||
@ -607,6 +652,7 @@ void ospf_gr_nvm_read(struct ospf *ospf)
|
||||
json_object *json_instances;
|
||||
json_object *json_instance;
|
||||
json_object *json_timestamp;
|
||||
json_object *json_grace_period;
|
||||
time_t timestamp = 0;
|
||||
|
||||
filepath = ospf_gr_nvm_filepath(ospf);
|
||||
@ -629,29 +675,33 @@ void ospf_gr_nvm_read(struct ospf *ospf)
|
||||
json_instance);
|
||||
}
|
||||
|
||||
json_object_object_get_ex(json_instance, "gracePeriod",
|
||||
&json_grace_period);
|
||||
json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
|
||||
|
||||
if (json_timestamp) {
|
||||
time_t now;
|
||||
unsigned long remaining_time;
|
||||
|
||||
/* Check if the grace period has already expired. */
|
||||
/* Planned GR: check if the grace period has already expired. */
|
||||
now = time(NULL);
|
||||
timestamp = json_object_get_int(json_timestamp);
|
||||
if (now > timestamp) {
|
||||
ospf_gr_restart_exit(
|
||||
ospf, "grace period has expired already");
|
||||
} else {
|
||||
/* Schedule grace period timeout. */
|
||||
ospf->gr_info.restart_in_progress = true;
|
||||
remaining_time = timestamp - time(NULL);
|
||||
if (IS_DEBUG_OSPF_GR)
|
||||
zlog_debug(
|
||||
"GR: remaining time until grace period expires: %lu(s)",
|
||||
remaining_time);
|
||||
event_add_timer(master, ospf_gr_grace_period_expired,
|
||||
ospf, remaining_time,
|
||||
&ospf->gr_info.t_grace_period);
|
||||
}
|
||||
} else
|
||||
ospf_gr_restart_enter(ospf, OSPF_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);
|
||||
ospf->gr_info.grace_period = grace_period;
|
||||
ospf_gr_restart_enter(ospf, OSPF_GR_UNKNOWN_RESTART,
|
||||
time(NULL) + ospf->gr_info.grace_period);
|
||||
}
|
||||
|
||||
json_object_object_del(json_instances, inst_name);
|
||||
@ -660,6 +710,12 @@ void ospf_gr_nvm_read(struct ospf *ospf)
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
void ospf_gr_unplanned_start_interface(struct ospf_interface *oi)
|
||||
{
|
||||
/* Send Grace-LSA. */
|
||||
ospf_gr_lsa_originate(oi, oi->ospf->gr_info.reason, false);
|
||||
}
|
||||
|
||||
/* Prepare to start a Graceful Restart. */
|
||||
static void ospf_gr_prepare(void)
|
||||
{
|
||||
@ -687,20 +743,12 @@ static void ospf_gr_prepare(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Freeze OSPF routes in the RIB. */
|
||||
if (ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period)) {
|
||||
zlog_warn(
|
||||
"%s: failed to activate graceful restart: not connected to zebra",
|
||||
__func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Send a Grace-LSA to all neighbors. */
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi))
|
||||
ospf_gr_lsa_originate(oi, false);
|
||||
ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART, false);
|
||||
|
||||
/* Record end of the grace period in non-volatile memory. */
|
||||
ospf_gr_nvm_update(ospf);
|
||||
ospf_gr_nvm_update(ospf, true);
|
||||
|
||||
/*
|
||||
* Mark that a Graceful Restart preparation is in progress, to
|
||||
@ -749,6 +797,12 @@ DEFPY(graceful_restart, graceful_restart_cmd,
|
||||
ospf->gr_info.restart_support = true;
|
||||
ospf->gr_info.grace_period = grace_period;
|
||||
|
||||
/* Freeze OSPF routes in the RIB. */
|
||||
(void)ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period);
|
||||
|
||||
/* Record that GR is enabled in non-volatile memory. */
|
||||
ospf_gr_nvm_update(ospf, false);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -771,6 +825,8 @@ DEFPY(no_graceful_restart, no_graceful_restart_cmd,
|
||||
|
||||
ospf->gr_info.restart_support = false;
|
||||
ospf->gr_info.grace_period = OSPF_DFLT_GRACE_INTERVAL;
|
||||
ospf_gr_nvm_delete(ospf);
|
||||
ospf_zebra_gr_disable(ospf);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -166,11 +166,15 @@ 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);
|
||||
|
||||
extern void ospf_gr_restart_enter(struct ospf *ospf,
|
||||
enum ospf_gr_restart_reason reason,
|
||||
int timestamp);
|
||||
extern void ospf_gr_check_lsdb_consistency(struct ospf *ospf,
|
||||
struct ospf_area *area);
|
||||
extern void ospf_gr_check_adjs(struct ospf *ospf);
|
||||
extern void ospf_gr_nvm_read(struct ospf *ospf);
|
||||
extern void ospf_gr_nvm_delete(struct ospf *ospf);
|
||||
extern void ospf_gr_unplanned_start_interface(struct ospf_interface *oi);
|
||||
extern void ospf_gr_init(void);
|
||||
|
||||
#endif /* _ZEBRA_OSPF_GR_H */
|
||||
|
@ -4040,9 +4040,8 @@ static struct ospf_packet *ospf_ls_upd_packet_new(struct list *update,
|
||||
return ospf_packet_new(size - sizeof(struct ip));
|
||||
}
|
||||
|
||||
static void ospf_ls_upd_queue_send(struct ospf_interface *oi,
|
||||
struct list *update, struct in_addr addr,
|
||||
int send_lsupd_now)
|
||||
void ospf_ls_upd_queue_send(struct ospf_interface *oi, struct list *update,
|
||||
struct in_addr addr, int send_lsupd_now)
|
||||
{
|
||||
struct ospf_packet *op;
|
||||
uint16_t length = OSPF_HEADER_SIZE;
|
||||
|
@ -132,6 +132,9 @@ extern void ospf_ls_req_send(struct ospf_neighbor *);
|
||||
extern void ospf_ls_upd_send_lsa(struct ospf_neighbor *, struct ospf_lsa *,
|
||||
int);
|
||||
extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int);
|
||||
extern void ospf_ls_upd_queue_send(struct ospf_interface *oi,
|
||||
struct list *update, struct in_addr addr,
|
||||
int send_lsupd_now);
|
||||
extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *);
|
||||
extern void ospf_ls_ack_send_delayed(struct ospf_interface *);
|
||||
extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *);
|
||||
|
@ -232,9 +232,12 @@ DEFUN (no_router_ospf,
|
||||
return CMD_NOT_MY_INSTANCE;
|
||||
|
||||
ospf = ospf_lookup(instance, vrf_name);
|
||||
if (ospf)
|
||||
if (ospf) {
|
||||
if (ospf->gr_info.restart_support)
|
||||
ospf_gr_nvm_delete(ospf);
|
||||
|
||||
ospf_finish(ospf);
|
||||
else
|
||||
} else
|
||||
ret = CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
return ret;
|
||||
|
@ -2120,10 +2120,20 @@ int ospf_zebra_label_manager_connect(void)
|
||||
|
||||
static void ospf_zebra_connected(struct zclient *zclient)
|
||||
{
|
||||
struct ospf *ospf;
|
||||
struct listnode *node;
|
||||
|
||||
/* Send the client registration */
|
||||
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
|
||||
|
||||
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
||||
|
||||
/* Activate graceful restart if configured. */
|
||||
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
|
||||
if (!ospf->gr_info.restart_support)
|
||||
continue;
|
||||
(void)ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -720,6 +720,7 @@ static void ospf_finish_final(struct ospf *ospf)
|
||||
|
||||
if (!ospf->gr_info.prepare_in_progress)
|
||||
ospf_flush_self_originated_lsas_now(ospf);
|
||||
XFREE(MTYPE_TMP, ospf->gr_info.exit_reason);
|
||||
|
||||
/* Unregister redistribution */
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
@ -1131,6 +1132,17 @@ struct ospf_interface *add_ospf_interface(struct connected *co,
|
||||
&& if_is_operative(co->ifp))
|
||||
ospf_if_up(oi);
|
||||
|
||||
/*
|
||||
* RFC 3623 - Section 5 ("Unplanned Outages"):
|
||||
* "The grace-LSAs are encapsulated in Link State Update Packets
|
||||
* and sent out to all interfaces, even though the restarted
|
||||
* router has no adjacencies and no knowledge of previous
|
||||
* adjacencies".
|
||||
*/
|
||||
if (oi->ospf->gr_info.restart_in_progress &&
|
||||
oi->ospf->gr_info.reason == OSPF_GR_UNKNOWN_RESTART)
|
||||
ospf_gr_unplanned_start_interface(oi);
|
||||
|
||||
return oi;
|
||||
}
|
||||
|
||||
|
@ -148,6 +148,8 @@ struct ospf_gr_info {
|
||||
bool prepare_in_progress;
|
||||
bool finishing_restart;
|
||||
uint32_t grace_period;
|
||||
int reason;
|
||||
char *exit_reason;
|
||||
struct event *t_grace_period;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user