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