]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_nsm.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / ospfd / ospf_nsm.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
2d59836a 2/*
3 * OSPF version 2 Neighbor State Machine
4 * From RFC2328 [OSPF Version 2]
5 * Copyright (C) 1999, 2000 Toshiaki Takada
2d59836a 6 */
7
8#include <zebra.h>
9
10#include "thread.h"
11#include "memory.h"
12#include "hash.h"
13#include "linklist.h"
14#include "prefix.h"
15#include "if.h"
16#include "table.h"
17#include "stream.h"
18#include "table.h"
19#include "log.h"
bf2bfafd 20#include "command.h"
5920b3eb 21#include "network.h"
2d59836a 22
23#include "ospfd/ospfd.h"
24#include "ospfd/ospf_interface.h"
25#include "ospfd/ospf_ism.h"
26#include "ospfd/ospf_asbr.h"
27#include "ospfd/ospf_lsa.h"
28#include "ospfd/ospf_lsdb.h"
29#include "ospfd/ospf_neighbor.h"
30#include "ospfd/ospf_nsm.h"
31#include "ospfd/ospf_network.h"
32#include "ospfd/ospf_packet.h"
33#include "ospfd/ospf_dump.h"
34#include "ospfd/ospf_flood.h"
35#include "ospfd/ospf_abr.h"
7f342629 36#include "ospfd/ospf_bfd.h"
10514170 37#include "ospfd/ospf_gr.h"
14c5ef90 38#include "ospfd/ospf_errors.h"
2d59836a 39
3012671f 40DEFINE_HOOK(ospf_nsm_change,
d62a17ae 41 (struct ospf_neighbor * on, int state, int oldstate),
8451921b 42 (on, state, oldstate));
3012671f 43
d62a17ae 44static void nsm_clear_adj(struct ospf_neighbor *);
6b0655a2 45
2d59836a 46/* OSPF NSM Timer functions. */
cc9f21da 47static void ospf_inactivity_timer(struct thread *thread)
2d59836a 48{
d62a17ae 49 struct ospf_neighbor *nbr;
2d59836a 50
d62a17ae 51 nbr = THREAD_ARG(thread);
52 nbr->t_inactivity = NULL;
2d59836a 53
d62a17ae 54 if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
96b663a3
MS
55 zlog_debug("NSM[%s:%pI4:%s]: Timer (Inactivity timer expire)",
56 IF_NAME(nbr->oi), &nbr->router_id,
868a0861 57 ospf_get_name(nbr->oi->ospf));
2d59836a 58
5a77dd8f 59 /* Dont trigger NSM_InactivityTimer event , if the current
60 * router acting as HELPER for this neighbour.
61 */
62 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
63 OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
65bf67b3
IR
64 else {
65 if (IS_DEBUG_OSPF_GR)
66 zlog_debug(
67 "%s, Acting as HELPER for this neighbour, So restart the dead timer",
68 __func__);
89eb4727 69 OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
70 nbr->v_inactivity);
71 }
2d59836a 72}
73
cc9f21da 74static void ospf_db_desc_timer(struct thread *thread)
2d59836a 75{
d62a17ae 76 struct ospf_neighbor *nbr;
2d59836a 77
d62a17ae 78 nbr = THREAD_ARG(thread);
79 nbr->t_db_desc = NULL;
2d59836a 80
d62a17ae 81 if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
96b663a3
MS
82 zlog_debug("NSM[%s:%pI4:%s]: Timer (DD Retransmit timer expire)",
83 IF_NAME(nbr->oi), &nbr->src,
868a0861 84 ospf_get_name(nbr->oi->ospf));
2d59836a 85
d62a17ae 86 /* resent last send DD packet. */
87 assert(nbr->last_send);
88 ospf_db_desc_resend(nbr);
2d59836a 89
d62a17ae 90 /* DD Retransmit timer set. */
91 OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
2d59836a 92}
93
0437e105 94/* Hook function called after ospf NSM event is occurred.
1f2c2743
PJ
95 *
96 * Set/clear any timers whose condition is implicit to the neighbour
97 * state. There may be other timers which are set/unset according to other
98 * state.
99 *
100 * We rely on this function to properly clear timers in lower states,
101 * particularly before deleting a neighbour.
102 */
d62a17ae 103static void nsm_timer_set(struct ospf_neighbor *nbr)
2d59836a 104{
d62a17ae 105 switch (nbr->state) {
106 case NSM_Deleted:
107 case NSM_Down:
cccd44f3
DS
108 THREAD_OFF(nbr->t_inactivity);
109 THREAD_OFF(nbr->t_hello_reply);
d62a17ae 110 /* fallthru */
111 case NSM_Attempt:
112 case NSM_Init:
113 case NSM_TwoWay:
cccd44f3
DS
114 THREAD_OFF(nbr->t_db_desc);
115 THREAD_OFF(nbr->t_ls_upd);
116 THREAD_OFF(nbr->t_ls_req);
d62a17ae 117 break;
118 case NSM_ExStart:
119 OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer,
120 nbr->v_db_desc);
cccd44f3
DS
121 THREAD_OFF(nbr->t_ls_upd);
122 THREAD_OFF(nbr->t_ls_req);
d62a17ae 123 break;
124 case NSM_Exchange:
125 OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer,
126 nbr->v_ls_upd);
127 if (!IS_SET_DD_MS(nbr->dd_flags))
cccd44f3 128 THREAD_OFF(nbr->t_db_desc);
d62a17ae 129 break;
130 case NSM_Loading:
131 case NSM_Full:
132 default:
cccd44f3 133 THREAD_OFF(nbr->t_db_desc);
d62a17ae 134 break;
135 }
2d59836a 136}
137
d7b0fb62
PJ
138/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
139 * the given neighbour
140 */
ad686992 141int nsm_should_adj(struct ospf_neighbor *nbr)
d7b0fb62 142{
d62a17ae 143 struct ospf_interface *oi = nbr->oi;
144
145 /* These network types must always form adjacencies. */
146 if (oi->type == OSPF_IFTYPE_POINTOPOINT
147 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
148 || oi->type == OSPF_IFTYPE_VIRTUALLINK
149 /* Router itself is the DRouter or the BDRouter. */
150 || IPV4_ADDR_SAME(&oi->address->u.prefix4, &DR(oi))
151 || IPV4_ADDR_SAME(&oi->address->u.prefix4, &BDR(oi))
152 /* Neighboring Router is the DRouter or the BDRouter. */
153 || IPV4_ADDR_SAME(&nbr->address.u.prefix4, &DR(oi))
154 || IPV4_ADDR_SAME(&nbr->address.u.prefix4, &BDR(oi)))
155 return 1;
156
157 return 0;
d7b0fb62 158}
6b0655a2 159
2d59836a 160/* OSPF NSM functions. */
874a549d 161static int nsm_hello_received(struct ospf_neighbor *nbr)
2d59836a 162{
d62a17ae 163 /* Start or Restart Inactivity Timer. */
cccd44f3 164 THREAD_OFF(nbr->t_inactivity);
d62a17ae 165
166 OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
167 nbr->v_inactivity);
2d59836a 168
d62a17ae 169 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
cccd44f3 170 THREAD_OFF(nbr->nbr_nbma->t_poll);
2d59836a 171
d62a17ae 172 /* Send proactive ARP requests */
173 if (nbr->state < NSM_Exchange)
174 ospf_proactively_arp(nbr);
8b6912c2 175
d62a17ae 176 return 0;
2d59836a 177}
178
d62a17ae 179static int nsm_start(struct ospf_neighbor *nbr)
2d59836a 180{
d62a17ae 181 if (nbr->nbr_nbma)
cccd44f3 182 THREAD_OFF(nbr->nbr_nbma->t_poll);
2d59836a 183
cccd44f3 184 THREAD_OFF(nbr->t_inactivity);
2d59836a 185
d62a17ae 186 OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
187 nbr->v_inactivity);
8b6912c2 188
d62a17ae 189 /* Send proactive ARP requests */
190 ospf_proactively_arp(nbr);
191
192 return 0;
2d59836a 193}
194
d62a17ae 195static int nsm_twoway_received(struct ospf_neighbor *nbr)
2d59836a 196{
d62a17ae 197 int adj = nsm_should_adj(nbr);
8b6912c2 198
d62a17ae 199 /* Send proactive ARP requests */
200 if (adj)
201 ospf_proactively_arp(nbr);
8b6912c2 202
d62a17ae 203 return (adj ? NSM_ExStart : NSM_TwoWay);
2d59836a 204}
205
d62a17ae 206int ospf_db_summary_count(struct ospf_neighbor *nbr)
2d59836a 207{
d62a17ae 208 return ospf_lsdb_count_all(&nbr->db_sum);
2d59836a 209}
210
d62a17ae 211int ospf_db_summary_isempty(struct ospf_neighbor *nbr)
2d59836a 212{
d62a17ae 213 return ospf_lsdb_isempty(&nbr->db_sum);
2d59836a 214}
215
d62a17ae 216static int ospf_db_summary_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
2d59836a 217{
d62a17ae 218 switch (lsa->data->type) {
219 case OSPF_OPAQUE_LINK_LSA:
220 /* Exclude type-9 LSAs that does not have the same "oi" with
221 * "nbr". */
45559c4d 222 if (ospf_if_exists(lsa->oi) != nbr->oi)
d62a17ae 223 return 0;
224 break;
225 case OSPF_OPAQUE_AREA_LSA:
226 /*
227 * It is assured by the caller function "nsm_negotiation_done()"
228 * that every given LSA belongs to the same area with "nbr".
229 */
230 break;
231 case OSPF_OPAQUE_AS_LSA:
232 default:
233 break;
234 }
235
236 /* Stay away from any Local Translated Type-7 LSAs */
237 if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT))
238 return 0;
239
240 if (IS_LSA_MAXAGE(lsa))
241 ospf_ls_retransmit_add(nbr, lsa);
242 else
243 ospf_lsdb_add(&nbr->db_sum, lsa);
244
245 return 0;
2d59836a 246}
247
d62a17ae 248void ospf_db_summary_clear(struct ospf_neighbor *nbr)
2d59836a 249{
d62a17ae 250 struct ospf_lsdb *lsdb;
251 int i;
2d59836a 252
d62a17ae 253 lsdb = &nbr->db_sum;
254 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
255 struct route_table *table = lsdb->type[i].db;
256 struct route_node *rn;
257
258 for (rn = route_top(table); rn; rn = route_next(rn))
259 if (rn->info)
260 ospf_lsdb_delete(&nbr->db_sum, rn->info);
261 }
262}
6b0655a2 263
2d59836a 264
2d59836a 265/* The area link state database consists of the router-LSAs,
266 network-LSAs and summary-LSAs contained in the area structure,
68980084 267 along with the AS-external-LSAs contained in the global structure.
268 AS-external-LSAs are omitted from a virtual neighbor's Database
2d59836a 269 summary list. AS-external-LSAs are omitted from the Database
270 summary list if the area has been configured as a stub. */
d62a17ae 271static int nsm_negotiation_done(struct ospf_neighbor *nbr)
2d59836a 272{
d62a17ae 273 struct ospf_area *area = nbr->oi->area;
274 struct ospf_lsa *lsa;
275 struct route_node *rn;
276
277 /* Send proactive ARP requests */
278 ospf_proactively_arp(nbr);
279
996c9314 280 LSDB_LOOP (ROUTER_LSDB(area), rn, lsa)
044506e7 281 ospf_db_summary_add(nbr, lsa);
996c9314 282 LSDB_LOOP (NETWORK_LSDB(area), rn, lsa)
044506e7 283 ospf_db_summary_add(nbr, lsa);
996c9314 284 LSDB_LOOP (SUMMARY_LSDB(area), rn, lsa)
044506e7 285 ospf_db_summary_add(nbr, lsa);
d62a17ae 286
287 /* Process only if the neighbor is opaque capable. */
288 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
996c9314 289 LSDB_LOOP (OPAQUE_LINK_LSDB(area), rn, lsa)
044506e7 290 ospf_db_summary_add(nbr, lsa);
996c9314 291 LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa)
044506e7 292 ospf_db_summary_add(nbr, lsa);
d62a17ae 293 }
294
295 if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) {
996c9314 296 LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
044506e7 297 ospf_db_summary_add(nbr, lsa);
d62a17ae 298 }
299
d125213c 300 /* For Stub/NSSA area, we should not send Type-4 and Type-5 LSAs */
d62a17ae 301 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
d125213c
MR
302 && area->external_routing == OSPF_AREA_DEFAULT) {
303 LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
304 ospf_db_summary_add(nbr, lsa);
996c9314 305 LSDB_LOOP (EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa)
044506e7 306 ospf_db_summary_add(nbr, lsa);
d125213c 307 }
d62a17ae 308
309 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)
310 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
311 && area->external_routing == OSPF_AREA_DEFAULT))
996c9314 312 LSDB_LOOP (OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa)
044506e7 313 ospf_db_summary_add(nbr, lsa);
d62a17ae 314
315 return 0;
2d59836a 316}
317
d62a17ae 318static int nsm_exchange_done(struct ospf_neighbor *nbr)
2d59836a 319{
d62a17ae 320 if (ospf_ls_request_isempty(nbr))
321 return NSM_Full;
2d59836a 322
d62a17ae 323 /* Send Link State Request. */
324 if (nbr->t_ls_req == NULL)
325 ospf_ls_req_send(nbr);
2d59836a 326
d62a17ae 327 return NSM_Loading;
2d59836a 328}
329
d62a17ae 330static int nsm_adj_ok(struct ospf_neighbor *nbr)
2d59836a 331{
d62a17ae 332 int next_state = nbr->state;
333 int adj = nsm_should_adj(nbr);
2d59836a 334
d62a17ae 335 if (nbr->state == NSM_TwoWay && adj == 1) {
336 next_state = NSM_ExStart;
8b6912c2 337
d62a17ae 338 /* Send proactive ARP requests */
339 ospf_proactively_arp(nbr);
340 } else if (nbr->state >= NSM_ExStart && adj == 0)
341 next_state = NSM_TwoWay;
2d59836a 342
d62a17ae 343 return next_state;
2d59836a 344}
345
d1b1cd8f
PJ
346/* Clear adjacency related state for a neighbour, intended where nbr
347 * transitions from > ExStart (i.e. a Full or forming adjacency)
348 * to <= ExStart.
349 */
d62a17ae 350static void nsm_clear_adj(struct ospf_neighbor *nbr)
2d59836a 351{
d62a17ae 352 /* Clear Database Summary list. */
353 if (!ospf_db_summary_isempty(nbr))
354 ospf_db_summary_clear(nbr);
2d59836a 355
d62a17ae 356 /* Clear Link State Request list. */
357 if (!ospf_ls_request_isempty(nbr))
358 ospf_ls_request_delete_all(nbr);
2d59836a 359
d62a17ae 360 /* Clear Link State Retransmission list. */
361 if (!ospf_ls_retransmit_isempty(nbr))
362 ospf_ls_retransmit_clear(nbr);
2d59836a 363
d62a17ae 364 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O))
365 UNSET_FLAG(nbr->options, OSPF_OPTION_O);
2d59836a 366}
367
d62a17ae 368static int nsm_kill_nbr(struct ospf_neighbor *nbr)
2d59836a 369{
14fad76c
DS
370 struct ospf_interface *oi = nbr->oi;
371 struct ospf_neighbor *on;
372 struct route_node *rn;
373
d62a17ae 374 /* killing nbr_self is invalid */
375 if (nbr == nbr->oi->nbr_self) {
376 assert(nbr != nbr->oi->nbr_self);
377 return 0;
378 }
379
380 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) {
381 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
382
383 nbr_nbma->nbr = NULL;
384 nbr_nbma->state_change = nbr->state_change;
385
386 nbr->nbr_nbma = NULL;
387
388 OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer,
389 nbr_nbma->v_poll);
390
391 if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
392 zlog_debug(
96b663a3 393 "NSM[%s:%pI4:%s]: Down (PollIntervalTimer scheduled)",
d62a17ae 394 IF_NAME(nbr->oi),
96b663a3 395 &nbr->address.u.prefix4,
868a0861 396 ospf_get_name(nbr->oi->ospf));
d62a17ae 397 }
398
14fad76c
DS
399 /*
400 * Do we have any neighbors that are also operating
401 * on this interface?
402 */
403 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
404 on = rn->info;
405
406 if (!on)
407 continue;
408
409 if (on == nbr || on == oi->nbr_self)
410 continue;
411
412 /*
413 * on is in some state where we might be
414 * sending packets on this interface
415 */
416 if (on->state > NSM_Down) {
417 route_unlock_node(rn);
418 return 0;
419 }
420 }
421 /*
422 * If we get here we know that this interface
423 * has no neighbors in a state where we could
424 * be sending packets. Let's flush anything
425 * we got.
426 */
fb617d18 427 ospf_interface_fifo_flush(oi);
d62a17ae 428 return 0;
2d59836a 429}
430
2d59836a 431/* Neighbor State Machine */
2b64873d 432const struct {
d62a17ae 433 int (*func)(struct ospf_neighbor *);
434 int next_state;
435} NSM[OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = {
436 {
437 /* DependUpon: dummy state. */
438 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 439 {NULL, NSM_DependUpon}, /* HelloReceived */
d62a17ae 440 {NULL, NSM_DependUpon}, /* Start */
441 {NULL, NSM_DependUpon}, /* 2-WayReceived */
442 {NULL, NSM_DependUpon}, /* NegotiationDone */
443 {NULL, NSM_DependUpon}, /* ExchangeDone */
444 {NULL, NSM_DependUpon}, /* BadLSReq */
445 {NULL, NSM_DependUpon}, /* LoadingDone */
446 {NULL, NSM_DependUpon}, /* AdjOK? */
447 {NULL, NSM_DependUpon}, /* SeqNumberMismatch */
448 {NULL, NSM_DependUpon}, /* 1-WayReceived */
449 {NULL, NSM_DependUpon}, /* KillNbr */
450 {NULL, NSM_DependUpon}, /* InactivityTimer */
451 {NULL, NSM_DependUpon}, /* LLDown */
452 },
453 {
454 /* Deleted: dummy state. */
455 {NULL, NSM_Deleted}, /* NoEvent */
874a549d 456 {NULL, NSM_Deleted}, /* HelloReceived */
d62a17ae 457 {NULL, NSM_Deleted}, /* Start */
458 {NULL, NSM_Deleted}, /* 2-WayReceived */
459 {NULL, NSM_Deleted}, /* NegotiationDone */
460 {NULL, NSM_Deleted}, /* ExchangeDone */
461 {NULL, NSM_Deleted}, /* BadLSReq */
462 {NULL, NSM_Deleted}, /* LoadingDone */
463 {NULL, NSM_Deleted}, /* AdjOK? */
464 {NULL, NSM_Deleted}, /* SeqNumberMismatch */
465 {NULL, NSM_Deleted}, /* 1-WayReceived */
466 {NULL, NSM_Deleted}, /* KillNbr */
467 {NULL, NSM_Deleted}, /* InactivityTimer */
468 {NULL, NSM_Deleted}, /* LLDown */
469 },
470 {
471 /* Down: */
472 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d
MR
473 {nsm_hello_received, NSM_Init}, /* HelloReceived */
474 {nsm_start, NSM_Attempt}, /* Start */
d62a17ae 475 {NULL, NSM_Down}, /* 2-WayReceived */
476 {NULL, NSM_Down}, /* NegotiationDone */
477 {NULL, NSM_Down}, /* ExchangeDone */
478 {NULL, NSM_Down}, /* BadLSReq */
479 {NULL, NSM_Down}, /* LoadingDone */
480 {NULL, NSM_Down}, /* AdjOK? */
481 {NULL, NSM_Down}, /* SeqNumberMismatch */
482 {NULL, NSM_Down}, /* 1-WayReceived */
483 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
484 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
485 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
486 },
487 {
488 /* Attempt: */
489 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 490 {nsm_hello_received, NSM_Init}, /* HelloReceived */
d62a17ae 491 {NULL, NSM_Attempt}, /* Start */
492 {NULL, NSM_Attempt}, /* 2-WayReceived */
493 {NULL, NSM_Attempt}, /* NegotiationDone */
494 {NULL, NSM_Attempt}, /* ExchangeDone */
495 {NULL, NSM_Attempt}, /* BadLSReq */
496 {NULL, NSM_Attempt}, /* LoadingDone */
497 {NULL, NSM_Attempt}, /* AdjOK? */
498 {NULL, NSM_Attempt}, /* SeqNumberMismatch */
499 {NULL, NSM_Attempt}, /* 1-WayReceived */
500 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
501 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
502 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
503 },
504 {
505 /* Init: */
506 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 507 {nsm_hello_received, NSM_Init}, /* HelloReceived */
d62a17ae 508 {NULL, NSM_Init}, /* Start */
509 {nsm_twoway_received, NSM_DependUpon}, /* 2-WayReceived */
510 {NULL, NSM_Init}, /* NegotiationDone */
511 {NULL, NSM_Init}, /* ExchangeDone */
512 {NULL, NSM_Init}, /* BadLSReq */
513 {NULL, NSM_Init}, /* LoadingDone */
514 {NULL, NSM_Init}, /* AdjOK? */
515 {NULL, NSM_Init}, /* SeqNumberMismatch */
516 {NULL, NSM_Init}, /* 1-WayReceived */
517 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
518 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
519 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
520 },
521 {
522 /* 2-Way: */
523 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 524 {nsm_hello_received, NSM_TwoWay}, /* HelloReceived */
d62a17ae 525 {NULL, NSM_TwoWay}, /* Start */
526 {NULL, NSM_TwoWay}, /* 2-WayReceived */
527 {NULL, NSM_TwoWay}, /* NegotiationDone */
528 {NULL, NSM_TwoWay}, /* ExchangeDone */
529 {NULL, NSM_TwoWay}, /* BadLSReq */
530 {NULL, NSM_TwoWay}, /* LoadingDone */
531 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
532 {NULL, NSM_TwoWay}, /* SeqNumberMismatch */
533 {NULL, NSM_Init}, /* 1-WayReceived */
534 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
535 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
536 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
537 },
538 {
539 /* ExStart: */
540 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 541 {nsm_hello_received, NSM_ExStart}, /* HelloReceived */
d62a17ae 542 {NULL, NSM_ExStart}, /* Start */
543 {NULL, NSM_ExStart}, /* 2-WayReceived */
544 {nsm_negotiation_done, NSM_Exchange}, /* NegotiationDone */
545 {NULL, NSM_ExStart}, /* ExchangeDone */
546 {NULL, NSM_ExStart}, /* BadLSReq */
547 {NULL, NSM_ExStart}, /* LoadingDone */
548 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
549 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
550 {NULL, NSM_Init}, /* 1-WayReceived */
551 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
552 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
553 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
554 },
555 {
556 /* Exchange: */
557 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 558 {nsm_hello_received, NSM_Exchange}, /* HelloReceived */
d62a17ae 559 {NULL, NSM_Exchange}, /* Start */
560 {NULL, NSM_Exchange}, /* 2-WayReceived */
561 {NULL, NSM_Exchange}, /* NegotiationDone */
562 {nsm_exchange_done, NSM_DependUpon}, /* ExchangeDone */
563 {NULL, NSM_ExStart}, /* BadLSReq */
564 {NULL, NSM_Exchange}, /* LoadingDone */
565 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
566 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
567 {NULL, NSM_Init}, /* 1-WayReceived */
568 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
569 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
570 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
571 },
572 {
573 /* Loading: */
574 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 575 {nsm_hello_received, NSM_Loading}, /* HelloReceived */
d62a17ae 576 {NULL, NSM_Loading}, /* Start */
577 {NULL, NSM_Loading}, /* 2-WayReceived */
578 {NULL, NSM_Loading}, /* NegotiationDone */
579 {NULL, NSM_Loading}, /* ExchangeDone */
580 {NULL, NSM_ExStart}, /* BadLSReq */
581 {NULL, NSM_Full}, /* LoadingDone */
582 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
583 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
584 {NULL, NSM_Init}, /* 1-WayReceived */
585 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
586 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
587 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
588 },
589 {
590 /* Full: */
591 {NULL, NSM_DependUpon}, /* NoEvent */
874a549d 592 {nsm_hello_received, NSM_Full}, /* HelloReceived */
d62a17ae 593 {NULL, NSM_Full}, /* Start */
594 {NULL, NSM_Full}, /* 2-WayReceived */
595 {NULL, NSM_Full}, /* NegotiationDone */
596 {NULL, NSM_Full}, /* ExchangeDone */
597 {NULL, NSM_ExStart}, /* BadLSReq */
598 {NULL, NSM_Full}, /* LoadingDone */
599 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
600 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
601 {NULL, NSM_Init}, /* 1-WayReceived */
602 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
603 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
604 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
605 },
2d59836a 606};
607
2b64873d 608static const char *const ospf_nsm_event_str[] = {
874a549d 609 "NoEvent", "HelloReceived", "Start",
d62a17ae 610 "2-WayReceived", "NegotiationDone", "ExchangeDone",
611 "BadLSReq", "LoadingDone", "AdjOK?",
612 "SeqNumberMismatch", "1-WayReceived", "KillNbr",
613 "InactivityTimer", "LLDown",
2d59836a 614};
615
d62a17ae 616static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state,
617 int event)
3d63f380 618{
d62a17ae 619 /* Logging change of status. */
620 if (IS_DEBUG_OSPF(nsm, NSM_STATUS))
96b663a3
MS
621 zlog_debug("NSM[%s:%pI4:%s]: State change %s -> %s (%s)",
622 IF_NAME(nbr->oi), &nbr->router_id,
868a0861 623 ospf_get_name(nbr->oi->ospf),
d62a17ae 624 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
625 lookup_msg(ospf_nsm_state_msg, next_state, NULL),
626 ospf_nsm_event_str[event]);
627
628 /* Optionally notify about adjacency changes */
629 if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES)
630 && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)
631 || (next_state == NSM_Full) || (next_state < nbr->state)))
96b663a3
MS
632 zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
633 &nbr->router_id,
868a0861 634 ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi),
d62a17ae 635 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
636 lookup_msg(ospf_nsm_state_msg, next_state, NULL),
637 ospf_nsm_event_str[event]);
638
639 /* Advance in NSM */
640 if (next_state > nbr->state)
641 monotime(&nbr->ts_last_progress);
642 else /* regression in NSM */
643 {
644 monotime(&nbr->ts_last_regress);
645 nbr->last_regress_str = ospf_nsm_event_str[event];
646 }
3d63f380
PJ
647}
648
d62a17ae 649static void nsm_change_state(struct ospf_neighbor *nbr, int state)
2d59836a 650{
d62a17ae 651 struct ospf_interface *oi = nbr->oi;
652 struct ospf_area *vl_area = NULL;
d7c0a89a 653 uint8_t old_state;
d62a17ae 654
655 /* Preserve old status. */
656 old_state = nbr->state;
657
658 /* Change to new status. */
659 nbr->state = state;
660
661 /* Statistics. */
662 nbr->state_change++;
663
664 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
665 vl_area = ospf_area_lookup_by_area_id(oi->ospf,
666 oi->vl_data->vl_area_id);
667
668 /* Generate NeighborChange ISM event.
669 *
670 * In response to NeighborChange, DR election is rerun. The information
671 * from the election process is required by the router-lsa construction.
672 *
673 * Therefore, trigger the event prior to refreshing the LSAs. */
674 switch (oi->state) {
675 case ISM_DROther:
676 case ISM_Backup:
677 case ISM_DR:
678 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay)
679 || (old_state >= NSM_TwoWay && state < NSM_TwoWay))
680 OSPF_ISM_EVENT_EXECUTE(oi, ISM_NeighborChange);
681 break;
682 default:
683 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc.
684 */
685 break;
2d59836a 686 }
2d59836a 687
d62a17ae 688 /* One of the neighboring routers changes to/from the FULL state. */
689 if ((old_state != NSM_Full && state == NSM_Full)
690 || (old_state == NSM_Full && state != NSM_Full)) {
691 if (state == NSM_Full) {
692 oi->full_nbrs++;
693 oi->area->full_nbrs++;
694
695 ospf_check_abr_status(oi->ospf);
696
697 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
698 if (++vl_area->full_vls == 1)
699 ospf_schedule_abr_task(oi->ospf);
d62a17ae 700 } else {
701 oi->full_nbrs--;
702 oi->area->full_nbrs--;
703
704 ospf_check_abr_status(oi->ospf);
705
706 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
707 if (vl_area->full_vls > 0)
708 if (--vl_area->full_vls == 0)
709 ospf_schedule_abr_task(
710 oi->ospf);
711 }
712
05ba78e4 713 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
996c9314 714 zlog_info(
96b663a3
MS
715 "%s:[%pI4:%s], %s -> %s): scheduling new router-LSA origination",
716 __func__, &nbr->router_id,
868a0861 717 ospf_get_name(oi->ospf),
05ba78e4
CS
718 lookup_msg(ospf_nsm_state_msg, old_state, NULL),
719 lookup_msg(ospf_nsm_state_msg, state, NULL));
d62a17ae 720
5a77dd8f 721 /* Dont originate router LSA if the current
722 * router is acting as a HELPER for this neighbour.
723 */
724 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
725 ospf_router_lsa_update_area(oi->area);
d62a17ae 726
727 if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
f7813c7c 728 vl_area = ospf_area_lookup_by_area_id(
d62a17ae 729 oi->ospf, oi->vl_data->vl_area_id);
730
731 if (vl_area)
732 ospf_router_lsa_update_area(vl_area);
733 }
734
5a77dd8f 735 /* Dont originate/flush network LSA if the current
736 * router is acting as a HELPER for this neighbour.
737 */
738 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
739 /* Originate network-LSA. */
740 if (oi->state == ISM_DR) {
741 if (oi->network_lsa_self
742 && oi->full_nbrs == 0) {
743 ospf_lsa_flush_area(
744 oi->network_lsa_self, oi->area);
745 ospf_lsa_unlock(&oi->network_lsa_self);
746 oi->network_lsa_self = NULL;
747 } else
748 ospf_network_lsa_update(oi);
749 }
d62a17ae 750 }
10514170
RW
751
752 if (state == NSM_Full && oi->ospf->gr_info.restart_in_progress)
753 ospf_gr_check_adjs(oi->ospf);
d62a17ae 754 }
2d59836a 755
d62a17ae 756 ospf_opaque_nsm_change(nbr, old_state);
757
758 /* State changes from > ExStart to <= ExStart should clear any Exchange
759 * or Full/LSA Update related lists and state.
760 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
761 */
762 if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
763 nsm_clear_adj(nbr);
764
765 /* Start DD exchange protocol */
766 if (state == NSM_ExStart) {
767 if (nbr->dd_seqnum == 0)
5920b3eb 768 nbr->dd_seqnum = (uint32_t)frr_weak_random();
d62a17ae 769 else
770 nbr->dd_seqnum++;
771
772 nbr->dd_flags =
773 OSPF_DD_FLAG_I | OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS;
e6a22aeb
SK
774 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
775 zlog_info(
96b663a3 776 "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x",
44076f4d
RW
777 ospf_get_name(oi->ospf), &nbr->router_id,
778 nbr->dd_seqnum, nbr->dd_flags);
d62a17ae 779 ospf_db_desc_send(nbr);
2d59836a 780 }
781
d62a17ae 782 /* clear cryptographic sequence number */
783 if (state == NSM_Down)
784 nbr->crypt_seqnum = 0;
2d59836a 785
659f4e40
RZ
786 if (nbr->bfd_session)
787 ospf_bfd_trigger_event(nbr, old_state, state);
2d59836a 788
d62a17ae 789 /* Preserve old status? */
2d59836a 790}
791
792/* Execute NSM event process. */
cc9f21da 793void ospf_nsm_event(struct thread *thread)
2d59836a 794{
d62a17ae 795 int event;
796 int next_state;
797 struct ospf_neighbor *nbr;
798
799 nbr = THREAD_ARG(thread);
800 event = THREAD_VAL(thread);
801
802 if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
96b663a3
MS
803 zlog_debug("NSM[%s:%pI4:%s]: %s (%s)", IF_NAME(nbr->oi),
804 &nbr->router_id,
868a0861 805 ospf_get_name(nbr->oi->ospf),
d62a17ae 806 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
807 ospf_nsm_event_str[event]);
808
809 next_state = NSM[nbr->state][event].next_state;
810
811 /* Call function. */
812 if (NSM[nbr->state][event].func != NULL) {
813 int func_state = (*(NSM[nbr->state][event].func))(nbr);
814
815 if (NSM[nbr->state][event].next_state == NSM_DependUpon)
816 next_state = func_state;
817 else if (func_state) {
818 /* There's a mismatch between the FSM tables and what an
819 * FSM
820 * action/state-change function returned. State changes
821 * which
822 * do not have conditional/DependUpon next-states should
823 * not
824 * try set next_state.
825 */
ade6974d 826 flog_err(
cf444bcf 827 EC_OSPF_FSM_INVALID_STATE,
96b663a3
MS
828 "NSM[%s:%pI4:%s]: %s (%s): Warning: action tried to change next_state to %s",
829 IF_NAME(nbr->oi), &nbr->router_id,
868a0861 830 ospf_get_name(nbr->oi->ospf),
ade6974d
QY
831 lookup_msg(ospf_nsm_state_msg, nbr->state,
832 NULL),
833 ospf_nsm_event_str[event],
834 lookup_msg(ospf_nsm_state_msg, func_state,
835 NULL));
d62a17ae 836 }
837 }
838
839 assert(next_state != NSM_DependUpon);
840
841 /* If state is changed. */
842 if (next_state != nbr->state) {
843 int old_state = nbr->state;
844
845 nsm_notice_state_change(nbr, next_state, event);
846 nsm_change_state(nbr, next_state);
847
848 hook_call(ospf_nsm_change, nbr, next_state, old_state);
849 }
850
851 /* Make sure timer is set. */
852 nsm_timer_set(nbr);
853
854 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
855 * is deleted.
856 *
857 * Rather than encode knowledge here of which events lead to NBR
858 * delete, we take our cue from the NSM table, via the dummy
859 * 'Deleted' neighbour state.
860 */
861 if (nbr->state == NSM_Deleted)
862 ospf_nbr_delete(nbr);
2d59836a 863}
864
865/* Check loading state. */
d62a17ae 866void ospf_check_nbr_loading(struct ospf_neighbor *nbr)
2d59836a 867{
d62a17ae 868 if (nbr->state == NSM_Loading) {
869 if (ospf_ls_request_isempty(nbr))
870 OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_LoadingDone);
871 else if (nbr->ls_req_last == NULL)
872 ospf_ls_req_event(nbr);
873 }
2d59836a 874}