ospf6d: update DR election to handle GR corner case

Consider the case where a DR router is performing a graceful restart,
and all neighbors attached to the DR network have their priorities
set to zero.

According to RFC 3623, the router should reclaim its DR status while
coming back up once it receives a Hello packet from a neighbor
listing the router as the DR, and the associated interface is in
Waiting state.

The problem arises when the DR election starts. Since the router
is already elected the DR, and no BDR will be elected (since all
neighbors have their priorities set to zero), the AdjOk event won't
be triggered at the end of the DR election as it would normally
happen. That causes all neighbors reachable over the broadcast
interface to get stuck in the 2-Way state.

Fix this corner case by always triggering the AdjOk event at the
end of the DR election process when a GR is in progress. Triggering
the AdjOk event when not necessary should never be a problem as
the neighbor FSM is already prepared to deal with that.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2023-03-01 17:31:56 -03:00
parent d7917c2541
commit e23e568319

View file

@ -592,6 +592,7 @@ static struct ospf6_neighbor *better_drouter(struct ospf6_neighbor *a,
uint8_t dr_election(struct ospf6_interface *oi)
{
struct ospf6 *ospf6 = oi->area->ospf6;
struct listnode *node, *nnode;
struct ospf6_neighbor *on, *drouter, *bdrouter, myself;
struct ospf6_neighbor *best_drouter, *best_bdrouter;
@ -602,13 +603,12 @@ uint8_t dr_election(struct ospf6_interface *oi)
/* pseudo neighbor myself, including noting current DR/BDR (1) */
memset(&myself, 0, sizeof(myself));
inet_ntop(AF_INET, &oi->area->ospf6->router_id, myself.name,
sizeof(myself.name));
inet_ntop(AF_INET, &ospf6->router_id, myself.name, sizeof(myself.name));
myself.state = OSPF6_NEIGHBOR_TWOWAY;
myself.drouter = oi->drouter;
myself.bdrouter = oi->bdrouter;
myself.priority = oi->priority;
myself.router_id = oi->area->ospf6->router_id;
myself.router_id = ospf6->router_id;
/* Electing BDR (2) */
for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on))
@ -657,8 +657,10 @@ uint8_t dr_election(struct ospf6_interface *oi)
/* If DR or BDR change, invoke AdjOK? for each neighbor (7) */
/* RFC 2328 section 12.4. Originating LSAs (3) will be handled
accordingly after AdjOK */
if (oi->drouter != (drouter ? drouter->router_id : htonl(0))
|| oi->bdrouter != (bdrouter ? bdrouter->router_id : htonl(0))) {
if (oi->drouter != (drouter ? drouter->router_id : htonl(0)) ||
oi->bdrouter != (bdrouter ? bdrouter->router_id : htonl(0)) ||
ospf6->gr_info.restart_in_progress) {
if (IS_OSPF6_DEBUG_INTERFACE)
zlog_debug("DR Election on %s: DR: %s BDR: %s",
oi->interface->name,