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