/*
* IS-IS Rout(e)ing protocol - isis_route.c
* Copyright (C) 2001,2002 Sampo Saaristo
- * Tampere University of Technology
+ * Tampere University of Technology
* Institute of Communications Engineering
*
* based on ../ospf6d/ospf6_route.[ch]
* by Yasuhiro Ohara
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public Licenseas published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public Licenseas published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
- * This program is distributed in the hope that it will be useful,but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * This program is distributed in the hope that it will be useful,but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
#include "hash.h"
#include "if.h"
#include "table.h"
+#include "srcdest_table.h"
#include "isis_constants.h"
#include "isis_common.h"
#include "isis_misc.h"
#include "isis_adjacency.h"
#include "isis_circuit.h"
-#include "isis_tlv.h"
#include "isis_pdu.h"
#include "isis_lsp.h"
#include "isis_spf.h"
#include "isis_route.h"
#include "isis_zebra.h"
-static struct isis_nexthop *
-isis_nexthop_create (struct in_addr *ip, ifindex_t ifindex)
+static struct isis_nexthop *isis_nexthop_create(struct in_addr *ip,
+ ifindex_t ifindex)
{
- struct listnode *node;
- struct isis_nexthop *nexthop;
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
- for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop))
- {
- if (nexthop->ifindex != ifindex)
- continue;
- if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
- continue;
+ for (ALL_LIST_ELEMENTS_RO(isis->nexthops, node, nexthop)) {
+ if (nexthop->ifindex != ifindex)
+ continue;
+ if (ip && memcmp(&nexthop->ip, ip, sizeof(struct in_addr)) != 0)
+ continue;
- nexthop->lock++;
- return nexthop;
- }
+ nexthop->lock++;
+ return nexthop;
+ }
- nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
+ nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
- nexthop->ifindex = ifindex;
- memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
- listnode_add (isis->nexthops, nexthop);
- nexthop->lock++;
+ nexthop->ifindex = ifindex;
+ memcpy(&nexthop->ip, ip, sizeof(struct in_addr));
+ listnode_add(isis->nexthops, nexthop);
+ nexthop->lock++;
- return nexthop;
+ return nexthop;
}
-static void
-isis_nexthop_delete (struct isis_nexthop *nexthop)
+static void isis_nexthop_delete(struct isis_nexthop *nexthop)
{
- nexthop->lock--;
- if (nexthop->lock == 0)
- {
- listnode_delete (isis->nexthops, nexthop);
- XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
- }
-
- return;
+ nexthop->lock--;
+ if (nexthop->lock == 0) {
+ listnode_delete(isis->nexthops, nexthop);
+ XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
+ }
+
+ return;
}
-static int
-nexthoplookup (struct list *nexthops, struct in_addr *ip,
- ifindex_t ifindex)
+static int nexthoplookup(struct list *nexthops, struct in_addr *ip,
+ ifindex_t ifindex)
{
- struct listnode *node;
- struct isis_nexthop *nh;
+ struct listnode *node;
+ struct isis_nexthop *nh;
- for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
- {
- if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
- ifindex == nh->ifindex)
- return 1;
- }
+ for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
+ if (!(memcmp(ip, &nh->ip, sizeof(struct in_addr)))
+ && ifindex == nh->ifindex)
+ return 1;
+ }
- return 0;
+ return 0;
}
-#ifdef EXTREME_DEBUG
-static void
-nexthop_print (struct isis_nexthop *nh)
+static struct isis_nexthop6 *isis_nexthop6_new(struct in6_addr *ip6,
+ ifindex_t ifindex)
{
- u_char buf[BUFSIZ];
+ struct isis_nexthop6 *nexthop6;
- inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
+ nexthop6 = XCALLOC(MTYPE_ISIS_NEXTHOP6, sizeof(struct isis_nexthop6));
- zlog_debug (" %s %u", buf, nh->ifindex);
-}
+ nexthop6->ifindex = ifindex;
+ memcpy(&nexthop6->ip6, ip6, sizeof(struct in6_addr));
+ nexthop6->lock++;
-static void
-nexthops_print (struct list *nhs)
-{
- struct listnode *node;
- struct isis_nexthop *nh;
-
- for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
- nexthop_print (nh);
+ return nexthop6;
}
-#endif /* EXTREME_DEBUG */
-static struct isis_nexthop6 *
-isis_nexthop6_new (struct in6_addr *ip6, ifindex_t ifindex)
+static struct isis_nexthop6 *isis_nexthop6_create(struct in6_addr *ip6,
+ ifindex_t ifindex)
{
- struct isis_nexthop6 *nexthop6;
-
- nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
+ struct listnode *node;
+ struct isis_nexthop6 *nexthop6;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->nexthops6, node, nexthop6)) {
+ if (nexthop6->ifindex != ifindex)
+ continue;
+ if (ip6
+ && memcmp(&nexthop6->ip6, ip6, sizeof(struct in6_addr))
+ != 0)
+ continue;
+
+ nexthop6->lock++;
+ return nexthop6;
+ }
- nexthop6->ifindex = ifindex;
- memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
- nexthop6->lock++;
+ nexthop6 = isis_nexthop6_new(ip6, ifindex);
- return nexthop6;
+ return nexthop6;
}
-static struct isis_nexthop6 *
-isis_nexthop6_create (struct in6_addr *ip6, ifindex_t ifindex)
+static void isis_nexthop6_delete(struct isis_nexthop6 *nexthop6)
{
- struct listnode *node;
- struct isis_nexthop6 *nexthop6;
- for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
- {
- if (nexthop6->ifindex != ifindex)
- continue;
- if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
- continue;
-
- nexthop6->lock++;
- return nexthop6;
- }
-
- nexthop6 = isis_nexthop6_new (ip6, ifindex);
+ nexthop6->lock--;
+ if (nexthop6->lock == 0) {
+ listnode_delete(isis->nexthops6, nexthop6);
+ XFREE(MTYPE_ISIS_NEXTHOP6, nexthop6);
+ }
- return nexthop6;
+ return;
}
-static void
-isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
+static int nexthop6lookup(struct list *nexthops6, struct in6_addr *ip6,
+ ifindex_t ifindex)
{
+ struct listnode *node;
+ struct isis_nexthop6 *nh6;
- nexthop6->lock--;
- if (nexthop6->lock == 0)
- {
- listnode_delete (isis->nexthops6, nexthop6);
- XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
- }
+ for (ALL_LIST_ELEMENTS_RO(nexthops6, node, nh6)) {
+ if (!(memcmp(ip6, &nh6->ip6, sizeof(struct in6_addr)))
+ && ifindex == nh6->ifindex)
+ return 1;
+ }
- return;
+ return 0;
}
-static int
-nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
- ifindex_t ifindex)
+static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
{
- struct listnode *node;
- struct isis_nexthop6 *nh6;
-
- for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
- {
- if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
- ifindex == nh6->ifindex)
- return 1;
- }
-
- return 0;
+ struct isis_nexthop *nh;
+
+ for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
+ struct in_addr *ipv4_addr = &adj->ipv4_addresses[i];
+ if (!nexthoplookup(nexthops, ipv4_addr,
+ adj->circuit->interface->ifindex)) {
+ nh = isis_nexthop_create(
+ ipv4_addr, adj->circuit->interface->ifindex);
+ nh->router_address = adj->router_address;
+ listnode_add(nexthops, nh);
+ return;
+ }
+ }
}
-#ifdef EXTREME_DEBUG
-static void
-nexthop6_print (struct isis_nexthop6 *nh6)
+static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
{
- u_char buf[BUFSIZ];
-
- inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
-
- zlog_debug (" %s %u", buf, nh6->ifindex);
+ struct isis_nexthop6 *nh6;
+
+ for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
+ struct in6_addr *ipv6_addr = &adj->ipv6_addresses[i];
+ if (!nexthop6lookup(nexthops6, ipv6_addr,
+ adj->circuit->interface->ifindex)) {
+ nh6 = isis_nexthop6_create(
+ ipv6_addr, adj->circuit->interface->ifindex);
+ nh6->router_address6 = adj->router_address6;
+ listnode_add(nexthops6, nh6);
+ return;
+ }
+ }
}
-static void
-nexthops6_print (struct list *nhs6)
+static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
+ uint32_t cost,
+ uint32_t depth,
+ struct list *adjacencies)
{
- struct listnode *node;
- struct isis_nexthop6 *nh6;
+ struct isis_route_info *rinfo;
+ struct isis_adjacency *adj;
+ struct listnode *node;
+
+ rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
+
+ if (prefix->family == AF_INET) {
+ rinfo->nexthops = list_new();
+ for (ALL_LIST_ELEMENTS_RO(adjacencies, node, 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);
+ }
+ }
+ if (prefix->family == AF_INET6) {
+ rinfo->nexthops6 = list_new();
+ for (ALL_LIST_ELEMENTS_RO(adjacencies, node, 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
+ && (!src_p || !src_p->prefixlen)) {
+ adj->router_address6 = prefix->u.prefix6;
+ }
+ adjinfo2nexthop6(rinfo->nexthops6, adj);
+ }
+ }
+
+ rinfo->cost = cost;
+ rinfo->depth = depth;
- for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
- nexthop6_print (nh6);
+ return rinfo;
}
-#endif /* EXTREME_DEBUG */
-static void
-adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
+static void isis_route_info_delete(struct isis_route_info *route_info)
{
- struct isis_nexthop *nh;
- struct listnode *node;
- struct in_addr *ipv4_addr;
-
- if (adj->ipv4_addrs == NULL)
- return;
-
- for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
- {
- if (!nexthoplookup (nexthops, ipv4_addr,
- adj->circuit->interface->ifindex))
- {
- nh = isis_nexthop_create (ipv4_addr,
- adj->circuit->interface->ifindex);
- nh->router_address = adj->router_address;
- listnode_add (nexthops, nh);
+ if (route_info->nexthops) {
+ route_info->nexthops->del =
+ (void (*)(void *))isis_nexthop_delete;
+ list_delete(&route_info->nexthops);
}
- }
-}
-static void
-adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
-{
- struct listnode *node;
- struct in6_addr *ipv6_addr;
- struct isis_nexthop6 *nh6;
-
- if (!adj->ipv6_addrs)
- return;
-
- for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
- {
- if (!nexthop6lookup (nexthops6, ipv6_addr,
- adj->circuit->interface->ifindex))
- {
- nh6 = isis_nexthop6_create (ipv6_addr,
- adj->circuit->interface->ifindex);
- nh6->router_address6 = adj->router_address6;
- listnode_add (nexthops6, nh6);
+ if (route_info->nexthops6) {
+ route_info->nexthops6->del =
+ (void (*)(void *))isis_nexthop6_delete;
+ list_delete(&route_info->nexthops6);
}
- }
-}
-static struct isis_route_info *
-isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth,
- struct list *adjacencies)
-{
- struct isis_route_info *rinfo;
- struct isis_adjacency *adj;
- struct listnode *node;
-
- rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
-
- if (prefix->family == AF_INET)
- {
- rinfo->nexthops = list_new ();
- for (ALL_LIST_ELEMENTS_RO (adjacencies, node, 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);
- }
- }
- if (prefix->family == AF_INET6)
- {
- rinfo->nexthops6 = list_new ();
- for (ALL_LIST_ELEMENTS_RO (adjacencies, node, 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);
- }
- }
-
- rinfo->cost = cost;
- rinfo->depth = depth;
-
- return rinfo;
+ XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
}
-static void
-isis_route_info_delete (struct isis_route_info *route_info)
+static int isis_route_info_same_attrib(struct isis_route_info *new,
+ struct isis_route_info *old)
{
- if (route_info->nexthops)
- {
- route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
- list_delete (route_info->nexthops);
- }
-
- if (route_info->nexthops6)
- {
- route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
- list_delete (route_info->nexthops6);
- }
-
- XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
+ if (new->cost != old->cost)
+ return 0;
+ if (new->depth != old->depth)
+ return 0;
+
+ return 1;
}
-static int
-isis_route_info_same_attrib (struct isis_route_info *new,
- struct isis_route_info *old)
+static int isis_route_info_same(struct isis_route_info *new,
+ struct isis_route_info *old, uint8_t family)
{
- if (new->cost != old->cost)
- return 0;
- if (new->depth != old->depth)
- return 0;
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+ struct isis_nexthop6 *nexthop6;
+
+ 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))
+ return 0;
+
+ if (family == AF_INET) {
+ for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
+ if (nexthoplookup(old->nexthops, &nexthop->ip,
+ nexthop->ifindex)
+ == 0)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
+ if (nexthoplookup(new->nexthops, &nexthop->ip,
+ nexthop->ifindex)
+ == 0)
+ return 0;
+ } else if (family == AF_INET6) {
+ for (ALL_LIST_ELEMENTS_RO(new->nexthops6, node, nexthop6))
+ if (nexthop6lookup(old->nexthops6, &nexthop6->ip6,
+ nexthop6->ifindex)
+ == 0)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS_RO(old->nexthops6, node, nexthop6))
+ if (nexthop6lookup(new->nexthops6, &nexthop6->ip6,
+ nexthop6->ifindex)
+ == 0)
+ return 0;
+ }
- return 1;
+ return 1;
}
-static int
-isis_route_info_same (struct isis_route_info *new,
- struct isis_route_info *old, u_char family)
+struct isis_route_info *isis_route_create(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
+ uint32_t cost,
+ uint32_t depth,
+ struct list *adjacencies,
+ struct isis_area *area,
+ struct route_table *table)
{
- struct listnode *node;
- struct isis_nexthop *nexthop;
- struct isis_nexthop6 *nexthop6;
-
- 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))
- return 0;
-
- if (family == AF_INET)
- {
- for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
- if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
- == 0)
- return 0;
-
- for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
- if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
- == 0)
- return 0;
- }
- else if (family == AF_INET6)
- {
- for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
- if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
- nexthop6->ifindex) == 0)
- return 0;
-
- for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
- if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
- nexthop6->ifindex) == 0)
- return 0;
- }
-
- return 1;
-}
+ struct route_node *route_node;
+ struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
+ char buff[PREFIX2STR_BUFFER];
+ uint8_t family;
+
+ family = prefix->family;
+ /* for debugs */
+ prefix2str(prefix, buff, sizeof(buff));
+
+ if (!table)
+ return NULL;
+
+ rinfo_new = isis_route_info_new(prefix, src_p, cost,
+ depth, adjacencies);
+ route_node = srcdest_rnode_get(table, prefix, src_p);
+
+ rinfo_old = route_node->info;
+ if (!rinfo_old) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug("ISIS-Rte (%s) route created: %s",
+ area->area_tag, buff);
+ route_info = rinfo_new;
+ UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+ } else {
+ route_unlock_node(route_node);
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug("ISIS-Rte (%s) route already exists: %s",
+ area->area_tag, buff);
+ if (isis_route_info_same(rinfo_new, rinfo_old, family)) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug("ISIS-Rte (%s) route unchanged: %s",
+ area->area_tag, buff);
+ isis_route_info_delete(rinfo_new);
+ route_info = rinfo_old;
+ } else {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug("ISIS-Rte (%s) route changed: %s",
+ area->area_tag, buff);
+ isis_route_info_delete(rinfo_old);
+ route_info = rinfo_new;
+ UNSET_FLAG(route_info->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+ }
+ }
-struct isis_route_info *
-isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
- struct list *adjacencies, struct isis_area *area,
- int level)
-{
- struct route_node *route_node;
- struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
- char buff[PREFIX2STR_BUFFER];
- u_char family;
-
- family = prefix->family;
- /* for debugs */
- prefix2str (prefix, buff, sizeof (buff));
-
- rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies);
-
- if (family == AF_INET)
- route_node = route_node_get (area->route_table[level - 1], prefix);
- else if (family == AF_INET6)
- route_node = route_node_get (area->route_table6[level - 1], prefix);
- else
- {
- isis_route_info_delete (rinfo_new);
- return NULL;
- }
-
- rinfo_old = route_node->info;
- if (!rinfo_old)
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
- route_info = rinfo_new;
- UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
- }
- else
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
- buff);
- if (isis_route_info_same (rinfo_new, rinfo_old, family))
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag,
- buff);
- isis_route_info_delete (rinfo_new);
- route_info = rinfo_old;
- }
- else
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
- buff);
- isis_route_info_delete (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);
- route_node->info = route_info;
-
- return route_info;
+ SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ route_node->info = route_info;
+
+ return route_info;
}
-static void
-isis_route_delete (struct prefix *prefix, struct route_table *table)
+static void isis_route_delete(struct route_node *rode,
+ struct route_table *table)
{
- struct route_node *rode;
- struct isis_route_info *rinfo;
- char buff[PREFIX2STR_BUFFER];
-
- /* for log */
- prefix2str (prefix, buff, sizeof (buff));
-
-
- rode = route_node_get (table, prefix);
- rinfo = rode->info;
-
- if (rinfo == NULL)
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
- return;
- }
-
- if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
- {
- UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte: route delete %s", buff);
- isis_zebra_route_update (prefix, rinfo);
- }
- isis_route_info_delete (rinfo);
- rode->info = NULL;
-
- return;
+ struct isis_route_info *rinfo;
+ char buff[SRCDEST2STR_BUFFER];
+ struct prefix *prefix;
+ struct prefix_ipv6 *src_p;
+
+ /* for log */
+ srcdest_rnode2str(rode, buff, sizeof(buff));
+
+ srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
+ (const struct prefix **)&src_p);
+
+ rinfo = rode->info;
+ if (rinfo == NULL) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug(
+ "ISIS-Rte: tried to delete non-existant route %s",
+ buff);
+ return;
+ }
+
+ if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
+ UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug("ISIS-Rte: route delete %s", buff);
+ isis_zebra_route_update(prefix, src_p, rinfo);
+ }
+ isis_route_info_delete(rinfo);
+ rode->info = NULL;
+ route_unlock_node(rode);
}
-/* Validating routes in particular table. */
-static void
-isis_route_validate_table (struct isis_area *area, struct route_table *table)
+static void _isis_route_verify_table(struct isis_area *area,
+ struct route_table *table,
+ struct route_table **tables)
{
- struct route_node *rnode, *drnode;
- struct isis_route_info *rinfo;
- char buff[PREFIX2STR_BUFFER];
-
- for (rnode = route_top (table); rnode; rnode = route_next (rnode))
- {
- if (rnode->info == NULL)
- continue;
- rinfo = rnode->info;
-
- if (isis->debugs & DEBUG_RTE_EVENTS)
- {
- prefix2str (&rnode->p, buff, sizeof (buff));
- zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s",
- area->area_tag,
- (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ?
- "synced" : "not-synced"),
- (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ?
- "resync" : "not-resync"),
- (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
- "active" : "inactive"), buff);
+ struct route_node *rnode, *drnode;
+ struct isis_route_info *rinfo;
+ char buff[SRCDEST2STR_BUFFER];
+
+ for (rnode = route_top(table); rnode;
+ rnode = srcdest_route_next(rnode)) {
+ if (rnode->info == NULL)
+ continue;
+ rinfo = rnode->info;
+
+ struct prefix *dst_p;
+ struct prefix_ipv6 *src_p;
+
+ srcdest_rnode_prefixes(rnode,
+ (const struct prefix **)&dst_p,
+ (const struct prefix **)&src_p);
+
+ if (isis->debugs & DEBUG_RTE_EVENTS) {
+ srcdest2str(dst_p, src_p, buff, sizeof(buff));
+ zlog_debug(
+ "ISIS-Rte (%s): route validate: %s %s %s %s",
+ area->area_tag,
+ (CHECK_FLAG(rinfo->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
+ ? "synced"
+ : "not-synced"),
+ (CHECK_FLAG(rinfo->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
+ ? "resync"
+ : "not-resync"),
+ (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
+ ? "active"
+ : "inactive"),
+ buff);
+ }
+
+ isis_zebra_route_update(dst_p, src_p, rinfo);
+
+ if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
+ continue;
+
+ /* Area is either L1 or L2 => we use level route tables
+ * directly for
+ * validating => no problems with deleting routes. */
+ if (!tables) {
+ isis_route_delete(rnode, table);
+ continue;
+ }
+
+ /* If area is L1L2, we work with merge table and
+ * therefore must
+ * delete node from level tables as well before deleting
+ * route info. */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ drnode = srcdest_rnode_lookup(tables[level - 1],
+ dst_p, src_p);
+ if (!drnode)
+ continue;
+
+ route_unlock_node(drnode);
+
+ if (drnode->info != rnode->info)
+ continue;
+
+ drnode->info = NULL;
+ route_unlock_node(drnode);
+ }
+
+ isis_route_delete(rnode, table);
}
+}
- isis_zebra_route_update (&rnode->p, rinfo);
- if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
- {
- /* Area is either L1 or L2 => we use level route tables directly for
- * validating => no problems with deleting routes. */
- if (area->is_type != IS_LEVEL_1_AND_2)
- {
- isis_route_delete (&rnode->p, table);
- continue;
- }
- /* If area is L1L2, we work with merge table and therefore must
- * delete node from level tables as well before deleting route info.
- * FIXME: Is it performance problem? There has to be the better way.
- * Like not to deal with it here at all (see the next comment)? */
- if (rnode->p.family == AF_INET)
- {
- drnode = route_node_get (area->route_table[0], &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- drnode = route_node_get (area->route_table[1], &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- }
-
- if (rnode->p.family == AF_INET6)
- {
- drnode = route_node_get (area->route_table6[0], &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- drnode = route_node_get (area->route_table6[1], &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- }
-
- isis_route_delete (&rnode->p, table);
- }
- }
+void isis_route_verify_table(struct isis_area *area, struct route_table *table)
+{
+ _isis_route_verify_table(area, table, NULL);
}
/* Function to validate route tables for L1L2 areas. In this case we can't use
*
* FIXME: Is it right place to do it at all? Maybe we should push both levels
* to the RIB with different zebra route types and let RIB handle this? */
-static void
-isis_route_validate_merge (struct isis_area *area, int family)
-{
- struct route_table *table = NULL;
- struct route_table *merge;
- struct route_node *rnode, *mrnode;
-
- merge = route_table_init ();
-
- if (family == AF_INET)
- table = area->route_table[0];
- else if (family == AF_INET6)
- table = area->route_table6[0];
- else
- {
- zlog_warn ("ISIS-Rte (%s) %s called for unknown family %d",
- area->area_tag, __func__, family);
- route_table_finish(merge);
- return;
- }
-
- for (rnode = route_top (table); rnode; rnode = route_next (rnode))
- {
- if (rnode->info == NULL)
- continue;
- mrnode = route_node_get (merge, &rnode->p);
- mrnode->info = rnode->info;
- }
-
- if (family == AF_INET)
- table = area->route_table[1];
- else if (family == AF_INET6)
- table = area->route_table6[1];
-
- for (rnode = route_top (table); rnode; rnode = route_next (rnode))
- {
- if (rnode->info == NULL)
- continue;
- mrnode = route_node_get (merge, &rnode->p);
- if (mrnode->info != NULL)
- continue;
- mrnode->info = rnode->info;
- }
-
- isis_route_validate_table (area, merge);
- route_table_finish (merge);
-}
-
-/* Walk through route tables and propagate necessary changes into RIB. In case
- * of L1L2 area, level tables have to be merged at first. */
-void
-isis_route_validate (struct isis_area *area)
+void isis_route_verify_merge(struct isis_area *area,
+ struct route_table *level1_table,
+ struct route_table *level2_table)
{
- struct listnode *node;
- struct isis_circuit *circuit;
-
- if (area->is_type == IS_LEVEL_1)
- isis_route_validate_table (area, area->route_table[0]);
- else if (area->is_type == IS_LEVEL_2)
- isis_route_validate_table (area, area->route_table[1]);
- else
- isis_route_validate_merge (area, AF_INET);
-
- 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);
-
- if (!area->circuit_list) {
- return;
- }
- /* 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;
-}
+ struct route_table *tables[] = { level1_table, level2_table };
+ struct route_table *merge;
+ struct route_node *rnode, *mrnode;
+
+ merge = srcdest_table_init();
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ for (rnode = route_top(tables[level - 1]); rnode;
+ rnode = srcdest_route_next(rnode)) {
+ struct isis_route_info *rinfo = rnode->info;
+ if (!rinfo)
+ continue;
+
+ struct prefix *prefix;
+ struct prefix_ipv6 *src_p;
+
+ srcdest_rnode_prefixes(rnode,
+ (const struct prefix **)&prefix,
+ (const struct prefix **)&src_p);
+ mrnode = srcdest_rnode_get(merge, prefix, src_p);
+ struct isis_route_info *mrinfo = mrnode->info;
+ if (mrinfo) {
+ route_unlock_node(mrnode);
+ if (CHECK_FLAG(mrinfo->flag,
+ ISIS_ROUTE_FLAG_ACTIVE)) {
+ /* Clear the ZEBRA_SYNCED flag on the
+ * L2 route when L1 wins, otherwise L2
+ * won't get reinstalled when L1
+ * disappears.
+ */
+ UNSET_FLAG(
+ rinfo->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_SYNCED
+ );
+ continue;
+ } else {
+ /* Clear the ZEBRA_SYNCED flag on the L1
+ * route when L2 wins, otherwise L1
+ * won't get reinstalled when it
+ * reappears.
+ */
+ UNSET_FLAG(
+ mrinfo->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_SYNCED
+ );
+ }
+ }
+ mrnode->info = rnode->info;
+ }
+ }
-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))
- {
- if (rode->info == NULL)
- continue;
- rinfo = rode->info;
-
- UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
- }
+ _isis_route_verify_table(area, merge, tables);
+ route_table_finish(merge);
}
-void
-isis_route_invalidate (struct isis_area *area)
+void isis_route_invalidate_table(struct isis_area *area,
+ struct route_table *table)
{
- 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]);
+ struct route_node *rode;
+ struct isis_route_info *rinfo;
+ for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
+ if (rode->info == NULL)
+ continue;
+ rinfo = rode->info;
+
+ UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ }
}