]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospfd/ospf_route.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / ospfd / ospf_route.c
index e3e6f68a8230cfc82a4949a379ad07a36750b57b..5f18bff1cf79996de3b9523a3e982fc669cc0e5d 100644 (file)
@@ -1,22 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * OSPF routing table.
  * Copyright (C) 1999, 2000 Toshiaki Takada
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra 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>
 #include "ospfd/ospf_zebra.h"
 #include "ospfd/ospf_dump.h"
 
+const char *ospf_path_type_name(int path_type)
+{
+       switch (path_type) {
+       case OSPF_PATH_INTRA_AREA:
+               return "Intra-Area";
+       case OSPF_PATH_INTER_AREA:
+               return "Inter-Area";
+       case OSPF_PATH_TYPE1_EXTERNAL:
+               return "External-1";
+       case OSPF_PATH_TYPE2_EXTERNAL:
+               return "External-2";
+       default:
+               return "Unknown";
+       }
+}
+
 struct ospf_route *ospf_route_new(void)
 {
        struct ospf_route *new;
@@ -71,15 +72,31 @@ struct ospf_path *ospf_path_new(void)
 static struct ospf_path *ospf_path_dup(struct ospf_path *path)
 {
        struct ospf_path *new;
+       int memsize;
 
        new = ospf_path_new();
        memcpy(new, path, sizeof(struct ospf_path));
 
+       /* optional TI-LFA backup paths */
+       if (path->srni.backup_label_stack) {
+               memsize = sizeof(struct mpls_label_stack)
+                         + (sizeof(mpls_label_t)
+                            * path->srni.backup_label_stack->num_labels);
+               new->srni.backup_label_stack =
+                       XCALLOC(MTYPE_OSPF_PATH, memsize);
+               memcpy(new->srni.backup_label_stack,
+                      path->srni.backup_label_stack, memsize);
+       }
+
        return new;
 }
 
 void ospf_path_free(struct ospf_path *op)
 {
+       /* optional TI-LFA backup paths */
+       if (op->srni.backup_label_stack)
+               XFREE(MTYPE_OSPF_PATH, op->srni.backup_label_stack);
+
        XFREE(MTYPE_OSPF_PATH, op);
 }
 
@@ -140,6 +157,35 @@ static int ospf_route_exist_new_table(struct route_table *rt,
        return 1;
 }
 
+static int ospf_route_backup_path_same(struct sr_nexthop_info *srni1,
+                                      struct sr_nexthop_info *srni2)
+{
+       struct mpls_label_stack *ls1, *ls2;
+       uint8_t label_count;
+
+       ls1 = srni1->backup_label_stack;
+       ls2 = srni2->backup_label_stack;
+
+       if (!ls1 && !ls2)
+               return 1;
+
+       if ((ls1 && !ls2) || (!ls1 && ls2))
+               return 0;
+
+       if (ls1->num_labels != ls2->num_labels)
+               return 0;
+
+       for (label_count = 0; label_count < ls1->num_labels; label_count++) {
+               if (ls1->label[label_count] != ls2->label[label_count])
+                       return 0;
+       }
+
+       if (!IPV4_ADDR_SAME(&srni1->backup_nexthop, &srni2->backup_nexthop))
+               return 0;
+
+       return 1;
+}
+
 /* If a prefix and a nexthop match any route in the routing table,
    then return 1, otherwise return 0. */
 int ospf_route_match_same(struct route_table *rt, struct prefix_ipv4 *prefix,
@@ -163,6 +209,9 @@ int ospf_route_match_same(struct route_table *rt, struct prefix_ipv4 *prefix,
 
        or = rn->info;
        if (or->type == newor->type && or->cost == newor->cost) {
+               if (or->changed)
+                       return 0;
+
                if (or->type == OSPF_DESTINATION_NETWORK) {
                        if (or->paths->count != newor->paths->count)
                                return 0;
@@ -180,6 +229,11 @@ int ospf_route_match_same(struct route_table *rt, struct prefix_ipv4 *prefix,
                                        return 0;
                                if (op->ifindex != newop->ifindex)
                                        return 0;
+
+                               /* check TI-LFA backup paths */
+                               if (!ospf_route_backup_path_same(&op->srni,
+                                                                &newop->srni))
+                                       return 0;
                        }
                        return 1;
                } else if (prefix_same(&rn->p, (struct prefix *)prefix))
@@ -294,43 +348,49 @@ void ospf_route_install(struct ospf *ospf, struct route_table *rt)
 
 /* RFC2328 16.1. (4). For "router". */
 void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
-                          struct ospf_area *area)
+                          struct ospf_area *area, bool add_only)
 {
        struct route_node *rn;
        struct ospf_route * or ;
        struct prefix_ipv4 p;
        struct router_lsa *lsa;
 
-       if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_router: Start");
-
+       if (IS_DEBUG_OSPF_EVENT) {
+               if (!add_only)
+                       zlog_debug("%s: Start", __func__);
+               else
+                       zlog_debug("%s: REACHRUN: Start", __func__);
+       }
        lsa = (struct router_lsa *)v->lsa;
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_router: LS ID: %s",
-                          inet_ntoa(lsa->header.id));
+               zlog_debug("%s: LS ID: %pI4", __func__, &lsa->header.id);
 
-       if (!OSPF_IS_AREA_BACKBONE(area))
-               ospf_vl_up_check(area, lsa->header.id, v);
+       if (!add_only) {
+               if (!OSPF_IS_AREA_BACKBONE(area))
+                       ospf_vl_up_check(area, lsa->header.id, v);
 
-       if (!CHECK_FLAG(lsa->flags, ROUTER_LSA_SHORTCUT))
-               area->shortcut_capability = 0;
+               if (!CHECK_FLAG(lsa->flags, ROUTER_LSA_SHORTCUT))
+                       area->shortcut_capability = 0;
 
-       /* If the newly added vertex is an area border router or AS boundary
-          router, a routing table entry is added whose destination type is
-          "router". */
-       if (!IS_ROUTER_LSA_BORDER(lsa) && !IS_ROUTER_LSA_EXTERNAL(lsa)) {
-               if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_intra_add_router: this router is neither ASBR nor ABR, skipping it");
-               return;
-       }
+               /* If the newly added vertex is an area border router or AS
+                  boundary router, a routing table entry is added whose
+                  destination type is "router". */
+               if (!IS_ROUTER_LSA_BORDER(lsa) &&
+                   !IS_ROUTER_LSA_EXTERNAL(lsa)) {
+                       if (IS_DEBUG_OSPF_EVENT)
+                               zlog_debug(
+                                       "%s: this router is neither ASBR nor ABR, skipping it",
+                                       __func__);
+                       return;
+               }
 
-       /* Update ABR and ASBR count in this area. */
-       if (IS_ROUTER_LSA_BORDER(lsa))
-               area->abr_count++;
-       if (IS_ROUTER_LSA_EXTERNAL(lsa))
-               area->asbr_count++;
+               /* Update ABR and ASBR count in this area. */
+               if (IS_ROUTER_LSA_BORDER(lsa))
+                       area->abr_count++;
+               if (IS_ROUTER_LSA_EXTERNAL(lsa))
+                       area->asbr_count++;
+       }
 
        /* The Options field found in the associated router-LSA is copied
           into the routing table entry's Optional capabilities field. Call
@@ -364,8 +424,7 @@ void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
        apply_mask_ipv4(&p);
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_router: talking about %s/%d",
-                          inet_ntoa(p.prefix), p.prefixlen);
+               zlog_debug("%s: talking about %pFX", __func__, &p);
 
        rn = route_node_get(rt, (struct prefix *)&p);
 
@@ -379,8 +438,12 @@ void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
 
        listnode_add(rn->info, or);
 
-       if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_router: Stop");
+       if (IS_DEBUG_OSPF_EVENT) {
+               if (!add_only)
+                       zlog_debug("%s: Stop", __func__);
+               else
+                       zlog_debug("%s: REACHRUN: Stop", __func__);
+       }
 }
 
 /* RFC2328 16.1. (4).  For transit network. */
@@ -457,7 +520,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
        struct ospf_path *path;
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_stub(): Start");
+               zlog_debug("%s: Start", __func__);
 
        lsa = (struct router_lsa *)v->lsa;
 
@@ -467,8 +530,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
        apply_mask_ipv4(&p);
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_stub(): processing route to %s/%d",
-                          inet_ntoa(p.prefix), p.prefixlen);
+               zlog_debug("%s: processing route to %pFX", __func__, &p);
 
        /* (1) Calculate the distance D of stub network from the root.  D is
           equal to the distance from the root to the router vertex
@@ -477,9 +539,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
        cost = v->distance + ntohs(link->m[0].metric);
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug(
-                       "ospf_intra_add_stub(): calculated cost is %d + %d = %d",
-                       v->distance, ntohs(link->m[0].metric), cost);
+               zlog_debug("%s: calculated cost is %d + %d = %d", __func__,
+                          v->distance, ntohs(link->m[0].metric), cost);
 
        /* PtP links with /32 masks adds host routes to remote, directly
         * connected hosts, see RFC 2328, 12.4.1.1, Option 1.
@@ -488,8 +549,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
        if (parent_is_root && link->link_data.s_addr == 0xffffffff
            && ospf_if_lookup_by_local_addr(area->ospf, NULL, link->link_id)) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug("%s: ignoring host route %s/32 to self.",
-                                  __func__, inet_ntoa(link->link_id));
+                       zlog_debug("%s: ignoring host route %pI4/32 to self.",
+                                  __func__, &link->link_id);
                return;
        }
 
@@ -505,8 +566,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
 
                if (IS_DEBUG_OSPF_EVENT)
                        zlog_debug(
-                               "ospf_intra_add_stub(): another route to the same prefix found with cost %u",
-                               cur_or->cost);
+                               "%s: another route to the same prefix found with cost %u",
+                               __func__, cur_or->cost);
 
                /* Compare this distance to the current best cost to the stub
                   network.  This is done by looking up the stub network's
@@ -515,8 +576,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
                   LSA. */
                if (cost > cur_or->cost) {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_intra_add_stub(): old route is better, exit");
+                               zlog_debug("%s: old route is better, exit",
+                                          __func__);
                        return;
                }
 
@@ -535,8 +596,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
 
                if (cost == cur_or->cost) {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_intra_add_stub(): routes are equal, merge");
+                               zlog_debug("%s: routes are equal, merge",
+                                          __func__);
 
                        ospf_route_copy_nexthops_from_vertex(area, cur_or, v);
 
@@ -556,8 +617,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
 
                if (cost < cur_or->cost) {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_intra_add_stub(): new route is better, set it");
+                               zlog_debug("%s: new route is better, set it",
+                                          __func__);
 
                        cur_or->cost = cost;
 
@@ -571,7 +632,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
        }
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_stub(): installing new route");
+               zlog_debug("%s: installing new route", __func__);
 
        or = ospf_route_new();
 
@@ -586,13 +647,13 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
        /* Nexthop is depend on connection type. */
        if (v != area->spf) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_intra_add_stub(): this network is on remote router");
+                       zlog_debug("%s: this network is on remote router",
+                                  __func__);
                ospf_route_copy_nexthops_from_vertex(area, or, v);
        } else {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_intra_add_stub(): this network is on this router");
+                       zlog_debug("%s: this network is on this router",
+                                  __func__);
 
                /*
                 * Only deal with interface data when we
@@ -603,9 +664,8 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
 
                if (oi || area->spf_dry_run) {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_intra_add_stub(): the lsa pos is %d",
-                                       lsa_pos);
+                               zlog_debug("%s: the lsa pos is %d", __func__,
+                                          lsa_pos);
 
                        path = ospf_path_new();
                        path->nexthop.s_addr = INADDR_ANY;
@@ -620,15 +680,15 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
                        listnode_add(or->paths, path);
                } else {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_intra_add_stub(): where's the interface ?");
+                               zlog_debug("%s: where's the interface ?",
+                                          __func__);
                }
        }
 
        rn->info = or ;
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_intra_add_stub(): Stop");
+               zlog_debug("%s: Stop", __func__);
 }
 
 static const char *const ospf_path_type_str[] = {
@@ -653,8 +713,8 @@ void ospf_route_table_dump(struct route_table *rt)
                                           or->cost);
                                for (ALL_LIST_ELEMENTS_RO(or->paths, pnode,
                                                          path))
-                                       zlog_debug("  -> %s",
-                                                  inet_ntoa(path->nexthop));
+                                       zlog_debug("  -> %pI4",
+                                                  &path->nexthop);
                        } else
                                zlog_debug("R %-18pI4 %-15pI4 %s %d",
                                           &rn->p.u.prefix4,
@@ -665,35 +725,22 @@ void ospf_route_table_dump(struct route_table *rt)
        zlog_debug("========================================");
 }
 
-void ospf_route_table_print(struct vty *vty, struct route_table *rt)
+void ospf_router_route_table_dump(struct route_table *rt)
 {
        struct route_node *rn;
-       struct ospf_route * or ;
-       struct listnode *pnode;
-       struct ospf_path *path;
+       struct ospf_route *or;
+       struct listnode *node;
 
-       vty_out(vty, "========== OSPF routing table ==========\n");
-       for (rn = route_top(rt); rn; rn = route_next(rn))
-               if ((or = rn->info) != NULL) {
-                       if (or->type == OSPF_DESTINATION_NETWORK) {
-                               vty_out(vty, "N %-18pFX %-15pI4 %s %d\n",
-                                       &rn->p, & or->u.std.area_id,
-                                       ospf_path_type_str[or->path_type],
-                                       or->cost);
-                               for (ALL_LIST_ELEMENTS_RO(or->paths, pnode,
-                                                         path))
-                                       vty_out(vty, "  -> %s\n",
-                                               path->nexthop.s_addr != 0
-                                                       ? inet_ntoa(
-                                                               path->nexthop)
-                                                       : "directly connected");
-                       } else
-                               vty_out(vty, "R %-18pI4 %-15pI4 %s %d\n",
-                                       &rn->p.u.prefix4, & or->u.std.area_id,
-                                       ospf_path_type_str[or->path_type],
-                                       or->cost);
+       zlog_debug("========== OSPF routing table ==========");
+       for (rn = route_top(rt); rn; rn = route_next(rn)) {
+               for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or)) {
+                       assert(or->type == OSPF_DESTINATION_ROUTER);
+                       zlog_debug("R %-18pI4 %-15pI4 %s %d", &rn->p.u.prefix4,
+                                  &or->u.std.area_id,
+                                  ospf_path_type_str[or->path_type], or->cost);
                }
-       vty_out(vty, "========================================\n");
+       }
+       zlog_debug("========================================");
 }
 
 /* This is 16.4.1 implementation.
@@ -802,6 +849,7 @@ void ospf_route_copy_nexthops_from_vertex(struct ospf_area *area,
                    || area->spf_dry_run) {
                        path = ospf_path_new();
                        path->nexthop = nexthop->router;
+                       path->adv_router = v->id;
 
                        if (oi) {
                                path->ifindex = oi->ifp->ifindex;
@@ -874,7 +922,7 @@ void ospf_route_add(struct route_table *rt, struct prefix_ipv4 *p,
 
        if (rn->info) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug("ospf_route_add(): something's wrong !");
+                       zlog_debug("%s: something's wrong !", __func__);
                route_unlock_node(rn);
                return;
        }
@@ -896,9 +944,8 @@ void ospf_prune_unreachable_networks(struct route_table *rt)
                        or = rn->info;
                        if (listcount(or->paths) == 0) {
                                if (IS_DEBUG_OSPF_EVENT)
-                                       zlog_debug("Pruning route to %s/%d",
-                                                  inet_ntoa(rn->p.u.prefix4),
-                                                  rn->p.prefixlen);
+                                       zlog_debug("Pruning route to %pFX",
+                                                  &rn->p);
 
                                ospf_route_free(or);
                                rn->info = NULL;
@@ -926,13 +973,23 @@ void ospf_prune_unreachable_routers(struct route_table *rtrs)
                for (ALL_LIST_ELEMENTS(paths, node, nnode, or)) {
                        if (listcount(or->paths) == 0) {
                                if (IS_DEBUG_OSPF_EVENT) {
-                                       zlog_debug("Pruning route to rtr %s",
-                                                  inet_ntoa(rn->p.u.prefix4));
+                                       zlog_debug("Pruning route to rtr %pI4",
+                                                  &rn->p.u.prefix4);
                                        zlog_debug(
-                                               "               via area %s",
-                                               inet_ntoa(or->u.std.area_id));
+                                               "               via area %pI4",
+                                               &or->u.std.area_id);
                                }
 
+                               /* Unset the DNA flag on lsa, if the router
+                                * which generated this lsa is no longer
+                                * reachabele.
+                                */
+                               (CHECK_FLAG(or->u.std.origin->ls_age,
+                                           DO_NOT_AGE))
+                                       ? UNSET_FLAG(or->u.std.origin->ls_age,
+                                                    DO_NOT_AGE)
+                                       : 0;
+
                                listnode_delete(paths, or);
                                ospf_route_free(or);
                        }
@@ -940,8 +997,8 @@ void ospf_prune_unreachable_routers(struct route_table *rtrs)
 
                if (listcount(paths) == 0) {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug("Pruning router node %s",
-                                          inet_ntoa(rn->p.u.prefix4));
+                               zlog_debug("Pruning router node %pI4",
+                                          &rn->p.u.prefix4);
 
                        list_delete(&paths);
                        rn->info = NULL;
@@ -960,8 +1017,7 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
 
        if (rn == NULL) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_add_discard_route(): router installation error");
+                       zlog_debug("%s: router installation error", __func__);
                return 0;
        }
 
@@ -973,15 +1029,16 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
 
                if (or->path_type == OSPF_PATH_INTRA_AREA) {
                        if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_add_discard_route(): an intra-area route exists");
+                               zlog_debug("%s: an intra-area route exists",
+                                          __func__);
                        return 0;
                }
 
                if (or->type == OSPF_DESTINATION_DISCARD) {
                        if (IS_DEBUG_OSPF_EVENT)
                                zlog_debug(
-                                       "ospf_add_discard_route(): discard entry already installed");
+                                       "%s: discard entry already installed",
+                                       __func__);
                        return 0;
                }
 
@@ -989,7 +1046,7 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
        }
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_add_discard_route(): adding %pFX", p);
+               zlog_debug("%s: adding %pFX", __func__, p);
 
        new_or = ospf_route_new();
        new_or->type = OSPF_DESTINATION_DISCARD;
@@ -1012,14 +1069,13 @@ void ospf_delete_discard_route(struct ospf *ospf, struct route_table *rt,
        struct ospf_route * or ;
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("ospf_delete_discard_route(): deleting %pFX", p);
+               zlog_debug("%s: deleting %pFX", __func__, p);
 
        rn = route_node_lookup(rt, (struct prefix *)p);
 
        if (rn == NULL) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_delete_discard_route(): no route found");
+                       zlog_debug("%s: no route found", __func__);
                return;
        }
 
@@ -1027,15 +1083,13 @@ void ospf_delete_discard_route(struct ospf *ospf, struct route_table *rt,
 
        if (or->path_type == OSPF_PATH_INTRA_AREA) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_delete_discard_route(): an intra-area route exists");
+                       zlog_debug("%s: an intra-area route exists", __func__);
                return;
        }
 
        if (or->type != OSPF_DESTINATION_DISCARD) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug(
-                               "ospf_delete_discard_route(): not a discard entry");
+                       zlog_debug("%s: not a discard entry", __func__);
                return;
        }