]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * Copyright (C) 2002 Yasuhiro Ohara | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with GNU Zebra; see the file COPYING. If not, write to the | |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | * Boston, MA 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #include "ospf6d.h" | |
23 | ||
24 | static int intra_index; | |
25 | #define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index)) | |
26 | ||
27 | #define ADD 0 | |
28 | #define REMOVE 1 | |
29 | ||
30 | static void | |
31 | ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa, | |
32 | struct ospf6_route_req *topo_entry) | |
33 | { | |
34 | struct ospf6_intra_area_prefix_lsa *intra_prefix; | |
35 | char *start, *end; | |
36 | struct ospf6_prefix *ospf6_prefix; | |
37 | struct ospf6_route_req request; | |
38 | struct ospf6_area *area; | |
39 | ||
40 | if (IS_OSPF6_DUMP_INTRA) | |
41 | { | |
42 | char buf[64]; | |
43 | struct prefix_ls *p_ls; | |
44 | p_ls = (struct prefix_ls *) &topo_entry->route.prefix; | |
45 | inet_ntop (AF_INET, &p_ls->adv_router, buf, sizeof (buf)); | |
46 | zlog_info ("INTRA: Calculate [%s] %s and %s", | |
47 | (type == ADD ? "add" : "remove"), lsa->str, buf); | |
48 | } | |
49 | ||
50 | intra_prefix = OSPF6_LSA_HEADER_END (lsa->header); | |
51 | ||
52 | area = lsa->scope; | |
53 | assert (area); | |
54 | ||
55 | start = (char *) (intra_prefix + 1); | |
56 | end = (char *) lsa->header + ntohs (lsa->header->length); | |
57 | for (ospf6_prefix = (struct ospf6_prefix *) start; | |
58 | (char *) ospf6_prefix < end; | |
59 | ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix)) | |
60 | { | |
61 | memset (&request, 0, sizeof (request)); | |
62 | ||
63 | request.route.type = OSPF6_DEST_TYPE_NETWORK; | |
64 | request.route.prefix.family = AF_INET6; | |
65 | request.route.prefix.prefixlen = ospf6_prefix->prefix_length; | |
66 | ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6); | |
67 | ||
68 | request.path.type = OSPF6_PATH_TYPE_INTRA; | |
69 | request.path.area_id = area->area_id; | |
70 | request.path.origin.type = lsa->header->type; | |
71 | request.path.origin.id = lsa->header->id; | |
72 | request.path.origin.adv_router = lsa->header->adv_router; | |
73 | request.path.cost = topo_entry->path.cost + | |
74 | ntohs (ospf6_prefix->prefix_metric); | |
75 | request.path.capability[0] = topo_entry->path.capability[0]; | |
76 | request.path.capability[1] = topo_entry->path.capability[1]; | |
77 | request.path.capability[2] = topo_entry->path.capability[2]; | |
78 | ||
79 | memcpy (&request.nexthop.address, &topo_entry->nexthop.address, | |
80 | sizeof (request.nexthop.address)); | |
81 | request.nexthop.ifindex = topo_entry->nexthop.ifindex; | |
82 | ||
83 | if (type == ADD) | |
84 | ospf6_route_add (&request, area->route_table); | |
85 | else if (type == REMOVE) | |
86 | ospf6_route_remove (&request, area->route_table); | |
87 | else | |
88 | assert (0); | |
89 | } | |
90 | } | |
91 | ||
92 | int | |
93 | ospf6_intra_prefix_database_hook_remove (void *data) | |
94 | { | |
95 | struct ospf6_lsa *lsa = data; | |
96 | struct ospf6_area *area; | |
97 | struct ospf6_intra_area_prefix_lsa *iap; | |
98 | struct prefix_ls prefix_ls; | |
99 | struct ospf6_route_req topo_entry; | |
100 | ||
101 | if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX)) | |
102 | return 0; | |
103 | ||
104 | area = (struct ospf6_area *) lsa->scope; | |
105 | assert (area); | |
106 | ||
107 | if (IS_OSPF6_DUMP_INTRA) | |
108 | zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str); | |
109 | ||
110 | iap = OSPF6_LSA_HEADER_END (lsa->header); | |
111 | memset (&prefix_ls, 0, sizeof (prefix_ls)); | |
112 | prefix_ls.prefixlen = 64; | |
113 | prefix_ls.adv_router.s_addr = iap->refer_advrtr; | |
114 | prefix_ls.id.s_addr = iap->refer_lsid; | |
115 | ||
116 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && | |
117 | iap->refer_lsid != htonl (0)) | |
118 | { | |
119 | zlog_warn ("SPF: Malformed ID %lu of Router reference in %s", | |
120 | (u_long) ntohl (iap->refer_lsid), lsa->str); | |
121 | prefix_ls.id.s_addr = htonl (0); | |
122 | } | |
123 | ||
124 | ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls, | |
125 | area->table_topology); | |
126 | ||
127 | while (iap->refer_lstype == topo_entry.path.origin.type && | |
128 | iap->refer_lsid == topo_entry.path.origin.id && | |
129 | iap->refer_advrtr == topo_entry.path.origin.adv_router) | |
130 | { | |
131 | ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry); | |
132 | ospf6_route_next (&topo_entry); | |
133 | } | |
134 | return 0; | |
135 | } | |
136 | ||
137 | int | |
138 | ospf6_intra_prefix_database_hook_add (void *data) | |
139 | { | |
140 | struct ospf6_lsa *lsa = data; | |
141 | struct ospf6_area *area; | |
142 | struct ospf6_intra_area_prefix_lsa *iap; | |
143 | struct prefix_ls prefix_ls; | |
144 | struct ospf6_route_req topo_entry; | |
145 | ||
146 | if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX)) | |
147 | return 0; | |
148 | ||
149 | area = (struct ospf6_area *) lsa->scope; | |
150 | assert (area); | |
151 | ||
152 | if (IS_LSA_MAXAGE (lsa)) | |
153 | { | |
154 | ospf6_intra_prefix_database_hook_remove (lsa); | |
155 | return 0; | |
156 | } | |
157 | ||
158 | if (IS_OSPF6_DUMP_INTRA) | |
159 | zlog_info ("INTRA: area %s add: %s", area->str, lsa->str); | |
160 | ||
161 | iap = OSPF6_LSA_HEADER_END (lsa->header); | |
162 | ||
163 | memset (&prefix_ls, 0, sizeof (struct prefix_ls)); | |
164 | prefix_ls.prefixlen = 64; | |
165 | prefix_ls.adv_router.s_addr = iap->refer_advrtr; | |
166 | prefix_ls.id.s_addr = iap->refer_lsid; | |
167 | ||
168 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && | |
169 | iap->refer_lsid != htonl (0)) | |
170 | { | |
171 | zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s", | |
172 | (u_long) ntohl (iap->refer_lsid), lsa->str); | |
173 | prefix_ls.id.s_addr = htonl (0); | |
174 | } | |
175 | ||
176 | ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls, | |
177 | area->table_topology); | |
178 | ||
179 | while (iap->refer_lstype == topo_entry.path.origin.type && | |
180 | iap->refer_lsid == topo_entry.path.origin.id && | |
181 | iap->refer_advrtr == topo_entry.path.origin.adv_router) | |
182 | { | |
183 | ospf6_intra_route_calculate (ADD, lsa, &topo_entry); | |
184 | ospf6_route_next (&topo_entry); | |
185 | } | |
186 | return 0; | |
187 | } | |
188 | ||
189 | void | |
190 | ospf6_intra_topology_add (void *data) | |
191 | { | |
192 | struct ospf6_route_req *topo_entry = data; | |
193 | struct ospf6_area *area; | |
194 | struct ospf6_intra_area_prefix_lsa *iap; | |
195 | struct ospf6_lsdb_node node; | |
196 | ||
197 | area = ospf6_area_lookup (topo_entry->path.area_id, ospf6); | |
198 | if (! area) | |
199 | return; | |
200 | ||
201 | if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER && | |
202 | (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) || | |
203 | CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))) | |
204 | ospf6_route_add (topo_entry, ospf6->topology_table); | |
205 | ||
206 | for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX), | |
207 | area->lsdb); | |
208 | ! ospf6_lsdb_is_end (&node); | |
209 | ospf6_lsdb_next (&node)) | |
210 | { | |
211 | if (IS_LSA_MAXAGE (node.lsa)) | |
212 | continue; | |
213 | ||
214 | iap = OSPF6_LSA_HEADER_END (node.lsa->header); | |
215 | ||
216 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && | |
217 | iap->refer_lsid != htonl (0)) | |
218 | { | |
219 | zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s", | |
220 | (u_long) ntohl (iap->refer_lsid), node.lsa->str); | |
221 | } | |
222 | ||
223 | if (iap->refer_lstype != topo_entry->path.origin.type || | |
224 | iap->refer_lsid != topo_entry->path.origin.id || | |
225 | iap->refer_advrtr != topo_entry->path.origin.adv_router) | |
226 | continue; | |
227 | ||
228 | ospf6_intra_route_calculate (ADD, node.lsa, topo_entry); | |
229 | } | |
230 | } | |
231 | ||
232 | void | |
233 | ospf6_intra_topology_remove (void *data) | |
234 | { | |
235 | struct ospf6_route_req *topo_entry = data; | |
236 | struct ospf6_area *area; | |
237 | struct ospf6_intra_area_prefix_lsa *iap; | |
238 | struct ospf6_lsdb_node node; | |
239 | ||
240 | area = ospf6_area_lookup (topo_entry->path.area_id, ospf6); | |
241 | if (! area) | |
242 | return; | |
243 | ||
244 | if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER && | |
245 | (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) || | |
246 | CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))) | |
247 | ospf6_route_remove (topo_entry, ospf6->topology_table); | |
248 | ||
249 | for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX), | |
250 | area->lsdb); | |
251 | ! ospf6_lsdb_is_end (&node); | |
252 | ospf6_lsdb_next (&node)) | |
253 | { | |
254 | if (IS_LSA_MAXAGE (node.lsa)) | |
255 | continue; | |
256 | ||
257 | iap = OSPF6_LSA_HEADER_END (node.lsa->header); | |
258 | ||
259 | if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) && | |
260 | iap->refer_lsid != htonl (0)) | |
261 | zlog_warn ("SPF: Malformed ID %lu of Router reference in %s", | |
262 | (u_long) ntohl (iap->refer_lsid), node.lsa->str); | |
263 | ||
264 | if (iap->refer_lstype != topo_entry->path.origin.type || | |
265 | iap->refer_lsid != topo_entry->path.origin.id || | |
266 | iap->refer_advrtr != topo_entry->path.origin.adv_router) | |
267 | continue; | |
268 | ||
269 | ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry); | |
270 | } | |
271 | } | |
272 | ||
273 | \f | |
274 | /*****************************************/ | |
275 | /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */ | |
276 | /*****************************************/ | |
277 | ||
278 | #define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\ | |
279 | if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\ | |
280 | {\ | |
281 | char buf[64];\ | |
282 | prefix2str (addr, buf, sizeof (buf));\ | |
283 | if (IS_OSPF6_DUMP_PREFIX)\ | |
284 | zlog_info (" Filter out Linklocal: %s", buf);\ | |
285 | continue;\ | |
286 | } | |
287 | ||
288 | #define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\ | |
289 | if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\ | |
290 | {\ | |
291 | char buf[64];\ | |
292 | prefix2str (addr, buf, sizeof (buf));\ | |
293 | if (IS_OSPF6_DUMP_PREFIX)\ | |
294 | zlog_info (" Filter out Unspecified: %s", buf);\ | |
295 | continue;\ | |
296 | } | |
297 | ||
298 | #define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\ | |
299 | if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\ | |
300 | {\ | |
301 | char buf[64];\ | |
302 | prefix2str (addr, buf, sizeof (buf));\ | |
303 | if (IS_OSPF6_DUMP_PREFIX)\ | |
304 | zlog_info (" Filter out Loopback: %s", buf);\ | |
305 | continue;\ | |
306 | } | |
307 | ||
308 | #define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\ | |
309 | if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\ | |
310 | {\ | |
311 | char buf[64];\ | |
312 | prefix2str (addr, buf, sizeof (buf));\ | |
313 | if (IS_OSPF6_DUMP_PREFIX)\ | |
314 | zlog_info (" Filter out V4Compat: %s", buf);\ | |
315 | continue;\ | |
316 | } | |
317 | ||
318 | #define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\ | |
319 | if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\ | |
320 | {\ | |
321 | char buf[64];\ | |
322 | prefix2str (addr, buf, sizeof (buf));\ | |
323 | if (IS_OSPF6_DUMP_PREFIX)\ | |
324 | zlog_info (" Filter out V4Mapped: %s", buf);\ | |
325 | continue;\ | |
326 | } | |
327 | ||
328 | ||
329 | int | |
330 | ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa) | |
331 | { | |
332 | struct ospf6_intra_area_prefix_lsa *iap_lsa; | |
333 | struct ospf6_prefix *prefix; | |
334 | unsigned short prefixnum; | |
335 | char buf[128], type[32], id[32], adv_router[32]; | |
336 | struct in6_addr in6; | |
337 | char *start, *end, *current; | |
338 | ||
339 | assert (lsa->header); | |
340 | iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1); | |
341 | ||
342 | prefixnum = ntohs (iap_lsa->prefix_number); | |
343 | ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type)); | |
344 | inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id)); | |
345 | inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router, | |
346 | sizeof (adv_router)); | |
347 | ||
348 | vty_out (vty, " Number of Prefix: %d%s", prefixnum, VTY_NEWLINE); | |
349 | vty_out (vty, " Referenced LS Type: %s%s", type, VTY_NEWLINE); | |
350 | vty_out (vty, " Referenced LS ID: %s%s", id, VTY_NEWLINE); | |
351 | vty_out (vty, " Referenced Advertising Router: %s%s", adv_router, | |
352 | VTY_NEWLINE); | |
353 | ||
354 | start = (char *) lsa->header + sizeof (struct ospf6_lsa_header) | |
355 | + sizeof (struct ospf6_intra_area_prefix_lsa); | |
356 | end = (char *) lsa->header + ntohs (lsa->header->length); | |
357 | ||
358 | for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) | |
359 | { | |
360 | prefix = (struct ospf6_prefix *) current; | |
361 | if (current + OSPF6_PREFIX_SIZE (prefix) > end) | |
362 | { | |
363 | vty_out (vty, " Trailing %d byte garbage ... Malformed%s", | |
364 | end - current, VTY_NEWLINE); | |
365 | return -1; | |
366 | } | |
367 | ||
368 | ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf)); | |
369 | vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); | |
370 | ||
371 | ospf6_prefix_in6_addr (prefix, &in6); | |
372 | inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); | |
373 | vty_out (vty, " Prefix: %s/%d%s", | |
374 | buf, prefix->prefix_length, VTY_NEWLINE); | |
375 | } | |
376 | ||
377 | return 0; | |
378 | } | |
379 | ||
380 | void | |
381 | ospf6_lsa_intra_prefix_update_transit (char *ifname) | |
382 | { | |
383 | char buffer [MAXLSASIZE]; | |
384 | u_int16_t size; | |
385 | struct ospf6_lsa *old; | |
386 | struct interface *ifp; | |
387 | struct ospf6_interface *o6i; | |
388 | struct ospf6_neighbor *o6n; | |
389 | ||
390 | struct ospf6_intra_area_prefix_lsa *iap; | |
391 | struct ospf6_lsdb_node n; | |
392 | listnode node; | |
393 | char *start, *end, *current; | |
394 | struct ospf6_prefix *prefix, *dup, *src, *dst; | |
395 | struct ospf6_link_lsa *link; | |
396 | char buf[128]; | |
397 | int count, prefix_num; | |
398 | ||
399 | list adv_list; | |
400 | ||
401 | ifp = if_lookup_by_name (ifname); | |
402 | if (! ifp) | |
403 | { | |
404 | zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s", | |
405 | ifname); | |
406 | return; | |
407 | } | |
408 | ||
409 | o6i = (struct ospf6_interface *) ifp->info; | |
410 | if (! o6i || ! o6i->area) | |
411 | { | |
412 | zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s", | |
413 | ifname); | |
414 | return; | |
415 | } | |
416 | ||
417 | /* find previous LSA */ | |
418 | old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), | |
419 | htonl (o6i->if_id), ospf6->router_id, | |
420 | o6i->area); | |
421 | ||
422 | /* Don't originate Network-LSA if not DR */ | |
423 | if (o6i->state != IFS_DR) | |
424 | { | |
425 | if (old) | |
426 | { | |
427 | if (IS_OSPF6_DUMP_PREFIX) | |
428 | zlog_info ("Update Intra-Prefix (Transit): %s not DR", | |
429 | o6i->interface->name); | |
430 | ospf6_lsa_premature_aging (old); | |
431 | } | |
432 | return; | |
433 | } | |
434 | ||
435 | /* If none of neighbor is adjacent to us */ | |
436 | count = 0; | |
437 | o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); | |
438 | if (count == 0) | |
439 | { | |
440 | if (IS_OSPF6_DUMP_PREFIX) | |
441 | zlog_info ("Update Intra-Prefix (Transit): %s is Stub", | |
442 | o6i->interface->name); | |
443 | if (old) | |
444 | ospf6_lsa_premature_aging (old); | |
445 | return; | |
446 | } | |
447 | ||
448 | if (IS_OSPF6_DUMP_PREFIX) | |
449 | zlog_info ("Update Intra-Prefix (Transit): Interface %s", | |
450 | o6i->interface->name); | |
451 | ||
452 | adv_list = list_new (); | |
453 | ||
454 | /* foreach Link-LSA associated with this Link */ | |
455 | for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb); | |
456 | ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n)) | |
457 | { | |
458 | if (IS_LSA_MAXAGE (n.lsa)) | |
459 | continue; | |
460 | ||
461 | if (IS_OSPF6_DUMP_PREFIX) | |
462 | zlog_info ("Update Intra-Prefix (Transit): Checking %s", | |
463 | n.lsa->str); | |
464 | ||
465 | /* Check status of the advertising router */ | |
466 | if (n.lsa->header->adv_router != o6i->area->ospf6->router_id) | |
467 | { | |
468 | o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i); | |
469 | if (! o6n) | |
470 | { | |
471 | if (IS_OSPF6_DUMP_PREFIX) | |
472 | zlog_info ("Update Intra-Prefix (Transit): neighbor not found"); | |
473 | continue; | |
474 | } | |
475 | ||
476 | if (o6n->state != NBS_FULL) | |
477 | { | |
478 | if (IS_OSPF6_DUMP_PREFIX) | |
479 | zlog_info ("Update Intra-Prefix (Transit): %s not FULL", | |
480 | o6n->str); | |
481 | continue; | |
482 | } | |
483 | } | |
484 | ||
485 | /* For each Prefix in this Link-LSA */ | |
486 | link = (struct ospf6_link_lsa *) (n.lsa->header + 1); | |
487 | prefix_num = ntohl (link->llsa_prefix_num); | |
488 | ||
489 | if (IS_OSPF6_DUMP_PREFIX) | |
490 | zlog_info (" Prefix #%d", prefix_num); | |
491 | ||
492 | start = (char *) (link + 1); | |
493 | end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length); | |
494 | prefix = (struct ospf6_prefix *) start; | |
495 | for (current = start; current < end; | |
496 | current += OSPF6_PREFIX_SIZE (prefix)) | |
497 | { | |
498 | prefix = (struct ospf6_prefix *) current; | |
499 | ospf6_prefix_string (prefix, buf, sizeof (buf)); | |
500 | ||
501 | /* Check duplicate prefix */ | |
502 | dup = ospf6_prefix_lookup (adv_list, prefix); | |
503 | if (dup) | |
504 | { | |
505 | if (IS_OSPF6_DUMP_PREFIX) | |
506 | zlog_info (" Duplicate %s", buf); | |
507 | dup->prefix_options |= prefix->prefix_options; | |
508 | continue; | |
509 | } | |
510 | ||
511 | if (prefix_num <= 0) | |
512 | { | |
513 | zlog_warn (" Wong prefix number ..."); | |
514 | break; | |
515 | } | |
516 | ||
517 | if (IS_OSPF6_DUMP_PREFIX) | |
518 | zlog_info (" Prefix %s", buf); | |
519 | ||
520 | /* copy prefix to advertise list */ | |
521 | ospf6_prefix_add (adv_list, prefix); | |
522 | ||
523 | prefix_num --; | |
524 | } | |
525 | } | |
526 | ||
527 | /* if no prefix to advertise, return */ | |
528 | if (listcount (adv_list) == 0) | |
529 | { | |
530 | if (IS_OSPF6_DUMP_PREFIX) | |
531 | zlog_info (" No Prefix to advertise"); | |
532 | if (old) | |
533 | ospf6_lsa_premature_aging (old); | |
534 | return; | |
535 | } | |
536 | ||
537 | /* prepare buffer */ | |
538 | memset (buffer, 0, sizeof (buffer)); | |
539 | size = sizeof (struct ospf6_intra_area_prefix_lsa); | |
540 | iap = (struct ospf6_intra_area_prefix_lsa *) buffer; | |
541 | ||
542 | /* Set Referenced LSA field */ | |
543 | iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK); | |
544 | iap->refer_lsid = htonl (o6i->if_id); | |
545 | iap->refer_advrtr = o6i->area->ospf6->router_id; | |
546 | ||
547 | dst = (struct ospf6_prefix *) (iap + 1); | |
548 | for (node = listhead (adv_list); node; nextnode (node)) | |
549 | { | |
550 | src = (struct ospf6_prefix *) getdata (node); | |
551 | ||
552 | memcpy (dst, src, OSPF6_PREFIX_SIZE (src)); | |
553 | ||
554 | size += OSPF6_PREFIX_SIZE (dst); | |
555 | dst = OSPF6_NEXT_PREFIX (dst); | |
556 | } | |
557 | iap->prefix_number = htons (listcount (adv_list)); | |
558 | ||
559 | while ((node = listhead (adv_list)) != NULL) | |
560 | { | |
561 | prefix = getdata (node); | |
562 | ospf6_prefix_delete (prefix); | |
563 | listnode_delete (adv_list, prefix); | |
564 | } | |
565 | list_delete (adv_list); | |
566 | ||
567 | ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), | |
568 | htonl (o6i->if_id), ospf6->router_id, | |
569 | buffer, size, o6i->area); | |
570 | } | |
571 | ||
572 | void | |
573 | ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id) | |
574 | { | |
575 | char buffer [MAXLSASIZE]; | |
576 | u_int16_t size; | |
577 | struct ospf6_lsa *old; | |
578 | struct ospf6_area *o6a; | |
579 | int count; | |
580 | ||
581 | struct ospf6_intra_area_prefix_lsa *iap; | |
582 | listnode i,j; | |
583 | struct ospf6_interface *o6i = NULL; | |
584 | struct ospf6_prefix *prefix, *dst, *src; | |
585 | struct connected *c; | |
586 | char buf[128]; | |
587 | ||
588 | list adv_list; | |
589 | listnode node; | |
590 | char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)]; | |
591 | ||
592 | o6a = ospf6_area_lookup (area_id, ospf6); | |
593 | if (! o6a) | |
594 | { | |
595 | char tmp[16]; | |
596 | inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp)); | |
597 | zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp); | |
598 | return; | |
599 | } | |
600 | else if (IS_OSPF6_DUMP_PREFIX) | |
601 | { | |
602 | zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str); | |
603 | } | |
604 | ||
605 | /* find previous LSA */ | |
606 | old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), | |
607 | htonl (0), ospf6->router_id, | |
608 | o6a); /* xxx, ls-id */ | |
609 | ||
610 | adv_list = list_new (); | |
611 | ||
612 | /* Examin for each interface */ | |
613 | for (i = listhead (o6a->if_list); i; nextnode (i)) | |
614 | { | |
615 | o6i = (struct ospf6_interface *) getdata (i); | |
616 | ||
617 | if (o6i->state == IFS_DOWN) | |
618 | { | |
619 | if (IS_OSPF6_DUMP_PREFIX) | |
620 | zlog_info (" Interface %s: down", o6i->interface->name); | |
621 | continue; | |
622 | } | |
623 | ||
624 | count = 0; | |
625 | o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state); | |
626 | if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP && | |
627 | count != 0) | |
628 | { | |
629 | /* This interface's prefix will be included in DR's */ | |
630 | if (IS_OSPF6_DUMP_PREFIX) | |
631 | zlog_info (" Interface %s: not stub", o6i->interface->name); | |
632 | continue; | |
633 | } | |
634 | ||
635 | if (IS_OSPF6_DUMP_PREFIX) | |
636 | zlog_info (" Interface %s:", o6i->interface->name); | |
637 | ||
638 | /* copy foreach address prefix */ | |
639 | for (j = listhead (o6i->interface->connected); j; nextnode (j)) | |
640 | { | |
641 | c = (struct connected *) getdata (j); | |
642 | ||
643 | /* filter prefix not IPv6 */ | |
644 | if (c->address->family != AF_INET6) | |
645 | continue; | |
646 | ||
647 | /* for log */ | |
648 | prefix2str (c->address, buf, sizeof (buf)); | |
649 | ||
650 | CONTINUE_IF_ADDRESS_LINKLOCAL (c->address); | |
651 | CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address); | |
652 | CONTINUE_IF_ADDRESS_LOOPBACK (c->address); | |
653 | CONTINUE_IF_ADDRESS_V4COMPAT (c->address); | |
654 | CONTINUE_IF_ADDRESS_V4MAPPED (c->address); | |
655 | ||
656 | /* filter prefix specified by configuration */ | |
657 | if (o6i->plist_name) | |
658 | { | |
659 | struct prefix_list *plist; | |
660 | enum prefix_list_type result = PREFIX_PERMIT; | |
661 | ||
662 | plist = prefix_list_lookup (AFI_IP6, o6i->plist_name); | |
663 | if (plist) | |
664 | result = prefix_list_apply (plist, c->address); | |
665 | else | |
666 | zlog_warn ("Update Intra-Prefix (Stub): " | |
667 | "Prefix list \"%s\" not found", | |
668 | o6i->plist_name); | |
669 | ||
670 | if (result == PREFIX_DENY) | |
671 | { | |
672 | if (IS_OSPF6_DUMP_PREFIX) | |
673 | zlog_info (" %s: Filtered by %s", | |
674 | buf, o6i->plist_name); | |
675 | continue; | |
676 | } | |
677 | } | |
678 | ||
679 | /* initialize buffer for ospf6 prefix */ | |
680 | memset (prefix_buf, 0, sizeof (prefix_buf)); | |
681 | prefix = (struct ospf6_prefix *) prefix_buf; | |
682 | ||
683 | /* set ospf6 prefix according to its state */ | |
684 | /* xxx, virtual links */ | |
685 | if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) && | |
686 | (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP | |
687 | /* xxx, PoinToMultiPoint I/F type */ )) | |
688 | { | |
689 | prefix->prefix_length = 128; | |
690 | prefix->prefix_options = OSPF6_PREFIX_OPTION_LA; | |
691 | prefix->prefix_metric = htons (0); | |
692 | memcpy (prefix + 1, &c->address->u.prefix6, | |
693 | OSPF6_PREFIX_SPACE (prefix->prefix_length)); | |
694 | } | |
695 | else | |
696 | { | |
697 | struct prefix_ipv6 prefix_ipv6; | |
698 | /* apply mask */ | |
699 | prefix_copy ((struct prefix *) &prefix_ipv6, c->address); | |
700 | apply_mask_ipv6 (&prefix_ipv6); | |
701 | ||
702 | prefix->prefix_length = prefix_ipv6.prefixlen; | |
703 | prefix->prefix_options = 0; /* xxx, no options yet */ | |
704 | prefix->prefix_metric = htons (o6i->cost); | |
705 | memcpy (prefix + 1, &prefix_ipv6.prefix, | |
706 | OSPF6_PREFIX_SPACE (prefix->prefix_length)); | |
707 | } | |
708 | ||
709 | ospf6_prefix_string (prefix, buf, sizeof (buf)); | |
710 | if (IS_OSPF6_DUMP_PREFIX) | |
711 | zlog_info (" Advertise %s", buf); | |
712 | ||
713 | /* check in the prefix to advertising prefix list */ | |
714 | ospf6_prefix_add (adv_list, prefix); | |
715 | } | |
716 | } | |
717 | ||
718 | /* If no prefix to advertise */ | |
719 | if (listcount (adv_list) == 0) | |
720 | { | |
721 | if (IS_OSPF6_DUMP_PREFIX) | |
722 | zlog_info (" No prefix to advertise"); | |
723 | if (old) | |
724 | ospf6_lsa_premature_aging (old); | |
725 | return; | |
726 | } | |
727 | ||
728 | /* prepare buffer */ | |
729 | memset (buffer, 0, sizeof (buffer)); | |
730 | size = sizeof (struct ospf6_intra_area_prefix_lsa); | |
731 | iap = (struct ospf6_intra_area_prefix_lsa *) buffer; | |
732 | ||
733 | /* Set Referenced LSA field */ | |
734 | iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER); | |
735 | iap->refer_lsid = htonl (0); | |
736 | iap->refer_advrtr = o6a->ospf6->router_id; | |
737 | ||
738 | dst = (struct ospf6_prefix *) (iap + 1); | |
739 | for (node = listhead (adv_list); node; nextnode (node)) | |
740 | { | |
741 | src = (struct ospf6_prefix *) getdata (node); | |
742 | ||
743 | memcpy (dst, src, OSPF6_PREFIX_SIZE (src)); | |
744 | ||
745 | size += OSPF6_PREFIX_SIZE (dst); | |
746 | dst = OSPF6_NEXT_PREFIX (dst); | |
747 | } | |
748 | iap->prefix_number = htons (listcount (adv_list)); | |
749 | ||
750 | while ((node = listhead (adv_list)) != NULL) | |
751 | { | |
752 | prefix = getdata (node); | |
753 | ospf6_prefix_delete (prefix); | |
754 | listnode_delete (adv_list, prefix); | |
755 | } | |
756 | list_delete (adv_list); | |
757 | ||
758 | ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX), | |
759 | htonl (0) /* xxx */, ospf6->router_id, | |
760 | buffer, size, o6a); | |
761 | } | |
762 | ||
763 | int | |
764 | ospf6_lsa_intra_prefix_hook_interface (void *interface) | |
765 | { | |
766 | struct ospf6_interface *o6i = interface; | |
767 | if (o6i->area) | |
768 | { | |
769 | ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); | |
770 | ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id); | |
771 | } | |
772 | return 0; | |
773 | } | |
774 | ||
775 | int | |
776 | ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor) | |
777 | { | |
778 | struct ospf6_neighbor *o6n = neighbor; | |
779 | if (o6n->ospf6_interface->area) | |
780 | { | |
781 | ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name); | |
782 | ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id); | |
783 | } | |
784 | return 0; | |
785 | } | |
786 | ||
787 | int | |
788 | ospf6_intra_prefix_link_database_hook (void *new) | |
789 | { | |
790 | struct ospf6_lsa *lsa = new; | |
791 | struct ospf6_interface *o6i; | |
792 | ||
793 | if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK)) | |
794 | return 0; | |
795 | ||
796 | o6i = lsa->scope; | |
797 | if (o6i->state != IFS_DR) | |
798 | return 0; | |
799 | ||
800 | ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); | |
801 | ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id); | |
802 | return 0; | |
803 | } | |
804 | ||
805 | int | |
806 | ospf6_lsa_intra_prefix_refresh (void *old) | |
807 | { | |
808 | struct ospf6_lsa *lsa = old; | |
809 | struct ospf6_interface *o6i; | |
810 | struct ospf6_area *o6a; | |
811 | u_int32_t id; | |
812 | ||
813 | id = ntohl (lsa->header->id); | |
814 | if (id) | |
815 | { | |
816 | o6i = ospf6_interface_lookup_by_index (id); | |
817 | if (o6i) | |
818 | ospf6_lsa_intra_prefix_update_transit (o6i->interface->name); | |
819 | else | |
820 | ospf6_lsa_premature_aging (lsa); | |
821 | } | |
822 | else | |
823 | { | |
824 | o6a = lsa->scope; | |
825 | ospf6_lsa_intra_prefix_update_stub (o6a->area_id); | |
826 | } | |
827 | ||
828 | return 0; | |
829 | } | |
830 | ||
831 | void | |
832 | ospf6_intra_prefix_register () | |
833 | { | |
834 | struct ospf6_lsa_slot slot, *sp; | |
835 | struct ospf6_hook hook; | |
836 | ||
837 | memset (&slot, 0, sizeof (struct ospf6_lsa_slot)); | |
838 | slot.type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX); | |
839 | slot.name = "Intra-Prefix"; | |
840 | slot.func_show = ospf6_lsa_intra_prefix_show; | |
841 | slot.func_refresh = ospf6_lsa_intra_prefix_refresh; | |
842 | ospf6_lsa_slot_register (&slot); | |
843 | ||
844 | memset (&hook, 0, sizeof (hook)); | |
845 | hook.name = "OriginateIntraPrefix"; | |
846 | hook.hook_add = ospf6_lsa_intra_prefix_hook_interface; | |
847 | hook.hook_change = ospf6_lsa_intra_prefix_hook_interface; | |
848 | hook.hook_remove = NULL; /* XXX */ | |
849 | ospf6_hook_register (&hook, &interface_hook); | |
850 | ||
851 | memset (&hook, 0, sizeof (hook)); | |
852 | hook.name = "OriginateIntraPrefix"; | |
853 | hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor; | |
854 | hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor; | |
855 | hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor; | |
856 | ospf6_hook_register (&hook, &neighbor_hook); | |
857 | ||
858 | sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX)); | |
859 | hook.name = "CalculateIntraPrefix"; | |
860 | hook.hook_add = ospf6_intra_prefix_database_hook_add; | |
861 | hook.hook_change = ospf6_intra_prefix_database_hook_add; | |
862 | hook.hook_remove = ospf6_intra_prefix_database_hook_remove; | |
863 | ospf6_hook_register (&hook, &sp->database_hook); | |
864 | } | |
865 | ||
866 | void | |
867 | ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old, | |
868 | struct ospf6_lsa *new) | |
869 | { | |
870 | if (old) | |
871 | ospf6_intra_prefix_database_hook_remove (old); | |
872 | if (new && ! IS_LSA_MAXAGE (new)) | |
873 | ospf6_intra_prefix_database_hook_add (new); | |
874 | } | |
875 | ||
876 | void | |
877 | ospf6_intra_database_hook_link (struct ospf6_lsa *old, | |
878 | struct ospf6_lsa *new) | |
879 | { | |
880 | ospf6_intra_prefix_link_database_hook (new); | |
881 | ospf6_spf_database_hook (old, new); | |
882 | } | |
883 | ||
884 | void | |
885 | ospf6_intra_init () | |
886 | { | |
887 | ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook = | |
888 | ospf6_intra_database_hook_intra_prefix; | |
889 | ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = | |
890 | ospf6_intra_database_hook_link; | |
891 | ||
892 | intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n"); | |
893 | ospf6_intra_prefix_register (); | |
894 | } | |
895 | ||
896 |