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