]>
Commit | Line | Data |
---|---|---|
4364b47e OF |
1 | /* |
2 | * BIRD -- OSPF | |
3 | * | |
70945cb6 OZ |
4 | * (c) 1999--2004 Ondrej Filip <feela@network.cz> |
5 | * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org> | |
6 | * (c) 2009--2014 CZ.NIC z.s.p.o. | |
4364b47e OF |
7 | * |
8 | * Can be freely distributed and used under the terms of the GNU GPL. | |
9 | */ | |
10 | ||
11 | #include "ospf.h" | |
12 | ||
f8fefde3 OZ |
13 | |
14 | const char *ospf_ns_names[] = { | |
15 | "Down", "Attempt", "Init", "2-Way", "ExStart", "Exchange", "Loading", "Full" | |
2e10a170 OF |
16 | }; |
17 | ||
f8fefde3 OZ |
18 | const char *ospf_inm_names[] = { |
19 | "HelloReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone", | |
20 | "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived", | |
21 | "KillNbr", "InactivityTimer", "LLDown" | |
2e10a170 | 22 | }; |
79f036ef | 23 | |
f8fefde3 OZ |
24 | |
25 | static int can_do_adj(struct ospf_neighbor *n); | |
6f8bbaa1 OZ |
26 | static void inactivity_timer_hook(timer * timer); |
27 | static void dbdes_timer_hook(timer *t); | |
28 | static void lsrq_timer_hook(timer *t); | |
29 | static void lsrt_timer_hook(timer *t); | |
30 | static void ackd_timer_hook(timer *t); | |
31 | ||
0844b65d OZ |
32 | |
33 | static void | |
a7a7372a | 34 | init_lists(struct ospf_proto *p, struct ospf_neighbor *n) |
0844b65d OZ |
35 | { |
36 | s_init_list(&(n->lsrql)); | |
6f8bbaa1 | 37 | n->lsrqi = SHEAD(n->lsrql); |
a7a7372a | 38 | n->lsrqh = ospf_top_new(p, n->pool); |
0844b65d OZ |
39 | |
40 | s_init_list(&(n->lsrtl)); | |
a7a7372a OZ |
41 | n->lsrth = ospf_top_new(p, n->pool); |
42 | } | |
43 | ||
44 | static void | |
45 | release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n) | |
46 | { | |
47 | struct top_hash_entry *ret, *en; | |
48 | ||
49 | WALK_SLIST(ret, n->lsrtl) | |
50 | { | |
51 | en = ospf_hash_find_entry(p->gr, ret); | |
52 | if (en) | |
53 | en->ret_count--; | |
54 | } | |
0844b65d | 55 | } |
39e517d4 | 56 | |
0dd7ccc7 | 57 | /* Resets LSA request and retransmit lists. |
742029eb | 58 | * We do not reset DB summary list iterator here, |
0844b65d OZ |
59 | * it is reset during entering EXCHANGE state. |
60 | */ | |
61 | static void | |
a7a7372a | 62 | reset_lists(struct ospf_proto *p, struct ospf_neighbor *n) |
0844b65d | 63 | { |
6f8bbaa1 | 64 | release_lsrtl(p, n); |
0844b65d OZ |
65 | ospf_top_free(n->lsrqh); |
66 | ospf_top_free(n->lsrth); | |
6f8bbaa1 OZ |
67 | ospf_reset_lsack_queue(n); |
68 | ||
69 | tm_stop(n->dbdes_timer); | |
70 | tm_stop(n->lsrq_timer); | |
71 | tm_stop(n->lsrt_timer); | |
72 | tm_stop(n->ackd_timer); | |
73 | ||
a7a7372a | 74 | init_lists(p, n); |
0844b65d | 75 | } |
39e517d4 OF |
76 | |
77 | struct ospf_neighbor * | |
78 | ospf_neighbor_new(struct ospf_iface *ifa) | |
79 | { | |
70945cb6 OZ |
80 | struct ospf_proto *p = ifa->oa->po; |
81 | struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor"); | |
39e517d4 OF |
82 | struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor)); |
83 | ||
84 | n->pool = pool; | |
85 | n->ifa = ifa; | |
86 | add_tail(&ifa->neigh_list, NODE n); | |
87 | n->adj = 0; | |
3e2bd0f1 | 88 | n->csn = 0; |
2e10a170 | 89 | n->state = NEIGHBOR_DOWN; |
39e517d4 | 90 | |
a7a7372a | 91 | init_lists(p, n); |
70945cb6 | 92 | s_init(&(n->dbsi), &(p->lsal)); |
0844b65d | 93 | |
c76ba51a OF |
94 | init_list(&n->ackl[ACKL_DIRECT]); |
95 | init_list(&n->ackl[ACKL_DELAY]); | |
6f8bbaa1 OZ |
96 | |
97 | n->inactim = tm_new_set(pool, inactivity_timer_hook, n, 0, 0); | |
98 | n->dbdes_timer = tm_new_set(pool, dbdes_timer_hook, n, 0, ifa->rxmtint); | |
99 | n->lsrq_timer = tm_new_set(pool, lsrq_timer_hook, n, 0, ifa->rxmtint); | |
100 | n->lsrt_timer = tm_new_set(pool, lsrt_timer_hook, n, 0, ifa->rxmtint); | |
101 | n->ackd_timer = tm_new_set(pool, ackd_timer_hook, n, 0, ifa->rxmtint / 2); | |
39e517d4 | 102 | |
2e10a170 | 103 | return (n); |
39e517d4 OF |
104 | } |
105 | ||
f8fefde3 OZ |
106 | static void |
107 | ospf_neigh_down(struct ospf_neighbor *n) | |
108 | { | |
109 | struct ospf_iface *ifa = n->ifa; | |
110 | struct ospf_proto *p = ifa->oa->po; | |
a459f4df | 111 | u32 rid = n->rid; |
f8fefde3 OZ |
112 | |
113 | if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) | |
114 | { | |
115 | struct nbma_node *nn = find_nbma_node(ifa, n->ip); | |
116 | if (nn) | |
117 | nn->found = 0; | |
118 | } | |
119 | ||
120 | s_get(&(n->dbsi)); | |
121 | release_lsrtl(p, n); | |
122 | rem_node(NODE n); | |
123 | rfree(n->pool); | |
124 | ||
a459f4df | 125 | OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", rid, ifa->ifname); |
f8fefde3 OZ |
126 | } |
127 | ||
7ab3ff6a | 128 | /** |
f8fefde3 | 129 | * ospf_neigh_chstate - handles changes related to new or lod state of neighbor |
7ab3ff6a OF |
130 | * @n: OSPF neighbor |
131 | * @state: new state | |
132 | * | |
baa5dd6c | 133 | * Many actions have to be taken acording to a change of state of a neighbor. It |
7ab3ff6a OF |
134 | * starts rxmt timers, call interface state machine etc. |
135 | */ | |
0844b65d | 136 | static void |
f8fefde3 | 137 | ospf_neigh_chstate(struct ospf_neighbor *n, u8 state) |
4364b47e | 138 | { |
70945cb6 OZ |
139 | struct ospf_iface *ifa = n->ifa; |
140 | struct ospf_proto *p = ifa->oa->po; | |
141 | u8 old_state = n->state; | |
142 | int old_fadj = ifa->fadj; | |
4364b47e | 143 | |
70945cb6 OZ |
144 | if (state == old_state) |
145 | return; | |
eae4fcf2 | 146 | |
f8fefde3 OZ |
147 | OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed state from %s to %s", |
148 | n->rid, ifa->ifname, ospf_ns_names[old_state], ospf_ns_names[state]); | |
4057093f | 149 | |
70945cb6 | 150 | n->state = state; |
4057093f | 151 | |
70945cb6 OZ |
152 | /* Increase number of partial adjacencies */ |
153 | if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING)) | |
154 | p->padj++; | |
4057093f | 155 | |
70945cb6 OZ |
156 | /* Decrease number of partial adjacencies */ |
157 | if ((old_state == NEIGHBOR_EXCHANGE) || (old_state == NEIGHBOR_LOADING)) | |
158 | p->padj--; | |
2e10a170 | 159 | |
70945cb6 OZ |
160 | /* Increase number of full adjacencies */ |
161 | if (state == NEIGHBOR_FULL) | |
162 | ifa->fadj++; | |
163 | ||
164 | /* Decrease number of full adjacencies */ | |
165 | if (old_state == NEIGHBOR_FULL) | |
166 | ifa->fadj--; | |
167 | ||
168 | if (ifa->fadj != old_fadj) | |
169 | { | |
170 | /* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */ | |
171 | ospf_notify_rt_lsa(ifa->oa); | |
172 | ospf_notify_net_lsa(ifa); | |
173 | ||
174 | /* RFC 2328 12.4 Event 8 - vlink state change */ | |
175 | if (ifa->type == OSPF_IT_VLINK) | |
176 | ospf_notify_rt_lsa(ifa->voa); | |
177 | } | |
178 | ||
179 | if (state == NEIGHBOR_EXSTART) | |
180 | { | |
181 | /* First time adjacency */ | |
182 | if (n->adj == 0) | |
183 | n->dds = random_u32(); | |
184 | ||
185 | n->dds++; | |
186 | n->myimms = DBDES_IMMS; | |
6f8bbaa1 OZ |
187 | |
188 | tm_start(n->dbdes_timer, 0); | |
189 | tm_start(n->ackd_timer, ifa->rxmtint / 2); | |
4364b47e | 190 | } |
70945cb6 OZ |
191 | |
192 | if (state > NEIGHBOR_EXSTART) | |
193 | n->myimms &= ~DBDES_I; | |
4364b47e | 194 | |
f8fefde3 OZ |
195 | /* Generate NeighborChange event if needed, see RFC 2328 9.2 */ |
196 | if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY)) | |
197 | ospf_iface_sm(ifa, ISM_NEICH); | |
198 | if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY)) | |
199 | ospf_iface_sm(ifa, ISM_NEICH); | |
4364b47e OF |
200 | } |
201 | ||
7ab3ff6a OF |
202 | /** |
203 | * ospf_neigh_sm - ospf neighbor state machine | |
204 | * @n: neighor | |
205 | * @event: actual event | |
206 | * | |
baa5dd6c OF |
207 | * This part implements the neighbor state machine as described in 10.3 of |
208 | * RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not | |
209 | * used. We discover neighbors on nonbroadcast networks in the | |
210 | * same way as on broadcast networks. The only difference is in | |
211 | * sending hello packets. These are sent to IPs listed in | |
7ab3ff6a OF |
212 | * @ospf_iface->nbma_list . |
213 | */ | |
4364b47e OF |
214 | void |
215 | ospf_neigh_sm(struct ospf_neighbor *n, int event) | |
4364b47e | 216 | { |
70945cb6 | 217 | struct ospf_proto *p = n->ifa->oa->po; |
4364b47e | 218 | |
f8fefde3 OZ |
219 | DBG("Neighbor state machine for %R on %s, event %s\n", |
220 | n->rid, n->ifa->ifname, ospf_inm_names[event]); | |
79f036ef | 221 | |
2e10a170 | 222 | switch (event) |
4364b47e | 223 | { |
2e10a170 | 224 | case INM_START: |
f8fefde3 | 225 | ospf_neigh_chstate(n, NEIGHBOR_ATTEMPT); |
2e10a170 OF |
226 | /* NBMA are used different way */ |
227 | break; | |
70945cb6 | 228 | |
2e10a170 | 229 | case INM_HELLOREC: |
f8fefde3 OZ |
230 | if (n->state < NEIGHBOR_INIT) |
231 | ospf_neigh_chstate(n, NEIGHBOR_INIT); | |
70945cb6 OZ |
232 | |
233 | /* Restart inactivity timer */ | |
234 | tm_start(n->inactim, n->ifa->deadint); | |
2e10a170 | 235 | break; |
70945cb6 | 236 | |
2e10a170 OF |
237 | case INM_2WAYREC: |
238 | if (n->state < NEIGHBOR_2WAY) | |
f8fefde3 | 239 | ospf_neigh_chstate(n, NEIGHBOR_2WAY); |
2e10a170 | 240 | if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n)) |
f8fefde3 | 241 | ospf_neigh_chstate(n, NEIGHBOR_EXSTART); |
2e10a170 | 242 | break; |
70945cb6 | 243 | |
2e10a170 OF |
244 | case INM_NEGDONE: |
245 | if (n->state == NEIGHBOR_EXSTART) | |
246 | { | |
f8fefde3 | 247 | ospf_neigh_chstate(n, NEIGHBOR_EXCHANGE); |
0844b65d OZ |
248 | |
249 | /* Reset DB summary list iterator */ | |
250 | s_get(&(n->dbsi)); | |
70945cb6 | 251 | s_init(&(n->dbsi), &p->lsal); |
0844b65d | 252 | |
a7a7372a OZ |
253 | /* Add MaxAge LSA entries to retransmission list */ |
254 | ospf_add_flushed_to_lsrt(p, n); | |
2e10a170 OF |
255 | } |
256 | else | |
257 | bug("NEGDONE and I'm not in EXSTART?"); | |
258 | break; | |
70945cb6 | 259 | |
2e10a170 | 260 | case INM_EXDONE: |
6f8bbaa1 OZ |
261 | if (!EMPTY_SLIST(n->lsrql)) |
262 | ospf_neigh_chstate(n, NEIGHBOR_LOADING); | |
263 | else | |
264 | ospf_neigh_chstate(n, NEIGHBOR_FULL); | |
2e10a170 | 265 | break; |
70945cb6 | 266 | |
2e10a170 | 267 | case INM_LOADDONE: |
f8fefde3 | 268 | ospf_neigh_chstate(n, NEIGHBOR_FULL); |
2e10a170 | 269 | break; |
70945cb6 | 270 | |
2e10a170 | 271 | case INM_ADJOK: |
6f8bbaa1 OZ |
272 | /* Can In build adjacency? */ |
273 | if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n)) | |
2e10a170 | 274 | { |
6f8bbaa1 OZ |
275 | ospf_neigh_chstate(n, NEIGHBOR_EXSTART); |
276 | } | |
277 | else if ((n->state >= NEIGHBOR_EXSTART) && !can_do_adj(n)) | |
278 | { | |
279 | reset_lists(p, n); | |
280 | ospf_neigh_chstate(n, NEIGHBOR_2WAY); | |
2e10a170 OF |
281 | } |
282 | break; | |
70945cb6 | 283 | |
2e10a170 OF |
284 | case INM_SEQMIS: |
285 | case INM_BADLSREQ: | |
286 | if (n->state >= NEIGHBOR_EXCHANGE) | |
287 | { | |
a7a7372a | 288 | reset_lists(p, n); |
f8fefde3 | 289 | ospf_neigh_chstate(n, NEIGHBOR_EXSTART); |
2e10a170 OF |
290 | } |
291 | break; | |
70945cb6 | 292 | |
2e10a170 OF |
293 | case INM_KILLNBR: |
294 | case INM_LLDOWN: | |
295 | case INM_INACTTIM: | |
f8fefde3 OZ |
296 | /* No need for reset_lists() */ |
297 | ospf_neigh_chstate(n, NEIGHBOR_DOWN); | |
298 | ospf_neigh_down(n); | |
2e10a170 | 299 | break; |
70945cb6 | 300 | |
2e10a170 | 301 | case INM_1WAYREC: |
a7a7372a | 302 | reset_lists(p, n); |
f8fefde3 | 303 | ospf_neigh_chstate(n, NEIGHBOR_INIT); |
2e10a170 | 304 | break; |
70945cb6 | 305 | |
2e10a170 | 306 | default: |
70945cb6 | 307 | bug("%s: INM - Unknown event?", p->p.name); |
2e10a170 | 308 | break; |
4364b47e OF |
309 | } |
310 | } | |
311 | ||
f8fefde3 OZ |
312 | static int |
313 | can_do_adj(struct ospf_neighbor *n) | |
314 | { | |
315 | struct ospf_iface *ifa = n->ifa; | |
316 | struct ospf_proto *p = ifa->oa->po; | |
317 | int i = 0; | |
318 | ||
319 | switch (ifa->type) | |
320 | { | |
321 | case OSPF_IT_PTP: | |
322 | case OSPF_IT_PTMP: | |
323 | case OSPF_IT_VLINK: | |
324 | i = 1; | |
325 | break; | |
326 | case OSPF_IT_BCAST: | |
327 | case OSPF_IT_NBMA: | |
328 | switch (ifa->state) | |
329 | { | |
330 | case OSPF_IS_DOWN: | |
331 | case OSPF_IS_LOOP: | |
332 | bug("%s: Iface %s in down state?", p->p.name, ifa->ifname); | |
333 | break; | |
334 | case OSPF_IS_WAITING: | |
335 | DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname); | |
336 | break; | |
337 | case OSPF_IS_DROTHER: | |
338 | if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid)) | |
339 | && (n->state >= NEIGHBOR_2WAY)) | |
340 | i = 1; | |
341 | break; | |
342 | case OSPF_IS_PTP: | |
343 | case OSPF_IS_BACKUP: | |
344 | case OSPF_IS_DR: | |
345 | if (n->state >= NEIGHBOR_2WAY) | |
346 | i = 1; | |
347 | break; | |
348 | default: | |
349 | bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname); | |
350 | break; | |
351 | } | |
352 | break; | |
353 | default: | |
354 | bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname); | |
355 | break; | |
356 | } | |
357 | DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i); | |
358 | return i; | |
359 | } | |
360 | ||
361 | ||
362 | static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n) | |
363 | { return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; } | |
364 | ||
365 | static struct ospf_neighbor * | |
366 | elect_bdr(struct ospf_proto *p, list nl) | |
367 | { | |
368 | struct ospf_neighbor *neigh, *n1, *n2; | |
369 | u32 nid; | |
370 | ||
371 | n1 = NULL; | |
372 | n2 = NULL; | |
373 | WALK_LIST(neigh, nl) /* First try those decl. themselves */ | |
374 | { | |
375 | nid = neigh_get_id(p, neigh); | |
376 | ||
377 | if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ | |
378 | if (neigh->priority > 0) /* Eligible */ | |
379 | if (neigh->dr != nid) /* And not decl. itself DR */ | |
380 | { | |
381 | if (neigh->bdr == nid) /* Declaring BDR */ | |
382 | { | |
383 | if (n1 != NULL) | |
384 | { | |
385 | if (neigh->priority > n1->priority) | |
386 | n1 = neigh; | |
387 | else if (neigh->priority == n1->priority) | |
388 | if (neigh->rid > n1->rid) | |
389 | n1 = neigh; | |
390 | } | |
391 | else | |
392 | { | |
393 | n1 = neigh; | |
394 | } | |
395 | } | |
396 | else /* And NOT declaring BDR */ | |
397 | { | |
398 | if (n2 != NULL) | |
399 | { | |
400 | if (neigh->priority > n2->priority) | |
401 | n2 = neigh; | |
402 | else if (neigh->priority == n2->priority) | |
403 | if (neigh->rid > n2->rid) | |
404 | n2 = neigh; | |
405 | } | |
406 | else | |
407 | { | |
408 | n2 = neigh; | |
409 | } | |
410 | } | |
411 | } | |
412 | } | |
413 | if (n1 == NULL) | |
414 | n1 = n2; | |
415 | ||
416 | return (n1); | |
417 | } | |
418 | ||
419 | static struct ospf_neighbor * | |
420 | elect_dr(struct ospf_proto *p, list nl) | |
421 | { | |
422 | struct ospf_neighbor *neigh, *n; | |
423 | u32 nid; | |
424 | ||
425 | n = NULL; | |
426 | WALK_LIST(neigh, nl) /* And now DR */ | |
427 | { | |
428 | nid = neigh_get_id(p, neigh); | |
429 | ||
430 | if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ | |
431 | if (neigh->priority > 0) /* Eligible */ | |
432 | if (neigh->dr == nid) /* And declaring itself DR */ | |
433 | { | |
434 | if (n != NULL) | |
435 | { | |
436 | if (neigh->priority > n->priority) | |
437 | n = neigh; | |
438 | else if (neigh->priority == n->priority) | |
439 | if (neigh->rid > n->rid) | |
440 | n = neigh; | |
441 | } | |
442 | else | |
443 | { | |
444 | n = neigh; | |
445 | } | |
446 | } | |
447 | } | |
448 | ||
449 | return (n); | |
450 | } | |
451 | ||
7ab3ff6a | 452 | /** |
70945cb6 | 453 | * ospf_dr_election - (Backup) Designed Router election |
7ab3ff6a OF |
454 | * @ifa: actual interface |
455 | * | |
baa5dd6c | 456 | * When the wait timer fires, it is time to elect (Backup) Designated Router. |
f8fefde3 OZ |
457 | * Structure describing me is added to this list so every electing router has |
458 | * the same list. Backup Designated Router is elected before Designated | |
459 | * Router. This process is described in 9.4 of RFC 2328. The function is | |
460 | * supposed to be called only from ospf_iface_sm() as a part of the interface | |
461 | * state machine. | |
7ab3ff6a | 462 | */ |
4364b47e | 463 | void |
70945cb6 | 464 | ospf_dr_election(struct ospf_iface *ifa) |
4364b47e | 465 | { |
70945cb6 | 466 | struct ospf_proto *p = ifa->oa->po; |
2e10a170 | 467 | struct ospf_neighbor *neigh, *ndr, *nbdr, me; |
70945cb6 | 468 | u32 myid = p->router_id; |
4364b47e | 469 | |
423230f2 | 470 | DBG("(B)DR election.\n"); |
4364b47e | 471 | |
2e10a170 OF |
472 | me.state = NEIGHBOR_2WAY; |
473 | me.rid = myid; | |
474 | me.priority = ifa->priority; | |
353729f5 | 475 | me.ip = ifa->addr->ip; |
4364b47e | 476 | |
70945cb6 OZ |
477 | me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid; |
478 | me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid; | |
dd4da6f6 | 479 | me.iface_id = ifa->iface_id; |
c3226991 | 480 | |
2e10a170 | 481 | add_tail(&ifa->neigh_list, NODE & me); |
4364b47e | 482 | |
70945cb6 OZ |
483 | nbdr = elect_bdr(p, ifa->neigh_list); |
484 | ndr = elect_dr(p, ifa->neigh_list); | |
4364b47e | 485 | |
2e10a170 OF |
486 | if (ndr == NULL) |
487 | ndr = nbdr; | |
4364b47e | 488 | |
c3226991 | 489 | /* 9.4. (4) */ |
2e10a170 OF |
490 | if (((ifa->drid == myid) && (ndr != &me)) |
491 | || ((ifa->drid != myid) && (ndr == &me)) | |
492 | || ((ifa->bdrid == myid) && (nbdr != &me)) | |
493 | || ((ifa->bdrid != myid) && (nbdr == &me))) | |
4364b47e | 494 | { |
70945cb6 OZ |
495 | me.dr = ndr ? neigh_get_id(p, ndr) : 0; |
496 | me.bdr = nbdr ? neigh_get_id(p, nbdr) : 0; | |
2e10a170 | 497 | |
70945cb6 OZ |
498 | nbdr = elect_bdr(p, ifa->neigh_list); |
499 | ndr = elect_dr(p, ifa->neigh_list); | |
423230f2 | 500 | |
c3226991 OZ |
501 | if (ndr == NULL) |
502 | ndr = nbdr; | |
28950169 OF |
503 | } |
504 | ||
70945cb6 OZ |
505 | rem_node(NODE & me); |
506 | ||
507 | ||
508 | u32 old_drid = ifa->drid; | |
509 | u32 old_bdrid = ifa->bdrid; | |
742029eb | 510 | |
c3226991 OZ |
511 | ifa->drid = ndr ? ndr->rid : 0; |
512 | ifa->drip = ndr ? ndr->ip : IPA_NONE; | |
70945cb6 OZ |
513 | ifa->dr_iface_id = ndr ? ndr->iface_id : 0; |
514 | ||
c3226991 OZ |
515 | ifa->bdrid = nbdr ? nbdr->rid : 0; |
516 | ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE; | |
517 | ||
3aab39f5 | 518 | DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid); |
4364b47e | 519 | |
f8fefde3 | 520 | /* We are part of the interface state machine */ |
70945cb6 | 521 | if (ifa->drid == myid) |
2e10a170 | 522 | ospf_iface_chstate(ifa, OSPF_IS_DR); |
70945cb6 OZ |
523 | else if (ifa->bdrid == myid) |
524 | ospf_iface_chstate(ifa, OSPF_IS_BACKUP); | |
4364b47e | 525 | else |
70945cb6 | 526 | ospf_iface_chstate(ifa, OSPF_IS_DROTHER); |
4364b47e | 527 | |
70945cb6 OZ |
528 | /* Review neighbor adjacencies if DR or BDR changed */ |
529 | if ((ifa->drid != old_drid) || (ifa->bdrid != old_bdrid)) | |
2e10a170 | 530 | WALK_LIST(neigh, ifa->neigh_list) |
70945cb6 OZ |
531 | if (neigh->state >= NEIGHBOR_2WAY) |
532 | ospf_neigh_sm(neigh, INM_ADJOK); | |
533 | ||
534 | /* RFC 2328 12.4 Event 3 - DR change */ | |
535 | if (ifa->drid != old_drid) | |
536 | ospf_notify_rt_lsa(ifa->oa); | |
4364b47e OF |
537 | } |
538 | ||
539 | struct ospf_neighbor * | |
540 | find_neigh(struct ospf_iface *ifa, u32 rid) | |
541 | { | |
542 | struct ospf_neighbor *n; | |
919f5411 OZ |
543 | WALK_LIST(n, ifa->neigh_list) |
544 | if (n->rid == rid) | |
545 | return n; | |
546 | return NULL; | |
547 | } | |
4364b47e | 548 | |
919f5411 OZ |
549 | struct ospf_neighbor * |
550 | find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip) | |
551 | { | |
552 | struct ospf_neighbor *n; | |
553 | WALK_LIST(n, ifa->neigh_list) | |
554 | if (ipa_equal(n->ip, ip)) | |
555 | return n; | |
4364b47e OF |
556 | return NULL; |
557 | } | |
558 | ||
0844b65d | 559 | static void |
6f8bbaa1 | 560 | inactivity_timer_hook(timer * timer) |
c7e46aae | 561 | { |
86c84d76 | 562 | struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; |
f8fefde3 | 563 | struct ospf_proto *p = n->ifa->oa->po; |
a7a7372a | 564 | |
6f8bbaa1 | 565 | OSPF_TRACE(D_EVENTS, "Inactivity timer expired for nbr %R on %s", |
f8fefde3 OZ |
566 | n->rid, n->ifa->ifname); |
567 | ospf_neigh_sm(n, INM_INACTTIM); | |
18a0c0bb | 568 | } |
a783e259 | 569 | |
1ec52253 OZ |
570 | static void |
571 | ospf_neigh_bfd_hook(struct bfd_request *req) | |
572 | { | |
573 | struct ospf_neighbor *n = req->data; | |
70945cb6 | 574 | struct ospf_proto *p = n->ifa->oa->po; |
1ec52253 OZ |
575 | |
576 | if (req->down) | |
577 | { | |
6f8bbaa1 | 578 | OSPF_TRACE(D_EVENTS, "BFD session down for nbr %R on %s", |
f8fefde3 OZ |
579 | n->rid, n->ifa->ifname); |
580 | ospf_neigh_sm(n, INM_INACTTIM); | |
1ec52253 OZ |
581 | } |
582 | } | |
583 | ||
584 | void | |
585 | ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd) | |
586 | { | |
587 | if (use_bfd && !n->bfd_req) | |
588 | n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip, n->ifa->iface, | |
589 | ospf_neigh_bfd_hook, n); | |
590 | ||
591 | if (!use_bfd && n->bfd_req) | |
592 | { | |
593 | rfree(n->bfd_req); | |
594 | n->bfd_req = NULL; | |
595 | } | |
596 | } | |
597 | ||
598 | ||
6f8bbaa1 OZ |
599 | static void |
600 | dbdes_timer_hook(timer *t) | |
601 | { | |
602 | struct ospf_neighbor *n = t->data; | |
603 | struct ospf_proto *p = n->ifa->oa->po; | |
604 | ||
605 | // OSPF_TRACE(D_EVENTS, "DBDES timer expired for nbr %R on %s", n->rid, n->ifa->ifname); | |
606 | ||
607 | if (n->state == NEIGHBOR_EXSTART) | |
608 | ospf_send_dbdes(p, n); | |
609 | ||
610 | if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS)) | |
611 | ospf_rxmt_dbdes(p, n); | |
612 | } | |
613 | ||
614 | static void | |
615 | lsrq_timer_hook(timer *t) | |
616 | { | |
617 | struct ospf_neighbor *n = t->data; | |
618 | struct ospf_proto *p = n->ifa->oa->po; | |
619 | ||
620 | // OSPF_TRACE(D_EVENTS, "LSRQ timer expired for nbr %R on %s", n->rid, n->ifa->ifname); | |
621 | ||
622 | if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql)) | |
623 | ospf_send_lsreq(p, n); | |
624 | } | |
625 | ||
626 | static void | |
627 | lsrt_timer_hook(timer *t) | |
628 | { | |
629 | struct ospf_neighbor *n = t->data; | |
630 | struct ospf_proto *p = n->ifa->oa->po; | |
631 | ||
632 | // OSPF_TRACE(D_EVENTS, "LSRT timer expired for nbr %R on %s", n->rid, n->ifa->ifname); | |
633 | ||
634 | if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl)) | |
635 | ospf_rxmt_lsupd(p, n); | |
636 | } | |
637 | ||
638 | static void | |
639 | ackd_timer_hook(timer *t) | |
640 | { | |
641 | struct ospf_neighbor *n = t->data; | |
642 | struct ospf_proto *p = n->ifa->oa->po; | |
643 | ||
644 | ospf_send_lsack(p, n, ACKL_DELAY); | |
645 | } | |
646 | ||
647 | ||
a783e259 OF |
648 | void |
649 | ospf_sh_neigh_info(struct ospf_neighbor *n) | |
650 | { | |
2e10a170 | 651 | struct ospf_iface *ifa = n->ifa; |
6f8bbaa1 | 652 | char *pos = "PtP "; |
2e10a170 OF |
653 | char etime[6]; |
654 | int exp, sec, min; | |
655 | ||
656 | exp = n->inactim->expires - now; | |
6eb4b73f OF |
657 | sec = exp % 60; |
658 | min = exp / 60; | |
2e10a170 OF |
659 | if (min > 59) |
660 | { | |
661 | bsprintf(etime, "-Inf-"); | |
662 | } | |
663 | else | |
664 | { | |
665 | bsprintf(etime, "%02u:%02u", min, sec); | |
666 | } | |
667 | ||
f8fefde3 OZ |
668 | if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) |
669 | { | |
670 | if (n->rid == ifa->drid) | |
6f8bbaa1 | 671 | pos = "DR "; |
f8fefde3 | 672 | else if (n->rid == ifa->bdrid) |
6f8bbaa1 | 673 | pos = "BDR "; |
f8fefde3 | 674 | else |
6f8bbaa1 | 675 | pos = "Other"; |
f8fefde3 | 676 | } |
2e10a170 | 677 | |
cf31112f | 678 | cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority, |
f8fefde3 | 679 | ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip); |
a783e259 | 680 | } |