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
7 * based on ../ospf6d/ospf6_route.[ch]
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)
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
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.
28 #include <net/ethernet.h>
40 #include "isis_constants.h"
41 #include "isis_common.h"
44 #include "isis_misc.h"
45 #include "isis_adjacency.h"
46 #include "isis_circuit.h"
51 #include "isis_route.h"
52 #include "isis_zebra.h"
54 extern struct isis
*isis
;
55 extern struct thread_master
*master
;
58 isis_nexthop_create (struct in_addr
*ip
, unsigned int ifindex
)
61 struct listnode
*node
;
62 struct isis_nexthop
*nexthop
;
64 for (node
= listhead (isis
->nexthops
); node
; nextnode (node
)) {
65 nexthop
= getdata (node
);
66 if (nexthop
->ifindex
!= ifindex
)
68 if (ip
&& memcmp (&nexthop
->ip
, ip
, sizeof (struct in_addr
)) != 0)
75 nexthop
= XMALLOC (MTYPE_ISIS_NEXTHOP
, sizeof (struct isis_nexthop
));
77 zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
80 memset (nexthop
, 0, sizeof (struct isis_nexthop
));
81 nexthop
->ifindex
= ifindex
;
82 memcpy (&nexthop
->ip
, ip
, sizeof (struct in_addr
));
83 listnode_add (isis
->nexthops
, nexthop
);
91 isis_nexthop_delete (struct isis_nexthop
*nexthop
)
94 if (nexthop
->lock
== 0) {
95 listnode_delete (isis
->nexthops
, nexthop
);
96 XFREE (MTYPE_ISIS_NEXTHOP
, nexthop
);
103 nexthoplookup (struct list
*nexthops
, struct in_addr
*ip
,
104 unsigned int ifindex
)
106 struct listnode
*node
;
107 struct isis_nexthop
*nh
;
109 for (node
= listhead (nexthops
); node
; nextnode (node
)) {
111 if (!(memcmp (ip
, &nh
->ip
, sizeof (struct in_addr
))) &&
112 ifindex
== nh
->ifindex
)
120 nexthop_print (struct isis_nexthop
*nh
)
124 inet_ntop (AF_INET
, &nh
->ip
, buf
, BUFSIZ
);
126 zlog_info (" %s %u", buf
, nh
->ifindex
);
130 nexthops_print (struct list
*nhs
)
132 struct listnode
*node
;
134 for (node
= listhead(nhs
); node
; nextnode (node
))
135 nexthop_print (getdata (node
));
140 struct isis_nexthop6
*
141 isis_nexthop6_new (struct in6_addr
*ip6
, unsigned int ifindex
)
144 struct isis_nexthop6
*nexthop6
;
146 nexthop6
= XMALLOC (MTYPE_ISIS_NEXTHOP6
, sizeof (struct isis_nexthop6
));
148 zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
151 memset (nexthop6
, 0, sizeof (struct isis_nexthop6
));
152 nexthop6
->ifindex
= ifindex
;
153 memcpy (&nexthop6
->ip6
, ip6
, sizeof (struct in6_addr
));
159 struct isis_nexthop6
*
160 isis_nexthop6_create (struct in6_addr
*ip6
, unsigned int ifindex
)
163 struct listnode
*node
;
164 struct isis_nexthop6
*nexthop6
;
166 for (node
= listhead (isis
->nexthops6
); node
; nextnode (node
)) {
167 nexthop6
= getdata (node
);
168 if (nexthop6
->ifindex
!= ifindex
)
170 if (ip6
&& memcmp (&nexthop6
->ip6
, ip6
, sizeof (struct in6_addr
)) != 0)
177 nexthop6
= isis_nexthop6_new (ip6
, ifindex
);
184 isis_nexthop6_delete (struct isis_nexthop6
*nexthop6
)
188 if (nexthop6
->lock
== 0) {
189 listnode_delete (isis
->nexthops6
, nexthop6
);
190 XFREE (MTYPE_ISIS_NEXTHOP6
, nexthop6
);
197 nexthop6lookup (struct list
*nexthops6
, struct in6_addr
*ip6
,
198 unsigned int ifindex
)
200 struct listnode
*node
;
201 struct isis_nexthop6
*nh6
;
203 for (node
= listhead (nexthops6
); node
; nextnode (node
)) {
204 nh6
= getdata (node
);
205 if (!(memcmp (ip6
, &nh6
->ip6
, sizeof (struct in6_addr
))) &&
206 ifindex
== nh6
->ifindex
)
214 nexthop6_print (struct isis_nexthop6
*nh6
)
218 inet_ntop (AF_INET6
, &nh6
->ip6
, buf
, BUFSIZ
);
220 zlog_info (" %s %u", buf
, nh6
->ifindex
);
224 nexthops6_print (struct list
*nhs6
)
226 struct listnode
*node
;
228 for (node
= listhead(nhs6
); node
; nextnode (node
))
229 nexthop6_print (getdata (node
));
233 #endif /* HAVE_IPV6 */
236 adjinfo2nexthop (struct list
*nexthops
, struct isis_adjacency
*adj
)
238 struct isis_nexthop
*nh
;
239 struct listnode
*node
;
240 struct in_addr
*ipv4_addr
;
242 if (adj
->ipv4_addrs
== NULL
)
244 for (node
= listhead (adj
->ipv4_addrs
); node
; nextnode (node
)) {
245 ipv4_addr
= getdata (node
);
246 if (!nexthoplookup (nexthops
, ipv4_addr
,
247 adj
->circuit
->interface
->ifindex
)) {
248 nh
= isis_nexthop_create (ipv4_addr
,
249 adj
->circuit
->interface
->ifindex
);
250 listnode_add (nexthops
, nh
);
257 adjinfo2nexthop6 (struct list
*nexthops6
, struct isis_adjacency
*adj
)
259 struct listnode
*node
;
260 struct in6_addr
*ipv6_addr
;
261 struct isis_nexthop6
*nh6
;
263 if (!adj
->ipv6_addrs
)
266 for (node
= listhead (adj
->ipv6_addrs
); node
; nextnode (node
)) {
267 ipv6_addr
= getdata (node
);
268 if (!nexthop6lookup (nexthops6
, ipv6_addr
,
269 adj
->circuit
->interface
->ifindex
)) {
270 nh6
= isis_nexthop6_create (ipv6_addr
,
271 adj
->circuit
->interface
->ifindex
);
272 listnode_add (nexthops6
, nh6
);
276 #endif /* HAVE_IPV6 */
278 struct isis_route_info
*
279 isis_route_info_new (uint32_t cost
, uint32_t depth
, u_char family
,
280 struct list
*adjacencies
)
282 struct isis_route_info
*rinfo
;
283 struct isis_adjacency
*adj
;
284 struct listnode
*node
;
286 rinfo
= XMALLOC (MTYPE_ISIS_ROUTE_INFO
, sizeof (struct isis_route_info
));
288 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
291 memset (rinfo
, 0, sizeof (struct isis_route_info
));
293 if (family
== AF_INET
) {
294 rinfo
->nexthops
= list_new ();
295 for (node
= listhead (adjacencies
); node
; nextnode (node
)) {
296 adj
= getdata (node
);
297 adjinfo2nexthop (rinfo
->nexthops
, adj
);
301 if (family
== AF_INET6
) {
302 rinfo
->nexthops6
= list_new ();
303 for (node
= listhead (adjacencies
); node
; nextnode (node
)) {
305 adjinfo2nexthop6 (rinfo
->nexthops6
, adj
);
309 #endif /* HAVE_IPV6 */
312 rinfo
->depth
= depth
;
319 isis_route_info_delete (struct isis_route_info
*route_info
)
322 if (route_info
->nexthops
) {
323 route_info
->nexthops
->del
= (void *)isis_nexthop_delete
;
324 list_delete (route_info
->nexthops
);
328 if (route_info
->nexthops6
) {
329 route_info
->nexthops6
->del
= (void *)isis_nexthop6_delete
;
330 list_delete (route_info
->nexthops6
);
332 #endif /* HAVE_IPV6 */
334 XFREE (MTYPE_ISIS_ROUTE_INFO
, route_info
);
338 isis_route_info_same_attrib (struct isis_route_info
*new,
339 struct isis_route_info
*old
)
341 if (new->cost
!= old
->cost
)
343 if (new->depth
!= old
->depth
)
350 isis_route_info_same (struct isis_route_info
*new, struct isis_route_info
*old
,
353 struct listnode
*node
;
354 struct isis_nexthop
*nexthop
;
356 struct isis_nexthop6
*nexthop6
;
357 #endif /* HAVE_IPV6 */
358 if (!isis_route_info_same_attrib (new, old
))
361 if (family
== AF_INET
) {
362 for (node
= listhead (new->nexthops
); node
; nextnode (node
)) {
363 nexthop
= (struct isis_nexthop
*) getdata (node
);
364 if (nexthoplookup (old
->nexthops
, &nexthop
->ip
, nexthop
->ifindex
) == 0)
368 for (node
= listhead (old
->nexthops
); node
; nextnode (node
)) {
369 nexthop
= (struct isis_nexthop
*) getdata (node
);
370 if (nexthoplookup (new->nexthops
, &nexthop
->ip
, nexthop
->ifindex
) == 0)
375 else if (family
== AF_INET6
) {
376 for (node
= listhead (new->nexthops6
); node
; nextnode (node
)) {
377 nexthop6
= (struct isis_nexthop6
*) getdata (node
);
378 if (nexthop6lookup (old
->nexthops6
, &nexthop6
->ip6
,
379 nexthop6
->ifindex
) == 0)
383 for (node
= listhead (old
->nexthops6
); node
; nextnode (node
)) {
384 nexthop6
= (struct isis_nexthop6
*) getdata (node
);
385 if (nexthop6lookup (new->nexthops6
, &nexthop6
->ip6
,
386 nexthop6
->ifindex
) == 0)
390 #endif /* HAVE_IPV6 */
397 isis_nexthops_merge (struct list
*new, struct list
*old
)
399 struct listnode
*node
;
400 struct isis_nexthop
*nexthop
;
402 for (node
= listhead (new); node
; nextnode (node
)) {
403 nexthop
= (struct isis_nexthop
*) getdata (node
);
404 if (nexthoplookup (old
, &nexthop
->ip
, nexthop
->ifindex
))
406 listnode_add (old
, nexthop
);
414 isis_nexthops6_merge (struct list
*new, struct list
*old
)
416 struct listnode
*node
;
417 struct isis_nexthop6
*nexthop6
;
419 for (node
= listhead (new); node
; nextnode (node
)) {
420 nexthop6
= (struct isis_nexthop6
*) getdata (node
);
421 if (nexthop6lookup (old
, &nexthop6
->ip6
, nexthop6
->ifindex
))
423 listnode_add (old
, nexthop6
);
427 #endif /* HAVE_IPV6 */
430 isis_route_info_merge (struct isis_route_info
*new,
431 struct isis_route_info
*old
, u_char family
)
434 if (family
== AF_INET
)
435 isis_nexthops_merge (new->nexthops
, old
->nexthops
);
437 else if (family
== AF_INET6
)
438 isis_nexthops6_merge (new->nexthops6
, old
->nexthops6
);
439 #endif /* HAVE_IPV6 */
446 isis_route_info_prefer_new (struct isis_route_info
*new,
447 struct isis_route_info
*old
)
450 if (!CHECK_FLAG (old
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
453 if (new->cost
< old
->cost
)
460 struct isis_route_info
*
461 isis_route_create (struct prefix
*prefix
, u_int32_t cost
, u_int32_t depth
,
462 struct list
*adjacencies
, struct isis_area
*area
)
464 struct route_node
*route_node
;
465 struct isis_route_info
*rinfo_new
, *rinfo_old
, *route_info
= NULL
;
469 family
= prefix
->family
;
471 prefix2str (prefix
, buff
, BUFSIZ
);
473 rinfo_new
= isis_route_info_new (cost
, depth
, family
, adjacencies
);
475 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
480 if (family
== AF_INET
)
481 route_node
= route_node_get (area
->route_table
, prefix
);
483 else if (family
== AF_INET6
)
484 route_node
= route_node_get (area
->route_table6
, prefix
);
485 #endif /* HAVE_IPV6 */
488 rinfo_old
= route_node
->info
;
490 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
491 zlog_info ("ISIS-Rte (%s) route created: %s", area
->area_tag
, buff
);
492 SET_FLAG(rinfo_new
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
493 route_node
->info
= rinfo_new
;
497 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
498 zlog_info ("ISIS-Rte (%s) route already exists: %s", area
->area_tag
, buff
);
500 if (isis_route_info_same (rinfo_new
, rinfo_old
, family
)) {
501 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
502 zlog_info ("ISIS-Rte (%s) route unchanged: %s", area
->area_tag
, buff
);
503 isis_route_info_delete (rinfo_new
);
504 route_info
= rinfo_old
;
505 } else if (isis_route_info_same_attrib (rinfo_new
, rinfo_old
)) {
506 /* merge the nexthop lists */
507 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
508 zlog_info ("ISIS-Rte (%s) route changed (same attribs): %s",
509 area
->area_tag
, buff
);
511 zlog_info ("Old nexthops");
512 nexthops6_print (rinfo_old
->nexthops6
);
513 zlog_info ("New nexthops");
514 nexthops6_print (rinfo_new
->nexthops6
);
515 #endif /* EXTREME_DEBUG */
516 isis_route_info_merge (rinfo_new
, rinfo_old
, family
);
517 isis_route_info_delete (rinfo_new
);
518 route_info
= rinfo_old
;
520 if (isis_route_info_prefer_new (rinfo_new
, rinfo_old
)) {
521 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
522 zlog_info ("ISIS-Rte (%s) route changed: %s", area
->area_tag
, buff
);
523 isis_route_info_delete (rinfo_old
);
524 route_info
= rinfo_new
;
526 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
527 zlog_info ("ISIS-Rte (%s) route rejected: %s", area
->area_tag
, buff
);
528 isis_route_info_delete (rinfo_new
);
529 route_info
= rinfo_old
;
533 SET_FLAG (route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
534 route_node
->info
= route_info
;
540 isis_route_delete (struct prefix
*prefix
, struct route_table
*table
)
542 struct route_node
*rode
;
543 struct isis_route_info
*rinfo
;
547 prefix2str (prefix
, buff
, BUFSIZ
);
550 rode
= route_node_get (table
, prefix
);
554 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
555 zlog_info ("ISIS-Rte: tried to delete non-existant route %s", buff
);
559 if (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNC
)) {
560 UNSET_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
561 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
562 zlog_info ("ISIS-Rte: route delete %s", buff
);
563 isis_zebra_route_update (prefix
, rinfo
);
565 isis_route_info_delete (rinfo
);
572 isis_route_validate (struct thread
*thread
)
574 struct isis_area
*area
;
575 struct route_table
*table
;
576 struct route_node
*rode
;
577 struct isis_route_info
*rinfo
;
582 area
= THREAD_ARG (thread
);
583 table
= area
->route_table
;
587 for (rode
= route_top (table
); rode
; rode
= route_next (rode
)) {
588 if (rode
->info
== NULL
)
592 if (isis
->debugs
& DEBUG_RTE_EVENTS
) {
593 prefix2str (&rode
->p
, buff
, BUFSIZ
);
594 zlog_info ("ISIS-Rte (%s): route validate: %s %s %s",
596 (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNC
) ?
597 "sync'ed": "nosync"),
598 (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
) ?
599 "active": "inactive"), buff
);
602 isis_zebra_route_update (&rode
->p
, rinfo
);
603 if (!CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
604 isis_route_delete (&rode
->p
, area
->route_table
);
609 table
= area
->route_table6
;