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