blob: ab91e8d88e0f09f31b6785a4acc7b5f70c110b03 [file] [log] [blame]
paul2d598362003-01-17 23:48:42 +00001/*
2 * OSPF version 2 Interface 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 "linklist.h"
28#include "prefix.h"
29#include "if.h"
30#include "table.h"
31#include "log.h"
32
33#include "ospfd/ospfd.h"
34#include "ospfd/ospf_interface.h"
35#include "ospfd/ospf_ism.h"
36#include "ospfd/ospf_asbr.h"
37#include "ospfd/ospf_lsa.h"
38#include "ospfd/ospf_lsdb.h"
39#include "ospfd/ospf_neighbor.h"
40#include "ospfd/ospf_nsm.h"
41#include "ospfd/ospf_network.h"
42#include "ospfd/ospf_dump.h"
43#include "ospfd/ospf_packet.h"
44#include "ospfd/ospf_flood.h"
45#include "ospfd/ospf_abr.h"
vincent5e4914c2005-09-29 16:34:30 +000046#include "ospfd/ospf_snmp.h"
paul2d598362003-01-17 23:48:42 +000047
48/* elect DR and BDR. Refer to RFC2319 section 9.4 */
paul4dadc292005-05-06 21:37:42 +000049static struct ospf_neighbor *
hasso52dc7ee2004-09-23 19:18:23 +000050ospf_dr_election_sub (struct list *routers)
paul2d598362003-01-17 23:48:42 +000051{
hasso52dc7ee2004-09-23 19:18:23 +000052 struct listnode *node;
paul2d598362003-01-17 23:48:42 +000053 struct ospf_neighbor *nbr, *max = NULL;
54
55 /* Choose highest router priority.
56 In case of tie, choose highest Router ID. */
paul1eb8ef22005-04-07 07:30:20 +000057 for (ALL_LIST_ELEMENTS_RO (routers, node, nbr))
paul2d598362003-01-17 23:48:42 +000058 {
paul2d598362003-01-17 23:48:42 +000059 if (max == NULL)
60 max = nbr;
61 else
62 {
63 if (max->priority < nbr->priority)
64 max = nbr;
65 else if (max->priority == nbr->priority)
66 if (IPV4_ADDR_CMP (&max->router_id, &nbr->router_id) < 0)
67 max = nbr;
68 }
69 }
70
71 return max;
72}
73
paul4dadc292005-05-06 21:37:42 +000074static struct ospf_neighbor *
hasso52dc7ee2004-09-23 19:18:23 +000075ospf_elect_dr (struct ospf_interface *oi, struct list *el_list)
paul2d598362003-01-17 23:48:42 +000076{
hasso52dc7ee2004-09-23 19:18:23 +000077 struct list *dr_list;
78 struct listnode *node;
paul2d598362003-01-17 23:48:42 +000079 struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL;
80
81 dr_list = list_new ();
82
83 /* Add neighbors to the list. */
paul1eb8ef22005-04-07 07:30:20 +000084 for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr))
paul2d598362003-01-17 23:48:42 +000085 {
paul2d598362003-01-17 23:48:42 +000086 /* neighbor declared to be DR. */
87 if (NBR_IS_DR (nbr))
88 listnode_add (dr_list, nbr);
89
90 /* Preserve neighbor BDR. */
91 if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4))
92 bdr = nbr;
93 }
94
95 /* Elect Designated Router. */
96 if (listcount (dr_list) > 0)
97 dr = ospf_dr_election_sub (dr_list);
98 else
99 dr = bdr;
100
101 /* Set DR to interface. */
102 if (dr)
paul7e440862005-06-01 11:20:51 +0000103 DR (oi) = dr->address.u.prefix4;
paul2d598362003-01-17 23:48:42 +0000104 else
paul7e440862005-06-01 11:20:51 +0000105 DR (oi).s_addr = 0;
paul2d598362003-01-17 23:48:42 +0000106
107 list_delete (dr_list);
108
109 return dr;
110}
111
paul4dadc292005-05-06 21:37:42 +0000112static struct ospf_neighbor *
hasso52dc7ee2004-09-23 19:18:23 +0000113ospf_elect_bdr (struct ospf_interface *oi, struct list *el_list)
paul2d598362003-01-17 23:48:42 +0000114{
hasso52dc7ee2004-09-23 19:18:23 +0000115 struct list *bdr_list, *no_dr_list;
116 struct listnode *node;
paul2d598362003-01-17 23:48:42 +0000117 struct ospf_neighbor *nbr, *bdr = NULL;
118
119 bdr_list = list_new ();
120 no_dr_list = list_new ();
121
122 /* Add neighbors to the list. */
paul1eb8ef22005-04-07 07:30:20 +0000123 for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr))
paul2d598362003-01-17 23:48:42 +0000124 {
paul2d598362003-01-17 23:48:42 +0000125 /* neighbor declared to be DR. */
126 if (NBR_IS_DR (nbr))
127 continue;
128
129 /* neighbor declared to be BDR. */
130 if (NBR_IS_BDR (nbr))
131 listnode_add (bdr_list, nbr);
132
133 listnode_add (no_dr_list, nbr);
134 }
135
136 /* Elect Backup Designated Router. */
137 if (listcount (bdr_list) > 0)
138 bdr = ospf_dr_election_sub (bdr_list);
139 else
140 bdr = ospf_dr_election_sub (no_dr_list);
141
142 /* Set BDR to interface. */
143 if (bdr)
paul7e440862005-06-01 11:20:51 +0000144 BDR (oi) = bdr->address.u.prefix4;
paul2d598362003-01-17 23:48:42 +0000145 else
146 BDR (oi).s_addr = 0;
147
148 list_delete (bdr_list);
149 list_delete (no_dr_list);
150
151 return bdr;
152}
153
paul4dadc292005-05-06 21:37:42 +0000154static int
paul2d598362003-01-17 23:48:42 +0000155ospf_ism_state (struct ospf_interface *oi)
156{
157 if (IPV4_ADDR_SAME (&DR (oi), &oi->address->u.prefix4))
158 return ISM_DR;
159 else if (IPV4_ADDR_SAME (&BDR (oi), &oi->address->u.prefix4))
160 return ISM_Backup;
161 else
162 return ISM_DROther;
163}
164
paul4dadc292005-05-06 21:37:42 +0000165static void
hasso52dc7ee2004-09-23 19:18:23 +0000166ospf_dr_eligible_routers (struct route_table *nbrs, struct list *el_list)
paul2d598362003-01-17 23:48:42 +0000167{
168 struct route_node *rn;
169 struct ospf_neighbor *nbr;
170
171 for (rn = route_top (nbrs); rn; rn = route_next (rn))
172 if ((nbr = rn->info) != NULL)
173 /* Ignore 0.0.0.0 node*/
174 if (nbr->router_id.s_addr != 0)
175 /* Is neighbor eligible? */
176 if (nbr->priority != 0)
177 /* Is neighbor upper 2-Way? */
178 if (nbr->state >= NSM_TwoWay)
179 listnode_add (el_list, nbr);
180}
181
182/* Generate AdjOK? NSM event. */
paul4dadc292005-05-06 21:37:42 +0000183static void
paul68980082003-03-25 05:07:42 +0000184ospf_dr_change (struct ospf *ospf, struct route_table *nbrs)
paul2d598362003-01-17 23:48:42 +0000185{
186 struct route_node *rn;
187 struct ospf_neighbor *nbr;
188
189 for (rn = route_top (nbrs); rn; rn = route_next (rn))
190 if ((nbr = rn->info) != NULL)
191 /* Ignore 0.0.0.0 node*/
192 if (nbr->router_id.s_addr != 0)
193 /* Is neighbor upper 2-Way? */
194 if (nbr->state >= NSM_TwoWay)
195 /* Ignore myself. */
paul68980082003-03-25 05:07:42 +0000196 if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf->router_id))
paul2d598362003-01-17 23:48:42 +0000197 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_AdjOK);
198}
199
paul4dadc292005-05-06 21:37:42 +0000200static int
paul2d598362003-01-17 23:48:42 +0000201ospf_dr_election (struct ospf_interface *oi)
202{
203 struct in_addr old_dr, old_bdr;
204 int old_state, new_state;
hasso52dc7ee2004-09-23 19:18:23 +0000205 struct list *el_list;
paul2d598362003-01-17 23:48:42 +0000206 struct ospf_neighbor *dr, *bdr;
207
208 /* backup current values. */
209 old_dr = DR (oi);
210 old_bdr = BDR (oi);
211 old_state = oi->state;
212
213 el_list = list_new ();
214
215 /* List eligible routers. */
216 ospf_dr_eligible_routers (oi->nbrs, el_list);
217
218 /* First election of DR and BDR. */
219 bdr = ospf_elect_bdr (oi, el_list);
220 dr = ospf_elect_dr (oi, el_list);
221
222 new_state = ospf_ism_state (oi);
223
224 zlog_info ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi)));
225 zlog_info ("DR-Election[1st]: DR %s", inet_ntoa (DR (oi)));
226
227 if (new_state != old_state &&
228 !(new_state == ISM_DROther && old_state < ISM_DROther))
229 {
230 ospf_elect_bdr (oi, el_list);
231 ospf_elect_dr (oi, el_list);
232
233 new_state = ospf_ism_state (oi);
234
235 zlog_info ("DR-Election[2nd]: Backup %s", inet_ntoa (BDR (oi)));
236 zlog_info ("DR-Election[2nd]: DR %s", inet_ntoa (DR (oi)));
237 }
238
239 list_delete (el_list);
240
241 /* if DR or BDR changes, cause AdjOK? neighbor event. */
242 if (!IPV4_ADDR_SAME (&old_dr, &DR (oi)) ||
243 !IPV4_ADDR_SAME (&old_bdr, &BDR (oi)))
paul68980082003-03-25 05:07:42 +0000244 ospf_dr_change (oi->ospf, oi->nbrs);
paul2d598362003-01-17 23:48:42 +0000245
paul2d598362003-01-17 23:48:42 +0000246 return new_state;
247}
248
249
250int
251ospf_hello_timer (struct thread *thread)
252{
253 struct ospf_interface *oi;
254
255 oi = THREAD_ARG (thread);
256 oi->t_hello = NULL;
257
258 if (IS_DEBUG_OSPF (ism, ISM_TIMERS))
259 zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Hello timer expire)",
260 IF_NAME (oi));
261
262 /* Sending hello packet. */
263 ospf_hello_send (oi);
264
265 /* Hello timer set. */
266 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer,
267 OSPF_IF_PARAM (oi, v_hello));
268
269 return 0;
270}
271
paul4dadc292005-05-06 21:37:42 +0000272static int
paul2d598362003-01-17 23:48:42 +0000273ospf_wait_timer (struct thread *thread)
274{
275 struct ospf_interface *oi;
276
277 oi = THREAD_ARG (thread);
278 oi->t_wait = NULL;
279
280 if (IS_DEBUG_OSPF (ism, ISM_TIMERS))
281 zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Wait timer expire)",
282 IF_NAME (oi));
283
284 OSPF_ISM_EVENT_SCHEDULE (oi, ISM_WaitTimer);
285
286 return 0;
287}
288
289/* Hook function called after ospf ISM event is occured. And vty's
290 network command invoke this function after making interface
291 structure. */
paul4dadc292005-05-06 21:37:42 +0000292static void
paul2d598362003-01-17 23:48:42 +0000293ism_timer_set (struct ospf_interface *oi)
294{
295 switch (oi->state)
296 {
297 case ISM_Down:
298 /* First entry point of ospf interface state machine. In this state
299 interface parameters must be set to initial values, and timers are
300 reset also. */
301 OSPF_ISM_TIMER_OFF (oi->t_hello);
302 OSPF_ISM_TIMER_OFF (oi->t_wait);
303 OSPF_ISM_TIMER_OFF (oi->t_ls_ack);
304 break;
305 case ISM_Loopback:
306 /* In this state, the interface may be looped back and will be
307 unavailable for regular data traffic. */
308 OSPF_ISM_TIMER_OFF (oi->t_hello);
309 OSPF_ISM_TIMER_OFF (oi->t_wait);
310 OSPF_ISM_TIMER_OFF (oi->t_ls_ack);
311 break;
312 case ISM_Waiting:
313 /* The router is trying to determine the identity of DRouter and
314 BDRouter. The router begin to receive and send Hello Packets. */
315 /* send first hello immediately */
316 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1);
317 OSPF_ISM_TIMER_ON (oi->t_wait, ospf_wait_timer,
318 OSPF_IF_PARAM (oi, v_wait));
319 OSPF_ISM_TIMER_OFF (oi->t_ls_ack);
320 break;
321 case ISM_PointToPoint:
322 /* The interface connects to a physical Point-to-point network or
323 virtual link. The router attempts to form an adjacency with
324 neighboring router. Hello packets are also sent. */
325 /* send first hello immediately */
326 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1);
327
328 OSPF_ISM_TIMER_OFF (oi->t_wait);
329 OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
330 break;
331 case ISM_DROther:
332 /* The network type of the interface is broadcast or NBMA network,
333 and the router itself is neither Designated Router nor
334 Backup Designated Router. */
335 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer,
336 OSPF_IF_PARAM (oi, v_hello));
337 OSPF_ISM_TIMER_OFF (oi->t_wait);
338 OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
339 break;
340 case ISM_Backup:
341 /* The network type of the interface is broadcast os NBMA network,
342 and the router is Backup Designated Router. */
343 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer,
344 OSPF_IF_PARAM (oi, v_hello));
345 OSPF_ISM_TIMER_OFF (oi->t_wait);
346 OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
347 break;
348 case ISM_DR:
349 /* The network type of the interface is broadcast or NBMA network,
350 and the router is Designated Router. */
351 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer,
352 OSPF_IF_PARAM (oi, v_hello));
353 OSPF_ISM_TIMER_OFF (oi->t_wait);
354 OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
355 break;
356 }
357}
358
paul4dadc292005-05-06 21:37:42 +0000359static int
paul2d598362003-01-17 23:48:42 +0000360ism_interface_up (struct ospf_interface *oi)
361{
362 int next_state = 0;
363
364 /* if network type is point-to-point, Point-to-MultiPoint or virtual link,
365 the state transitions to Point-to-Point. */
366 if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
367 oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
368 oi->type == OSPF_IFTYPE_VIRTUALLINK)
369 next_state = ISM_PointToPoint;
370 /* Else if the router is not eligible to DR, the state transitions to
371 DROther. */
372 else if (PRIORITY (oi) == 0) /* router is eligible? */
373 next_state = ISM_DROther;
374 else
375 /* Otherwise, the state transitions to Waiting. */
376 next_state = ISM_Waiting;
377
378 if (oi->type == OSPF_IFTYPE_NBMA)
paul68980082003-03-25 05:07:42 +0000379 ospf_nbr_nbma_if_update (oi->ospf, oi);
paul2d598362003-01-17 23:48:42 +0000380
381 /* ospf_ism_event (t); */
382 return next_state;
383}
384
paul4dadc292005-05-06 21:37:42 +0000385static int
paul2d598362003-01-17 23:48:42 +0000386ism_loop_ind (struct ospf_interface *oi)
387{
388 int ret = 0;
389
390 /* call ism_interface_down. */
391 /* ret = ism_interface_down (oi); */
392
393 return ret;
394}
395
396/* Interface down event handler. */
paul4dadc292005-05-06 21:37:42 +0000397static int
paul2d598362003-01-17 23:48:42 +0000398ism_interface_down (struct ospf_interface *oi)
399{
400 ospf_if_cleanup (oi);
401 return 0;
402}
403
404
paul4dadc292005-05-06 21:37:42 +0000405static int
paul2d598362003-01-17 23:48:42 +0000406ism_backup_seen (struct ospf_interface *oi)
407{
408 return ospf_dr_election (oi);
409}
410
paul4dadc292005-05-06 21:37:42 +0000411static int
paul2d598362003-01-17 23:48:42 +0000412ism_wait_timer (struct ospf_interface *oi)
413{
414 return ospf_dr_election (oi);
415}
416
paul4dadc292005-05-06 21:37:42 +0000417static int
paul2d598362003-01-17 23:48:42 +0000418ism_neighbor_change (struct ospf_interface *oi)
419{
420 return ospf_dr_election (oi);
421}
422
paul4dadc292005-05-06 21:37:42 +0000423static int
paul2d598362003-01-17 23:48:42 +0000424ism_ignore (struct ospf_interface *oi)
425{
426 if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
ajs60925302004-12-08 17:45:02 +0000427 zlog (NULL, LOG_DEBUG, "ISM[%s]: ism_ignore called", IF_NAME (oi));
paul2d598362003-01-17 23:48:42 +0000428
429 return 0;
430}
431
432/* Interface State Machine */
433struct {
paul4dadc292005-05-06 21:37:42 +0000434 int (*func) (struct ospf_interface *);
paul2d598362003-01-17 23:48:42 +0000435 int next_state;
436} ISM [OSPF_ISM_STATE_MAX][OSPF_ISM_EVENT_MAX] =
437{
438 {
439 /* DependUpon: dummy state. */
440 { ism_ignore, ISM_DependUpon }, /* NoEvent */
441 { ism_ignore, ISM_DependUpon }, /* InterfaceUp */
442 { ism_ignore, ISM_DependUpon }, /* WaitTimer */
443 { ism_ignore, ISM_DependUpon }, /* BackupSeen */
444 { ism_ignore, ISM_DependUpon }, /* NeighborChange */
445 { ism_ignore, ISM_DependUpon }, /* LoopInd */
446 { ism_ignore, ISM_DependUpon }, /* UnloopInd */
447 { ism_ignore, ISM_DependUpon }, /* InterfaceDown */
448 },
449 {
450 /* Down:*/
451 { ism_ignore, ISM_DependUpon }, /* NoEvent */
452 { ism_interface_up, ISM_DependUpon }, /* InterfaceUp */
453 { ism_ignore, ISM_Down }, /* WaitTimer */
454 { ism_ignore, ISM_Down }, /* BackupSeen */
455 { ism_ignore, ISM_Down }, /* NeighborChange */
456 { ism_loop_ind, ISM_Loopback }, /* LoopInd */
457 { ism_ignore, ISM_Down }, /* UnloopInd */
458 { ism_interface_down, ISM_Down }, /* InterfaceDown */
459 },
460 {
461 /* Loopback: */
462 { ism_ignore, ISM_DependUpon }, /* NoEvent */
463 { ism_ignore, ISM_Loopback }, /* InterfaceUp */
464 { ism_ignore, ISM_Loopback }, /* WaitTimer */
465 { ism_ignore, ISM_Loopback }, /* BackupSeen */
466 { ism_ignore, ISM_Loopback }, /* NeighborChange */
467 { ism_ignore, ISM_Loopback }, /* LoopInd */
468 { ism_ignore, ISM_Down }, /* UnloopInd */
469 { ism_interface_down, ISM_Down }, /* InterfaceDown */
470 },
471 {
472 /* Waiting: */
473 { ism_ignore, ISM_DependUpon }, /* NoEvent */
474 { ism_ignore, ISM_Waiting }, /* InterfaceUp */
475 { ism_wait_timer, ISM_DependUpon }, /* WaitTimer */
476 { ism_backup_seen, ISM_DependUpon }, /* BackupSeen */
477 { ism_ignore, ISM_Waiting }, /* NeighborChange */
478 { ism_loop_ind, ISM_Loopback }, /* LoopInd */
479 { ism_ignore, ISM_Waiting }, /* UnloopInd */
480 { ism_interface_down, ISM_Down }, /* InterfaceDown */
481 },
482 {
483 /* Point-to-Point: */
484 { ism_ignore, ISM_DependUpon }, /* NoEvent */
485 { ism_ignore, ISM_PointToPoint }, /* InterfaceUp */
486 { ism_ignore, ISM_PointToPoint }, /* WaitTimer */
487 { ism_ignore, ISM_PointToPoint }, /* BackupSeen */
488 { ism_ignore, ISM_PointToPoint }, /* NeighborChange */
489 { ism_loop_ind, ISM_Loopback }, /* LoopInd */
490 { ism_ignore, ISM_PointToPoint }, /* UnloopInd */
491 { ism_interface_down, ISM_Down }, /* InterfaceDown */
492 },
493 {
494 /* DROther: */
495 { ism_ignore, ISM_DependUpon }, /* NoEvent */
496 { ism_ignore, ISM_DROther }, /* InterfaceUp */
497 { ism_ignore, ISM_DROther }, /* WaitTimer */
498 { ism_ignore, ISM_DROther }, /* BackupSeen */
499 { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */
500 { ism_loop_ind, ISM_Loopback }, /* LoopInd */
501 { ism_ignore, ISM_DROther }, /* UnloopInd */
502 { ism_interface_down, ISM_Down }, /* InterfaceDown */
503 },
504 {
505 /* Backup: */
506 { ism_ignore, ISM_DependUpon }, /* NoEvent */
507 { ism_ignore, ISM_Backup }, /* InterfaceUp */
508 { ism_ignore, ISM_Backup }, /* WaitTimer */
509 { ism_ignore, ISM_Backup }, /* BackupSeen */
510 { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */
511 { ism_loop_ind, ISM_Loopback }, /* LoopInd */
512 { ism_ignore, ISM_Backup }, /* UnloopInd */
513 { ism_interface_down, ISM_Down }, /* InterfaceDown */
514 },
515 {
516 /* DR: */
517 { ism_ignore, ISM_DependUpon }, /* NoEvent */
518 { ism_ignore, ISM_DR }, /* InterfaceUp */
519 { ism_ignore, ISM_DR }, /* WaitTimer */
520 { ism_ignore, ISM_DR }, /* BackupSeen */
521 { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */
522 { ism_loop_ind, ISM_Loopback }, /* LoopInd */
523 { ism_ignore, ISM_DR }, /* UnloopInd */
524 { ism_interface_down, ISM_Down }, /* InterfaceDown */
525 },
526};
527
hassoeb1ce602004-10-08 08:17:22 +0000528const static char *ospf_ism_event_str[] =
paul2d598362003-01-17 23:48:42 +0000529{
530 "NoEvent",
531 "InterfaceUp",
532 "WaitTimer",
533 "BackupSeen",
534 "NeighborChange",
535 "LoopInd",
536 "UnLoopInd",
537 "InterfaceDown",
538};
539
paul4dadc292005-05-06 21:37:42 +0000540static void
paul2d598362003-01-17 23:48:42 +0000541ism_change_state (struct ospf_interface *oi, int state)
542{
543 int old_state;
544 struct ospf_lsa *lsa;
545
546 /* Logging change of state. */
547 if (IS_DEBUG_OSPF (ism, ISM_STATUS))
ajs60925302004-12-08 17:45:02 +0000548 zlog (NULL, LOG_DEBUG, "ISM[%s]: State change %s -> %s", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000549 LOOKUP (ospf_ism_state_msg, oi->state),
550 LOOKUP (ospf_ism_state_msg, state));
551
552 old_state = oi->state;
553 oi->state = state;
554 oi->state_change++;
555
vincent5e4914c2005-09-29 16:34:30 +0000556#ifdef HAVE_SNMP
557 /* Terminal state or regression */
558 if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) ||
559 (state == ISM_PointToPoint) || (state < old_state))
560 {
561 /* ospfVirtIfStateChange */
562 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
563 ospfTrapVirtIfStateChange (oi);
564 /* ospfIfStateChange */
565 else
566 ospfTrapIfStateChange (oi);
567 }
568#endif
569
ajsba6454e2005-02-08 15:37:30 +0000570 /* Set multicast memberships appropriately for new state. */
571 ospf_if_set_multicast(oi);
572
paul2d598362003-01-17 23:48:42 +0000573 if (old_state == ISM_Down || state == ISM_Down)
paul68980082003-03-25 05:07:42 +0000574 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000575
576 /* Originate router-LSA. */
577 if (oi->area)
578 {
579 if (state == ISM_Down)
580 {
581 if (oi->area->act_ints > 0)
582 oi->area->act_ints--;
583 }
584 else if (old_state == ISM_Down)
585 oi->area->act_ints++;
586
587 /* schedule router-LSA originate. */
588 ospf_router_lsa_timer_add (oi->area);
589 }
590
591 /* Originate network-LSA. */
592 if (old_state != ISM_DR && state == ISM_DR)
593 ospf_network_lsa_timer_add (oi);
594 else if (old_state == ISM_DR && state != ISM_DR)
595 {
596 /* Free self originated network LSA. */
597 lsa = oi->network_lsa_self;
598 if (lsa)
599 {
600 ospf_lsa_flush_area (lsa, oi->area);
601 OSPF_TIMER_OFF (oi->t_network_lsa_self);
602 }
603
604 ospf_lsa_unlock (oi->network_lsa_self);
605 oi->network_lsa_self = NULL;
606 }
607
608#ifdef HAVE_OPAQUE_LSA
609 ospf_opaque_ism_change (oi, old_state);
610#endif /* HAVE_OPAQUE_LSA */
611
612 /* Check area border status. */
paul68980082003-03-25 05:07:42 +0000613 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000614}
615
616/* Execute ISM event process. */
617int
618ospf_ism_event (struct thread *thread)
619{
620 int event;
621 int next_state;
622 struct ospf_interface *oi;
623
624 oi = THREAD_ARG (thread);
625 event = THREAD_VAL (thread);
626
627 /* Call function. */
628 next_state = (*(ISM [oi->state][event].func))(oi);
629
630 if (! next_state)
631 next_state = ISM [oi->state][event].next_state;
632
633 if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
ajs60925302004-12-08 17:45:02 +0000634 zlog (NULL, LOG_DEBUG, "ISM[%s]: %s (%s)", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000635 LOOKUP (ospf_ism_state_msg, oi->state),
636 ospf_ism_event_str[event]);
637
638 /* If state is changed. */
639 if (next_state != oi->state)
640 ism_change_state (oi, next_state);
641
642 /* Make sure timer is set. */
643 ism_timer_set (oi);
644
645 return 0;
646}
647