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