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