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