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