]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_ism.c
Merge pull request #5851 from volta-networks/feat_ldp_oc_review
[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 *ospf_dr_election_sub(struct list *routers)
52 {
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 }
70 }
71
72 return max;
73 }
74
75 static struct ospf_neighbor *ospf_elect_dr(struct ospf_interface *oi,
76 struct list *el_list)
77 {
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;
110 }
111
112 static struct ospf_neighbor *ospf_elect_bdr(struct ospf_interface *oi,
113 struct list *el_list)
114 {
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;
151 }
152
153 static int ospf_ism_state(struct ospf_interface *oi)
154 {
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;
161 }
162
163 static void ospf_dr_eligible_routers(struct route_table *nbrs,
164 struct list *el_list)
165 {
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 != INADDR_ANY)
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);
178 }
179
180 /* Generate AdjOK? NSM event. */
181 static void ospf_dr_change(struct ospf *ospf, struct route_table *nbrs)
182 {
183 struct route_node *rn;
184 struct ospf_neighbor *nbr;
185
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 }
202 }
203
204 static int 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 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 ospf_hello_timer(struct thread *thread)
252 {
253 struct ospf_interface *oi;
254
255 oi = THREAD_ARG(thread);
256 oi->t_hello = NULL;
257
258 if (IS_DEBUG_OSPF(ism, ISM_TIMERS))
259 zlog_debug("ISM[%s]: Timer (Hello timer expire)", IF_NAME(oi));
260
261 /* Sending hello packet. */
262 ospf_hello_send(oi);
263
264 /* Hello timer set. */
265 OSPF_HELLO_TIMER_ON(oi);
266
267 return 0;
268 }
269
270 static int ospf_wait_timer(struct thread *thread)
271 {
272 struct ospf_interface *oi;
273
274 oi = THREAD_ARG(thread);
275 oi->t_wait = NULL;
276
277 if (IS_DEBUG_OSPF(ism, ISM_TIMERS))
278 zlog_debug("ISM[%s]: Timer (Wait timer expire)", IF_NAME(oi));
279
280 OSPF_ISM_EVENT_SCHEDULE(oi, ISM_WaitTimer);
281
282 return 0;
283 }
284
285 /* Hook function called after ospf ISM event is occurred. And vty's
286 network command invoke this function after making interface
287 structure. */
288 static void ism_timer_set(struct ospf_interface *oi)
289 {
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 }
358 }
359
360 static int ism_interface_up(struct ospf_interface *oi)
361 {
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;
384 }
385
386 static int ism_loop_ind(struct ospf_interface *oi)
387 {
388 /* call ism_interface_down. */
389 /* ret = ism_interface_down (oi); */
390
391 return 0;
392 }
393
394 /* Interface down event handler. */
395 static int ism_interface_down(struct ospf_interface *oi)
396 {
397 ospf_if_cleanup(oi);
398 return 0;
399 }
400
401
402 static int ism_backup_seen(struct ospf_interface *oi)
403 {
404 return ospf_dr_election(oi);
405 }
406
407 static int ism_wait_timer(struct ospf_interface *oi)
408 {
409 return ospf_dr_election(oi);
410 }
411
412 static int ism_neighbor_change(struct ospf_interface *oi)
413 {
414 return ospf_dr_election(oi);
415 }
416
417 static int ism_ignore(struct ospf_interface *oi)
418 {
419 if (IS_DEBUG_OSPF(ism, ISM_EVENTS))
420 zlog_debug("ISM[%s]: ism_ignore called", IF_NAME(oi));
421
422 return 0;
423 }
424
425 /* Interface State Machine */
426 const struct {
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
520 static const char *const ospf_ism_event_str[] = {
521 "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen",
522 "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown",
523 };
524
525 static void ism_change_state(struct ospf_interface *oi, int state)
526 {
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);
575 }
576
577 /* Execute ISM event process. */
578 int ospf_ism_event(struct thread *thread)
579 {
580 int event;
581 int next_state;
582 struct ospf_interface *oi;
583
584 oi = THREAD_ARG(thread);
585 event = THREAD_VAL(thread);
586
587 /* Call function. */
588 next_state = (*(ISM[oi->state][event].func))(oi);
589
590 if (!next_state)
591 next_state = ISM[oi->state][event].next_state;
592
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]);
597
598 /* If state is changed. */
599 if (next_state != oi->state)
600 ism_change_state(oi, next_state);
601
602 /* Make sure timer is set. */
603 ism_timer_set(oi);
604
605 return 0;
606 }