version 1.1.1.1, 2012/02/21 17:26:11
|
version 1.1.1.3, 2013/07/21 23:54:38
|
Line 36
|
Line 36
|
|
|
#include "isis_constants.h" |
#include "isis_constants.h" |
#include "isis_common.h" |
#include "isis_common.h" |
|
#include "isis_flags.h" |
#include "dict.h" |
#include "dict.h" |
#include "isisd.h" |
#include "isisd.h" |
#include "isis_misc.h" |
#include "isis_misc.h" |
Line 48
|
Line 49
|
#include "isis_route.h" |
#include "isis_route.h" |
#include "isis_zebra.h" |
#include "isis_zebra.h" |
|
|
extern struct isis *isis; |
|
extern struct thread_master *master; |
|
|
|
static struct isis_nexthop * |
static struct isis_nexthop * |
isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) |
isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) |
{ |
{ |
Line 246 adjinfo2nexthop (struct list *nexthops, struct isis_ad
|
Line 244 adjinfo2nexthop (struct list *nexthops, struct isis_ad
|
{ |
{ |
nh = isis_nexthop_create (ipv4_addr, |
nh = isis_nexthop_create (ipv4_addr, |
adj->circuit->interface->ifindex); |
adj->circuit->interface->ifindex); |
|
nh->router_address = adj->router_address; |
listnode_add (nexthops, nh); |
listnode_add (nexthops, nh); |
} |
} |
} |
} |
Line 269 adjinfo2nexthop6 (struct list *nexthops6, struct isis_
|
Line 268 adjinfo2nexthop6 (struct list *nexthops6, struct isis_
|
{ |
{ |
nh6 = isis_nexthop6_create (ipv6_addr, |
nh6 = isis_nexthop6_create (ipv6_addr, |
adj->circuit->interface->ifindex); |
adj->circuit->interface->ifindex); |
|
nh6->router_address6 = adj->router_address6; |
listnode_add (nexthops6, nh6); |
listnode_add (nexthops6, nh6); |
} |
} |
} |
} |
Line 276 adjinfo2nexthop6 (struct list *nexthops6, struct isis_
|
Line 276 adjinfo2nexthop6 (struct list *nexthops6, struct isis_
|
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
|
|
static struct isis_route_info * |
static struct isis_route_info * |
isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, | isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth, |
struct list *adjacencies) | struct list *adjacencies) |
{ |
{ |
struct isis_route_info *rinfo; |
struct isis_route_info *rinfo; |
struct isis_adjacency *adj; |
struct isis_adjacency *adj; |
Line 290 isis_route_info_new (uint32_t cost, uint32_t depth, u_
|
Line 290 isis_route_info_new (uint32_t cost, uint32_t depth, u_
|
return NULL; |
return NULL; |
} |
} |
|
|
if (family == AF_INET) | if (prefix->family == AF_INET) |
{ |
{ |
rinfo->nexthops = list_new (); |
rinfo->nexthops = list_new (); |
for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) |
for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) |
adjinfo2nexthop (rinfo->nexthops, adj); | { |
| /* check for force resync this route */ |
| if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) |
| SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); |
| /* update neighbor router address */ |
| if (depth == 2 && prefix->prefixlen == 32) |
| adj->router_address = prefix->u.prefix4; |
| adjinfo2nexthop (rinfo->nexthops, adj); |
| } |
} |
} |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
if (family == AF_INET6) | if (prefix->family == AF_INET6) |
{ |
{ |
rinfo->nexthops6 = list_new (); |
rinfo->nexthops6 = list_new (); |
for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) |
for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) |
adjinfo2nexthop6 (rinfo->nexthops6, adj); | { |
| /* check for force resync this route */ |
| if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) |
| SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); |
| /* update neighbor router address */ |
| if (depth == 2 && prefix->prefixlen == 128) |
| adj->router_address6 = prefix->u.prefix6; |
| adjinfo2nexthop6 (rinfo->nexthops6, adj); |
| } |
} |
} |
|
|
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
Line 353 isis_route_info_same (struct isis_route_info *new,
|
Line 369 isis_route_info_same (struct isis_route_info *new,
|
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
struct isis_nexthop6 *nexthop6; |
struct isis_nexthop6 *nexthop6; |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
|
|
|
if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) |
|
return 0; |
|
|
|
if (CHECK_FLAG (new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) |
|
return 0; |
|
|
if (!isis_route_info_same_attrib (new, old)) |
if (!isis_route_info_same_attrib (new, old)) |
return 0; |
return 0; |
|
|
if (family == AF_INET) |
if (family == AF_INET) |
{ |
{ |
for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop)) |
for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop)) |
if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) | if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) |
== 0) |
== 0) |
return 0; |
return 0; |
|
|
for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop)) |
for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop)) |
if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) | if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) |
== 0) |
== 0) |
return 0; |
return 0; |
} |
} |
Line 386 isis_route_info_same (struct isis_route_info *new,
|
Line 409 isis_route_info_same (struct isis_route_info *new,
|
return 1; |
return 1; |
} |
} |
|
|
static void |
|
isis_nexthops_merge (struct list *new, struct list *old) |
|
{ |
|
struct listnode *node; |
|
struct isis_nexthop *nexthop; |
|
|
|
for (ALL_LIST_ELEMENTS_RO (new, node, nexthop)) |
|
{ |
|
if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex)) |
|
continue; |
|
listnode_add (old, nexthop); |
|
nexthop->lock++; |
|
} |
|
} |
|
|
|
#ifdef HAVE_IPV6 |
|
static void |
|
isis_nexthops6_merge (struct list *new, struct list *old) |
|
{ |
|
struct listnode *node; |
|
struct isis_nexthop6 *nexthop6; |
|
|
|
for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6)) |
|
{ |
|
if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex)) |
|
continue; |
|
listnode_add (old, nexthop6); |
|
nexthop6->lock++; |
|
} |
|
} |
|
#endif /* HAVE_IPV6 */ |
|
|
|
static void |
|
isis_route_info_merge (struct isis_route_info *new, |
|
struct isis_route_info *old, u_char family) |
|
{ |
|
if (family == AF_INET) |
|
isis_nexthops_merge (new->nexthops, old->nexthops); |
|
#ifdef HAVE_IPV6 |
|
else if (family == AF_INET6) |
|
isis_nexthops6_merge (new->nexthops6, old->nexthops6); |
|
#endif /* HAVE_IPV6 */ |
|
|
|
return; |
|
} |
|
|
|
static int |
|
isis_route_info_prefer_new (struct isis_route_info *new, |
|
struct isis_route_info *old) |
|
{ |
|
if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE)) |
|
return 1; |
|
|
|
if (new->cost < old->cost) |
|
return 1; |
|
|
|
return 0; |
|
} |
|
|
|
struct isis_route_info * |
struct isis_route_info * |
isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, |
isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, |
struct list *adjacencies, struct isis_area *area, |
struct list *adjacencies, struct isis_area *area, |
Line 459 isis_route_create (struct prefix *prefix, u_int32_t co
|
Line 423 isis_route_create (struct prefix *prefix, u_int32_t co
|
/* for debugs */ |
/* for debugs */ |
prefix2str (prefix, (char *) buff, BUFSIZ); |
prefix2str (prefix, (char *) buff, BUFSIZ); |
|
|
rinfo_new = isis_route_info_new (cost, depth, family, adjacencies); | rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies); |
if (!rinfo_new) |
if (!rinfo_new) |
{ |
{ |
zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", |
zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", |
Line 474 isis_route_create (struct prefix *prefix, u_int32_t co
|
Line 438 isis_route_create (struct prefix *prefix, u_int32_t co
|
route_node = route_node_get (area->route_table6[level - 1], prefix); |
route_node = route_node_get (area->route_table6[level - 1], prefix); |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
else |
else |
return NULL; |
|
rinfo_old = route_node->info; |
|
if (!rinfo_old) |
|
{ |
{ |
if (isis->debugs & DEBUG_RTE_EVENTS) | isis_route_info_delete (rinfo_new); |
zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); | return NULL; |
SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE); | |
route_node->info = rinfo_new; | |
return rinfo_new; | |
} |
} |
|
|
if (isis->debugs & DEBUG_RTE_EVENTS) | rinfo_old = route_node->info; |
zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag, | if (!rinfo_old) |
buff); | |
| |
if (isis_route_info_same (rinfo_new, rinfo_old, family)) | |
{ |
{ |
if (isis->debugs & DEBUG_RTE_EVENTS) |
if (isis->debugs & DEBUG_RTE_EVENTS) |
zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff); | zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); |
isis_route_info_delete (rinfo_new); | route_info = rinfo_new; |
route_info = rinfo_old; | UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); |
} |
} |
else if (isis_route_info_same_attrib (rinfo_new, rinfo_old)) |
|
{ |
|
/* merge the nexthop lists */ |
|
if (isis->debugs & DEBUG_RTE_EVENTS) |
|
zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s", |
|
area->area_tag, buff); |
|
#ifdef EXTREME_DEBUG |
|
if (family == AF_INET) |
|
{ |
|
zlog_debug ("Old nexthops"); |
|
nexthops_print (rinfo_old->nexthops); |
|
zlog_debug ("New nexthops"); |
|
nexthops_print (rinfo_new->nexthops); |
|
} |
|
else if (family == AF_INET6) |
|
{ |
|
zlog_debug ("Old nexthops"); |
|
nexthops6_print (rinfo_old->nexthops6); |
|
zlog_debug ("New nexthops"); |
|
nexthops6_print (rinfo_new->nexthops6); |
|
} |
|
#endif /* EXTREME_DEBUG */ |
|
isis_route_info_merge (rinfo_new, rinfo_old, family); |
|
isis_route_info_delete (rinfo_new); |
|
route_info = rinfo_old; |
|
UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); |
|
} |
|
else |
else |
{ |
{ |
if (isis_route_info_prefer_new (rinfo_new, rinfo_old)) | if (isis->debugs & DEBUG_RTE_EVENTS) |
{ | zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag, |
if (isis->debugs & DEBUG_RTE_EVENTS) | buff); |
zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag, | if (isis_route_info_same (rinfo_new, rinfo_old, family)) |
buff); | { |
isis_route_info_delete (rinfo_old); | if (isis->debugs & DEBUG_RTE_EVENTS) |
route_info = rinfo_new; | zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, |
} | buff); |
| isis_route_info_delete (rinfo_new); |
| route_info = rinfo_old; |
| } |
else |
else |
{ | { |
if (isis->debugs & DEBUG_RTE_EVENTS) | if (isis->debugs & DEBUG_RTE_EVENTS) |
zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag, | zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag, |
buff); | buff); |
isis_route_info_delete (rinfo_new); | isis_route_info_delete (rinfo_old); |
route_info = rinfo_old; | route_info = rinfo_new; |
} | UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); |
| } |
} |
} |
|
|
SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE); |
SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE); |
Line 570 isis_route_delete (struct prefix *prefix, struct route
|
Line 502 isis_route_delete (struct prefix *prefix, struct route
|
return; |
return; |
} |
} |
|
|
if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) | if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) |
{ |
{ |
UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); |
UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); |
if (isis->debugs & DEBUG_RTE_EVENTS) |
if (isis->debugs & DEBUG_RTE_EVENTS) |
Line 600 isis_route_validate_table (struct isis_area *area, str
|
Line 532 isis_route_validate_table (struct isis_area *area, str
|
if (isis->debugs & DEBUG_RTE_EVENTS) |
if (isis->debugs & DEBUG_RTE_EVENTS) |
{ |
{ |
prefix2str (&rnode->p, (char *) buff, BUFSIZ); |
prefix2str (&rnode->p, (char *) buff, BUFSIZ); |
zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s", | zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s", |
area->area_tag, |
area->area_tag, |
(CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ? | (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ? |
"sync'ed" : "nosync"), | "synced" : "not-synced"), |
| (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ? |
| "resync" : "not-resync"), |
(CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ? |
(CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ? |
"active" : "inactive"), buff); |
"active" : "inactive"), buff); |
} |
} |
Line 706 isis_route_validate_merge (struct isis_area *area, int
|
Line 640 isis_route_validate_merge (struct isis_area *area, int
|
|
|
/* Walk through route tables and propagate necessary changes into RIB. In case |
/* Walk through route tables and propagate necessary changes into RIB. In case |
* of L1L2 area, level tables have to be merged at first. */ |
* of L1L2 area, level tables have to be merged at first. */ |
int | void |
isis_route_validate (struct thread *thread) | isis_route_validate (struct isis_area *area) |
{ |
{ |
struct isis_area *area; | struct listnode *node; |
| struct isis_circuit *circuit; |
|
|
area = THREAD_ARG (thread); |
|
|
|
if (area->is_type == IS_LEVEL_1) |
if (area->is_type == IS_LEVEL_1) |
{ | isis_route_validate_table (area, area->route_table[0]); |
isis_route_validate_table (area, area->route_table[0]); | else if (area->is_type == IS_LEVEL_2) |
goto validate_ipv6; | isis_route_validate_table (area, area->route_table[1]); |
} | else |
if (area->is_type == IS_LEVEL_2) | isis_route_validate_merge (area, AF_INET); |
{ | |
isis_route_validate_table (area, area->route_table[1]); | |
goto validate_ipv6; | |
} | |
|
|
isis_route_validate_merge (area, AF_INET); |
|
|
|
validate_ipv6: |
|
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
if (area->is_type == IS_LEVEL_1) |
if (area->is_type == IS_LEVEL_1) |
|
isis_route_validate_table (area, area->route_table6[0]); |
|
else if (area->is_type == IS_LEVEL_2) |
|
isis_route_validate_table (area, area->route_table6[1]); |
|
else |
|
isis_route_validate_merge (area, AF_INET6); |
|
#endif |
|
|
|
/* walk all circuits and reset any spf specific flags */ |
|
for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) |
|
UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); |
|
|
|
return; |
|
} |
|
|
|
void |
|
isis_route_invalidate_table (struct isis_area *area, struct route_table *table) |
|
{ |
|
struct route_node *rode; |
|
struct isis_route_info *rinfo; |
|
for (rode = route_top (table); rode; rode = route_next (rode)) |
{ |
{ |
isis_route_validate_table (area, area->route_table6[0]); | if (rode->info == NULL) |
return ISIS_OK; | continue; |
| rinfo = rode->info; |
| |
| UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); |
} |
} |
if (area->is_type == IS_LEVEL_2) | } |
{ | |
isis_route_validate_table (area, area->route_table6[1]); | |
return ISIS_OK; | |
} | |
|
|
isis_route_validate_merge (area, AF_INET6); | void |
#endif | isis_route_invalidate (struct isis_area *area) |
| { |
return ISIS_OK; | if (area->is_type & IS_LEVEL_1) |
| isis_route_invalidate_table (area, area->route_table[0]); |
| if (area->is_type & IS_LEVEL_2) |
| isis_route_invalidate_table (area, area->route_table[1]); |
} |
} |