1: /*
2: * IS-IS Rout(e)ing protocol - isis_route.c
3: * Copyright (C) 2001,2002 Sampo Saaristo
4: * Tampere University of Technology
5: * Institute of Communications Engineering
6: *
7: * based on ../ospf6d/ospf6_route.[ch]
8: * by Yasuhiro Ohara
9: *
10: * This program is free software; you can redistribute it and/or modify it
11: * under the terms of the GNU General Public Licenseas published by the Free
12: * Software Foundation; either version 2 of the License, or (at your option)
13: * any later version.
14: *
15: * This program is distributed in the hope that it will be useful,but WITHOUT
16: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18: * more details.
19:
20: * You should have received a copy of the GNU General Public License along
21: * with this program; if not, write to the Free Software Foundation, Inc.,
22: * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23: */
24:
25: #include <zebra.h>
26:
27: #include "thread.h"
28: #include "linklist.h"
29: #include "vty.h"
30: #include "log.h"
31: #include "memory.h"
32: #include "prefix.h"
33: #include "hash.h"
34: #include "if.h"
35: #include "table.h"
36:
37: #include "isis_constants.h"
38: #include "isis_common.h"
39: #include "dict.h"
40: #include "isisd.h"
41: #include "isis_misc.h"
42: #include "isis_adjacency.h"
43: #include "isis_circuit.h"
44: #include "isis_tlv.h"
45: #include "isis_pdu.h"
46: #include "isis_lsp.h"
47: #include "isis_spf.h"
48: #include "isis_route.h"
49: #include "isis_zebra.h"
50:
51: extern struct isis *isis;
52: extern struct thread_master *master;
53:
54: static struct isis_nexthop *
55: isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
56: {
57: struct listnode *node;
58: struct isis_nexthop *nexthop;
59:
60: for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop))
61: {
62: if (nexthop->ifindex != ifindex)
63: continue;
64: if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
65: continue;
66:
67: nexthop->lock++;
68: return nexthop;
69: }
70:
71: nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
72: if (!nexthop)
73: {
74: zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
75: }
76:
77: nexthop->ifindex = ifindex;
78: memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
79: listnode_add (isis->nexthops, nexthop);
80: nexthop->lock++;
81:
82: return nexthop;
83: }
84:
85: static void
86: isis_nexthop_delete (struct isis_nexthop *nexthop)
87: {
88: nexthop->lock--;
89: if (nexthop->lock == 0)
90: {
91: listnode_delete (isis->nexthops, nexthop);
92: XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
93: }
94:
95: return;
96: }
97:
98: static int
99: nexthoplookup (struct list *nexthops, struct in_addr *ip,
100: unsigned int ifindex)
101: {
102: struct listnode *node;
103: struct isis_nexthop *nh;
104:
105: for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
106: {
107: if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
108: ifindex == nh->ifindex)
109: return 1;
110: }
111:
112: return 0;
113: }
114:
115: #ifdef EXTREME_DEBUG
116: static void
117: nexthop_print (struct isis_nexthop *nh)
118: {
119: u_char buf[BUFSIZ];
120:
121: inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
122:
123: zlog_debug (" %s %u", buf, nh->ifindex);
124: }
125:
126: static void
127: nexthops_print (struct list *nhs)
128: {
129: struct listnode *node;
130: struct isis_nexthop *nh;
131:
132: for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
133: nexthop_print (nh);
134: }
135: #endif /* EXTREME_DEBUG */
136:
137: #ifdef HAVE_IPV6
138: static struct isis_nexthop6 *
139: isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
140: {
141: struct isis_nexthop6 *nexthop6;
142:
143: nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
144: if (!nexthop6)
145: {
146: zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
147: }
148:
149: nexthop6->ifindex = ifindex;
150: memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
151: nexthop6->lock++;
152:
153: return nexthop6;
154: }
155:
156: static struct isis_nexthop6 *
157: isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
158: {
159: struct listnode *node;
160: struct isis_nexthop6 *nexthop6;
161:
162: for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
163: {
164: if (nexthop6->ifindex != ifindex)
165: continue;
166: if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
167: continue;
168:
169: nexthop6->lock++;
170: return nexthop6;
171: }
172:
173: nexthop6 = isis_nexthop6_new (ip6, ifindex);
174:
175: return nexthop6;
176: }
177:
178: static void
179: isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
180: {
181:
182: nexthop6->lock--;
183: if (nexthop6->lock == 0)
184: {
185: listnode_delete (isis->nexthops6, nexthop6);
186: XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
187: }
188:
189: return;
190: }
191:
192: static int
193: nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
194: unsigned int ifindex)
195: {
196: struct listnode *node;
197: struct isis_nexthop6 *nh6;
198:
199: for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
200: {
201: if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
202: ifindex == nh6->ifindex)
203: return 1;
204: }
205:
206: return 0;
207: }
208:
209: #ifdef EXTREME_DEBUG
210: static void
211: nexthop6_print (struct isis_nexthop6 *nh6)
212: {
213: u_char buf[BUFSIZ];
214:
215: inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
216:
217: zlog_debug (" %s %u", buf, nh6->ifindex);
218: }
219:
220: static void
221: nexthops6_print (struct list *nhs6)
222: {
223: struct listnode *node;
224: struct isis_nexthop6 *nh6;
225:
226: for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
227: nexthop6_print (nh6);
228: }
229: #endif /* EXTREME_DEBUG */
230: #endif /* HAVE_IPV6 */
231:
232: static void
233: adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
234: {
235: struct isis_nexthop *nh;
236: struct listnode *node;
237: struct in_addr *ipv4_addr;
238:
239: if (adj->ipv4_addrs == NULL)
240: return;
241:
242: for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
243: {
244: if (!nexthoplookup (nexthops, ipv4_addr,
245: adj->circuit->interface->ifindex))
246: {
247: nh = isis_nexthop_create (ipv4_addr,
248: adj->circuit->interface->ifindex);
249: listnode_add (nexthops, nh);
250: }
251: }
252: }
253:
254: #ifdef HAVE_IPV6
255: static void
256: adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
257: {
258: struct listnode *node;
259: struct in6_addr *ipv6_addr;
260: struct isis_nexthop6 *nh6;
261:
262: if (!adj->ipv6_addrs)
263: return;
264:
265: for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
266: {
267: if (!nexthop6lookup (nexthops6, ipv6_addr,
268: adj->circuit->interface->ifindex))
269: {
270: nh6 = isis_nexthop6_create (ipv6_addr,
271: adj->circuit->interface->ifindex);
272: listnode_add (nexthops6, nh6);
273: }
274: }
275: }
276: #endif /* HAVE_IPV6 */
277:
278: static struct isis_route_info *
279: isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
280: struct list *adjacencies)
281: {
282: struct isis_route_info *rinfo;
283: struct isis_adjacency *adj;
284: struct listnode *node;
285:
286: rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
287: if (!rinfo)
288: {
289: zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
290: return NULL;
291: }
292:
293: if (family == AF_INET)
294: {
295: rinfo->nexthops = list_new ();
296: for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
297: adjinfo2nexthop (rinfo->nexthops, adj);
298: }
299: #ifdef HAVE_IPV6
300: if (family == AF_INET6)
301: {
302: rinfo->nexthops6 = list_new ();
303: for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
304: adjinfo2nexthop6 (rinfo->nexthops6, adj);
305: }
306:
307: #endif /* HAVE_IPV6 */
308:
309: rinfo->cost = cost;
310: rinfo->depth = depth;
311:
312: return rinfo;
313: }
314:
315: static void
316: isis_route_info_delete (struct isis_route_info *route_info)
317: {
318: if (route_info->nexthops)
319: {
320: route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
321: list_delete (route_info->nexthops);
322: }
323:
324: #ifdef HAVE_IPV6
325: if (route_info->nexthops6)
326: {
327: route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
328: list_delete (route_info->nexthops6);
329: }
330: #endif /* HAVE_IPV6 */
331:
332: XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
333: }
334:
335: static int
336: isis_route_info_same_attrib (struct isis_route_info *new,
337: struct isis_route_info *old)
338: {
339: if (new->cost != old->cost)
340: return 0;
341: if (new->depth != old->depth)
342: return 0;
343:
344: return 1;
345: }
346:
347: static int
348: isis_route_info_same (struct isis_route_info *new,
349: struct isis_route_info *old, u_char family)
350: {
351: struct listnode *node;
352: struct isis_nexthop *nexthop;
353: #ifdef HAVE_IPV6
354: struct isis_nexthop6 *nexthop6;
355: #endif /* HAVE_IPV6 */
356: if (!isis_route_info_same_attrib (new, old))
357: return 0;
358:
359: if (family == AF_INET)
360: {
361: for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
362: if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
363: == 0)
364: return 0;
365:
366: for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
367: if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
368: == 0)
369: return 0;
370: }
371: #ifdef HAVE_IPV6
372: else if (family == AF_INET6)
373: {
374: for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
375: if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
376: nexthop6->ifindex) == 0)
377: return 0;
378:
379: for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
380: if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
381: nexthop6->ifindex) == 0)
382: return 0;
383: }
384: #endif /* HAVE_IPV6 */
385:
386: return 1;
387: }
388:
389: static void
390: isis_nexthops_merge (struct list *new, struct list *old)
391: {
392: struct listnode *node;
393: struct isis_nexthop *nexthop;
394:
395: for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
396: {
397: if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
398: continue;
399: listnode_add (old, nexthop);
400: nexthop->lock++;
401: }
402: }
403:
404: #ifdef HAVE_IPV6
405: static void
406: isis_nexthops6_merge (struct list *new, struct list *old)
407: {
408: struct listnode *node;
409: struct isis_nexthop6 *nexthop6;
410:
411: for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
412: {
413: if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
414: continue;
415: listnode_add (old, nexthop6);
416: nexthop6->lock++;
417: }
418: }
419: #endif /* HAVE_IPV6 */
420:
421: static void
422: isis_route_info_merge (struct isis_route_info *new,
423: struct isis_route_info *old, u_char family)
424: {
425: if (family == AF_INET)
426: isis_nexthops_merge (new->nexthops, old->nexthops);
427: #ifdef HAVE_IPV6
428: else if (family == AF_INET6)
429: isis_nexthops6_merge (new->nexthops6, old->nexthops6);
430: #endif /* HAVE_IPV6 */
431:
432: return;
433: }
434:
435: static int
436: isis_route_info_prefer_new (struct isis_route_info *new,
437: struct isis_route_info *old)
438: {
439: if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
440: return 1;
441:
442: if (new->cost < old->cost)
443: return 1;
444:
445: return 0;
446: }
447:
448: struct isis_route_info *
449: isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
450: struct list *adjacencies, struct isis_area *area,
451: int level)
452: {
453: struct route_node *route_node;
454: struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
455: u_char buff[BUFSIZ];
456: u_char family;
457:
458: family = prefix->family;
459: /* for debugs */
460: prefix2str (prefix, (char *) buff, BUFSIZ);
461:
462: rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
463: if (!rinfo_new)
464: {
465: zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
466: area->area_tag);
467: return NULL;
468: }
469:
470: if (family == AF_INET)
471: route_node = route_node_get (area->route_table[level - 1], prefix);
472: #ifdef HAVE_IPV6
473: else if (family == AF_INET6)
474: route_node = route_node_get (area->route_table6[level - 1], prefix);
475: #endif /* HAVE_IPV6 */
476: else
477: return NULL;
478: rinfo_old = route_node->info;
479: if (!rinfo_old)
480: {
481: if (isis->debugs & DEBUG_RTE_EVENTS)
482: zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
483: SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
484: route_node->info = rinfo_new;
485: return rinfo_new;
486: }
487:
488: if (isis->debugs & DEBUG_RTE_EVENTS)
489: zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
490: buff);
491:
492: if (isis_route_info_same (rinfo_new, rinfo_old, family))
493: {
494: if (isis->debugs & DEBUG_RTE_EVENTS)
495: zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
496: isis_route_info_delete (rinfo_new);
497: route_info = rinfo_old;
498: }
499: else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
500: {
501: /* merge the nexthop lists */
502: if (isis->debugs & DEBUG_RTE_EVENTS)
503: zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
504: area->area_tag, buff);
505: #ifdef EXTREME_DEBUG
506: if (family == AF_INET)
507: {
508: zlog_debug ("Old nexthops");
509: nexthops_print (rinfo_old->nexthops);
510: zlog_debug ("New nexthops");
511: nexthops_print (rinfo_new->nexthops);
512: }
513: else if (family == AF_INET6)
514: {
515: zlog_debug ("Old nexthops");
516: nexthops6_print (rinfo_old->nexthops6);
517: zlog_debug ("New nexthops");
518: nexthops6_print (rinfo_new->nexthops6);
519: }
520: #endif /* EXTREME_DEBUG */
521: isis_route_info_merge (rinfo_new, rinfo_old, family);
522: isis_route_info_delete (rinfo_new);
523: route_info = rinfo_old;
524: UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
525: }
526: else
527: {
528: if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
529: {
530: if (isis->debugs & DEBUG_RTE_EVENTS)
531: zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
532: buff);
533: isis_route_info_delete (rinfo_old);
534: route_info = rinfo_new;
535: }
536: else
537: {
538: if (isis->debugs & DEBUG_RTE_EVENTS)
539: zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
540: buff);
541: isis_route_info_delete (rinfo_new);
542: route_info = rinfo_old;
543: }
544: }
545:
546: SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
547: route_node->info = route_info;
548:
549: return route_info;
550: }
551:
552: static void
553: isis_route_delete (struct prefix *prefix, struct route_table *table)
554: {
555: struct route_node *rode;
556: struct isis_route_info *rinfo;
557: char buff[BUFSIZ];
558:
559: /* for log */
560: prefix2str (prefix, buff, BUFSIZ);
561:
562:
563: rode = route_node_get (table, prefix);
564: rinfo = rode->info;
565:
566: if (rinfo == NULL)
567: {
568: if (isis->debugs & DEBUG_RTE_EVENTS)
569: zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
570: return;
571: }
572:
573: if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
574: {
575: UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
576: if (isis->debugs & DEBUG_RTE_EVENTS)
577: zlog_debug ("ISIS-Rte: route delete %s", buff);
578: isis_zebra_route_update (prefix, rinfo);
579: }
580: isis_route_info_delete (rinfo);
581: rode->info = NULL;
582:
583: return;
584: }
585:
586: /* Validating routes in particular table. */
587: static void
588: isis_route_validate_table (struct isis_area *area, struct route_table *table)
589: {
590: struct route_node *rnode, *drnode;
591: struct isis_route_info *rinfo;
592: u_char buff[BUFSIZ];
593:
594: for (rnode = route_top (table); rnode; rnode = route_next (rnode))
595: {
596: if (rnode->info == NULL)
597: continue;
598: rinfo = rnode->info;
599:
600: if (isis->debugs & DEBUG_RTE_EVENTS)
601: {
602: prefix2str (&rnode->p, (char *) buff, BUFSIZ);
603: zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
604: area->area_tag,
605: (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
606: "sync'ed" : "nosync"),
607: (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
608: "active" : "inactive"), buff);
609: }
610:
611: isis_zebra_route_update (&rnode->p, rinfo);
612: if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
613: {
614: /* Area is either L1 or L2 => we use level route tables directly for
615: * validating => no problems with deleting routes. */
616: if (area->is_type != IS_LEVEL_1_AND_2)
617: {
618: isis_route_delete (&rnode->p, table);
619: continue;
620: }
621: /* If area is L1L2, we work with merge table and therefore must
622: * delete node from level tables as well before deleting route info.
623: * FIXME: Is it performance problem? There has to be the better way.
624: * Like not to deal with it here at all (see the next comment)? */
625: if (rnode->p.family == AF_INET)
626: {
627: drnode = route_node_get (area->route_table[0], &rnode->p);
628: if (drnode->info == rnode->info)
629: drnode->info = NULL;
630: drnode = route_node_get (area->route_table[1], &rnode->p);
631: if (drnode->info == rnode->info)
632: drnode->info = NULL;
633: }
634:
635: #ifdef HAVE_IPV6
636: if (rnode->p.family == AF_INET6)
637: {
638: drnode = route_node_get (area->route_table6[0], &rnode->p);
639: if (drnode->info == rnode->info)
640: drnode->info = NULL;
641: drnode = route_node_get (area->route_table6[1], &rnode->p);
642: if (drnode->info == rnode->info)
643: drnode->info = NULL;
644: }
645: #endif
646:
647: isis_route_delete (&rnode->p, table);
648: }
649: }
650: }
651:
652: /* Function to validate route tables for L1L2 areas. In this case we can't use
653: * level route tables directly, we have to merge them at first. L1 routes are
654: * preferred over the L2 ones.
655: *
656: * Merge algorithm is trivial (at least for now). All L1 paths are copied into
657: * merge table at first, then L2 paths are added if L1 path for same prefix
658: * doesn't already exists there.
659: *
660: * FIXME: Is it right place to do it at all? Maybe we should push both levels
661: * to the RIB with different zebra route types and let RIB handle this? */
662: static void
663: isis_route_validate_merge (struct isis_area *area, int family)
664: {
665: struct route_table *table = NULL;
666: struct route_table *merge;
667: struct route_node *rnode, *mrnode;
668:
669: merge = route_table_init ();
670:
671: if (family == AF_INET)
672: table = area->route_table[0];
673: #ifdef HAVE_IPV6
674: else if (family == AF_INET6)
675: table = area->route_table6[0];
676: #endif
677:
678: for (rnode = route_top (table); rnode; rnode = route_next (rnode))
679: {
680: if (rnode->info == NULL)
681: continue;
682: mrnode = route_node_get (merge, &rnode->p);
683: mrnode->info = rnode->info;
684: }
685:
686: if (family == AF_INET)
687: table = area->route_table[1];
688: #ifdef HAVE_IPV6
689: else if (family == AF_INET6)
690: table = area->route_table6[1];
691: #endif
692:
693: for (rnode = route_top (table); rnode; rnode = route_next (rnode))
694: {
695: if (rnode->info == NULL)
696: continue;
697: mrnode = route_node_get (merge, &rnode->p);
698: if (mrnode->info != NULL)
699: continue;
700: mrnode->info = rnode->info;
701: }
702:
703: isis_route_validate_table (area, merge);
704: route_table_finish (merge);
705: }
706:
707: /* Walk through route tables and propagate necessary changes into RIB. In case
708: * of L1L2 area, level tables have to be merged at first. */
709: int
710: isis_route_validate (struct thread *thread)
711: {
712: struct isis_area *area;
713:
714: area = THREAD_ARG (thread);
715:
716: if (area->is_type == IS_LEVEL_1)
717: {
718: isis_route_validate_table (area, area->route_table[0]);
719: goto validate_ipv6;
720: }
721: if (area->is_type == IS_LEVEL_2)
722: {
723: isis_route_validate_table (area, area->route_table[1]);
724: goto validate_ipv6;
725: }
726:
727: isis_route_validate_merge (area, AF_INET);
728:
729: validate_ipv6:
730: #ifdef HAVE_IPV6
731: if (area->is_type == IS_LEVEL_1)
732: {
733: isis_route_validate_table (area, area->route_table6[0]);
734: return ISIS_OK;
735: }
736: if (area->is_type == IS_LEVEL_2)
737: {
738: isis_route_validate_table (area, area->route_table6[1]);
739: return ISIS_OK;
740: }
741:
742: isis_route_validate_merge (area, AF_INET6);
743: #endif
744:
745: return ISIS_OK;
746: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>