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 51void nsm_reset_nbr (struct ospf_neighbor *); 52 53 54/* OSPF NSM Timer functions. */ 55int 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 72int 73ospf_db_desc_timer (struct thread *thread) 74{ 75 struct ospf_interface *oi; 76 struct ospf_neighbor *nbr; 77 78 nbr = THREAD_ARG (thread); 79 nbr->t_db_desc = NULL; 80 81 oi = nbr->oi; 82 83 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) 84 zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (DD Retransmit timer expire)", 85 IF_NAME (nbr->oi), inet_ntoa (nbr->src)); 86 87 /* resent last send DD packet. */ 88 assert (nbr->last_send); 89 ospf_db_desc_resend (nbr); 90 91 /* DD Retransmit timer set. */ 92 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); 93 94 return 0; 95} 96 97/* Hook function called after ospf NSM event is occured. */ 98 99void 100nsm_timer_set (struct ospf_neighbor *nbr) 101{ 102 switch (nbr->state) 103 { 104 case NSM_Down: 105 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 106 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); 107 break; 108 case NSM_Attempt: 109 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 110 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); 111 break; 112 case NSM_Init: 113 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 114 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); 115 break; 116 case NSM_TwoWay: 117 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 118 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); 119 break; 120 case NSM_ExStart: 121 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); 122 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); 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 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 131 break; 132 case NSM_Full: 133 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 134 break; 135 default: 136 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 137 break; 138 } 139} 140 141 142/* OSPF NSM functions. */ 143int 144nsm_ignore (struct ospf_neighbor *nbr) 145{ 146 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) 147 zlog (NULL, LOG_INFO, "NSM[%s:%s]: nsm_ignore called", 148 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); 149 150 return 0; 151} 152 153int 154nsm_hello_received (struct ospf_neighbor *nbr) 155{ 156 /* Start or Restart Inactivity Timer. */ 157 OSPF_NSM_TIMER_OFF (nbr->t_inactivity); 158 159 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer, 160 nbr->v_inactivity); 161 162 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma) 163 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll); 164 165 return 0; 166} 167 168int 169nsm_start (struct ospf_neighbor *nbr) 170{ 171 172 nsm_reset_nbr (nbr); 173 174 if (nbr->nbr_nbma) 175 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll); 176 177 OSPF_NSM_TIMER_OFF (nbr->t_inactivity); 178 179 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer, 180 nbr->v_inactivity); 181 182 return 0; 183} 184 185int 186nsm_twoway_received (struct ospf_neighbor *nbr) 187{ 188 struct ospf_interface *oi; 189 int next_state = NSM_TwoWay; 190 191 oi = nbr->oi; 192 193 /* These netowork types must be adjacency. */ 194 if (oi->type == OSPF_IFTYPE_POINTOPOINT || 195 oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || 196 oi->type == OSPF_IFTYPE_VIRTUALLINK) 197 next_state = NSM_ExStart; 198 199 /* Router itself is the DRouter or the BDRouter. */ 200 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) || 201 IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))) 202 next_state = NSM_ExStart; 203 204 /* Neighboring Router is the DRouter or the BDRouter. */ 205 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router) || 206 IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router)) 207 next_state = NSM_ExStart; 208 209 return next_state; 210} 211 212int 213ospf_db_summary_count (struct ospf_neighbor *nbr) 214{ 215 return ospf_lsdb_count_all (&nbr->db_sum); 216} 217 218int 219ospf_db_summary_isempty (struct ospf_neighbor *nbr) 220{ 221 return ospf_lsdb_isempty (&nbr->db_sum); 222} 223 224int 225ospf_db_summary_add (struct ospf_lsa *lsa, void *v, int i) 226{ 227 struct ospf_neighbor *nbr = (struct ospf_neighbor *) v; 228 229 if (lsa == NULL) 230 return 0; 231 232#ifdef HAVE_NSSA 233 /* Stay away from any Local Translated Type-7 LSAs */ 234 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) 235 return 0; 236#endif /* HAVE_NSSA */ 237 238 if (IS_LSA_MAXAGE (lsa)) 239 ospf_ls_retransmit_add (nbr, lsa); 240 else 241 ospf_lsdb_add (&nbr->db_sum, lsa); 242 243 return 0; 244} 245 246void 247ospf_db_summary_clear (struct ospf_neighbor *nbr) 248{ 249 struct ospf_lsdb *lsdb; 250 int i; 251 252 lsdb = &nbr->db_sum; 253 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) 254 { 255 struct route_table *table = lsdb->type[i].db; 256 struct route_node *rn; 257 258 for (rn = route_top (table); rn; rn = route_next (rn)) 259 if (rn->info) 260 ospf_lsdb_delete (&nbr->db_sum, rn->info); 261 } 262} 263 264 265 266#ifdef HAVE_OPAQUE_LSA 267/* The area link state database consists of the router-LSAs, 268 network-LSAs, summary-LSAs, and type-9/10 opaque-LSAs contained 269 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 270 in the area structure, along with the AS-external and type-11 271 ^^^^^^^^^^^ 272 opaque LSAs contained in the global structure. 273 ^^^^^^ 274 AS-external and type-11 opaque LSAs are omitted from a virtual 275 ^^^^^^^^^^^^^^^^^^ 276 neighbor's Database summary list. AS-external and type-11 opaque 277 ^^^^^^^^^^^^^^^^^^ 278 LSAs are omitted from the Database summary list if the area has 279 been configured as a stub. */ 280#else /* HAVE_OPAQUE_LSA */ 281/* The area link state database consists of the router-LSAs, 282 network-LSAs and summary-LSAs contained in the area structure, 283 along with the AS-external- LSAs contained in the global structure. 284 AS- external-LSAs are omitted from a virtual neighbor's Database 285 summary list. AS-external-LSAs are omitted from the Database 286 summary list if the area has been configured as a stub. */ 287#endif /* HAVE_OPAQUE_LSA */ 288int 289nsm_negotiation_done (struct ospf_neighbor *nbr) 290{ 291 struct ospf_area *area; 292 293 area = nbr->oi->area; 294 295 foreach_lsa (ROUTER_LSDB (area), nbr, 0, ospf_db_summary_add); 296 foreach_lsa (NETWORK_LSDB (area), nbr, 0, ospf_db_summary_add); 297 foreach_lsa (SUMMARY_LSDB (area), nbr, 0, ospf_db_summary_add); 298 foreach_lsa (ASBR_SUMMARY_LSDB (area), nbr, 0, ospf_db_summary_add); 299 300#ifdef HAVE_OPAQUE_LSA 301 /* Process only if the neighbor is opaque capable. */ 302 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) 303 { 304 foreach_lsa (OPAQUE_LINK_LSDB (area), nbr, 0, ospf_db_summary_add); 305 foreach_lsa (OPAQUE_AREA_LSDB (area), nbr, 0, ospf_db_summary_add); 306 } 307#endif /* HAVE_OPAQUE_LSA */ 308 309 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && 310 area->external_routing == OSPF_AREA_DEFAULT) 311 foreach_lsa (EXTERNAL_LSDB (ospf_top), nbr, 0, ospf_db_summary_add); 312 313#ifdef HAVE_OPAQUE_LSA 314 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) && 315 (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && 316 area->external_routing == OSPF_AREA_DEFAULT)) 317 foreach_lsa (OPAQUE_AS_LSDB (ospf_top), 318 nbr, 0, ospf_db_summary_add); 319#endif /* HAVE_OPAQUE_LSA */ 320 321 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */ 322 323 return 0; 324} 325 326int 327nsm_exchange_done (struct ospf_neighbor *nbr) 328{ 329 struct ospf_interface *oi; 330 331 oi = nbr->oi; 332 333 if (ospf_ls_request_isempty (nbr)) 334 return NSM_Full; 335 336 /* Cancel dd retransmit timer. */ 337 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */ 338 339 /* Send Link State Request. */ 340 ospf_ls_req_send (nbr); 341 342 return NSM_Loading; 343} 344 345int 346nsm_bad_ls_req (struct ospf_neighbor *nbr) 347{ 348 /* Clear neighbor. */ 349 nsm_reset_nbr (nbr); 350 351 return 0; 352} 353 354int 355nsm_adj_ok (struct ospf_neighbor *nbr) 356{ 357 struct ospf_interface *oi; 358 int next_state; 359 int flag = 0; 360 361 oi = nbr->oi; 362 next_state = nbr->state; 363 364 /* These netowork types must be adjacency. */ 365 if (oi->type == OSPF_IFTYPE_POINTOPOINT || 366 oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || 367 oi->type == OSPF_IFTYPE_VIRTUALLINK) 368 flag = 1; 369 370 /* Router itself is the DRouter or the BDRouter. */ 371 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) || 372 IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))) 373 flag = 1; 374 375 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi)) || 376 IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi))) 377 flag = 1; 378 379 if (nbr->state == NSM_TwoWay && flag == 1) 380 next_state = NSM_ExStart; 381 else if (nbr->state >= NSM_ExStart && flag == 0) 382 next_state = NSM_TwoWay; 383 384 return next_state; 385} 386 387int 388nsm_seq_number_mismatch (struct ospf_neighbor *nbr) 389{ 390 /* Clear neighbor. */ 391 nsm_reset_nbr (nbr); 392 393 return 0; 394} 395 396int 397nsm_oneway_received (struct ospf_neighbor *nbr) 398{ 399 /* Clear neighbor. */ 400 nsm_reset_nbr (nbr); 401 402 return 0; 403} 404 405void 406nsm_reset_nbr (struct ospf_neighbor *nbr) 407{ 408 /* Clear Database Summary list. */ 409 if (!ospf_db_summary_isempty (nbr)) 410 ospf_db_summary_clear (nbr); 411 412 /* Clear Link State Request list. */ 413 if (!ospf_ls_request_isempty (nbr)) 414 ospf_ls_request_delete_all (nbr); 415 416 /* Clear Link State Retransmission list. */ 417 if (!ospf_ls_retransmit_isempty (nbr)) 418 ospf_ls_retransmit_clear (nbr); 419 420 /* Cancel thread. */ 421 OSPF_NSM_TIMER_OFF (nbr->t_db_desc); 422 OSPF_NSM_TIMER_OFF (nbr->t_ls_req); 423 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); 424 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply); 425 426#ifdef HAVE_OPAQUE_LSA 427 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) 428 UNSET_FLAG (nbr->options, OSPF_OPTION_O); 429#endif /* HAVE_OPAQUE_LSA */ 430} 431 432int 433nsm_kill_nbr (struct ospf_neighbor *nbr) 434{ 435 /* call it here because we cannot call it from ospf_nsm_event */ 436 nsm_change_state (nbr, NSM_Down); 437 438 /* Reset neighbor. */ 439 nsm_reset_nbr (nbr); 440 441 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) 442 { 443 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma; 444 445 nbr_nbma->nbr = NULL; 446 nbr_nbma->state_change = nbr->state_change; 447 448 nbr->nbr_nbma = NULL; 449 450 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, 451 nbr_nbma->v_poll); 452 453 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) 454 zlog_info ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)", 455 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4)); 456 } 457 458 /* Delete neighbor from interface. */ 459 ospf_nbr_delete (nbr); 460 461 return 0; 462} 463 464int 465nsm_inactivity_timer (struct ospf_neighbor *nbr) 466{ 467 /* Kill neighbor. */ 468 nsm_kill_nbr (nbr); 469 470 return 0; 471} 472 473int 474nsm_ll_down (struct ospf_neighbor *nbr) 475{ 476 /* Reset neighbor. */ 477 /*nsm_reset_nbr (nbr);*/ 478 479 /* Kill neighbor. */ 480 nsm_kill_nbr (nbr); 481 482 return 0; 483} 484 485/* Neighbor State Machine */ 486struct { 487 int (*func) (); 488 int next_state; 489} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = 490{ 491 { 492 /* DependUpon: dummy state. */ 493 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 494 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */ 495 { nsm_ignore, NSM_DependUpon }, /* Start */ 496 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */ 497 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */ 498 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */ 499 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */ 500 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */ 501 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */ 502 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */ 503 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */ 504 { nsm_ignore, NSM_DependUpon }, /* KillNbr */ 505 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */ 506 { nsm_ignore, NSM_DependUpon }, /* LLDown */ 507 }, 508 { 509 /* Down: */ 510 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 511 { nsm_hello_received, NSM_Init }, /* HelloReceived */ 512 { nsm_start, NSM_Attempt }, /* Start */ 513 { nsm_ignore, NSM_Down }, /* 2-WayReceived */ 514 { nsm_ignore, NSM_Down }, /* NegotiationDone */ 515 { nsm_ignore, NSM_Down }, /* ExchangeDone */ 516 { nsm_ignore, NSM_Down }, /* BadLSReq */ 517 { nsm_ignore, NSM_Down }, /* LoadingDone */ 518 { nsm_ignore, NSM_Down }, /* AdjOK? */ 519 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */ 520 { nsm_ignore, NSM_Down }, /* 1-WayReceived */ 521 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 522 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 523 { nsm_ll_down, NSM_Down }, /* LLDown */ 524 }, 525 { 526 /* Attempt: */ 527 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 528 { nsm_hello_received, NSM_Init }, /* HelloReceived */ 529 { nsm_ignore, NSM_Attempt }, /* Start */ 530 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */ 531 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */ 532 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */ 533 { nsm_ignore, NSM_Attempt }, /* BadLSReq */ 534 { nsm_ignore, NSM_Attempt }, /* LoadingDone */ 535 { nsm_ignore, NSM_Attempt }, /* AdjOK? */ 536 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */ 537 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */ 538 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 539 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 540 { nsm_ll_down, NSM_Down }, /* LLDown */ 541 }, 542 { 543 /* Init: */ 544 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 545 { nsm_hello_received, NSM_Init }, /* HelloReceived */ 546 { nsm_ignore, NSM_Init }, /* Start */ 547 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */ 548 { nsm_ignore, NSM_Init }, /* NegotiationDone */ 549 { nsm_ignore, NSM_Init }, /* ExchangeDone */ 550 { nsm_ignore, NSM_Init }, /* BadLSReq */ 551 { nsm_ignore, NSM_Init }, /* LoadingDone */ 552 { nsm_ignore, NSM_Init }, /* AdjOK? */ 553 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */ 554 { nsm_ignore, NSM_Init }, /* 1-WayReceived */ 555 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 556 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 557 { nsm_ll_down, NSM_Down }, /* LLDown */ 558 }, 559 { 560 /* 2-Way: */ 561 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 562 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */ 563 { nsm_ignore, NSM_TwoWay }, /* Start */ 564 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */ 565 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */ 566 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */ 567 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */ 568 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */ 569 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ 570 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */ 571 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ 572 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 573 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 574 { nsm_ll_down, NSM_Down }, /* LLDown */ 575 }, 576 { 577 /* ExStart: */ 578 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 579 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */ 580 { nsm_ignore, NSM_ExStart }, /* Start */ 581 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */ 582 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */ 583 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */ 584 { nsm_ignore, NSM_ExStart }, /* BadLSReq */ 585 { nsm_ignore, NSM_ExStart }, /* LoadingDone */ 586 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ 587 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */ 588 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ 589 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 590 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 591 { nsm_ll_down, NSM_Down }, /* LLDown */ 592 }, 593 { 594 /* Exchange: */ 595 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 596 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */ 597 { nsm_ignore, NSM_Exchange }, /* Start */ 598 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */ 599 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */ 600 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */ 601 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */ 602 { nsm_ignore, NSM_Exchange }, /* LoadingDone */ 603 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ 604 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */ 605 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ 606 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 607 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 608 { nsm_ll_down, NSM_Down }, /* LLDown */ 609 }, 610 { 611 /* Loading: */ 612 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 613 { nsm_hello_received, NSM_Loading }, /* HelloReceived */ 614 { nsm_ignore, NSM_Loading }, /* Start */ 615 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */ 616 { nsm_ignore, NSM_Loading }, /* NegotiationDone */ 617 { nsm_ignore, NSM_Loading }, /* ExchangeDone */ 618 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */ 619 { nsm_ignore, NSM_Full }, /* LoadingDone */ 620 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ 621 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */ 622 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ 623 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 624 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 625 { nsm_ll_down, NSM_Down }, /* LLDown */ 626 }, 627 { /* Full: */ 628 { nsm_ignore, NSM_DependUpon }, /* NoEvent */ 629 { nsm_hello_received, NSM_Full }, /* HelloReceived */ 630 { nsm_ignore, NSM_Full }, /* Start */ 631 { nsm_ignore, NSM_Full }, /* 2-WayReceived */ 632 { nsm_ignore, NSM_Full }, /* NegotiationDone */ 633 { nsm_ignore, NSM_Full }, /* ExchangeDone */ 634 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */ 635 { nsm_ignore, NSM_Full }, /* LoadingDone */ 636 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ 637 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */ 638 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ 639 { nsm_kill_nbr, NSM_Down }, /* KillNbr */ 640 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ 641 { nsm_ll_down, NSM_Down }, /* LLDown */ 642 }, 643}; 644 645static char *ospf_nsm_event_str[] = 646{ 647 "NoEvent", 648 "HelloReceived", 649 "Start", 650 "2-WayReceived", 651 "NegotiationDone", 652 "ExchangeDone", 653 "BadLSReq", 654 "LoadingDone", 655 "AdjOK?", 656 "SeqNumberMismatch", 657 "1-WayReceived", 658 "KillNbr", 659 "InactivityTimer", 660 "LLDown", 661}; 662 663void 664nsm_change_state (struct ospf_neighbor *nbr, int state) 665{ 666 struct ospf_interface *oi; 667 struct ospf_area *vl_area = NULL; 668 u_char old_state; 669 670 /* Logging change of status. */ 671 if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) 672 zlog_info ("NSM[%s:%s]: State change %s -> %s", 673 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), 674 LOOKUP (ospf_nsm_state_msg, nbr->state), 675 LOOKUP (ospf_nsm_state_msg, state)); 676 677 /* Preserve old status. */ 678 old_state = nbr->state; 679 680 /* Change to new status. */ 681 nbr->state = state; 682 683 /* Statistics. */ 684 nbr->state_change++; 685 686 oi = nbr->oi; 687 688 if (oi->type == OSPF_IFTYPE_VIRTUALLINK) 689 vl_area = ospf_area_lookup_by_area_id (oi->vl_data->vl_area_id); 690 691 /* One of the neighboring routers changes to/from the FULL state. */ 692 if ((old_state != NSM_Full && state == NSM_Full) || 693 (old_state == NSM_Full && state != NSM_Full)) 694 { 695 if (state == NSM_Full) 696 { 697 oi->full_nbrs++; 698 oi->area->full_nbrs++; 699 700 ospf_check_abr_status (); 701 702 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) 703 if (++vl_area->full_vls == 1) 704 ospf_schedule_abr_task (); 705 } 706 else 707 { 708 oi->full_nbrs--; 709 oi->area->full_nbrs--; 710 711 ospf_check_abr_status (); 712 713 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) 714 if (vl_area->full_vls > 0) 715 if (--vl_area->full_vls == 0) 716 ospf_schedule_abr_task (); 717 718 /* clear neighbor retransmit list */ 719 if (!ospf_ls_retransmit_isempty (nbr)) 720 ospf_ls_retransmit_clear (nbr); 721 } 722 723 zlog_info ("nsm_change_state(): " 724 "scheduling new router-LSA origination"); 725 726 ospf_router_lsa_timer_add (oi->area); 727 728 if (oi->type == OSPF_IFTYPE_VIRTUALLINK) 729 { 730 struct ospf_area *vl_area = 731 ospf_area_lookup_by_area_id (oi->vl_data->vl_area_id); 732 733 if (vl_area) 734 ospf_router_lsa_timer_add (vl_area); 735 } 736 737 /* Originate network-LSA. */ 738 if (oi->state == ISM_DR) 739 { 740 if (oi->network_lsa_self && oi->full_nbrs == 0) 741 { 742 ospf_lsa_flush_area (oi->network_lsa_self, oi->area); 743 ospf_lsa_unlock (oi->network_lsa_self); 744 oi->network_lsa_self = NULL; 745 OSPF_TIMER_OFF (oi->t_network_lsa_self); 746 } 747 else 748 ospf_network_lsa_timer_add (oi); 749 } 750 } 751 752#ifdef HAVE_OPAQUE_LSA 753 ospf_opaque_nsm_change (nbr, old_state); 754#endif /* HAVE_OPAQUE_LSA */ 755 756 /* Start DD exchange protocol */ 757 if (state == NSM_ExStart) 758 { 759 if (nbr->dd_seqnum == 0) 760 nbr->dd_seqnum = time (NULL); 761 else 762 nbr->dd_seqnum++; 763 764 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS; 765 ospf_db_desc_send (nbr); 766 } 767 768 /* clear cryptographic sequence number */ 769 if (state == NSM_Down) 770 nbr->crypt_seqnum = 0; 771 772 /* Generete NeighborChange ISM event. */ 773 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) || 774 (old_state >= NSM_TwoWay && state < NSM_TwoWay)) 775 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange); 776 777 /* Performance hack. Send hello immideately when some neighbor enter 778 Init state. This whay we decrease neighbor discovery time. Gleb.*/ 779 if (state == NSM_Init) 780 { 781 OSPF_ISM_TIMER_OFF (oi->t_hello); 782 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1); 783 } 784 785 /* Preserve old status? */ 786} 787 788/* Execute NSM event process. */ 789int 790ospf_nsm_event (struct thread *thread) 791{ 792 int event; 793 int next_state; 794 struct ospf_neighbor *nbr; 795 struct in_addr router_id; 796 int old_state; 797 struct ospf_interface *oi; 798 799 nbr = THREAD_ARG (thread); 800 event = THREAD_VAL (thread); 801 router_id = nbr->router_id; 802 803 old_state = nbr->state; 804 oi = nbr->oi ; 805 806 /* Call function. */ 807 next_state = (*(NSM [nbr->state][event].func))(nbr); 808 809 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is 810 deleted. */ 811 if (event == NSM_KillNbr || event == NSM_InactivityTimer) 812 { 813 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) 814 zlog_info ("NSM[%s:%s]: neighbor deleted", 815 IF_NAME (oi), inet_ntoa (router_id)); 816 817 /* Timers are canceled in ospf_nbr_free, moreover we cannot call 818 nsm_timer_set here because nbr is freed already!!!*/ 819 /*nsm_timer_set (nbr);*/ 820 821 return 0; 822 } 823 824 if (! next_state) 825 next_state = NSM [nbr->state][event].next_state; 826 827 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) 828 zlog_info ("NSM[%s:%s]: %s (%s)", IF_NAME (oi), 829 inet_ntoa (nbr->router_id), 830 LOOKUP (ospf_nsm_state_msg, nbr->state), 831 ospf_nsm_event_str [event]); 832 833 /* If state is changed. */ 834 if (next_state != nbr->state) 835 nsm_change_state (nbr, next_state); 836 837 /* Make sure timer is set. */ 838 nsm_timer_set (nbr); 839 840 return 0; 841} 842 843/* Check loading state. */ 844void 845ospf_check_nbr_loading (struct ospf_neighbor *nbr) 846{ 847 if (nbr->state == NSM_Loading) 848 { 849 if (ospf_ls_request_isempty (nbr)) 850 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone); 851 else if (nbr->ls_req_last == NULL) 852 ospf_ls_req_event (nbr); 853 } 854} 855