]>
Commit | Line | Data |
---|---|---|
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 | |
46 | DEFINE_HOOK(ospf_ism_change, | |
d62a17ae | 47 | (struct ospf_interface * oi, int state, int oldstate), |
8451921b | 48 | (oi, state, oldstate)); |
6b0655a2 | 49 | |
2d59836a | 50 | /* elect DR and BDR. Refer to RFC2319 section 9.4 */ |
d62a17ae | 51 | static 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 | 75 | static 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 | 112 | static 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 | 153 | static 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 | 163 | static 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*/ | |
975a328e | 172 | if (nbr->router_id.s_addr != INADDR_ANY) |
d62a17ae | 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 | 181 | static 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 | ||
850dda33 DS |
186 | for (rn = route_top(nbrs); rn; rn = route_next(rn)) { |
187 | nbr = rn->info; | |
188 | ||
189 | if (!nbr) | |
190 | continue; | |
191 | ||
192 | /* | |
193 | * Ignore 0.0.0.0 node | |
194 | * Is neighbor 2-Way? | |
195 | * Ignore myself | |
196 | */ | |
197 | if (nbr->router_id.s_addr != INADDR_ANY | |
198 | && nbr->state >= NSM_TwoWay | |
199 | && !IPV4_ADDR_SAME(&nbr->router_id, &ospf->router_id)) | |
200 | OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_AdjOK); | |
201 | } | |
2d59836a | 202 | } |
203 | ||
df074ec3 | 204 | int ospf_dr_election(struct ospf_interface *oi) |
2d59836a | 205 | { |
d62a17ae | 206 | struct in_addr old_dr, old_bdr; |
207 | int old_state, new_state; | |
208 | struct list *el_list; | |
2d59836a | 209 | |
d62a17ae | 210 | /* backup current values. */ |
211 | old_dr = DR(oi); | |
212 | old_bdr = BDR(oi); | |
213 | old_state = oi->state; | |
2d59836a | 214 | |
d62a17ae | 215 | el_list = list_new(); |
2d59836a | 216 | |
d62a17ae | 217 | /* List eligible routers. */ |
218 | ospf_dr_eligible_routers(oi->nbrs, el_list); | |
2d59836a | 219 | |
d62a17ae | 220 | /* First election of DR and BDR. */ |
221 | ospf_elect_bdr(oi, el_list); | |
222 | ospf_elect_dr(oi, el_list); | |
2d59836a | 223 | |
d62a17ae | 224 | new_state = ospf_ism_state(oi); |
2d59836a | 225 | |
96b663a3 MS |
226 | zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi)); |
227 | zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi)); | |
2d59836a | 228 | |
d62a17ae | 229 | if (new_state != old_state |
230 | && !(new_state == ISM_DROther && old_state < ISM_DROther)) { | |
231 | ospf_elect_bdr(oi, el_list); | |
232 | ospf_elect_dr(oi, el_list); | |
2d59836a | 233 | |
d62a17ae | 234 | new_state = ospf_ism_state(oi); |
2d59836a | 235 | |
96b663a3 MS |
236 | zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi)); |
237 | zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi)); | |
d62a17ae | 238 | } |
2d59836a | 239 | |
6a154c88 | 240 | list_delete(&el_list); |
2d59836a | 241 | |
d62a17ae | 242 | /* if DR or BDR changes, cause AdjOK? neighbor event. */ |
243 | if (!IPV4_ADDR_SAME(&old_dr, &DR(oi)) | |
244 | || !IPV4_ADDR_SAME(&old_bdr, &BDR(oi))) | |
245 | ospf_dr_change(oi->ospf, oi->nbrs); | |
2d59836a | 246 | |
d62a17ae | 247 | return new_state; |
2d59836a | 248 | } |
249 | ||
6b0655a2 | 250 | |
d62a17ae | 251 | int ospf_hello_timer(struct thread *thread) |
2d59836a | 252 | { |
d62a17ae | 253 | struct ospf_interface *oi; |
2d59836a | 254 | |
d62a17ae | 255 | oi = THREAD_ARG(thread); |
256 | oi->t_hello = NULL; | |
2d59836a | 257 | |
d62a17ae | 258 | if (IS_DEBUG_OSPF(ism, ISM_TIMERS)) |
259 | zlog_debug("ISM[%s]: Timer (Hello timer expire)", IF_NAME(oi)); | |
2d59836a | 260 | |
d62a17ae | 261 | /* Sending hello packet. */ |
262 | ospf_hello_send(oi); | |
2d59836a | 263 | |
d62a17ae | 264 | /* Hello timer set. */ |
265 | OSPF_HELLO_TIMER_ON(oi); | |
266 | ||
267 | return 0; | |
2d59836a | 268 | } |
269 | ||
d62a17ae | 270 | static int ospf_wait_timer(struct thread *thread) |
2d59836a | 271 | { |
d62a17ae | 272 | struct ospf_interface *oi; |
2d59836a | 273 | |
d62a17ae | 274 | oi = THREAD_ARG(thread); |
275 | oi->t_wait = NULL; | |
2d59836a | 276 | |
d62a17ae | 277 | if (IS_DEBUG_OSPF(ism, ISM_TIMERS)) |
278 | zlog_debug("ISM[%s]: Timer (Wait timer expire)", IF_NAME(oi)); | |
2d59836a | 279 | |
d62a17ae | 280 | OSPF_ISM_EVENT_SCHEDULE(oi, ISM_WaitTimer); |
2d59836a | 281 | |
d62a17ae | 282 | return 0; |
2d59836a | 283 | } |
284 | ||
0437e105 | 285 | /* Hook function called after ospf ISM event is occurred. And vty's |
2d59836a | 286 | network command invoke this function after making interface |
287 | structure. */ | |
d62a17ae | 288 | static void ism_timer_set(struct ospf_interface *oi) |
2d59836a | 289 | { |
d62a17ae | 290 | switch (oi->state) { |
291 | 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 | OSPF_ISM_TIMER_OFF(oi->t_hello); | |
298 | OSPF_ISM_TIMER_OFF(oi->t_wait); | |
299 | OSPF_ISM_TIMER_OFF(oi->t_ls_ack); | |
300 | break; | |
301 | case ISM_Loopback: | |
302 | /* In this state, the interface may be looped back and will be | |
303 | unavailable for regular data traffic. */ | |
304 | OSPF_ISM_TIMER_OFF(oi->t_hello); | |
305 | OSPF_ISM_TIMER_OFF(oi->t_wait); | |
306 | OSPF_ISM_TIMER_OFF(oi->t_ls_ack); | |
307 | break; | |
308 | 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 | OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); | |
314 | OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer, | |
315 | OSPF_IF_PARAM(oi, v_wait)); | |
316 | OSPF_ISM_TIMER_OFF(oi->t_ls_ack); | |
317 | break; | |
318 | 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 | OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); | |
325 | OSPF_ISM_TIMER_OFF(oi->t_wait); | |
326 | OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, | |
327 | oi->v_ls_ack); | |
328 | break; | |
329 | 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 | OSPF_HELLO_TIMER_ON(oi); | |
335 | OSPF_ISM_TIMER_OFF(oi->t_wait); | |
336 | OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, | |
337 | oi->v_ls_ack); | |
338 | break; | |
339 | 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 | OSPF_HELLO_TIMER_ON(oi); | |
344 | OSPF_ISM_TIMER_OFF(oi->t_wait); | |
345 | OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, | |
346 | oi->v_ls_ack); | |
347 | break; | |
348 | case ISM_DR: | |
349 | /* The network type of the interface is broadcast or NBMA | |
350 | network, | |
351 | and the router is Designated Router. */ | |
352 | OSPF_HELLO_TIMER_ON(oi); | |
353 | OSPF_ISM_TIMER_OFF(oi->t_wait); | |
354 | OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, | |
355 | oi->v_ls_ack); | |
356 | break; | |
357 | } | |
2d59836a | 358 | } |
359 | ||
d62a17ae | 360 | static int ism_interface_up(struct ospf_interface *oi) |
2d59836a | 361 | { |
d62a17ae | 362 | 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 | if (oi->type == OSPF_IFTYPE_POINTOPOINT | |
368 | || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT | |
369 | || 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 | else if (PRIORITY(oi) == 0) /* router is eligible? */ | |
374 | next_state = ISM_DROther; | |
375 | else | |
376 | /* Otherwise, the state transitions to Waiting. */ | |
377 | next_state = ISM_Waiting; | |
378 | ||
379 | if (oi->type == OSPF_IFTYPE_NBMA) | |
380 | ospf_nbr_nbma_if_update(oi->ospf, oi); | |
381 | ||
382 | /* ospf_ism_event (t); */ | |
383 | return next_state; | |
2d59836a | 384 | } |
385 | ||
d62a17ae | 386 | static int ism_loop_ind(struct ospf_interface *oi) |
2d59836a | 387 | { |
d62a17ae | 388 | /* call ism_interface_down. */ |
389 | /* ret = ism_interface_down (oi); */ | |
2d59836a | 390 | |
9f2d0354 | 391 | return 0; |
2d59836a | 392 | } |
393 | ||
394 | /* Interface down event handler. */ | |
d62a17ae | 395 | static int ism_interface_down(struct ospf_interface *oi) |
2d59836a | 396 | { |
d62a17ae | 397 | ospf_if_cleanup(oi); |
398 | return 0; | |
2d59836a | 399 | } |
400 | ||
401 | ||
d62a17ae | 402 | static int ism_backup_seen(struct ospf_interface *oi) |
2d59836a | 403 | { |
d62a17ae | 404 | return ospf_dr_election(oi); |
2d59836a | 405 | } |
406 | ||
d62a17ae | 407 | static int ism_wait_timer(struct ospf_interface *oi) |
2d59836a | 408 | { |
d62a17ae | 409 | return ospf_dr_election(oi); |
2d59836a | 410 | } |
411 | ||
d62a17ae | 412 | static int ism_neighbor_change(struct ospf_interface *oi) |
2d59836a | 413 | { |
d62a17ae | 414 | return ospf_dr_election(oi); |
2d59836a | 415 | } |
416 | ||
d62a17ae | 417 | static int ism_ignore(struct ospf_interface *oi) |
2d59836a | 418 | { |
d62a17ae | 419 | if (IS_DEBUG_OSPF(ism, ISM_EVENTS)) |
420 | zlog_debug("ISM[%s]: ism_ignore called", IF_NAME(oi)); | |
2d59836a | 421 | |
d62a17ae | 422 | return 0; |
2d59836a | 423 | } |
424 | ||
425 | /* Interface State Machine */ | |
2b64873d | 426 | const struct { |
d62a17ae | 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 | ||
2b64873d | 520 | static const char *const ospf_ism_event_str[] = { |
d62a17ae | 521 | "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen", |
522 | "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown", | |
2d59836a | 523 | }; |
524 | ||
d62a17ae | 525 | static void ism_change_state(struct ospf_interface *oi, int state) |
2d59836a | 526 | { |
d62a17ae | 527 | int old_state; |
528 | struct ospf_lsa *lsa; | |
529 | ||
530 | /* Logging change of state. */ | |
531 | if (IS_DEBUG_OSPF(ism, ISM_STATUS)) | |
532 | 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 | old_state = oi->state; | |
537 | oi->state = state; | |
538 | oi->state_change++; | |
539 | ||
540 | hook_call(ospf_ism_change, oi, state, old_state); | |
541 | ||
542 | /* Set multicast memberships appropriately for new state. */ | |
543 | ospf_if_set_multicast(oi); | |
544 | ||
545 | if (old_state == ISM_Down || state == ISM_Down) | |
546 | ospf_check_abr_status(oi->ospf); | |
547 | ||
548 | /* Originate router-LSA. */ | |
549 | if (state == ISM_Down) { | |
550 | if (oi->area->act_ints > 0) | |
551 | oi->area->act_ints--; | |
552 | } else if (old_state == ISM_Down) | |
553 | oi->area->act_ints++; | |
554 | ||
555 | /* schedule router-LSA originate. */ | |
556 | ospf_router_lsa_update_area(oi->area); | |
557 | ||
558 | /* Originate network-LSA. */ | |
559 | if (old_state != ISM_DR && state == ISM_DR) | |
560 | ospf_network_lsa_update(oi); | |
561 | else if (old_state == ISM_DR && state != ISM_DR) { | |
562 | /* Free self originated network LSA. */ | |
563 | lsa = oi->network_lsa_self; | |
564 | if (lsa) | |
565 | ospf_lsa_flush_area(lsa, oi->area); | |
566 | ||
567 | ospf_lsa_unlock(&oi->network_lsa_self); | |
568 | oi->network_lsa_self = NULL; | |
569 | } | |
570 | ||
571 | ospf_opaque_ism_change(oi, old_state); | |
572 | ||
573 | /* Check area border status. */ | |
574 | ospf_check_abr_status(oi->ospf); | |
2d59836a | 575 | } |
576 | ||
577 | /* Execute ISM event process. */ | |
d62a17ae | 578 | int ospf_ism_event(struct thread *thread) |
2d59836a | 579 | { |
d62a17ae | 580 | int event; |
581 | int next_state; | |
582 | struct ospf_interface *oi; | |
2d59836a | 583 | |
d62a17ae | 584 | oi = THREAD_ARG(thread); |
585 | event = THREAD_VAL(thread); | |
2d59836a | 586 | |
d62a17ae | 587 | /* Call function. */ |
588 | next_state = (*(ISM[oi->state][event].func))(oi); | |
2d59836a | 589 | |
d62a17ae | 590 | if (!next_state) |
591 | next_state = ISM[oi->state][event].next_state; | |
2d59836a | 592 | |
d62a17ae | 593 | if (IS_DEBUG_OSPF(ism, ISM_EVENTS)) |
594 | 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]); | |
2d59836a | 597 | |
d62a17ae | 598 | /* If state is changed. */ |
599 | if (next_state != oi->state) | |
600 | ism_change_state(oi, next_state); | |
2d59836a | 601 | |
d62a17ae | 602 | /* Make sure timer is set. */ |
603 | ism_timer_set(oi); | |
2d59836a | 604 | |
d62a17ae | 605 | return 0; |
2d59836a | 606 | } |