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