]> git.proxmox.com Git - mirror_frr.git/blobdiff - isisd/isis_route.c
zebra: Fix label manager memory leak (#5680)
[mirror_frr.git] / isisd / isis_route.c
index 82005c911ea19db0db484fcede61ed9cf4eeff91..05394e0fe4bc8a2ac67fef377706845a80cd25a3 100644 (file)
@@ -28,6 +28,7 @@
 #include "linklist.h"
 #include "vty.h"
 #include "log.h"
+#include "lib_errors.h"
 #include "memory.h"
 #include "prefix.h"
 #include "hash.h"
 #include "isis_route.h"
 #include "isis_zebra.h"
 
-static struct isis_nexthop *isis_nexthop_create(struct in_addr *ip,
+DEFINE_HOOK(isis_route_update_hook,
+           (struct isis_area * area, struct prefix *prefix,
+            struct isis_route_info *route_info),
+           (area, prefix, route_info))
+
+static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
+                                         union g_addr *ip, ifindex_t ifindex);
+static void isis_route_update(struct isis_area *area, struct prefix *prefix,
+                             struct prefix_ipv6 *src_p,
+                             struct isis_route_info *route_info);
+
+static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
                                                ifindex_t ifindex)
 {
-       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;
-
+       nexthop = nexthoplookup(isis->nexthops, family, ip, ifindex);
+       if (nexthop) {
                nexthop->lock++;
                return nexthop;
        }
 
        nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
 
+       nexthop->family = family;
        nexthop->ifindex = ifindex;
-       memcpy(&nexthop->ip, ip, sizeof(struct in_addr));
+       nexthop->ip = *ip;
        listnode_add(isis->nexthops, nexthop);
        nexthop->lock++;
 
@@ -85,116 +93,79 @@ static void isis_nexthop_delete(struct isis_nexthop *nexthop)
        return;
 }
 
-static int nexthoplookup(struct list *nexthops, struct in_addr *ip,
-                        ifindex_t ifindex)
+static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
+                                         union g_addr *ip, ifindex_t ifindex)
 {
        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;
-       }
-
-       return 0;
-}
-
-static struct isis_nexthop6 *isis_nexthop6_new(struct in6_addr *ip6,
-                                              ifindex_t ifindex)
-{
-       struct isis_nexthop6 *nexthop6;
-
-       nexthop6 = XCALLOC(MTYPE_ISIS_NEXTHOP6, sizeof(struct isis_nexthop6));
-
-       nexthop6->ifindex = ifindex;
-       memcpy(&nexthop6->ip6, ip6, sizeof(struct in6_addr));
-       nexthop6->lock++;
-
-       return nexthop6;
-}
-
-static struct isis_nexthop6 *isis_nexthop6_create(struct in6_addr *ip6,
-                                                 ifindex_t ifindex)
-{
-       struct listnode *node;
-       struct isis_nexthop6 *nexthop6;
-
-       for (ALL_LIST_ELEMENTS_RO(isis->nexthops6, node, nexthop6)) {
-               if (nexthop6->ifindex != ifindex)
+               if (nh->family != family)
                        continue;
-               if (ip6
-                   && memcmp(&nexthop6->ip6, ip6, sizeof(struct in6_addr))
-                              != 0)
+               if (nh->ifindex != ifindex)
                        continue;
 
-               nexthop6->lock++;
-               return nexthop6;
-       }
-
-       nexthop6 = isis_nexthop6_new(ip6, ifindex);
-
-       return nexthop6;
-}
-
-static void isis_nexthop6_delete(struct isis_nexthop6 *nexthop6)
-{
-
-       nexthop6->lock--;
-       if (nexthop6->lock == 0) {
-               listnode_delete(isis->nexthops6, nexthop6);
-               XFREE(MTYPE_ISIS_NEXTHOP6, nexthop6);
-       }
-
-       return;
-}
-
-static int nexthop6lookup(struct list *nexthops6, struct in6_addr *ip6,
-                         ifindex_t ifindex)
-{
-       struct listnode *node;
-       struct isis_nexthop6 *nh6;
+               switch (family) {
+               case AF_INET:
+                       if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
+                               continue;
+                       break;
+               case AF_INET6:
+                       if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
+                               continue;
+                       break;
+               default:
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "%s: unknown address family [%d]", __func__,
+                                family);
+                       exit(1);
+               }
 
-       for (ALL_LIST_ELEMENTS_RO(nexthops6, node, nh6)) {
-               if (!(memcmp(ip6, &nh6->ip6, sizeof(struct in6_addr)))
-                   && ifindex == nh6->ifindex)
-                       return 1;
+               return nh;
        }
 
-       return 0;
+       return NULL;
 }
 
-static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
+static void adjinfo2nexthop(int family, struct list *nexthops,
+                           struct isis_adjacency *adj)
 {
        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;
+       union g_addr ip = {};
+
+       switch (family) {
+       case AF_INET:
+               for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
+                       ip.ipv4 = adj->ipv4_addresses[i];
+
+                       if (!nexthoplookup(nexthops, AF_INET, &ip,
+                                          adj->circuit->interface->ifindex)) {
+                               nh = isis_nexthop_create(
+                                       AF_INET, &ip,
+                                       adj->circuit->interface->ifindex);
+                               listnode_add(nexthops, nh);
+                               break;
+                       }
                }
-       }
-}
-
-static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
-{
-       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;
+               break;
+       case AF_INET6:
+               for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
+                       ip.ipv6 = adj->ipv6_addresses[i];
+
+                       if (!nexthoplookup(nexthops, AF_INET6, &ip,
+                                          adj->circuit->interface->ifindex)) {
+                               nh = isis_nexthop_create(
+                                       AF_INET6, &ip,
+                                       adj->circuit->interface->ifindex);
+                               listnode_add(nexthops, nh);
+                               break;
+                       }
                }
+               break;
+       default:
+               flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
+                        __func__, family);
+               exit(1);
        }
 }
 
@@ -210,35 +181,32 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
 
        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 */
+       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 */
+               switch (prefix->family) {
+               case AF_INET:
                        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 */
+                       break;
+               case AF_INET6:
                        if (depth == 2 && prefix->prefixlen == 128
                            && (!src_p || !src_p->prefixlen)) {
                                adj->router_address6 = prefix->u.prefix6;
                        }
-                       adjinfo2nexthop6(rinfo->nexthops6, adj);
+                       break;
+               default:
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "%s: unknown address family [%d]", __func__,
+                                prefix->family);
+                       exit(1);
                }
+               adjinfo2nexthop(prefix->family, rinfo->nexthops, adj);
        }
 
        rinfo->cost = cost;
@@ -255,12 +223,6 @@ static void isis_route_info_delete(struct isis_route_info *route_info)
                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);
 }
 
@@ -280,7 +242,6 @@ static int isis_route_info_same(struct isis_route_info *new,
 {
        struct listnode *node;
        struct isis_nexthop *nexthop;
-       struct isis_nexthop6 *nexthop6;
 
        if (!CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
                return 0;
@@ -291,31 +252,15 @@ static int isis_route_info_same(struct isis_route_info *new,
        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;
-       }
+       for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
+               if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
+                                  nexthop->ifindex))
+                       return 0;
+
+       for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
+               if (!nexthoplookup(new->nexthops, nexthop->family, &nexthop->ip,
+                                  nexthop->ifindex))
+                       return 0;
 
        return 1;
 }
@@ -379,7 +324,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
        return route_info;
 }
 
-static void isis_route_delete(struct route_node *rode,
+static void isis_route_delete(struct isis_area *area, struct route_node *rode,
                              struct route_table *table)
 {
        struct isis_route_info *rinfo;
@@ -406,13 +351,37 @@ static void isis_route_delete(struct route_node *rode,
                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_update(area, prefix, src_p, rinfo);
        }
        isis_route_info_delete(rinfo);
        rode->info = NULL;
        route_unlock_node(rode);
 }
 
+static void isis_route_update(struct isis_area *area, struct prefix *prefix,
+                             struct prefix_ipv6 *src_p,
+                             struct isis_route_info *route_info)
+{
+       if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
+               if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+                       return;
+
+               isis_zebra_route_add_route(prefix, src_p, route_info);
+               hook_call(isis_route_update_hook, area, prefix, route_info);
+
+               SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+               UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+       } else {
+               if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+                       return;
+
+               isis_zebra_route_del_route(prefix, src_p, route_info);
+               hook_call(isis_route_update_hook, area, prefix, route_info);
+
+               UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+       }
+}
+
 static void _isis_route_verify_table(struct isis_area *area,
                                     struct route_table *table,
                                     struct route_table **tables)
@@ -453,7 +422,7 @@ static void _isis_route_verify_table(struct isis_area *area,
                                buff);
                }
 
-               isis_zebra_route_update(dst_p, src_p, rinfo);
+               isis_route_update(area, dst_p, src_p, rinfo);
 
                if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
                        continue;
@@ -462,7 +431,7 @@ static void _isis_route_verify_table(struct isis_area *area,
                 * directly for
                 * validating => no problems with deleting routes. */
                if (!tables) {
-                       isis_route_delete(rnode, table);
+                       isis_route_delete(area, rnode, table);
                        continue;
                }
 
@@ -485,7 +454,7 @@ static void _isis_route_verify_table(struct isis_area *area,
                        route_unlock_node(drnode);
                }
 
-               isis_route_delete(rnode, table);
+               isis_route_delete(area, rnode, table);
        }
 }
 
@@ -543,7 +512,8 @@ void isis_route_verify_merge(struct isis_area *area,
                                                ISIS_ROUTE_FLAG_ZEBRA_SYNCED
                                        );
                                        continue;
-                               } else {
+                               } else if (CHECK_FLAG(rinfo->flag,
+                                                     ISIS_ROUTE_FLAG_ACTIVE)) {
                                        /* Clear the ZEBRA_SYNCED flag on the L1
                                         * route when L2 wins, otherwise L1
                                         * won't get reinstalled when it
@@ -553,6 +523,11 @@ void isis_route_verify_merge(struct isis_area *area,
                                                mrinfo->flag,
                                                ISIS_ROUTE_FLAG_ZEBRA_SYNCED
                                        );
+                               } else if (
+                                       CHECK_FLAG(
+                                               mrinfo->flag,
+                                               ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
+                                       continue;
                                }
                        }
                        mrnode->info = rnode->info;