]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ism.c
zebra: Allow ns delete to happen after under/over flow checks
[mirror_frr.git] / ospfd / ospf_ism.c
CommitLineData
2d59836a 1/*
2 * OSPF version 2 Interface State Machine
d62a17ae 3 * From RFC2328 [OSPF Version 2]
2d59836a 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 *
896014f4
DL
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2d59836a 21 */
22
23#include <zebra.h>
24
25#include "thread.h"
26#include "linklist.h"
27#include "prefix.h"
28#include "if.h"
29#include "table.h"
30#include "log.h"
31
32#include "ospfd/ospfd.h"
33#include "ospfd/ospf_interface.h"
34#include "ospfd/ospf_ism.h"
35#include "ospfd/ospf_asbr.h"
36#include "ospfd/ospf_lsa.h"
37#include "ospfd/ospf_lsdb.h"
38#include "ospfd/ospf_neighbor.h"
39#include "ospfd/ospf_nsm.h"
40#include "ospfd/ospf_network.h"
41#include "ospfd/ospf_dump.h"
42#include "ospfd/ospf_packet.h"
43#include "ospfd/ospf_flood.h"
44#include "ospfd/ospf_abr.h"
3012671f
DL
45
46DEFINE_HOOK(ospf_ism_change,
d62a17ae 47 (struct ospf_interface * oi, int state, int oldstate),
48 (oi, state, oldstate))
6b0655a2 49
2d59836a 50/* elect DR and BDR. Refer to RFC2319 section 9.4 */
d62a17ae 51static struct ospf_neighbor *ospf_dr_election_sub(struct list *routers)
2d59836a 52{
d62a17ae 53 struct listnode *node;
54 struct ospf_neighbor *nbr, *max = NULL;
55
56 /* Choose highest router priority.
57 In case of tie, choose highest Router ID. */
58 for (ALL_LIST_ELEMENTS_RO(routers, node, nbr)) {
59 if (max == NULL)
60 max = nbr;
61 else {
62 if (max->priority < nbr->priority)
63 max = nbr;
64 else if (max->priority == nbr->priority)
65 if (IPV4_ADDR_CMP(&max->router_id,
66 &nbr->router_id)
67 < 0)
68 max = nbr;
69 }
2d59836a 70 }
2d59836a 71
d62a17ae 72 return max;
2d59836a 73}
74
d62a17ae 75static struct ospf_neighbor *ospf_elect_dr(struct ospf_interface *oi,
76 struct list *el_list)
2d59836a 77{
d62a17ae 78 struct list *dr_list;
79 struct listnode *node;
80 struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL;
81
82 dr_list = list_new();
83
84 /* Add neighbors to the list. */
85 for (ALL_LIST_ELEMENTS_RO(el_list, node, nbr)) {
86 /* 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)
103 DR(oi) = dr->address.u.prefix4;
104 else
105 DR(oi).s_addr = 0;
106
6a154c88 107 list_delete(&dr_list);
d62a17ae 108
109 return dr;
2d59836a 110}
111
d62a17ae 112static struct ospf_neighbor *ospf_elect_bdr(struct ospf_interface *oi,
113 struct list *el_list)
2d59836a 114{
d62a17ae 115 struct list *bdr_list, *no_dr_list;
116 struct listnode *node;
117 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. */
123 for (ALL_LIST_ELEMENTS_RO(el_list, node, nbr)) {
124 /* 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)
143 BDR(oi) = bdr->address.u.prefix4;
144 else
145 BDR(oi).s_addr = 0;
146
6a154c88
DL
147 list_delete(&bdr_list);
148 list_delete(&no_dr_list);
d62a17ae 149
150 return bdr;
2d59836a 151}
152
d62a17ae 153static int ospf_ism_state(struct ospf_interface *oi)
2d59836a 154{
d62a17ae 155 if (IPV4_ADDR_SAME(&DR(oi), &oi->address->u.prefix4))
156 return ISM_DR;
157 else if (IPV4_ADDR_SAME(&BDR(oi), &oi->address->u.prefix4))
158 return ISM_Backup;
159 else
160 return ISM_DROther;
2d59836a 161}
162
d62a17ae 163static void ospf_dr_eligible_routers(struct route_table *nbrs,
164 struct list *el_list)
2d59836a 165{
d62a17ae 166 struct route_node *rn;
167 struct ospf_neighbor *nbr;
168
169 for (rn = route_top(nbrs); rn; rn = route_next(rn))
170 if ((nbr = rn->info) != NULL)
171 /* Ignore 0.0.0.0 node*/
172 if (nbr->router_id.s_addr != 0)
173 /* Is neighbor eligible? */
174 if (nbr->priority > 0)
175 /* Is neighbor upper 2-Way? */
176 if (nbr->state >= NSM_TwoWay)
177 listnode_add(el_list, nbr);
2d59836a 178}
179
180/* Generate AdjOK? NSM event. */
d62a17ae 181static void ospf_dr_change(struct ospf *ospf, struct route_table *nbrs)
2d59836a 182{
d62a17ae 183 struct route_node *rn;
184 struct ospf_neighbor *nbr;
185
186 for (rn = route_top(nbrs); rn; rn = route_next(rn))
187 if ((nbr = rn->info) != NULL)
188 /* Ignore 0.0.0.0 node*/
189 if (nbr->router_id.s_addr != 0)
190 /* Is neighbor upper 2-Way? */
191 if (nbr->state >= NSM_TwoWay)
192 /* Ignore myself. */
193 if (!IPV4_ADDR_SAME(&nbr->router_id,
194 &ospf->router_id))
195 OSPF_NSM_EVENT_SCHEDULE(
196 nbr, NSM_AdjOK);
2d59836a 197}
198
d62a17ae 199static int ospf_dr_election(struct ospf_interface *oi)
2d59836a 200{
d62a17ae 201 struct in_addr old_dr, old_bdr;
202 int old_state, new_state;
203 struct list *el_list;
2d59836a 204
d62a17ae 205 /* backup current values. */
206 old_dr = DR(oi);
207 old_bdr = BDR(oi);
208 old_state = oi->state;
2d59836a 209
d62a17ae 210 el_list = list_new();
2d59836a 211
d62a17ae 212 /* List eligible routers. */
213 ospf_dr_eligible_routers(oi->nbrs, el_list);
2d59836a 214
d62a17ae 215 /* First election of DR and BDR. */
216 ospf_elect_bdr(oi, el_list);
217 ospf_elect_dr(oi, el_list);
2d59836a 218
d62a17ae 219 new_state = ospf_ism_state(oi);
2d59836a 220
d62a17ae 221 zlog_debug("DR-Election[1st]: Backup %s", inet_ntoa(BDR(oi)));
222 zlog_debug("DR-Election[1st]: DR %s", inet_ntoa(DR(oi)));
2d59836a 223
d62a17ae 224 if (new_state != old_state
225 && !(new_state == ISM_DROther && old_state < ISM_DROther)) {
226 ospf_elect_bdr(oi, el_list);
227 ospf_elect_dr(oi, el_list);
2d59836a 228
d62a17ae 229 new_state = ospf_ism_state(oi);
2d59836a 230
d62a17ae 231 zlog_debug("DR-Election[2nd]: Backup %s", inet_ntoa(BDR(oi)));
232 zlog_debug("DR-Election[2nd]: DR %s", inet_ntoa(DR(oi)));
233 }
2d59836a 234
6a154c88 235 list_delete(&el_list);
2d59836a 236
d62a17ae 237 /* if DR or BDR changes, cause AdjOK? neighbor event. */
238 if (!IPV4_ADDR_SAME(&old_dr, &DR(oi))
239 || !IPV4_ADDR_SAME(&old_bdr, &BDR(oi)))
240 ospf_dr_change(oi->ospf, oi->nbrs);
2d59836a 241
d62a17ae 242 return new_state;
2d59836a 243}
244
6b0655a2 245
d62a17ae 246int ospf_hello_timer(struct thread *thread)
2d59836a 247{
d62a17ae 248 struct ospf_interface *oi;
2d59836a 249
d62a17ae 250 oi = THREAD_ARG(thread);
251 oi->t_hello = NULL;
2d59836a 252
d62a17ae 253 if (IS_DEBUG_OSPF(ism, ISM_TIMERS))
254 zlog_debug("ISM[%s]: Timer (Hello timer expire)", IF_NAME(oi));
2d59836a 255
d62a17ae 256 /* Sending hello packet. */
257 ospf_hello_send(oi);
2d59836a 258
d62a17ae 259 /* Hello timer set. */
260 OSPF_HELLO_TIMER_ON(oi);
261
262 return 0;
2d59836a 263}
264
d62a17ae 265static int ospf_wait_timer(struct thread *thread)
2d59836a 266{
d62a17ae 267 struct ospf_interface *oi;
2d59836a 268
d62a17ae 269 oi = THREAD_ARG(thread);
270 oi->t_wait = NULL;
2d59836a 271
d62a17ae 272 if (IS_DEBUG_OSPF(ism, ISM_TIMERS))
273 zlog_debug("ISM[%s]: Timer (Wait timer expire)", IF_NAME(oi));
2d59836a 274
d62a17ae 275 OSPF_ISM_EVENT_SCHEDULE(oi, ISM_WaitTimer);
2d59836a 276
d62a17ae 277 return 0;
2d59836a 278}
279
0437e105 280/* Hook function called after ospf ISM event is occurred. And vty's
2d59836a 281 network command invoke this function after making interface
282 structure. */
d62a17ae 283static void ism_timer_set(struct ospf_interface *oi)
2d59836a 284{
d62a17ae 285 switch (oi->state) {
286 case ISM_Down:
287 /* First entry point of ospf interface state machine. In this
288 state
289 interface parameters must be set to initial values, and
290 timers are
291 reset also. */
292 OSPF_ISM_TIMER_OFF(oi->t_hello);
293 OSPF_ISM_TIMER_OFF(oi->t_wait);
294 OSPF_ISM_TIMER_OFF(oi->t_ls_ack);
295 break;
296 case ISM_Loopback:
297 /* In this state, the interface may be looped back and will be
298 unavailable for regular data traffic. */
299 OSPF_ISM_TIMER_OFF(oi->t_hello);
300 OSPF_ISM_TIMER_OFF(oi->t_wait);
301 OSPF_ISM_TIMER_OFF(oi->t_ls_ack);
302 break;
303 case ISM_Waiting:
304 /* The router is trying to determine the identity of DRouter and
305 BDRouter. The router begin to receive and send Hello Packets.
306 */
307 /* send first hello immediately */
308 OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1);
309 OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer,
310 OSPF_IF_PARAM(oi, v_wait));
311 OSPF_ISM_TIMER_OFF(oi->t_ls_ack);
312 break;
313 case ISM_PointToPoint:
314 /* The interface connects to a physical Point-to-point network
315 or
316 virtual link. The router attempts to form an adjacency with
317 neighboring router. Hello packets are also sent. */
318 /* send first hello immediately */
319 OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1);
320 OSPF_ISM_TIMER_OFF(oi->t_wait);
321 OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
322 oi->v_ls_ack);
323 break;
324 case ISM_DROther:
325 /* The network type of the interface is broadcast or NBMA
326 network,
327 and the router itself is neither Designated Router nor
328 Backup Designated Router. */
329 OSPF_HELLO_TIMER_ON(oi);
330 OSPF_ISM_TIMER_OFF(oi->t_wait);
331 OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
332 oi->v_ls_ack);
333 break;
334 case ISM_Backup:
335 /* The network type of the interface is broadcast os NBMA
336 network,
337 and the router is Backup Designated Router. */
338 OSPF_HELLO_TIMER_ON(oi);
339 OSPF_ISM_TIMER_OFF(oi->t_wait);
340 OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
341 oi->v_ls_ack);
342 break;
343 case ISM_DR:
344 /* The network type of the interface is broadcast or NBMA
345 network,
346 and the router is Designated Router. */
347 OSPF_HELLO_TIMER_ON(oi);
348 OSPF_ISM_TIMER_OFF(oi->t_wait);
349 OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer,
350 oi->v_ls_ack);
351 break;
352 }
2d59836a 353}
354
d62a17ae 355static int ism_interface_up(struct ospf_interface *oi)
2d59836a 356{
d62a17ae 357 int next_state = 0;
358
359 /* if network type is point-to-point, Point-to-MultiPoint or virtual
360 link,
361 the state transitions to Point-to-Point. */
362 if (oi->type == OSPF_IFTYPE_POINTOPOINT
363 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
364 || oi->type == OSPF_IFTYPE_VIRTUALLINK)
365 next_state = ISM_PointToPoint;
366 /* Else if the router is not eligible to DR, the state transitions to
367 DROther. */
368 else if (PRIORITY(oi) == 0) /* router is eligible? */
369 next_state = ISM_DROther;
370 else
371 /* Otherwise, the state transitions to Waiting. */
372 next_state = ISM_Waiting;
373
374 if (oi->type == OSPF_IFTYPE_NBMA)
375 ospf_nbr_nbma_if_update(oi->ospf, oi);
376
377 /* ospf_ism_event (t); */
378 return next_state;
2d59836a 379}
380
d62a17ae 381static int ism_loop_ind(struct ospf_interface *oi)
2d59836a 382{
d62a17ae 383 int ret = 0;
2d59836a 384
d62a17ae 385 /* call ism_interface_down. */
386 /* ret = ism_interface_down (oi); */
2d59836a 387
d62a17ae 388 return ret;
2d59836a 389}
390
391/* Interface down event handler. */
d62a17ae 392static int ism_interface_down(struct ospf_interface *oi)
2d59836a 393{
d62a17ae 394 ospf_if_cleanup(oi);
395 return 0;
2d59836a 396}
397
398
d62a17ae 399static int ism_backup_seen(struct ospf_interface *oi)
2d59836a 400{
d62a17ae 401 return ospf_dr_election(oi);
2d59836a 402}
403
d62a17ae 404static int ism_wait_timer(struct ospf_interface *oi)
2d59836a 405{
d62a17ae 406 return ospf_dr_election(oi);
2d59836a 407}
408
d62a17ae 409static int ism_neighbor_change(struct ospf_interface *oi)
2d59836a 410{
d62a17ae 411 return ospf_dr_election(oi);
2d59836a 412}
413
d62a17ae 414static int ism_ignore(struct ospf_interface *oi)
2d59836a 415{
d62a17ae 416 if (IS_DEBUG_OSPF(ism, ISM_EVENTS))
417 zlog_debug("ISM[%s]: ism_ignore called", IF_NAME(oi));
2d59836a 418
d62a17ae 419 return 0;
2d59836a 420}
421
422/* Interface State Machine */
423struct {
d62a17ae 424 int (*func)(struct ospf_interface *);
425 int next_state;
426} ISM[OSPF_ISM_STATE_MAX][OSPF_ISM_EVENT_MAX] = {
427 {
428 /* DependUpon: dummy state. */
429 {ism_ignore, ISM_DependUpon}, /* NoEvent */
430 {ism_ignore, ISM_DependUpon}, /* InterfaceUp */
431 {ism_ignore, ISM_DependUpon}, /* WaitTimer */
432 {ism_ignore, ISM_DependUpon}, /* BackupSeen */
433 {ism_ignore, ISM_DependUpon}, /* NeighborChange */
434 {ism_ignore, ISM_DependUpon}, /* LoopInd */
435 {ism_ignore, ISM_DependUpon}, /* UnloopInd */
436 {ism_ignore, ISM_DependUpon}, /* InterfaceDown */
437 },
438 {
439 /* Down:*/
440 {ism_ignore, ISM_DependUpon}, /* NoEvent */
441 {ism_interface_up, ISM_DependUpon}, /* InterfaceUp */
442 {ism_ignore, ISM_Down}, /* WaitTimer */
443 {ism_ignore, ISM_Down}, /* BackupSeen */
444 {ism_ignore, ISM_Down}, /* NeighborChange */
445 {ism_loop_ind, ISM_Loopback}, /* LoopInd */
446 {ism_ignore, ISM_Down}, /* UnloopInd */
447 {ism_interface_down, ISM_Down}, /* InterfaceDown */
448 },
449 {
450 /* Loopback: */
451 {ism_ignore, ISM_DependUpon}, /* NoEvent */
452 {ism_ignore, ISM_Loopback}, /* InterfaceUp */
453 {ism_ignore, ISM_Loopback}, /* WaitTimer */
454 {ism_ignore, ISM_Loopback}, /* BackupSeen */
455 {ism_ignore, ISM_Loopback}, /* NeighborChange */
456 {ism_ignore, ISM_Loopback}, /* LoopInd */
457 {ism_ignore, ISM_Down}, /* UnloopInd */
458 {ism_interface_down, ISM_Down}, /* InterfaceDown */
459 },
460 {
461 /* Waiting: */
462 {ism_ignore, ISM_DependUpon}, /* NoEvent */
463 {ism_ignore, ISM_Waiting}, /* InterfaceUp */
464 {ism_wait_timer, ISM_DependUpon}, /* WaitTimer */
465 {ism_backup_seen, ISM_DependUpon}, /* BackupSeen */
466 {ism_ignore, ISM_Waiting}, /* NeighborChange */
467 {ism_loop_ind, ISM_Loopback}, /* LoopInd */
468 {ism_ignore, ISM_Waiting}, /* UnloopInd */
469 {ism_interface_down, ISM_Down}, /* InterfaceDown */
470 },
471 {
472 /* Point-to-Point: */
473 {ism_ignore, ISM_DependUpon}, /* NoEvent */
474 {ism_ignore, ISM_PointToPoint}, /* InterfaceUp */
475 {ism_ignore, ISM_PointToPoint}, /* WaitTimer */
476 {ism_ignore, ISM_PointToPoint}, /* BackupSeen */
477 {ism_ignore, ISM_PointToPoint}, /* NeighborChange */
478 {ism_loop_ind, ISM_Loopback}, /* LoopInd */
479 {ism_ignore, ISM_PointToPoint}, /* UnloopInd */
480 {ism_interface_down, ISM_Down}, /* InterfaceDown */
481 },
482 {
483 /* DROther: */
484 {ism_ignore, ISM_DependUpon}, /* NoEvent */
485 {ism_ignore, ISM_DROther}, /* InterfaceUp */
486 {ism_ignore, ISM_DROther}, /* WaitTimer */
487 {ism_ignore, ISM_DROther}, /* BackupSeen */
488 {ism_neighbor_change, ISM_DependUpon}, /* NeighborChange */
489 {ism_loop_ind, ISM_Loopback}, /* LoopInd */
490 {ism_ignore, ISM_DROther}, /* UnloopInd */
491 {ism_interface_down, ISM_Down}, /* InterfaceDown */
492 },
493 {
494 /* Backup: */
495 {ism_ignore, ISM_DependUpon}, /* NoEvent */
496 {ism_ignore, ISM_Backup}, /* InterfaceUp */
497 {ism_ignore, ISM_Backup}, /* WaitTimer */
498 {ism_ignore, ISM_Backup}, /* BackupSeen */
499 {ism_neighbor_change, ISM_DependUpon}, /* NeighborChange */
500 {ism_loop_ind, ISM_Loopback}, /* LoopInd */
501 {ism_ignore, ISM_Backup}, /* UnloopInd */
502 {ism_interface_down, ISM_Down}, /* InterfaceDown */
503 },
504 {
505 /* DR: */
506 {ism_ignore, ISM_DependUpon}, /* NoEvent */
507 {ism_ignore, ISM_DR}, /* InterfaceUp */
508 {ism_ignore, ISM_DR}, /* WaitTimer */
509 {ism_ignore, ISM_DR}, /* BackupSeen */
510 {ism_neighbor_change, ISM_DependUpon}, /* NeighborChange */
511 {ism_loop_ind, ISM_Loopback}, /* LoopInd */
512 {ism_ignore, ISM_DR}, /* UnloopInd */
513 {ism_interface_down, ISM_Down}, /* InterfaceDown */
514 },
515};
516
517static const char *ospf_ism_event_str[] = {
518 "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen",
519 "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown",
2d59836a 520};
521
d62a17ae 522static void ism_change_state(struct ospf_interface *oi, int state)
2d59836a 523{
d62a17ae 524 int old_state;
525 struct ospf_lsa *lsa;
526
527 /* Logging change of state. */
528 if (IS_DEBUG_OSPF(ism, ISM_STATUS))
529 zlog_debug("ISM[%s]: State change %s -> %s", IF_NAME(oi),
530 lookup_msg(ospf_ism_state_msg, oi->state, NULL),
531 lookup_msg(ospf_ism_state_msg, state, NULL));
532
533 old_state = oi->state;
534 oi->state = state;
535 oi->state_change++;
536
537 hook_call(ospf_ism_change, oi, state, old_state);
538
539 /* Set multicast memberships appropriately for new state. */
540 ospf_if_set_multicast(oi);
541
542 if (old_state == ISM_Down || state == ISM_Down)
543 ospf_check_abr_status(oi->ospf);
544
545 /* Originate router-LSA. */
546 if (state == ISM_Down) {
547 if (oi->area->act_ints > 0)
548 oi->area->act_ints--;
549 } else if (old_state == ISM_Down)
550 oi->area->act_ints++;
551
552 /* schedule router-LSA originate. */
553 ospf_router_lsa_update_area(oi->area);
554
555 /* Originate network-LSA. */
556 if (old_state != ISM_DR && state == ISM_DR)
557 ospf_network_lsa_update(oi);
558 else if (old_state == ISM_DR && state != ISM_DR) {
559 /* Free self originated network LSA. */
560 lsa = oi->network_lsa_self;
561 if (lsa)
562 ospf_lsa_flush_area(lsa, oi->area);
563
564 ospf_lsa_unlock(&oi->network_lsa_self);
565 oi->network_lsa_self = NULL;
566 }
567
568 ospf_opaque_ism_change(oi, old_state);
569
570 /* Check area border status. */
571 ospf_check_abr_status(oi->ospf);
2d59836a 572}
573
574/* Execute ISM event process. */
d62a17ae 575int ospf_ism_event(struct thread *thread)
2d59836a 576{
d62a17ae 577 int event;
578 int next_state;
579 struct ospf_interface *oi;
2d59836a 580
d62a17ae 581 oi = THREAD_ARG(thread);
582 event = THREAD_VAL(thread);
2d59836a 583
d62a17ae 584 /* Call function. */
585 next_state = (*(ISM[oi->state][event].func))(oi);
2d59836a 586
d62a17ae 587 if (!next_state)
588 next_state = ISM[oi->state][event].next_state;
2d59836a 589
d62a17ae 590 if (IS_DEBUG_OSPF(ism, ISM_EVENTS))
591 zlog_debug("ISM[%s]: %s (%s)", IF_NAME(oi),
592 lookup_msg(ospf_ism_state_msg, oi->state, NULL),
593 ospf_ism_event_str[event]);
2d59836a 594
d62a17ae 595 /* If state is changed. */
596 if (next_state != oi->state)
597 ism_change_state(oi, next_state);
2d59836a 598
d62a17ae 599 /* Make sure timer is set. */
600 ism_timer_set(oi);
2d59836a 601
d62a17ae 602 return 0;
2d59836a 603}