]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2803 from opensourcerouting/pimd-nbr-uninit-warning
authorRuss White <russ@riw.us>
Wed, 8 Aug 2018 10:35:15 +0000 (06:35 -0400)
committerGitHub <noreply@github.com>
Wed, 8 Aug 2018 10:35:15 +0000 (06:35 -0400)
pimd: fix bogus uninitialized warning

21 files changed:
isisd/isis_lsp.c
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_pdu.c
isisd/isis_redist.c
isisd/isis_redist.h
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_zebra.c
isisd/isis_zebra.h
isisd/isisd.c
isisd/isisd.h
lib/srcdest_table.c
lib/srcdest_table.h
lib/zebra.h
tests/isisd/test_fuzz_isis_tlv_tests.h.gz
tests/isisd/test_isis_vertex_queue.c

index c8ef829064b54bfa268ee21a284f49a8fec8f5c2..37651163f58b48cc1cfa20abeaca891fc507334d 100644 (file)
@@ -37,6 +37,7 @@
 #include "checksum.h"
 #include "md5.h"
 #include "table.h"
+#include "srcdest_table.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -765,18 +766,28 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
                return;
 
        for (struct route_node *rn = route_top(er_table); rn;
-            rn = route_next(rn)) {
+            rn = srcdest_route_next(rn)) {
                if (!rn->info)
                        continue;
-
-               struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p;
                struct isis_ext_info *info = rn->info;
 
+               struct prefix_ipv6 *p, *src_p;
+               srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
+                                      (const struct prefix **)&src_p);
+
                uint32_t metric = info->metric;
                if (info->metric > MAX_WIDE_PATH_METRIC)
                        metric = MAX_WIDE_PATH_METRIC;
-               isis_tlvs_add_ipv6_reach(
-                       lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric);
+
+               if (!src_p || !src_p->prefixlen) {
+                       isis_tlvs_add_ipv6_reach(lsp->tlvs,
+                                                isis_area_ipv6_topology(area),
+                                                p, metric);
+               } else if (isis_area_ipv6_dstsrc_enabled(area)) {
+                       isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs,
+                                                       ISIS_MT_IPV6_DSTSRC,
+                                                       p, src_p, metric);
+               }
        }
 }
 
index d13f2a13f314ddb15a9a05566b9e88cb5c3192a9..2155bf584ec13d78aebd0d0d9401a365c3059093 100644 (file)
@@ -33,6 +33,14 @@ DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
 
+bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area)
+{
+       struct isis_area_mt_setting *area_mt_setting;
+       area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_DSTSRC);
+
+       return (area_mt_setting && area_mt_setting->enabled);
+}
+
 uint16_t isis_area_ipv6_topology(struct isis_area *area)
 {
        struct isis_area_mt_setting *area_mt_setting;
@@ -61,6 +69,8 @@ const char *isis_mtid2str(uint16_t mtid)
                return "ipv6-multicast";
        case ISIS_MT_IPV6_MGMT:
                return "ipv6-mgmt";
+       case ISIS_MT_IPV6_DSTSRC:
+               return "ipv6-dstsrc";
        default:
                snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
                return buf;
@@ -81,6 +91,8 @@ uint16_t isis_str2mtid(const char *name)
                return ISIS_MT_IPV6_MULTICAST;
        if (!strcmp(name, "ipv6-mgmt"))
                return ISIS_MT_IPV6_MGMT;
+       if (!strcmp(name, "ipv6-dstsrc"))
+               return ISIS_MT_IPV6_DSTSRC;
        return -1;
 }
 
index 95aa99dba0bd6be1b87be4bb9028020b24512e70..8c57d24afa4dae95fca6c9afaed6dae0869e677b 100644 (file)
@@ -32,6 +32,7 @@
 #define ISIS_MT_IPV4_MULTICAST 3
 #define ISIS_MT_IPV6_MULTICAST 4
 #define ISIS_MT_IPV6_MGMT      5
+#define ISIS_MT_IPV6_DSTSRC    3996 /* FIXME: IANA */
 
 #define ISIS_MT_NAMES                                                          \
        "<ipv4-unicast"                                                        \
@@ -40,6 +41,7 @@
        "|ipv4-multicast"                                                      \
        "|ipv6-multicast"                                                      \
        "|ipv6-mgmt"                                                           \
+       "|ipv6-dstsrc"                                                         \
        ">"
 
 #define ISIS_MT_DESCRIPTIONS                                                   \
@@ -48,7 +50,9 @@
        "IPv6 unicast topology\n"                                              \
        "IPv4 multicast topology\n"                                            \
        "IPv6 multicast topology\n"                                            \
-       "IPv6 management topology\n"
+       "IPv6 management topology\n"                                           \
+       "IPv6 dst-src topology\n"                                              \
+       ""
 
 #define ISIS_MT_INFO_FIELDS uint16_t mtid;
 
@@ -75,6 +79,8 @@ struct tlvs;
 struct te_is_neigh;
 struct isis_tlvs;
 
+bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area);
+
 uint16_t isis_area_ipv6_topology(struct isis_area *area);
 
 struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area,
index 7a6c4dd2dc105d67b1d5e3ce28a8f83ac8e08784..8e2a7f13a5cb2eb01cb9460b13bb2aa747490219 100644 (file)
@@ -673,8 +673,15 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
        iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link)
                         && iih.tlvs->ipv6_address.count);
 
-       if (!iih.v4_usable && !iih.v6_usable)
+       if (!iih.v4_usable && !iih.v6_usable) {
+               if (isis->debugs & DEBUG_ADJ_PACKETS) {
+                       zlog_warn(
+                               "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH",
+                               circuit->area->area_tag);
+               }
+
                goto out;
+       }
 
        retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih);
 out:
index e903dc8c7fea87d8dfd97c676b7c57e480f7f8d9..cd3ca44379c35aaeff9fbd98b1d8d2377277a073 100644 (file)
@@ -30,6 +30,7 @@
 #include "stream.h"
 #include "table.h"
 #include "vty.h"
+#include "srcdest_table.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -86,33 +87,13 @@ struct route_table *get_ext_reach(struct isis_area *area, int family, int level)
        return area->ext_reach[protocol][level - 1];
 }
 
-static struct route_node *
-isis_redist_route_node_create(route_table_delegate_t *delegate,
-                             struct route_table *table)
-{
-       struct route_node *node;
-       node = XCALLOC(MTYPE_ISIS_EXT_ROUTE, sizeof(*node));
-       return node;
-}
-
-static void isis_redist_route_node_destroy(route_table_delegate_t *delegate,
-                                          struct route_table *table,
-                                          struct route_node *node)
-{
-       if (node->info)
-               XFREE(MTYPE_ISIS_EXT_INFO, node->info);
-       XFREE(MTYPE_ISIS_EXT_ROUTE, node);
-}
-
-static route_table_delegate_t isis_redist_rt_delegate = {
-       .create_node = isis_redist_route_node_create,
-       .destroy_node = isis_redist_route_node_destroy};
-
 /* Install external reachability information into a
  * specific area for a specific level.
  * Schedule an lsp regenerate if necessary */
 static void isis_redist_install(struct isis_area *area, int level,
-                               struct prefix *p, struct isis_ext_info *info)
+                               const struct prefix *p,
+                               const struct prefix_ipv6 *src_p,
+                               struct isis_ext_info *info)
 {
        int family = p->family;
        struct route_table *er_table = get_ext_reach(area, family, level);
@@ -126,7 +107,7 @@ static void isis_redist_install(struct isis_area *area, int level,
                return;
        }
 
-       er_node = route_node_get(er_table, p);
+       er_node = srcdest_rnode_get(er_table, p, src_p);
        if (er_node->info) {
                route_unlock_node(er_node);
 
@@ -145,7 +126,8 @@ static void isis_redist_install(struct isis_area *area, int level,
  * specific area for a specific level.
  * Schedule an lsp regenerate if necessary. */
 static void isis_redist_uninstall(struct isis_area *area, int level,
-                                 struct prefix *p)
+                                 const struct prefix *p,
+                                 const struct prefix_ipv6 *src_p)
 {
        int family = p->family;
        struct route_table *er_table = get_ext_reach(area, family, level);
@@ -159,7 +141,7 @@ static void isis_redist_uninstall(struct isis_area *area, int level,
                return;
        }
 
-       er_node = route_node_lookup(er_table, p);
+       er_node = srcdest_rnode_lookup(er_table, p, src_p);
        if (!er_node)
                return;
        else
@@ -177,7 +159,8 @@ static void isis_redist_uninstall(struct isis_area *area, int level,
  * and prefix, using the given redistribution settings. */
 static void isis_redist_update_ext_reach(struct isis_area *area, int level,
                                         struct isis_redist *redist,
-                                        struct prefix *p,
+                                        const struct prefix *p,
+                                        const struct prefix_ipv6 *src_p,
                                         struct isis_ext_info *info)
 {
        struct isis_ext_info area_info;
@@ -188,7 +171,8 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level,
 
        if (redist->map_name) {
                map_ret =
-                       route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
+                       route_map_apply(redist->map, (struct prefix *)p,
+                                       RMAP_ISIS, &area_info);
                if (map_ret == RMAP_DENYMATCH)
                        area_info.distance = 255;
        }
@@ -199,9 +183,9 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level,
                area_info.distance = 255;
 
        if (area_info.distance < 255)
-               isis_redist_install(area, level, p, &area_info);
+               isis_redist_install(area, level, p, src_p, &area_info);
        else
-               isis_redist_uninstall(area, level, p);
+               isis_redist_uninstall(area, level, p, src_p);
 }
 
 static void isis_redist_ensure_default(struct isis *isis, int family)
@@ -222,7 +206,7 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
        } else
                assert(!"Unknown family!");
 
-       ei_node = route_node_get(ei_table, &p);
+       ei_node = srcdest_rnode_get(ei_table, &p, NULL);
        if (ei_node->info) {
                route_unlock_node(ei_node);
                return;
@@ -238,8 +222,8 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
 }
 
 /* Handle notification about route being added */
-void isis_redist_add(int type, struct prefix *p, uint8_t distance,
-                    uint32_t metric)
+void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
+                    uint8_t distance, uint32_t metric)
 {
        int family = p->family;
        struct route_table *ei_table = get_ext_info(isis, family);
@@ -262,7 +246,7 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
                return;
        }
 
-       ei_node = route_node_get(ei_table, p);
+       ei_node = srcdest_rnode_get(ei_table, p, src_p);
        if (ei_node->info)
                route_unlock_node(ei_node);
        else
@@ -274,8 +258,10 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
        info->distance = distance;
        info->metric = metric;
 
-       if (is_default_prefix(p))
+       if (is_default_prefix(p)
+           && (!src_p || !src_p->prefixlen)) {
                type = DEFAULT_ROUTE;
+       }
 
        for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
                for (level = 1; level <= ISIS_LEVELS; level++) {
@@ -284,11 +270,11 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
                                continue;
 
                        isis_redist_update_ext_reach(area, level, redist, p,
-                                                    info);
+                                                    src_p, info);
                }
 }
 
-void isis_redist_delete(int type, struct prefix *p)
+void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p)
 {
        int family = p->family;
        struct route_table *ei_table = get_ext_info(isis, family);
@@ -304,12 +290,14 @@ void isis_redist_delete(int type, struct prefix *p)
        zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
                   zebra_route_string(type));
 
-       if (is_default_prefix(p)) {
+       if (is_default_prefix(p)
+           && (!src_p || !src_p->prefixlen)) {
                /* Don't remove default route but add synthetic route for use
                 * by "default-information originate always". Areas without the
                 * "always" setting will ignore routes with origin
                 * DEFAULT_ROUTE. */
-               isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC);
+               isis_redist_add(DEFAULT_ROUTE, p, NULL,
+                               254, MAX_WIDE_PATH_METRIC);
                return;
        }
 
@@ -319,7 +307,7 @@ void isis_redist_delete(int type, struct prefix *p)
                return;
        }
 
-       ei_node = route_node_lookup(ei_table, p);
+       ei_node = srcdest_rnode_lookup(ei_table, p, src_p);
        if (!ei_node || !ei_node->info) {
                char buf[BUFSIZ];
                prefix2str(p, buf, sizeof(buf));
@@ -334,12 +322,12 @@ void isis_redist_delete(int type, struct prefix *p)
        route_unlock_node(ei_node);
 
        for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
-               for (level = 1; level < ISIS_LEVELS; level++) {
+               for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
                        redist = get_redist_settings(area, family, type, level);
                        if (!redist->redist)
                                continue;
 
-                       isis_redist_uninstall(area, level, p);
+                       isis_redist_uninstall(area, level, p, src_p);
                }
 
        XFREE(MTYPE_ISIS_EXT_INFO, ei_node->info);
@@ -418,17 +406,14 @@ static void isis_redist_set(struct isis_area *area, int level, int family,
        isis_redist_routemap_set(redist, routemap);
 
        if (!area->ext_reach[protocol][level - 1]) {
-               area->ext_reach[protocol][level - 1] =
-                       route_table_init_with_delegate(
-                               &isis_redist_rt_delegate);
+               area->ext_reach[protocol][level - 1] = srcdest_table_init();
        }
 
-       for (i = 0; i < REDIST_PROTOCOL_COUNT; i++)
+       for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) {
                if (!area->isis->ext_info[i]) {
-                       area->isis->ext_info[i] =
-                               route_table_init_with_delegate(
-                                       &isis_redist_rt_delegate);
+                       area->isis->ext_info[i] = srcdest_table_init();
                }
+       }
 
        isis_redist_update_zebra_subscriptions(area->isis);
 
@@ -436,20 +421,27 @@ static void isis_redist_set(struct isis_area *area, int level, int family,
                isis_redist_ensure_default(area->isis, family);
 
        ei_table = get_ext_info(area->isis, family);
-       for (rn = route_top(ei_table); rn; rn = route_next(rn)) {
+       for (rn = route_top(ei_table); rn; rn = srcdest_route_next(rn)) {
                if (!rn->info)
                        continue;
                info = rn->info;
 
+               const struct prefix *p, *src_p;
+
+               srcdest_rnode_prefixes(rn, &p, &src_p);
+
                if (type == DEFAULT_ROUTE) {
-                       if (!is_default_prefix(&rn->p))
+                       if (!is_default_prefix(p)
+                           || (src_p && src_p->prefixlen)) {
                                continue;
+                       }
                } else {
                        if (info->origin != type)
                                continue;
                }
 
-               isis_redist_update_ext_reach(area, level, redist, &rn->p, info);
+               isis_redist_update_ext_reach(area, level, redist, p,
+                                            (struct prefix_ipv6 *)src_p, info);
        }
 }
 
@@ -472,14 +464,19 @@ static void isis_redist_unset(struct isis_area *area, int level, int family,
                return;
        }
 
-       for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+       for (rn = route_top(er_table); rn; rn = srcdest_route_next(rn)) {
                if (!rn->info)
                        continue;
                info = rn->info;
 
+               const struct prefix *p, *src_p;
+               srcdest_rnode_prefixes(rn, &p, &src_p);
+
                if (type == DEFAULT_ROUTE) {
-                       if (!is_default_prefix(&rn->p))
+                       if (!is_default_prefix(p)
+                           || (src_p && src_p->prefixlen)) {
                                continue;
+                       }
                } else {
                        if (info->origin != type)
                                continue;
index c12363d5089ae6454b26795f29ac5805254642b1..95f06f71ec9a343f88e71e4fa4f88867d77797f9 100644 (file)
@@ -42,13 +42,14 @@ struct isis_redist {
 
 struct isis_area;
 struct prefix;
+struct prefix_ipv6;
 struct vty;
 
 struct route_table *get_ext_reach(struct isis_area *area, int family,
                                  int level);
-void isis_redist_add(int type, struct prefix *p, uint8_t distance,
-                    uint32_t metric);
-void isis_redist_delete(int type, struct prefix *p);
+void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
+                    uint8_t distance, uint32_t metric);
+void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p);
 int isis_redist_config_write(struct vty *vty, struct isis_area *area,
                             int family);
 void isis_redist_init(void);
index c98e16e2bdb40af92b14128d487cce7dfb42741d..b1225ae5474c90389539d442a3454cb407bc347d 100644 (file)
@@ -33,6 +33,7 @@
 #include "hash.h"
 #include "if.h"
 #include "table.h"
+#include "srcdest_table.h"
 
 #include "isis_constants.h"
 #include "isis_common.h"
@@ -199,6 +200,7 @@ static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
 }
 
 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)
@@ -232,8 +234,10 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
                                SET_FLAG(rinfo->flag,
                                         ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
                        /* update neighbor router address */
-                       if (depth == 2 && prefix->prefixlen == 128)
+                       if (depth == 2 && prefix->prefixlen == 128
+                           && (!src_p || !src_p->prefixlen)) {
                                adj->router_address6 = prefix->u.prefix6;
+                       }
                        adjinfo2nexthop6(rinfo->nexthops6, adj);
                }
        }
@@ -317,10 +321,13 @@ static int isis_route_info_same(struct isis_route_info *new,
        return 1;
 }
 
-struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
+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, int level)
+                                         struct isis_area *area,
+                                         struct route_table *table)
 {
        struct route_node *route_node;
        struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
@@ -331,18 +338,12 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
        /* 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);
+       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) {
@@ -352,6 +353,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
                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);
@@ -378,19 +380,21 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
        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];
+       char buff[SRCDEST2STR_BUFFER];
+       struct prefix *prefix;
+       struct prefix_ipv6 *src_p;
 
        /* for log */
-       prefix2str(prefix, buff, sizeof(buff));
+       srcdest_rnode2str(rode, buff, sizeof(buff));
 
+       srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
+                              (const struct prefix **)&src_p);
 
-       rode = route_node_get(table, prefix);
        rinfo = rode->info;
-
        if (rinfo == NULL) {
                if (isis->debugs & DEBUG_RTE_EVENTS)
                        zlog_debug(
@@ -403,29 +407,36 @@ static void isis_route_delete(struct prefix *prefix, struct route_table *table)
                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_zebra_route_update(prefix, src_p, rinfo);
        }
        isis_route_info_delete(rinfo);
        rode->info = NULL;
-
-       return;
+       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];
+       char buff[SRCDEST2STR_BUFFER];
 
-       for (rnode = route_top(table); rnode; rnode = route_next(rnode)) {
+       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) {
-                       prefix2str(&rnode->p, buff, sizeof(buff));
+                       srcdest2str(dst_p, src_p, buff, sizeof(buff));
                        zlog_debug(
                                "ISIS-Rte (%s): route validate: %s %s %s %s",
                                area->area_tag,
@@ -443,50 +454,47 @@ static void isis_route_validate_table(struct isis_area *area,
                                buff);
                }
 
-               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);
+               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;
-                       }
-                       /* 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;
-                       }
+                       route_unlock_node(drnode);
+
+                       if (drnode->info != rnode->info)
+                               continue;
 
-                       isis_route_delete(&rnode->p, table);
+                       drnode->info = NULL;
+                       route_unlock_node(drnode);
                }
+
+               isis_route_delete(rnode, table);
        }
 }
 
+void isis_route_verify_table(struct isis_area *area, struct route_table *table)
+{
+       return _isis_route_verify_table(area, table, NULL);
+}
+
 /* Function to validate route tables for L1L2 areas. In this case we can't use
  * level route tables directly, we have to merge them at first. L1 routes are
  * preferred over the L2 ones.
@@ -497,87 +505,71 @@ static void isis_route_validate_table(struct isis_area *area,
  *
  * 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)
+void isis_route_verify_merge(struct isis_area *area,
+                            struct route_table *level1_table,
+                            struct route_table *level2_table)
 {
-       struct route_table *table = NULL;
+       struct route_table *tables[] = { level1_table, level2_table };
        struct route_table *merge;
        struct route_node *rnode, *mrnode;
 
-       merge = route_table_init();
+       merge = srcdest_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 (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;
 
-       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;
+                       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;
+               }
        }
 
-       isis_route_validate_table(area, merge);
+       _isis_route_verify_table(area, merge, tables);
        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)
-{
-       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;
-}
-
 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)) {
+       for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
                if (rode->info == NULL)
                        continue;
                rinfo = rode->info;
@@ -585,11 +577,3 @@ void isis_route_invalidate_table(struct isis_area *area,
                UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
        }
 }
-
-void isis_route_invalidate(struct isis_area *area)
-{
-       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]);
-}
index 82f37c29f23b41fe96f89db68da7d847475143cd..9d6858586be5d696be2cc4f045fbbfc0b17a52d9 100644 (file)
@@ -50,14 +50,26 @@ struct isis_route_info {
        struct list *nexthops6;
 };
 
-struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
+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, int level);
+                                         struct isis_area *area,
+                                         struct route_table *table);
 
-void isis_route_validate(struct isis_area *area);
+/* Walk the given table and install new routes to zebra and remove old ones.
+ * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
+void isis_route_verify_table(struct isis_area *area,
+                            struct route_table *table);
+
+/* Same as isis_route_verify_table, but merge L1 and L2 routes before */
+void isis_route_verify_merge(struct isis_area *area,
+                            struct route_table *level1_table,
+                            struct route_table *level2_table);
+
+/* Unset ISIS_ROUTE_FLAG_ACTIVE on all routes. Used before running spf. */
 void isis_route_invalidate_table(struct isis_area *area,
                                 struct route_table *table);
-void isis_route_invalidate(struct isis_area *area);
 
 #endif /* _ZEBRA_ISIS_ROUTE_H */
index 556f2890cfbc22caee61a27ed0783f72bb3e799c..0a8b0e927e5a0f34322aa21e81b54e5314b44dca 100644 (file)
@@ -37,6 +37,7 @@
 #include "spf_backoff.h"
 #include "jhash.h"
 #include "skiplist.h"
+#include "srcdest_table.h"
 
 #include "isis_constants.h"
 #include "isis_common.h"
@@ -74,12 +75,17 @@ enum vertextype {
 #define VTYPE_ES(t) ((t) == VTYPE_ES)
 #define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
 
+struct prefix_pair {
+       struct prefix dest;
+       struct prefix_ipv6 src;
+};
+
 /*
  * Triple <N, d(N), {Adj(N)}>
  */
 union isis_N {
        uint8_t id[ISIS_SYS_ID_LEN + 1];
-       struct prefix prefix;
+       struct prefix_pair ip;
 };
 struct isis_vertex {
        enum vertextype type;
@@ -106,8 +112,13 @@ static unsigned isis_vertex_queue_hash_key(void *vp)
 {
        struct isis_vertex *vertex = vp;
 
-       if (VTYPE_IP(vertex->type))
-               return prefix_hash_key(&vertex->N.prefix);
+       if (VTYPE_IP(vertex->type)) {
+               uint32_t key;
+
+               key = prefix_hash_key(&vertex->N.ip.dest);
+               key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key);
+               return key;
+       }
 
        return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
 }
@@ -119,8 +130,13 @@ static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
        if (va->type != vb->type)
                return 0;
 
-       if (VTYPE_IP(va->type))
-               return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0;
+       if (VTYPE_IP(va->type)) {
+               if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest))
+                       return 0;
+
+               return prefix_cmp((struct prefix *)&va->N.ip.src,
+                                 (struct prefix *)&vb->N.ip.src) == 0;
+       }
 
        return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
 }
@@ -275,6 +291,7 @@ static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
 struct isis_spftree {
        struct isis_vertex_queue paths; /* the SPT */
        struct isis_vertex_queue tents; /* TENT */
+       struct route_table *route_table;
        struct isis_area *area;    /* back pointer to area */
        unsigned int runcount;     /* number of runs since uptime */
        time_t last_run_timestamp; /* last run timestamp as wall time for display */
@@ -284,6 +301,7 @@ struct isis_spftree {
        uint16_t mtid;
        int family;
        int level;
+       enum spf_tree_id tree_id;
 };
 
 
@@ -392,6 +410,7 @@ static const char *vtype2string(enum vertextype vtype)
        return NULL; /* Not reached */
 }
 
+#define VID2STR_BUFFER SRCDEST2STR_BUFFER
 static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
 {
        if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
@@ -399,7 +418,9 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
        }
 
        if (VTYPE_IP(vertex->type)) {
-               prefix2str((struct prefix *)&vertex->N.prefix, buff, size);
+               srcdest2str(&vertex->N.ip.dest,
+                           &vertex->N.ip.src,
+                           buff, size);
                return buff;
        }
 
@@ -414,7 +435,7 @@ static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
        if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
                memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1);
        } else if (VTYPE_IP(vtype)) {
-               memcpy(&vertex->N.prefix, &n->prefix, sizeof(struct prefix));
+               memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip));
        } else {
                zlog_err("WTF!");
        }
@@ -472,6 +493,7 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
 
        isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
        isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
+       tree->route_table = srcdest_table_init();
        tree->area = area;
        tree->last_run_timestamp = 0;
        tree->last_run_monotime = 0;
@@ -484,8 +506,10 @@ void isis_spftree_del(struct isis_spftree *spftree)
 {
        isis_vertex_queue_free(&spftree->tents);
        isis_vertex_queue_free(&spftree->paths);
-       XFREE(MTYPE_ISIS_SPFTREE, spftree);
+       route_table_finish(spftree->route_table);
+       spftree->route_table = NULL;
 
+       XFREE(MTYPE_ISIS_SPFTREE, spftree);
        return;
 }
 
@@ -504,67 +528,44 @@ static void isis_spftree_adj_del(struct isis_spftree *spftree,
 
 void spftree_area_init(struct isis_area *area)
 {
-       if (area->is_type & IS_LEVEL_1) {
-               if (area->spftree[0] == NULL)
-                       area->spftree[0] = isis_spftree_new(area);
-               if (area->spftree6[0] == NULL)
-                       area->spftree6[0] = isis_spftree_new(area);
-       }
+       for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+               for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+                       if (!(area->is_type & level))
+                               continue;
+                       if (area->spftree[tree][level - 1])
+                               continue;
 
-       if (area->is_type & IS_LEVEL_2) {
-               if (area->spftree[1] == NULL)
-                       area->spftree[1] = isis_spftree_new(area);
-               if (area->spftree6[1] == NULL)
-                       area->spftree6[1] = isis_spftree_new(area);
+                       area->spftree[tree][level - 1] = isis_spftree_new(area);
+               }
        }
-
-       return;
 }
 
 void spftree_area_del(struct isis_area *area)
 {
-       if (area->is_type & IS_LEVEL_1) {
-               if (area->spftree[0] != NULL) {
-                       isis_spftree_del(area->spftree[0]);
-                       area->spftree[0] = NULL;
-               }
-               if (area->spftree6[0]) {
-                       isis_spftree_del(area->spftree6[0]);
-                       area->spftree6[0] = NULL;
-               }
-       }
+       for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+               for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+                       if (!(area->is_type & level))
+                               continue;
+                       if (!area->spftree[tree][level - 1])
+                               continue;
 
-       if (area->is_type & IS_LEVEL_2) {
-               if (area->spftree[1] != NULL) {
-                       isis_spftree_del(area->spftree[1]);
-                       area->spftree[1] = NULL;
-               }
-               if (area->spftree6[1] != NULL) {
-                       isis_spftree_del(area->spftree6[1]);
-                       area->spftree6[1] = NULL;
+                       isis_spftree_del(area->spftree[tree][level - 1]);
                }
        }
-
-       return;
 }
 
 void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
 {
-       if (area->is_type & IS_LEVEL_1) {
-               if (area->spftree[0] != NULL)
-                       isis_spftree_adj_del(area->spftree[0], adj);
-               if (area->spftree6[0] != NULL)
-                       isis_spftree_adj_del(area->spftree6[0], adj);
-       }
-
-       if (area->is_type & IS_LEVEL_2) {
-               if (area->spftree[1] != NULL)
-                       isis_spftree_adj_del(area->spftree[1], adj);
-               if (area->spftree6[1] != NULL)
-                       isis_spftree_adj_del(area->spftree6[1], adj);
+       for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+               for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+                       if (!(area->is_type & level))
+                               continue;
+                       if (!area->spftree[tree][level - 1])
+                               continue;
+                       isis_spftree_adj_del(area->spftree[tree][level - 1],
+                                            adj);
+               }
        }
-
-       return;
 }
 
 /*
@@ -595,7 +596,7 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
        struct isis_vertex *vertex;
        struct isis_lsp *lsp;
 #ifdef EXTREME_DEBUG
-       char buff[PREFIX2STR_BUFFER];
+       char buff[VID2STR_BUFFER];
 #endif /* EXTREME_DEBUG */
        union isis_N n;
 
@@ -646,7 +647,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
        struct listnode *node;
        struct isis_adjacency *parent_adj;
 #ifdef EXTREME_DEBUG
-       char buff[PREFIX2STR_BUFFER];
+       char buff[VID2STR_BUFFER];
 #endif
 
        assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL);
@@ -719,15 +720,16 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
 {
        struct isis_vertex *vertex;
 #ifdef EXTREME_DEBUG
-       char buff[PREFIX2STR_BUFFER];
+       char buff[VID2STR_BUFFER];
 #endif
 
        assert(spftree && parent);
 
-       struct prefix p;
+       struct prefix_pair p;
        if (vtype >= VTYPE_IPREACH_INTERNAL) {
-               prefix_copy(&p, id);
-               apply_mask(&p);
+               memcpy(&p, id, sizeof(p));
+               apply_mask(&p.dest);
+               apply_mask((struct prefix *)&p.src);
                id = &p;
        }
 
@@ -814,6 +816,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
        enum vertextype vtype;
        static const uint8_t null_sysid[ISIS_SYS_ID_LEN];
        struct isis_mt_router_info *mt_router_info = NULL;
+       struct prefix_pair ip_info;
 
        if (!lsp->tlvs)
                return ISIS_OK;
@@ -907,12 +910,17 @@ lspfragloop:
                        vtype = i ? VTYPE_IPREACH_EXTERNAL
                                  : VTYPE_IPREACH_INTERNAL;
 
+                       memset(&ip_info, 0, sizeof(ip_info));
+                       ip_info.dest.family = AF_INET;
+
                        struct isis_oldstyle_ip_reach *r;
                        for (r = (struct isis_oldstyle_ip_reach *)reachs[i]
                                         ->head;
                             r; r = r->next) {
                                dist = cost + r->metric;
-                               process_N(spftree, vtype, (void *)&r->prefix,
+                               ip_info.dest.u.prefix4 = r->prefix.prefix;
+                               ip_info.dest.prefixlen = r->prefix.prefixlen;
+                               process_N(spftree, vtype, &ip_info,
                                          dist, depth + 1, parent);
                        }
                }
@@ -926,6 +934,9 @@ lspfragloop:
                        ipv4_reachs = isis_lookup_mt_items(
                                &lsp->tlvs->mt_ip_reach, spftree->mtid);
 
+               memset(&ip_info, 0, sizeof(ip_info));
+               ip_info.dest.family = AF_INET;
+
                struct isis_extended_ip_reach *r;
                for (r = ipv4_reachs
                                 ? (struct isis_extended_ip_reach *)
@@ -933,7 +944,9 @@ lspfragloop:
                                 : NULL;
                     r; r = r->next) {
                        dist = cost + r->metric;
-                       process_N(spftree, VTYPE_IPREACH_TE, (void *)&r->prefix,
+                       ip_info.dest.u.prefix4 = r->prefix.prefix;
+                       ip_info.dest.prefixlen = r->prefix.prefixlen;
+                       process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
                                  dist, depth + 1, parent);
                }
        }
@@ -954,7 +967,28 @@ lspfragloop:
                        dist = cost + r->metric;
                        vtype = r->external ? VTYPE_IP6REACH_EXTERNAL
                                            : VTYPE_IP6REACH_INTERNAL;
-                       process_N(spftree, vtype, (void *)&r->prefix, dist,
+                       memset(&ip_info, 0, sizeof(ip_info));
+                       ip_info.dest.family = AF_INET6;
+                       ip_info.dest.u.prefix6 = r->prefix.prefix;
+                       ip_info.dest.prefixlen = r->prefix.prefixlen;
+
+                       if (r->subtlvs
+                           && r->subtlvs->source_prefix
+                           && r->subtlvs->source_prefix->prefixlen) {
+                               if (spftree->tree_id != SPFTREE_DSTSRC) {
+                                       char buff[VID2STR_BUFFER];
+                                       zlog_warn("Ignoring dest-src route %s in non dest-src topology",
+                                               srcdest2str(
+                                                       &ip_info.dest,
+                                                       r->subtlvs->source_prefix,
+                                                       buff, sizeof(buff)
+                                               )
+                                       );
+                                       continue;
+                               }
+                               ip_info.src = *r->subtlvs->source_prefix;
+                       }
+                       process_N(spftree, vtype, &ip_info, dist,
                                  depth + 1, parent);
                }
        }
@@ -983,7 +1017,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
        struct list *adj_list;
        struct list *adjdb;
        struct prefix_ipv4 *ipv4;
-       struct prefix prefix;
+       struct prefix_pair ip_info;
        int retval = ISIS_OK;
        uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
        static uint8_t null_lsp_id[ISIS_SYS_ID_LEN + 2];
@@ -1007,27 +1041,29 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                 * Add IP(v6) addresses of this circuit
                 */
                if (spftree->family == AF_INET) {
-                       prefix.family = AF_INET;
+                       memset(&ip_info, 0, sizeof(ip_info));
+                       ip_info.dest.family = AF_INET;
                        for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
                                                  ipv4)) {
-                               prefix.u.prefix4 = ipv4->prefix;
-                               prefix.prefixlen = ipv4->prefixlen;
-                               apply_mask(&prefix);
+                               ip_info.dest.u.prefix4 = ipv4->prefix;
+                               ip_info.dest.prefixlen = ipv4->prefixlen;
+                               apply_mask(&ip_info.dest);
                                isis_spf_add_local(spftree,
                                                   VTYPE_IPREACH_INTERNAL,
-                                                  &prefix, NULL, 0, parent);
+                                                  &ip_info, NULL, 0, parent);
                        }
                }
                if (spftree->family == AF_INET6) {
-                       prefix.family = AF_INET6;
+                       memset(&ip_info, 0, sizeof(ip_info));
+                       ip_info.dest.family = AF_INET6;
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
                                                  ipnode, ipv6)) {
-                               prefix.prefixlen = ipv6->prefixlen;
-                               prefix.u.prefix6 = ipv6->prefix;
-                               apply_mask(&prefix);
+                               ip_info.dest.u.prefix6 = ipv6->prefix;
+                               ip_info.dest.prefixlen = ipv6->prefixlen;
+                               apply_mask(&ip_info.dest);
                                isis_spf_add_local(spftree,
                                                   VTYPE_IP6REACH_INTERNAL,
-                                                  &prefix, NULL, 0, parent);
+                                                  &ip_info, NULL, 0, parent);
                        }
                }
                if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
@@ -1210,7 +1246,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
 static void add_to_paths(struct isis_spftree *spftree,
                         struct isis_vertex *vertex)
 {
-       char buff[PREFIX2STR_BUFFER];
+       char buff[VID2STR_BUFFER];
 
        if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
                return;
@@ -1225,10 +1261,11 @@ static void add_to_paths(struct isis_spftree *spftree,
 
        if (VTYPE_IP(vertex->type)) {
                if (listcount(vertex->Adj_N) > 0)
-                       isis_route_create((struct prefix *)&vertex->N.prefix,
+                       isis_route_create(&vertex->N.ip.dest,
+                                         &vertex->N.ip.src,
                                          vertex->d_N, vertex->depth,
                                          vertex->Adj_N, spftree->area,
-                                         spftree->level);
+                                         spftree->route_table);
                else if (isis->debugs & DEBUG_SPF_EVENTS)
                        zlog_debug(
                                "ISIS-Spf: no adjacencies do not install route for "
@@ -1241,7 +1278,7 @@ static void add_to_paths(struct isis_spftree *spftree,
 }
 
 static void init_spt(struct isis_spftree *spftree, int mtid, int level,
-                    int family)
+                    int family, enum spf_tree_id tree_id)
 {
        isis_vertex_queue_clear(&spftree->tents);
        isis_vertex_queue_clear(&spftree->paths);
@@ -1249,53 +1286,54 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level,
        spftree->mtid = mtid;
        spftree->level = level;
        spftree->family = family;
+       spftree->tree_id = tree_id;
        return;
 }
 
-static int isis_run_spf(struct isis_area *area, int level, int family,
+static int isis_run_spf(struct isis_area *area, int level,
+                       enum spf_tree_id tree_id,
                        uint8_t *sysid, struct timeval *nowtv)
 {
        int retval = ISIS_OK;
        struct isis_vertex *vertex;
        struct isis_vertex *root_vertex;
-       struct isis_spftree *spftree = NULL;
+       struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
        uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
        struct isis_lsp *lsp;
-       struct route_table *table = NULL;
        struct timeval time_now;
        unsigned long long start_time, end_time;
-       uint16_t mtid;
+       uint16_t mtid = 0;
 
        /* Get time that can't roll backwards. */
        start_time = nowtv->tv_sec;
        start_time = (start_time * 1000000) + nowtv->tv_usec;
 
-       if (family == AF_INET)
-               spftree = area->spftree[level - 1];
-       else if (family == AF_INET6)
-               spftree = area->spftree6[level - 1];
+       int family = -1;
+       switch (tree_id) {
+       case SPFTREE_IPV4:
+               family = AF_INET;
+               mtid = ISIS_MT_IPV4_UNICAST;
+               break;
+       case SPFTREE_IPV6:
+               family = AF_INET6;
+               mtid = isis_area_ipv6_topology(area);
+               break;
+       case SPFTREE_DSTSRC:
+               family = AF_INET6;
+               mtid = ISIS_MT_IPV6_DSTSRC;
+               break;
+       case SPFTREE_COUNT:
+               assert(!"isis_run_spf should never be called with SPFTREE_COUNT as argument!");
+               return ISIS_WARNING;
+       }
+
        assert(spftree);
        assert(sysid);
 
-       /* Make all routes in current route table inactive. */
-       if (family == AF_INET)
-               table = area->route_table[level - 1];
-       else if (family == AF_INET6)
-               table = area->route_table6[level - 1];
-
-       isis_route_invalidate_table(area, table);
-
-       /* We only support ipv4-unicast and ipv6-unicast as topologies for now
-        */
-       if (family == AF_INET6)
-               mtid = isis_area_ipv6_topology(area);
-       else
-               mtid = ISIS_MT_IPV4_UNICAST;
-
        /*
         * C.2.5 Step 0
         */
-       init_spt(spftree, mtid, level, family);
+       init_spt(spftree, mtid, level, family, tree_id);
        /*              a) */
        root_vertex = isis_spf_add_root(spftree, sysid);
        /*              b) */
@@ -1342,7 +1380,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
        }
 
 out:
-       isis_route_validate(area);
        spftree->runcount++;
        spftree->last_run_timestamp = time(NULL);
        spftree->last_run_monotime = monotime(&time_now);
@@ -1353,6 +1390,23 @@ out:
        return retval;
 }
 
+void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
+{
+       if (area->is_type == IS_LEVEL_1) {
+               isis_route_verify_table(area, trees[0]->route_table);
+       } else if (area->is_type == IS_LEVEL_2) {
+               isis_route_verify_table(area, trees[1]->route_table);
+       } else {
+               isis_route_verify_merge(area, trees[0]->route_table,
+                                       trees[1]->route_table);
+       }
+}
+
+void isis_spf_invalidate_routes(struct isis_spftree *tree)
+{
+       isis_route_invalidate_table(tree->area, tree->route_table);
+}
+
 static int isis_run_spf_cb(struct thread *thread)
 {
        struct isis_spf_run *run = THREAD_ARG(thread);
@@ -1370,17 +1424,31 @@ static int isis_run_spf_cb(struct thread *thread)
                return ISIS_WARNING;
        }
 
+       isis_area_invalidate_routes(area, level);
+
        if (isis->debugs & DEBUG_SPF_EVENTS)
                zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
                           area->area_tag, level);
 
        if (area->ip_circuits)
-               retval = isis_run_spf(area, level, AF_INET, isis->sysid,
+               retval = isis_run_spf(area, level, SPFTREE_IPV4, isis->sysid,
                                      &thread->real);
        if (area->ipv6_circuits)
-               retval = isis_run_spf(area, level, AF_INET6, isis->sysid,
+               retval = isis_run_spf(area, level, SPFTREE_IPV6, isis->sysid,
+                                     &thread->real);
+       if (area->ipv6_circuits
+           && isis_area_ipv6_dstsrc_enabled(area))
+               retval = isis_run_spf(area, level, SPFTREE_DSTSRC, isis->sysid,
                                      &thread->real);
 
+       isis_area_verify_routes(area);
+
+       /* walk all circuits and reset any spf specific flags */
+       struct listnode *node;
+       struct isis_circuit *circuit;
+       for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+               UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
+
        return retval;
 }
 
@@ -1396,7 +1464,7 @@ static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
 
 int isis_spf_schedule(struct isis_area *area, int level)
 {
-       struct isis_spftree *spftree = area->spftree[level - 1];
+       struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1];
        time_t now = monotime(NULL);
        int diff = now - spftree->last_run_monotime;
 
@@ -1451,7 +1519,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
 {
        struct listnode *node;
        struct isis_vertex *vertex;
-       char buff[PREFIX2STR_BUFFER];
+       char buff[VID2STR_BUFFER];
 
        vty_out(vty,
                "Vertex               Type         Metric Next-Hop             Interface Parent\n");
@@ -1517,6 +1585,39 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
        }
 }
 
+static void isis_print_spftree(struct vty *vty, int level,
+                              struct isis_area *area,
+                              enum spf_tree_id tree_id)
+{
+       const char *tree_id_text = NULL;
+
+       switch (tree_id) {
+       case SPFTREE_IPV4:
+               tree_id_text = "that speak IP";
+               break;
+       case SPFTREE_IPV6:
+               tree_id_text = "that speak IPv6";
+               break;
+       case SPFTREE_DSTSRC:
+               tree_id_text = "that support IPv6 dst-src routing";
+               break;
+       case SPFTREE_COUNT:
+               assert(!"isis_print_spftree shouldn't be called with SPFTREE_COUNT as type");
+               return;
+       }
+
+       if (!area->spftree[tree_id][level - 1]
+           || !isis_vertex_queue_count(
+                   &area->spftree[tree_id][level - 1]->paths))
+               return;
+
+       vty_out(vty, "IS-IS paths to level-%d routers %s\n",
+               level, tree_id_text);
+       isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths,
+                        isis->sysid);
+       vty_out(vty, "\n");
+}
+
 DEFUN (show_isis_topology,
        show_isis_topology_cmd,
        "show isis topology [<level-1|level-2>]",
@@ -1548,25 +1649,17 @@ DEFUN (show_isis_topology,
                        if ((level & levels) == 0)
                                continue;
 
-                       if (area->ip_circuits > 0 && area->spftree[level - 1]
-                           && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) {
-                               vty_out(vty,
-                                       "IS-IS paths to level-%d routers that speak IP\n",
-                                       level);
-                               isis_print_paths(
-                                       vty, &area->spftree[level - 1]->paths,
-                                       isis->sysid);
-                               vty_out(vty, "\n");
+                       if (area->ip_circuits > 0) {
+                               isis_print_spftree(vty, level, area,
+                                                  SPFTREE_IPV4);
                        }
-                       if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
-                           && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) {
-                               vty_out(vty,
-                                       "IS-IS paths to level-%d routers that speak IPv6\n",
-                                       level);
-                               isis_print_paths(
-                                       vty, &area->spftree6[level - 1]->paths,
-                                       isis->sysid);
-                               vty_out(vty, "\n");
+                       if (area->ipv6_circuits > 0) {
+                               isis_print_spftree(vty, level, area,
+                                                  SPFTREE_IPV6);
+                       }
+                       if (isis_area_ipv6_dstsrc_enabled(area)) {
+                               isis_print_spftree(vty, level, area,
+                                                  SPFTREE_DSTSRC);
                        }
                }
 
index 84e07861d2c351252316efde190b28982f5a1f61..9a73ca8783dd3b6d766eb2b73b21fe45692773b0 100644 (file)
@@ -27,6 +27,9 @@
 struct isis_spftree;
 
 struct isis_spftree *isis_spftree_new(struct isis_area *area);
+void isis_spf_invalidate_routes(struct isis_spftree *tree);
+void isis_spf_verify_routes(struct isis_area *area,
+                           struct isis_spftree **trees);
 void isis_spftree_del(struct isis_spftree *spftree);
 void spftree_area_init(struct isis_area *area);
 void spftree_area_del(struct isis_area *area);
index 9b2aa7470b6f6cd418f4f357acf70efac19b2456..a433fcdb41a86f3da769b084d55d8c1dfb12ce56 100644 (file)
@@ -1912,6 +1912,11 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item)
        dest->count++;
 }
 
+static struct isis_item *last_item(struct isis_item_list *list)
+{
+       return container_of(list->tail, struct isis_item, next);
+}
+
 static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
                       uint8_t tlv_type, uint8_t len, struct stream *s,
                       struct sbuf *log, void *dest, int indent)
@@ -3168,6 +3173,21 @@ void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
        append_item(l, (struct isis_item *)r);
 }
 
+void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+                                    struct prefix_ipv6 *dest,
+                                    struct prefix_ipv6 *src,
+                                    uint32_t metric)
+{
+       isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric);
+       struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
+                                                    mtid);
+
+       struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
+       r->subtlvs = isis_alloc_subtlvs();
+       r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
+       memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
+}
+
 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
                                  uint8_t metric)
 {
index 98edbf14e7dc0233c7511d1fd1c217f985665619..bd1fa3e6768d3cea582f6b3821393a0bc2b9765a 100644 (file)
@@ -313,6 +313,10 @@ void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
                                     struct prefix_ipv4 *dest, uint32_t metric);
 void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                              struct prefix_ipv6 *dest, uint32_t metric);
+void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+                                    struct prefix_ipv6 *dest,
+                                    struct prefix_ipv6 *src,
+                                    uint32_t metric);
 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
                                  uint8_t metric);
 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
index ac640c5e4909c4b0ce4f729d4c44adcb858ebc44..9bc0f2ef350f674a896e0a87d802713c2802d615 100644 (file)
@@ -247,6 +247,7 @@ static int isis_zebra_link_params(int command, struct zclient *zclient,
 }
 
 static void isis_zebra_route_add_route(struct prefix *prefix,
+                                      struct prefix_ipv6 *src_p,
                                       struct isis_route_info *route_info)
 {
        struct zapi_route api;
@@ -264,6 +265,10 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
        api.type = ZEBRA_ROUTE_ISIS;
        api.safi = SAFI_UNICAST;
        api.prefix = *prefix;
+       if (src_p && src_p->prefixlen) {
+               api.src_prefix = *src_p;
+               SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+       }
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
        SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
        api.metric = route_info->cost;
@@ -322,6 +327,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
 }
 
 static void isis_zebra_route_del_route(struct prefix *prefix,
+                                      struct prefix_ipv6 *src_p,
                                       struct isis_route_info *route_info)
 {
        struct zapi_route api;
@@ -334,21 +340,26 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
        api.type = ZEBRA_ROUTE_ISIS;
        api.safi = SAFI_UNICAST;
        api.prefix = *prefix;
+       if (src_p && src_p->prefixlen) {
+               api.src_prefix = *src_p;
+               SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+       }
 
        zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
        UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
 }
 
 void isis_zebra_route_update(struct prefix *prefix,
+                            struct prefix_ipv6 *src_p,
                             struct isis_route_info *route_info)
 {
        if (zclient->sock < 0)
                return;
 
        if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE))
-               isis_zebra_route_add_route(prefix, route_info);
+               isis_zebra_route_add_route(prefix, src_p, route_info);
        else
-               isis_zebra_route_del_route(prefix, route_info);
+               isis_zebra_route_del_route(prefix, src_p, route_info);
 }
 
 static int isis_zebra_read(int command, struct zclient *zclient,
@@ -359,24 +370,23 @@ static int isis_zebra_read(int command, struct zclient *zclient,
        if (zapi_route_decode(zclient->ibuf, &api) < 0)
                return -1;
 
-       /* we completely ignore srcdest routes for now. */
-       if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
-               return 0;
-
        /*
         * Avoid advertising a false default reachability. (A default
         * route installed by IS-IS gets redistributed from zebra back
         * into IS-IS causing us to start advertising default reachabity
         * without this check)
         */
-       if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
+       if (api.prefix.prefixlen == 0
+           && api.src_prefix.prefixlen == 0
+           && api.type == ZEBRA_ROUTE_ISIS) {
                command = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
+       }
 
        if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
-               isis_redist_add(api.type, &api.prefix, api.distance,
-                               api.metric);
+               isis_redist_add(api.type, &api.prefix, &api.src_prefix,
+                               api.distance, api.metric);
        else
-               isis_redist_delete(api.type, &api.prefix);
+               isis_redist_delete(api.type, &api.prefix, &api.src_prefix);
 
        return 0;
 }
index bd7bf2b5c5b8ffbd678280faf56da7e49dd6ae68..4fbcf87217eef265857b036d5196d37fb870b6e9 100644 (file)
@@ -28,6 +28,7 @@ void isis_zebra_init(struct thread_master *);
 void isis_zebra_stop(void);
 
 void isis_zebra_route_update(struct prefix *prefix,
+                            struct prefix_ipv6 *src_p,
                             struct isis_route_info *route_info);
 int isis_distribute_list_update(int routetype);
 void isis_zebra_redistribute_set(afi_t afi, int type);
index cecaa0693dba709ee8212a699230edc0ffdbbf1c..a19f287453f463ad817301038bcb5a4a1659be07 100644 (file)
@@ -118,13 +118,9 @@ struct isis_area *isis_area_create(const char *area_tag)
         */
        if (area->is_type & IS_LEVEL_1) {
                area->lspdb[0] = lsp_db_init();
-               area->route_table[0] = route_table_init();
-               area->route_table6[0] = route_table_init();
        }
        if (area->is_type & IS_LEVEL_2) {
                area->lspdb[1] = lsp_db_init();
-               area->route_table[1] = route_table_init();
-               area->route_table6[1] = route_table_init();
        }
 
        spftree_area_init(area);
@@ -232,6 +228,10 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)
                area->lspdb[1] = NULL;
        }
 
+       /* invalidate and verify to delete all routes from zebra */
+       isis_area_invalidate_routes(area, ISIS_LEVEL1 & ISIS_LEVEL2);
+       isis_area_verify_routes(area);
+
        spftree_area_del(area);
 
        THREAD_TIMER_OFF(area->spf_timer[0]);
@@ -240,27 +240,6 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)
        spf_backoff_free(area->spf_delay_ietf[0]);
        spf_backoff_free(area->spf_delay_ietf[1]);
 
-       /* invalidate and validate would delete all routes from zebra */
-       isis_route_invalidate(area);
-       isis_route_validate(area);
-
-       if (area->route_table[0]) {
-               route_table_finish(area->route_table[0]);
-               area->route_table[0] = NULL;
-       }
-       if (area->route_table[1]) {
-               route_table_finish(area->route_table[1]);
-               area->route_table[1] = NULL;
-       }
-       if (area->route_table6[0]) {
-               route_table_finish(area->route_table6[0]);
-               area->route_table6[0] = NULL;
-       }
-       if (area->route_table6[1]) {
-               route_table_finish(area->route_table6[1]);
-               area->route_table6[1] = NULL;
-       }
-
        isis_redist_area_finish(area);
 
        for (ALL_LIST_ELEMENTS(area->area_addrs, node, nnode, addr)) {
@@ -1340,10 +1319,16 @@ DEFUN (show_isis_summary,
                        vty_out(vty, "\n");
 
                        vty_out(vty, "    IPv4 route computation:\n");
-                       isis_spf_print(area->spftree[level - 1], vty);
+                       isis_spf_print(area->spftree[SPFTREE_IPV4][level - 1],
+                                      vty);
 
                        vty_out(vty, "    IPv6 route computation:\n");
-                       isis_spf_print(area->spftree6[level - 1], vty);
+                       isis_spf_print(area->spftree[SPFTREE_IPV6][level - 1],
+                                      vty);
+
+                       vty_out(vty, "    IPv6 dst-src route computation:\n");
+                       isis_spf_print(area->spftree[SPFTREE_DSTSRC][level-1],
+                                      vty);
                }
        }
        vty_out(vty, "\n");
@@ -1680,29 +1665,42 @@ int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,
                                    passwd, snp_auth);
 }
 
+void isis_area_invalidate_routes(struct isis_area *area, int levels)
+{
+       for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+               if (!(level & levels))
+                       continue;
+               for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+                       isis_spf_invalidate_routes(
+                                       area->spftree[tree][level - 1]);
+               }
+       }
+}
+
+void isis_area_verify_routes(struct isis_area *area)
+{
+       for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++)
+               isis_spf_verify_routes(area, area->spftree[tree]);
+}
+
 static void area_resign_level(struct isis_area *area, int level)
 {
+       isis_area_invalidate_routes(area, level);
+       isis_area_verify_routes(area);
+
        if (area->lspdb[level - 1]) {
                lsp_db_destroy(area->lspdb[level - 1]);
                area->lspdb[level - 1] = NULL;
        }
-       if (area->spftree[level - 1]) {
-               isis_spftree_del(area->spftree[level - 1]);
-               area->spftree[level - 1] = NULL;
-       }
-       if (area->spftree6[level - 1]) {
-               isis_spftree_del(area->spftree6[level - 1]);
-               area->spftree6[level - 1] = NULL;
+
+       for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+               if (area->spftree[tree][level - 1]) {
+                       isis_spftree_del(area->spftree[tree][level - 1]);
+                       area->spftree[tree][level - 1] = NULL;
+               }
        }
+
        THREAD_TIMER_OFF(area->spf_timer[level - 1]);
-       if (area->route_table[level - 1]) {
-               route_table_finish(area->route_table[level - 1]);
-               area->route_table[level - 1] = NULL;
-       }
-       if (area->route_table6[level - 1]) {
-               route_table_finish(area->route_table6[level - 1]);
-               area->route_table6[level - 1] = NULL;
-       }
 
        sched_debug(
                "ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.",
@@ -1731,10 +1729,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type)
 
                if (area->lspdb[1] == NULL)
                        area->lspdb[1] = lsp_db_init();
-               if (area->route_table[1] == NULL)
-                       area->route_table[1] = route_table_init();
-               if (area->route_table6[1] == NULL)
-                       area->route_table6[1] = route_table_init();
                break;
 
        case IS_LEVEL_1_AND_2:
@@ -1750,10 +1744,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type)
 
                if (area->lspdb[0] == NULL)
                        area->lspdb[0] = lsp_db_init();
-               if (area->route_table[0] == NULL)
-                       area->route_table[0] = route_table_init();
-               if (area->route_table6[0] == NULL)
-                       area->route_table6[0] = route_table_init();
                break;
 
        default:
index d1ad9f3b8e74ba91866d7893b2bbb9842a3a9a76..ce602e4402b3488fd7f9223333629dbd6b6304c9 100644 (file)
@@ -63,13 +63,17 @@ struct isis {
 extern struct isis *isis;
 DECLARE_QOBJ_TYPE(isis_area)
 
+enum spf_tree_id {
+       SPFTREE_IPV4 = 0,
+       SPFTREE_IPV6,
+       SPFTREE_DSTSRC,
+       SPFTREE_COUNT
+};
+
 struct isis_area {
        struct isis *isis;                             /* back pointer */
        dict_t *lspdb[ISIS_LEVELS];                    /* link-state dbs */
-       struct isis_spftree *spftree[ISIS_LEVELS];     /* The v4 SPTs */
-       struct route_table *route_table[ISIS_LEVELS];  /* IPv4 routes */
-       struct isis_spftree *spftree6[ISIS_LEVELS];    /* The v6 SPTs */
-       struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */
+       struct isis_spftree *spftree[SPFTREE_COUNT][ISIS_LEVELS];
 #define DEFAULT_LSP_MTU 1497
        unsigned int lsp_mtu;      /* Size of LSPs to generate */
        struct list *circuit_list; /* IS-IS circuits */
@@ -144,6 +148,9 @@ struct isis_area *isis_area_lookup(const char *);
 int isis_area_get(struct vty *vty, const char *area_tag);
 void print_debug(struct vty *, int, int);
 
+void isis_area_invalidate_routes(struct isis_area *area, int levels);
+void isis_area_verify_routes(struct isis_area *area);
+
 void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
 void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit);
 void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname);
index 32f8e8ca5b473d6c7eb21185edc00648ac6535ee..4497faf6fcec773a4ddb8c7a9dc9586020bc874c 100644 (file)
@@ -281,13 +281,12 @@ void srcdest_rnode_prefixes(struct route_node *rn, const struct prefix **p,
        }
 }
 
-const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
+const char *srcdest2str(const struct prefix *dst_p,
+                       const struct prefix_ipv6 *src_p,
+                       char *str, int size)
 {
-       const struct prefix *dst_p, *src_p;
        char dst_buf[PREFIX_STRLEN], src_buf[PREFIX_STRLEN];
 
-       srcdest_rnode_prefixes(rn, &dst_p, &src_p);
-
        snprintf(str, size, "%s%s%s",
                 prefix2str(dst_p, dst_buf, sizeof(dst_buf)),
                 (src_p && src_p->prefixlen) ? " from " : "",
@@ -296,3 +295,11 @@ const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
                         : "");
        return str;
 }
+
+const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
+{
+       const struct prefix *dst_p, *src_p;
+
+       srcdest_rnode_prefixes(rn, &dst_p, &src_p);
+       return srcdest2str(dst_p, (struct prefix_ipv6*)src_p, str, size);
+}
index 5f97f02bacfd757707dba9b87eba39ebc8eddd80..9ceb876f81b81bba96a85b8133d6ccd0d7da1c31 100644 (file)
@@ -64,6 +64,9 @@ extern struct route_node *srcdest_rnode_lookup(struct route_table *table,
 extern void srcdest_rnode_prefixes(struct route_node *rn,
                                   const struct prefix **p,
                                   const struct prefix **src_p);
+extern const char *srcdest2str(const struct prefix *dst_p,
+                              const struct prefix_ipv6 *src_p,
+                              char *str, int size);
 extern const char *srcdest_rnode2str(struct route_node *rn, char *str,
                                     int size);
 extern struct route_node *srcdest_route_next(struct route_node *rn);
index 98428eaab237685d5e6872e801705ef9123a308b..9ac96372ff70e6514062fe659654ed511d75963f 100644 (file)
@@ -365,6 +365,22 @@ struct in_pktinfo {
                _a < _b ? _a : _b;                                             \
        })
 
+#ifndef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member)                                        \
+       ({                                                                     \
+               const typeof(((type *)0)->member) *__mptr = (ptr);             \
+               (type *)((char *)__mptr - offsetof(type, member));             \
+       })
+#endif
+
 #define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0]))
 
 /* For old definition. */
index cca702b138f99f61f49760b0d403c8379f085109..4abbe81499be693f39a91cf6581bde569ebd3da8 100644 (file)
Binary files a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ
index fe528203aa93c311afd42ac317176a05dcb1a672..3e31b833511d2ded04ba55ce053d4ab5cfa6b3ad 100644 (file)
@@ -17,21 +17,21 @@ static size_t vertex_count;
 static void setup_test_vertices(void)
 {
        union isis_N nid, nip = {
-               .prefix.family = AF_UNSPEC
+               .ip.dest.family = AF_UNSPEC
        };
 
        vertices = XMALLOC(MTYPE_TMP, sizeof(*vertices) * 16);
 
-       nip.prefix.family = AF_INET;
-       nip.prefix.prefixlen = 24;
-       inet_pton(AF_INET, "192.168.1.0", &nip.prefix.u.prefix4);
+       nip.ip.dest.family = AF_INET;
+       nip.ip.dest.prefixlen = 24;
+       inet_pton(AF_INET, "192.168.1.0", &nip.ip.dest.u.prefix4);
        vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
        vertices[vertex_count]->d_N = 20;
        vertex_count++;
 
-       nip.prefix.family = AF_INET;
-       nip.prefix.prefixlen = 24;
-       inet_pton(AF_INET, "192.168.2.0", &nip.prefix.u.prefix4);
+       nip.ip.dest.family = AF_INET;
+       nip.ip.dest.prefixlen = 24;
+       inet_pton(AF_INET, "192.168.2.0", &nip.ip.dest.u.prefix4);
        vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
        vertices[vertex_count]->d_N = 20;
        vertex_count++;
@@ -48,9 +48,9 @@ static void setup_test_vertices(void)
        vertices[vertex_count]->d_N = 15;
        vertex_count++;
 
-       nip.prefix.family = AF_INET;
-       nip.prefix.prefixlen = 24;
-       inet_pton(AF_INET, "192.168.3.0", &nip.prefix.u.prefix4);
+       nip.ip.dest.family = AF_INET;
+       nip.ip.dest.prefixlen = 24;
+       inet_pton(AF_INET, "192.168.3.0", &nip.ip.dest.u.prefix4);
        vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
        vertices[vertex_count]->d_N = 20;
        vertex_count++;