]>
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), |
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 | ||
107 | list_delete(dr_list); | |
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 | ||
147 | list_delete(bdr_list); | |
148 | list_delete(no_dr_list); | |
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*/ | |
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 | 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 | ||
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 | 199 | static 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 | |
d62a17ae | 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 | 246 | int 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 | 265 | static 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 | ||
280 | /* Hook function called after ospf ISM event is occured. And vty's | |
281 | network command invoke this function after making interface | |
282 | structure. */ | |
d62a17ae | 283 | static 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 | 355 | static 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 | 381 | static 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 | 392 | static int ism_interface_down(struct ospf_interface *oi) |
2d59836a | 393 | { |
d62a17ae | 394 | ospf_if_cleanup(oi); |
395 | return 0; | |
2d59836a | 396 | } |
397 | ||
398 | ||
d62a17ae | 399 | static int ism_backup_seen(struct ospf_interface *oi) |
2d59836a | 400 | { |
d62a17ae | 401 | return ospf_dr_election(oi); |
2d59836a | 402 | } |
403 | ||
d62a17ae | 404 | static int ism_wait_timer(struct ospf_interface *oi) |
2d59836a | 405 | { |
d62a17ae | 406 | return ospf_dr_election(oi); |
2d59836a | 407 | } |
408 | ||
d62a17ae | 409 | static int ism_neighbor_change(struct ospf_interface *oi) |
2d59836a | 410 | { |
d62a17ae | 411 | return ospf_dr_election(oi); |
2d59836a | 412 | } |
413 | ||
d62a17ae | 414 | static 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 */ | |
423 | struct { | |
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 | ||
517 | static const char *ospf_ism_event_str[] = { | |
518 | "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen", | |
519 | "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown", | |
2d59836a | 520 | }; |
521 | ||
d62a17ae | 522 | static 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 | 575 | int 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 | } |