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