Coverage Report

Created: 2026-08-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/ospfd/ospf_nsm.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * OSPF version 2  Neighbor State Machine
4
 * From RFC2328 [OSPF Version 2]
5
 * Copyright (C) 1999, 2000 Toshiaki Takada
6
 */
7
8
#include <zebra.h>
9
10
#include "frrevent.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"
20
#include "command.h"
21
#include "network.h"
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"
36
#include "ospfd/ospf_bfd.h"
37
#include "ospfd/ospf_gr.h"
38
#include "ospfd/ospf_errors.h"
39
40
DEFINE_HOOK(ospf_nsm_change,
41
      (struct ospf_neighbor * on, int state, int oldstate),
42
      (on, state, oldstate));
43
44
static void nsm_clear_adj(struct ospf_neighbor *);
45
46
/* OSPF NSM Timer functions. */
47
static void ospf_inactivity_timer(struct event *thread)
48
0
{
49
0
  struct ospf_neighbor *nbr;
50
0
51
0
  nbr = EVENT_ARG(thread);
52
0
  nbr->t_inactivity = NULL;
53
0
54
0
  if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
55
0
    zlog_debug("NSM[%s:%pI4:%s]: Timer (Inactivity timer expire)",
56
0
         IF_NAME(nbr->oi), &nbr->router_id,
57
0
         ospf_get_name(nbr->oi->ospf));
58
0
59
0
  /* Dont trigger NSM_InactivityTimer event , if the current
60
0
   * router acting as HELPER for this neighbour.
61
0
   */
62
0
  if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
63
0
    OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
64
0
  else {
65
0
    if (IS_DEBUG_OSPF_GR)
66
0
      zlog_debug(
67
0
        "%s, Acting as HELPER for this neighbour, So restart the dead timer",
68
0
        __func__);
69
0
    OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
70
0
          nbr->v_inactivity);
71
0
  }
72
0
}
73
74
static void ospf_db_desc_timer(struct event *thread)
75
0
{
76
0
  struct ospf_neighbor *nbr;
77
0
78
0
  nbr = EVENT_ARG(thread);
79
0
  nbr->t_db_desc = NULL;
80
0
81
0
  if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
82
0
    zlog_debug("NSM[%s:%pI4:%s]: Timer (DD Retransmit timer expire)",
83
0
         IF_NAME(nbr->oi), &nbr->src,
84
0
         ospf_get_name(nbr->oi->ospf));
85
0
86
0
  /* resent last send DD packet. */
87
0
  assert(nbr->last_send);
88
0
  ospf_db_desc_resend(nbr);
89
0
90
0
  /* DD Retransmit timer set. */
91
0
  OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
92
0
}
93
94
/* Hook function called after ospf NSM event is occurred.
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
 */
103
static void nsm_timer_set(struct ospf_neighbor *nbr)
104
0
{
105
0
  switch (nbr->state) {
106
0
  case NSM_Deleted:
107
0
  case NSM_Down:
108
0
    EVENT_OFF(nbr->t_inactivity);
109
0
    EVENT_OFF(nbr->t_hello_reply);
110
  /* fallthru */
111
0
  case NSM_Attempt:
112
0
  case NSM_Init:
113
0
  case NSM_TwoWay:
114
0
    EVENT_OFF(nbr->t_db_desc);
115
0
    EVENT_OFF(nbr->t_ls_upd);
116
0
    EVENT_OFF(nbr->t_ls_req);
117
0
    break;
118
0
  case NSM_ExStart:
119
0
    OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer,
120
0
          nbr->v_db_desc);
121
0
    EVENT_OFF(nbr->t_ls_upd);
122
0
    EVENT_OFF(nbr->t_ls_req);
123
0
    break;
124
0
  case NSM_Exchange:
125
0
    OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer,
126
0
          nbr->v_ls_upd);
127
0
    if (!IS_SET_DD_MS(nbr->dd_flags))
128
0
      EVENT_OFF(nbr->t_db_desc);
129
0
    break;
130
0
  case NSM_Loading:
131
0
  case NSM_Full:
132
0
  default:
133
0
    EVENT_OFF(nbr->t_db_desc);
134
0
    break;
135
0
  }
136
0
}
137
138
/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
139
 * the given neighbour
140
 */
141
int nsm_should_adj(struct ospf_neighbor *nbr)
142
0
{
143
0
  struct ospf_interface *oi = nbr->oi;
144
145
  /* These network types must always form adjacencies. */
146
0
  if (oi->type == OSPF_IFTYPE_POINTOPOINT
147
0
      || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
148
0
      || oi->type == OSPF_IFTYPE_VIRTUALLINK
149
      /* Router itself is the DRouter or the BDRouter. */
150
0
      || IPV4_ADDR_SAME(&oi->address->u.prefix4, &DR(oi))
151
0
      || IPV4_ADDR_SAME(&oi->address->u.prefix4, &BDR(oi))
152
      /* Neighboring Router is the DRouter or the BDRouter. */
153
0
      || IPV4_ADDR_SAME(&nbr->address.u.prefix4, &DR(oi))
154
0
      || IPV4_ADDR_SAME(&nbr->address.u.prefix4, &BDR(oi)))
155
0
    return 1;
156
157
0
  return 0;
158
0
}
159
160
/* OSPF NSM functions. */
161
static int nsm_hello_received(struct ospf_neighbor *nbr)
162
0
{
163
  /* Start or Restart Inactivity Timer. */
164
0
  EVENT_OFF(nbr->t_inactivity);
165
166
0
  OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
167
0
        nbr->v_inactivity);
168
169
0
  if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
170
0
    EVENT_OFF(nbr->nbr_nbma->t_poll);
171
172
  /* Send proactive ARP requests */
173
0
  if (nbr->state < NSM_Exchange)
174
0
    ospf_proactively_arp(nbr);
175
176
0
  return 0;
177
0
}
178
179
static int nsm_start(struct ospf_neighbor *nbr)
180
0
{
181
0
  if (nbr->nbr_nbma)
182
0
    EVENT_OFF(nbr->nbr_nbma->t_poll);
183
184
0
  EVENT_OFF(nbr->t_inactivity);
185
186
0
  OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
187
0
        nbr->v_inactivity);
188
189
  /* Send proactive ARP requests */
190
0
  ospf_proactively_arp(nbr);
191
192
0
  return 0;
193
0
}
194
195
static int nsm_twoway_received(struct ospf_neighbor *nbr)
196
0
{
197
0
  int adj = nsm_should_adj(nbr);
198
199
  /* Send proactive ARP requests */
200
0
  if (adj)
201
0
    ospf_proactively_arp(nbr);
202
203
0
  return (adj ? NSM_ExStart : NSM_TwoWay);
204
0
}
205
206
int ospf_db_summary_count(struct ospf_neighbor *nbr)
207
0
{
208
0
  return ospf_lsdb_count_all(&nbr->db_sum);
209
0
}
210
211
int ospf_db_summary_isempty(struct ospf_neighbor *nbr)
212
59
{
213
59
  return ospf_lsdb_isempty(&nbr->db_sum);
214
59
}
215
216
static int ospf_db_summary_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
217
0
{
218
0
  switch (lsa->data->type) {
219
0
  case OSPF_OPAQUE_LINK_LSA:
220
    /* Exclude type-9 LSAs that does not have the same "oi" with
221
     * "nbr". */
222
0
    if (ospf_if_exists(lsa->oi) != nbr->oi)
223
0
      return 0;
224
0
    break;
225
0
  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
0
    break;
231
0
  case OSPF_OPAQUE_AS_LSA:
232
0
  default:
233
0
    break;
234
0
  }
235
236
  /* Stay away from any Local Translated Type-7 LSAs */
237
0
  if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT))
238
0
    return 0;
239
240
0
  if (IS_LSA_MAXAGE(lsa))
241
0
    ospf_ls_retransmit_add(nbr, lsa);
242
0
  else
243
0
    ospf_lsdb_add(&nbr->db_sum, lsa);
244
245
0
  return 0;
246
0
}
247
248
void ospf_db_summary_clear(struct ospf_neighbor *nbr)
249
0
{
250
0
  struct ospf_lsdb *lsdb;
251
0
  int i;
252
253
0
  lsdb = &nbr->db_sum;
254
0
  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
255
0
    struct route_table *table = lsdb->type[i].db;
256
0
    struct route_node *rn;
257
258
0
    for (rn = route_top(table); rn; rn = route_next(rn))
259
0
      if (rn->info)
260
0
        ospf_lsdb_delete(&nbr->db_sum, rn->info);
261
0
  }
262
0
}
263
264
265
/* The area link state database consists of the router-LSAs,
266
   network-LSAs and summary-LSAs contained in the area structure,
267
   along with the AS-external-LSAs contained in the global structure.
268
   AS-external-LSAs are omitted from a virtual neighbor's Database
269
   summary list.  AS-external-LSAs are omitted from the Database
270
   summary list if the area has been configured as a stub. */
271
static int nsm_negotiation_done(struct ospf_neighbor *nbr)
272
0
{
273
0
  struct ospf_area *area = nbr->oi->area;
274
0
  struct ospf_lsa *lsa;
275
0
  struct route_node *rn;
276
277
  /* Send proactive ARP requests */
278
0
  ospf_proactively_arp(nbr);
279
280
0
  LSDB_LOOP (ROUTER_LSDB(area), rn, lsa)
281
0
    ospf_db_summary_add(nbr, lsa);
282
0
  LSDB_LOOP (NETWORK_LSDB(area), rn, lsa)
283
0
    ospf_db_summary_add(nbr, lsa);
284
0
  LSDB_LOOP (SUMMARY_LSDB(area), rn, lsa)
285
0
    ospf_db_summary_add(nbr, lsa);
286
287
  /* Process only if the neighbor is opaque capable. */
288
0
  if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
289
0
    LSDB_LOOP (OPAQUE_LINK_LSDB(area), rn, lsa)
290
0
      ospf_db_summary_add(nbr, lsa);
291
0
    LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa)
292
0
      ospf_db_summary_add(nbr, lsa);
293
0
  }
294
295
0
  if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) {
296
0
    LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
297
0
      ospf_db_summary_add(nbr, lsa);
298
0
  }
299
300
  /* For Stub/NSSA area, we should not send Type-4 and Type-5 LSAs */
301
0
  if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
302
0
      && area->external_routing == OSPF_AREA_DEFAULT) {
303
0
    LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
304
0
      ospf_db_summary_add(nbr, lsa);
305
0
    LSDB_LOOP (EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa)
306
0
      ospf_db_summary_add(nbr, lsa);
307
0
  }
308
309
0
  if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)
310
0
      && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
311
0
    && area->external_routing == OSPF_AREA_DEFAULT))
312
0
    LSDB_LOOP (OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa)
313
0
      ospf_db_summary_add(nbr, lsa);
314
315
0
  return 0;
316
0
}
317
318
static int nsm_exchange_done(struct ospf_neighbor *nbr)
319
0
{
320
0
  if (ospf_ls_request_isempty(nbr))
321
0
    return NSM_Full;
322
323
  /* Send Link State Request. */
324
0
  if (nbr->t_ls_req == NULL)
325
0
    ospf_ls_req_send(nbr);
326
327
0
  return NSM_Loading;
328
0
}
329
330
static int nsm_adj_ok(struct ospf_neighbor *nbr)
331
0
{
332
0
  int next_state = nbr->state;
333
0
  int adj = nsm_should_adj(nbr);
334
335
0
  if (nbr->state == NSM_TwoWay && adj == 1) {
336
0
    next_state = NSM_ExStart;
337
338
    /* Send proactive ARP requests */
339
0
    ospf_proactively_arp(nbr);
340
0
  } else if (nbr->state >= NSM_ExStart && adj == 0)
341
0
    next_state = NSM_TwoWay;
342
343
0
  return next_state;
344
0
}
345
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
 */
350
static void nsm_clear_adj(struct ospf_neighbor *nbr)
351
0
{
352
  /* Clear Database Summary list. */
353
0
  if (!ospf_db_summary_isempty(nbr))
354
0
    ospf_db_summary_clear(nbr);
355
356
  /* Clear Link State Request list. */
357
0
  if (!ospf_ls_request_isempty(nbr))
358
0
    ospf_ls_request_delete_all(nbr);
359
360
  /* Clear Link State Retransmission list. */
361
0
  if (!ospf_ls_retransmit_isempty(nbr))
362
0
    ospf_ls_retransmit_clear(nbr);
363
364
0
  if (CHECK_FLAG(nbr->options, OSPF_OPTION_O))
365
0
    UNSET_FLAG(nbr->options, OSPF_OPTION_O);
366
0
}
367
368
static int nsm_kill_nbr(struct ospf_neighbor *nbr)
369
0
{
370
0
  struct ospf_interface *oi = nbr->oi;
371
0
  struct ospf_neighbor *on;
372
0
  struct route_node *rn;
373
374
  /* killing nbr_self is invalid */
375
0
  if (nbr == nbr->oi->nbr_self) {
376
0
    assert(nbr != nbr->oi->nbr_self);
377
0
    return 0;
378
0
  }
379
380
0
  if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) {
381
0
    struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
382
383
0
    nbr_nbma->nbr = NULL;
384
0
    nbr_nbma->state_change = nbr->state_change;
385
386
0
    nbr->nbr_nbma = NULL;
387
388
0
    OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer,
389
0
           nbr_nbma->v_poll);
390
391
0
    if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
392
0
      zlog_debug(
393
0
        "NSM[%s:%pI4:%s]: Down (PollIntervalTimer scheduled)",
394
0
        IF_NAME(nbr->oi),
395
0
        &nbr->address.u.prefix4,
396
0
        ospf_get_name(nbr->oi->ospf));
397
0
  }
398
399
  /*
400
   * Do we have any neighbors that are also operating
401
   * on this interface?
402
   */
403
0
  for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
404
0
    on = rn->info;
405
406
0
    if (!on)
407
0
      continue;
408
409
0
    if (on == nbr || on == oi->nbr_self)
410
0
      continue;
411
412
    /*
413
     * on is in some state where we might be
414
     * sending packets on this interface
415
     */
416
0
    if (on->state > NSM_Down) {
417
0
      route_unlock_node(rn);
418
0
      return 0;
419
0
    }
420
0
  }
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
   */
427
0
  ospf_interface_fifo_flush(oi);
428
0
  return 0;
429
0
}
430
431
/* Neighbor State Machine */
432
const struct {
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           */
439
    {NULL, NSM_DependUpon}, /* HelloReceived     */
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           */
456
    {NULL, NSM_Deleted}, /* HelloReceived     */
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           */
473
    {nsm_hello_received, NSM_Init},  /* HelloReceived     */
474
    {nsm_start, NSM_Attempt},  /* Start             */
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           */
490
    {nsm_hello_received, NSM_Init},  /* HelloReceived     */
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           */
507
    {nsm_hello_received, NSM_Init},        /* HelloReceived     */
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           */
524
    {nsm_hello_received, NSM_TwoWay},  /* HelloReceived     */
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           */
541
    {nsm_hello_received, NSM_ExStart},    /* HelloReceived     */
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           */
558
    {nsm_hello_received, NSM_Exchange},  /* HelloReceived     */
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           */
575
    {nsm_hello_received, NSM_Loading},  /* HelloReceived     */
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           */
592
    {nsm_hello_received, NSM_Full},  /* HelloReceived     */
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
  },
606
};
607
608
static const char *const ospf_nsm_event_str[] = {
609
  "NoEvent",     "HelloReceived",  "Start",
610
  "2-WayReceived",     "NegotiationDone", "ExchangeDone",
611
  "BadLSReq",   "LoadingDone",     "AdjOK?",
612
  "SeqNumberMismatch", "1-WayReceived",   "KillNbr",
613
  "InactivityTimer",   "LLDown",
614
};
615
616
static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state,
617
            int event)
618
0
{
619
  /* Logging change of status. */
620
0
  if (IS_DEBUG_OSPF(nsm, NSM_STATUS))
621
0
    zlog_debug("NSM[%s:%pI4:%s]: State change %s -> %s (%s)",
622
0
         IF_NAME(nbr->oi), &nbr->router_id,
623
0
         ospf_get_name(nbr->oi->ospf),
624
0
         lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
625
0
         lookup_msg(ospf_nsm_state_msg, next_state, NULL),
626
0
         ospf_nsm_event_str[event]);
627
628
  /* Optionally notify about adjacency changes */
629
0
  if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES)
630
0
      && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)
631
0
    || (next_state == NSM_Full) || (next_state < nbr->state)))
632
0
    zlog_notice(
633
0
      "AdjChg: Nbr %pI4, NbrIP %pI4 (%s) on %s: %s -> %s (%s)",
634
0
      &nbr->router_id, &nbr->src,
635
0
      ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi),
636
0
      lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
637
0
      lookup_msg(ospf_nsm_state_msg, next_state, NULL),
638
0
      ospf_nsm_event_str[event]);
639
640
  /* Advance in NSM */
641
0
  if (next_state > nbr->state)
642
0
    monotime(&nbr->ts_last_progress);
643
0
  else /* regression in NSM */
644
0
  {
645
0
    monotime(&nbr->ts_last_regress);
646
0
    nbr->last_regress_str = ospf_nsm_event_str[event];
647
0
  }
648
0
}
649
650
static void nsm_change_state(struct ospf_neighbor *nbr, int state)
651
0
{
652
0
  struct ospf_interface *oi = nbr->oi;
653
0
  struct ospf_area *vl_area = NULL;
654
0
  uint8_t old_state;
655
656
  /* Preserve old status. */
657
0
  old_state = nbr->state;
658
659
  /* Change to new status. */
660
0
  nbr->state = state;
661
662
  /* Statistics. */
663
0
  nbr->state_change++;
664
665
0
  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
666
0
    vl_area = ospf_area_lookup_by_area_id(oi->ospf,
667
0
                  oi->vl_data->vl_area_id);
668
669
  /* Generate NeighborChange ISM event.
670
   *
671
   * In response to NeighborChange, DR election is rerun. The information
672
   * from the election process is required by the router-lsa construction.
673
   *
674
   * Therefore, trigger the event prior to refreshing the LSAs. */
675
0
  switch (oi->state) {
676
0
  case ISM_DROther:
677
0
  case ISM_Backup:
678
0
  case ISM_DR:
679
0
    if ((old_state < NSM_TwoWay && state >= NSM_TwoWay)
680
0
        || (old_state >= NSM_TwoWay && state < NSM_TwoWay))
681
0
      OSPF_ISM_EVENT_EXECUTE(oi, ISM_NeighborChange);
682
0
    break;
683
0
  default:
684
    /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc.
685
     */
686
0
    break;
687
0
  }
688
689
  /* One of the neighboring routers changes to/from the FULL state. */
690
0
  if ((old_state != NSM_Full && state == NSM_Full)
691
0
      || (old_state == NSM_Full && state != NSM_Full)) {
692
0
    if (state == NSM_Full) {
693
0
      oi->full_nbrs++;
694
0
      oi->area->full_nbrs++;
695
696
0
      ospf_check_abr_status(oi->ospf);
697
698
0
      if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
699
0
        if (++vl_area->full_vls == 1)
700
0
          ospf_schedule_abr_task(oi->ospf);
701
0
    } else {
702
0
      oi->full_nbrs--;
703
0
      oi->area->full_nbrs--;
704
705
0
      ospf_check_abr_status(oi->ospf);
706
707
0
      if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
708
0
        if (vl_area->full_vls > 0)
709
0
          if (--vl_area->full_vls == 0)
710
0
            ospf_schedule_abr_task(
711
0
              oi->ospf);
712
0
    }
713
714
0
    if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
715
0
      zlog_info(
716
0
        "%s:[%pI4:%s], %s -> %s): scheduling new router-LSA origination",
717
0
        __func__, &nbr->router_id,
718
0
        ospf_get_name(oi->ospf),
719
0
        lookup_msg(ospf_nsm_state_msg, old_state, NULL),
720
0
        lookup_msg(ospf_nsm_state_msg, state, NULL));
721
722
    /* Dont originate router LSA if the current
723
     * router is acting as a HELPER for this neighbour.
724
     */
725
0
    if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
726
0
      ospf_router_lsa_update_area(oi->area);
727
728
0
    if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
729
0
      vl_area = ospf_area_lookup_by_area_id(
730
0
        oi->ospf, oi->vl_data->vl_area_id);
731
732
0
      if (vl_area)
733
0
        ospf_router_lsa_update_area(vl_area);
734
0
    }
735
736
    /* Dont originate/flush network LSA if the current
737
     * router is acting as a HELPER for this neighbour.
738
     */
739
0
    if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
740
      /* Originate network-LSA. */
741
0
      if (oi->state == ISM_DR) {
742
0
        if (oi->network_lsa_self
743
0
            && oi->full_nbrs == 0) {
744
0
          ospf_lsa_flush_area(
745
0
            oi->network_lsa_self, oi->area);
746
0
          ospf_lsa_unlock(&oi->network_lsa_self);
747
0
          oi->network_lsa_self = NULL;
748
0
        } else
749
0
          ospf_network_lsa_update(oi);
750
0
      }
751
0
    }
752
753
0
    if (state == NSM_Full && oi->ospf->gr_info.restart_in_progress)
754
0
      ospf_gr_check_adjs(oi->ospf);
755
0
  }
756
757
0
  ospf_opaque_nsm_change(nbr, old_state);
758
759
  /* State changes from > ExStart to <= ExStart should clear any Exchange
760
   * or Full/LSA Update related lists and state.
761
   * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
762
   */
763
0
  if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
764
0
    nsm_clear_adj(nbr);
765
766
  /* Start DD exchange protocol */
767
0
  if (state == NSM_ExStart) {
768
0
    if (nbr->dd_seqnum == 0)
769
0
      nbr->dd_seqnum = (uint32_t)frr_weak_random();
770
0
    else
771
0
      nbr->dd_seqnum++;
772
773
0
    nbr->dd_flags =
774
0
      OSPF_DD_FLAG_I | OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS;
775
0
    if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
776
0
      zlog_info(
777
0
        "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x",
778
0
        ospf_get_name(oi->ospf), &nbr->router_id,
779
0
        nbr->dd_seqnum, nbr->dd_flags);
780
0
    ospf_db_desc_send(nbr);
781
0
  }
782
783
  /* clear cryptographic sequence number */
784
0
  if (state == NSM_Down)
785
0
    nbr->crypt_seqnum = 0;
786
787
0
  if (nbr->bfd_session)
788
0
    ospf_bfd_trigger_event(nbr, old_state, state);
789
790
  /* Preserve old status? */
791
0
}
792
793
/* Execute NSM event process. */
794
void ospf_nsm_event(struct event *thread)
795
0
{
796
0
  int event;
797
0
  int next_state;
798
0
  struct ospf_neighbor *nbr;
799
800
0
  nbr = EVENT_ARG(thread);
801
0
  event = EVENT_VAL(thread);
802
803
0
  if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
804
0
    zlog_debug("NSM[%s:%pI4:%s]: %s (%s)", IF_NAME(nbr->oi),
805
0
         &nbr->router_id,
806
0
         ospf_get_name(nbr->oi->ospf),
807
0
         lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
808
0
         ospf_nsm_event_str[event]);
809
810
0
  next_state = NSM[nbr->state][event].next_state;
811
812
  /* Call function. */
813
0
  if (NSM[nbr->state][event].func != NULL) {
814
0
    int func_state = (*(NSM[nbr->state][event].func))(nbr);
815
816
0
    if (NSM[nbr->state][event].next_state == NSM_DependUpon)
817
0
      next_state = func_state;
818
0
    else if (func_state) {
819
      /* There's a mismatch between the FSM tables and what an
820
       * FSM
821
       * action/state-change function returned. State changes
822
       * which
823
       * do not have conditional/DependUpon next-states should
824
       * not
825
       * try set next_state.
826
       */
827
0
      flog_err(
828
0
        EC_OSPF_FSM_INVALID_STATE,
829
0
        "NSM[%s:%pI4:%s]: %s (%s): Warning: action tried to change next_state to %s",
830
0
        IF_NAME(nbr->oi), &nbr->router_id,
831
0
        ospf_get_name(nbr->oi->ospf),
832
0
        lookup_msg(ospf_nsm_state_msg, nbr->state,
833
0
             NULL),
834
0
        ospf_nsm_event_str[event],
835
0
        lookup_msg(ospf_nsm_state_msg, func_state,
836
0
             NULL));
837
0
    }
838
0
  }
839
840
0
  assert(next_state != NSM_DependUpon);
841
842
  /* If state is changed. */
843
0
  if (next_state != nbr->state) {
844
0
    int old_state = nbr->state;
845
846
0
    nsm_notice_state_change(nbr, next_state, event);
847
0
    nsm_change_state(nbr, next_state);
848
849
0
    hook_call(ospf_nsm_change, nbr, next_state, old_state);
850
0
  }
851
852
  /* Make sure timer is set. */
853
0
  nsm_timer_set(nbr);
854
855
  /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
856
   * is deleted.
857
   *
858
   * Rather than encode knowledge here of which events lead to NBR
859
   * delete, we take our cue from the NSM table, via the dummy
860
   * 'Deleted' neighbour state.
861
   */
862
0
  if (nbr->state == NSM_Deleted)
863
0
    ospf_nbr_delete(nbr);
864
0
}
865
866
/* Check loading state. */
867
void ospf_check_nbr_loading(struct ospf_neighbor *nbr)
868
0
{
869
0
  if (nbr->state == NSM_Loading) {
870
0
    if (ospf_ls_request_isempty(nbr))
871
0
      OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_LoadingDone);
872
0
    else if (nbr->ls_req_last == NULL)
873
0
      ospf_ls_req_event(nbr);
874
0
  }
875
0
}