]>
Commit | Line | Data |
---|---|---|
6ba36f06 MM |
1 | /* |
2 | * BIRD -- OSPF Topological Database | |
3 | * | |
98ac6176 OF |
4 | * (c) 1999 Martin Mares <mj@ucw.cz> |
5 | * (c) 1999--2004 Ondrej Filip <feela@network.cz> | |
6ba36f06 MM |
6 | * |
7 | * Can be freely distributed and used under the terms of the GNU GPL. | |
8 | */ | |
9 | ||
6ba36f06 | 10 | #include "nest/bird.h" |
221135d6 | 11 | #include "lib/string.h" |
6ba36f06 MM |
12 | |
13 | #include "ospf.h" | |
14 | ||
8d56febe | 15 | #define HASH_DEF_ORDER 6 |
6ba36f06 MM |
16 | #define HASH_HI_MARK *4 |
17 | #define HASH_HI_STEP 2 | |
18 | #define HASH_HI_MAX 16 | |
19 | #define HASH_LO_MARK /5 | |
20 | #define HASH_LO_STEP 2 | |
21 | #define HASH_LO_MIN 8 | |
22 | ||
b49e6f5a OZ |
23 | void originate_prefix_rt_lsa(struct ospf_area *oa); |
24 | void originate_prefix_net_lsa(struct ospf_iface *ifa); | |
061ab802 | 25 | void flush_prefix_net_lsa(struct ospf_iface *ifa); |
b49e6f5a OZ |
26 | |
27 | #ifdef OSPFv2 | |
28 | #define ipa_to_rid(x) _I(x) | |
29 | #else /* OSPFv3 */ | |
30 | #define ipa_to_rid(x) _I3(x) | |
31 | #endif | |
32 | ||
d82fc18d | 33 | |
b49e6f5a | 34 | #ifdef OSPFv2 |
d82fc18d OZ |
35 | static inline u32 |
36 | fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) | |
37 | { | |
38 | /* We have to map IP prefixes to u32 in such manner that resulting | |
39 | u32 interpreted as IP address is a member of given | |
40 | prefix. Therefore, /32 prefix have to be mapped on itself. | |
41 | All received prefixes have to be mapped on different u32s. | |
42 | ||
43 | We have an assumption that if there is nontrivial (non-/32) | |
44 | network prefix, then there is not /32 prefix for the first | |
45 | and the last IP address of the network (these are usually | |
46 | reserved, therefore it is not an important restriction). | |
47 | The network prefix is mapped to the first or the last | |
48 | IP address in the manner that disallow collisions - we | |
49 | use IP address that cannot be used by parent prefix. | |
50 | ||
51 | For example: | |
52 | 192.168.0.0/24 maps to 192.168.0.255 | |
53 | 192.168.1.0/24 maps to 192.168.1.0 | |
54 | because 192.168.0.0 and 192.168.1.255 might be used by | |
55 | 192.168.0.0/23 . | |
56 | ||
57 | This is not compatible with older RFC 1583, so we have an option | |
58 | to the RFC 1583 compatible assignment (that always uses the first | |
59 | address) which disallows subnetting. | |
60 | ||
61 | Appendig E of RFC 2328 suggests different algorithm, that tries | |
62 | to maximize both compatibility and subnetting. But as it is not | |
63 | possible to have both reliably and the suggested algorithm was | |
64 | unnecessary complicated and it does crazy things like changing | |
65 | LSA ID for a network because different network appeared, we | |
66 | choose a different way. */ | |
67 | ||
68 | u32 id = _I(fn->prefix); | |
69 | ||
70 | if ((po->rfc1583) || (fn->pxlen == 0) || (fn->pxlen == 32)) | |
71 | return id; | |
72 | ||
73 | if (id & (1 << (32 - fn->pxlen))) | |
74 | return id; | |
75 | else | |
76 | return id | ~u32_mkmask(fn->pxlen); | |
77 | } | |
78 | ||
b49e6f5a | 79 | #else /* OSPFv3 */ |
d82fc18d OZ |
80 | |
81 | static inline u32 | |
82 | fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) | |
83 | { | |
6384c7d7 OZ |
84 | /* |
85 | * In OSPFv3, it is simpler. There is not a requirement for | |
86 | * membership of the result in the input network, so we just use a | |
87 | * hash-based unique ID of a routing table entry for a route that | |
88 | * originated given LSA. For ext-LSA, it is an imported route in the | |
89 | * nest's routing table (p->table). For summary-LSA, it is a | |
90 | * 'source' route in the protocol internal routing table (po->rtf). | |
91 | */ | |
d82fc18d OZ |
92 | return fn->uid; |
93 | } | |
94 | ||
b49e6f5a OZ |
95 | #endif |
96 | ||
97 | ||
3d15dcdb OZ |
98 | static void * |
99 | lsab_alloc(struct proto_ospf *po, unsigned size) | |
100 | { | |
101 | unsigned offset = po->lsab_used; | |
102 | po->lsab_used += size; | |
103 | if (po->lsab_used > po->lsab_size) | |
104 | { | |
105 | po->lsab_size = MAX(po->lsab_used, 2 * po->lsab_size); | |
6a8d3f1c OZ |
106 | po->lsab = po->lsab ? mb_realloc(po->lsab, po->lsab_size): |
107 | mb_alloc(po->proto.pool, po->lsab_size); | |
3d15dcdb OZ |
108 | } |
109 | return ((byte *) po->lsab) + offset; | |
110 | } | |
111 | ||
112 | static inline void * | |
113 | lsab_allocz(struct proto_ospf *po, unsigned size) | |
114 | { | |
115 | void *r = lsab_alloc(po, size); | |
116 | bzero(r, size); | |
117 | return r; | |
118 | } | |
119 | ||
120 | static inline void * | |
121 | lsab_flush(struct proto_ospf *po) | |
122 | { | |
f0160f0e | 123 | void *r = mb_alloc(po->proto.pool, po->lsab_used); |
3d15dcdb OZ |
124 | memcpy(r, po->lsab, po->lsab_used); |
125 | po->lsab_used = 0; | |
126 | return r; | |
127 | } | |
128 | ||
c3226991 OZ |
129 | static inline void * |
130 | lsab_offset(struct proto_ospf *po, unsigned offset) | |
131 | { | |
132 | return ((byte *) po->lsab) + offset; | |
133 | } | |
134 | ||
135 | static inline void * | |
136 | lsab_end(struct proto_ospf *po) | |
137 | { | |
138 | return ((byte *) po->lsab) + po->lsab_used; | |
139 | } | |
140 | ||
52572e94 OZ |
141 | static s32 |
142 | get_seqnum(struct top_hash_entry *en) | |
143 | { | |
144 | if (!en) | |
145 | return LSA_INITSEQNO; | |
146 | ||
147 | if (en->lsa.sn == LSA_MAXSEQNO) | |
148 | { | |
d395fe48 | 149 | log(L_WARN "OSPF: Premature origination of LSA (Type: %04x, Id: %R, Rt: %R)", |
52572e94 OZ |
150 | en->lsa.type, en->lsa.id, en->lsa.rt); |
151 | return LSA_INITSEQNO; | |
152 | } | |
153 | ||
74add5df | 154 | return en->lsa.sn + 1; |
52572e94 OZ |
155 | } |
156 | ||
c3226991 | 157 | |
38675202 OZ |
158 | static int |
159 | configured_stubnet(struct ospf_area *oa, struct ifa *a) | |
160 | { | |
5cdf264f OZ |
161 | if (!oa->ac) |
162 | return 0; | |
163 | ||
52a43ae3 | 164 | /* Does not work for IA_PEER addresses, but it is not called on these */ |
38675202 OZ |
165 | struct ospf_stubnet_config *sn; |
166 | WALK_LIST(sn, oa->ac->stubnet_list) | |
167 | { | |
168 | if (sn->summary) | |
169 | { | |
170 | if (ipa_in_net(a->prefix, sn->px.addr, sn->px.len) && (a->pxlen >= sn->px.len)) | |
171 | return 1; | |
172 | } | |
173 | else | |
174 | { | |
175 | if (ipa_equal(a->prefix, sn->px.addr) && (a->pxlen == sn->px.len)) | |
176 | return 1; | |
177 | } | |
178 | } | |
179 | return 0; | |
180 | } | |
3d15dcdb | 181 | |
c3226991 OZ |
182 | int |
183 | bcast_net_active(struct ospf_iface *ifa) | |
184 | { | |
185 | struct ospf_neighbor *neigh; | |
186 | ||
187 | if (ifa->state == OSPF_IS_WAITING) | |
188 | return 0; | |
189 | ||
190 | WALK_LIST(neigh, ifa->neigh_list) | |
191 | { | |
192 | if (neigh->state == NEIGHBOR_FULL) | |
193 | { | |
194 | if (neigh->rid == ifa->drid) | |
195 | return 1; | |
196 | ||
197 | if (ifa->state == OSPF_IS_DR) | |
198 | return 1; | |
199 | } | |
200 | } | |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
205 | ||
206 | #ifdef OSPFv2 | |
207 | ||
9831e591 | 208 | static void * |
c3226991 | 209 | originate_rt_lsa_body(struct ospf_area *oa, u16 *length) |
ce17d4c1 | 210 | { |
b9ed99f7 | 211 | struct proto_ospf *po = oa->po; |
ce17d4c1 | 212 | struct ospf_iface *ifa; |
c3226991 | 213 | int i = 0, bitv = 0; |
ce17d4c1 | 214 | struct ospf_lsa_rt *rt; |
3d15dcdb | 215 | struct ospf_lsa_rt_link *ln; |
ce17d4c1 | 216 | struct ospf_neighbor *neigh; |
ce17d4c1 | 217 | |
3d15dcdb OZ |
218 | ASSERT(po->lsab_used == 0); |
219 | rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); | |
c3226991 | 220 | |
f9c799a0 | 221 | rt->options = 0; |
c3226991 | 222 | |
b9ed99f7 | 223 | if (po->areano > 1) |
c3226991 OZ |
224 | rt->options |= OPT_RT_B; |
225 | ||
4160a9dd OZ |
226 | if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator) |
227 | rt->options |= OPT_RT_NT; | |
228 | ||
41b612c3 | 229 | if (po->ebit && !oa_is_stub(oa)) |
c3226991 OZ |
230 | rt->options |= OPT_RT_E; |
231 | ||
3d15dcdb | 232 | rt = NULL; /* buffer might be reallocated later */ |
b9ed99f7 OF |
233 | |
234 | WALK_LIST(ifa, po->iface_list) | |
ce17d4c1 | 235 | { |
353729f5 | 236 | int net_lsa = 0; |
f623ab98 | 237 | u32 link_cost = po->stub_router ? 0xffff : ifa->cost; |
3d15dcdb OZ |
238 | |
239 | if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && | |
240 | (!EMPTY_LIST(ifa->neigh_list))) | |
5d3f5552 OF |
241 | { |
242 | neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); | |
243 | if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) | |
3d15dcdb | 244 | bitv = 1; |
5d3f5552 | 245 | } |
3b16080c OF |
246 | |
247 | if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) | |
b9ed99f7 | 248 | continue; |
3b580a23 | 249 | |
e7b4948c OZ |
250 | ifa->rt_pos_beg = i; |
251 | ||
919f5411 | 252 | /* RFC2328 - 12.4.1.1-4 */ |
3d15dcdb | 253 | switch (ifa->type) |
ce17d4c1 | 254 | { |
919f5411 OZ |
255 | case OSPF_IT_PTP: |
256 | case OSPF_IT_PTMP: | |
257 | WALK_LIST(neigh, ifa->neigh_list) | |
258 | if (neigh->state == NEIGHBOR_FULL) | |
259 | { | |
260 | ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); | |
261 | ln->type = LSART_PTP; | |
262 | ln->id = neigh->rid; | |
6cadbf32 OZ |
263 | |
264 | /* | |
265 | * ln->data should be ifa->iface_id in case of no/ptp | |
266 | * address (ifa->addr->flags & IA_PEER) on PTP link (see | |
267 | * RFC 2328 12.4.1.1.), but the iface ID value has no use, | |
268 | * while using IP address even in this case is here for | |
269 | * compatibility with some broken implementations that use | |
270 | * this address as a next-hop. | |
271 | */ | |
272 | ln->data = ipa_to_u32(ifa->addr->ip); | |
f623ab98 | 273 | ln->metric = link_cost; |
919f5411 OZ |
274 | ln->padding = 0; |
275 | i++; | |
276 | } | |
b9ed99f7 | 277 | break; |
3d15dcdb | 278 | |
919f5411 | 279 | case OSPF_IT_BCAST: |
b9ed99f7 | 280 | case OSPF_IT_NBMA: |
c3226991 | 281 | if (bcast_net_active(ifa)) |
b9ed99f7 | 282 | { |
3d15dcdb | 283 | ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); |
b9ed99f7 OF |
284 | ln->type = LSART_NET; |
285 | ln->id = ipa_to_u32(ifa->drip); | |
353729f5 | 286 | ln->data = ipa_to_u32(ifa->addr->ip); |
f623ab98 | 287 | ln->metric = link_cost; |
c15e5690 | 288 | ln->padding = 0; |
3d15dcdb | 289 | i++; |
353729f5 | 290 | net_lsa = 1; |
b9ed99f7 | 291 | } |
b9ed99f7 | 292 | break; |
3d15dcdb | 293 | |
919f5411 | 294 | case OSPF_IT_VLINK: |
98ac6176 OF |
295 | neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); |
296 | if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) | |
297 | { | |
3d15dcdb | 298 | ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); |
98ac6176 OF |
299 | ln->type = LSART_VLNK; |
300 | ln->id = neigh->rid; | |
353729f5 | 301 | ln->data = ipa_to_u32(ifa->addr->ip); |
f623ab98 | 302 | ln->metric = link_cost; |
c15e5690 | 303 | ln->padding = 0; |
3d15dcdb | 304 | i++; |
12dd8dc8 OF |
305 | } |
306 | break; | |
3d15dcdb | 307 | |
12dd8dc8 | 308 | default: |
48e5f32d | 309 | log("Unknown interface type %s", ifa->ifname); |
98ac6176 | 310 | break; |
ce17d4c1 | 311 | } |
3d15dcdb | 312 | |
e7b4948c OZ |
313 | ifa->rt_pos_end = i; |
314 | ||
0aad2b92 OZ |
315 | /* Now we will originate stub area if there is no primary */ |
316 | if (net_lsa || | |
317 | (ifa->type == OSPF_IT_VLINK) || | |
a55a90fa | 318 | ((ifa->addr->flags & IA_PEER) && ! ifa->cf->stub) || |
0aad2b92 OZ |
319 | configured_stubnet(oa, ifa->addr)) |
320 | continue; | |
3d15dcdb | 321 | |
0aad2b92 | 322 | ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); |
52a43ae3 OZ |
323 | if ((ifa->addr->flags & IA_HOST) || |
324 | (ifa->state == OSPF_IS_LOOP) || | |
325 | (ifa->type == OSPF_IT_PTMP)) | |
d9e7e1b1 OZ |
326 | { |
327 | /* Host stub entry */ | |
328 | ln->type = LSART_STUB; | |
329 | ln->id = ipa_to_u32(ifa->addr->ip); | |
330 | ln->data = 0xffffffff; | |
331 | ln->metric = 0; | |
332 | ln->padding = 0; | |
333 | } | |
334 | else | |
335 | { | |
336 | /* Network stub entry */ | |
337 | ln->type = LSART_STUB; | |
338 | ln->id = ipa_to_u32(ifa->addr->prefix); | |
339 | ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen)); | |
340 | ln->metric = ifa->cost; | |
341 | ln->padding = 0; | |
342 | } | |
0aad2b92 | 343 | i++; |
e7b4948c OZ |
344 | |
345 | ifa->rt_pos_end = i; | |
ce17d4c1 | 346 | } |
3d15dcdb | 347 | |
38675202 | 348 | struct ospf_stubnet_config *sn; |
5cdf264f OZ |
349 | if (oa->ac) |
350 | WALK_LIST(sn, oa->ac->stubnet_list) | |
351 | if (!sn->hidden) | |
38675202 OZ |
352 | { |
353 | ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); | |
354 | ln->type = LSART_STUB; | |
355 | ln->id = ipa_to_u32(sn->px.addr); | |
356 | ln->data = ipa_to_u32(ipa_mkmask(sn->px.len)); | |
357 | ln->metric = sn->cost; | |
c15e5690 | 358 | ln->padding = 0; |
38675202 OZ |
359 | i++; |
360 | } | |
361 | ||
3d15dcdb | 362 | rt = po->lsab; |
b9ed99f7 | 363 | rt->links = i; |
c3226991 OZ |
364 | |
365 | if (bitv) | |
366 | rt->options |= OPT_RT_V; | |
367 | ||
3d15dcdb OZ |
368 | *length = po->lsab_used + sizeof(struct ospf_lsa_header); |
369 | return lsab_flush(po); | |
ce17d4c1 | 370 | } |
c45f48fb | 371 | |
c3226991 OZ |
372 | #else /* OSPFv3 */ |
373 | ||
374 | static void | |
375 | add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, u32 id) | |
376 | { | |
377 | struct ospf_lsa_rt_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); | |
378 | ln->type = type; | |
379 | ln->padding = 0; | |
380 | ln->metric = ifa->cost; | |
dd4da6f6 | 381 | ln->lif = ifa->iface_id; |
c3226991 OZ |
382 | ln->nif = nif; |
383 | ln->id = id; | |
384 | } | |
385 | ||
386 | static void * | |
387 | originate_rt_lsa_body(struct ospf_area *oa, u16 *length) | |
388 | { | |
389 | struct proto_ospf *po = oa->po; | |
390 | struct ospf_iface *ifa; | |
b49e6f5a | 391 | int bitv = 0; |
e7b4948c | 392 | int i = 0; |
c3226991 OZ |
393 | struct ospf_lsa_rt *rt; |
394 | struct ospf_neighbor *neigh; | |
395 | ||
c3226991 OZ |
396 | ASSERT(po->lsab_used == 0); |
397 | rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); | |
398 | ||
399 | rt->options = oa->options & OPTIONS_MASK; | |
400 | ||
401 | if (po->areano > 1) | |
402 | rt->options |= OPT_RT_B; | |
403 | ||
4160a9dd OZ |
404 | if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator) |
405 | rt->options |= OPT_RT_NT; | |
406 | ||
41b612c3 | 407 | if (po->ebit && !oa_is_stub(oa)) |
c3226991 OZ |
408 | rt->options |= OPT_RT_E; |
409 | ||
410 | rt = NULL; /* buffer might be reallocated later */ | |
411 | ||
412 | WALK_LIST(ifa, po->iface_list) | |
413 | { | |
414 | if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && | |
415 | (!EMPTY_LIST(ifa->neigh_list))) | |
416 | { | |
417 | neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); | |
418 | if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) | |
419 | bitv = 1; | |
420 | } | |
421 | ||
422 | if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) | |
423 | continue; | |
424 | ||
e7b4948c OZ |
425 | ifa->rt_pos_beg = i; |
426 | ||
c3226991 OZ |
427 | /* RFC5340 - 4.4.3.2 */ |
428 | switch (ifa->type) | |
429 | { | |
430 | case OSPF_IT_PTP: | |
919f5411 OZ |
431 | case OSPF_IT_PTMP: |
432 | WALK_LIST(neigh, ifa->neigh_list) | |
433 | if (neigh->state == NEIGHBOR_FULL) | |
e7b4948c | 434 | add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid), i++; |
c3226991 OZ |
435 | break; |
436 | ||
437 | case OSPF_IT_BCAST: | |
438 | case OSPF_IT_NBMA: | |
439 | if (bcast_net_active(ifa)) | |
e7b4948c | 440 | add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid), i++; |
c3226991 OZ |
441 | break; |
442 | ||
443 | case OSPF_IT_VLINK: | |
444 | neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); | |
445 | if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) | |
e7b4948c | 446 | add_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid), i++; |
c3226991 OZ |
447 | break; |
448 | ||
449 | default: | |
48e5f32d | 450 | log("Unknown interface type %s", ifa->ifname); |
c3226991 OZ |
451 | break; |
452 | } | |
e7b4948c OZ |
453 | |
454 | ifa->rt_pos_end = i; | |
c3226991 OZ |
455 | } |
456 | ||
457 | if (bitv) | |
458 | { | |
459 | rt = po->lsab; | |
460 | rt->options |= OPT_RT_V; | |
461 | } | |
462 | ||
463 | *length = po->lsab_used + sizeof(struct ospf_lsa_header); | |
464 | return lsab_flush(po); | |
465 | } | |
466 | ||
467 | #endif | |
468 | ||
7ab3ff6a OF |
469 | /** |
470 | * originate_rt_lsa - build new instance of router LSA | |
471 | * @oa: ospf_area which is LSA built to | |
472 | * | |
473 | * It builds router LSA walking through all OSPF interfaces in | |
474 | * specified OSPF area. This function is mostly called from | |
475 | * area_disp(). Builds new LSA, increases sequence number (if old | |
476 | * instance exists) and sets age of LSA to zero. | |
477 | */ | |
9bc1808a | 478 | void |
70a38319 | 479 | originate_rt_lsa(struct ospf_area *oa) |
d8852b36 OF |
480 | { |
481 | struct ospf_lsa_header lsa; | |
b9ed99f7 OF |
482 | struct proto_ospf *po = oa->po; |
483 | struct proto *p = &po->proto; | |
d8852b36 OF |
484 | void *body; |
485 | ||
be862406 | 486 | OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid); |
b9ed99f7 OF |
487 | |
488 | lsa.age = 0; | |
b9ed99f7 | 489 | lsa.type = LSA_T_RT; |
c3226991 OZ |
490 | |
491 | #ifdef OSPFv2 | |
492 | lsa.options = oa->options; | |
8a70a13e | 493 | lsa.id = po->router_id; |
cf31112f OZ |
494 | #else /* OSPFv3 */ |
495 | lsa.id = 0; | |
496 | #endif | |
497 | ||
8a70a13e | 498 | lsa.rt = po->router_id; |
52572e94 | 499 | lsa.sn = get_seqnum(oa->rt); |
c3226991 OZ |
500 | u32 dom = oa->areaid; |
501 | ||
b9ed99f7 | 502 | body = originate_rt_lsa_body(oa, &lsa.length); |
d5d9693c | 503 | lsasum_calculate(&lsa, body); |
b49e6f5a OZ |
504 | oa->rt = lsa_install_new(po, &lsa, dom, body); |
505 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); | |
506 | } | |
507 | ||
508 | void | |
509 | update_rt_lsa(struct ospf_area *oa) | |
510 | { | |
511 | struct proto_ospf *po = oa->po; | |
512 | ||
513 | if ((oa->rt) && ((oa->rt->inst_t + MINLSINTERVAL)) > now) | |
514 | return; | |
515 | /* | |
516 | * Tick is probably set to very low value. We cannot | |
517 | * originate new LSA before MINLSINTERVAL. We will | |
518 | * try to do it next tick. | |
519 | */ | |
520 | ||
521 | originate_rt_lsa(oa); | |
f9c799a0 | 522 | #ifdef OSPFv3 |
b49e6f5a | 523 | originate_prefix_rt_lsa(oa); |
f9c799a0 | 524 | #endif |
b49e6f5a | 525 | |
b8f17cf1 | 526 | schedule_rtcalc(po); |
b9ed99f7 | 527 | oa->origrt = 0; |
ab56f6b1 OF |
528 | } |
529 | ||
9831e591 | 530 | static void * |
c3226991 | 531 | originate_net_lsa_body(struct ospf_iface *ifa, u16 *length, |
b9ed99f7 | 532 | struct proto_ospf *po) |
0bf2f203 | 533 | { |
b9ed99f7 | 534 | u16 i = 1; |
0bf2f203 | 535 | struct ospf_neighbor *n; |
d345cda5 | 536 | struct ospf_lsa_net *net; |
c3226991 OZ |
537 | int nodes = ifa->fadj + 1; |
538 | ||
539 | net = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_net) | |
540 | + nodes * sizeof(u32)); | |
0bf2f203 | 541 | |
c3226991 | 542 | #ifdef OSPFv2 |
353729f5 | 543 | net->netmask = ipa_mkmask(ifa->addr->pxlen); |
c3226991 OZ |
544 | #endif |
545 | ||
546 | #ifdef OSPFv3 | |
547 | /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */ | |
548 | struct top_hash_entry *en; | |
549 | u32 options = 0; | |
550 | #endif | |
551 | ||
8a70a13e | 552 | net->routers[0] = po->router_id; |
d345cda5 | 553 | |
b9ed99f7 | 554 | WALK_LIST(n, ifa->neigh_list) |
0bf2f203 | 555 | { |
b9ed99f7 | 556 | if (n->state == NEIGHBOR_FULL) |
0bf2f203 | 557 | { |
c3226991 | 558 | #ifdef OSPFv3 |
dd4da6f6 | 559 | en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK); |
c3226991 OZ |
560 | if (en) |
561 | options |= ((struct ospf_lsa_link *) en->lsa_body)->options; | |
562 | #endif | |
563 | ||
564 | net->routers[i] = n->rid; | |
0bf2f203 OF |
565 | i++; |
566 | } | |
567 | } | |
c3226991 OZ |
568 | ASSERT(i == nodes); |
569 | ||
570 | #ifdef OSPFv3 | |
571 | net->options = options & OPTIONS_MASK; | |
572 | #endif | |
573 | ||
574 | *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_net) | |
575 | + nodes * sizeof(u32); | |
d345cda5 | 576 | return net; |
0bf2f203 OF |
577 | } |
578 | ||
b49e6f5a | 579 | |
7ab3ff6a OF |
580 | /** |
581 | * originate_net_lsa - originates of deletes network LSA | |
582 | * @ifa: interface which is LSA originated for | |
583 | * | |
baa5dd6c OF |
584 | * Interface counts number of adjacent neighbors. If this number is |
585 | * lower than one or interface is not in state %OSPF_IS_DR it deletes | |
7ab3ff6a OF |
586 | * and premature ages instance of network LSA for specified interface. |
587 | * In other case, new instance of network LSA is originated. | |
588 | */ | |
9bc1808a | 589 | void |
7ab3ff6a | 590 | originate_net_lsa(struct ospf_iface *ifa) |
0bf2f203 | 591 | { |
86c84d76 | 592 | struct proto_ospf *po = ifa->oa->po; |
8a70a13e | 593 | struct proto *p = &po->proto; |
0bf2f203 | 594 | struct ospf_lsa_header lsa; |
c3226991 | 595 | u32 dom = ifa->oa->areaid; |
8a70a13e | 596 | |
0bf2f203 OF |
597 | void *body; |
598 | ||
48e5f32d | 599 | OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname); |
b9ed99f7 OF |
600 | |
601 | lsa.age = 0; | |
b9ed99f7 | 602 | lsa.type = LSA_T_NET; |
c3226991 OZ |
603 | |
604 | #ifdef OSPFv2 | |
605 | lsa.options = ifa->oa->options; | |
353729f5 | 606 | lsa.id = ipa_to_u32(ifa->addr->ip); |
c3226991 | 607 | #else /* OSPFv3 */ |
dd4da6f6 | 608 | lsa.id = ifa->iface_id; |
c3226991 OZ |
609 | #endif |
610 | ||
8a70a13e | 611 | lsa.rt = po->router_id; |
52572e94 | 612 | lsa.sn = get_seqnum(ifa->net_lsa); |
3dd8f983 | 613 | |
b9ed99f7 | 614 | body = originate_net_lsa_body(ifa, &lsa.length, po); |
d5d9693c | 615 | lsasum_calculate(&lsa, body); |
c3226991 OZ |
616 | ifa->net_lsa = lsa_install_new(po, &lsa, dom, body); |
617 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); | |
0bf2f203 OF |
618 | } |
619 | ||
b49e6f5a OZ |
620 | void |
621 | flush_net_lsa(struct ospf_iface *ifa) | |
622 | { | |
623 | struct proto_ospf *po = ifa->oa->po; | |
624 | struct proto *p = &po->proto; | |
625 | u32 dom = ifa->oa->areaid; | |
626 | ||
627 | if (ifa->net_lsa == NULL) | |
628 | return; | |
629 | ||
48e5f32d | 630 | OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->ifname); |
b49e6f5a OZ |
631 | ifa->net_lsa->lsa.sn += 1; |
632 | ifa->net_lsa->lsa.age = LSA_MAXAGE; | |
633 | lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body); | |
634 | ospf_lsupd_flood(po, NULL, NULL, &ifa->net_lsa->lsa, dom, 0); | |
b49e6f5a OZ |
635 | flush_lsa(ifa->net_lsa, po); |
636 | ifa->net_lsa = NULL; | |
637 | } | |
638 | ||
639 | void | |
640 | update_net_lsa(struct ospf_iface *ifa) | |
641 | { | |
642 | struct proto_ospf *po = ifa->oa->po; | |
643 | ||
644 | if (ifa->net_lsa && ((ifa->net_lsa->inst_t + MINLSINTERVAL) > now)) | |
645 | return; | |
646 | /* | |
647 | * It's too early to originate new network LSA. We will | |
648 | * try to do it next tick | |
649 | */ | |
650 | ||
651 | if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0)) | |
652 | { | |
653 | flush_net_lsa(ifa); | |
f9c799a0 | 654 | #ifdef OSPFv3 |
b49e6f5a | 655 | flush_prefix_net_lsa(ifa); |
f9c799a0 | 656 | #endif |
b49e6f5a OZ |
657 | } |
658 | else | |
659 | { | |
660 | originate_net_lsa(ifa); | |
f9c799a0 | 661 | #ifdef OSPFv3 |
b49e6f5a | 662 | originate_prefix_net_lsa(ifa); |
f9c799a0 | 663 | #endif |
b49e6f5a OZ |
664 | } |
665 | ||
666 | schedule_rtcalc(po); | |
667 | ifa->orignet = 0; | |
668 | } | |
98ac6176 | 669 | |
c3226991 OZ |
670 | #ifdef OSPFv2 |
671 | ||
9727681a | 672 | static inline void * |
c3226991 | 673 | originate_sum_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric) |
e8085aba | 674 | { |
c3226991 OZ |
675 | struct ospf_lsa_sum *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum)); |
676 | *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum); | |
e8085aba | 677 | |
c3226991 OZ |
678 | sum->netmask = ipa_mkmask(mlen); |
679 | sum->metric = metric; | |
e8085aba | 680 | |
c3226991 OZ |
681 | return sum; |
682 | } | |
5919c66e | 683 | |
c3226991 OZ |
684 | #define originate_sum_net_lsa_body(po,length,fn,metric) \ |
685 | originate_sum_lsa_body(po, length, (fn)->pxlen, metric) | |
b9ed99f7 | 686 | |
c3226991 OZ |
687 | #define originate_sum_rt_lsa_body(po,length,drid,metric,options) \ |
688 | originate_sum_lsa_body(po, length, 0, metric) | |
e8085aba | 689 | |
9727681a OZ |
690 | static inline int |
691 | check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en) | |
692 | { | |
693 | struct ospf_lsa_sum *sum = en->lsa_body; | |
98955023 | 694 | return fn->pxlen != ipa_mklen(sum->netmask); |
9727681a OZ |
695 | } |
696 | ||
697 | static inline int | |
7ff5803b | 698 | check_sum_lsa_same(struct top_hash_entry *en, u32 metric) |
9727681a | 699 | { |
7ff5803b OZ |
700 | /* Netmask already checked in check_sum_net_lsaid_collision() */ |
701 | struct ospf_lsa_sum *sum = en->lsa_body; | |
d395fe48 | 702 | return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); |
9727681a OZ |
703 | } |
704 | ||
7ff5803b OZ |
705 | #define check_sum_net_lsa_same(en,metric) \ |
706 | check_sum_lsa_same(en, metric) | |
707 | ||
708 | #define check_sum_rt_lsa_same(en,drid,metric,options) \ | |
709 | check_sum_lsa_same(en, metric) | |
710 | ||
711 | ||
c3226991 | 712 | #else /* OSPFv3 */ |
0077aab4 | 713 | |
9727681a | 714 | static inline void * |
c3226991 | 715 | originate_sum_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric) |
0077aab4 | 716 | { |
c3226991 OZ |
717 | int size = sizeof(struct ospf_lsa_sum_net) + IPV6_PREFIX_SPACE(fn->pxlen); |
718 | struct ospf_lsa_sum_net *sum = mb_alloc(po->proto.pool, size); | |
719 | *length = sizeof(struct ospf_lsa_header) + size; | |
720 | ||
721 | sum->metric = metric; | |
722 | put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0); | |
723 | ||
724 | return sum; | |
725 | } | |
726 | ||
9727681a OZ |
727 | static inline int |
728 | check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en) | |
729 | { | |
730 | struct ospf_lsa_sum_net *sum = en->lsa_body; | |
731 | ip_addr prefix; | |
732 | int pxlen; | |
733 | u8 pxopts; | |
734 | u16 rest; | |
735 | ||
736 | lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest); | |
737 | return (fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix); | |
738 | } | |
739 | ||
740 | static inline int | |
7ff5803b | 741 | check_sum_net_lsa_same(struct top_hash_entry *en, u32 metric) |
9727681a | 742 | { |
7ff5803b OZ |
743 | /* Prefix already checked in check_sum_net_lsaid_collision() */ |
744 | struct ospf_lsa_sum_net *sum = en->lsa_body; | |
d395fe48 | 745 | return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); |
9727681a OZ |
746 | } |
747 | ||
748 | static inline void * | |
c3226991 OZ |
749 | originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options) |
750 | { | |
751 | struct ospf_lsa_sum_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum_rt)); | |
752 | *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum_rt); | |
753 | ||
7ff5803b | 754 | sum->options = options; |
c3226991 OZ |
755 | sum->metric = metric; |
756 | sum->drid = drid; | |
757 | ||
758 | return sum; | |
0077aab4 MM |
759 | } |
760 | ||
7ff5803b OZ |
761 | static inline int |
762 | check_sum_rt_lsa_same(struct top_hash_entry *en, u32 drid, u32 metric, u32 options) | |
763 | { | |
764 | struct ospf_lsa_sum_rt *sum = en->lsa_body; | |
d395fe48 OZ |
765 | return (en->lsa.sn != LSA_MAXSEQNO) && (sum->options == options) && |
766 | (sum->metric == metric) && (sum->drid == drid); | |
7ff5803b OZ |
767 | } |
768 | ||
c3226991 OZ |
769 | #endif |
770 | ||
98ac6176 | 771 | void |
9727681a | 772 | originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) |
98ac6176 OF |
773 | { |
774 | struct proto_ospf *po = oa->po; | |
775 | struct proto *p = &po->proto; | |
776 | struct top_hash_entry *en; | |
9727681a | 777 | u32 dom = oa->areaid; |
98ac6176 | 778 | struct ospf_lsa_header lsa; |
c3226991 | 779 | void *body; |
98ac6176 | 780 | |
9727681a OZ |
781 | OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", |
782 | fn->prefix, fn->pxlen, metric); | |
c3226991 | 783 | |
9727681a | 784 | /* options argument is used in ORT_NET and OSPFv3 only */ |
c3226991 | 785 | lsa.age = 0; |
c3226991 OZ |
786 | #ifdef OSPFv2 |
787 | lsa.options = oa->options; | |
788 | #endif | |
9727681a OZ |
789 | lsa.type = LSA_T_SUM_NET; |
790 | lsa.id = fibnode_to_lsaid(po, fn); | |
8a70a13e | 791 | lsa.rt = po->router_id; |
98ac6176 | 792 | |
9727681a OZ |
793 | if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL) |
794 | { | |
795 | if (check_sum_net_lsaid_collision(fn, en)) | |
7ff5803b | 796 | { |
35c875f0 | 797 | log(L_ERR "%s: LSAID collision for %I/%d", |
7ff5803b OZ |
798 | p->name, fn->prefix, fn->pxlen); |
799 | return; | |
800 | } | |
801 | ||
802 | if (check_sum_net_lsa_same(en, metric)) | |
803 | return; | |
9727681a | 804 | } |
52572e94 | 805 | lsa.sn = get_seqnum(en); |
c3226991 | 806 | |
9727681a OZ |
807 | body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric); |
808 | lsasum_calculate(&lsa, body); | |
d494df63 | 809 | lsa_install_new(po, &lsa, dom, body); |
9727681a OZ |
810 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); |
811 | } | |
c3226991 | 812 | |
9727681a | 813 | void |
e81b440f | 814 | originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED) |
9727681a OZ |
815 | { |
816 | struct proto_ospf *po = oa->po; | |
817 | struct proto *p = &po->proto; | |
818 | struct top_hash_entry *en; | |
353729f5 OZ |
819 | u32 dom = oa->areaid; |
820 | u32 rid = ipa_to_rid(fn->prefix); | |
9727681a OZ |
821 | struct ospf_lsa_header lsa; |
822 | void *body; | |
c3226991 | 823 | |
9727681a | 824 | OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", |
353729f5 | 825 | rid, metric); |
9727681a OZ |
826 | |
827 | lsa.age = 0; | |
828 | #ifdef OSPFv2 | |
829 | lsa.options = oa->options; | |
830 | #endif | |
831 | lsa.type = LSA_T_SUM_RT; | |
832 | /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ | |
353729f5 | 833 | lsa.id = rid; |
8a70a13e | 834 | lsa.rt = po->router_id; |
9727681a | 835 | |
7ff5803b | 836 | options &= OPTIONS_MASK; |
9727681a | 837 | if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL) |
7ff5803b OZ |
838 | { |
839 | if (check_sum_rt_lsa_same(en, lsa.id, metric, options)) | |
840 | return; | |
7ff5803b | 841 | } |
52572e94 | 842 | lsa.sn = get_seqnum(en); |
c3226991 | 843 | |
9727681a | 844 | body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options); |
c3226991 | 845 | lsasum_calculate(&lsa, body); |
d494df63 | 846 | lsa_install_new(po, &lsa, dom, body); |
c3226991 | 847 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); |
98ac6176 OF |
848 | } |
849 | ||
98ac6176 | 850 | void |
c3226991 | 851 | flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) |
98ac6176 OF |
852 | { |
853 | struct proto_ospf *po = oa->po; | |
854 | struct proto *p = &po->proto; | |
855 | struct top_hash_entry *en; | |
98ac6176 | 856 | struct ospf_lsa_header lsa; |
98ac6176 | 857 | |
8a70a13e | 858 | lsa.rt = po->router_id; |
c3226991 | 859 | if (type == ORT_NET) |
98ac6176 | 860 | { |
d82fc18d | 861 | lsa.id = fibnode_to_lsaid(po, fn); |
c3226991 | 862 | lsa.type = LSA_T_SUM_NET; |
98ac6176 | 863 | } |
c3226991 | 864 | else |
98ac6176 | 865 | { |
9727681a | 866 | /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ |
c3226991 OZ |
867 | lsa.id = ipa_to_rid(fn->prefix); |
868 | lsa.type = LSA_T_SUM_RT; | |
98ac6176 | 869 | } |
98ac6176 | 870 | |
b49e6f5a | 871 | if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL) |
c3226991 | 872 | { |
bbcfd5a0 OZ |
873 | OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)", |
874 | en->lsa.id, en->lsa.type); | |
875 | ||
9727681a OZ |
876 | if ((type == ORT_NET) && check_sum_net_lsaid_collision(fn, en)) |
877 | { | |
35c875f0 | 878 | log(L_ERR "%s: LSAID collision for %I/%d", |
9727681a OZ |
879 | p->name, fn->prefix, fn->pxlen); |
880 | return; | |
881 | } | |
882 | ||
c3226991 OZ |
883 | struct ospf_lsa_sum *sum = en->lsa_body; |
884 | en->lsa.age = LSA_MAXAGE; | |
885 | en->lsa.sn = LSA_MAXSEQNO; | |
886 | lsasum_calculate(&en->lsa, sum); | |
c3226991 OZ |
887 | ospf_lsupd_flood(po, NULL, NULL, &en->lsa, oa->areaid, 1); |
888 | if (can_flush_lsa(po)) flush_lsa(en, po); | |
889 | } | |
98ac6176 OF |
890 | } |
891 | ||
7ff5803b | 892 | #ifdef OSPFv2 |
c3226991 | 893 | |
7ff5803b | 894 | static inline void * |
ed317862 | 895 | originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, |
2918e610 | 896 | u32 metric, ip_addr fwaddr, u32 tag, int pbit UNUSED) |
c3226991 | 897 | { |
7ff5803b OZ |
898 | struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext)); |
899 | *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext); | |
c3226991 | 900 | |
7ff5803b | 901 | ext->metric = metric; |
ed317862 | 902 | ext->netmask = ipa_mkmask(fn->pxlen); |
7ff5803b OZ |
903 | ext->fwaddr = fwaddr; |
904 | ext->tag = tag; | |
c3226991 | 905 | |
7ff5803b OZ |
906 | return ext; |
907 | } | |
c3226991 | 908 | |
7ff5803b OZ |
909 | /* |
910 | * check_ext_lsa() combines functions of check_*_lsaid_collision() and | |
911 | * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters | |
912 | * are parameters of new ext route. Function returns -1 if there is | |
913 | * LSAID collision, returns 1 if the existing LSA is the same and | |
914 | * returns 0 otherwise (in that case, we need to originate a new LSA). | |
915 | * | |
916 | * Really, checking for the same parameters is not as important as in | |
917 | * summary LSA origination, because in most cases the duplicate | |
918 | * external route propagation would be stopped by the nest. But there | |
919 | * are still some cases (route reload, the same route propagated through | |
920 | * different protocol) so it is also done here. | |
921 | */ | |
c3226991 | 922 | |
7ff5803b OZ |
923 | static inline int |
924 | check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) | |
925 | { | |
926 | struct ospf_lsa_ext *ext = en->lsa_body; | |
927 | ||
928 | /* LSAID collision */ | |
929 | if (fn->pxlen != ipa_mklen(ext->netmask)) | |
930 | return -1; | |
931 | ||
d395fe48 OZ |
932 | return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) && |
933 | (ext->tag == tag) && ipa_equal(ext->fwaddr,fwaddr); | |
7ff5803b | 934 | } |
c3226991 | 935 | |
c3226991 | 936 | #else /* OSPFv3 */ |
7ff5803b OZ |
937 | |
938 | static inline void * | |
ed317862 | 939 | originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, |
2918e610 | 940 | u32 metric, ip_addr fwaddr, u32 tag, int pbit) |
7ff5803b OZ |
941 | { |
942 | int size = sizeof(struct ospf_lsa_ext) | |
2918e610 | 943 | + IPV6_PREFIX_SPACE(fn->pxlen) |
7ff5803b OZ |
944 | + (ipa_nonzero(fwaddr) ? 16 : 0) |
945 | + (tag ? 4 : 0); | |
946 | ||
947 | struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, size); | |
948 | *length = sizeof(struct ospf_lsa_header) + size; | |
949 | ||
950 | ext->metric = metric; | |
951 | ||
e81b440f | 952 | u32 *buf = ext->rest; |
2918e610 | 953 | buf = put_ipv6_prefix(buf, fn->prefix, fn->pxlen, pbit ? OPT_PX_P : 0, 0); |
c3226991 | 954 | |
7ff5803b OZ |
955 | if (ipa_nonzero(fwaddr)) |
956 | { | |
957 | ext->metric |= LSA_EXT_FBIT; | |
958 | buf = put_ipv6_addr(buf, fwaddr); | |
959 | } | |
c3226991 OZ |
960 | |
961 | if (tag) | |
7ff5803b OZ |
962 | { |
963 | ext->metric |= LSA_EXT_TBIT; | |
964 | *buf++ = tag; | |
965 | } | |
c3226991 OZ |
966 | |
967 | return ext; | |
968 | } | |
969 | ||
7ff5803b OZ |
970 | static inline int |
971 | check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) | |
972 | { | |
973 | struct ospf_lsa_ext *ext = en->lsa_body; | |
974 | ip_addr prefix; | |
975 | int pxlen; | |
976 | u8 pxopts; | |
977 | u16 rest; | |
978 | ||
979 | u32 *buf = lsa_get_ipv6_prefix(ext->rest, &prefix, &pxlen, &pxopts, &rest); | |
980 | ||
981 | /* LSAID collision */ | |
982 | if ((fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix)) | |
983 | return -1; | |
984 | ||
d395fe48 OZ |
985 | if (en->lsa.sn == LSA_MAXSEQNO) |
986 | return 0; | |
987 | ||
7ff5803b OZ |
988 | u32 rt_metric = ext->metric & METRIC_MASK; |
989 | ip_addr rt_fwaddr = IPA_NONE; | |
990 | u32 rt_tag = 0; | |
991 | ||
992 | if (ext->metric & LSA_EXT_FBIT) | |
993 | buf = lsa_get_ipv6_addr(buf, &rt_fwaddr); | |
994 | ||
995 | if (ext->metric & LSA_EXT_TBIT) | |
996 | rt_tag = *buf++; | |
997 | ||
998 | return (rt_metric == metric) && ipa_equal(rt_fwaddr, fwaddr) && (rt_tag == tag); | |
999 | } | |
1000 | ||
1001 | ||
1002 | #endif | |
1003 | ||
2918e610 OZ |
1004 | static inline ip_addr |
1005 | find_surrogate_fwaddr(struct ospf_area *oa) | |
1006 | { | |
1007 | struct proto_ospf *po = oa->po; | |
1008 | struct ospf_iface *ifa; | |
1009 | struct ifa *a, *cur_addr = NULL; | |
1010 | int np, cur_np = 0; | |
1011 | ||
1012 | WALK_LIST(ifa, po->iface_list) | |
1013 | { | |
1014 | if ((ifa->oa != oa) || | |
2918e610 OZ |
1015 | (ifa->type == OSPF_IT_VLINK)) |
1016 | continue; | |
1017 | ||
1018 | #ifdef OSPFv2 | |
1019 | a = ifa->addr; | |
1020 | if (a->flags & IA_PEER) | |
1021 | continue; | |
1022 | ||
1023 | np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1; | |
1024 | if (np > cur_np) | |
1025 | { | |
1026 | cur_addr = a; | |
1027 | cur_np = np; | |
1028 | } | |
1029 | ||
1030 | #else /* OSPFv3 */ | |
1031 | WALK_LIST(a, ifa->iface->addrs) | |
1032 | { | |
1033 | if ((a->flags & IA_SECONDARY) || | |
1034 | (a->flags & IA_PEER) || | |
1035 | (a->scope <= SCOPE_LINK)) | |
1036 | continue; | |
1037 | ||
1038 | np = ((a->flags & IA_HOST) || ifa->stub) ? 2 : 1; | |
1039 | if (np > cur_np) | |
1040 | { | |
1041 | cur_addr = a; | |
1042 | cur_np = np; | |
1043 | } | |
1044 | } | |
1045 | #endif | |
1046 | } | |
1047 | ||
1048 | return cur_addr ? cur_addr->ip : IPA_NONE; | |
1049 | } | |
1050 | ||
1051 | ||
7ab3ff6a | 1052 | /** |
baa5dd6c | 1053 | * originate_ext_lsa - new route received from nest and filters |
41b612c3 | 1054 | * @oa: ospf_area for which LSA is originated |
ed317862 | 1055 | * @fn: network prefix and mask |
2918e610 | 1056 | * @src: the source of origination of the LSA (EXT_EXPORT/EXT_NSSA) |
ed317862 OZ |
1057 | * @metric: the metric of a route |
1058 | * @fwaddr: the forwarding address | |
1059 | * @tag: the route tag | |
2918e610 | 1060 | * @pbit: P-bit for NSSA LSAs, ignored for external LSAs |
7ab3ff6a | 1061 | * |
baa5dd6c | 1062 | * If I receive a message that new route is installed, I try to originate an |
41b612c3 | 1063 | * external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead. |
2918e610 OZ |
1064 | * @oa should not be a stub area. @src does not specify whether the LSA |
1065 | * is external or NSSA, but it specifies the source of origination - | |
1066 | * the export from ospf_rt_notify(), or the NSSA-EXT translation. | |
fdb19982 | 1067 | * |
baa5dd6c | 1068 | * The function also sets flag ebit. If it's the first time, the new router lsa |
fdb19982 | 1069 | * origination is necessary. |
7ab3ff6a | 1070 | */ |
e8085aba | 1071 | void |
2918e610 OZ |
1072 | originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, |
1073 | u32 metric, ip_addr fwaddr, u32 tag, int pbit) | |
e8085aba | 1074 | { |
41b612c3 | 1075 | struct proto_ospf *po = oa->po; |
be862406 | 1076 | struct proto *p = &po->proto; |
e8085aba | 1077 | struct ospf_lsa_header lsa; |
b9ed99f7 | 1078 | struct top_hash_entry *en = NULL; |
c3226991 | 1079 | void *body; |
41b612c3 OZ |
1080 | int nssa = oa_is_nssa(oa); |
1081 | u32 dom = nssa ? oa->areaid : 0; | |
1082 | ||
41b612c3 OZ |
1083 | OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d", |
1084 | nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); | |
b9ed99f7 OF |
1085 | |
1086 | lsa.age = 0; | |
c3226991 | 1087 | #ifdef OSPFv2 |
2918e610 | 1088 | lsa.options = nssa ? (pbit ? OPT_P : 0) : OPT_E; |
c3226991 | 1089 | #endif |
41b612c3 | 1090 | lsa.type = nssa ? LSA_T_NSSA : LSA_T_EXT; |
9727681a | 1091 | lsa.id = fibnode_to_lsaid(po, fn); |
8a70a13e | 1092 | lsa.rt = po->router_id; |
273fd2c1 | 1093 | |
2918e610 | 1094 | if (nssa && pbit && ipa_zero(fwaddr)) |
41b612c3 | 1095 | { |
2918e610 OZ |
1096 | /* NSSA-LSA with P-bit set must have non-zero forwarding address */ |
1097 | ||
1098 | fwaddr = find_surrogate_fwaddr(oa); | |
1099 | if (ipa_zero(fwaddr)) | |
1100 | { | |
35c875f0 | 1101 | log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %I/%d", |
2918e610 OZ |
1102 | p->name, fn->prefix, fn->pxlen); |
1103 | return; | |
1104 | } | |
41b612c3 OZ |
1105 | } |
1106 | ||
1107 | if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL) | |
7ff5803b | 1108 | { |
ed317862 | 1109 | int rv = check_ext_lsa(en, fn, metric, fwaddr, tag); |
7ff5803b | 1110 | if (rv < 0) |
273fd2c1 | 1111 | { |
35c875f0 | 1112 | log(L_ERR "%s: LSAID collision for %I/%d", |
7ff5803b OZ |
1113 | p->name, fn->prefix, fn->pxlen); |
1114 | return; | |
273fd2c1 | 1115 | } |
273fd2c1 | 1116 | |
7ff5803b OZ |
1117 | if (rv > 0) |
1118 | return; | |
7ff5803b | 1119 | } |
52572e94 | 1120 | lsa.sn = get_seqnum(en); |
7ff5803b | 1121 | |
2918e610 | 1122 | body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag, pbit); |
d5d9693c | 1123 | lsasum_calculate(&lsa, body); |
c3226991 | 1124 | |
2918e610 OZ |
1125 | if (src) |
1126 | fn->x1 = src; | |
1127 | ||
d494df63 | 1128 | lsa_install_new(po, &lsa, dom, body); |
41b612c3 | 1129 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); |
fdb19982 | 1130 | |
b9ed99f7 | 1131 | if (po->ebit == 0) |
fdb19982 | 1132 | { |
b9ed99f7 | 1133 | po->ebit = 1; |
fdb19982 OF |
1134 | WALK_LIST(oa, po->area_list) |
1135 | { | |
1136 | schedule_rt_lsa(oa); | |
1137 | } | |
1138 | } | |
e8085aba OF |
1139 | } |
1140 | ||
c3226991 | 1141 | void |
bbcfd5a0 | 1142 | flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int nssa) |
c3226991 | 1143 | { |
41b612c3 | 1144 | struct proto_ospf *po = oa->po; |
be862406 | 1145 | struct proto *p = &po->proto; |
c3226991 | 1146 | struct top_hash_entry *en; |
be862406 | 1147 | |
41b612c3 OZ |
1148 | u32 dom = nssa ? oa->areaid : 0; |
1149 | u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT; | |
9727681a | 1150 | u32 lsaid = fibnode_to_lsaid(po, fn); |
c3226991 | 1151 | |
41b612c3 | 1152 | if (en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type)) |
c3226991 | 1153 | { |
bbcfd5a0 OZ |
1154 | OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", |
1155 | nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); | |
1156 | ||
7ff5803b | 1157 | if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0) |
c3226991 | 1158 | { |
35c875f0 | 1159 | log(L_ERR "%s: LSAID collision for %I/%d", |
9727681a OZ |
1160 | p->name, fn->prefix, fn->pxlen); |
1161 | return; | |
c3226991 | 1162 | } |
9727681a | 1163 | |
ed317862 | 1164 | fn->x1 = 0; |
9727681a | 1165 | ospf_lsupd_flush_nlsa(po, en); |
c3226991 OZ |
1166 | } |
1167 | } | |
1168 | ||
1169 | ||
1170 | #ifdef OSPFv3 | |
1171 | ||
1172 | static void * | |
1173 | originate_link_lsa_body(struct ospf_iface *ifa, u16 *length) | |
1174 | { | |
1175 | struct proto_ospf *po = ifa->oa->po; | |
1176 | struct ospf_lsa_link *ll; | |
1177 | int i = 0; | |
1178 | u8 flags; | |
1179 | ||
1180 | ASSERT(po->lsab_used == 0); | |
1181 | ll = lsab_allocz(po, sizeof(struct ospf_lsa_link)); | |
1182 | ll->options = ifa->oa->options | (ifa->priority << 24); | |
353729f5 | 1183 | ll->lladdr = ifa->addr->ip; |
c3226991 OZ |
1184 | ll = NULL; /* buffer might be reallocated later */ |
1185 | ||
1186 | struct ifa *a; | |
1187 | WALK_LIST(a, ifa->iface->addrs) | |
1188 | { | |
1189 | if ((a->flags & IA_SECONDARY) || | |
1190 | (a->scope < SCOPE_SITE)) | |
1191 | continue; | |
1192 | ||
1193 | flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; | |
1194 | put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)), | |
1195 | a->ip, a->pxlen, flags, 0); | |
1196 | i++; | |
1197 | } | |
1198 | ||
1199 | ll = po->lsab; | |
1200 | ll->pxcount = i; | |
1201 | *length = po->lsab_used + sizeof(struct ospf_lsa_header); | |
1202 | return lsab_flush(po); | |
1203 | } | |
1204 | ||
1205 | void | |
1206 | originate_link_lsa(struct ospf_iface *ifa) | |
1207 | { | |
1208 | struct ospf_lsa_header lsa; | |
1209 | struct proto_ospf *po = ifa->oa->po; | |
1210 | struct proto *p = &po->proto; | |
c3226991 OZ |
1211 | void *body; |
1212 | ||
48e5f32d OZ |
1213 | /* Vlinks do not have link-LSAs */ |
1214 | if (ifa->type == OSPF_IT_VLINK) | |
1215 | return; | |
1216 | ||
1217 | OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname); | |
c3226991 OZ |
1218 | |
1219 | lsa.age = 0; | |
1220 | lsa.type = LSA_T_LINK; | |
dd4da6f6 | 1221 | lsa.id = ifa->iface_id; |
8a70a13e | 1222 | lsa.rt = po->router_id; |
52572e94 | 1223 | lsa.sn = get_seqnum(ifa->link_lsa); |
dd4da6f6 | 1224 | u32 dom = ifa->iface_id; |
c3226991 OZ |
1225 | |
1226 | body = originate_link_lsa_body(ifa, &lsa.length); | |
1227 | lsasum_calculate(&lsa, body); | |
1228 | ifa->link_lsa = lsa_install_new(po, &lsa, dom, body); | |
1229 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); | |
be862406 OZ |
1230 | |
1231 | /* Just to be sure to not forget on our link LSA */ | |
1232 | if (ifa->state == OSPF_IS_DR) | |
1233 | schedule_net_lsa(ifa); | |
c3226991 OZ |
1234 | } |
1235 | ||
b49e6f5a OZ |
1236 | void |
1237 | update_link_lsa(struct ospf_iface *ifa) | |
1238 | { | |
1239 | if (ifa->link_lsa && ((ifa->link_lsa->inst_t + MINLSINTERVAL) > now)) | |
1240 | return; | |
1241 | /* | |
1242 | * It's too early to originate new link LSA. We will | |
1243 | * try to do it next tick | |
1244 | */ | |
1245 | originate_link_lsa(ifa); | |
1246 | ifa->origlink = 0; | |
1247 | } | |
c3226991 | 1248 | |
d9e7e1b1 OZ |
1249 | static inline void |
1250 | lsa_put_prefix(struct proto_ospf *po, ip_addr prefix, u32 pxlen, u32 cost) | |
1251 | { | |
1252 | put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(pxlen)), prefix, pxlen, | |
1253 | (pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA, cost); | |
1254 | } | |
1255 | ||
c3226991 OZ |
1256 | static void * |
1257 | originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) | |
1258 | { | |
1259 | struct proto_ospf *po = oa->po; | |
8e48831a | 1260 | struct ospf_config *cf = (struct ospf_config *) (po->proto.cf); |
c3226991 OZ |
1261 | struct ospf_iface *ifa; |
1262 | struct ospf_lsa_prefix *lp; | |
3b89a232 | 1263 | int host_addr = 0; |
c3226991 OZ |
1264 | int net_lsa; |
1265 | int i = 0; | |
c3226991 OZ |
1266 | |
1267 | ASSERT(po->lsab_used == 0); | |
1268 | lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix)); | |
1269 | lp->ref_type = LSA_T_RT; | |
1270 | lp->ref_id = 0; | |
8a70a13e | 1271 | lp->ref_rt = po->router_id; |
c3226991 OZ |
1272 | lp = NULL; /* buffer might be reallocated later */ |
1273 | ||
1274 | WALK_LIST(ifa, po->iface_list) | |
1275 | { | |
e4404cef | 1276 | if ((ifa->oa != oa) || (ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN)) |
c3226991 OZ |
1277 | continue; |
1278 | ||
e7b4948c OZ |
1279 | ifa->px_pos_beg = i; |
1280 | ||
c3226991 OZ |
1281 | if ((ifa->type == OSPF_IT_BCAST) || |
1282 | (ifa->type == OSPF_IT_NBMA)) | |
1283 | net_lsa = bcast_net_active(ifa); | |
1284 | else | |
1285 | net_lsa = 0; | |
1286 | ||
1287 | struct ifa *a; | |
1288 | WALK_LIST(a, ifa->iface->addrs) | |
1289 | { | |
3b89a232 | 1290 | if ((a->flags & IA_SECONDARY) || |
52a43ae3 | 1291 | (a->flags & IA_PEER) || |
3b89a232 OZ |
1292 | (a->scope <= SCOPE_LINK)) |
1293 | continue; | |
1294 | ||
3b89a232 | 1295 | if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) || |
c3226991 OZ |
1296 | configured_stubnet(oa, a)) |
1297 | continue; | |
1298 | ||
52a43ae3 OZ |
1299 | if ((a->flags & IA_HOST) || |
1300 | (ifa->state == OSPF_IS_LOOP) || | |
1301 | (ifa->type == OSPF_IT_PTMP)) | |
1302 | { | |
d9e7e1b1 | 1303 | lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0); |
52a43ae3 OZ |
1304 | host_addr = 1; |
1305 | } | |
d9e7e1b1 OZ |
1306 | else |
1307 | lsa_put_prefix(po, a->prefix, a->pxlen, ifa->cost); | |
c3226991 OZ |
1308 | i++; |
1309 | } | |
e7b4948c OZ |
1310 | |
1311 | ifa->px_pos_end = i; | |
c3226991 OZ |
1312 | } |
1313 | ||
c3226991 | 1314 | struct ospf_stubnet_config *sn; |
5cdf264f OZ |
1315 | if (oa->ac) |
1316 | WALK_LIST(sn, oa->ac->stubnet_list) | |
1317 | if (!sn->hidden) | |
c3226991 | 1318 | { |
d9e7e1b1 | 1319 | lsa_put_prefix(po, sn->px.addr, sn->px.len, sn->cost); |
e4404cef OZ |
1320 | if (sn->px.len == MAX_PREFIX_LENGTH) |
1321 | host_addr = 1; | |
1322 | i++; | |
1323 | } | |
1324 | ||
1325 | /* If there are some configured vlinks, find some global address | |
1326 | (even from another area), which will be used as a vlink endpoint. */ | |
1327 | if (!EMPTY_LIST(cf->vlink_list) && !host_addr) | |
1328 | { | |
1329 | WALK_LIST(ifa, po->iface_list) | |
1330 | { | |
1331 | if ((ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN)) | |
1332 | continue; | |
1333 | ||
1334 | struct ifa *a; | |
1335 | WALK_LIST(a, ifa->iface->addrs) | |
1336 | { | |
1337 | if ((a->flags & IA_SECONDARY) || (a->scope <= SCOPE_LINK)) | |
1338 | continue; | |
1339 | ||
1340 | /* Found some IP */ | |
1341 | lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0); | |
c3226991 | 1342 | i++; |
e4404cef | 1343 | goto done; |
c3226991 | 1344 | } |
e4404cef OZ |
1345 | } |
1346 | } | |
c3226991 | 1347 | |
e4404cef | 1348 | done: |
c3226991 OZ |
1349 | lp = po->lsab; |
1350 | lp->pxcount = i; | |
1351 | *length = po->lsab_used + sizeof(struct ospf_lsa_header); | |
1352 | return lsab_flush(po); | |
1353 | } | |
1354 | ||
1355 | void | |
1356 | originate_prefix_rt_lsa(struct ospf_area *oa) | |
1357 | { | |
c3226991 | 1358 | struct proto_ospf *po = oa->po; |
be862406 | 1359 | struct proto *p = &po->proto; |
be862406 | 1360 | struct ospf_lsa_header lsa; |
c3226991 OZ |
1361 | void *body; |
1362 | ||
be862406 OZ |
1363 | OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid); |
1364 | ||
c3226991 OZ |
1365 | lsa.age = 0; |
1366 | lsa.type = LSA_T_PREFIX; | |
be862406 | 1367 | lsa.id = 0; |
8a70a13e | 1368 | lsa.rt = po->router_id; |
52572e94 | 1369 | lsa.sn = get_seqnum(oa->pxr_lsa); |
c3226991 OZ |
1370 | u32 dom = oa->areaid; |
1371 | ||
1372 | body = originate_prefix_rt_lsa_body(oa, &lsa.length); | |
1373 | lsasum_calculate(&lsa, body); | |
1374 | oa->pxr_lsa = lsa_install_new(po, &lsa, dom, body); | |
1375 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); | |
1376 | } | |
1377 | ||
1378 | ||
1379 | static inline int | |
1380 | prefix_space(u32 *buf) | |
1381 | { | |
1382 | int pxl = *buf >> 24; | |
1383 | return IPV6_PREFIX_SPACE(pxl); | |
1384 | } | |
1385 | ||
1386 | static inline int | |
1387 | prefix_same(u32 *b1, u32 *b2) | |
1388 | { | |
1389 | int pxl1 = *b1 >> 24; | |
1390 | int pxl2 = *b2 >> 24; | |
1391 | int pxs, i; | |
1392 | ||
1393 | if (pxl1 != pxl2) | |
1394 | return 0; | |
1395 | ||
1396 | pxs = IPV6_PREFIX_WORDS(pxl1); | |
1397 | for (i = 1; i < pxs; i++) | |
1398 | if (b1[i] != b2[i]) | |
1399 | return 0; | |
1400 | ||
1401 | return 1; | |
1402 | } | |
1403 | ||
1404 | static inline u32 * | |
1405 | prefix_advance(u32 *buf) | |
1406 | { | |
be862406 OZ |
1407 | int pxl = *buf >> 24; |
1408 | return buf + IPV6_PREFIX_WORDS(pxl); | |
c3226991 OZ |
1409 | } |
1410 | ||
2918e610 | 1411 | /* FIXME eliminate items with LA bit set? see 4.4.3.9 */ |
c3226991 | 1412 | static void |
be862406 | 1413 | add_prefix(struct proto_ospf *po, u32 *px, int offset, int *pxc) |
c3226991 | 1414 | { |
be862406 | 1415 | u32 *pxl = lsab_offset(po, offset); |
c3226991 | 1416 | int i; |
e4404cef OZ |
1417 | for (i = 0; i < *pxc; pxl = prefix_advance(pxl), i++) |
1418 | if (prefix_same(px, pxl)) | |
c3226991 | 1419 | { |
e4404cef OZ |
1420 | /* Options should be logically OR'ed together */ |
1421 | *pxl |= (*px & 0x00FF0000); | |
1422 | return; | |
c3226991 OZ |
1423 | } |
1424 | ||
1425 | ASSERT(pxl == lsab_end(po)); | |
1426 | ||
1427 | int pxspace = prefix_space(px); | |
1428 | pxl = lsab_alloc(po, pxspace); | |
1429 | memcpy(pxl, px, pxspace); | |
e4404cef | 1430 | *pxl &= 0xFFFF0000; /* Set metric to zero */ |
c3226991 OZ |
1431 | (*pxc)++; |
1432 | } | |
1433 | ||
be862406 OZ |
1434 | static void |
1435 | add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int *pxc) | |
1436 | { | |
1437 | struct ospf_lsa_link *ll = en->lsa_body; | |
1438 | u32 *pxb = ll->rest; | |
1439 | int j; | |
1440 | ||
e4404cef OZ |
1441 | for (j = 0; j < ll->pxcount; pxb = prefix_advance(pxb), j++) |
1442 | { | |
1443 | u8 pxlen = (pxb[0] >> 24); | |
1444 | u8 pxopts = (pxb[0] >> 16); | |
1445 | ||
1446 | /* Skip NU or LA prefixes */ | |
1447 | if (pxopts & (OPT_PX_NU | OPT_PX_LA)) | |
1448 | continue; | |
1449 | ||
1450 | /* Skip link-local prefixes */ | |
1451 | if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000)) | |
1452 | continue; | |
1453 | ||
1454 | add_prefix(po, pxb, offset, pxc); | |
1455 | } | |
be862406 OZ |
1456 | } |
1457 | ||
1458 | ||
c3226991 OZ |
1459 | |
1460 | static void * | |
1461 | originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length) | |
1462 | { | |
1463 | struct proto_ospf *po = ifa->oa->po; | |
1464 | struct ospf_lsa_prefix *lp; | |
c3226991 OZ |
1465 | struct ospf_neighbor *n; |
1466 | struct top_hash_entry *en; | |
be862406 | 1467 | int pxc, offset; |
c3226991 OZ |
1468 | |
1469 | ASSERT(po->lsab_used == 0); | |
1470 | lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix)); | |
1471 | lp->ref_type = LSA_T_NET; | |
1472 | lp->ref_id = ifa->net_lsa->lsa.id; | |
8a70a13e | 1473 | lp->ref_rt = po->router_id; |
c3226991 OZ |
1474 | lp = NULL; /* buffer might be reallocated later */ |
1475 | ||
be862406 | 1476 | pxc = 0; |
c3226991 OZ |
1477 | offset = po->lsab_used; |
1478 | ||
be862406 OZ |
1479 | /* Find all Link LSAs associated with the link and merge their prefixes */ |
1480 | if (ifa->link_lsa) | |
1481 | add_link_lsa(po, ifa->link_lsa, offset, &pxc); | |
1482 | ||
c3226991 OZ |
1483 | WALK_LIST(n, ifa->neigh_list) |
1484 | if ((n->state == NEIGHBOR_FULL) && | |
dd4da6f6 | 1485 | (en = ospf_hash_find(po->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK))) |
be862406 | 1486 | add_link_lsa(po, en, offset, &pxc); |
c3226991 OZ |
1487 | |
1488 | lp = po->lsab; | |
be862406 | 1489 | lp->pxcount = pxc; |
c3226991 OZ |
1490 | *length = po->lsab_used + sizeof(struct ospf_lsa_header); |
1491 | return lsab_flush(po); | |
1492 | } | |
1493 | ||
1494 | void | |
1495 | originate_prefix_net_lsa(struct ospf_iface *ifa) | |
1496 | { | |
c3226991 | 1497 | struct proto_ospf *po = ifa->oa->po; |
be862406 | 1498 | struct proto *p = &po->proto; |
be862406 | 1499 | struct ospf_lsa_header lsa; |
c3226991 OZ |
1500 | void *body; |
1501 | ||
48e5f32d | 1502 | OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname); |
be862406 | 1503 | |
c3226991 OZ |
1504 | lsa.age = 0; |
1505 | lsa.type = LSA_T_PREFIX; | |
dd4da6f6 | 1506 | lsa.id = ifa->iface_id; |
8a70a13e | 1507 | lsa.rt = po->router_id; |
52572e94 | 1508 | lsa.sn = get_seqnum(ifa->pxn_lsa); |
c3226991 OZ |
1509 | u32 dom = ifa->oa->areaid; |
1510 | ||
1511 | body = originate_prefix_net_lsa_body(ifa, &lsa.length); | |
1512 | lsasum_calculate(&lsa, body); | |
1513 | ifa->pxn_lsa = lsa_install_new(po, &lsa, dom, body); | |
1514 | ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); | |
1515 | } | |
1516 | ||
061ab802 OZ |
1517 | void |
1518 | flush_prefix_net_lsa(struct ospf_iface *ifa) | |
1519 | { | |
1520 | struct proto_ospf *po = ifa->oa->po; | |
1521 | struct proto *p = &po->proto; | |
1522 | struct top_hash_entry *en = ifa->pxn_lsa; | |
1523 | u32 dom = ifa->oa->areaid; | |
1524 | ||
1525 | if (en == NULL) | |
1526 | return; | |
1527 | ||
48e5f32d | 1528 | OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", ifa->ifname); |
be862406 | 1529 | |
061ab802 OZ |
1530 | en->lsa.sn += 1; |
1531 | en->lsa.age = LSA_MAXAGE; | |
1532 | lsasum_calculate(&en->lsa, en->lsa_body); | |
1533 | ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 0); | |
1534 | flush_lsa(en, po); | |
1535 | ifa->pxn_lsa = NULL; | |
1536 | } | |
1537 | ||
1538 | ||
c3226991 | 1539 | #endif |
e8085aba | 1540 | |
b49e6f5a | 1541 | |
6ba36f06 MM |
1542 | static void |
1543 | ospf_top_ht_alloc(struct top_graph *f) | |
1544 | { | |
1545 | f->hash_size = 1 << f->hash_order; | |
1546 | f->hash_mask = f->hash_size - 1; | |
1547 | if (f->hash_order > HASH_HI_MAX - HASH_HI_STEP) | |
1548 | f->hash_entries_max = ~0; | |
1549 | else | |
1550 | f->hash_entries_max = f->hash_size HASH_HI_MARK; | |
1551 | if (f->hash_order < HASH_LO_MIN + HASH_LO_STEP) | |
1552 | f->hash_entries_min = 0; | |
1553 | else | |
1554 | f->hash_entries_min = f->hash_size HASH_LO_MARK; | |
1555 | DBG("Allocating OSPF hash of order %d: %d hash_entries, %d low, %d high\n", | |
1556 | f->hash_order, f->hash_size, f->hash_entries_min, f->hash_entries_max); | |
b9ed99f7 OF |
1557 | f->hash_table = |
1558 | mb_alloc(f->pool, f->hash_size * sizeof(struct top_hash_entry *)); | |
6ba36f06 MM |
1559 | bzero(f->hash_table, f->hash_size * sizeof(struct top_hash_entry *)); |
1560 | } | |
1561 | ||
1562 | static inline void | |
1563 | ospf_top_ht_free(struct top_hash_entry **h) | |
1564 | { | |
1565 | mb_free(h); | |
1566 | } | |
1567 | ||
1568 | static inline u32 | |
1569 | ospf_top_hash_u32(u32 a) | |
1570 | { | |
1571 | /* Shamelessly stolen from IP address hashing in ipv4.h */ | |
1572 | a ^= a >> 16; | |
1573 | a ^= a << 10; | |
1574 | return a; | |
1575 | } | |
1576 | ||
1577 | static inline unsigned | |
c3226991 OZ |
1578 | ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type) |
1579 | { | |
be862406 | 1580 | /* In OSPFv2, we don't know Router ID when looking for network LSAs. |
9f0ba7b1 OZ |
1581 | In OSPFv3, we don't know LSA ID when looking for router LSAs. |
1582 | In both cases, there is (usually) just one (or small number) | |
1583 | appropriate LSA, so we just clear unknown part of key. */ | |
c3226991 | 1584 | |
9f0ba7b1 | 1585 | return ( |
c3226991 OZ |
1586 | #ifdef OSPFv2 |
1587 | ((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) + | |
9f0ba7b1 | 1588 | ospf_top_hash_u32(lsaid) + |
c3226991 OZ |
1589 | #else /* OSPFv3 */ |
1590 | ospf_top_hash_u32(rtrid) + | |
9f0ba7b1 | 1591 | ((type == LSA_T_RT) ? 0 : ospf_top_hash_u32(lsaid)) + |
c3226991 | 1592 | #endif |
9f0ba7b1 | 1593 | type + domain) & f->hash_mask; |
c3226991 OZ |
1594 | |
1595 | /* | |
b9ed99f7 | 1596 | return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) + |
86c84d76 | 1597 | type + areaid) & f->hash_mask; |
c3226991 | 1598 | */ |
6ba36f06 MM |
1599 | } |
1600 | ||
7ab3ff6a OF |
1601 | /** |
1602 | * ospf_top_new - allocated new topology database | |
c3226991 | 1603 | * @p: current instance of ospf |
7ab3ff6a | 1604 | * |
c3226991 | 1605 | * this dynamically hashed structure is often used for keeping lsas. mainly |
baa5dd6c | 1606 | * its used in @ospf_area structure. |
7ab3ff6a | 1607 | */ |
6ba36f06 | 1608 | struct top_graph * |
d5d9693c | 1609 | ospf_top_new(pool *pool) |
6ba36f06 MM |
1610 | { |
1611 | struct top_graph *f; | |
1612 | ||
035f6acb OF |
1613 | f = mb_allocz(pool, sizeof(struct top_graph)); |
1614 | f->pool = pool; | |
6ba36f06 MM |
1615 | f->hash_slab = sl_new(f->pool, sizeof(struct top_hash_entry)); |
1616 | f->hash_order = HASH_DEF_ORDER; | |
1617 | ospf_top_ht_alloc(f); | |
1618 | f->hash_entries = 0; | |
1619 | f->hash_entries_min = 0; | |
1620 | return f; | |
1621 | } | |
1622 | ||
1623 | void | |
1624 | ospf_top_free(struct top_graph *f) | |
1625 | { | |
1626 | rfree(f->hash_slab); | |
1627 | ospf_top_ht_free(f->hash_table); | |
1628 | mb_free(f); | |
1629 | } | |
1630 | ||
1631 | static void | |
1632 | ospf_top_rehash(struct top_graph *f, int step) | |
1633 | { | |
1634 | unsigned int oldn, oldh; | |
1635 | struct top_hash_entry **n, **oldt, **newt, *e, *x; | |
1636 | ||
1637 | oldn = f->hash_size; | |
1638 | oldt = f->hash_table; | |
b49e6f5a | 1639 | DBG("re-hashing topology hash from order %d to %d\n", f->hash_order, |
b9ed99f7 | 1640 | f->hash_order + step); |
6ba36f06 MM |
1641 | f->hash_order += step; |
1642 | ospf_top_ht_alloc(f); | |
1643 | newt = f->hash_table; | |
1644 | ||
b9ed99f7 OF |
1645 | for (oldh = 0; oldh < oldn; oldh++) |
1646 | { | |
1647 | e = oldt[oldh]; | |
1648 | while (e) | |
6ba36f06 | 1649 | { |
b9ed99f7 | 1650 | x = e->next; |
c3226991 | 1651 | n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type); |
b9ed99f7 OF |
1652 | e->next = *n; |
1653 | *n = e; | |
1654 | e = x; | |
6ba36f06 | 1655 | } |
b9ed99f7 | 1656 | } |
6ba36f06 MM |
1657 | ospf_top_ht_free(oldt); |
1658 | } | |
1659 | ||
f9c799a0 OZ |
1660 | #ifdef OSPFv2 |
1661 | ||
1662 | u32 | |
1663 | ospf_lsa_domain(u32 type, struct ospf_iface *ifa) | |
1664 | { | |
1665 | return (type == LSA_T_EXT) ? 0 : ifa->oa->areaid; | |
1666 | } | |
1667 | ||
1668 | #else /* OSPFv3 */ | |
1669 | ||
b49e6f5a OZ |
1670 | u32 |
1671 | ospf_lsa_domain(u32 type, struct ospf_iface *ifa) | |
1672 | { | |
1673 | switch (type & LSA_SCOPE_MASK) | |
1674 | { | |
1675 | case LSA_SCOPE_LINK: | |
dd4da6f6 | 1676 | return ifa->iface_id; |
b49e6f5a OZ |
1677 | |
1678 | case LSA_SCOPE_AREA: | |
1679 | return ifa->oa->areaid; | |
1680 | ||
1681 | case LSA_SCOPE_AS: | |
1682 | default: | |
1683 | return 0; | |
1684 | } | |
1685 | } | |
1686 | ||
f9c799a0 OZ |
1687 | #endif |
1688 | ||
921a93f2 | 1689 | struct top_hash_entry * |
b49e6f5a | 1690 | ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) |
921a93f2 | 1691 | { |
b49e6f5a | 1692 | return ospf_hash_find(f, domain, h->id, h->rt, h->type); |
921a93f2 | 1693 | } |
d8852b36 OF |
1694 | |
1695 | struct top_hash_entry * | |
b49e6f5a | 1696 | ospf_hash_get_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) |
d8852b36 | 1697 | { |
b49e6f5a | 1698 | return ospf_hash_get(f, domain, h->id, h->rt, h->type); |
d8852b36 OF |
1699 | } |
1700 | ||
6ba36f06 | 1701 | struct top_hash_entry * |
b49e6f5a | 1702 | ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) |
6ba36f06 | 1703 | { |
86c84d76 | 1704 | struct top_hash_entry *e; |
c3226991 | 1705 | e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)]; |
86c84d76 | 1706 | |
9f0ba7b1 OZ |
1707 | while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain)) |
1708 | e = e->next; | |
1709 | ||
1710 | return e; | |
1711 | } | |
1712 | ||
1713 | ||
c3226991 | 1714 | #ifdef OSPFv2 |
c3226991 | 1715 | |
9f0ba7b1 OZ |
1716 | /* In OSPFv2, sometimes we don't know Router ID when looking for network LSAs. |
1717 | There should be just one, so we find any match. */ | |
1718 | struct top_hash_entry * | |
1719 | ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa) | |
1720 | { | |
1721 | struct top_hash_entry *e; | |
1722 | e = f->hash_table[ospf_top_hash(f, domain, lsa, 0, LSA_T_NET)]; | |
1723 | ||
1724 | while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain)) | |
1725 | e = e->next; | |
1726 | ||
1727 | return e; | |
1728 | } | |
86c84d76 | 1729 | |
c3226991 OZ |
1730 | #endif |
1731 | ||
c3226991 | 1732 | |
9f0ba7b1 OZ |
1733 | #ifdef OSPFv3 |
1734 | ||
1735 | /* In OSPFv3, usually we don't know LSA ID when looking for router | |
1736 | LSAs. We return matching LSA with smallest LSA ID. */ | |
1737 | struct top_hash_entry * | |
1738 | ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr) | |
1739 | { | |
1740 | struct top_hash_entry *rv = NULL; | |
1741 | struct top_hash_entry *e; | |
1742 | e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)]; | |
1743 | ||
1744 | while (e) | |
1745 | { | |
1746 | if (e->lsa.rt == rtr && e->lsa.type == LSA_T_RT && e->domain == domain) | |
1747 | if (!rv || e->lsa.id < rv->lsa.id) | |
1748 | rv = e; | |
1749 | e = e->next; | |
1750 | } | |
1751 | ||
1752 | return rv; | |
1753 | } | |
1754 | ||
1755 | static inline struct top_hash_entry * | |
1756 | find_matching_rt(struct top_hash_entry *e, u32 domain, u32 rtr) | |
1757 | { | |
1758 | while (e && (e->lsa.rt != rtr || e->lsa.type != LSA_T_RT || e->domain != domain)) | |
1759 | e = e->next; | |
6ba36f06 MM |
1760 | return e; |
1761 | } | |
1762 | ||
9f0ba7b1 OZ |
1763 | struct top_hash_entry * |
1764 | ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr) | |
1765 | { | |
1766 | struct top_hash_entry *e; | |
1767 | e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)]; | |
1768 | return find_matching_rt(e, domain, rtr); | |
1769 | } | |
1770 | ||
1771 | struct top_hash_entry * | |
1772 | ospf_hash_find_rt_next(struct top_hash_entry *e) | |
1773 | { | |
1774 | return find_matching_rt(e->next, e->domain, e->lsa.rt); | |
1775 | } | |
1776 | ||
1777 | #endif | |
1778 | ||
1779 | ||
6ba36f06 | 1780 | struct top_hash_entry * |
b49e6f5a | 1781 | ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) |
6ba36f06 | 1782 | { |
86c84d76 OF |
1783 | struct top_hash_entry **ee; |
1784 | struct top_hash_entry *e; | |
86c84d76 | 1785 | |
c3226991 | 1786 | ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type); |
86c84d76 OF |
1787 | e = *ee; |
1788 | ||
c3226991 OZ |
1789 | while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain)) |
1790 | e = e->next; | |
6ba36f06 | 1791 | |
6ba36f06 MM |
1792 | if (e) |
1793 | return e; | |
933bfdde | 1794 | |
6ba36f06 | 1795 | e = sl_alloc(f->hash_slab); |
933bfdde OF |
1796 | e->color = OUTSPF; |
1797 | e->dist = LSINFINITY; | |
57c574d8 | 1798 | e->nhs = NULL; |
3b16080c | 1799 | e->lb = IPA_NONE; |
ce17d4c1 OF |
1800 | e->lsa.id = lsa; |
1801 | e->lsa.rt = rtr; | |
1802 | e->lsa.type = type; | |
1803 | e->lsa_body = NULL; | |
c3226991 | 1804 | e->domain = domain; |
933bfdde | 1805 | e->next = *ee; |
b9ed99f7 | 1806 | *ee = e; |
6ba36f06 MM |
1807 | if (f->hash_entries++ > f->hash_entries_max) |
1808 | ospf_top_rehash(f, HASH_HI_STEP); | |
1809 | return e; | |
1810 | } | |
1811 | ||
1812 | void | |
1813 | ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e) | |
1814 | { | |
86c84d76 | 1815 | struct top_hash_entry **ee = f->hash_table + |
c3226991 | 1816 | ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type); |
6ba36f06 MM |
1817 | |
1818 | while (*ee) | |
b9ed99f7 OF |
1819 | { |
1820 | if (*ee == e) | |
6ba36f06 | 1821 | { |
b9ed99f7 OF |
1822 | *ee = e->next; |
1823 | sl_free(f->hash_slab, e); | |
1824 | if (f->hash_entries-- < f->hash_entries_min) | |
1825 | ospf_top_rehash(f, -HASH_LO_STEP); | |
1826 | return; | |
6ba36f06 | 1827 | } |
b9ed99f7 OF |
1828 | ee = &((*ee)->next); |
1829 | } | |
6ba36f06 MM |
1830 | bug("ospf_hash_delete() called for invalid node"); |
1831 | } | |
1832 | ||
e81b440f | 1833 | /* |
226cb2bc OF |
1834 | static void |
1835 | ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) | |
1836 | { | |
e81b440f | 1837 | |
226cb2bc OF |
1838 | struct ospf_lsa_rt *rt = NULL; |
1839 | struct ospf_lsa_rt_link *rr = NULL; | |
1840 | struct ospf_lsa_net *ln = NULL; | |
1841 | u32 *rts = NULL; | |
1842 | u32 i, max; | |
1843 | ||
3aab39f5 OZ |
1844 | OSPF_TRACE(D_EVENTS, "- %1x %-1R %-1R %4u 0x%08x 0x%04x %-1R", |
1845 | he->lsa.type, he->lsa.id, he->lsa.rt, he->lsa.age, he->lsa.sn, | |
c3226991 | 1846 | he->lsa.checksum, he->domain); |
226cb2bc | 1847 | |
b49e6f5a | 1848 | |
226cb2bc OF |
1849 | switch (he->lsa.type) |
1850 | { | |
1851 | case LSA_T_RT: | |
1852 | rt = he->lsa_body; | |
1853 | rr = (struct ospf_lsa_rt_link *) (rt + 1); | |
1854 | ||
c3226991 | 1855 | for (i = 0; i < lsa_rt_items(&he->lsa); i++) |
3aab39f5 OZ |
1856 | OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u", |
1857 | rr[i].type, rr[i].id, rr[i].data, rr[i].metric); | |
226cb2bc OF |
1858 | break; |
1859 | ||
1860 | case LSA_T_NET: | |
1861 | ln = he->lsa_body; | |
1862 | rts = (u32 *) (ln + 1); | |
226cb2bc | 1863 | |
c3226991 | 1864 | for (i = 0; i < lsa_net_items(&he->lsa); i++) |
3aab39f5 | 1865 | OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]); |
226cb2bc OF |
1866 | break; |
1867 | ||
1868 | default: | |
1869 | break; | |
1870 | } | |
1871 | } | |
1872 | ||
6ba36f06 | 1873 | void |
992705f6 | 1874 | ospf_top_dump(struct top_graph *f, struct proto *p) |
6ba36f06 | 1875 | { |
89ba9a18 | 1876 | unsigned int i; |
992705f6 | 1877 | OSPF_TRACE(D_EVENTS, "Hash entries: %d", f->hash_entries); |
6ba36f06 | 1878 | |
b9ed99f7 OF |
1879 | for (i = 0; i < f->hash_size; i++) |
1880 | { | |
226cb2bc OF |
1881 | struct top_hash_entry *e; |
1882 | for (e = f->hash_table[i]; e != NULL; e = e->next) | |
1883 | ospf_dump_lsa(e, p); | |
b9ed99f7 | 1884 | } |
6ba36f06 | 1885 | } |
e81b440f | 1886 | */ |
de30342f | 1887 | |
baa5dd6c | 1888 | /* This is very inefficient, please don't call it often */ |
ad5453b5 OF |
1889 | |
1890 | /* I should also test for every LSA if it's in some link state | |
baa5dd6c OF |
1891 | * retransmission list for every neighbor. I will not test it. |
1892 | * It could happen that I'll receive some strange ls ack's. | |
ad5453b5 OF |
1893 | */ |
1894 | ||
1895 | int | |
86c84d76 | 1896 | can_flush_lsa(struct proto_ospf *po) |
ad5453b5 OF |
1897 | { |
1898 | struct ospf_iface *ifa; | |
1899 | struct ospf_neighbor *n; | |
ad5453b5 | 1900 | |
86c84d76 | 1901 | WALK_LIST(ifa, po->iface_list) |
ad5453b5 | 1902 | { |
86c84d76 | 1903 | WALK_LIST(n, ifa->neigh_list) |
ad5453b5 | 1904 | { |
86c84d76 OF |
1905 | if ((n->state == NEIGHBOR_EXCHANGE) || (n->state == NEIGHBOR_LOADING)) |
1906 | return 0; | |
1907 | ||
b9ed99f7 | 1908 | break; |
ad5453b5 OF |
1909 | } |
1910 | } | |
1911 | ||
9e48d717 | 1912 | return 1; |
ad5453b5 | 1913 | } |