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