]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_intra.c
lib: add support for scripts directory
[mirror_frr.git] / ospf6d / ospf6_intra.c
1 /*
2 * Copyright (C) 2003 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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "linklist.h"
25 #include "thread.h"
26 #include "memory.h"
27 #include "if.h"
28 #include "prefix.h"
29 #include "table.h"
30 #include "vty.h"
31 #include "command.h"
32 #include "vrf.h"
33
34 #include "ospf6_proto.h"
35 #include "ospf6_message.h"
36 #include "ospf6_route.h"
37 #include "ospf6_lsa.h"
38 #include "ospf6_lsdb.h"
39
40 #include "ospf6_top.h"
41 #include "ospf6_area.h"
42 #include "ospf6_interface.h"
43 #include "ospf6_neighbor.h"
44 #include "ospf6_intra.h"
45 #include "ospf6_asbr.h"
46 #include "ospf6_abr.h"
47 #include "ospf6_flood.h"
48 #include "ospf6d.h"
49 #include "ospf6_spf.h"
50
51 unsigned char conf_debug_ospf6_brouter = 0;
52 uint32_t conf_debug_ospf6_brouter_specific_router_id;
53 uint32_t conf_debug_ospf6_brouter_specific_area_id;
54
55 #define MAX_LSA_PAYLOAD (1024 + 256)
56 /******************************/
57 /* RFC2740 3.4.3.1 Router-LSA */
58 /******************************/
59
60 static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf,
61 int buflen, int pos)
62 {
63 struct ospf6_router_lsa *router_lsa;
64 struct ospf6_router_lsdesc *lsdesc;
65 char *start, *end;
66 char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
67
68 if (lsa) {
69 router_lsa = (struct ospf6_router_lsa
70 *)((char *)lsa->header
71 + sizeof(struct ospf6_lsa_header));
72 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
73 end = (char *)lsa->header + ntohs(lsa->header->length);
74
75 lsdesc = (struct ospf6_router_lsdesc
76 *)(start
77 + pos * (sizeof(struct
78 ospf6_router_lsdesc)));
79 if ((char *)lsdesc < end) {
80 if (buf && (buflen > INET_ADDRSTRLEN * 2)) {
81 inet_ntop(AF_INET,
82 &lsdesc->neighbor_interface_id, buf1,
83 sizeof(buf1));
84 inet_ntop(AF_INET, &lsdesc->neighbor_router_id,
85 buf2, sizeof(buf2));
86 sprintf(buf, "%s/%s", buf2, buf1);
87 }
88 } else
89 return NULL;
90 }
91
92 return buf;
93 }
94
95 static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
96 {
97 char *start, *end, *current;
98 char buf[32], name[32], bits[16], options[32];
99 struct ospf6_router_lsa *router_lsa;
100 struct ospf6_router_lsdesc *lsdesc;
101
102 router_lsa =
103 (struct ospf6_router_lsa *)((char *)lsa->header
104 + sizeof(struct ospf6_lsa_header));
105
106 ospf6_capability_printbuf(router_lsa->bits, bits, sizeof(bits));
107 ospf6_options_printbuf(router_lsa->options, options, sizeof(options));
108 vty_out(vty, " Bits: %s Options: %s\n", bits, options);
109
110 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
111 end = (char *)lsa->header + ntohs(lsa->header->length);
112 for (current = start;
113 current + sizeof(struct ospf6_router_lsdesc) <= end;
114 current += sizeof(struct ospf6_router_lsdesc)) {
115 lsdesc = (struct ospf6_router_lsdesc *)current;
116
117 if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT)
118 snprintf(name, sizeof(name), "Point-To-Point");
119 else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK)
120 snprintf(name, sizeof(name), "Transit-Network");
121 else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK)
122 snprintf(name, sizeof(name), "Stub-Network");
123 else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK)
124 snprintf(name, sizeof(name), "Virtual-Link");
125 else
126 snprintf(name, sizeof(name), "Unknown (%#x)",
127 lsdesc->type);
128
129 vty_out(vty, " Type: %s Metric: %d\n", name,
130 ntohs(lsdesc->metric));
131 vty_out(vty, " Interface ID: %s\n",
132 inet_ntop(AF_INET, &lsdesc->interface_id, buf,
133 sizeof(buf)));
134 vty_out(vty, " Neighbor Interface ID: %s\n",
135 inet_ntop(AF_INET, &lsdesc->neighbor_interface_id, buf,
136 sizeof(buf)));
137 vty_out(vty, " Neighbor Router ID: %s\n",
138 inet_ntop(AF_INET, &lsdesc->neighbor_router_id, buf,
139 sizeof(buf)));
140 }
141 return 0;
142 }
143
144 static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
145 struct ospf6_router_lsa *router_lsa)
146 {
147 OSPF6_OPT_CLEAR_ALL(router_lsa->options);
148 memcpy(router_lsa->options, oa->options, 3);
149
150 if (ospf6_is_router_abr(oa->ospf6))
151 SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
152 else
153 UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
154
155 if (!IS_AREA_STUB(oa) && ospf6_asbr_is_asbr(oa->ospf6)) {
156 SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
157 } else {
158 UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
159 }
160
161 UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_V);
162 UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_W);
163 }
164
165 int ospf6_router_is_stub_router(struct ospf6_lsa *lsa)
166 {
167 struct ospf6_router_lsa *rtr_lsa;
168
169 if (lsa != NULL && OSPF6_LSA_IS_TYPE(ROUTER, lsa)) {
170 rtr_lsa = (struct ospf6_router_lsa
171 *)((caddr_t)lsa->header
172 + sizeof(struct ospf6_lsa_header));
173
174 if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_R)) {
175 return OSPF6_IS_STUB_ROUTER;
176 } else if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_V6)) {
177 return OSPF6_IS_STUB_ROUTER_V6;
178 }
179 }
180
181 return OSPF6_NOT_STUB_ROUTER;
182 }
183
184 int ospf6_router_lsa_originate(struct thread *thread)
185 {
186 struct ospf6_area *oa;
187
188 char buffer[OSPF6_MAX_LSASIZE];
189 struct ospf6_lsa_header *lsa_header;
190 struct ospf6_lsa *lsa;
191
192 uint32_t link_state_id = 0;
193 struct listnode *node, *nnode;
194 struct listnode *j;
195 struct ospf6_interface *oi;
196 struct ospf6_neighbor *on, *drouter = NULL;
197 struct ospf6_router_lsa *router_lsa;
198 struct ospf6_router_lsdesc *lsdesc;
199 uint16_t type;
200 uint32_t router;
201 int count;
202
203 oa = (struct ospf6_area *)THREAD_ARG(thread);
204 oa->thread_router_lsa = NULL;
205
206 if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
207 zlog_debug("Originate Router-LSA for Area %s", oa->name);
208
209 memset(buffer, 0, sizeof(buffer));
210 lsa_header = (struct ospf6_lsa_header *)buffer;
211 router_lsa =
212 (struct ospf6_router_lsa *)((caddr_t)lsa_header
213 + sizeof(struct ospf6_lsa_header));
214
215 ospf6_router_lsa_options_set(oa, router_lsa);
216
217 /* describe links for each interfaces */
218 lsdesc = (struct ospf6_router_lsdesc
219 *)((caddr_t)router_lsa
220 + sizeof(struct ospf6_router_lsa));
221
222 for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
223 /* Interfaces in state Down or Loopback are not described */
224 if (oi->state == OSPF6_INTERFACE_DOWN
225 || oi->state == OSPF6_INTERFACE_LOOPBACK)
226 continue;
227
228 /* Nor are interfaces without any full adjacencies described */
229 count = 0;
230 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on))
231 if (on->state == OSPF6_NEIGHBOR_FULL)
232 count++;
233
234 if (count == 0)
235 continue;
236
237 /* Multiple Router-LSA instance according to size limit setting
238 */
239 if ((oa->router_lsa_size_limit != 0)
240 && ((size_t)((char *)lsdesc - buffer)
241 + sizeof(struct ospf6_router_lsdesc)
242 > oa->router_lsa_size_limit)) {
243 if ((caddr_t)lsdesc
244 == (caddr_t)router_lsa
245 + sizeof(struct ospf6_router_lsa)) {
246 if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
247 zlog_debug(
248 "Size limit setting for Router-LSA too short");
249 return 0;
250 }
251
252 /* Fill LSA Header */
253 lsa_header->age = 0;
254 lsa_header->type = htons(OSPF6_LSTYPE_ROUTER);
255 lsa_header->id = htonl(link_state_id);
256 lsa_header->adv_router = oa->ospf6->router_id;
257 lsa_header->seqnum = ospf6_new_ls_seqnum(
258 lsa_header->type, lsa_header->id,
259 lsa_header->adv_router, oa->lsdb);
260 lsa_header->length =
261 htons((caddr_t)lsdesc - (caddr_t)buffer);
262
263 /* LSA checksum */
264 ospf6_lsa_checksum(lsa_header);
265
266 /* create LSA */
267 lsa = ospf6_lsa_create(lsa_header);
268
269 /* Originate */
270 ospf6_lsa_originate_area(lsa, oa);
271
272 /* Reset Buffer to fill next Router LSA */
273 memset(buffer, 0, sizeof(buffer));
274 lsa_header = (struct ospf6_lsa_header *)buffer;
275 router_lsa =
276 (struct ospf6_router_lsa
277 *)((caddr_t)lsa_header
278 + sizeof(struct ospf6_lsa_header));
279
280 ospf6_router_lsa_options_set(oa, router_lsa);
281
282 /* describe links for each interfaces */
283 lsdesc = (struct ospf6_router_lsdesc
284 *)((caddr_t)router_lsa
285 + sizeof(struct ospf6_router_lsa));
286
287 link_state_id++;
288 }
289
290 /* Point-to-Point interfaces */
291 if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
292 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
293 if (on->state != OSPF6_NEIGHBOR_FULL)
294 continue;
295
296 lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
297 lsdesc->metric = htons(oi->cost);
298 lsdesc->interface_id =
299 htonl(oi->interface->ifindex);
300 lsdesc->neighbor_interface_id =
301 htonl(on->ifindex);
302 lsdesc->neighbor_router_id = on->router_id;
303
304 lsdesc++;
305 }
306 }
307
308 /* Broadcast and NBMA interfaces */
309 else if (oi->type == OSPF_IFTYPE_BROADCAST) {
310 /* If this router is not DR,
311 and If this router not fully adjacent with DR,
312 this interface is not transit yet: ignore. */
313 if (oi->state != OSPF6_INTERFACE_DR) {
314 drouter =
315 ospf6_neighbor_lookup(oi->drouter, oi);
316 if (drouter == NULL
317 || drouter->state != OSPF6_NEIGHBOR_FULL)
318 continue;
319 }
320
321 lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK;
322 lsdesc->metric = htons(oi->cost);
323 lsdesc->interface_id = htonl(oi->interface->ifindex);
324 if (oi->state != OSPF6_INTERFACE_DR) {
325 lsdesc->neighbor_interface_id =
326 htonl(drouter->ifindex);
327 lsdesc->neighbor_router_id = drouter->router_id;
328 } else {
329 lsdesc->neighbor_interface_id =
330 htonl(oi->interface->ifindex);
331 lsdesc->neighbor_router_id =
332 oi->area->ospf6->router_id;
333 }
334
335 lsdesc++;
336 } else {
337 assert(0); /* Unknown interface type */
338 }
339
340 /* Virtual links */
341 /* xxx */
342 /* Point-to-Multipoint interfaces */
343 /* xxx */
344 }
345
346 /* Fill LSA Header */
347 lsa_header->age = 0;
348 lsa_header->type = htons(OSPF6_LSTYPE_ROUTER);
349 lsa_header->id = htonl(link_state_id);
350 lsa_header->adv_router = oa->ospf6->router_id;
351 lsa_header->seqnum =
352 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
353 lsa_header->adv_router, oa->lsdb);
354 lsa_header->length = htons((caddr_t)lsdesc - (caddr_t)buffer);
355
356 /* LSA checksum */
357 ospf6_lsa_checksum(lsa_header);
358
359 /* create LSA */
360 lsa = ospf6_lsa_create(lsa_header);
361
362 /* Originate */
363 ospf6_lsa_originate_area(lsa, oa);
364
365 link_state_id++;
366
367 /* Do premature-aging of rest, undesired Router-LSAs */
368 type = ntohs(OSPF6_LSTYPE_ROUTER);
369 router = oa->ospf6->router_id;
370 count = 0;
371 for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router, lsa)) {
372 if (ntohl(lsa->header->id) < link_state_id)
373 continue;
374 ospf6_lsa_purge(lsa);
375 count++;
376 }
377
378 /*
379 * Waiting till the LSA is actually removed from the database to trigger
380 * SPF delays network convergence. Unlike IPv4, for an ABR, when all
381 * interfaces associated with an area are gone, triggering an SPF right
382 * away
383 * helps convergence with inter-area routes.
384 */
385 if (count && !link_state_id)
386 ospf6_spf_schedule(oa->ospf6,
387 OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED);
388
389 return 0;
390 }
391
392 /*******************************/
393 /* RFC2740 3.4.3.2 Network-LSA */
394 /*******************************/
395
396 static char *ospf6_network_lsa_get_ar_id(struct ospf6_lsa *lsa, char *buf,
397 int buflen, int pos)
398 {
399 char *start, *end, *current;
400 struct ospf6_network_lsa *network_lsa;
401 struct ospf6_network_lsdesc *lsdesc;
402
403 if (lsa) {
404 network_lsa = (struct ospf6_network_lsa
405 *)((caddr_t)lsa->header
406 + sizeof(struct ospf6_lsa_header));
407
408 start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
409 end = (char *)lsa->header + ntohs(lsa->header->length);
410 current = start + pos * (sizeof(struct ospf6_network_lsdesc));
411
412 if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) {
413 lsdesc = (struct ospf6_network_lsdesc *)current;
414 if (buf)
415 inet_ntop(AF_INET, &lsdesc->router_id, buf,
416 buflen);
417 } else
418 return NULL;
419 }
420
421 return (buf);
422 }
423
424 static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
425 {
426 char *start, *end, *current;
427 struct ospf6_network_lsa *network_lsa;
428 struct ospf6_network_lsdesc *lsdesc;
429 char buf[128], options[32];
430
431 network_lsa =
432 (struct ospf6_network_lsa *)((caddr_t)lsa->header
433 + sizeof(struct ospf6_lsa_header));
434
435 ospf6_options_printbuf(network_lsa->options, options, sizeof(options));
436 vty_out(vty, " Options: %s\n", options);
437
438 start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
439 end = (char *)lsa->header + ntohs(lsa->header->length);
440 for (current = start;
441 current + sizeof(struct ospf6_network_lsdesc) <= end;
442 current += sizeof(struct ospf6_network_lsdesc)) {
443 lsdesc = (struct ospf6_network_lsdesc *)current;
444 inet_ntop(AF_INET, &lsdesc->router_id, buf, sizeof(buf));
445 vty_out(vty, " Attached Router: %s\n", buf);
446 }
447 return 0;
448 }
449
450 int ospf6_network_lsa_originate(struct thread *thread)
451 {
452 struct ospf6_interface *oi;
453
454 char buffer[OSPF6_MAX_LSASIZE];
455 struct ospf6_lsa_header *lsa_header;
456
457 int count;
458 struct ospf6_lsa *old, *lsa;
459 struct ospf6_network_lsa *network_lsa;
460 struct ospf6_network_lsdesc *lsdesc;
461 struct ospf6_neighbor *on;
462 struct ospf6_link_lsa *link_lsa;
463 struct listnode *i;
464 uint16_t type;
465
466 oi = (struct ospf6_interface *)THREAD_ARG(thread);
467 oi->thread_network_lsa = NULL;
468
469 /* The interface must be enabled until here. A Network-LSA of a
470 disabled interface (but was once enabled) should be flushed
471 by ospf6_lsa_refresh (), and does not come here. */
472 assert(oi->area);
473
474 old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
475 htonl(oi->interface->ifindex),
476 oi->area->ospf6->router_id, oi->area->lsdb);
477
478 /* Do not originate Network-LSA if not DR */
479 if (oi->state != OSPF6_INTERFACE_DR) {
480 if (old) {
481 ospf6_lsa_purge(old);
482 /*
483 * Waiting till the LSA is actually removed from the
484 * database to
485 * trigger SPF delays network convergence.
486 */
487 ospf6_spf_schedule(
488 oi->area->ospf6,
489 OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED);
490 }
491 return 0;
492 }
493
494 if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK))
495 zlog_debug("Originate Network-LSA for Interface %s",
496 oi->interface->name);
497
498 /* If none of neighbor is adjacent to us */
499 count = 0;
500
501 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on))
502 if (on->state == OSPF6_NEIGHBOR_FULL)
503 count++;
504
505 if (count == 0) {
506 if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK))
507 zlog_debug("Interface stub, ignore");
508 if (old)
509 ospf6_lsa_purge(old);
510 return 0;
511 }
512
513 /* prepare buffer */
514 memset(buffer, 0, sizeof(buffer));
515 lsa_header = (struct ospf6_lsa_header *)buffer;
516 network_lsa =
517 (struct ospf6_network_lsa *)((caddr_t)lsa_header
518 + sizeof(struct ospf6_lsa_header));
519
520 /* Collect the interface's Link-LSAs to describe
521 network's optional capabilities */
522 type = htons(OSPF6_LSTYPE_LINK);
523 for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
524 link_lsa = (struct ospf6_link_lsa
525 *)((caddr_t)lsa->header
526 + sizeof(struct ospf6_lsa_header));
527 network_lsa->options[0] |= link_lsa->options[0];
528 network_lsa->options[1] |= link_lsa->options[1];
529 network_lsa->options[2] |= link_lsa->options[2];
530 }
531
532 lsdesc = (struct ospf6_network_lsdesc
533 *)((caddr_t)network_lsa
534 + sizeof(struct ospf6_network_lsa));
535
536 /* set Link Description to the router itself */
537 lsdesc->router_id = oi->area->ospf6->router_id;
538 lsdesc++;
539
540 /* Walk through the neighbors */
541 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on)) {
542 if (on->state != OSPF6_NEIGHBOR_FULL)
543 continue;
544
545 /* set this neighbor's Router-ID to LSA */
546 lsdesc->router_id = on->router_id;
547 lsdesc++;
548 }
549
550 /* Fill LSA Header */
551 lsa_header->age = 0;
552 lsa_header->type = htons(OSPF6_LSTYPE_NETWORK);
553 lsa_header->id = htonl(oi->interface->ifindex);
554 lsa_header->adv_router = oi->area->ospf6->router_id;
555 lsa_header->seqnum =
556 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
557 lsa_header->adv_router, oi->area->lsdb);
558 lsa_header->length = htons((caddr_t)lsdesc - (caddr_t)buffer);
559
560 /* LSA checksum */
561 ospf6_lsa_checksum(lsa_header);
562
563 /* create LSA */
564 lsa = ospf6_lsa_create(lsa_header);
565
566 /* Originate */
567 ospf6_lsa_originate_area(lsa, oi->area);
568
569 return 0;
570 }
571
572
573 /****************************/
574 /* RFC2740 3.4.3.6 Link-LSA */
575 /****************************/
576
577 static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf,
578 int buflen, int pos)
579 {
580 char *start, *end, *current;
581 struct ospf6_link_lsa *link_lsa;
582 struct in6_addr in6;
583 struct ospf6_prefix *prefix;
584 int cnt = 0, prefixnum;
585
586 if (lsa) {
587 link_lsa = (struct ospf6_link_lsa
588 *)((caddr_t)lsa->header
589 + sizeof(struct ospf6_lsa_header));
590
591 if (pos == 0) {
592 inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
593 buflen);
594 return (buf);
595 }
596
597 prefixnum = ntohl(link_lsa->prefix_num);
598 if (pos > prefixnum)
599 return NULL;
600
601 start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
602 end = (char *)lsa->header + ntohs(lsa->header->length);
603 current = start;
604
605 do {
606 prefix = (struct ospf6_prefix *)current;
607 if (prefix->prefix_length == 0
608 || current + OSPF6_PREFIX_SIZE(prefix) > end) {
609 return NULL;
610 }
611
612 if (cnt < pos) {
613 current =
614 start + pos * OSPF6_PREFIX_SIZE(prefix);
615 cnt++;
616 } else {
617 memset(&in6, 0, sizeof(in6));
618 memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
619 OSPF6_PREFIX_SPACE(
620 prefix->prefix_length));
621 inet_ntop(AF_INET6, &in6, buf, buflen);
622 return (buf);
623 }
624 } while (current <= end);
625 }
626 return NULL;
627 }
628
629 static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
630 {
631 char *start, *end, *current;
632 struct ospf6_link_lsa *link_lsa;
633 int prefixnum;
634 char buf[128], options[32];
635 struct ospf6_prefix *prefix;
636 const char *p, *mc, *la, *nu;
637 struct in6_addr in6;
638
639 link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header
640 + sizeof(struct ospf6_lsa_header));
641
642 ospf6_options_printbuf(link_lsa->options, options, sizeof(options));
643 inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf));
644 prefixnum = ntohl(link_lsa->prefix_num);
645
646 vty_out(vty, " Priority: %d Options: %s\n", link_lsa->priority,
647 options);
648 vty_out(vty, " LinkLocal Address: %s\n", buf);
649 vty_out(vty, " Number of Prefix: %d\n", prefixnum);
650
651 start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
652 end = (char *)lsa->header + ntohs(lsa->header->length);
653 for (current = start; current < end;
654 current += OSPF6_PREFIX_SIZE(prefix)) {
655 prefix = (struct ospf6_prefix *)current;
656 if (prefix->prefix_length == 0
657 || current + OSPF6_PREFIX_SIZE(prefix) > end)
658 break;
659
660 p = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_P)
661 ? "P"
662 : "--");
663 mc = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_MC)
664 ? "MC"
665 : "--");
666 la = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_LA)
667 ? "LA"
668 : "--");
669 nu = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_NU)
670 ? "NU"
671 : "--");
672 vty_out(vty, " Prefix Options: %s|%s|%s|%s\n", p, mc, la,
673 nu);
674
675 memset(&in6, 0, sizeof(in6));
676 memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
677 OSPF6_PREFIX_SPACE(prefix->prefix_length));
678 inet_ntop(AF_INET6, &in6, buf, sizeof(buf));
679 vty_out(vty, " Prefix: %s/%d\n", buf,
680 prefix->prefix_length);
681 }
682
683 return 0;
684 }
685
686 int ospf6_link_lsa_originate(struct thread *thread)
687 {
688 struct ospf6_interface *oi;
689
690 char buffer[OSPF6_MAX_LSASIZE];
691 struct ospf6_lsa_header *lsa_header;
692 struct ospf6_lsa *old, *lsa;
693
694 struct ospf6_link_lsa *link_lsa;
695 struct ospf6_route *route;
696 struct ospf6_prefix *op;
697
698 oi = (struct ospf6_interface *)THREAD_ARG(thread);
699 oi->thread_link_lsa = NULL;
700
701 assert(oi->area);
702
703 /* find previous LSA */
704 old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_LINK),
705 htonl(oi->interface->ifindex),
706 oi->area->ospf6->router_id, oi->lsdb);
707
708 if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
709 if (old)
710 ospf6_lsa_purge(old);
711 return 0;
712 }
713
714 if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
715 zlog_debug("Originate Link-LSA for Interface %s",
716 oi->interface->name);
717
718 /* can't make Link-LSA if linklocal address not set */
719 if (oi->linklocal_addr == NULL) {
720 if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
721 zlog_debug(
722 "No Linklocal address on %s, defer originating",
723 oi->interface->name);
724 if (old)
725 ospf6_lsa_purge(old);
726 return 0;
727 }
728
729 /* prepare buffer */
730 memset(buffer, 0, sizeof(buffer));
731 lsa_header = (struct ospf6_lsa_header *)buffer;
732 link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa_header
733 + sizeof(struct ospf6_lsa_header));
734
735 /* Fill Link-LSA */
736 link_lsa->priority = oi->priority;
737 memcpy(link_lsa->options, oi->area->options, 3);
738 memcpy(&link_lsa->linklocal_addr, oi->linklocal_addr,
739 sizeof(struct in6_addr));
740 link_lsa->prefix_num = htonl(oi->route_connected->count);
741
742 op = (struct ospf6_prefix *)((caddr_t)link_lsa
743 + sizeof(struct ospf6_link_lsa));
744
745 /* connected prefix to advertise */
746 for (route = ospf6_route_head(oi->route_connected); route;
747 route = ospf6_route_next(route)) {
748 op->prefix_length = route->prefix.prefixlen;
749 op->prefix_options = route->path.prefix_options;
750 op->prefix_metric = htons(0);
751 memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
752 OSPF6_PREFIX_SPACE(op->prefix_length));
753 op = OSPF6_PREFIX_NEXT(op);
754 }
755
756 /* Fill LSA Header */
757 lsa_header->age = 0;
758 lsa_header->type = htons(OSPF6_LSTYPE_LINK);
759 lsa_header->id = htonl(oi->interface->ifindex);
760 lsa_header->adv_router = oi->area->ospf6->router_id;
761 lsa_header->seqnum =
762 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
763 lsa_header->adv_router, oi->lsdb);
764 lsa_header->length = htons((caddr_t)op - (caddr_t)buffer);
765
766 /* LSA checksum */
767 ospf6_lsa_checksum(lsa_header);
768
769 /* create LSA */
770 lsa = ospf6_lsa_create(lsa_header);
771
772 /* Originate */
773 ospf6_lsa_originate_interface(lsa, oi);
774
775 return 0;
776 }
777
778
779 /*****************************************/
780 /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
781 /*****************************************/
782 static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
783 char *buf, int buflen,
784 int pos)
785 {
786 char *start, *end, *current;
787 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
788 struct in6_addr in6;
789 int prefixnum, cnt = 0;
790 struct ospf6_prefix *prefix;
791
792 if (lsa) {
793 intra_prefix_lsa =
794 (struct ospf6_intra_prefix_lsa
795 *)((caddr_t)lsa->header
796 + sizeof(struct ospf6_lsa_header));
797
798 prefixnum = ntohs(intra_prefix_lsa->prefix_num);
799 if (pos > prefixnum)
800 return NULL;
801
802 start = (char *)intra_prefix_lsa
803 + sizeof(struct ospf6_intra_prefix_lsa);
804 end = (char *)lsa->header + ntohs(lsa->header->length);
805 current = start;
806
807 do {
808 prefix = (struct ospf6_prefix *)current;
809 if (prefix->prefix_length == 0
810 || current + OSPF6_PREFIX_SIZE(prefix) > end) {
811 return NULL;
812 }
813
814 if (cnt < pos) {
815 current =
816 start + pos * OSPF6_PREFIX_SIZE(prefix);
817 cnt++;
818 } else {
819 memset(&in6, 0, sizeof(in6));
820 memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
821 OSPF6_PREFIX_SPACE(
822 prefix->prefix_length));
823 inet_ntop(AF_INET6, &in6, buf, buflen);
824 sprintf(&buf[strlen(buf)], "/%d",
825 prefix->prefix_length);
826 return (buf);
827 }
828 } while (current <= end);
829 }
830 return (buf);
831 }
832
833 static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
834 {
835 char *start, *end, *current;
836 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
837 int prefixnum;
838 char buf[128];
839 struct ospf6_prefix *prefix;
840 char id[16], adv_router[16];
841 const char *p, *mc, *la, *nu;
842 struct in6_addr in6;
843
844 intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
845 *)((caddr_t)lsa->header
846 + sizeof(struct ospf6_lsa_header));
847
848 prefixnum = ntohs(intra_prefix_lsa->prefix_num);
849
850 vty_out(vty, " Number of Prefix: %d\n", prefixnum);
851
852 inet_ntop(AF_INET, &intra_prefix_lsa->ref_id, id, sizeof(id));
853 inet_ntop(AF_INET, &intra_prefix_lsa->ref_adv_router, adv_router,
854 sizeof(adv_router));
855 vty_out(vty, " Reference: %s Id: %s Adv: %s\n",
856 ospf6_lstype_name(intra_prefix_lsa->ref_type), id, adv_router);
857
858 start = (char *)intra_prefix_lsa
859 + sizeof(struct ospf6_intra_prefix_lsa);
860 end = (char *)lsa->header + ntohs(lsa->header->length);
861 for (current = start; current < end;
862 current += OSPF6_PREFIX_SIZE(prefix)) {
863 prefix = (struct ospf6_prefix *)current;
864 if (prefix->prefix_length == 0
865 || current + OSPF6_PREFIX_SIZE(prefix) > end)
866 break;
867
868 p = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_P)
869 ? "P"
870 : "--");
871 mc = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_MC)
872 ? "MC"
873 : "--");
874 la = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_LA)
875 ? "LA"
876 : "--");
877 nu = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_NU)
878 ? "NU"
879 : "--");
880 vty_out(vty, " Prefix Options: %s|%s|%s|%s\n", p, mc, la,
881 nu);
882
883 memset(&in6, 0, sizeof(in6));
884 memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
885 OSPF6_PREFIX_SPACE(prefix->prefix_length));
886 inet_ntop(AF_INET6, &in6, buf, sizeof(buf));
887 vty_out(vty, " Prefix: %s/%d\n", buf,
888 prefix->prefix_length);
889 }
890
891 return 0;
892 }
893
894 int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
895 {
896 struct ospf6_area *oa;
897
898 char buffer[OSPF6_MAX_LSASIZE];
899 struct ospf6_lsa_header *lsa_header;
900 struct ospf6_lsa *old, *lsa, *old_next = NULL;
901
902 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
903 struct ospf6_interface *oi;
904 struct ospf6_neighbor *on;
905 struct ospf6_route *route;
906 struct ospf6_prefix *op;
907 struct listnode *i, *j;
908 int full_count = 0;
909 unsigned short prefix_num = 0;
910 struct ospf6_route_table *route_advertise;
911 int ls_id = 0;
912
913 oa = (struct ospf6_area *)THREAD_ARG(thread);
914 oa->thread_intra_prefix_lsa = NULL;
915
916 /* find previous LSA */
917 old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX), htonl(0),
918 oa->ospf6->router_id, oa->lsdb);
919
920 if (!IS_AREA_ENABLED(oa)) {
921 if (old) {
922 ospf6_lsa_purge(old);
923 /* find previous LSA */
924 old_next = ospf6_lsdb_lookup(
925 htons(OSPF6_LSTYPE_INTRA_PREFIX),
926 htonl(++ls_id), oa->ospf6->router_id, oa->lsdb);
927
928 while (old_next) {
929 ospf6_lsa_purge(old_next);
930 old_next = ospf6_lsdb_lookup(
931 htons(OSPF6_LSTYPE_INTRA_PREFIX),
932 htonl(++ls_id), oa->ospf6->router_id,
933 oa->lsdb);
934 }
935 }
936 return 0;
937 }
938
939 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
940 zlog_debug(
941 "Originate Intra-Area-Prefix-LSA for area %s's stub prefix",
942 oa->name);
943
944 /* prepare buffer */
945 memset(buffer, 0, sizeof(buffer));
946 lsa_header = (struct ospf6_lsa_header *)buffer;
947 intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
948 *)((caddr_t)lsa_header
949 + sizeof(struct ospf6_lsa_header));
950
951 /* Fill Intra-Area-Prefix-LSA */
952 intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
953 intra_prefix_lsa->ref_id = htonl(0);
954 intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
955
956 route_advertise = ospf6_route_table_create(0, 0);
957
958 for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi)) {
959 if (oi->state == OSPF6_INTERFACE_DOWN) {
960 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
961 zlog_debug(" Interface %s is down, ignore",
962 oi->interface->name);
963 continue;
964 }
965
966 full_count = 0;
967
968 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on))
969 if (on->state == OSPF6_NEIGHBOR_FULL)
970 full_count++;
971
972 if (oi->state != OSPF6_INTERFACE_LOOPBACK
973 && oi->state != OSPF6_INTERFACE_POINTTOPOINT
974 && full_count != 0) {
975 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
976 zlog_debug(" Interface %s is not stub, ignore",
977 oi->interface->name);
978 continue;
979 }
980
981 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
982 zlog_debug(" Interface %s:", oi->interface->name);
983
984 /* connected prefix to advertise */
985 for (route = ospf6_route_head(oi->route_connected); route;
986 route = ospf6_route_best_next(route)) {
987 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
988 zlog_debug(" include %pFX", &route->prefix);
989 ospf6_route_add(ospf6_route_copy(route),
990 route_advertise, oa->ospf6);
991 }
992 }
993
994 if (route_advertise->count == 0) {
995 if (old) {
996 ls_id = 0;
997 ospf6_lsa_purge(old);
998 /* find previous LSA */
999 old_next = ospf6_lsdb_lookup(
1000 htons(OSPF6_LSTYPE_INTRA_PREFIX),
1001 htonl(++ls_id), oa->ospf6->router_id, oa->lsdb);
1002
1003 while (old_next) {
1004 ospf6_lsa_purge(old_next);
1005 old_next = ospf6_lsdb_lookup(
1006 htons(OSPF6_LSTYPE_INTRA_PREFIX),
1007 htonl(++ls_id), oa->ospf6->router_id,
1008 oa->lsdb);
1009 }
1010 }
1011 ospf6_route_table_delete(route_advertise, oa->ospf6);
1012 return 0;
1013 }
1014
1015 /* Neighbor change to FULL, if INTRA-AREA-PREFIX LSA
1016 * has not change, Flush old LSA and Re-Originate INP,
1017 * as ospf6_flood() checks if LSA is same as DB,
1018 * it won't be updated to neighbor's DB.
1019 */
1020 if (oa->intra_prefix_originate) {
1021 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1022 zlog_debug(
1023 "%s: Re-originate intra prefix LSA, Current full nbrs %u",
1024 __func__, oa->full_nbrs);
1025 if (old)
1026 ospf6_lsa_purge_multi_ls_id(oa, old);
1027 oa->intra_prefix_originate = 0;
1028 }
1029
1030 /* put prefixes to advertise */
1031 prefix_num = 0;
1032 op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
1033 + sizeof(struct ospf6_intra_prefix_lsa));
1034 for (route = ospf6_route_head(route_advertise); route;
1035 route = ospf6_route_best_next(route)) {
1036 if (((caddr_t)op - (caddr_t)lsa_header) > MAX_LSA_PAYLOAD) {
1037
1038 intra_prefix_lsa->prefix_num = htons(prefix_num);
1039
1040 /* Fill LSA Header */
1041 lsa_header->age = 0;
1042 lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1043 lsa_header->id = htonl(ls_id++);
1044 lsa_header->adv_router = oa->ospf6->router_id;
1045 lsa_header->seqnum = ospf6_new_ls_seqnum(
1046 lsa_header->type, lsa_header->id,
1047 lsa_header->adv_router, oa->lsdb);
1048 lsa_header->length =
1049 htons((caddr_t)op - (caddr_t)lsa_header);
1050
1051 /* LSA checksum */
1052 ospf6_lsa_checksum(lsa_header);
1053
1054 /* Create LSA */
1055 lsa = ospf6_lsa_create(lsa_header);
1056
1057 /* Originate */
1058 ospf6_lsa_originate_area(lsa, oa);
1059
1060 /* Prepare next buffer */
1061 memset(buffer, 0, sizeof(buffer));
1062 lsa_header = (struct ospf6_lsa_header *)buffer;
1063 intra_prefix_lsa =
1064 (struct ospf6_intra_prefix_lsa
1065 *)((caddr_t)lsa_header
1066 + sizeof(struct ospf6_lsa_header));
1067
1068 /* Fill Intra-Area-Prefix-LSA */
1069 intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
1070 intra_prefix_lsa->ref_id = htonl(0);
1071 intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
1072
1073 /* Put next set of prefixes to advertise */
1074 prefix_num = 0;
1075 op = (struct ospf6_prefix
1076 *)((caddr_t)intra_prefix_lsa
1077 + sizeof(struct
1078 ospf6_intra_prefix_lsa));
1079 }
1080
1081 op->prefix_length = route->prefix.prefixlen;
1082 op->prefix_options = route->path.prefix_options;
1083 op->prefix_metric = htons(route->path.cost);
1084 memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
1085 OSPF6_PREFIX_SPACE(op->prefix_length));
1086 prefix_num++;
1087
1088 op = OSPF6_PREFIX_NEXT(op);
1089 }
1090
1091 ospf6_route_table_delete(route_advertise, oa->ospf6);
1092
1093 if (prefix_num == 0) {
1094 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1095 zlog_debug(
1096 "Quit to Advertise Intra-Prefix: no route to advertise");
1097 return 0;
1098 }
1099
1100 intra_prefix_lsa->prefix_num = htons(prefix_num);
1101
1102 /* Fill LSA Header */
1103 lsa_header->age = 0;
1104 lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1105 lsa_header->id = htonl(ls_id++);
1106 lsa_header->adv_router = oa->ospf6->router_id;
1107 lsa_header->seqnum =
1108 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
1109 lsa_header->adv_router, oa->lsdb);
1110 lsa_header->length = htons((caddr_t)op - (caddr_t)lsa_header);
1111
1112 /* LSA checksum */
1113 ospf6_lsa_checksum(lsa_header);
1114
1115 /* create LSA */
1116 lsa = ospf6_lsa_create(lsa_header);
1117
1118 /* Originate */
1119 ospf6_lsa_originate_area(lsa, oa);
1120
1121 return 0;
1122 }
1123
1124
1125 int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
1126 {
1127 struct ospf6_interface *oi;
1128
1129 char buffer[OSPF6_MAX_LSASIZE];
1130 struct ospf6_lsa_header *lsa_header;
1131 struct ospf6_lsa *old, *lsa;
1132
1133 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1134 struct ospf6_neighbor *on;
1135 struct ospf6_route *route;
1136 struct ospf6_prefix *op;
1137 struct listnode *i;
1138 int full_count = 0;
1139 unsigned short prefix_num = 0;
1140 struct ospf6_route_table *route_advertise;
1141 struct ospf6_link_lsa *link_lsa;
1142 char *start, *end, *current;
1143 uint16_t type;
1144
1145 oi = (struct ospf6_interface *)THREAD_ARG(thread);
1146 oi->thread_intra_prefix_lsa = NULL;
1147
1148 assert(oi->area);
1149
1150 /* find previous LSA */
1151 old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX),
1152 htonl(oi->interface->ifindex),
1153 oi->area->ospf6->router_id, oi->area->lsdb);
1154
1155 if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
1156 if (old)
1157 ospf6_lsa_purge(old);
1158 return 0;
1159 }
1160
1161 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1162 zlog_debug(
1163 "Originate Intra-Area-Prefix-LSA for interface %s's prefix",
1164 oi->interface->name);
1165
1166 /* prepare buffer */
1167 memset(buffer, 0, sizeof(buffer));
1168 lsa_header = (struct ospf6_lsa_header *)buffer;
1169 intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
1170 *)((caddr_t)lsa_header
1171 + sizeof(struct ospf6_lsa_header));
1172
1173 /* Fill Intra-Area-Prefix-LSA */
1174 intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_NETWORK);
1175 intra_prefix_lsa->ref_id = htonl(oi->interface->ifindex);
1176 intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id;
1177
1178 if (oi->state != OSPF6_INTERFACE_DR) {
1179 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1180 zlog_debug(" Interface is not DR");
1181 if (old)
1182 ospf6_lsa_purge(old);
1183 return 0;
1184 }
1185
1186 full_count = 0;
1187 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on))
1188 if (on->state == OSPF6_NEIGHBOR_FULL)
1189 full_count++;
1190
1191 if (full_count == 0) {
1192 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1193 zlog_debug(" Interface is stub");
1194 if (old)
1195 ospf6_lsa_purge(old);
1196 return 0;
1197 }
1198
1199 /* connected prefix to advertise */
1200 route_advertise = ospf6_route_table_create(0, 0);
1201
1202 type = ntohs(OSPF6_LSTYPE_LINK);
1203 for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
1204 if (OSPF6_LSA_IS_MAXAGE(lsa))
1205 continue;
1206
1207 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1208 zlog_debug(" include prefix from %s", lsa->name);
1209
1210 if (lsa->header->adv_router != oi->area->ospf6->router_id) {
1211 on = ospf6_neighbor_lookup(lsa->header->adv_router, oi);
1212 if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL) {
1213 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1214 zlog_debug(
1215 " Neighbor not found or not Full, ignore");
1216 continue;
1217 }
1218 }
1219
1220 link_lsa = (struct ospf6_link_lsa
1221 *)((caddr_t)lsa->header
1222 + sizeof(struct ospf6_lsa_header));
1223
1224 prefix_num = (unsigned short)ntohl(link_lsa->prefix_num);
1225 start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
1226 end = (char *)lsa->header + ntohs(lsa->header->length);
1227 for (current = start; current < end && prefix_num;
1228 current += OSPF6_PREFIX_SIZE(op)) {
1229 op = (struct ospf6_prefix *)current;
1230 if (op->prefix_length == 0
1231 || current + OSPF6_PREFIX_SIZE(op) > end)
1232 break;
1233
1234 route = ospf6_route_create();
1235
1236 route->type = OSPF6_DEST_TYPE_NETWORK;
1237 route->prefix.family = AF_INET6;
1238 route->prefix.prefixlen = op->prefix_length;
1239 memset(&route->prefix.u.prefix6, 0,
1240 sizeof(struct in6_addr));
1241 memcpy(&route->prefix.u.prefix6, OSPF6_PREFIX_BODY(op),
1242 OSPF6_PREFIX_SPACE(op->prefix_length));
1243
1244 route->path.origin.type = lsa->header->type;
1245 route->path.origin.id = lsa->header->id;
1246 route->path.origin.adv_router = lsa->header->adv_router;
1247 route->path.options[0] = link_lsa->options[0];
1248 route->path.options[1] = link_lsa->options[1];
1249 route->path.options[2] = link_lsa->options[2];
1250 route->path.prefix_options = op->prefix_options;
1251 route->path.area_id = oi->area->area_id;
1252 route->path.type = OSPF6_PATH_TYPE_INTRA;
1253
1254 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1255 zlog_debug(" include %pFX", &route->prefix);
1256
1257 ospf6_route_add(route, route_advertise,
1258 oi->area->ospf6);
1259 prefix_num--;
1260 }
1261 if (current != end && IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1262 zlog_debug("Trailing garbage in %s", lsa->name);
1263 }
1264
1265 op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
1266 + sizeof(struct ospf6_intra_prefix_lsa));
1267
1268 prefix_num = 0;
1269 for (route = ospf6_route_head(route_advertise); route;
1270 route = ospf6_route_best_next(route)) {
1271 op->prefix_length = route->prefix.prefixlen;
1272 op->prefix_options = route->path.prefix_options;
1273 op->prefix_metric = htons(0);
1274 memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
1275 OSPF6_PREFIX_SPACE(op->prefix_length));
1276 op = OSPF6_PREFIX_NEXT(op);
1277 prefix_num++;
1278 }
1279
1280 ospf6_route_table_delete(route_advertise, oi->area->ospf6);
1281
1282 if (prefix_num == 0) {
1283 if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1284 zlog_debug(
1285 "Quit to Advertise Intra-Prefix: no route to advertise");
1286 return 0;
1287 }
1288
1289 intra_prefix_lsa->prefix_num = htons(prefix_num);
1290
1291 /* Fill LSA Header */
1292 lsa_header->age = 0;
1293 lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1294 lsa_header->id = htonl(oi->interface->ifindex);
1295 lsa_header->adv_router = oi->area->ospf6->router_id;
1296 lsa_header->seqnum =
1297 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
1298 lsa_header->adv_router, oi->area->lsdb);
1299 lsa_header->length = htons((caddr_t)op - (caddr_t)lsa_header);
1300
1301 /* LSA checksum */
1302 ospf6_lsa_checksum(lsa_header);
1303
1304 /* create LSA */
1305 lsa = ospf6_lsa_create(lsa_header);
1306
1307 /* Originate */
1308 ospf6_lsa_originate_area(lsa, oi->area);
1309
1310 return 0;
1311 }
1312
1313 static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route,
1314 struct ospf6 *ospf6)
1315 {
1316 struct ospf6_path *h_path;
1317 struct ospf6_route *g_route, *nroute;
1318
1319 /* Update Global ospf6 route path */
1320 g_route = ospf6_route_lookup(&oa_route->prefix, ospf6->route_table);
1321
1322 assert(g_route);
1323
1324 for (ospf6_route_lock(g_route); g_route &&
1325 ospf6_route_is_prefix(&oa_route->prefix, g_route);
1326 g_route = nroute) {
1327 nroute = ospf6_route_next(g_route);
1328 if (g_route->type != oa_route->type)
1329 continue;
1330 if (g_route->path.area_id != oa_route->path.area_id)
1331 continue;
1332 if (g_route->path.type != OSPF6_PATH_TYPE_INTRA)
1333 continue;
1334 if (g_route->path.cost != oa_route->path.cost)
1335 continue;
1336
1337 if (ospf6_route_is_same_origin(g_route, oa_route)) {
1338 h_path = (struct ospf6_path *)listgetdata(
1339 listhead(g_route->paths));
1340 g_route->path.origin.type = h_path->origin.type;
1341 g_route->path.origin.id = h_path->origin.id;
1342 g_route->path.origin.adv_router =
1343 h_path->origin.adv_router;
1344 break;
1345 }
1346 }
1347
1348 h_path = (struct ospf6_path *)listgetdata(
1349 listhead(oa_route->paths));
1350 oa_route->path.origin.type = h_path->origin.type;
1351 oa_route->path.origin.id = h_path->origin.id;
1352 oa_route->path.origin.adv_router = h_path->origin.adv_router;
1353 }
1354
1355 void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
1356 struct ospf6_route *old,
1357 struct ospf6_route *route)
1358 {
1359 struct ospf6_route *old_route, *ls_entry;
1360 struct ospf6_path *ecmp_path, *o_path = NULL;
1361 struct listnode *anode, *anext;
1362 struct listnode *nnode, *rnode, *rnext;
1363 struct ospf6_nexthop *nh, *rnh;
1364 char buf[PREFIX2STR_BUFFER];
1365 bool route_found = false;
1366 struct interface *ifp = NULL;
1367 struct ospf6_lsa *lsa;
1368 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1369
1370 /* check for old entry match with new route origin,
1371 * delete old entry.
1372 */
1373 for (old_route = old; old_route; old_route = old_route->next) {
1374 bool route_updated = false;
1375
1376 if (!ospf6_route_is_same(old_route, route) ||
1377 (old_route->path.type != route->path.type))
1378 continue;
1379
1380 /* Current and New route has same origin,
1381 * delete old entry.
1382 */
1383 for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
1384 o_path)) {
1385 /* Check old route path and route has same
1386 * origin.
1387 */
1388 if (o_path->area_id != route->path.area_id ||
1389 (memcmp(&(o_path)->origin, &(route)->path.origin,
1390 sizeof(struct ospf6_ls_origin)) != 0))
1391 continue;
1392
1393 /* Cost is not same then delete current path */
1394 if (o_path->cost == route->path.cost)
1395 continue;
1396
1397 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1398 zlog_debug(
1399 "%s: route %pFX cost old %u new %u is not same, replace route",
1400 __func__, &old_route->prefix, o_path->cost,
1401 route->path.cost);
1402 }
1403
1404 /* Remove selected current path's nh from
1405 * effective nh list.
1406 */
1407 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
1408 for (ALL_LIST_ELEMENTS(old_route->nh_list,
1409 rnode, rnext, rnh)) {
1410 if (!ospf6_nexthop_is_same(rnh, nh))
1411 continue;
1412 listnode_delete(old_route->nh_list,
1413 rnh);
1414 ospf6_nexthop_delete(rnh);
1415 route_updated = true;
1416 }
1417 }
1418
1419 listnode_delete(old_route->paths, o_path);
1420 ospf6_path_free(o_path);
1421
1422 /* Current route's path (adv_router info) is similar
1423 * to route being added.
1424 * Replace current route's path with paths list head.
1425 * Update FIB with effective NHs.
1426 */
1427 if (listcount(old_route->paths)) {
1428 if (route_updated) {
1429 for (ALL_LIST_ELEMENTS(old_route->paths,
1430 anode, anext, o_path)) {
1431 ospf6_merge_nexthops(
1432 old_route->nh_list,
1433 o_path->nh_list);
1434 }
1435 /* Update ospf6 route table and
1436 * RIB/FIB with effective
1437 * nh_list
1438 */
1439 if (oa->route_table->hook_add)
1440 (*oa->route_table->hook_add)(
1441 old_route, oa->ospf6);
1442
1443 if (old_route->path.origin.id ==
1444 route->path.origin.id &&
1445 old_route->path.origin.adv_router ==
1446 route->path.origin.adv_router) {
1447 ospf6_intra_prefix_update_route_origin(
1448 old_route, oa->ospf6);
1449 }
1450 break;
1451 }
1452 } else {
1453 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1454 zlog_debug(
1455 "%s: route %pFX old cost %u new cost %u, delete old entry.",
1456 __func__, &old_route->prefix,
1457 old_route->path.cost,
1458 route->path.cost);
1459 }
1460 if (oa->route_table->hook_remove)
1461 ospf6_route_remove(old_route,
1462 oa->route_table,
1463 oa->ospf6);
1464 else
1465 SET_FLAG(old_route->flag,
1466 OSPF6_ROUTE_REMOVE);
1467 break;
1468 }
1469 }
1470 if (route_updated)
1471 break;
1472 }
1473
1474 for (old_route = old; old_route; old_route = old_route->next) {
1475
1476 if (!ospf6_route_is_same(old_route, route) ||
1477 (old_route->path.type != route->path.type))
1478 continue;
1479
1480 /* Old Route and New Route have Equal Cost, Merge NHs */
1481 if (old_route->path.cost == route->path.cost) {
1482 route_found = true;
1483
1484 /* check if this path exists already in
1485 * route->paths list, if so, replace nh_list.
1486 */
1487 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
1488 o_path)) {
1489 if (o_path->area_id == route->path.area_id &&
1490 (memcmp(&(o_path)->origin,
1491 &(route)->path.origin,
1492 sizeof(struct ospf6_ls_origin)) == 0))
1493 break;
1494 }
1495 /* If path is not found in old_route paths's list,
1496 * add a new path to route paths list and merge
1497 * nexthops in route->path->nh_list.
1498 * Otherwise replace existing path's nh_list.
1499 */
1500 if (o_path == NULL) {
1501 ecmp_path = ospf6_path_dup(&route->path);
1502
1503 /* Add a nh_list to new ecmp path */
1504 ospf6_copy_nexthops(ecmp_path->nh_list,
1505 route->nh_list);
1506 /* Add the new path to route's path list */
1507 listnode_add_sort(old_route->paths, ecmp_path);
1508
1509 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1510 zlog_debug(
1511 "%s: route %pFX %p another path added with nh %u, effective paths %u nh %u",
1512 __func__, &route->prefix,
1513 (void *)old_route,
1514 listcount(ecmp_path->nh_list),
1515 old_route->paths ? listcount(
1516 old_route->paths)
1517 : 0,
1518 listcount(old_route->nh_list));
1519 }
1520 } else {
1521 list_delete_all_node(o_path->nh_list);
1522 ospf6_copy_nexthops(o_path->nh_list,
1523 route->nh_list);
1524
1525 }
1526
1527 list_delete_all_node(old_route->nh_list);
1528
1529 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
1530 o_path)) {
1531 ls_entry = ospf6_route_lookup(
1532 &o_path->ls_prefix,
1533 oa->spf_table);
1534 if (ls_entry == NULL) {
1535 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1536 zlog_debug(
1537 "%s: ls_prfix %s ls_entry not found.",
1538 __func__, buf);
1539 continue;
1540 }
1541 lsa = ospf6_lsdb_lookup(o_path->origin.type,
1542 o_path->origin.id,
1543 o_path->origin.adv_router,
1544 oa->lsdb);
1545 if (lsa == NULL) {
1546 if (IS_OSPF6_DEBUG_EXAMIN(
1547 INTRA_PREFIX)) {
1548 struct prefix adv_prefix;
1549
1550 ospf6_linkstate_prefix(
1551 o_path->origin.adv_router,
1552 o_path->origin.id, &adv_prefix);
1553 zlog_debug(
1554 "%s: adv_router %pFX lsa not found",
1555 __func__, &adv_prefix);
1556 }
1557 continue;
1558 }
1559 intra_prefix_lsa =
1560 (struct ospf6_intra_prefix_lsa *)
1561 OSPF6_LSA_HEADER_END(lsa->header);
1562
1563 if (intra_prefix_lsa->ref_adv_router
1564 == oa->ospf6->router_id) {
1565 ifp = if_lookup_prefix(
1566 &old_route->prefix,
1567 oa->ospf6->vrf_id);
1568 }
1569
1570 if (ifp) {
1571 /* Nexthop interface found */
1572 ospf6_route_add_nexthop(old_route,
1573 ifp->ifindex,
1574 NULL);
1575 } else {
1576 /* The connected interfaces between
1577 * routers can be in different networks.
1578 * In this case the matching interface
1579 * is not found. Copy nexthops from the
1580 * link state entry
1581 */
1582 ospf6_route_merge_nexthops(old_route,
1583 ls_entry);
1584 }
1585 }
1586
1587 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1588 zlog_debug(
1589 "%s: route %pFX %p with final effective paths %u nh%u",
1590 __func__, &route->prefix,
1591 (void *)old_route,
1592 old_route->paths
1593 ? listcount(old_route->paths)
1594 : 0,
1595 listcount(old_route->nh_list));
1596
1597 /* used in intra_route_calculation() to add to
1598 * global ospf6 route table.
1599 */
1600 UNSET_FLAG(old_route->flag, OSPF6_ROUTE_REMOVE);
1601 SET_FLAG(old_route->flag, OSPF6_ROUTE_ADD);
1602 /* Update ospf6 route table and RIB/FIB */
1603 if (oa->route_table->hook_add)
1604 (*oa->route_table->hook_add)(old_route,
1605 oa->ospf6);
1606 /* Delete the new route its info added to existing
1607 * route.
1608 */
1609 ospf6_route_delete(route);
1610
1611 break;
1612 }
1613 }
1614
1615 if (!route_found) {
1616 /* Add new route to existing node in ospf6 route table. */
1617 ospf6_route_add(route, oa->route_table, oa->ospf6);
1618 }
1619 }
1620
1621 void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
1622 {
1623 struct ospf6_area *oa;
1624 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1625 struct prefix ls_prefix;
1626 struct ospf6_route *route, *ls_entry, *old;
1627 int prefix_num;
1628 struct ospf6_prefix *op;
1629 char *start, *current, *end;
1630 char buf[PREFIX2STR_BUFFER];
1631 struct interface *ifp = NULL;
1632 int direct_connect = 0;
1633 struct ospf6_path *path;
1634
1635 if (OSPF6_LSA_IS_MAXAGE(lsa))
1636 return;
1637
1638 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1639 zlog_debug("%s: LSA %s found", __func__, lsa->name);
1640
1641 oa = OSPF6_AREA(lsa->lsdb->data);
1642
1643 intra_prefix_lsa =
1644 (struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
1645 lsa->header);
1646 if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER))
1647 ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
1648 intra_prefix_lsa->ref_id, &ls_prefix);
1649 else if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK))
1650 ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
1651 intra_prefix_lsa->ref_id, &ls_prefix);
1652 else {
1653 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1654 zlog_debug("Unknown reference LS-type: %#hx",
1655 ntohs(intra_prefix_lsa->ref_type));
1656 return;
1657 }
1658
1659 ls_entry = ospf6_route_lookup(&ls_prefix, oa->spf_table);
1660 if (ls_entry == NULL) {
1661 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1662 ospf6_linkstate_prefix2str(&ls_prefix, buf,
1663 sizeof(buf));
1664 zlog_debug("LS entry does not exist: %s", buf);
1665 }
1666 return;
1667 }
1668
1669 if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) {
1670 /* the intra-prefix are directly connected */
1671 direct_connect = 1;
1672 }
1673
1674 prefix_num = ntohs(intra_prefix_lsa->prefix_num);
1675 start = (caddr_t)intra_prefix_lsa
1676 + sizeof(struct ospf6_intra_prefix_lsa);
1677 end = OSPF6_LSA_END(lsa->header);
1678 for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) {
1679 op = (struct ospf6_prefix *)current;
1680 if (prefix_num == 0)
1681 break;
1682 if (end < current + OSPF6_PREFIX_SIZE(op))
1683 break;
1684
1685 /* Appendix A.4.1.1 */
1686 if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU)) {
1687 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1688 ospf6_linkstate_prefix2str(
1689 (struct prefix *)OSPF6_PREFIX_BODY(op),
1690 buf, sizeof(buf));
1691 zlog_debug(
1692 "%s: Skipping Prefix %s has NU option set",
1693 __func__, buf);
1694 }
1695 continue;
1696 }
1697
1698 route = ospf6_route_create();
1699
1700 memset(&route->prefix, 0, sizeof(struct prefix));
1701 route->prefix.family = AF_INET6;
1702 route->prefix.prefixlen = op->prefix_length;
1703 ospf6_prefix_in6_addr(&route->prefix.u.prefix6,
1704 intra_prefix_lsa, op);
1705
1706 route->type = OSPF6_DEST_TYPE_NETWORK;
1707 route->path.origin.type = lsa->header->type;
1708 route->path.origin.id = lsa->header->id;
1709 route->path.origin.adv_router = lsa->header->adv_router;
1710 route->path.prefix_options = op->prefix_options;
1711 route->path.area_id = oa->area_id;
1712 route->path.type = OSPF6_PATH_TYPE_INTRA;
1713 route->path.metric_type = 1;
1714 route->path.cost =
1715 ls_entry->path.cost + ntohs(op->prefix_metric);
1716 memcpy(&route->path.ls_prefix, &ls_prefix,
1717 sizeof(struct prefix));
1718 if (direct_connect) {
1719 ifp = if_lookup_prefix(&route->prefix,
1720 oa->ospf6->vrf_id);
1721 }
1722
1723 if (ifp) {
1724 /* Nexthop interface found */
1725 ospf6_route_add_nexthop(route, ifp->ifindex, NULL);
1726 } else {
1727 /* The connected interfaces between routers can be in
1728 * different networks. In this case the matching
1729 * interface is not found. Copy nexthops from the
1730 * link state entry
1731 */
1732 ospf6_route_copy_nexthops(route, ls_entry);
1733 }
1734
1735 path = ospf6_path_dup(&route->path);
1736 ospf6_copy_nexthops(path->nh_list, route->path.nh_list);
1737 listnode_add_sort(route->paths, path);
1738
1739 old = ospf6_route_lookup(&route->prefix, oa->route_table);
1740 if (old) {
1741 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1742 prefix2str(&route->prefix, buf, sizeof(buf));
1743 zlog_debug(
1744 "%s Update route: %s old cost %u new cost %u paths %u nh %u",
1745 __func__, buf, old->path.cost,
1746 route->path.cost,
1747 listcount(route->paths),
1748 listcount(route->nh_list));
1749 }
1750 ospf6_intra_prefix_route_ecmp_path(oa, old, route);
1751 } else {
1752 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1753 prefix2str(&route->prefix, buf, sizeof(buf));
1754 zlog_debug(
1755 "%s route %s add with cost %u paths %u nh %u",
1756 __func__, buf, route->path.cost,
1757 listcount(route->paths),
1758 listcount(route->nh_list));
1759 }
1760 ospf6_route_add(route, oa->route_table, oa->ospf6);
1761 }
1762 prefix_num--;
1763 }
1764
1765 if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1766 zlog_debug("Trailing garbage ignored");
1767 }
1768
1769 static void ospf6_intra_prefix_lsa_remove_update_route(struct ospf6_lsa *lsa,
1770 struct ospf6_area *oa,
1771 struct ospf6_route *route)
1772 {
1773 struct listnode *anode, *anext;
1774 struct listnode *nnode, *rnode, *rnext;
1775 struct ospf6_nexthop *nh, *rnh;
1776 struct ospf6_path *o_path;
1777 bool nh_updated = false;
1778 char buf[PREFIX2STR_BUFFER];
1779
1780 /* Iterate all paths of route to find maching
1781 * with LSA remove info.
1782 * If route->path is same, replace
1783 * from paths list.
1784 */
1785 for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path)) {
1786 if ((o_path->origin.type != lsa->header->type) ||
1787 (o_path->origin.adv_router != lsa->header->adv_router) ||
1788 (o_path->origin.id != lsa->header->id))
1789 continue;
1790
1791 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1792 prefix2str(&route->prefix, buf, sizeof(buf));
1793 zlog_debug(
1794 "%s: route %s path found with cost %u nh %u to remove.",
1795 __func__, buf, o_path->cost,
1796 listcount(o_path->nh_list));
1797 }
1798
1799 /* Remove found path's nh_list from
1800 * the route's nh_list.
1801 */
1802 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
1803 for (ALL_LIST_ELEMENTS(route->nh_list, rnode,
1804 rnext, rnh)) {
1805 if (!ospf6_nexthop_is_same(rnh, nh))
1806 continue;
1807 listnode_delete(route->nh_list, rnh);
1808 ospf6_nexthop_delete(rnh);
1809 }
1810 }
1811 /* Delete the path from route's
1812 * path list
1813 */
1814 listnode_delete(route->paths, o_path);
1815 ospf6_path_free(o_path);
1816 nh_updated = true;
1817 break;
1818 }
1819
1820 if (nh_updated) {
1821 /* Iterate all paths and merge nexthop,
1822 * unlesss any of the nexthop similar to
1823 * ones deleted as part of path deletion.
1824 */
1825 for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path))
1826 ospf6_merge_nexthops(route->nh_list, o_path->nh_list);
1827
1828
1829 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1830 prefix2str(&route->prefix, buf, sizeof(buf));
1831 zlog_debug(
1832 "%s: route %s update paths %u nh %u", __func__,
1833 buf, route->paths ? listcount(route->paths) : 0,
1834 route->nh_list ? listcount(route->nh_list) : 0);
1835 }
1836
1837 /* Update Global Route table and
1838 * RIB/FIB with effective
1839 * nh_list
1840 */
1841 if (oa->route_table->hook_add)
1842 (*oa->route_table->hook_add)(route, oa->ospf6);
1843
1844 /* route's primary path is similar
1845 * to LSA, replace route's primary
1846 * path with route's paths list
1847 * head.
1848 */
1849 if ((route->path.origin.id == lsa->header->id) &&
1850 (route->path.origin.adv_router ==
1851 lsa->header->adv_router)) {
1852 ospf6_intra_prefix_update_route_origin(route,
1853 oa->ospf6);
1854 }
1855 }
1856
1857 }
1858
1859 void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
1860 {
1861 struct ospf6_area *oa;
1862 struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1863 struct prefix prefix;
1864 struct ospf6_route *route, *nroute;
1865 int prefix_num;
1866 struct ospf6_prefix *op;
1867 char *start, *current, *end;
1868 char buf[PREFIX2STR_BUFFER];
1869
1870 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1871 zlog_debug("%s: %s disappearing", __func__, lsa->name);
1872
1873 oa = OSPF6_AREA(lsa->lsdb->data);
1874
1875 intra_prefix_lsa =
1876 (struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
1877 lsa->header);
1878
1879 prefix_num = ntohs(intra_prefix_lsa->prefix_num);
1880 start = (caddr_t)intra_prefix_lsa
1881 + sizeof(struct ospf6_intra_prefix_lsa);
1882 end = OSPF6_LSA_END(lsa->header);
1883 for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) {
1884 op = (struct ospf6_prefix *)current;
1885 if (prefix_num == 0)
1886 break;
1887 if (end < current + OSPF6_PREFIX_SIZE(op))
1888 break;
1889 prefix_num--;
1890
1891 memset(&prefix, 0, sizeof(struct prefix));
1892 prefix.family = AF_INET6;
1893 prefix.prefixlen = op->prefix_length;
1894 ospf6_prefix_in6_addr(&prefix.u.prefix6, intra_prefix_lsa, op);
1895
1896 route = ospf6_route_lookup(&prefix, oa->route_table);
1897 if (route == NULL)
1898 continue;
1899
1900 for (ospf6_route_lock(route);
1901 route && ospf6_route_is_prefix(&prefix, route);
1902 route = nroute) {
1903 nroute = ospf6_route_next(route);
1904 if (route->type != OSPF6_DEST_TYPE_NETWORK)
1905 continue;
1906 if (route->path.area_id != oa->area_id)
1907 continue;
1908 if (route->path.type != OSPF6_PATH_TYPE_INTRA)
1909 continue;
1910 /* Route has multiple ECMP paths, remove matching
1911 * path. Update current route's effective nh list
1912 * after removal of one of the path.
1913 */
1914 if (listcount(route->paths) > 1) {
1915 ospf6_intra_prefix_lsa_remove_update_route(
1916 lsa, oa, route);
1917 } else {
1918
1919 if (route->path.origin.type != lsa->header->type
1920 || route->path.origin.id != lsa->header->id
1921 || route->path.origin.adv_router
1922 != lsa->header->adv_router)
1923 continue;
1924
1925 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1926 prefix2str(&route->prefix, buf,
1927 sizeof(buf));
1928 zlog_debug(
1929 "%s: route remove %s with path type %u cost %u paths %u nh %u",
1930 __func__, buf, route->path.type,
1931 route->path.cost,
1932 listcount(route->paths),
1933 listcount(route->nh_list));
1934 }
1935 ospf6_route_remove(route, oa->route_table,
1936 oa->ospf6);
1937 }
1938 }
1939 if (route)
1940 ospf6_route_unlock(route);
1941 }
1942
1943 if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1944 zlog_debug("Trailing garbage ignored");
1945 }
1946
1947 void ospf6_intra_route_calculation(struct ospf6_area *oa)
1948 {
1949 struct ospf6_route *route, *nroute;
1950 uint16_t type;
1951 struct ospf6_lsa *lsa;
1952 void (*hook_add)(struct ospf6_route *, struct ospf6 *) = NULL;
1953 void (*hook_remove)(struct ospf6_route *, struct ospf6 *) = NULL;
1954
1955 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1956 zlog_debug("Re-examin intra-routes for area %s", oa->name);
1957
1958 hook_add = oa->route_table->hook_add;
1959 hook_remove = oa->route_table->hook_remove;
1960 oa->route_table->hook_add = NULL;
1961 oa->route_table->hook_remove = NULL;
1962
1963 for (route = ospf6_route_head(oa->route_table); route;
1964 route = ospf6_route_next(route))
1965 route->flag = OSPF6_ROUTE_REMOVE;
1966
1967 type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1968 for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
1969 ospf6_intra_prefix_lsa_add(lsa);
1970
1971 oa->route_table->hook_add = hook_add;
1972 oa->route_table->hook_remove = hook_remove;
1973
1974 for (route = ospf6_route_head(oa->route_table); route; route = nroute) {
1975 nroute = ospf6_route_next(route);
1976 if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
1977 && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
1978 UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
1979 UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
1980 }
1981
1982 if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
1983 ospf6_route_remove(route, oa->route_table, oa->ospf6);
1984 else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
1985 || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
1986 if (hook_add)
1987 (*hook_add)(route, oa->ospf6);
1988 route->flag = 0;
1989 } else {
1990 /* Redo the summaries as things might have changed */
1991 ospf6_abr_originate_summary(route, oa->ospf6);
1992 route->flag = 0;
1993 }
1994 }
1995
1996 if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1997 zlog_debug("Re-examin intra-routes for area %s: Done",
1998 oa->name);
1999 }
2000
2001 static void ospf6_brouter_debug_print(struct ospf6_route *brouter)
2002 {
2003 uint32_t brouter_id;
2004 char brouter_name[16];
2005 char area_name[16];
2006 char destination[64];
2007 char installed[64], changed[64];
2008 struct timeval now, res;
2009 char id[16], adv_router[16];
2010 char capa[16], options[16];
2011
2012 brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2013 inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name));
2014 inet_ntop(AF_INET, &brouter->path.area_id, area_name,
2015 sizeof(area_name));
2016 ospf6_linkstate_prefix2str(&brouter->prefix, destination,
2017 sizeof(destination));
2018
2019 monotime(&now);
2020 timersub(&now, &brouter->installed, &res);
2021 timerstring(&res, installed, sizeof(installed));
2022
2023 monotime(&now);
2024 timersub(&now, &brouter->changed, &res);
2025 timerstring(&res, changed, sizeof(changed));
2026
2027 inet_ntop(AF_INET, &brouter->path.origin.id, id, sizeof(id));
2028 inet_ntop(AF_INET, &brouter->path.origin.adv_router, adv_router,
2029 sizeof(adv_router));
2030
2031 ospf6_options_printbuf(brouter->path.options, options, sizeof(options));
2032 ospf6_capability_printbuf(brouter->path.router_bits, capa,
2033 sizeof(capa));
2034
2035 zlog_info("Brouter: %s via area %s", brouter_name, area_name);
2036 zlog_info(" memory: prev: %p this: %p next: %p parent rnode: %p",
2037 (void *)brouter->prev, (void *)brouter, (void *)brouter->next,
2038 (void *)brouter->rnode);
2039 zlog_info(" type: %d prefix: %s installed: %s changed: %s",
2040 brouter->type, destination, installed, changed);
2041 zlog_info(" lock: %d flags: %s%s%s%s", brouter->lock,
2042 (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
2043 (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
2044 (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
2045 (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"));
2046 zlog_info(" path type: %s ls-origin %s id: %s adv-router %s",
2047 OSPF6_PATH_TYPE_NAME(brouter->path.type),
2048 ospf6_lstype_name(brouter->path.origin.type), id, adv_router);
2049 zlog_info(" options: %s router-bits: %s metric-type: %d metric: %d/%d",
2050 options, capa, brouter->path.metric_type, brouter->path.cost,
2051 brouter->path.u.cost_e2);
2052 zlog_info(" paths %u nh %u", listcount(brouter->paths),
2053 listcount(brouter->nh_list));
2054 }
2055
2056 void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
2057 {
2058 struct ospf6_route *brouter, *nbrouter, *copy;
2059 void (*hook_add)(struct ospf6_route *, struct ospf6 *) = NULL;
2060 void (*hook_remove)(struct ospf6_route *, struct ospf6 *) = NULL;
2061 uint32_t brouter_id;
2062 char brouter_name[16];
2063
2064 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
2065 IS_OSPF6_DEBUG_ROUTE(MEMORY))
2066 zlog_info("%s: border-router calculation for area %s", __func__,
2067 oa->name);
2068
2069 hook_add = oa->ospf6->brouter_table->hook_add;
2070 hook_remove = oa->ospf6->brouter_table->hook_remove;
2071 oa->ospf6->brouter_table->hook_add = NULL;
2072 oa->ospf6->brouter_table->hook_remove = NULL;
2073
2074 /* withdraw the previous router entries for the area */
2075 for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter;
2076 brouter = ospf6_route_next(brouter)) {
2077 brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2078 inet_ntop(AF_INET, &brouter_id, brouter_name,
2079 sizeof(brouter_name));
2080
2081 if (brouter->path.area_id != oa->area_id)
2082 continue;
2083
2084 SET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
2085
2086 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
2087 || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
2088 zlog_info("%p: mark as removing: area %s brouter %s",
2089 (void *)brouter, oa->name, brouter_name);
2090 ospf6_brouter_debug_print(brouter);
2091 }
2092 }
2093
2094 for (brouter = ospf6_route_head(oa->spf_table); brouter;
2095 brouter = ospf6_route_next(brouter)) {
2096 brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2097 inet_ntop(AF_INET, &brouter_id, brouter_name,
2098 sizeof(brouter_name));
2099
2100 if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE)
2101 continue;
2102
2103 if (ospf6_linkstate_prefix_id(&brouter->prefix) != htonl(0))
2104 continue;
2105
2106 if (!CHECK_FLAG(brouter->path.router_bits, OSPF6_ROUTER_BIT_E)
2107 && !CHECK_FLAG(brouter->path.router_bits,
2108 OSPF6_ROUTER_BIT_B))
2109 continue;
2110
2111 if (!OSPF6_OPT_ISSET(brouter->path.options, OSPF6_OPT_V6)
2112 || !OSPF6_OPT_ISSET(brouter->path.options, OSPF6_OPT_R))
2113 continue;
2114
2115 copy = ospf6_route_copy(brouter);
2116 copy->type = OSPF6_DEST_TYPE_ROUTER;
2117 copy->path.area_id = oa->area_id;
2118 ospf6_route_add(copy, oa->ospf6->brouter_table, oa->ospf6);
2119
2120 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
2121 || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
2122 zlog_info("%p: transfer: area %s brouter %s",
2123 (void *)brouter, oa->name, brouter_name);
2124 ospf6_brouter_debug_print(brouter);
2125 }
2126 }
2127
2128 oa->ospf6->brouter_table->hook_add = hook_add;
2129 oa->ospf6->brouter_table->hook_remove = hook_remove;
2130
2131 for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter;
2132 brouter = nbrouter) {
2133
2134 /*
2135 * brouter may have been "deleted" in the last loop iteration.
2136 * If this is the case there is still 1 final refcount lock
2137 * taken by ospf6_route_next, that will be released by the same
2138 * call and result in deletion. To avoid heap UAF we must then
2139 * skip processing the deleted route.
2140 */
2141 if (brouter->lock == 1) {
2142 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
2143 ospf6_brouter_debug_print(brouter);
2144 nbrouter = ospf6_route_next(brouter);
2145 continue;
2146 } else {
2147 nbrouter = ospf6_route_next(brouter);
2148 }
2149
2150 brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2151 inet_ntop(AF_INET, &brouter_id, brouter_name,
2152 sizeof(brouter_name));
2153
2154 if (brouter->path.area_id != oa->area_id)
2155 continue;
2156
2157 if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_WAS_REMOVED))
2158 continue;
2159
2160 /* After iterating spf_table for all routers including
2161 * intra brouter, clear mark for remove flag for
2162 * inter border router if its adv router present in
2163 * SPF table.
2164 */
2165 if (brouter->path.type == OSPF6_PATH_TYPE_INTER) {
2166 struct prefix adv_prefix;
2167
2168 ospf6_linkstate_prefix(brouter->path.origin.adv_router,
2169 htonl(0), &adv_prefix);
2170
2171 if (ospf6_route_lookup(&adv_prefix, oa->spf_table)) {
2172 if (IS_OSPF6_DEBUG_BROUTER) {
2173 zlog_debug(
2174 "%s: keep inter brouter %s as adv router 0x%x found in spf",
2175 __func__, brouter_name,
2176 brouter->path.origin
2177 .adv_router);
2178 ospf6_brouter_debug_print(brouter);
2179 }
2180 UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
2181 }
2182 }
2183
2184 if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)
2185 && CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)) {
2186 UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
2187 UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
2188 }
2189
2190 if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)) {
2191 if (IS_OSPF6_DEBUG_BROUTER
2192 || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
2193 brouter_id)
2194 || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
2195 oa->area_id))
2196 zlog_info(
2197 "%s: brouter %s disappears via area %s",
2198 __func__, brouter_name, oa->name);
2199 /* This is used to protect nbrouter from removed from
2200 * the table. For an example, ospf6_abr_examin_summary,
2201 * removes brouters which are marked for remove.
2202 */
2203 oa->intra_brouter_calc = 1;
2204 ospf6_route_remove(brouter, oa->ospf6->brouter_table,
2205 oa->ospf6);
2206 brouter = NULL;
2207 } else if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)
2208 || CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE)) {
2209 if (IS_OSPF6_DEBUG_BROUTER
2210 || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
2211 brouter_id)
2212 || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
2213 oa->area_id))
2214 zlog_info("%s: brouter %s appears via area %s",
2215 __func__, brouter_name, oa->name);
2216
2217 /* newly added */
2218 if (hook_add)
2219 (*hook_add)(brouter, oa->ospf6);
2220 } else {
2221 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
2222 brouter_id)
2223 || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
2224 oa->area_id))
2225 zlog_info("brouter %s still exists via area %s",
2226 brouter_name, oa->name);
2227 /* But re-originate summaries */
2228 ospf6_abr_originate_summary(brouter, oa->ospf6);
2229 }
2230
2231 if (brouter) {
2232 UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
2233 UNSET_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE);
2234 }
2235 /* Reset for nbrouter */
2236 oa->intra_brouter_calc = 0;
2237 }
2238
2239 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
2240 IS_OSPF6_DEBUG_ROUTE(MEMORY))
2241 zlog_info("%s: border-router calculation for area %s: done",
2242 __func__, oa->name);
2243 }
2244
2245 static struct ospf6_lsa_handler router_handler = {
2246 .lh_type = OSPF6_LSTYPE_ROUTER,
2247 .lh_name = "Router",
2248 .lh_short_name = "Rtr",
2249 .lh_show = ospf6_router_lsa_show,
2250 .lh_get_prefix_str = ospf6_router_lsa_get_nbr_id,
2251 .lh_debug = 0};
2252
2253 static struct ospf6_lsa_handler network_handler = {
2254 .lh_type = OSPF6_LSTYPE_NETWORK,
2255 .lh_name = "Network",
2256 .lh_short_name = "Net",
2257 .lh_show = ospf6_network_lsa_show,
2258 .lh_get_prefix_str = ospf6_network_lsa_get_ar_id,
2259 .lh_debug = 0};
2260
2261 static struct ospf6_lsa_handler link_handler = {
2262 .lh_type = OSPF6_LSTYPE_LINK,
2263 .lh_name = "Link",
2264 .lh_short_name = "Lnk",
2265 .lh_show = ospf6_link_lsa_show,
2266 .lh_get_prefix_str = ospf6_link_lsa_get_prefix_str,
2267 .lh_debug = 0};
2268
2269 static struct ospf6_lsa_handler intra_prefix_handler = {
2270 .lh_type = OSPF6_LSTYPE_INTRA_PREFIX,
2271 .lh_name = "Intra-Prefix",
2272 .lh_short_name = "INP",
2273 .lh_show = ospf6_intra_prefix_lsa_show,
2274 .lh_get_prefix_str = ospf6_intra_prefix_lsa_get_prefix_str,
2275 .lh_debug = 0};
2276
2277 void ospf6_intra_init(void)
2278 {
2279 ospf6_install_lsa_handler(&router_handler);
2280 ospf6_install_lsa_handler(&network_handler);
2281 ospf6_install_lsa_handler(&link_handler);
2282 ospf6_install_lsa_handler(&intra_prefix_handler);
2283 }
2284
2285 DEFUN (debug_ospf6_brouter,
2286 debug_ospf6_brouter_cmd,
2287 "debug ospf6 border-routers",
2288 DEBUG_STR
2289 OSPF6_STR
2290 "Debug border router\n"
2291 )
2292 {
2293 OSPF6_DEBUG_BROUTER_ON();
2294 return CMD_SUCCESS;
2295 }
2296
2297 DEFUN (no_debug_ospf6_brouter,
2298 no_debug_ospf6_brouter_cmd,
2299 "no debug ospf6 border-routers",
2300 NO_STR
2301 DEBUG_STR
2302 OSPF6_STR
2303 "Debug border router\n"
2304 )
2305 {
2306 OSPF6_DEBUG_BROUTER_OFF();
2307 return CMD_SUCCESS;
2308 }
2309
2310 DEFUN (debug_ospf6_brouter_router,
2311 debug_ospf6_brouter_router_cmd,
2312 "debug ospf6 border-routers router-id A.B.C.D",
2313 DEBUG_STR
2314 OSPF6_STR
2315 "Debug border router\n"
2316 "Debug specific border router\n"
2317 "Specify border-router's router-id\n"
2318 )
2319 {
2320 int idx_ipv4 = 4;
2321 uint32_t router_id;
2322 inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
2323 OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON(router_id);
2324 return CMD_SUCCESS;
2325 }
2326
2327 DEFUN (no_debug_ospf6_brouter_router,
2328 no_debug_ospf6_brouter_router_cmd,
2329 "no debug ospf6 border-routers router-id",
2330 NO_STR
2331 DEBUG_STR
2332 OSPF6_STR
2333 "Debug border router\n"
2334 "Debug specific border router\n"
2335 )
2336 {
2337 OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF();
2338 return CMD_SUCCESS;
2339 }
2340
2341 DEFUN (debug_ospf6_brouter_area,
2342 debug_ospf6_brouter_area_cmd,
2343 "debug ospf6 border-routers area-id A.B.C.D",
2344 DEBUG_STR
2345 OSPF6_STR
2346 "Debug border router\n"
2347 "Debug border routers in specific Area\n"
2348 "Specify Area-ID\n"
2349 )
2350 {
2351 int idx_ipv4 = 4;
2352 uint32_t area_id;
2353 inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id);
2354 OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON(area_id);
2355 return CMD_SUCCESS;
2356 }
2357
2358 DEFUN (no_debug_ospf6_brouter_area,
2359 no_debug_ospf6_brouter_area_cmd,
2360 "no debug ospf6 border-routers area-id",
2361 NO_STR
2362 DEBUG_STR
2363 OSPF6_STR
2364 "Debug border router\n"
2365 "Debug border routers in specific Area\n"
2366 )
2367 {
2368 OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF();
2369 return CMD_SUCCESS;
2370 }
2371
2372 int config_write_ospf6_debug_brouter(struct vty *vty)
2373 {
2374 char buf[16];
2375 if (IS_OSPF6_DEBUG_BROUTER)
2376 vty_out(vty, "debug ospf6 border-routers\n");
2377 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) {
2378 inet_ntop(AF_INET, &conf_debug_ospf6_brouter_specific_router_id,
2379 buf, sizeof(buf));
2380 vty_out(vty, "debug ospf6 border-routers router-id %s\n", buf);
2381 }
2382 if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) {
2383 inet_ntop(AF_INET, &conf_debug_ospf6_brouter_specific_area_id,
2384 buf, sizeof(buf));
2385 vty_out(vty, "debug ospf6 border-routers area-id %s\n", buf);
2386 }
2387 return 0;
2388 }
2389
2390 void install_element_ospf6_debug_brouter(void)
2391 {
2392 install_element(ENABLE_NODE, &debug_ospf6_brouter_cmd);
2393 install_element(ENABLE_NODE, &debug_ospf6_brouter_router_cmd);
2394 install_element(ENABLE_NODE, &debug_ospf6_brouter_area_cmd);
2395 install_element(ENABLE_NODE, &no_debug_ospf6_brouter_cmd);
2396 install_element(ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd);
2397 install_element(ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd);
2398 install_element(CONFIG_NODE, &debug_ospf6_brouter_cmd);
2399 install_element(CONFIG_NODE, &debug_ospf6_brouter_router_cmd);
2400 install_element(CONFIG_NODE, &debug_ospf6_brouter_area_cmd);
2401 install_element(CONFIG_NODE, &no_debug_ospf6_brouter_cmd);
2402 install_element(CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd);
2403 install_element(CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd);
2404 }