]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_intra.c
Initial revision
[mirror_frr.git] / ospf6d / ospf6_intra.c
CommitLineData
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
24static 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
30static void
31ospf6_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
92int
93ospf6_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
137int
138ospf6_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
189void
190ospf6_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
232void
233ospf6_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
329int
330ospf6_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
380void
381ospf6_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
572void
573ospf6_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
763int
764ospf6_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
775int
776ospf6_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
787int
788ospf6_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
805int
806ospf6_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
831void
832ospf6_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
866void
867ospf6_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
876void
877ospf6_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
884void
885ospf6_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