]> git.proxmox.com Git - mirror_frr.git/blobdiff - isisd/isis_route.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / isisd / isis_route.c
index 9f8f639e5d2e6fbc1d9390491b1fb1c5f04bb6f9..711d5cbed9f481e03149579aaf7077e30ac2c84a 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * IS-IS Rout(e)ing protocol               - isis_route.c
  * Copyright (C) 2001,2002   Sampo Saaristo
@@ -6,20 +7,6 @@
  *
  *                                         based on ../ospf6d/ospf6_route.[ch]
  *                                         by Yasuhiro Ohara
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public Licenseas published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -91,11 +78,18 @@ static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
        struct isis_nexthop *nh;
 
        for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
-               if (nh->family != family)
-                       continue;
                if (nh->ifindex != ifindex)
                        continue;
 
+               /* if the IP is unspecified, return the first nexthop found on
+                * the interface
+                */
+               if (!ip)
+                       return nh;
+
+               if (nh->family != family)
+                       continue;
+
                switch (family) {
                case AF_INET:
                        if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
@@ -459,25 +453,33 @@ void isis_route_delete(struct isis_area *area, struct route_node *rode,
        route_unlock_node(rode);
 }
 
+static void isis_route_remove_previous_sid(struct isis_area *area,
+                                          struct prefix *prefix,
+                                          struct isis_route_info *route_info)
+{
+       /*
+        * Explicitly uninstall previous Prefix-SID label if it has
+        * changed or was removed.
+        */
+       if (route_info->sr_previous.present &&
+           (!route_info->sr.present ||
+            route_info->sr_previous.label != route_info->sr.label))
+               isis_zebra_prefix_sid_uninstall(area, prefix, route_info,
+                                               &route_info->sr_previous);
+}
+
 static void isis_route_update(struct isis_area *area, struct prefix *prefix,
                              struct prefix_ipv6 *src_p,
                              struct isis_route_info *route_info)
 {
+       if (area == NULL)
+               return;
+
        if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
                if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
                        return;
 
-               /*
-                * Explicitly uninstall previous Prefix-SID label if it has
-                * changed or was removed.
-                */
-               if (route_info->sr_previous.present
-                   && (!route_info->sr.present
-                       || route_info->sr_previous.label
-                                  != route_info->sr.label))
-                       isis_zebra_prefix_sid_uninstall(
-                               area, prefix, route_info,
-                               &route_info->sr_previous);
+               isis_route_remove_previous_sid(area, prefix, route_info);
 
                /* Install route. */
                isis_zebra_route_add_route(area->isis, prefix, src_p,
@@ -724,3 +726,54 @@ void isis_route_invalidate_table(struct isis_area *area,
                UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
        }
 }
+
+void isis_route_switchover_nexthop(struct isis_area *area,
+                                  struct route_table *table, int family,
+                                  union g_addr *nexthop_addr,
+                                  ifindex_t ifindex)
+{
+       const char *ifname = NULL, *vrfname = NULL;
+       struct isis_route_info *rinfo;
+       struct prefix_ipv6 *src_p;
+       struct route_node *rnode;
+       vrf_id_t vrf_id;
+       struct prefix *prefix;
+
+       if (IS_DEBUG_EVENTS) {
+               if (area && area->isis) {
+                       vrf_id = area->isis->vrf_id;
+                       vrfname = vrf_id_to_name(vrf_id);
+                       ifname = ifindex2ifname(ifindex, vrf_id);
+               }
+               zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
+                          __func__, family2str(family), vrfname ? vrfname : "",
+                          ifname ? ifname : "");
+       }
+
+       for (rnode = route_top(table); rnode;
+            rnode = srcdest_route_next(rnode)) {
+               if (!rnode->info)
+                       continue;
+               rinfo = rnode->info;
+
+               if (!rinfo->backup)
+                       continue;
+
+               if (!nexthoplookup(rinfo->nexthops, family, nexthop_addr,
+                                  ifindex))
+                       continue;
+
+               srcdest_rnode_prefixes(rnode, (const struct prefix **)&prefix,
+                                      (const struct prefix **)&src_p);
+
+               /* Switchover route. */
+               isis_route_remove_previous_sid(area, prefix, rinfo);
+               UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+               isis_route_update(area, prefix, src_p, rinfo->backup);
+
+               isis_route_info_delete(rinfo);
+
+               rnode->info = NULL;
+               route_unlock_node(rnode);
+       }
+}