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