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