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