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