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