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