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