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