mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 15:36:25 +00:00
458 lines
12 KiB
C
458 lines
12 KiB
C
/*
|
|
* OSPF BGP-IGP IGP metric update handling routines
|
|
* Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
|
|
* Madhurilatha Kuruganti
|
|
*
|
|
* This program 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 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>
|
|
#include <string.h>
|
|
|
|
#include "monotime.h"
|
|
#include "memory.h"
|
|
#include "thread.h"
|
|
#include "prefix.h"
|
|
#include "table.h"
|
|
#include "vty.h"
|
|
#include "command.h"
|
|
#include "plist.h"
|
|
#include "log.h"
|
|
#include "zclient.h"
|
|
#include <lib/json.h>
|
|
#include "defaults.h"
|
|
#include "orr_msg.h"
|
|
|
|
#include "ospfd.h"
|
|
#include "ospf_asbr.h"
|
|
#include "ospf_dump.h"
|
|
#include "ospf_lsa.h"
|
|
#include "ospf_orr.h"
|
|
#include "ospf_route.h"
|
|
#include "ospf_spf.h"
|
|
#include "ospf_te.h"
|
|
|
|
static void ospf_show_orr_root(struct orr_root *root);
|
|
void ospf_show_orr(struct ospf *ospf, afi_t afi, safi_t safi);
|
|
static struct orr_root *ospf_orr_root_new(struct ospf *ospf, afi_t afi,
|
|
safi_t safi, struct prefix *p)
|
|
{
|
|
struct list *orr_root_list = NULL;
|
|
struct orr_root *root = NULL;
|
|
|
|
if (!ospf->orr_root[afi][safi])
|
|
ospf->orr_root[afi][safi] = list_new();
|
|
|
|
orr_root_list = ospf->orr_root[afi][safi];
|
|
root = XCALLOC(MTYPE_OSPF_ORR_ROOT, sizeof(struct orr_root));
|
|
|
|
listnode_add(orr_root_list, root);
|
|
|
|
root->afi = afi;
|
|
root->safi = safi;
|
|
prefix_copy(&root->prefix, p);
|
|
IPV4_ADDR_COPY(&root->router_id, &p->u.prefix4);
|
|
root->new_rtrs = NULL;
|
|
root->new_table = NULL;
|
|
|
|
ospf_orr_debug("%s: For %s %s, created ORR Root entry %pFX.", __func__,
|
|
afi2str(afi), safi2str(safi), p);
|
|
|
|
return root;
|
|
}
|
|
|
|
static struct orr_root *ospf_orr_root_lookup(struct ospf *ospf, afi_t afi,
|
|
safi_t safi, struct in_addr *rid)
|
|
{
|
|
struct list *orr_root_list = NULL;
|
|
struct orr_root *root = NULL;
|
|
struct listnode *node;
|
|
|
|
orr_root_list = ospf->orr_root[afi][safi];
|
|
if (!orr_root_list)
|
|
return NULL;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root))
|
|
if (IPV4_ADDR_SAME(&root->router_id, rid))
|
|
return root;
|
|
|
|
ospf_orr_debug("%s: For %s %s, ORR Root '%pI4' not found.", __func__,
|
|
afi2str(afi), safi2str(safi), rid);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct orr_root *ospf_orr_root_lookup_by_adv_rid(struct ospf *ospf,
|
|
afi_t afi, safi_t safi,
|
|
struct in_addr *rid)
|
|
{
|
|
struct list *orr_root_list = NULL;
|
|
struct orr_root *root = NULL;
|
|
struct listnode *node;
|
|
|
|
orr_root_list = ospf->orr_root[afi][safi];
|
|
if (!orr_root_list)
|
|
return NULL;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root))
|
|
if (IPV4_ADDR_SAME(&root->adv_router, rid))
|
|
return root;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Lookup each area's LSDB if is there is any opaque area LSA received and
|
|
* update the root database with the advertising router.
|
|
*/
|
|
static struct ospf_lsa *
|
|
ospf_orr_lookup_opaque_area_lsa_by_id(struct in_addr rid)
|
|
{
|
|
struct ospf_lsa *lsa = NULL;
|
|
struct ospf_area *area = NULL;
|
|
struct ospf *ospf = NULL;
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
/* if ospf is not enabled ignore */
|
|
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
|
|
if (!ospf)
|
|
return NULL;
|
|
|
|
/* Lookup for Opaque area LSA in each area. */
|
|
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
|
|
lsa = ospf_lsa_lookup_by_mpls_te_rid(area, OSPF_OPAQUE_AREA_LSA,
|
|
rid);
|
|
if (!lsa)
|
|
continue;
|
|
ospf_orr_debug(
|
|
"%s: Opaque Area LSA found in area %pI4 for %pI4",
|
|
__func__, &area->area_id, &rid);
|
|
return lsa;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Lookup each area's LSDB if is there is any opaque area LSA received and
|
|
* update the root database with the advertising router.
|
|
*/
|
|
static struct ospf_lsa *ospf_orr_lookup_router_lsa_by_id(struct in_addr rid)
|
|
{
|
|
struct ospf_lsa *lsa = NULL;
|
|
struct ospf_area *area = NULL;
|
|
struct ospf *ospf = NULL;
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
/* if ospf is not enabled ignore */
|
|
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
|
|
if (!ospf)
|
|
return NULL;
|
|
|
|
/* Lookup for Router LSA in each area. */
|
|
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
|
|
lsa = ospf_lsa_lookup_by_adv_rid(area, OSPF_ROUTER_LSA, rid);
|
|
if (!lsa)
|
|
continue;
|
|
ospf_orr_debug("%s: Router LSA found in area %pI4 for %pI4",
|
|
__func__, &area->area_id, &rid);
|
|
return lsa;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* BGP-IGP IGP metric msg between BGP and IGP
|
|
*/
|
|
int ospf_orr_igp_metric_register(struct orr_igp_metric_reg msg)
|
|
{
|
|
afi_t afi;
|
|
safi_t safi;
|
|
struct ospf *ospf = NULL;
|
|
struct ospf_lsa *lsa = NULL;
|
|
struct orr_root *root = NULL;
|
|
|
|
/* if ospf is not enabled ignore */
|
|
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
|
|
if (!ospf)
|
|
return -1;
|
|
|
|
if (msg.proto != ZEBRA_ROUTE_BGP)
|
|
return -1;
|
|
|
|
afi = family2afi(msg.prefix.family);
|
|
safi = msg.safi;
|
|
|
|
ospf_orr_debug(
|
|
"%s: Received IGP metric %s message from BGP for location %pFX",
|
|
__func__, msg.reg ? "Register" : "Unregister", &msg.prefix);
|
|
|
|
/* Get ORR Root entry for the given address-family */
|
|
root = ospf_orr_root_lookup(ospf, afi, safi, &msg.prefix.u.prefix4);
|
|
|
|
/* Should not hit this condition */
|
|
if ((root && msg.reg) || (!root && !msg.reg))
|
|
return -1;
|
|
|
|
/* Create ORR Root entry and calculate SPF from root */
|
|
if (!root) {
|
|
root = ospf_orr_root_new(ospf, afi, safi, &msg.prefix);
|
|
if (!root) {
|
|
ospf_orr_debug(
|
|
"%s: For %s %s, Failed to create ORR Root entry %pFX.",
|
|
__func__, afi2str(afi), safi2str(safi),
|
|
&msg.prefix);
|
|
return -1;
|
|
}
|
|
ospf->orr_spf_request++;
|
|
|
|
lsa = ospf_orr_lookup_opaque_area_lsa_by_id(root->router_id);
|
|
if (!lsa || !lsa->data)
|
|
return -1;
|
|
|
|
IPV4_ADDR_COPY(&root->adv_router, &lsa->data->adv_router);
|
|
|
|
/* Lookup LSDB for Router LSA */
|
|
if (!root->router_lsa_rcvd) {
|
|
lsa = ospf_orr_lookup_router_lsa_by_id(
|
|
root->adv_router);
|
|
if (!lsa || !lsa->data)
|
|
return -1;
|
|
root->router_lsa_rcvd = lsa;
|
|
}
|
|
|
|
/* Compute SPF for all root nodes */
|
|
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ORR_ROOT_CHANGE);
|
|
}
|
|
/* Delete ORR Root entry. SPF calculation not required. */
|
|
else {
|
|
listnode_delete(ospf->orr_root[afi][safi], root);
|
|
XFREE(MTYPE_OSPF_ORR_ROOT, root);
|
|
|
|
/* If last node is deleted in the list */
|
|
if (!ospf->orr_root[afi][safi]->count)
|
|
list_delete(&ospf->orr_root[afi][safi]);
|
|
|
|
ospf->orr_spf_request--;
|
|
}
|
|
ospf_show_orr(ospf, afi, safi);
|
|
return 0;
|
|
}
|
|
|
|
void ospf_orr_igp_metric_send_update(struct orr_root *root,
|
|
unsigned short instance)
|
|
{
|
|
int ret;
|
|
uint8_t count = 0;
|
|
struct route_node *rn;
|
|
struct ospf_route *or;
|
|
struct orr_igp_metric_info msg;
|
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.proto = ZEBRA_ROUTE_OSPF;
|
|
msg.safi = root->safi;
|
|
msg.instId = instance;
|
|
prefix_copy(&msg.root, &root->prefix);
|
|
msg.num_entries = root->new_table->count;
|
|
|
|
/* Update prefix table from ORR Route table */
|
|
for (rn = route_top(root->new_table); rn; rn = route_next(rn)) {
|
|
or = rn->info;
|
|
if (!or)
|
|
continue;
|
|
|
|
if (or->type != OSPF_DESTINATION_NETWORK)
|
|
continue;
|
|
|
|
if (count < ORR_MAX_PREFIX) {
|
|
prefix_copy(&msg.nexthop[count].prefix,
|
|
(struct prefix_ipv4 *)&rn->p);
|
|
msg.nexthop[count].metric = or->cost;
|
|
count++;
|
|
} else {
|
|
msg.num_entries = count;
|
|
ret = zclient_send_opaque(zclient,
|
|
ORR_IGP_METRIC_UPDATE,
|
|
(uint8_t *)&msg, sizeof(msg));
|
|
if (ret != ZCLIENT_SEND_SUCCESS)
|
|
ospf_orr_debug(
|
|
"%s: Failed to send message to BGP.",
|
|
__func__);
|
|
count = 0;
|
|
prefix_copy(&msg.nexthop[count].prefix,
|
|
(struct prefix_ipv4 *)&rn->p);
|
|
msg.nexthop[count].metric = or->cost;
|
|
count++;
|
|
}
|
|
}
|
|
if (count <= ORR_MAX_PREFIX) {
|
|
msg.num_entries = count;
|
|
ret = zclient_send_opaque(zclient, ORR_IGP_METRIC_UPDATE,
|
|
(uint8_t *)&msg, sizeof(msg));
|
|
if (ret != ZCLIENT_SEND_SUCCESS)
|
|
ospf_orr_debug("%s: Failed to send message to BGP.",
|
|
__func__);
|
|
}
|
|
}
|
|
|
|
static void ospf_show_orr_root(struct orr_root *root)
|
|
{
|
|
if (!root)
|
|
return;
|
|
|
|
ospf_orr_debug("%s: Router-Address: %pI4:", __func__, &root->router_id);
|
|
ospf_orr_debug("%s: Advertising Router: %pI4:", __func__,
|
|
&root->adv_router);
|
|
}
|
|
|
|
void ospf_show_orr(struct ospf *ospf, afi_t afi, safi_t safi)
|
|
{
|
|
struct listnode *node = NULL;
|
|
struct orr_root *orr_root = NULL;
|
|
struct list *orr_root_list = NULL;
|
|
|
|
FOREACH_AFI_SAFI (afi, safi) {
|
|
orr_root_list = ospf->orr_root[afi][safi];
|
|
if (!orr_root_list)
|
|
return;
|
|
|
|
ospf_orr_debug("%s: For Address Family %s %s:", __func__,
|
|
afi2str(afi), safi2str(safi));
|
|
for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, orr_root))
|
|
ospf_show_orr_root(orr_root);
|
|
}
|
|
}
|
|
|
|
void ospf_orr_root_table_update(struct ospf_lsa *lsa, bool add)
|
|
{
|
|
afi_t afi;
|
|
safi_t safi;
|
|
struct lsa_header *lsah = lsa->data;
|
|
uint32_t lsid = ntohl(lsah->id.s_addr);
|
|
uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
|
|
uint32_t opaque_id = GET_OPAQUE_ID(lsid);
|
|
struct tlv_header *tlvh = TLV_HDR_TOP(lsah);
|
|
struct te_tlv_router_addr *router_addr = NULL;
|
|
struct orr_root *root = NULL;
|
|
struct ospf *ospf = NULL;
|
|
|
|
/* if ospf is not enabled ignore */
|
|
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
|
|
if (!ospf)
|
|
return;
|
|
|
|
if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
|
|
return;
|
|
|
|
if (!tlvh || (ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
|
|
(ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
|
|
return;
|
|
|
|
router_addr = (struct te_tlv_router_addr *)tlvh;
|
|
if (IS_DEBUG_OSPF_ORR) {
|
|
zlog_debug("[OSPF-ORR] %s: Opaque-area LSA %s LSDB", __func__,
|
|
add ? "added to" : "deleted from");
|
|
zlog_debug("[OSPF-ORR] %s: Opaque-Type %u (%s)", __func__,
|
|
opaque_type, "Traffic Engineering LSA");
|
|
zlog_debug("[OSPF-ORR] %s: Opaque-ID 0x%x", __func__,
|
|
opaque_id);
|
|
zlog_debug("[OSPF-ORR] %s: Opaque-Info: %u octets of data%s",
|
|
__func__, ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
|
|
VALID_OPAQUE_INFO_LEN(lsah) ? ""
|
|
: "(Invalid length?)");
|
|
zlog_debug("[OSPF-ORR] %s: Router-Address: %pI4", __func__,
|
|
&router_addr->value);
|
|
zlog_debug("[OSPF-ORR] %s: Advertising Router: %pI4", __func__,
|
|
&lsa->data->adv_router);
|
|
}
|
|
/*
|
|
* When Opaque LSA is added or removed from LSDB check if there is any
|
|
* change in MPLS-TE Router address and Advertising router address and
|
|
* update the table accordingly if there is no change in the mapping
|
|
* ignore update
|
|
*
|
|
* Get ORR Root entry for the given address-family
|
|
*/
|
|
FOREACH_AFI_SAFI (afi, safi) {
|
|
root = ospf_orr_root_lookup(ospf, afi, safi,
|
|
&router_addr->value);
|
|
if (root) {
|
|
IPV4_ADDR_COPY(&root->adv_router,
|
|
&lsa->data->adv_router);
|
|
ospf_show_orr(ospf, afi, safi);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ospf_orr_root_update_rcvd_lsa(struct ospf_lsa *lsa)
|
|
{
|
|
afi_t afi;
|
|
safi_t safi;
|
|
struct orr_root *root = NULL;
|
|
|
|
if (!lsa || !lsa->area || !lsa->area->ospf)
|
|
return;
|
|
|
|
FOREACH_AFI_SAFI (afi, safi) {
|
|
root = ospf_orr_root_lookup_by_adv_rid(
|
|
lsa->area->ospf, afi, safi, &lsa->data->adv_router);
|
|
if (!root)
|
|
continue;
|
|
|
|
ospf_orr_debug("%s: Received LSA[Type%d:%pI4]", __func__,
|
|
lsa->data->type, &lsa->data->adv_router);
|
|
|
|
root->router_lsa_rcvd = lsa;
|
|
/* Compute SPF for all root nodes */
|
|
ospf_spf_calculate_schedule(lsa->area->ospf,
|
|
SPF_FLAG_ORR_ROOT_CHANGE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Install routes to root table. */
|
|
void ospf_orr_route_install(struct orr_root *root, struct route_table *rt)
|
|
{
|
|
struct route_node *rn;
|
|
struct ospf_route *or;
|
|
|
|
/*
|
|
* rt contains new routing table, new_table contains an old one.
|
|
* updating pointers
|
|
*/
|
|
if (root->old_table)
|
|
ospf_route_table_free(root->old_table);
|
|
|
|
root->old_table = root->new_table;
|
|
root->new_table = rt;
|
|
|
|
/* Install new routes. */
|
|
for (rn = route_top(rt); rn; rn = route_next(rn)) {
|
|
or = rn->info;
|
|
if (or) {
|
|
if (or->type == OSPF_DESTINATION_NETWORK) {
|
|
if (!ospf_route_match_same(
|
|
root->old_table,
|
|
(struct prefix_ipv4 *)&rn->p, or)) {
|
|
}
|
|
} else if (or->type == OSPF_DESTINATION_DISCARD)
|
|
if (!ospf_route_match_same(
|
|
root->old_table,
|
|
(struct prefix_ipv4 *)&rn->p, or)) {
|
|
}
|
|
}
|
|
}
|
|
}
|