]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_nsm.c
Merge pull request #8637 from opensourcerouting/pim-vrf-acl-fixes
[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 LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
302 ospf_db_summary_add(nbr, lsa);
303
304 /* Process only if the neighbor is opaque capable. */
305 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
306 LSDB_LOOP (OPAQUE_LINK_LSDB(area), rn, lsa)
307 ospf_db_summary_add(nbr, lsa);
308 LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa)
309 ospf_db_summary_add(nbr, lsa);
310 }
311
312 if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) {
313 LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
314 ospf_db_summary_add(nbr, lsa);
315 }
316
317 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
318 && area->external_routing == OSPF_AREA_DEFAULT)
319 LSDB_LOOP (EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa)
320 ospf_db_summary_add(nbr, lsa);
321
322 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)
323 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
324 && area->external_routing == OSPF_AREA_DEFAULT))
325 LSDB_LOOP (OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa)
326 ospf_db_summary_add(nbr, lsa);
327
328 return 0;
329 }
330
331 static int nsm_exchange_done(struct ospf_neighbor *nbr)
332 {
333 if (ospf_ls_request_isempty(nbr))
334 return NSM_Full;
335
336 /* Send Link State Request. */
337 if (nbr->t_ls_req == NULL)
338 ospf_ls_req_send(nbr);
339
340 return NSM_Loading;
341 }
342
343 static int nsm_adj_ok(struct ospf_neighbor *nbr)
344 {
345 int next_state = nbr->state;
346 int adj = nsm_should_adj(nbr);
347
348 if (nbr->state == NSM_TwoWay && adj == 1) {
349 next_state = NSM_ExStart;
350
351 /* Send proactive ARP requests */
352 ospf_proactively_arp(nbr);
353 } else if (nbr->state >= NSM_ExStart && adj == 0)
354 next_state = NSM_TwoWay;
355
356 return next_state;
357 }
358
359 /* Clear adjacency related state for a neighbour, intended where nbr
360 * transitions from > ExStart (i.e. a Full or forming adjacency)
361 * to <= ExStart.
362 */
363 static void nsm_clear_adj(struct ospf_neighbor *nbr)
364 {
365 /* Clear Database Summary list. */
366 if (!ospf_db_summary_isempty(nbr))
367 ospf_db_summary_clear(nbr);
368
369 /* Clear Link State Request list. */
370 if (!ospf_ls_request_isempty(nbr))
371 ospf_ls_request_delete_all(nbr);
372
373 /* Clear Link State Retransmission list. */
374 if (!ospf_ls_retransmit_isempty(nbr))
375 ospf_ls_retransmit_clear(nbr);
376
377 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O))
378 UNSET_FLAG(nbr->options, OSPF_OPTION_O);
379 }
380
381 static int nsm_kill_nbr(struct ospf_neighbor *nbr)
382 {
383 /* killing nbr_self is invalid */
384 if (nbr == nbr->oi->nbr_self) {
385 assert(nbr != nbr->oi->nbr_self);
386 return 0;
387 }
388
389 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) {
390 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
391
392 nbr_nbma->nbr = NULL;
393 nbr_nbma->state_change = nbr->state_change;
394
395 nbr->nbr_nbma = NULL;
396
397 OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer,
398 nbr_nbma->v_poll);
399
400 if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
401 zlog_debug(
402 "NSM[%s:%pI4:%s]: Down (PollIntervalTimer scheduled)",
403 IF_NAME(nbr->oi),
404 &nbr->address.u.prefix4,
405 ospf_get_name(nbr->oi->ospf));
406 }
407
408 return 0;
409 }
410
411 /* Neighbor State Machine */
412 const struct {
413 int (*func)(struct ospf_neighbor *);
414 int next_state;
415 } NSM[OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = {
416 {
417 /* DependUpon: dummy state. */
418 {NULL, NSM_DependUpon}, /* NoEvent */
419 {NULL, NSM_DependUpon}, /* PacketReceived */
420 {NULL, NSM_DependUpon}, /* Start */
421 {NULL, NSM_DependUpon}, /* 2-WayReceived */
422 {NULL, NSM_DependUpon}, /* NegotiationDone */
423 {NULL, NSM_DependUpon}, /* ExchangeDone */
424 {NULL, NSM_DependUpon}, /* BadLSReq */
425 {NULL, NSM_DependUpon}, /* LoadingDone */
426 {NULL, NSM_DependUpon}, /* AdjOK? */
427 {NULL, NSM_DependUpon}, /* SeqNumberMismatch */
428 {NULL, NSM_DependUpon}, /* 1-WayReceived */
429 {NULL, NSM_DependUpon}, /* KillNbr */
430 {NULL, NSM_DependUpon}, /* InactivityTimer */
431 {NULL, NSM_DependUpon}, /* LLDown */
432 },
433 {
434 /* Deleted: dummy state. */
435 {NULL, NSM_Deleted}, /* NoEvent */
436 {NULL, NSM_Deleted}, /* PacketReceived */
437 {NULL, NSM_Deleted}, /* Start */
438 {NULL, NSM_Deleted}, /* 2-WayReceived */
439 {NULL, NSM_Deleted}, /* NegotiationDone */
440 {NULL, NSM_Deleted}, /* ExchangeDone */
441 {NULL, NSM_Deleted}, /* BadLSReq */
442 {NULL, NSM_Deleted}, /* LoadingDone */
443 {NULL, NSM_Deleted}, /* AdjOK? */
444 {NULL, NSM_Deleted}, /* SeqNumberMismatch */
445 {NULL, NSM_Deleted}, /* 1-WayReceived */
446 {NULL, NSM_Deleted}, /* KillNbr */
447 {NULL, NSM_Deleted}, /* InactivityTimer */
448 {NULL, NSM_Deleted}, /* LLDown */
449 },
450 {
451 /* Down: */
452 {NULL, NSM_DependUpon}, /* NoEvent */
453 {nsm_packet_received, NSM_Init}, /* PacketReceived */
454 {nsm_start, NSM_Attempt}, /* Start */
455 {NULL, NSM_Down}, /* 2-WayReceived */
456 {NULL, NSM_Down}, /* NegotiationDone */
457 {NULL, NSM_Down}, /* ExchangeDone */
458 {NULL, NSM_Down}, /* BadLSReq */
459 {NULL, NSM_Down}, /* LoadingDone */
460 {NULL, NSM_Down}, /* AdjOK? */
461 {NULL, NSM_Down}, /* SeqNumberMismatch */
462 {NULL, NSM_Down}, /* 1-WayReceived */
463 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
464 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
465 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
466 },
467 {
468 /* Attempt: */
469 {NULL, NSM_DependUpon}, /* NoEvent */
470 {nsm_packet_received, NSM_Init}, /* PacketReceived */
471 {NULL, NSM_Attempt}, /* Start */
472 {NULL, NSM_Attempt}, /* 2-WayReceived */
473 {NULL, NSM_Attempt}, /* NegotiationDone */
474 {NULL, NSM_Attempt}, /* ExchangeDone */
475 {NULL, NSM_Attempt}, /* BadLSReq */
476 {NULL, NSM_Attempt}, /* LoadingDone */
477 {NULL, NSM_Attempt}, /* AdjOK? */
478 {NULL, NSM_Attempt}, /* SeqNumberMismatch */
479 {NULL, NSM_Attempt}, /* 1-WayReceived */
480 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
481 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
482 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
483 },
484 {
485 /* Init: */
486 {NULL, NSM_DependUpon}, /* NoEvent */
487 {nsm_packet_received, NSM_Init}, /* PacketReceived */
488 {NULL, NSM_Init}, /* Start */
489 {nsm_twoway_received, NSM_DependUpon}, /* 2-WayReceived */
490 {NULL, NSM_Init}, /* NegotiationDone */
491 {NULL, NSM_Init}, /* ExchangeDone */
492 {NULL, NSM_Init}, /* BadLSReq */
493 {NULL, NSM_Init}, /* LoadingDone */
494 {NULL, NSM_Init}, /* AdjOK? */
495 {NULL, NSM_Init}, /* SeqNumberMismatch */
496 {NULL, NSM_Init}, /* 1-WayReceived */
497 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
498 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
499 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
500 },
501 {
502 /* 2-Way: */
503 {NULL, NSM_DependUpon}, /* NoEvent */
504 {nsm_packet_received, NSM_TwoWay}, /* HelloReceived */
505 {NULL, NSM_TwoWay}, /* Start */
506 {NULL, NSM_TwoWay}, /* 2-WayReceived */
507 {NULL, NSM_TwoWay}, /* NegotiationDone */
508 {NULL, NSM_TwoWay}, /* ExchangeDone */
509 {NULL, NSM_TwoWay}, /* BadLSReq */
510 {NULL, NSM_TwoWay}, /* LoadingDone */
511 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
512 {NULL, NSM_TwoWay}, /* SeqNumberMismatch */
513 {NULL, NSM_Init}, /* 1-WayReceived */
514 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
515 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
516 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
517 },
518 {
519 /* ExStart: */
520 {NULL, NSM_DependUpon}, /* NoEvent */
521 {nsm_packet_received, NSM_ExStart}, /* PacaketReceived */
522 {NULL, NSM_ExStart}, /* Start */
523 {NULL, NSM_ExStart}, /* 2-WayReceived */
524 {nsm_negotiation_done, NSM_Exchange}, /* NegotiationDone */
525 {NULL, NSM_ExStart}, /* ExchangeDone */
526 {NULL, NSM_ExStart}, /* BadLSReq */
527 {NULL, NSM_ExStart}, /* LoadingDone */
528 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
529 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
530 {NULL, NSM_Init}, /* 1-WayReceived */
531 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
532 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
533 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
534 },
535 {
536 /* Exchange: */
537 {NULL, NSM_DependUpon}, /* NoEvent */
538 {nsm_packet_received, NSM_Exchange}, /* PacketReceived */
539 {NULL, NSM_Exchange}, /* Start */
540 {NULL, NSM_Exchange}, /* 2-WayReceived */
541 {NULL, NSM_Exchange}, /* NegotiationDone */
542 {nsm_exchange_done, NSM_DependUpon}, /* ExchangeDone */
543 {NULL, NSM_ExStart}, /* BadLSReq */
544 {NULL, NSM_Exchange}, /* LoadingDone */
545 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
546 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
547 {NULL, NSM_Init}, /* 1-WayReceived */
548 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
549 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
550 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
551 },
552 {
553 /* Loading: */
554 {NULL, NSM_DependUpon}, /* NoEvent */
555 {nsm_packet_received, NSM_Loading}, /* PacketReceived */
556 {NULL, NSM_Loading}, /* Start */
557 {NULL, NSM_Loading}, /* 2-WayReceived */
558 {NULL, NSM_Loading}, /* NegotiationDone */
559 {NULL, NSM_Loading}, /* ExchangeDone */
560 {NULL, NSM_ExStart}, /* BadLSReq */
561 {NULL, NSM_Full}, /* LoadingDone */
562 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
563 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
564 {NULL, NSM_Init}, /* 1-WayReceived */
565 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
566 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
567 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
568 },
569 {
570 /* Full: */
571 {NULL, NSM_DependUpon}, /* NoEvent */
572 {nsm_packet_received, NSM_Full}, /* PacketReceived */
573 {NULL, NSM_Full}, /* Start */
574 {NULL, NSM_Full}, /* 2-WayReceived */
575 {NULL, NSM_Full}, /* NegotiationDone */
576 {NULL, NSM_Full}, /* ExchangeDone */
577 {NULL, NSM_ExStart}, /* BadLSReq */
578 {NULL, NSM_Full}, /* LoadingDone */
579 {nsm_adj_ok, NSM_DependUpon}, /* AdjOK? */
580 {NULL, NSM_ExStart}, /* SeqNumberMismatch */
581 {NULL, NSM_Init}, /* 1-WayReceived */
582 {nsm_kill_nbr, NSM_Deleted}, /* KillNbr */
583 {nsm_kill_nbr, NSM_Deleted}, /* InactivityTimer */
584 {nsm_kill_nbr, NSM_Deleted}, /* LLDown */
585 },
586 };
587
588 static const char *const ospf_nsm_event_str[] = {
589 "NoEvent", "PacketReceived", "Start",
590 "2-WayReceived", "NegotiationDone", "ExchangeDone",
591 "BadLSReq", "LoadingDone", "AdjOK?",
592 "SeqNumberMismatch", "1-WayReceived", "KillNbr",
593 "InactivityTimer", "LLDown",
594 };
595
596 static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state,
597 int event)
598 {
599 /* Logging change of status. */
600 if (IS_DEBUG_OSPF(nsm, NSM_STATUS))
601 zlog_debug("NSM[%s:%pI4:%s]: State change %s -> %s (%s)",
602 IF_NAME(nbr->oi), &nbr->router_id,
603 ospf_get_name(nbr->oi->ospf),
604 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
605 lookup_msg(ospf_nsm_state_msg, next_state, NULL),
606 ospf_nsm_event_str[event]);
607
608 /* Optionally notify about adjacency changes */
609 if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES)
610 && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)
611 || (next_state == NSM_Full) || (next_state < nbr->state)))
612 zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
613 &nbr->router_id,
614 ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi),
615 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
616 lookup_msg(ospf_nsm_state_msg, next_state, NULL),
617 ospf_nsm_event_str[event]);
618
619 /* Advance in NSM */
620 if (next_state > nbr->state)
621 monotime(&nbr->ts_last_progress);
622 else /* regression in NSM */
623 {
624 monotime(&nbr->ts_last_regress);
625 nbr->last_regress_str = ospf_nsm_event_str[event];
626 }
627 }
628
629 static void nsm_change_state(struct ospf_neighbor *nbr, int state)
630 {
631 struct ospf_interface *oi = nbr->oi;
632 struct ospf_area *vl_area = NULL;
633 uint8_t old_state;
634
635 /* Preserve old status. */
636 old_state = nbr->state;
637
638 /* Change to new status. */
639 nbr->state = state;
640
641 /* Statistics. */
642 nbr->state_change++;
643
644 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
645 vl_area = ospf_area_lookup_by_area_id(oi->ospf,
646 oi->vl_data->vl_area_id);
647
648 /* Generate NeighborChange ISM event.
649 *
650 * In response to NeighborChange, DR election is rerun. The information
651 * from the election process is required by the router-lsa construction.
652 *
653 * Therefore, trigger the event prior to refreshing the LSAs. */
654 switch (oi->state) {
655 case ISM_DROther:
656 case ISM_Backup:
657 case ISM_DR:
658 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay)
659 || (old_state >= NSM_TwoWay && state < NSM_TwoWay))
660 OSPF_ISM_EVENT_EXECUTE(oi, ISM_NeighborChange);
661 break;
662 default:
663 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc.
664 */
665 break;
666 }
667
668 /* One of the neighboring routers changes to/from the FULL state. */
669 if ((old_state != NSM_Full && state == NSM_Full)
670 || (old_state == NSM_Full && state != NSM_Full)) {
671 if (state == NSM_Full) {
672 oi->full_nbrs++;
673 oi->area->full_nbrs++;
674
675 ospf_check_abr_status(oi->ospf);
676
677 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
678 if (++vl_area->full_vls == 1)
679 ospf_schedule_abr_task(oi->ospf);
680 } else {
681 oi->full_nbrs--;
682 oi->area->full_nbrs--;
683
684 ospf_check_abr_status(oi->ospf);
685
686 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
687 if (vl_area->full_vls > 0)
688 if (--vl_area->full_vls == 0)
689 ospf_schedule_abr_task(
690 oi->ospf);
691 }
692
693 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
694 zlog_info(
695 "%s:[%pI4:%s], %s -> %s): scheduling new router-LSA origination",
696 __func__, &nbr->router_id,
697 ospf_get_name(oi->ospf),
698 lookup_msg(ospf_nsm_state_msg, old_state, NULL),
699 lookup_msg(ospf_nsm_state_msg, state, NULL));
700
701 /* Dont originate router LSA if the current
702 * router is acting as a HELPER for this neighbour.
703 */
704 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
705 ospf_router_lsa_update_area(oi->area);
706
707 if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
708 vl_area = ospf_area_lookup_by_area_id(
709 oi->ospf, oi->vl_data->vl_area_id);
710
711 if (vl_area)
712 ospf_router_lsa_update_area(vl_area);
713 }
714
715 /* Dont originate/flush network LSA if the current
716 * router is acting as a HELPER for this neighbour.
717 */
718 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
719 /* Originate network-LSA. */
720 if (oi->state == ISM_DR) {
721 if (oi->network_lsa_self
722 && oi->full_nbrs == 0) {
723 ospf_lsa_flush_area(
724 oi->network_lsa_self, oi->area);
725 ospf_lsa_unlock(&oi->network_lsa_self);
726 oi->network_lsa_self = NULL;
727 } else
728 ospf_network_lsa_update(oi);
729 }
730 }
731
732 if (state == NSM_Full && oi->ospf->gr_info.restart_in_progress)
733 ospf_gr_check_adjs(oi->ospf);
734 }
735
736 ospf_opaque_nsm_change(nbr, old_state);
737
738 /* State changes from > ExStart to <= ExStart should clear any Exchange
739 * or Full/LSA Update related lists and state.
740 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
741 */
742 if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
743 nsm_clear_adj(nbr);
744
745 /* Start DD exchange protocol */
746 if (state == NSM_ExStart) {
747 if (nbr->dd_seqnum == 0)
748 nbr->dd_seqnum = (uint32_t)frr_weak_random();
749 else
750 nbr->dd_seqnum++;
751
752 nbr->dd_flags =
753 OSPF_DD_FLAG_I | OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS;
754 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
755 zlog_info(
756 "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x",
757 (oi->ospf->name) ? oi->ospf->name
758 : VRF_DEFAULT_NAME,
759 &nbr->router_id, nbr->dd_seqnum,
760 nbr->dd_flags);
761 ospf_db_desc_send(nbr);
762 }
763
764 /* clear cryptographic sequence number */
765 if (state == NSM_Down)
766 nbr->crypt_seqnum = 0;
767
768 if (nbr->bfd_session)
769 ospf_bfd_trigger_event(nbr, old_state, state);
770
771 /* Preserve old status? */
772 }
773
774 /* Execute NSM event process. */
775 int ospf_nsm_event(struct thread *thread)
776 {
777 int event;
778 int next_state;
779 struct ospf_neighbor *nbr;
780
781 nbr = THREAD_ARG(thread);
782 event = THREAD_VAL(thread);
783
784 if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
785 zlog_debug("NSM[%s:%pI4:%s]: %s (%s)", IF_NAME(nbr->oi),
786 &nbr->router_id,
787 ospf_get_name(nbr->oi->ospf),
788 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
789 ospf_nsm_event_str[event]);
790
791 next_state = NSM[nbr->state][event].next_state;
792
793 /* Call function. */
794 if (NSM[nbr->state][event].func != NULL) {
795 int func_state = (*(NSM[nbr->state][event].func))(nbr);
796
797 if (NSM[nbr->state][event].next_state == NSM_DependUpon)
798 next_state = func_state;
799 else if (func_state) {
800 /* There's a mismatch between the FSM tables and what an
801 * FSM
802 * action/state-change function returned. State changes
803 * which
804 * do not have conditional/DependUpon next-states should
805 * not
806 * try set next_state.
807 */
808 flog_err(
809 EC_OSPF_FSM_INVALID_STATE,
810 "NSM[%s:%pI4:%s]: %s (%s): Warning: action tried to change next_state to %s",
811 IF_NAME(nbr->oi), &nbr->router_id,
812 ospf_get_name(nbr->oi->ospf),
813 lookup_msg(ospf_nsm_state_msg, nbr->state,
814 NULL),
815 ospf_nsm_event_str[event],
816 lookup_msg(ospf_nsm_state_msg, func_state,
817 NULL));
818 }
819 }
820
821 assert(next_state != NSM_DependUpon);
822
823 /* If state is changed. */
824 if (next_state != nbr->state) {
825 int old_state = nbr->state;
826
827 nsm_notice_state_change(nbr, next_state, event);
828 nsm_change_state(nbr, next_state);
829
830 hook_call(ospf_nsm_change, nbr, next_state, old_state);
831 }
832
833 /* Make sure timer is set. */
834 nsm_timer_set(nbr);
835
836 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
837 * is deleted.
838 *
839 * Rather than encode knowledge here of which events lead to NBR
840 * delete, we take our cue from the NSM table, via the dummy
841 * 'Deleted' neighbour state.
842 */
843 if (nbr->state == NSM_Deleted)
844 ospf_nbr_delete(nbr);
845
846 return 0;
847 }
848
849 /* Check loading state. */
850 void ospf_check_nbr_loading(struct ospf_neighbor *nbr)
851 {
852 if (nbr->state == NSM_Loading) {
853 if (ospf_ls_request_isempty(nbr))
854 OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_LoadingDone);
855 else if (nbr->ls_req_last == NULL)
856 ospf_ls_req_event(nbr);
857 }
858 }