2 * Copyright (C) 1999 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 /* Interface State Machine */
27 ifs_change (state_t ifs_next
, char *reason
, struct ospf6_interface
*o6i
)
31 ifs_prev
= o6i
->state
;
33 if (ifs_prev
== ifs_next
)
36 if (IS_OSPF6_DUMP_INTERFACE
)
37 zlog_info ("I/F: %s: %s -> %s (%s)",
39 ospf6_interface_state_string
[ifs_prev
],
40 ospf6_interface_state_string
[ifs_next
], reason
);
42 if ((ifs_prev
== IFS_DR
|| ifs_prev
== IFS_BDR
) &&
43 (ifs_next
!= IFS_DR
&& ifs_next
!= IFS_BDR
))
44 ospf6_leave_alldrouters (o6i
->interface
->ifindex
);
45 else if ((ifs_prev
!= IFS_DR
&& ifs_prev
!= IFS_BDR
) &&
46 (ifs_next
== IFS_DR
|| ifs_next
== IFS_BDR
))
47 ospf6_join_alldrouters (o6i
->interface
->ifindex
);
49 o6i
->state
= ifs_next
;
51 if (o6i
->prevdr
!= o6i
->dr
|| o6i
->prevbdr
!= o6i
->bdr
)
53 if (IS_OSPF6_DUMP_INTERFACE
)
55 char dr
[16], bdr
[16], prevdr
[16], prevbdr
[16];
56 inet_ntop (AF_INET
, &o6i
->prevdr
, prevdr
, sizeof (prevdr
));
57 inet_ntop (AF_INET
, &o6i
->prevbdr
, prevbdr
, sizeof (prevbdr
));
58 inet_ntop (AF_INET
, &o6i
->dr
, dr
, sizeof (dr
));
59 inet_ntop (AF_INET
, &o6i
->bdr
, bdr
, sizeof (bdr
));
60 zlog_info ("I/F: %s: DR: %s -> %s", o6i
->interface
->name
,
62 zlog_info ("I/F: %s: BDR: %s -> %s", o6i
->interface
->name
,
67 CALL_CHANGE_HOOK (&interface_hook
, o6i
);
72 /* Interface State Machine */
74 interface_up (struct thread
*thread
)
76 struct ospf6_interface
*ospf6_interface
;
78 ospf6_interface
= (struct ospf6_interface
*)THREAD_ARG (thread
);
80 assert (ospf6_interface
);
81 assert (ospf6_interface
->interface
);
83 if (IS_OSPF6_DUMP_INTERFACE
)
84 zlog_info ("I/F: %s: InterfaceUp",
85 ospf6_interface
->interface
->name
);
87 /* check physical interface is up */
88 if (!if_is_up (ospf6_interface
->interface
))
90 if (IS_OSPF6_DUMP_INTERFACE
)
91 zlog_warn (" interface %s down, can't execute InterfaceUp",
92 ospf6_interface
->interface
->name
);
96 /* if already enabled, do nothing */
97 if (ospf6_interface
->state
> IFS_DOWN
)
99 zlog_warn ("Interface %s already up",
100 ospf6_interface
->interface
->name
);
104 /* ifid of this interface */
105 ospf6_interface
->if_id
= ospf6_interface
->interface
->ifindex
;
107 /* Join AllSPFRouters */
108 ospf6_join_allspfrouters (ospf6_interface
->interface
->ifindex
);
110 /* set socket options */
111 ospf6_set_reuseaddr ();
112 ospf6_reset_mcastloop ();
113 ospf6_set_pktinfo ();
114 ospf6_set_checksum ();
117 if (! CHECK_FLAG (ospf6_interface
->flag
, OSPF6_INTERFACE_FLAG_PASSIVE
))
118 thread_add_event (master
, ospf6_send_hello
, ospf6_interface
, 0);
120 /* decide next interface state */
121 if (if_is_pointopoint (ospf6_interface
->interface
))
122 ifs_change (IFS_PTOP
, "IF Type PointToPoint", ospf6_interface
);
123 else if (ospf6_interface
->priority
== 0)
124 ifs_change (IFS_DROTHER
, "Router Priority = 0", ospf6_interface
);
127 ifs_change (IFS_WAITING
, "Priority > 0", ospf6_interface
);
128 thread_add_timer (master
, wait_timer
, ospf6_interface
,
129 ospf6_interface
->dead_interval
);
132 CALL_FOREACH_LSA_HOOK (hook_interface
, hook_change
, ospf6_interface
);
138 wait_timer (struct thread
*thread
)
140 struct ospf6_interface
*ospf6_interface
;
142 ospf6_interface
= (struct ospf6_interface
*)THREAD_ARG (thread
);
143 assert (ospf6_interface
);
145 if (ospf6_interface
->state
!= IFS_WAITING
)
148 if (IS_OSPF6_DUMP_INTERFACE
)
149 zlog_info ("I/F: %s: WaitTimer", ospf6_interface
->interface
->name
);
151 ifs_change (dr_election (ospf6_interface
),
152 "WaitTimer:DR Election", ospf6_interface
);
156 int backup_seen (struct thread
*thread
)
158 struct ospf6_interface
*ospf6_interface
;
160 ospf6_interface
= (struct ospf6_interface
*)THREAD_ARG (thread
);
161 assert (ospf6_interface
);
163 if (IS_OSPF6_DUMP_INTERFACE
)
164 zlog_info ("I/F: %s: BackupSeen", ospf6_interface
->interface
->name
);
166 if (ospf6_interface
->state
== IFS_WAITING
)
167 ifs_change (dr_election (ospf6_interface
),
168 "BackupSeen:DR Election", ospf6_interface
);
173 int neighbor_change (struct thread
*thread
)
175 struct ospf6_interface
*ospf6_interface
;
177 ospf6_interface
= (struct ospf6_interface
*)THREAD_ARG (thread
);
178 assert (ospf6_interface
);
180 if (ospf6_interface
->state
!= IFS_DROTHER
&&
181 ospf6_interface
->state
!= IFS_BDR
&&
182 ospf6_interface
->state
!= IFS_DR
)
185 if (IS_OSPF6_DUMP_INTERFACE
)
186 zlog_info ("I/F: %s: NeighborChange", ospf6_interface
->interface
->name
);
188 ifs_change (dr_election (ospf6_interface
),
189 "NeighborChange:DR Election", ospf6_interface
);
195 loopind (struct thread
*thread
)
197 struct ospf6_interface
*ospf6_interface
;
199 ospf6_interface
= (struct ospf6_interface
*)THREAD_ARG (thread
);
200 assert (ospf6_interface
);
202 if (IS_OSPF6_DUMP_INTERFACE
)
203 zlog_info ("I/F: %s: LoopInd", ospf6_interface
->interface
->name
);
211 interface_down (struct thread
*thread
)
213 struct ospf6_interface
*ospf6_interface
;
215 ospf6_interface
= (struct ospf6_interface
*) THREAD_ARG (thread
);
216 assert (ospf6_interface
);
218 if (IS_OSPF6_DUMP_INTERFACE
)
219 zlog_info ("I/F: %s: InterfaceDown", ospf6_interface
->interface
->name
);
221 if (ospf6_interface
->state
== IFS_NONE
)
224 /* Leave AllSPFRouters */
225 if (ospf6_interface_is_enabled (ospf6_interface
->interface
->ifindex
))
226 ospf6_leave_allspfrouters (ospf6_interface
->interface
->ifindex
);
228 ifs_change (IFS_DOWN
, "Configured", ospf6_interface
);
236 dr_election (struct ospf6_interface
*ospf6_interface
)
238 list candidate_list
= list_new ();
240 ifid_t prevdr
, prevbdr
, dr
= 0, bdr
;
241 struct ospf6_neighbor
*nbpi
, *nbpj
, myself
, *nbr
;
246 ospf6_interface
->ospf6_stat_dr_election
++;
248 /* pseudo neighbor "myself" */
249 memset (&myself
, 0, sizeof (myself
));
250 myself
.state
= NBS_TWOWAY
;
251 myself
.dr
= ospf6_interface
->dr
;
252 myself
.bdr
= ospf6_interface
->bdr
;
253 myself
.priority
= ospf6_interface
->priority
;
254 myself
.ifid
= ospf6_interface
->if_id
;
255 myself
.router_id
= ospf6_interface
->area
->ospf6
->router_id
;
259 ospf6_interface
->prevdr
= prevdr
= ospf6_interface
->dr
;
260 ospf6_interface
->prevbdr
= prevbdr
= ospf6_interface
->bdr
;
264 /* Calculate Backup Designated Router. */
265 /* Make Candidate list */
266 if (!list_isempty (candidate_list
))
267 list_delete_all_node (candidate_list
);
269 for (i
= listhead (ospf6_interface
->neighbor_list
); i
; nextnode (i
))
271 nbpi
= (struct ospf6_neighbor
*)getdata (i
);
272 if (nbpi
->priority
== 0)
274 if (nbpi
->state
< NBS_TWOWAY
)
276 if (nbpi
->dr
== nbpi
->router_id
)
278 if (nbpi
->bdr
== nbpi
->router_id
)
280 listnode_add (candidate_list
, nbpi
);
285 if (myself
.dr
!= myself
.router_id
)
287 if (myself
.bdr
== myself
.router_id
)
289 listnode_add (candidate_list
, &myself
);
294 for (i
= listhead (candidate_list
);
295 candidate_list
->count
> 1;
296 i
= listhead (candidate_list
))
301 nbpi
= (struct ospf6_neighbor
*)getdata (i
);
302 nbpj
= (struct ospf6_neighbor
*)getdata (j
);
306 if (nbpi
->bdr
!= nbpi
->router_id
)
308 listnode_delete (candidate_list
, nbpi
);
311 if (nbpj
->bdr
!= nbpj
->router_id
)
313 listnode_delete (candidate_list
, nbpj
);
319 if (nbpi
->priority
> nbpj
->priority
)
321 listnode_delete (candidate_list
, nbpj
);
324 else if (nbpi
->priority
< nbpj
->priority
)
326 listnode_delete (candidate_list
, nbpi
);
329 else /* equal, case of tie */
331 if (ntohl (nbpi
->router_id
) > ntohl (nbpj
->router_id
))
333 listnode_delete (candidate_list
, nbpj
);
336 else if (ntohl (nbpi
->router_id
) < ntohl (nbpj
->router_id
))
338 listnode_delete (candidate_list
, nbpi
);
346 if (!list_isempty (candidate_list
))
348 assert (candidate_list
->count
== 1);
349 n
= listhead (candidate_list
);
350 nbr
= (struct ospf6_neighbor
*)getdata (n
);
351 bdr
= nbr
->router_id
;
358 /* Calculate Designated Router. */
359 /* Make Candidate list */
360 if (!list_isempty (candidate_list
))
361 list_delete_all_node (candidate_list
);
363 for (i
= listhead (ospf6_interface
->neighbor_list
); i
; nextnode (i
))
365 nbpi
= (struct ospf6_neighbor
*)getdata (i
);
366 if (nbpi
->priority
== 0)
368 if (nbpi
->state
< NBS_TWOWAY
)
370 if (nbpi
->dr
== nbpi
->router_id
)
373 listnode_add (candidate_list
, nbpi
);
378 if (myself
.dr
== myself
.router_id
)
381 listnode_add (candidate_list
, &myself
);
388 assert (list_isempty (candidate_list
));
389 /* No one declare but candidate_list not empty */
394 assert (!list_isempty (candidate_list
));
395 for (i
= listhead (candidate_list
);
396 candidate_list
->count
> 1;
397 i
= listhead (candidate_list
))
402 nbpi
= (struct ospf6_neighbor
*)getdata (i
);
403 nbpj
= (struct ospf6_neighbor
*)getdata (j
);
405 if (nbpi
->dr
!= nbpi
->router_id
)
407 list_delete_node (candidate_list
, i
);
410 if (nbpj
->dr
!= nbpj
->router_id
)
412 list_delete_node (candidate_list
, j
);
416 if (nbpi
->priority
> nbpj
->priority
)
418 list_delete_node (candidate_list
, j
);
421 else if (nbpi
->priority
< nbpj
->priority
)
423 list_delete_node (candidate_list
, i
);
426 else /* equal, case of tie */
428 if (ntohl (nbpi
->router_id
) > ntohl (nbpj
->router_id
))
430 list_delete_node (candidate_list
, j
);
433 else if (ntohl (nbpi
->router_id
) < ntohl (nbpj
->router_id
))
435 list_delete_node (candidate_list
, i
);
440 zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR");
441 zlog_warn ("!!!MISCONFIGURATION?");
442 list_delete_node (candidate_list
, i
);
447 if (!list_isempty (candidate_list
))
449 assert (candidate_list
->count
== 1);
450 n
= listhead (candidate_list
);
451 nbr
= (struct ospf6_neighbor
*)getdata (n
);
465 if ((dr
== myself
.router_id
|| prevdr
== myself
.router_id
)
466 && !(dr
== myself
.router_id
&& prevdr
== myself
.router_id
))
476 if ((bdr
== myself
.router_id
|| prevbdr
== myself
.router_id
)
477 && !(bdr
== myself
.router_id
&& prevbdr
== myself
.router_id
))
488 ospf6_interface
->dr
= dr
;
489 ospf6_interface
->bdr
= bdr
;
491 if (prevdr
!= dr
|| prevbdr
!= bdr
)
493 for (i
= listhead (ospf6_interface
->neighbor_list
); i
; nextnode (i
))
496 if (nbpi
->state
< NBS_TWOWAY
)
498 /* Schedule or Execute AdjOK. which does "invoke" mean? */
499 thread_add_event (master
, adj_ok
, nbpi
, 0);
503 list_delete (candidate_list
);
505 if (dr
== myself
.router_id
)
507 assert (bdr
!= myself
.router_id
);
510 else if (bdr
== myself
.router_id
)
512 assert (dr
!= myself
.router_id
);