+// 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;
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);
}
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,
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;
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))
/* 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: %pI4",
- &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
apply_mask_ipv4(&p);
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("ospf_intra_add_router: talking about %pFX", &p);
+ zlog_debug("%s: talking about %pFX", __func__, &p);
rn = route_node_get(rt, (struct prefix *)&p);
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. */
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;
apply_mask_ipv4(&p);
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("ospf_intra_add_stub(): processing route to %pFX",
- &p);
+ 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
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.
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
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;
}
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);
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;
}
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();
/* 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
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;
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[] = {
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))
- if (path->nexthop.s_addr != 0)
- vty_out(vty, " -> %pI4\n",
- &path->nexthop);
- else
- vty_out(vty, " -> %s\n",
- "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.
|| area->spf_dry_run) {
path = ospf_path_new();
path->nexthop = nexthop->router;
+ path->adv_router = v->id;
if (oi) {
path->ifindex = oi->ifp->ifindex;
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;
}
&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);
}
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;
}
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;
}
}
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;
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;
}
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;
}