mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-29 06:29:40 +00:00
Merge pull request #11159 from maduri111/bgpd-orr
bgpd: optimal route reflection
This commit is contained in:
commit
984eb32b58
@ -71,6 +71,7 @@ unsigned long conf_bgp_debug_graceful_restart;
|
|||||||
unsigned long conf_bgp_debug_evpn_mh;
|
unsigned long conf_bgp_debug_evpn_mh;
|
||||||
unsigned long conf_bgp_debug_bfd;
|
unsigned long conf_bgp_debug_bfd;
|
||||||
unsigned long conf_bgp_debug_cond_adv;
|
unsigned long conf_bgp_debug_cond_adv;
|
||||||
|
unsigned long conf_bgp_debug_optimal_route_reflection;
|
||||||
|
|
||||||
unsigned long term_bgp_debug_as4;
|
unsigned long term_bgp_debug_as4;
|
||||||
unsigned long term_bgp_debug_neighbor_events;
|
unsigned long term_bgp_debug_neighbor_events;
|
||||||
@ -92,6 +93,7 @@ unsigned long term_bgp_debug_graceful_restart;
|
|||||||
unsigned long term_bgp_debug_evpn_mh;
|
unsigned long term_bgp_debug_evpn_mh;
|
||||||
unsigned long term_bgp_debug_bfd;
|
unsigned long term_bgp_debug_bfd;
|
||||||
unsigned long term_bgp_debug_cond_adv;
|
unsigned long term_bgp_debug_cond_adv;
|
||||||
|
unsigned long term_bgp_debug_optimal_route_reflection;
|
||||||
|
|
||||||
struct list *bgp_debug_neighbor_events_peers = NULL;
|
struct list *bgp_debug_neighbor_events_peers = NULL;
|
||||||
struct list *bgp_debug_keepalive_peers = NULL;
|
struct list *bgp_debug_keepalive_peers = NULL;
|
||||||
@ -2044,6 +2046,33 @@ DEFPY (debug_bgp_evpn_mh,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (debug_bgp_optimal_route_reflection,
|
||||||
|
debug_bgp_optimal_route_reflection_cmd,
|
||||||
|
"[no$no] debug bgp optimal-route-reflection",
|
||||||
|
NO_STR
|
||||||
|
DEBUG_STR
|
||||||
|
BGP_STR
|
||||||
|
BGP_ORR_DEBUG)
|
||||||
|
{
|
||||||
|
if (vty->node == CONFIG_NODE) {
|
||||||
|
if (no)
|
||||||
|
DEBUG_OFF(optimal_route_reflection, ORR);
|
||||||
|
else
|
||||||
|
DEBUG_ON(optimal_route_reflection, ORR);
|
||||||
|
} else {
|
||||||
|
if (no) {
|
||||||
|
TERM_DEBUG_OFF(optimal_route_reflection, ORR);
|
||||||
|
vty_out(vty,
|
||||||
|
"BGP Optimal Route Reflection debugging is off\n");
|
||||||
|
} else {
|
||||||
|
TERM_DEBUG_ON(optimal_route_reflection, ORR);
|
||||||
|
vty_out(vty,
|
||||||
|
"BGP Optimal Route Reflection debugging is on\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (debug_bgp_labelpool,
|
DEFUN (debug_bgp_labelpool,
|
||||||
debug_bgp_labelpool_cmd,
|
debug_bgp_labelpool_cmd,
|
||||||
"debug bgp labelpool",
|
"debug bgp labelpool",
|
||||||
@ -2182,6 +2211,7 @@ DEFUN (no_debug_bgp,
|
|||||||
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
|
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
|
||||||
TERM_DEBUG_OFF(bfd, BFD_LIB);
|
TERM_DEBUG_OFF(bfd, BFD_LIB);
|
||||||
TERM_DEBUG_OFF(cond_adv, COND_ADV);
|
TERM_DEBUG_OFF(cond_adv, COND_ADV);
|
||||||
|
TERM_DEBUG_OFF(optimal_route_reflection, ORR);
|
||||||
|
|
||||||
vty_out(vty, "All possible debugging has been turned off\n");
|
vty_out(vty, "All possible debugging has been turned off\n");
|
||||||
|
|
||||||
@ -2278,6 +2308,10 @@ DEFUN_NOSH (show_debugging_bgp,
|
|||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" BGP conditional advertisement debugging is on\n");
|
" BGP conditional advertisement debugging is on\n");
|
||||||
|
|
||||||
|
if (BGP_DEBUG(optimal_route_reflection, ORR))
|
||||||
|
vty_out(vty,
|
||||||
|
" BGP Optimal Route Reflection debugging is on\n");
|
||||||
|
|
||||||
cmd_show_lib_debugs(vty);
|
cmd_show_lib_debugs(vty);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@ -2414,6 +2448,11 @@ static int bgp_config_write_debug(struct vty *vty)
|
|||||||
write++;
|
write++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CONF_BGP_DEBUG(optimal_route_reflection, ORR)) {
|
||||||
|
vty_out(vty, "debug bgp optimal-route-reflection\n");
|
||||||
|
write++;
|
||||||
|
}
|
||||||
|
|
||||||
return write;
|
return write;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2546,6 +2585,10 @@ void bgp_debug_init(void)
|
|||||||
/* debug bgp conditional advertisement */
|
/* debug bgp conditional advertisement */
|
||||||
install_element(ENABLE_NODE, &debug_bgp_cond_adv_cmd);
|
install_element(ENABLE_NODE, &debug_bgp_cond_adv_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_bgp_cond_adv_cmd);
|
install_element(CONFIG_NODE, &debug_bgp_cond_adv_cmd);
|
||||||
|
|
||||||
|
/* debug bgp optimal route reflection */
|
||||||
|
install_element(ENABLE_NODE, &debug_bgp_optimal_route_reflection_cmd);
|
||||||
|
install_element(CONFIG_NODE, &debug_bgp_optimal_route_reflection_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
|
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
|
||||||
|
@ -81,6 +81,7 @@ extern unsigned long conf_bgp_debug_graceful_restart;
|
|||||||
extern unsigned long conf_bgp_debug_evpn_mh;
|
extern unsigned long conf_bgp_debug_evpn_mh;
|
||||||
extern unsigned long conf_bgp_debug_bfd;
|
extern unsigned long conf_bgp_debug_bfd;
|
||||||
extern unsigned long conf_bgp_debug_cond_adv;
|
extern unsigned long conf_bgp_debug_cond_adv;
|
||||||
|
extern unsigned long conf_bgp_debug_optimal_route_reflection;
|
||||||
|
|
||||||
extern unsigned long term_bgp_debug_as4;
|
extern unsigned long term_bgp_debug_as4;
|
||||||
extern unsigned long term_bgp_debug_neighbor_events;
|
extern unsigned long term_bgp_debug_neighbor_events;
|
||||||
@ -100,6 +101,7 @@ extern unsigned long term_bgp_debug_graceful_restart;
|
|||||||
extern unsigned long term_bgp_debug_evpn_mh;
|
extern unsigned long term_bgp_debug_evpn_mh;
|
||||||
extern unsigned long term_bgp_debug_bfd;
|
extern unsigned long term_bgp_debug_bfd;
|
||||||
extern unsigned long term_bgp_debug_cond_adv;
|
extern unsigned long term_bgp_debug_cond_adv;
|
||||||
|
extern unsigned long term_bgp_debug_optimal_route_reflection;
|
||||||
|
|
||||||
extern struct list *bgp_debug_neighbor_events_peers;
|
extern struct list *bgp_debug_neighbor_events_peers;
|
||||||
extern struct list *bgp_debug_keepalive_peers;
|
extern struct list *bgp_debug_keepalive_peers;
|
||||||
@ -138,6 +140,7 @@ struct bgp_debug_filter {
|
|||||||
#define BGP_DEBUG_PBR_ERROR 0x02
|
#define BGP_DEBUG_PBR_ERROR 0x02
|
||||||
#define BGP_DEBUG_EVPN_MH_ES 0x01
|
#define BGP_DEBUG_EVPN_MH_ES 0x01
|
||||||
#define BGP_DEBUG_EVPN_MH_RT 0x02
|
#define BGP_DEBUG_EVPN_MH_RT 0x02
|
||||||
|
#define BGP_DEBUG_ORR 0x01
|
||||||
|
|
||||||
#define BGP_DEBUG_PACKET_SEND 0x01
|
#define BGP_DEBUG_PACKET_SEND 0x01
|
||||||
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
|
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
|
||||||
|
@ -1330,6 +1330,9 @@ void bgp_fsm_change_status(struct peer *peer, int status)
|
|||||||
&& bgp_update_delay_applicable(peer->bgp))
|
&& bgp_update_delay_applicable(peer->bgp))
|
||||||
bgp_update_delay_process_status_change(peer);
|
bgp_update_delay_process_status_change(peer);
|
||||||
|
|
||||||
|
/* BGP ORR : Update Active Root */
|
||||||
|
bgp_peer_update_orr_active_roots(peer);
|
||||||
|
|
||||||
if (bgp_debug_neighbor_events(peer))
|
if (bgp_debug_neighbor_events(peer))
|
||||||
zlog_debug("%s went from %s to %s", peer->host,
|
zlog_debug("%s went from %s to %s", peer->host,
|
||||||
lookup_msg(bgp_status_msg, peer->ostatus, NULL),
|
lookup_msg(bgp_status_msg, peer->ostatus, NULL),
|
||||||
|
@ -175,4 +175,6 @@ const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
|
|||||||
const char *print_global_gr_mode(enum global_mode gl_mode);
|
const char *print_global_gr_mode(enum global_mode gl_mode);
|
||||||
const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
|
const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
|
||||||
int bgp_peer_reg_with_nht(struct peer *peer);
|
int bgp_peer_reg_with_nht(struct peer *peer);
|
||||||
|
|
||||||
|
extern void bgp_peer_update_orr_active_roots(struct peer *peer);
|
||||||
#endif /* _QUAGGA_BGP_FSM_H */
|
#endif /* _QUAGGA_BGP_FSM_H */
|
||||||
|
@ -134,8 +134,12 @@ DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT");
|
|||||||
|
|
||||||
DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
|
DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
|
||||||
DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
|
DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
|
||||||
|
|
||||||
DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
|
DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
|
||||||
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
|
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
|
||||||
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
|
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
|
||||||
|
|
||||||
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
|
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
|
||||||
|
DEFINE_MTYPE(BGPD, BGP_ORR_GROUP, "BGP Optimal Route Reflection Group");
|
||||||
|
DEFINE_MTYPE(BGPD, BGP_ORR_GROUP_NAME,
|
||||||
|
"BGP Optimal Route Reflection Group Name");
|
||||||
|
@ -137,5 +137,7 @@ DECLARE_MTYPE(BGP_SRV6_FUNCTION);
|
|||||||
DECLARE_MTYPE(EVPN_REMOTE_IP);
|
DECLARE_MTYPE(EVPN_REMOTE_IP);
|
||||||
|
|
||||||
DECLARE_MTYPE(BGP_NOTIFICATION);
|
DECLARE_MTYPE(BGP_NOTIFICATION);
|
||||||
|
DECLARE_MTYPE(BGP_ORR_GROUP);
|
||||||
|
DECLARE_MTYPE(BGP_ORR_GROUP_NAME);
|
||||||
|
|
||||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||||
|
1176
bgpd/bgp_orr.c
Normal file
1176
bgpd/bgp_orr.c
Normal file
File diff suppressed because it is too large
Load Diff
102
bgpd/bgp_orr.h
Normal file
102
bgpd/bgp_orr.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* BGP Optimal Route Reflection
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_BGP_ORR_H
|
||||||
|
#define _FRR_BGP_ORR_H
|
||||||
|
#include <zebra.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macro to log debug message */
|
||||||
|
#define bgp_orr_debug(...) \
|
||||||
|
do { \
|
||||||
|
if (BGP_DEBUG(optimal_route_reflection, ORR)) \
|
||||||
|
zlog_debug("[BGP-ORR] " __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/* BGP ORR Message Type */
|
||||||
|
enum bgp_orr_msg_type {
|
||||||
|
BGP_ORR_IMSG_INVALID = 0,
|
||||||
|
|
||||||
|
/* ORR group update */
|
||||||
|
BGP_ORR_IMSG_GROUP_CREATE = 1,
|
||||||
|
BGP_ORR_IMSG_GROUP_DELETE,
|
||||||
|
BGP_ORR_IMSG_GROUP_UPDATE,
|
||||||
|
|
||||||
|
/* ORR group update on a BGP RR Client */
|
||||||
|
BGP_ORR_IMSG_SET_ORR_ON_PEER = 4,
|
||||||
|
BGP_ORR_IMSG_UNSET_ORR_ON_PEER,
|
||||||
|
|
||||||
|
/* ORR IGP Metric Update from IGP from requested Location */
|
||||||
|
BGP_ORR_IMSG_IGP_METRIC_UPDATE = 6,
|
||||||
|
|
||||||
|
/* ORR Group Related Information display */
|
||||||
|
BGP_ORR_IMSG_SHOW_ORR = 7,
|
||||||
|
BGP_ORR_IMSG_SHOW_ORR_GROUP,
|
||||||
|
|
||||||
|
/* Invalid Message Type*/
|
||||||
|
BGP_ORR_IMSG_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct zclient *zclient;
|
||||||
|
|
||||||
|
extern void bgp_config_write_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||||
|
safi_t safi);
|
||||||
|
|
||||||
|
extern int bgp_afi_safi_orr_group_set_vty(struct vty *vty, afi_t afi,
|
||||||
|
safi_t safi, const char *name,
|
||||||
|
const char *primary_str,
|
||||||
|
const char *secondary_str,
|
||||||
|
const char *tertiary_str, bool unset);
|
||||||
|
extern int peer_orr_group_unset(struct peer *peer, afi_t afi, safi_t safi,
|
||||||
|
const char *orr_group_name);
|
||||||
|
extern int peer_orr_group_set_vty(struct vty *vty, const char *ip_str,
|
||||||
|
afi_t afi, safi_t safi,
|
||||||
|
const char *orr_group_name, bool unset);
|
||||||
|
extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
|
||||||
|
|
||||||
|
extern int bgp_show_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||||
|
safi_t safi, const char *orr_group_name,
|
||||||
|
uint8_t show_flags);
|
||||||
|
|
||||||
|
extern int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||||
|
const char *name, struct peer *primary,
|
||||||
|
struct peer *secondary,
|
||||||
|
struct peer *tertiary);
|
||||||
|
extern int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
extern void bgp_peer_update_orr_active_roots(struct peer *peer);
|
||||||
|
|
||||||
|
extern int bgg_orr_message_process(enum bgp_orr_msg_type msg_type, void *msg);
|
||||||
|
|
||||||
|
extern struct bgp_orr_group *bgp_orr_group_lookup_by_name(struct bgp *bgp,
|
||||||
|
afi_t afi,
|
||||||
|
safi_t safi,
|
||||||
|
const char *name);
|
||||||
|
extern void bgp_orr_cleanup(struct bgp *bgp);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FRR_BGP_ORR_H */
|
@ -72,6 +72,7 @@
|
|||||||
#include "bgpd/bgp_addpath.h"
|
#include "bgpd/bgp_addpath.h"
|
||||||
#include "bgpd/bgp_mac.h"
|
#include "bgpd/bgp_mac.h"
|
||||||
#include "bgpd/bgp_network.h"
|
#include "bgpd/bgp_network.h"
|
||||||
|
#include "bgpd/bgp_orr.h"
|
||||||
#include "bgpd/bgp_trace.h"
|
#include "bgpd/bgp_trace.h"
|
||||||
#include "bgpd/bgp_rpki.h"
|
#include "bgpd/bgp_rpki.h"
|
||||||
|
|
||||||
@ -567,6 +568,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||||||
enum bgp_path_selection_reason *reason)
|
enum bgp_path_selection_reason *reason)
|
||||||
{
|
{
|
||||||
const struct prefix *new_p;
|
const struct prefix *new_p;
|
||||||
|
struct prefix exist_p;
|
||||||
struct attr *newattr, *existattr;
|
struct attr *newattr, *existattr;
|
||||||
enum bgp_peer_sort new_sort;
|
enum bgp_peer_sort new_sort;
|
||||||
enum bgp_peer_sort exist_sort;
|
enum bgp_peer_sort exist_sort;
|
||||||
@ -599,6 +601,11 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||||||
bool new_origin, exist_origin;
|
bool new_origin, exist_origin;
|
||||||
struct bgp_path_info *bpi_ultimate;
|
struct bgp_path_info *bpi_ultimate;
|
||||||
|
|
||||||
|
struct bgp_orr_group *orr_group = NULL;
|
||||||
|
struct listnode *node;
|
||||||
|
struct bgp_orr_igp_metric *igp_metric = NULL;
|
||||||
|
struct list *orr_group_igp_metric_info = NULL;
|
||||||
|
|
||||||
*paths_eq = 0;
|
*paths_eq = 0;
|
||||||
|
|
||||||
/* 0. Null check. */
|
/* 0. Null check. */
|
||||||
@ -1061,6 +1068,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||||||
if (exist->extra)
|
if (exist->extra)
|
||||||
existm = exist->extra->igpmetric;
|
existm = exist->extra->igpmetric;
|
||||||
|
|
||||||
|
if (new->peer->orr_group_name[afi][safi]) {
|
||||||
|
ret = str2prefix(new->peer->host, &exist_p);
|
||||||
|
orr_group = bgp_orr_group_lookup_by_name(
|
||||||
|
bgp, afi, safi, new->peer->orr_group_name[afi][safi]);
|
||||||
|
if (orr_group) {
|
||||||
|
orr_group_igp_metric_info = orr_group->igp_metric_info;
|
||||||
|
if (orr_group_igp_metric_info) {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(
|
||||||
|
orr_group_igp_metric_info, node,
|
||||||
|
igp_metric)) {
|
||||||
|
if (ret &&
|
||||||
|
prefix_cmp(&exist_p,
|
||||||
|
&igp_metric->prefix) ==
|
||||||
|
0) {
|
||||||
|
newm = igp_metric->igp_metric;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exist->peer->orr_group_name[afi][safi]) {
|
||||||
|
ret = str2prefix(exist->peer->host, &exist_p);
|
||||||
|
orr_group = bgp_orr_group_lookup_by_name(
|
||||||
|
bgp, afi, safi, exist->peer->orr_group_name[afi][safi]);
|
||||||
|
if (orr_group) {
|
||||||
|
orr_group_igp_metric_info = orr_group->igp_metric_info;
|
||||||
|
if (orr_group_igp_metric_info) {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(
|
||||||
|
orr_group_igp_metric_info, node,
|
||||||
|
igp_metric)) {
|
||||||
|
if (ret &&
|
||||||
|
prefix_cmp(&exist_p,
|
||||||
|
&igp_metric->prefix) ==
|
||||||
|
0) {
|
||||||
|
existm = igp_metric->igp_metric;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (newm < existm) {
|
if (newm < existm) {
|
||||||
if (debug && peer_sort_ret < 0)
|
if (debug && peer_sort_ret < 0)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
@ -12406,6 +12456,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|
|||||||
|alias ALIAS_NAME\
|
|alias ALIAS_NAME\
|
||||||
|A.B.C.D/M longer-prefixes\
|
|A.B.C.D/M longer-prefixes\
|
||||||
|X:X::X:X/M longer-prefixes\
|
|X:X::X:X/M longer-prefixes\
|
||||||
|
|optimal-route-reflection [WORD$orr_group_name]\
|
||||||
] [json$uj [detail$detail] | wide$wide]",
|
] [json$uj [detail$detail] | wide$wide]",
|
||||||
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
|
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
|
||||||
BGP_SAFI_WITH_LABEL_HELP_STR
|
BGP_SAFI_WITH_LABEL_HELP_STR
|
||||||
@ -12454,6 +12505,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|
|||||||
"Display route and more specific routes\n"
|
"Display route and more specific routes\n"
|
||||||
"IPv6 prefix\n"
|
"IPv6 prefix\n"
|
||||||
"Display route and more specific routes\n"
|
"Display route and more specific routes\n"
|
||||||
|
"Display Optimal Route Reflection RR Clients\n"
|
||||||
|
"ORR Group name\n"
|
||||||
JSON_STR
|
JSON_STR
|
||||||
"Display detailed version of JSON output\n"
|
"Display detailed version of JSON output\n"
|
||||||
"Increase table width for longer prefixes\n")
|
"Increase table width for longer prefixes\n")
|
||||||
@ -12470,6 +12523,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|
|||||||
uint16_t show_flags = 0;
|
uint16_t show_flags = 0;
|
||||||
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
|
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
|
bool orr_group = false;
|
||||||
|
|
||||||
if (uj) {
|
if (uj) {
|
||||||
argc--;
|
argc--;
|
||||||
@ -12644,12 +12698,18 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|
|||||||
output_arg = &p;
|
output_arg = &p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argv_find(argv, argc, "optimal-route-reflection", &idx))
|
||||||
|
orr_group = true;
|
||||||
|
|
||||||
if (!all) {
|
if (!all) {
|
||||||
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
|
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
|
||||||
if (community)
|
if (community)
|
||||||
return bgp_show_community(vty, bgp, community,
|
return bgp_show_community(vty, bgp, community,
|
||||||
exact_match, afi, safi,
|
exact_match, afi, safi,
|
||||||
show_flags);
|
show_flags);
|
||||||
|
else if (orr_group)
|
||||||
|
return bgp_show_orr(vty, bgp, afi, safi, orr_group_name,
|
||||||
|
show_flags);
|
||||||
else
|
else
|
||||||
return bgp_show(vty, bgp, afi, safi, sh_type,
|
return bgp_show(vty, bgp, afi, safi, sh_type,
|
||||||
output_arg, show_flags,
|
output_arg, show_flags,
|
||||||
@ -12695,6 +12755,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|
|||||||
vty, abgp, community,
|
vty, abgp, community,
|
||||||
exact_match, afi, safi,
|
exact_match, afi, safi,
|
||||||
show_flags);
|
show_flags);
|
||||||
|
else if (orr_group)
|
||||||
|
bgp_show_orr(vty, bgp, afi,
|
||||||
|
safi,
|
||||||
|
orr_group_name,
|
||||||
|
show_flags);
|
||||||
else
|
else
|
||||||
bgp_show(vty, abgp, afi, safi,
|
bgp_show(vty, abgp, afi, safi,
|
||||||
sh_type, output_arg,
|
sh_type, output_arg,
|
||||||
@ -12734,6 +12799,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|
|||||||
vty, abgp, community,
|
vty, abgp, community,
|
||||||
exact_match, afi, safi,
|
exact_match, afi, safi,
|
||||||
show_flags);
|
show_flags);
|
||||||
|
else if (orr_group)
|
||||||
|
bgp_show_orr(vty, bgp, afi,
|
||||||
|
safi,
|
||||||
|
orr_group_name,
|
||||||
|
show_flags);
|
||||||
else
|
else
|
||||||
bgp_show(vty, abgp, afi, safi,
|
bgp_show(vty, abgp, afi, safi,
|
||||||
sh_type, output_arg,
|
sh_type, output_arg,
|
||||||
|
@ -78,6 +78,8 @@
|
|||||||
#ifdef ENABLE_BGP_VNC
|
#ifdef ENABLE_BGP_VNC
|
||||||
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "bgpd/bgp_orr.h"
|
||||||
|
|
||||||
|
|
||||||
FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
|
FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
|
||||||
{
|
{
|
||||||
@ -945,6 +947,9 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
|
|||||||
case BGP_ERR_INVALID_INTERNAL_ROLE:
|
case BGP_ERR_INVALID_INTERNAL_ROLE:
|
||||||
str = "External roles can be set only on eBGP session";
|
str = "External roles can be set only on eBGP session";
|
||||||
break;
|
break;
|
||||||
|
case BGP_ERR_PEER_ORR_CONFIGURED:
|
||||||
|
str = "Deconfigure optimal-route-reflection on this peer first";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (str) {
|
if (str) {
|
||||||
vty_out(vty, "%% %s\n", str);
|
vty_out(vty, "%% %s\n", str);
|
||||||
@ -6201,6 +6206,43 @@ ALIAS_HIDDEN(no_neighbor_route_reflector_client,
|
|||||||
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
|
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
|
||||||
"Configure a neighbor as Route Reflector client\n")
|
"Configure a neighbor as Route Reflector client\n")
|
||||||
|
|
||||||
|
/* optimal-route-reflection Root Routers configuration */
|
||||||
|
DEFPY (optimal_route_reflection,
|
||||||
|
optimal_route_reflection_cmd,
|
||||||
|
"[no$no] optimal-route-reflection WORD$orr_group [<A.B.C.D|X:X::X:X>$primary [<A.B.C.D|X:X::X:X>$secondary [<A.B.C.D|X:X::X:X>$tertiary]]]",
|
||||||
|
NO_STR
|
||||||
|
"Create ORR group and assign root router(s)\n"
|
||||||
|
"ORR Group name\n"
|
||||||
|
"Primary Root address\n"
|
||||||
|
"Primary Root IPv6 address\n"
|
||||||
|
"Secondary Root address\n"
|
||||||
|
"Secondary Root IPv6 address\n"
|
||||||
|
"Tertiary Root address\n"
|
||||||
|
"Tertiary Root IPv6 address\n")
|
||||||
|
{
|
||||||
|
if (!no && !primary) {
|
||||||
|
vty_out(vty, "%% Specify Primary Root address\n");
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
return bgp_afi_safi_orr_group_set_vty(
|
||||||
|
vty, bgp_node_afi(vty), bgp_node_safi(vty), orr_group,
|
||||||
|
primary_str, secondary_str, tertiary_str, !!no);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* neighbor optimal-route-reflection group*/
|
||||||
|
DEFPY (neighbor_optimal_route_reflection,
|
||||||
|
neighbor_optimal_route_reflection_cmd,
|
||||||
|
"[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor optimal-route-reflection WORD$orr_group",
|
||||||
|
NO_STR
|
||||||
|
NEIGHBOR_STR
|
||||||
|
NEIGHBOR_ADDR_STR2
|
||||||
|
"Apply ORR group configuration to the neighbor\n"
|
||||||
|
"ORR group name\n")
|
||||||
|
{
|
||||||
|
return peer_orr_group_set_vty(vty, neighbor, bgp_node_afi(vty),
|
||||||
|
bgp_node_safi(vty), orr_group, !!no);
|
||||||
|
}
|
||||||
|
|
||||||
/* neighbor route-server-client. */
|
/* neighbor route-server-client. */
|
||||||
DEFUN (neighbor_route_server_client,
|
DEFUN (neighbor_route_server_client,
|
||||||
neighbor_route_server_client_cmd,
|
neighbor_route_server_client_cmd,
|
||||||
@ -12388,6 +12430,11 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
|
|||||||
if (CHECK_FLAG(p->af_flags[afi][safi],
|
if (CHECK_FLAG(p->af_flags[afi][safi],
|
||||||
PEER_FLAG_RSERVER_CLIENT))
|
PEER_FLAG_RSERVER_CLIENT))
|
||||||
vty_out(vty, " Route-Server Client\n");
|
vty_out(vty, " Route-Server Client\n");
|
||||||
|
|
||||||
|
if (peer_af_flag_check(p, afi, safi, PEER_FLAG_ORR_GROUP))
|
||||||
|
vty_out(vty, " ORR group (configured) : %s\n",
|
||||||
|
p->orr_group_name[afi][safi]);
|
||||||
|
|
||||||
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
|
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" Inbound soft reconfiguration allowed\n");
|
" Inbound soft reconfiguration allowed\n");
|
||||||
@ -17364,6 +17411,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
|
|||||||
: "");
|
: "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP))
|
||||||
|
vty_out(vty, " neighbor %s optimal-route-reflection %s\n",
|
||||||
|
addr, peer->orr_group_name[afi][safi]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
|
static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||||
@ -17470,6 +17521,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Optimal Route Reflection */
|
||||||
|
bgp_config_write_orr(vty, bgp, afi, safi);
|
||||||
|
|
||||||
vty_endframe(vty, " exit-address-family\n");
|
vty_endframe(vty, " exit-address-family\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18979,6 +19033,34 @@ void bgp_vty_init(void)
|
|||||||
install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
|
install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
|
||||||
install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
|
install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
|
||||||
|
|
||||||
|
/* "optimal-route-reflection" commands */
|
||||||
|
install_element(BGP_IPV4_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV4M_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV4L_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV6_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV6M_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV6L_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_VPNV4_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_VPNV6_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_FLOWSPECV4_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_FLOWSPECV6_NODE, &optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_EVPN_NODE, &optimal_route_reflection_cmd);
|
||||||
|
|
||||||
|
/* "neighbor optimal-route-reflection" commands */
|
||||||
|
install_element(BGP_IPV4_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV4M_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV4L_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV6_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV6M_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_IPV6L_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_VPNV4_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_VPNV6_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_FLOWSPECV4_NODE,
|
||||||
|
&neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_FLOWSPECV6_NODE,
|
||||||
|
&neighbor_optimal_route_reflection_cmd);
|
||||||
|
install_element(BGP_EVPN_NODE, &neighbor_optimal_route_reflection_cmd);
|
||||||
|
|
||||||
/* "neighbor route-server" commands.*/
|
/* "neighbor route-server" commands.*/
|
||||||
install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
|
install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
|
||||||
install_element(BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
|
install_element(BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
|
||||||
|
@ -67,10 +67,13 @@
|
|||||||
#include "bgpd/bgp_trace.h"
|
#include "bgpd/bgp_trace.h"
|
||||||
#include "bgpd/bgp_community.h"
|
#include "bgpd/bgp_community.h"
|
||||||
#include "bgpd/bgp_lcommunity.h"
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
|
#include "bgpd/bgp_orr.h"
|
||||||
|
|
||||||
/* All information about zebra. */
|
/* All information about zebra. */
|
||||||
struct zclient *zclient = NULL;
|
struct zclient *zclient = NULL;
|
||||||
|
|
||||||
|
static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
|
||||||
|
|
||||||
/* hook to indicate vrf status change for SNMP */
|
/* hook to indicate vrf status change for SNMP */
|
||||||
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
|
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
|
||||||
(bgp, ifp));
|
(bgp, ifp));
|
||||||
@ -3388,6 +3391,7 @@ static zclient_handler *const bgp_handlers[] = {
|
|||||||
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
|
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
|
||||||
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
|
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
|
||||||
bgp_zebra_process_srv6_locator_chunk,
|
bgp_zebra_process_srv6_locator_chunk,
|
||||||
|
[ZEBRA_OPAQUE_MESSAGE] = bgp_opaque_msg_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int bgp_if_new_hook(struct interface *ifp)
|
static int bgp_if_new_hook(struct interface *ifp)
|
||||||
@ -3842,3 +3846,34 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
|
|||||||
{
|
{
|
||||||
return srv6_manager_release_locator_chunk(zclient, name);
|
return srv6_manager_release_locator_chunk(zclient, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ORR messages between processes
|
||||||
|
*/
|
||||||
|
static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
||||||
|
{
|
||||||
|
struct stream *s;
|
||||||
|
struct zapi_opaque_msg info;
|
||||||
|
struct orr_igp_metric_info table;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
s = zclient->ibuf;
|
||||||
|
|
||||||
|
if (zclient_opaque_decode(s, &info) != 0) {
|
||||||
|
bgp_orr_debug("%s: opaque decode failed", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (info.type) {
|
||||||
|
case ORR_IGP_METRIC_UPDATE:
|
||||||
|
STREAM_GET(&table, s, sizeof(table));
|
||||||
|
ret = bgg_orr_message_process(BGP_ORR_IMSG_IGP_METRIC_UPDATE,
|
||||||
|
(void *)&table);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_failure:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
15
bgpd/bgpd.c
15
bgpd/bgpd.c
@ -92,6 +92,7 @@
|
|||||||
#include "bgpd/bgp_evpn_private.h"
|
#include "bgpd/bgp_evpn_private.h"
|
||||||
#include "bgpd/bgp_evpn_mh.h"
|
#include "bgpd/bgp_evpn_mh.h"
|
||||||
#include "bgpd/bgp_mac.h"
|
#include "bgpd/bgp_mac.h"
|
||||||
|
#include "bgpd/bgp_orr.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
|
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
|
||||||
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
|
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
|
||||||
@ -1839,6 +1840,8 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
|
|||||||
/* Change peer's AS number. */
|
/* Change peer's AS number. */
|
||||||
void peer_as_change(struct peer *peer, as_t as, int as_specified)
|
void peer_as_change(struct peer *peer, as_t as, int as_specified)
|
||||||
{
|
{
|
||||||
|
afi_t afi;
|
||||||
|
safi_t safi;
|
||||||
enum bgp_peer_sort origtype, newtype;
|
enum bgp_peer_sort origtype, newtype;
|
||||||
|
|
||||||
/* Stop peer. */
|
/* Stop peer. */
|
||||||
@ -1877,6 +1880,11 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
|
|||||||
|
|
||||||
/* reflector-client reset */
|
/* reflector-client reset */
|
||||||
if (newtype != BGP_PEER_IBGP) {
|
if (newtype != BGP_PEER_IBGP) {
|
||||||
|
|
||||||
|
FOREACH_AFI_SAFI (afi, safi)
|
||||||
|
UNSET_FLAG(peer->af_flags[afi][safi],
|
||||||
|
PEER_FLAG_ORR_GROUP);
|
||||||
|
|
||||||
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST],
|
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST],
|
||||||
PEER_FLAG_REFLECTOR_CLIENT);
|
PEER_FLAG_REFLECTOR_CLIENT);
|
||||||
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST],
|
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST],
|
||||||
@ -3850,6 +3858,8 @@ void bgp_free(struct bgp *bgp)
|
|||||||
ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
|
ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bgp_orr_cleanup(bgp);
|
||||||
|
|
||||||
XFREE(MTYPE_BGP, bgp->name);
|
XFREE(MTYPE_BGP, bgp->name);
|
||||||
XFREE(MTYPE_BGP, bgp->name_pretty);
|
XFREE(MTYPE_BGP, bgp->name_pretty);
|
||||||
XFREE(MTYPE_BGP, bgp->snmp_stats);
|
XFREE(MTYPE_BGP, bgp->snmp_stats);
|
||||||
@ -4633,6 +4643,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP)
|
if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP)
|
||||||
return BGP_ERR_NOT_INTERNAL_PEER;
|
return BGP_ERR_NOT_INTERNAL_PEER;
|
||||||
|
|
||||||
|
/* Do not remove reflector client when ORR is configured on this peer */
|
||||||
|
if (flag & PEER_FLAG_REFLECTOR_CLIENT && !set &&
|
||||||
|
peer_orr_rrclient_check(peer, afi, safi))
|
||||||
|
return BGP_ERR_PEER_ORR_CONFIGURED;
|
||||||
|
|
||||||
/* Special check for remove-private-AS. */
|
/* Special check for remove-private-AS. */
|
||||||
if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP)
|
if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP)
|
||||||
return BGP_ERR_REMOVE_PRIVATE_AS;
|
return BGP_ERR_REMOVE_PRIVATE_AS;
|
||||||
|
55
bgpd/bgpd.h
55
bgpd/bgpd.h
@ -47,6 +47,7 @@
|
|||||||
#include "bgp_io.h"
|
#include "bgp_io.h"
|
||||||
|
|
||||||
#include "lib/bfd.h"
|
#include "lib/bfd.h"
|
||||||
|
#include "lib/orr_msg.h"
|
||||||
|
|
||||||
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
|
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
|
||||||
#define BGP_PEER_MAX_HASH_SIZE 16384
|
#define BGP_PEER_MAX_HASH_SIZE 16384
|
||||||
@ -197,6 +198,40 @@ struct bgp_redist {
|
|||||||
struct bgp_rmap rmap;
|
struct bgp_rmap rmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bgp_orr_igp_metric {
|
||||||
|
struct prefix prefix;
|
||||||
|
uint32_t igp_metric;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bgp_orr_group {
|
||||||
|
/* Name of this ORR group */
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* Address Family Identifiers */
|
||||||
|
afi_t afi;
|
||||||
|
safi_t safi;
|
||||||
|
|
||||||
|
/* Pointer to BGP */
|
||||||
|
struct bgp *bgp;
|
||||||
|
|
||||||
|
/* Root Routers of the group */
|
||||||
|
struct peer *primary;
|
||||||
|
struct peer *secondary;
|
||||||
|
struct peer *tertiary;
|
||||||
|
|
||||||
|
/* Active Root Router of the group */
|
||||||
|
struct peer *active;
|
||||||
|
|
||||||
|
/* RR clients belong to this group */
|
||||||
|
struct list *rr_client_list;
|
||||||
|
|
||||||
|
/* IGP metric data from active root */
|
||||||
|
struct list *igp_metric_info;
|
||||||
|
|
||||||
|
/* Route table calculated from active root for this group */
|
||||||
|
struct bgp_table *route_table;
|
||||||
|
};
|
||||||
|
|
||||||
enum vpn_policy_direction {
|
enum vpn_policy_direction {
|
||||||
BGP_VPN_POLICY_DIR_FROMVPN = 0,
|
BGP_VPN_POLICY_DIR_FROMVPN = 0,
|
||||||
BGP_VPN_POLICY_DIR_TOVPN = 1,
|
BGP_VPN_POLICY_DIR_TOVPN = 1,
|
||||||
@ -779,6 +814,10 @@ struct bgp {
|
|||||||
|
|
||||||
bool allow_martian;
|
bool allow_martian;
|
||||||
|
|
||||||
|
/* BGP optimal route reflection group and Root Router configuration */
|
||||||
|
uint32_t orr_group_count;
|
||||||
|
struct list *orr_group[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
QOBJ_FIELDS;
|
QOBJ_FIELDS;
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(bgp);
|
DECLARE_QOBJ_TYPE(bgp);
|
||||||
@ -1422,6 +1461,10 @@ struct peer {
|
|||||||
#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 28)
|
#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 28)
|
||||||
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29)
|
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29)
|
||||||
#define PEER_FLAG_SOO (1ULL << 30)
|
#define PEER_FLAG_SOO (1ULL << 30)
|
||||||
|
#define PEER_FLAG_ORR_GROUP (1ULL << 31) /* Optimal-Route-Reflection */
|
||||||
|
|
||||||
|
/* BGP Optimal Route Reflection Group name */
|
||||||
|
char *orr_group_name[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
|
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
@ -2029,7 +2072,10 @@ enum bgp_create_error_code {
|
|||||||
|
|
||||||
/*BGP Open Policy ERRORS */
|
/*BGP Open Policy ERRORS */
|
||||||
BGP_ERR_INVALID_ROLE_NAME = -35,
|
BGP_ERR_INVALID_ROLE_NAME = -35,
|
||||||
BGP_ERR_INVALID_INTERNAL_ROLE = -36
|
BGP_ERR_INVALID_INTERNAL_ROLE = -36,
|
||||||
|
|
||||||
|
/* BGP ORR ERRORS */
|
||||||
|
BGP_ERR_PEER_ORR_CONFIGURED = -37,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2081,6 +2127,7 @@ extern struct peer_group *peer_group_lookup_dynamic_neighbor(struct bgp *,
|
|||||||
extern struct peer *peer_lookup_dynamic_neighbor(struct bgp *,
|
extern struct peer *peer_lookup_dynamic_neighbor(struct bgp *,
|
||||||
union sockunion *);
|
union sockunion *);
|
||||||
|
|
||||||
|
extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
|
||||||
/*
|
/*
|
||||||
* Peers are incredibly easy to memory leak
|
* Peers are incredibly easy to memory leak
|
||||||
* due to the various ways that they are actually used
|
* due to the various ways that they are actually used
|
||||||
@ -2331,6 +2378,12 @@ extern void bgp_shutdown_disable(struct bgp *bgp);
|
|||||||
extern void bgp_close(void);
|
extern void bgp_close(void);
|
||||||
extern void bgp_free(struct bgp *);
|
extern void bgp_free(struct bgp *);
|
||||||
void bgp_gr_apply_running_config(void);
|
void bgp_gr_apply_running_config(void);
|
||||||
|
extern int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||||
|
const char *name, struct peer *primary,
|
||||||
|
struct peer *secondary,
|
||||||
|
struct peer *tertiary);
|
||||||
|
extern int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
/* BGP GR */
|
/* BGP GR */
|
||||||
int bgp_global_gr_init(struct bgp *bgp);
|
int bgp_global_gr_init(struct bgp *bgp);
|
||||||
|
@ -103,6 +103,7 @@ bgpd_libbgp_a_SOURCES = \
|
|||||||
bgpd/bgp_vty.c \
|
bgpd/bgp_vty.c \
|
||||||
bgpd/bgp_zebra.c \
|
bgpd/bgp_zebra.c \
|
||||||
bgpd/bgpd.c \
|
bgpd/bgpd.c \
|
||||||
|
bgpd/bgp_orr.c \
|
||||||
bgpd/bgp_trace.c \
|
bgpd/bgp_trace.c \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
@ -183,6 +184,7 @@ noinst_HEADERS += \
|
|||||||
bgpd/bgp_vty.h \
|
bgpd/bgp_vty.h \
|
||||||
bgpd/bgp_zebra.h \
|
bgpd/bgp_zebra.h \
|
||||||
bgpd/bgpd.h \
|
bgpd/bgpd.h \
|
||||||
|
bgpd/bgp_orr.h \
|
||||||
bgpd/bgp_trace.h \
|
bgpd/bgp_trace.h \
|
||||||
\
|
\
|
||||||
bgpd/rfapi/bgp_rfapi_cfg.h \
|
bgpd/rfapi/bgp_rfapi_cfg.h \
|
||||||
|
317
doc/user/bgp.rst
317
doc/user/bgp.rst
@ -3478,6 +3478,319 @@ When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2
|
|||||||
Total number of prefixes 3
|
Total number of prefixes 3
|
||||||
Router2#
|
Router2#
|
||||||
|
|
||||||
|
.. _bgp-optimal-route-reflection:
|
||||||
|
|
||||||
|
BGP Optimal Route Reflection
|
||||||
|
----------------------------
|
||||||
|
BGP Route Reflectors (RRs) are used to improve network scalability by reducing
|
||||||
|
or eliminating the need for a full-mesh of IBGP sessions.
|
||||||
|
|
||||||
|
When a BGP RR receives multiple paths for the same IP prefix, it typically
|
||||||
|
selects a single best path to send for all its clients.
|
||||||
|
If the RR has multiple nearly-equal best paths and the tie-break is determined
|
||||||
|
by the next-hop cost, the RR advertises the path based on its view of next-hop
|
||||||
|
costs, which leads to a non-optimal routing.
|
||||||
|
The advertised route may differ from the path that a client would select
|
||||||
|
if it had the visibility of the same set of candidate paths and used
|
||||||
|
its own view of next-hop costs.
|
||||||
|
|
||||||
|
Non-optimal advertisements by the RR can be a problem in hot-potato routing.
|
||||||
|
Hot-potato routing aims to hand off traffic to the next AS using the closest
|
||||||
|
possible exit point from the local AS.
|
||||||
|
In this context, the closest exit point implies minimum IGP cost to
|
||||||
|
reach the BGP next-hop.
|
||||||
|
|
||||||
|
The BGP Optimal Route Reflection allows the RR to choose and send a different
|
||||||
|
best path to a different or a set of RR clients.
|
||||||
|
|
||||||
|
A link-state protocol is required. It can be OSPF or IS-IS.
|
||||||
|
Current implementation of BGP ORR is based on the IGP cost to the BGP next hop,
|
||||||
|
and not based on some configured policy.
|
||||||
|
|
||||||
|
RR runs Shortest Path First (SPF) calculation with the selected
|
||||||
|
router as the root of the tree and calculates the cost to every other router.
|
||||||
|
|
||||||
|
This special SPF calculation with another router as the root, is referred to as
|
||||||
|
a Reverse SPF (rSPF). This can only be done if the RR learns all the BGP paths
|
||||||
|
from all the BGP border routers.
|
||||||
|
|
||||||
|
There could be as many rSPFs run as there are RR clients.
|
||||||
|
This will increase the CPU load somewhat on the RR.
|
||||||
|
|
||||||
|
Current implementation allows up to three root nodes for the rSPF calculation.
|
||||||
|
There is no need to configure each RR client as a root and run rSPF.
|
||||||
|
Current implementation allows to configure three, the primary, the secondary,
|
||||||
|
and the tertiary root, per set of RR clients, for redundancy purposes.
|
||||||
|
For the BGP ORR feature to apply to any RR client, that RR client must be
|
||||||
|
configured to be part of an ORR policy group.
|
||||||
|
|
||||||
|
The BGP ORR feature is enabled per address family.
|
||||||
|
|
||||||
|
The minimal configuration needed:
|
||||||
|
|
||||||
|
1. ORR needs to be enabled for specific groups of BGP neighbors.
|
||||||
|
2. For each group of BGP neighbors, at least one root needs to be configured.
|
||||||
|
Optionally, a secondary and tertiary root can be configured.
|
||||||
|
3. For OSPF, the root routers(RR clients) need additional configuration
|
||||||
|
to make BGP ORR work.
|
||||||
|
i.e. The MPLS TE configuration on the root router needs to have the minimal
|
||||||
|
configuration for MPLS TE enabled so that OSPF advertises the MPLS TE
|
||||||
|
router ID in an opaque-area LSA (type 10).
|
||||||
|
Once the RR has an opaque-area LSA with the MPLS TE router-ID matching the
|
||||||
|
configured root router address, rSPF can run and BGP on the RR can
|
||||||
|
advertise the optimal route.
|
||||||
|
|
||||||
|
.. clicmd:: neighbor A.B.C.D optimal-route-reflection NAME
|
||||||
|
|
||||||
|
This command allows the neighbor to be part of the ORR group.
|
||||||
|
|
||||||
|
.. clicmd:: optimal-route-reflection orr-1 A.B.C.D [A.B.C.D] [A.B.C.D]
|
||||||
|
|
||||||
|
This command creates an ORR group with a mandatory primary root
|
||||||
|
and optional secondary and/or tertiary roots.
|
||||||
|
When primary is reachable it will be the active root.
|
||||||
|
when primary goes down, secondary followed by tertiary takes over
|
||||||
|
the active root's role.
|
||||||
|
Always rSPF calculation runs active root as the root.
|
||||||
|
Which means the RR advertises the path based on active root's
|
||||||
|
view of next-hop costs.
|
||||||
|
|
||||||
|
Sample Configuration
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Sample configuration on Route Reflector
|
||||||
|
|
||||||
|
.. code-block:: frr
|
||||||
|
|
||||||
|
!
|
||||||
|
debug ospf 8 orr
|
||||||
|
debug bgp optimal-route-reflection
|
||||||
|
!
|
||||||
|
interface enp0s8
|
||||||
|
ip address 10.10.68.8/24
|
||||||
|
ip ospf 8 area 0
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.100.1.8/32
|
||||||
|
ip ospf 8 area 0
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
router bgp 1
|
||||||
|
neighbor 10.100.1.1 remote-as 1
|
||||||
|
neighbor 10.100.1.1 update-source lo
|
||||||
|
neighbor 10.100.1.2 remote-as 1
|
||||||
|
neighbor 10.100.1.2 update-source lo
|
||||||
|
neighbor 10.100.1.3 remote-as 1
|
||||||
|
neighbor 10.100.1.3 update-source lo
|
||||||
|
neighbor 10.100.1.4 remote-as 1
|
||||||
|
neighbor 10.100.1.4 update-source lo
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
neighbor 10.100.1.1 route-reflector-client
|
||||||
|
neighbor 10.100.1.1 optimal-route-reflection orr-1
|
||||||
|
neighbor 10.100.1.2 route-reflector-client
|
||||||
|
neighbor 10.100.1.2 optimal-route-reflection orr-1
|
||||||
|
neighbor 10.100.1.3 route-reflector-client
|
||||||
|
neighbor 10.100.1.3 optimal-route-reflection orr-1
|
||||||
|
neighbor 10.100.1.4 route-reflector-client
|
||||||
|
neighbor 10.100.1.4 optimal-route-reflection orr-1
|
||||||
|
optimal-route-reflection orr-1 10.100.1.4 10.100.1.3 10.100.1.1
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
router ospf 8
|
||||||
|
ospf router-id 8.8.8.8
|
||||||
|
area 0 authentication
|
||||||
|
capability opaque
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
end
|
||||||
|
|
||||||
|
Sample configuration on RR clients
|
||||||
|
|
||||||
|
.. code-block:: frr
|
||||||
|
|
||||||
|
interface enp0s8
|
||||||
|
ip address 10.10.34.4/24
|
||||||
|
ip ospf 4 area 0
|
||||||
|
link-params
|
||||||
|
enable
|
||||||
|
exit-link-params
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
interface enp0s9
|
||||||
|
ip address 10.10.74.4/24
|
||||||
|
ip ospf 4 area 0
|
||||||
|
link-params
|
||||||
|
enable
|
||||||
|
exit-link-params
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.100.1.4/32
|
||||||
|
ip ospf 4 area 0
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
router bgp 1
|
||||||
|
neighbor 10.100.1.8 remote-as 1
|
||||||
|
neighbor 10.100.1.8 update-source lo
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
neighbor 10.100.1.8 soft-reconfiguration inbound
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
router ospf 4
|
||||||
|
ospf router-id 4.4.4.4
|
||||||
|
area 0 authentication
|
||||||
|
capability opaque
|
||||||
|
mpls-te on
|
||||||
|
mpls-te router-address 10.100.1.4
|
||||||
|
mpls-te inter-as area 0.0.0.0
|
||||||
|
mpls-te export
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
end
|
||||||
|
|
||||||
|
Sample Output
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
When Optimal Route Reflection is not enabled on RR, it sends 10.100.1.1 as the best path to its clients.
|
||||||
|
|
||||||
|
.. code-block:: frr
|
||||||
|
|
||||||
|
Router-RR# show ip bgp neighbors 10.100.1.4
|
||||||
|
|
||||||
|
!--- Output suppressed.
|
||||||
|
|
||||||
|
For address family: IPv4 Unicast
|
||||||
|
Update group 2, subgroup 2
|
||||||
|
Packet Queue length 0
|
||||||
|
Route-Reflector Client
|
||||||
|
Community attribute sent to this neighbor(all)
|
||||||
|
0 accepted prefixes
|
||||||
|
|
||||||
|
!--- Output suppressed.
|
||||||
|
|
||||||
|
Router-RR#
|
||||||
|
Router-RR# show ip bgp
|
||||||
|
BGP table version is 3, local router ID is 10.100.1.8, vrf id 0
|
||||||
|
Default local pref 100, local AS 1
|
||||||
|
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
|
||||||
|
i internal, r RIB-failure, S Stale, R Removed
|
||||||
|
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
|
||||||
|
Origin codes: i - IGP, e - EGP, ? - incomplete
|
||||||
|
RPKI validation codes: V valid, I invalid, N Not found
|
||||||
|
|
||||||
|
Network Next Hop Metric LocPrf Weight Path
|
||||||
|
* i203.0.113.0/24 10.100.1.2 0 100 0 i
|
||||||
|
*>i 10.100.1.1 0 100 0 i
|
||||||
|
*=i 10.100.1.3 0 100 0 i
|
||||||
|
|
||||||
|
Displayed 1 routes and 3 total paths
|
||||||
|
Router-RR#
|
||||||
|
|
||||||
|
Router-PE4# show ip bgp
|
||||||
|
BGP table version is 5, local router ID is 10.100.1.4, vrf id 0
|
||||||
|
Default local pref 100, local AS 1
|
||||||
|
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
|
||||||
|
i internal, r RIB-failure, S Stale, R Removed
|
||||||
|
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
|
||||||
|
Origin codes: i - IGP, e - EGP, ? - incomplete
|
||||||
|
RPKI validation codes: V valid, I invalid, N Not found
|
||||||
|
|
||||||
|
Network Next Hop Metric LocPrf Weight Path
|
||||||
|
*>i203.0.113.0/24 10.100.1.1 0 100 0 i
|
||||||
|
|
||||||
|
Displayed 1 routes and 1 total paths
|
||||||
|
Router-PE4#
|
||||||
|
|
||||||
|
When Optimal Route Reflection is enabled on RR, it sends 10.100.1.3 as the best path to its clients.
|
||||||
|
|
||||||
|
.. code-block:: frr
|
||||||
|
|
||||||
|
Router-RR# show ip bgp neighbors 10.100.1.4
|
||||||
|
|
||||||
|
!--- Output suppressed.
|
||||||
|
|
||||||
|
For address family: IPv4 Unicast
|
||||||
|
Update group 1, subgroup 1
|
||||||
|
Packet Queue length 0
|
||||||
|
Route-Reflector Client
|
||||||
|
ORR group (configured) : orr-1
|
||||||
|
Community attribute sent to this neighbor(all)
|
||||||
|
0 accepted prefixes
|
||||||
|
|
||||||
|
!--- Output suppressed.
|
||||||
|
|
||||||
|
Router-RR#
|
||||||
|
Router-RR# show ip bgp
|
||||||
|
BGP table version is 1, local router ID is 10.100.1.8, vrf id 0
|
||||||
|
Default local pref 100, local AS 1
|
||||||
|
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
|
||||||
|
i internal, r RIB-failure, S Stale, R Removed
|
||||||
|
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
|
||||||
|
Origin codes: i - IGP, e - EGP, ? - incomplete
|
||||||
|
RPKI validation codes: V valid, I invalid, N Not found
|
||||||
|
|
||||||
|
Network Next Hop Metric LocPrf Weight Path
|
||||||
|
* i203.0.113.0/24 10.100.1.2 0 100 0 i
|
||||||
|
*>i 10.100.1.3 0 100 0 i
|
||||||
|
* i 10.100.1.1 0 100 0 i
|
||||||
|
|
||||||
|
Displayed 1 routes and 3 total paths
|
||||||
|
Router-RR#
|
||||||
|
|
||||||
|
Router-RR# show ip bgp optimal-route-reflection
|
||||||
|
|
||||||
|
ORR group: orr-1, IPv4 Unicast
|
||||||
|
Configured root: primary: 10.100.1.4(Router-PE4), secondary: 10.100.1.3(Router-PE3), tertiary: 10.100.1.1(Router-PE1)
|
||||||
|
Active Root: 10.100.1.4(Router-PE4)
|
||||||
|
|
||||||
|
RR Clients mapped:
|
||||||
|
10.100.1.1
|
||||||
|
10.100.1.2
|
||||||
|
10.100.1.3
|
||||||
|
10.100.1.4
|
||||||
|
|
||||||
|
Number of mapping entries: 4
|
||||||
|
|
||||||
|
Prefix Cost
|
||||||
|
10.10.34.0/24 100
|
||||||
|
10.10.61.0/24 300
|
||||||
|
10.10.63.0/24 200
|
||||||
|
10.10.67.0/24 200
|
||||||
|
10.10.68.0/24 300
|
||||||
|
10.10.72.0/24 200
|
||||||
|
10.10.74.0/24 100
|
||||||
|
10.100.1.1/32 300
|
||||||
|
10.100.1.2/32 200
|
||||||
|
10.100.1.3/32 100
|
||||||
|
10.100.1.4/32 0
|
||||||
|
10.100.1.6/32 200
|
||||||
|
10.100.1.7/32 100
|
||||||
|
10.100.1.8/32 300
|
||||||
|
|
||||||
|
Number of mapping entries: 14
|
||||||
|
|
||||||
|
Router-RR#
|
||||||
|
|
||||||
|
Router-PE4# show ip bgp
|
||||||
|
BGP table version is 3, local router ID is 10.100.1.4, vrf id 0
|
||||||
|
Default local pref 100, local AS 1
|
||||||
|
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
|
||||||
|
i internal, r RIB-failure, S Stale, R Removed
|
||||||
|
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
|
||||||
|
Origin codes: i - IGP, e - EGP, ? - incomplete
|
||||||
|
RPKI validation codes: V valid, I invalid, N Not found
|
||||||
|
|
||||||
|
Network Next Hop Metric LocPrf Weight Path
|
||||||
|
*>i203.0.113.0/24 10.100.1.3 0 100 0 i
|
||||||
|
|
||||||
|
Displayed 1 routes and 1 total paths
|
||||||
|
Router-PE4#
|
||||||
|
|
||||||
.. _bgp-debugging:
|
.. _bgp-debugging:
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
@ -3543,6 +3856,10 @@ Debugging
|
|||||||
|
|
||||||
Enable or disable debugging of communications between *bgpd* and *zebra*.
|
Enable or disable debugging of communications between *bgpd* and *zebra*.
|
||||||
|
|
||||||
|
.. clicmd:: debug bgp optimal-route-reflection
|
||||||
|
|
||||||
|
Enable or disable debugging of BGP Optimal Route Reflection.
|
||||||
|
|
||||||
Dumping Messages and Routing Tables
|
Dumping Messages and Routing Tables
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -831,6 +831,12 @@ Showing Information
|
|||||||
Show the OSPF routing table, as determined by the most recent SPF
|
Show the OSPF routing table, as determined by the most recent SPF
|
||||||
calculation.
|
calculation.
|
||||||
|
|
||||||
|
.. clicmd:: show ip ospf (1-65535) route orr [NAME]
|
||||||
|
|
||||||
|
.. clicmd:: show ip ospf [vrf <NAME|all>] route orr [NAME]
|
||||||
|
|
||||||
|
Show the OSPF routing table, calculated from the active root of all ORR groups or specified ORR group.
|
||||||
|
|
||||||
.. clicmd:: show ip ospf graceful-restart helper [detail] [json]
|
.. clicmd:: show ip ospf graceful-restart helper [detail] [json]
|
||||||
|
|
||||||
Displays the Grcaeful Restart Helper details including helper
|
Displays the Grcaeful Restart Helper details including helper
|
||||||
@ -1138,6 +1144,10 @@ Debugging OSPF
|
|||||||
.. clicmd:: show debugging ospf
|
.. clicmd:: show debugging ospf
|
||||||
|
|
||||||
|
|
||||||
|
.. clicmd:: debug ospf orr
|
||||||
|
|
||||||
|
Enable or disable debugging of BGP Optimal Route Reflection.
|
||||||
|
|
||||||
|
|
||||||
Sample Configuration
|
Sample Configuration
|
||||||
====================
|
====================
|
||||||
|
@ -417,6 +417,7 @@ struct cmd_node {
|
|||||||
#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
|
#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
|
||||||
#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
|
#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
|
||||||
#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
|
#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
|
||||||
|
#define BGP_ORR_DEBUG "Enable Optimal Route Reflection Debugging logs\n"
|
||||||
#define OSPF_STR "OSPF information\n"
|
#define OSPF_STR "OSPF information\n"
|
||||||
#define NEIGHBOR_STR "Specify neighbor router\n"
|
#define NEIGHBOR_STR "Specify neighbor router\n"
|
||||||
#define DEBUG_STR "Debugging functions\n"
|
#define DEBUG_STR "Debugging functions\n"
|
||||||
|
94
lib/orr_msg.h
Normal file
94
lib/orr_msg.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Structures common to BGP, OSPF and ISIS for BGP Optimal Route Reflection
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_ORR_MSG_H
|
||||||
|
#define _FRR_ORR_MSG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* REVISIT: Need to check if we can use zero length array */
|
||||||
|
#define ORR_MAX_PREFIX 100
|
||||||
|
#define ORR_GROUP_NAME_SIZE 32
|
||||||
|
|
||||||
|
struct orr_prefix_metric {
|
||||||
|
struct prefix prefix;
|
||||||
|
uint32_t metric;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BGP-IGP Register for IGP metric */
|
||||||
|
struct orr_igp_metric_reg {
|
||||||
|
bool reg;
|
||||||
|
uint8_t proto;
|
||||||
|
safi_t safi;
|
||||||
|
struct prefix prefix;
|
||||||
|
char group_name[ORR_GROUP_NAME_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* IGP-BGP message structures */
|
||||||
|
struct orr_igp_metric_info {
|
||||||
|
/* IGP instance data. */
|
||||||
|
uint8_t proto;
|
||||||
|
uint32_t instId;
|
||||||
|
|
||||||
|
safi_t safi;
|
||||||
|
|
||||||
|
/* Add or delete routes */
|
||||||
|
bool add;
|
||||||
|
|
||||||
|
/* IGP metric from Active Root. */
|
||||||
|
struct prefix root;
|
||||||
|
uint32_t num_entries;
|
||||||
|
struct orr_prefix_metric nexthop[ORR_MAX_PREFIX];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BGP ORR Root node */
|
||||||
|
struct orr_root {
|
||||||
|
afi_t afi;
|
||||||
|
safi_t safi;
|
||||||
|
|
||||||
|
char group_name[ORR_GROUP_NAME_SIZE];
|
||||||
|
|
||||||
|
/* MPLS_TE prefix and router ID */
|
||||||
|
struct prefix prefix;
|
||||||
|
struct in_addr router_id;
|
||||||
|
|
||||||
|
/* Advertising OSPF Router ID. */
|
||||||
|
struct in_addr adv_router;
|
||||||
|
|
||||||
|
/* BGP-ORR Received LSAs */
|
||||||
|
struct ospf_lsa *router_lsa_rcvd;
|
||||||
|
|
||||||
|
/* Routing tables from root node */
|
||||||
|
struct route_table *old_table; /* Old routing table. */
|
||||||
|
struct route_table *new_table; /* Current routing table. */
|
||||||
|
|
||||||
|
struct route_table *old_rtrs; /* Old ABR/ASBR RT. */
|
||||||
|
struct route_table *new_rtrs; /* New ABR/ASBR RT. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Prototypes. */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FRR_ORR_MSG_H */
|
@ -245,6 +245,7 @@ pkginclude_HEADERS += \
|
|||||||
lib/ns.h \
|
lib/ns.h \
|
||||||
lib/openbsd-queue.h \
|
lib/openbsd-queue.h \
|
||||||
lib/openbsd-tree.h \
|
lib/openbsd-tree.h \
|
||||||
|
lib/orr_msg.h \
|
||||||
lib/plist.h \
|
lib/plist.h \
|
||||||
lib/prefix.h \
|
lib/prefix.h \
|
||||||
lib/printfrr.h \
|
lib/printfrr.h \
|
||||||
|
@ -100,6 +100,8 @@ enum zserv_client_capabilities {
|
|||||||
extern struct sockaddr_storage zclient_addr;
|
extern struct sockaddr_storage zclient_addr;
|
||||||
extern socklen_t zclient_addr_len;
|
extern socklen_t zclient_addr_len;
|
||||||
|
|
||||||
|
#define ZAPI_ORR_FLAG_UNICAST 0x01
|
||||||
|
|
||||||
/* Zebra message types. */
|
/* Zebra message types. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ZEBRA_INTERFACE_ADD,
|
ZEBRA_INTERFACE_ADD,
|
||||||
@ -1229,6 +1231,10 @@ enum zapi_opaque_registry {
|
|||||||
LDP_RLFA_UNREGISTER_ALL = 8,
|
LDP_RLFA_UNREGISTER_ALL = 8,
|
||||||
/* Announce LDP labels associated to a previously registered RLFA */
|
/* Announce LDP labels associated to a previously registered RLFA */
|
||||||
LDP_RLFA_LABELS = 9,
|
LDP_RLFA_LABELS = 9,
|
||||||
|
/* Register for IGP METRIC with OSPF/ISIS */
|
||||||
|
ORR_IGP_METRIC_REGISTER = 10,
|
||||||
|
/* Send SPF data to BGP */
|
||||||
|
ORR_IGP_METRIC_UPDATE = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Send the hello message.
|
/* Send the hello message.
|
||||||
|
@ -63,6 +63,7 @@ unsigned long conf_debug_ospf_ldp_sync;
|
|||||||
unsigned long conf_debug_ospf_gr;
|
unsigned long conf_debug_ospf_gr;
|
||||||
unsigned long conf_debug_ospf_bfd;
|
unsigned long conf_debug_ospf_bfd;
|
||||||
unsigned long conf_debug_ospf_client_api;
|
unsigned long conf_debug_ospf_client_api;
|
||||||
|
unsigned long conf_debug_ospf_orr;
|
||||||
|
|
||||||
/* Enable debug option variables -- valid only session. */
|
/* Enable debug option variables -- valid only session. */
|
||||||
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
|
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
|
||||||
@ -81,6 +82,7 @@ unsigned long term_debug_ospf_ldp_sync;
|
|||||||
unsigned long term_debug_ospf_gr;
|
unsigned long term_debug_ospf_gr;
|
||||||
unsigned long term_debug_ospf_bfd;
|
unsigned long term_debug_ospf_bfd;
|
||||||
unsigned long term_debug_ospf_client_api;
|
unsigned long term_debug_ospf_client_api;
|
||||||
|
unsigned long term_debug_ospf_orr;
|
||||||
|
|
||||||
const char *ospf_redist_string(unsigned int route_type)
|
const char *ospf_redist_string(unsigned int route_type)
|
||||||
{
|
{
|
||||||
@ -1601,6 +1603,33 @@ DEFPY (debug_ospf_client_api,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (debug_ospf_orr,
|
||||||
|
debug_ospf_orr_cmd,
|
||||||
|
"[no$no] debug ospf [(1-65535)$instance] orr",
|
||||||
|
NO_STR
|
||||||
|
DEBUG_STR
|
||||||
|
OSPF_STR
|
||||||
|
"Instance ID\n"
|
||||||
|
"OSPF ORR information\n")
|
||||||
|
{
|
||||||
|
if (instance && instance != ospf_instance)
|
||||||
|
return CMD_NOT_MY_INSTANCE;
|
||||||
|
|
||||||
|
if (vty->node == CONFIG_NODE) {
|
||||||
|
if (no)
|
||||||
|
DEBUG_OFF(orr, ORR);
|
||||||
|
else
|
||||||
|
DEBUG_ON(orr, ORR);
|
||||||
|
} else {
|
||||||
|
if (no)
|
||||||
|
TERM_DEBUG_OFF(orr, ORR);
|
||||||
|
else
|
||||||
|
TERM_DEBUG_ON(orr, ORR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (no_debug_ospf,
|
DEFUN (no_debug_ospf,
|
||||||
no_debug_ospf_cmd,
|
no_debug_ospf_cmd,
|
||||||
"no debug ospf",
|
"no debug ospf",
|
||||||
@ -1643,6 +1672,8 @@ DEFUN (no_debug_ospf,
|
|||||||
|
|
||||||
for (i = 0; i < 5; i++)
|
for (i = 0; i < 5; i++)
|
||||||
DEBUG_PACKET_OFF(i, flag);
|
DEBUG_PACKET_OFF(i, flag);
|
||||||
|
|
||||||
|
DEBUG_OFF(orr, ORR);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 5; i++)
|
for (i = 0; i < 5; i++)
|
||||||
@ -1673,6 +1704,7 @@ DEFUN (no_debug_ospf,
|
|||||||
TERM_DEBUG_OFF(ti_lfa, TI_LFA);
|
TERM_DEBUG_OFF(ti_lfa, TI_LFA);
|
||||||
TERM_DEBUG_OFF(bfd, BFD_LIB);
|
TERM_DEBUG_OFF(bfd, BFD_LIB);
|
||||||
TERM_DEBUG_OFF(client_api, CLIENT_API);
|
TERM_DEBUG_OFF(client_api, CLIENT_API);
|
||||||
|
TERM_DEBUG_OFF(orr, ORR);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1802,6 +1834,12 @@ static int show_debugging_ospf_common(struct vty *vty)
|
|||||||
if (IS_DEBUG_OSPF(client_api, CLIENT_API) == OSPF_DEBUG_CLIENT_API)
|
if (IS_DEBUG_OSPF(client_api, CLIENT_API) == OSPF_DEBUG_CLIENT_API)
|
||||||
vty_out(vty, " OSPF client-api debugging is on\n");
|
vty_out(vty, " OSPF client-api debugging is on\n");
|
||||||
|
|
||||||
|
/* Show debug status for ORR. */
|
||||||
|
if (IS_DEBUG_OSPF(orr, ORR) == OSPF_DEBUG_ORR)
|
||||||
|
vty_out(vty, " OSPF ORR debugging is on\n");
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2014,6 +2052,12 @@ static int config_write_debug(struct vty *vty)
|
|||||||
write = 1;
|
write = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* debug ospf orr */
|
||||||
|
if (IS_CONF_DEBUG_OSPF(orr, ORR) == OSPF_DEBUG_ORR) {
|
||||||
|
vty_out(vty, "debug ospf%s orr\n", str);
|
||||||
|
write = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return write;
|
return write;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2035,6 +2079,7 @@ void ospf_debug_init(void)
|
|||||||
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
|
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
|
install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
|
||||||
install_element(ENABLE_NODE, &debug_ospf_client_api_cmd);
|
install_element(ENABLE_NODE, &debug_ospf_client_api_cmd);
|
||||||
|
install_element(ENABLE_NODE, &debug_ospf_orr_cmd);
|
||||||
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
|
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
|
||||||
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
|
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
|
||||||
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
|
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
|
||||||
@ -2074,6 +2119,7 @@ void ospf_debug_init(void)
|
|||||||
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
|
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
|
install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
|
||||||
install_element(CONFIG_NODE, &debug_ospf_client_api_cmd);
|
install_element(CONFIG_NODE, &debug_ospf_client_api_cmd);
|
||||||
|
install_element(CONFIG_NODE, &debug_ospf_orr_cmd);
|
||||||
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
|
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
|
||||||
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
|
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
|
||||||
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
|
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
|
||||||
|
@ -70,6 +70,8 @@
|
|||||||
|
|
||||||
#define OSPF_DEBUG_CLIENT_API 0x01
|
#define OSPF_DEBUG_CLIENT_API 0x01
|
||||||
|
|
||||||
|
#define OSPF_DEBUG_ORR 0x01
|
||||||
|
|
||||||
/* Macro for setting debug option. */
|
/* Macro for setting debug option. */
|
||||||
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
|
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
|
||||||
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
|
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
|
||||||
@ -129,6 +131,8 @@
|
|||||||
#define AREA_NAME(A) ospf_area_name_string ((A))
|
#define AREA_NAME(A) ospf_area_name_string ((A))
|
||||||
#define IF_NAME(I) ospf_if_name_string ((I))
|
#define IF_NAME(I) ospf_if_name_string ((I))
|
||||||
|
|
||||||
|
#define IS_DEBUG_OSPF_ORR IS_DEBUG_OSPF(orr, ORR)
|
||||||
|
|
||||||
/* Extern debug flag. */
|
/* Extern debug flag. */
|
||||||
extern unsigned long term_debug_ospf_packet[];
|
extern unsigned long term_debug_ospf_packet[];
|
||||||
extern unsigned long term_debug_ospf_event;
|
extern unsigned long term_debug_ospf_event;
|
||||||
@ -146,6 +150,7 @@ extern unsigned long term_debug_ospf_ldp_sync;
|
|||||||
extern unsigned long term_debug_ospf_gr;
|
extern unsigned long term_debug_ospf_gr;
|
||||||
extern unsigned long term_debug_ospf_bfd;
|
extern unsigned long term_debug_ospf_bfd;
|
||||||
extern unsigned long term_debug_ospf_client_api;
|
extern unsigned long term_debug_ospf_client_api;
|
||||||
|
extern unsigned long term_debug_ospf_orr;
|
||||||
|
|
||||||
/* Message Strings. */
|
/* Message Strings. */
|
||||||
extern char *ospf_lsa_type_str[];
|
extern char *ospf_lsa_type_str[];
|
||||||
|
@ -52,6 +52,8 @@
|
|||||||
#include "ospfd/ospf_zebra.h"
|
#include "ospfd/ospf_zebra.h"
|
||||||
#include "ospfd/ospf_abr.h"
|
#include "ospfd/ospf_abr.h"
|
||||||
#include "ospfd/ospf_errors.h"
|
#include "ospfd/ospf_errors.h"
|
||||||
|
#include "ospfd/ospf_te.h"
|
||||||
|
#include "ospfd/ospf_orr.h"
|
||||||
|
|
||||||
static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
|
static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
|
||||||
struct prefix_ipv4 *p,
|
struct prefix_ipv4 *p,
|
||||||
@ -2640,6 +2642,13 @@ ospf_router_lsa_install(struct ospf *ospf, struct ospf_lsa *new, int rt_recalc)
|
|||||||
|
|
||||||
ospf_refresher_register_lsa(ospf, new);
|
ospf_refresher_register_lsa(ospf, new);
|
||||||
}
|
}
|
||||||
|
/* For BGP ORR SPF should be calculated from specified root(s) */
|
||||||
|
else if (ospf->orr_spf_request) {
|
||||||
|
ospf_lsa_unlock(&area->router_lsa_rcvd);
|
||||||
|
area->router_lsa_rcvd = ospf_lsa_lock(new);
|
||||||
|
ospf_orr_root_update_rcvd_lsa(area->router_lsa_rcvd);
|
||||||
|
}
|
||||||
|
|
||||||
if (rt_recalc)
|
if (rt_recalc)
|
||||||
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL);
|
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL);
|
||||||
return new;
|
return new;
|
||||||
@ -2651,7 +2660,6 @@ static struct ospf_lsa *ospf_network_lsa_install(struct ospf *ospf,
|
|||||||
struct ospf_lsa *new,
|
struct ospf_lsa *new,
|
||||||
int rt_recalc)
|
int rt_recalc)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
|
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
|
||||||
The entire routing table must be recalculated, starting with
|
The entire routing table must be recalculated, starting with
|
||||||
the shortest path calculations for each area (not just the
|
the shortest path calculations for each area (not just the
|
||||||
@ -3400,6 +3408,82 @@ struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *area, uint32_t type,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
|
||||||
|
uint32_t type, struct in_addr id)
|
||||||
|
{
|
||||||
|
struct ospf_lsa *lsa = NULL;
|
||||||
|
struct route_node *rn = NULL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case OSPF_ROUTER_LSA:
|
||||||
|
for (rn = route_top(ROUTER_LSDB(area)); rn;
|
||||||
|
rn = route_next(rn)) {
|
||||||
|
lsa = rn->info;
|
||||||
|
if (lsa) {
|
||||||
|
if (IPV4_ADDR_SAME(&lsa->data->adv_router,
|
||||||
|
&id)) {
|
||||||
|
route_unlock_node(rn);
|
||||||
|
return lsa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OSPF_NETWORK_LSA:
|
||||||
|
case OSPF_SUMMARY_LSA:
|
||||||
|
case OSPF_ASBR_SUMMARY_LSA:
|
||||||
|
case OSPF_AS_EXTERNAL_LSA:
|
||||||
|
case OSPF_AS_NSSA_LSA:
|
||||||
|
case OSPF_OPAQUE_LINK_LSA:
|
||||||
|
case OSPF_OPAQUE_AREA_LSA:
|
||||||
|
case OSPF_OPAQUE_AS_LSA:
|
||||||
|
/* Currently not used. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
|
||||||
|
uint32_t type,
|
||||||
|
struct in_addr id)
|
||||||
|
{
|
||||||
|
struct ospf_lsa *lsa = NULL;
|
||||||
|
struct route_node *rn = NULL;
|
||||||
|
struct lsa_header *lsah = NULL;
|
||||||
|
uint32_t lsid;
|
||||||
|
uint8_t opaque_type;
|
||||||
|
struct tlv_header *tlvh = NULL;
|
||||||
|
struct te_tlv_router_addr *router_addr = NULL;
|
||||||
|
|
||||||
|
if (type != OSPF_OPAQUE_AREA_LSA)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (rn = route_top(OPAQUE_AREA_LSDB(area)); rn; rn = route_next(rn)) {
|
||||||
|
lsa = rn->info;
|
||||||
|
if (lsa) {
|
||||||
|
lsah = lsa->data;
|
||||||
|
lsid = ntohl(lsah->id.s_addr);
|
||||||
|
opaque_type = GET_OPAQUE_TYPE(lsid);
|
||||||
|
if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tlvh = TLV_HDR_TOP(lsah);
|
||||||
|
if (!tlvh ||
|
||||||
|
(ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
|
||||||
|
(ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
|
||||||
|
continue;
|
||||||
|
router_addr = (struct te_tlv_router_addr *)tlvh;
|
||||||
|
if (IPV4_ADDR_SAME(&router_addr->value, &id)) {
|
||||||
|
route_unlock_node(rn);
|
||||||
|
return lsa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area,
|
struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area,
|
||||||
struct lsa_header *lsah)
|
struct lsa_header *lsah)
|
||||||
{
|
{
|
||||||
@ -3823,8 +3907,9 @@ struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa)
|
|||||||
struct as_external_lsa *al;
|
struct as_external_lsa *al;
|
||||||
struct prefix_ipv4 p;
|
struct prefix_ipv4 p;
|
||||||
|
|
||||||
assert(CHECK_FLAG(lsa->flags, OSPF_LSA_SELF));
|
if (!CHECK_FLAG(lsa->flags, OSPF_LSA_SELF) && !IS_LSA_SELF(lsa) &&
|
||||||
assert(IS_LSA_SELF(lsa));
|
!IS_LSA_ORR(lsa))
|
||||||
|
return NULL;
|
||||||
assert(lsa->lock > 0);
|
assert(lsa->lock > 0);
|
||||||
|
|
||||||
switch (lsa->data->type) {
|
switch (lsa->data->type) {
|
||||||
@ -3894,7 +3979,8 @@ void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
|
|||||||
uint16_t index, current_index;
|
uint16_t index, current_index;
|
||||||
|
|
||||||
assert(lsa->lock > 0);
|
assert(lsa->lock > 0);
|
||||||
assert(IS_LSA_SELF(lsa));
|
if (!IS_LSA_SELF(lsa) && !IS_LSA_ORR(lsa))
|
||||||
|
return;
|
||||||
|
|
||||||
if (lsa->refresh_list < 0) {
|
if (lsa->refresh_list < 0) {
|
||||||
int delay;
|
int delay;
|
||||||
@ -3943,7 +4029,8 @@ void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
|
|||||||
void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
|
void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
|
||||||
{
|
{
|
||||||
assert(lsa->lock > 0);
|
assert(lsa->lock > 0);
|
||||||
assert(IS_LSA_SELF(lsa));
|
if (!IS_LSA_SELF(lsa) || !IS_LSA_ORR(lsa))
|
||||||
|
return;
|
||||||
if (lsa->refresh_list >= 0) {
|
if (lsa->refresh_list >= 0) {
|
||||||
struct list *refresh_list =
|
struct list *refresh_list =
|
||||||
ospf->lsa_refresh_queue.qs[lsa->refresh_list];
|
ospf->lsa_refresh_queue.qs[lsa->refresh_list];
|
||||||
|
@ -74,15 +74,16 @@ struct vertex;
|
|||||||
/* OSPF LSA. */
|
/* OSPF LSA. */
|
||||||
struct ospf_lsa {
|
struct ospf_lsa {
|
||||||
/* LSA origination flag. */
|
/* LSA origination flag. */
|
||||||
uint8_t flags;
|
uint16_t flags;
|
||||||
#define OSPF_LSA_SELF 0x01
|
#define OSPF_LSA_SELF 0x0001
|
||||||
#define OSPF_LSA_SELF_CHECKED 0x02
|
#define OSPF_LSA_SELF_CHECKED 0x0002
|
||||||
#define OSPF_LSA_RECEIVED 0x04
|
#define OSPF_LSA_RECEIVED 0x0004
|
||||||
#define OSPF_LSA_APPROVED 0x08
|
#define OSPF_LSA_APPROVED 0x0008
|
||||||
#define OSPF_LSA_DISCARD 0x10
|
#define OSPF_LSA_DISCARD 0x0010
|
||||||
#define OSPF_LSA_LOCAL_XLT 0x20
|
#define OSPF_LSA_LOCAL_XLT 0x0020
|
||||||
#define OSPF_LSA_PREMATURE_AGE 0x40
|
#define OSPF_LSA_PREMATURE_AGE 0x0040
|
||||||
#define OSPF_LSA_IN_MAXAGE 0x80
|
#define OSPF_LSA_IN_MAXAGE 0x0080
|
||||||
|
#define OSPF_LSA_ORR 0x0100
|
||||||
|
|
||||||
/* LSA data. and size */
|
/* LSA data. and size */
|
||||||
struct lsa_header *data;
|
struct lsa_header *data;
|
||||||
@ -222,6 +223,7 @@ enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
|
|||||||
#define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE)
|
#define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE)
|
||||||
#define IS_LSA_MAX_SEQ(L) \
|
#define IS_LSA_MAX_SEQ(L) \
|
||||||
((L)->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))
|
((L)->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))
|
||||||
|
#define IS_LSA_ORR(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_ORR))
|
||||||
|
|
||||||
#define OSPF_LSA_UPDATE_DELAY 2
|
#define OSPF_LSA_UPDATE_DELAY 2
|
||||||
|
|
||||||
@ -292,6 +294,12 @@ extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *,
|
|||||||
struct in_addr);
|
struct in_addr);
|
||||||
extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t,
|
extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t,
|
||||||
struct in_addr);
|
struct in_addr);
|
||||||
|
extern struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
|
||||||
|
uint32_t type,
|
||||||
|
struct in_addr id);
|
||||||
|
extern struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
|
||||||
|
uint32_t type,
|
||||||
|
struct in_addr id);
|
||||||
extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *,
|
extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *,
|
||||||
struct lsa_header *);
|
struct lsa_header *);
|
||||||
extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *);
|
extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "ospfd/ospf_asbr.h"
|
#include "ospfd/ospf_asbr.h"
|
||||||
#include "ospfd/ospf_lsa.h"
|
#include "ospfd/ospf_lsa.h"
|
||||||
#include "ospfd/ospf_lsdb.h"
|
#include "ospfd/ospf_lsdb.h"
|
||||||
|
#include "ospfd/ospf_orr.h"
|
||||||
|
|
||||||
struct ospf_lsdb *ospf_lsdb_new(void)
|
struct ospf_lsdb *ospf_lsdb_new(void)
|
||||||
{
|
{
|
||||||
@ -87,6 +88,10 @@ static void ospf_lsdb_delete_entry(struct ospf_lsdb *lsdb,
|
|||||||
|
|
||||||
assert(rn->table == lsdb->type[lsa->data->type].db);
|
assert(rn->table == lsdb->type[lsa->data->type].db);
|
||||||
|
|
||||||
|
/* Update ORR Root table MPLS-TE Router address's advertise router */
|
||||||
|
if (lsa->data->type == OSPF_OPAQUE_AREA_LSA)
|
||||||
|
ospf_orr_root_table_update(lsa, false);
|
||||||
|
|
||||||
if (IS_LSA_SELF(lsa))
|
if (IS_LSA_SELF(lsa))
|
||||||
lsdb->type[lsa->data->type].count_self--;
|
lsdb->type[lsa->data->type].count_self--;
|
||||||
lsdb->type[lsa->data->type].count--;
|
lsdb->type[lsa->data->type].count--;
|
||||||
@ -134,6 +139,10 @@ void ospf_lsdb_add(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
|
|||||||
#endif /* MONITOR_LSDB_CHANGE */
|
#endif /* MONITOR_LSDB_CHANGE */
|
||||||
lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum);
|
lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum);
|
||||||
rn->info = ospf_lsa_lock(lsa); /* lsdb */
|
rn->info = ospf_lsa_lock(lsa); /* lsdb */
|
||||||
|
|
||||||
|
/* Update ORR Root table MPLS-TE Router address's advertise router */
|
||||||
|
if (lsa->data->type == OSPF_OPAQUE_AREA_LSA)
|
||||||
|
ospf_orr_root_table_update(lsa, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ospf_lsdb_delete(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
|
void ospf_lsdb_delete(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
|
||||||
|
@ -60,3 +60,4 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper");
|
|||||||
DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
|
DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
|
||||||
DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
|
DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
|
||||||
DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
|
DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
|
||||||
|
DEFINE_MTYPE(OSPFD, OSPF_ORR_ROOT, "OSPF ORR Root");
|
||||||
|
@ -59,5 +59,6 @@ DECLARE_MTYPE(OSPF_GR_HELPER);
|
|||||||
DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
|
DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
|
||||||
DECLARE_MTYPE(OSPF_P_SPACE);
|
DECLARE_MTYPE(OSPF_P_SPACE);
|
||||||
DECLARE_MTYPE(OSPF_Q_SPACE);
|
DECLARE_MTYPE(OSPF_Q_SPACE);
|
||||||
|
DECLARE_MTYPE(OSPF_ORR_ROOT);
|
||||||
|
|
||||||
#endif /* _QUAGGA_OSPF_MEMORY_H */
|
#endif /* _QUAGGA_OSPF_MEMORY_H */
|
||||||
|
594
ospfd/ospf_orr.c
Normal file
594
ospfd/ospf_orr.c
Normal file
@ -0,0 +1,594 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
static 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,
|
||||||
|
char *group_name)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
strlcpy(root->group_name, group_name, sizeof(root->group_name));
|
||||||
|
root->new_rtrs = NULL;
|
||||||
|
root->new_table = NULL;
|
||||||
|
|
||||||
|
ospf_orr_debug(
|
||||||
|
"%s: For %s %s, ORR Group %s, created ORR Root entry %pFX.",
|
||||||
|
__func__, afi2str(afi), safi2str(safi), root->group_name, 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 ORR Group %s from location %pFX",
|
||||||
|
__func__, msg.reg ? "Register" : "Unregister", msg.group_name,
|
||||||
|
&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,
|
||||||
|
msg.group_name);
|
||||||
|
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_orr_spf_calculate_schedule(ospf);
|
||||||
|
}
|
||||||
|
/* 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--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_DEBUG_OSPF_ORR)
|
||||||
|
ospf_show_orr(ospf, afi, safi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf_orr_igp_metric_send_update_add(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;
|
||||||
|
msg.add = true;
|
||||||
|
prefix_copy(&msg.root, &root->prefix);
|
||||||
|
|
||||||
|
/* 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 &&
|
||||||
|
or->type != OSPF_DESTINATION_DISCARD)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ospf_route_match_same(root->old_table,
|
||||||
|
(struct prefix_ipv4 *)&rn->p, or))
|
||||||
|
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 > 0 && 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__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf_orr_igp_metric_send_update_delete(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;
|
||||||
|
|
||||||
|
if (!root->old_table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.proto = ZEBRA_ROUTE_OSPF;
|
||||||
|
msg.instId = instance;
|
||||||
|
msg.safi = root->safi;
|
||||||
|
msg.add = false;
|
||||||
|
prefix_copy(&msg.root, &root->prefix);
|
||||||
|
|
||||||
|
/* Update prefix table from ORR Route table */
|
||||||
|
for (rn = route_top(root->old_table); rn; rn = route_next(rn)) {
|
||||||
|
or = rn->info;
|
||||||
|
if (!or)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (or->path_type != OSPF_PATH_INTRA_AREA &&
|
||||||
|
or->path_type != OSPF_PATH_INTER_AREA)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (or->type != OSPF_DESTINATION_NETWORK &&
|
||||||
|
or->type != OSPF_DESTINATION_DISCARD)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ospf_route_exist_new_table(root->new_table,
|
||||||
|
(struct prefix_ipv4 *)&rn->p))
|
||||||
|
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 > 0 && 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: Address Family: %s %s", __func__,
|
||||||
|
afi2str(root->afi), safi2str(root->safi));
|
||||||
|
ospf_orr_debug("%s: ORR Group: %s", __func__, root->group_name);
|
||||||
|
ospf_orr_debug("%s: Router-Address: %pI4:", __func__, &root->router_id);
|
||||||
|
ospf_orr_debug("%s: Advertising Router: %pI4:", __func__,
|
||||||
|
&root->adv_router);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (IS_DEBUG_OSPF_ORR)
|
||||||
|
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) {
|
||||||
|
SET_FLAG(lsa->flags, OSPF_LSA_ORR);
|
||||||
|
ospf_refresher_register_lsa(lsa->area->ospf, lsa);
|
||||||
|
root->router_lsa_rcvd = lsa;
|
||||||
|
}
|
||||||
|
|
||||||
|
ospf_orr_debug("%s: Received LSA[Type%d:%pI4]", __func__,
|
||||||
|
lsa->data->type, &lsa->data->adv_router);
|
||||||
|
|
||||||
|
/* Compute SPF for all root nodes */
|
||||||
|
ospf_orr_spf_calculate_schedule(lsa->area->ospf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not Install routes to root table. Just update table ponters */
|
||||||
|
void ospf_orr_route_install(struct orr_root *root, struct route_table *rt,
|
||||||
|
unsigned short instance)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/* Send update to BGP to delete old routes. */
|
||||||
|
ospf_orr_igp_metric_send_update_delete(root, instance);
|
||||||
|
|
||||||
|
/* REVISIT: Skipping external route table for now */
|
||||||
|
|
||||||
|
/* Send update to BGP to add new routes. */
|
||||||
|
ospf_orr_igp_metric_send_update_add(root, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf_orr_spf_calculate_schedule(struct ospf *ospf)
|
||||||
|
{
|
||||||
|
/* OSPF instance does not exist. */
|
||||||
|
if (ospf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* No roots nodes rgistered for rSPF */
|
||||||
|
if (!ospf->orr_spf_request)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* ORR SPF calculation timer is already scheduled. */
|
||||||
|
if (ospf->t_orr_calc) {
|
||||||
|
ospf_orr_debug(
|
||||||
|
"SPF: calculation timer is already scheduled: %p",
|
||||||
|
(void *)ospf->t_orr_calc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ospf->t_orr_calc = NULL;
|
||||||
|
|
||||||
|
ospf_orr_debug("%s: SPF: calculation timer scheduled", __func__);
|
||||||
|
|
||||||
|
thread_add_timer(master, ospf_orr_spf_calculate_schedule_worker, ospf,
|
||||||
|
OSPF_ORR_CALC_INTERVAL, &ospf->t_orr_calc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf_orr_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
|
||||||
|
struct route_table *new_table,
|
||||||
|
struct route_table *all_rtrs,
|
||||||
|
struct route_table *new_rtrs,
|
||||||
|
struct ospf_lsa *lsa_rcvd)
|
||||||
|
{
|
||||||
|
ospf_spf_calculate(area, lsa_rcvd, new_table, all_rtrs, new_rtrs, false,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf_orr_spf_calculate_areas(struct ospf *ospf,
|
||||||
|
struct route_table *new_table,
|
||||||
|
struct route_table *all_rtrs,
|
||||||
|
struct route_table *new_rtrs,
|
||||||
|
struct ospf_lsa *lsa_rcvd)
|
||||||
|
{
|
||||||
|
struct ospf_area *area;
|
||||||
|
struct listnode *node, *nnode;
|
||||||
|
|
||||||
|
/* Calculate SPF for each area. */
|
||||||
|
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
|
||||||
|
/*
|
||||||
|
* Do backbone last, so as to first discover intra-area paths
|
||||||
|
* for any back-bone virtual-links
|
||||||
|
*/
|
||||||
|
if (ospf->backbone && ospf->backbone == area)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ospf_orr_spf_calculate_area(ospf, area, new_table, all_rtrs,
|
||||||
|
new_rtrs, lsa_rcvd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SPF for backbone, if required */
|
||||||
|
if (ospf->backbone)
|
||||||
|
ospf_orr_spf_calculate_area(ospf, ospf->backbone, new_table,
|
||||||
|
all_rtrs, new_rtrs, lsa_rcvd);
|
||||||
|
}
|
58
ospfd/ospf_orr.h
Normal file
58
ospfd/ospf_orr.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ZEBRA_OSPF_ORR_H
|
||||||
|
#define _ZEBRA_OSPF_ORR_H
|
||||||
|
|
||||||
|
#define BGP_OSPF_LSINFINITY 65535
|
||||||
|
#define OSPF_ORR_CALC_INTERVAL 1
|
||||||
|
|
||||||
|
/* Macro to log debug message */
|
||||||
|
#define ospf_orr_debug(...) \
|
||||||
|
do { \
|
||||||
|
if (IS_DEBUG_OSPF_ORR) \
|
||||||
|
zlog_debug("[OSPF-ORR] "__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
extern struct zclient *zclient;
|
||||||
|
|
||||||
|
extern int ospf_orr_igp_metric_register(struct orr_igp_metric_reg orr_reg);
|
||||||
|
extern void ospf_orr_igp_metric_send_update_add(struct orr_root *root,
|
||||||
|
unsigned short instance);
|
||||||
|
extern void ospf_orr_igp_metric_send_update_delete(struct orr_root *root,
|
||||||
|
unsigned short instance);
|
||||||
|
extern void ospf_orr_root_table_update(struct ospf_lsa *lsa, bool add);
|
||||||
|
extern void ospf_orr_root_update_rcvd_lsa(struct ospf_lsa *lsa);
|
||||||
|
extern void ospf_orr_route_install(struct orr_root *root,
|
||||||
|
struct route_table *rt,
|
||||||
|
unsigned short instance);
|
||||||
|
extern void ospf_orr_spf_calculate_schedule(struct ospf *ospf);
|
||||||
|
extern void ospf_orr_spf_calculate_area(struct ospf *ospf,
|
||||||
|
struct ospf_area *area,
|
||||||
|
struct route_table *new_table,
|
||||||
|
struct route_table *all_rtrs,
|
||||||
|
struct route_table *new_rtrs,
|
||||||
|
struct ospf_lsa *lsa_rcvd);
|
||||||
|
extern void ospf_orr_spf_calculate_areas(struct ospf *ospf,
|
||||||
|
struct route_table *new_table,
|
||||||
|
struct route_table *all_rtrs,
|
||||||
|
struct route_table *new_rtrs,
|
||||||
|
struct ospf_lsa *lsa_rcvd);
|
||||||
|
#endif /* _ZEBRA_OSPF_ORR_H */
|
@ -151,8 +151,8 @@ void ospf_route_table_free(struct route_table *rt)
|
|||||||
otherwise return 0. Since the ZEBRA-RIB does an implicit
|
otherwise return 0. Since the ZEBRA-RIB does an implicit
|
||||||
withdraw, it is not necessary to send a delete, an add later
|
withdraw, it is not necessary to send a delete, an add later
|
||||||
will act like an implicit delete. */
|
will act like an implicit delete. */
|
||||||
static int ospf_route_exist_new_table(struct route_table *rt,
|
int ospf_route_exist_new_table(struct route_table *rt,
|
||||||
struct prefix_ipv4 *prefix)
|
struct prefix_ipv4 *prefix)
|
||||||
{
|
{
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
|
|
||||||
|
@ -172,5 +172,6 @@ extern void ospf_delete_discard_route(struct ospf *, struct route_table *,
|
|||||||
struct prefix_ipv4 *);
|
struct prefix_ipv4 *);
|
||||||
extern int ospf_route_match_same(struct route_table *, struct prefix_ipv4 *,
|
extern int ospf_route_match_same(struct route_table *, struct prefix_ipv4 *,
|
||||||
struct ospf_route *);
|
struct ospf_route *);
|
||||||
|
extern int ospf_route_exist_new_table(struct route_table *rt,
|
||||||
|
struct prefix_ipv4 *prefix);
|
||||||
#endif /* _ZEBRA_OSPF_ROUTE_H */
|
#endif /* _ZEBRA_OSPF_ROUTE_H */
|
||||||
|
201
ospfd/ospf_spf.c
201
ospfd/ospf_spf.c
@ -53,6 +53,8 @@
|
|||||||
#include "ospfd/ospf_apiserver.h"
|
#include "ospfd/ospf_apiserver.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "ospfd/ospf_orr.h"
|
||||||
|
|
||||||
/* Variables to ensure a SPF scheduled log message is printed only once */
|
/* Variables to ensure a SPF scheduled log message is printed only once */
|
||||||
|
|
||||||
static unsigned int spf_reason_flags = 0;
|
static unsigned int spf_reason_flags = 0;
|
||||||
@ -1824,6 +1826,36 @@ void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
|
|||||||
all_rtrs, new_rtrs);
|
all_rtrs, new_rtrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print Reason for SPF calculation */
|
||||||
|
static void ospf_spf_calculation_reason2str(char *rbuf)
|
||||||
|
{
|
||||||
|
rbuf[0] = '\0';
|
||||||
|
if (spf_reason_flags) {
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
|
||||||
|
strlcat(rbuf, "R, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
|
||||||
|
strlcat(rbuf, "N, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
|
||||||
|
strlcat(rbuf, "S, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
|
||||||
|
strlcat(rbuf, "AS, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
|
||||||
|
strlcat(rbuf, "ABR, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
|
||||||
|
strlcat(rbuf, "ASBR, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
|
||||||
|
strlcat(rbuf, "M, ", sizeof(rbuf));
|
||||||
|
if (spf_reason_flags & (1 << SPF_FLAG_ORR_ROOT_CHANGE))
|
||||||
|
strlcat(rbuf, "ORR, ", sizeof(rbuf));
|
||||||
|
|
||||||
|
size_t rbuflen = strlen(rbuf);
|
||||||
|
if (rbuflen >= 2)
|
||||||
|
rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
|
||||||
|
else
|
||||||
|
rbuf[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Worker for SPF calculation scheduler. */
|
/* Worker for SPF calculation scheduler. */
|
||||||
static void ospf_spf_calculate_schedule_worker(struct thread *thread)
|
static void ospf_spf_calculate_schedule_worker(struct thread *thread)
|
||||||
{
|
{
|
||||||
@ -1879,6 +1911,8 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
|
|||||||
ospf_ase_calculate_schedule(ospf);
|
ospf_ase_calculate_schedule(ospf);
|
||||||
ospf_ase_calculate_timer_add(ospf);
|
ospf_ase_calculate_timer_add(ospf);
|
||||||
|
|
||||||
|
ospf_orr_spf_calculate_schedule(ospf);
|
||||||
|
|
||||||
if (IS_DEBUG_OSPF_EVENT)
|
if (IS_DEBUG_OSPF_EVENT)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"%s: ospf install new route, vrf %s id %u new_table count %lu",
|
"%s: ospf install new route, vrf %s id %u new_table count %lu",
|
||||||
@ -1901,7 +1935,6 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
|
|||||||
#ifdef SUPPORT_OSPF_API
|
#ifdef SUPPORT_OSPF_API
|
||||||
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
|
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Free old ABR/ASBR routing table */
|
/* Free old ABR/ASBR routing table */
|
||||||
if (ospf->old_rtrs)
|
if (ospf->old_rtrs)
|
||||||
/* ospf_route_delete (ospf->old_rtrs); */
|
/* ospf_route_delete (ospf->old_rtrs); */
|
||||||
@ -1926,31 +1959,7 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
|
|||||||
total_spf_time =
|
total_spf_time =
|
||||||
monotime_since(&spf_start_time, &ospf->ts_spf_duration);
|
monotime_since(&spf_start_time, &ospf->ts_spf_duration);
|
||||||
|
|
||||||
rbuf[0] = '\0';
|
ospf_spf_calculation_reason2str(rbuf);
|
||||||
if (spf_reason_flags) {
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
|
|
||||||
strlcat(rbuf, "R, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
|
|
||||||
strlcat(rbuf, "N, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
|
|
||||||
strlcat(rbuf, "S, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
|
|
||||||
strlcat(rbuf, "AS, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
|
|
||||||
strlcat(rbuf, "ABR, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
|
|
||||||
strlcat(rbuf, "ASBR, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
|
|
||||||
strlcat(rbuf, "M, ", sizeof(rbuf));
|
|
||||||
if (spf_reason_flags & (1 << SPF_FLAG_GR_FINISH))
|
|
||||||
strlcat(rbuf, "GR, ", sizeof(rbuf));
|
|
||||||
|
|
||||||
size_t rbuflen = strlen(rbuf);
|
|
||||||
if (rbuflen >= 2)
|
|
||||||
rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
|
|
||||||
else
|
|
||||||
rbuf[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_DEBUG_OSPF_EVENT) {
|
if (IS_DEBUG_OSPF_EVENT) {
|
||||||
zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
|
zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
|
||||||
@ -1967,6 +1976,145 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
|
|||||||
ospf_clear_spf_reason_flags();
|
ospf_clear_spf_reason_flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Worker for ORR SPF calculation scheduler. */
|
||||||
|
void ospf_orr_spf_calculate_schedule_worker(struct thread *thread)
|
||||||
|
{
|
||||||
|
afi_t afi;
|
||||||
|
safi_t safi;
|
||||||
|
struct ospf *ospf = THREAD_ARG(thread);
|
||||||
|
struct route_table *new_table, *new_rtrs;
|
||||||
|
struct route_table *all_rtrs = NULL;
|
||||||
|
struct timeval start_time, spf_start_time;
|
||||||
|
unsigned long ia_time, rt_time;
|
||||||
|
unsigned long abr_time, total_spf_time, spf_time;
|
||||||
|
struct listnode *rnode;
|
||||||
|
struct list *orr_root_list;
|
||||||
|
struct orr_root *root;
|
||||||
|
char rbuf[32]; /* reason_buf */
|
||||||
|
|
||||||
|
ospf_orr_debug("%s: SPF: Timer (SPF calculation expire)", __func__);
|
||||||
|
|
||||||
|
ospf->t_orr_calc = NULL;
|
||||||
|
|
||||||
|
/* Execute SPF for each ORR Root node */
|
||||||
|
FOREACH_AFI_SAFI (afi, safi) {
|
||||||
|
orr_root_list = ospf->orr_root[afi][safi];
|
||||||
|
if (!orr_root_list)
|
||||||
|
continue;
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(orr_root_list, rnode, root)) {
|
||||||
|
if (!root || !root->router_lsa_rcvd)
|
||||||
|
continue;
|
||||||
|
ospf_orr_debug(
|
||||||
|
"%s: For %s %s, MPLS TE Router address %pI4 advertised by %pI4",
|
||||||
|
__func__, afi2str(afi), safi2str(safi),
|
||||||
|
&root->router_id, &root->adv_router);
|
||||||
|
|
||||||
|
ospf_vl_unapprove(ospf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execute SPF for each area including backbone, see RFC
|
||||||
|
* 2328 16.1.
|
||||||
|
*/
|
||||||
|
monotime(&spf_start_time);
|
||||||
|
new_table = route_table_init(); /* routing table */
|
||||||
|
new_rtrs =
|
||||||
|
route_table_init(); /* ABR/ASBR routing table */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have opaque enabled then track all router
|
||||||
|
* reachability
|
||||||
|
*/
|
||||||
|
if (CHECK_FLAG(ospf->opaque,
|
||||||
|
OPAQUE_OPERATION_READY_BIT))
|
||||||
|
all_rtrs = route_table_init();
|
||||||
|
ospf_orr_spf_calculate_areas(ospf, new_table, all_rtrs,
|
||||||
|
new_rtrs,
|
||||||
|
root->router_lsa_rcvd);
|
||||||
|
|
||||||
|
spf_time = monotime_since(&spf_start_time, NULL);
|
||||||
|
|
||||||
|
ospf_vl_shut_unapproved(ospf);
|
||||||
|
|
||||||
|
/* Calculate inter-area routes, see RFC 2328 16.2. */
|
||||||
|
monotime(&start_time);
|
||||||
|
ospf_ia_routing(ospf, new_table, new_rtrs);
|
||||||
|
ia_time = monotime_since(&start_time, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REVISIT :
|
||||||
|
* Pruning of unreachable networks, routers skipped.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: RFC 2328 16.3. is apparently missing. */
|
||||||
|
/* Calculate AS external routes, see RFC 2328 16.4.
|
||||||
|
* There is a dedicated routing table for external
|
||||||
|
* routes which is not handled here directly
|
||||||
|
*/
|
||||||
|
ospf_ase_calculate_schedule(ospf);
|
||||||
|
ospf_ase_calculate_timer_add(ospf);
|
||||||
|
|
||||||
|
ospf_orr_debug(
|
||||||
|
"%s: ospf install new route, vrf %s id %u new_table count %lu",
|
||||||
|
__func__, ospf_vrf_id_to_name(ospf->vrf_id),
|
||||||
|
ospf->vrf_id, new_table->count);
|
||||||
|
|
||||||
|
/* Update routing table. */
|
||||||
|
monotime(&start_time);
|
||||||
|
ospf_orr_route_install(root, new_table, ospf->instance);
|
||||||
|
rt_time = monotime_since(&start_time, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REVISIT :
|
||||||
|
* Freeing up and Updating old all routers routing table
|
||||||
|
* skipped.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Free old ABR/ASBR routing table */
|
||||||
|
if (root->old_rtrs)
|
||||||
|
/* ospf_route_delete (ospf->old_rtrs); */
|
||||||
|
ospf_rtrs_free(root->old_rtrs);
|
||||||
|
|
||||||
|
/* Update ABR/ASBR routing table */
|
||||||
|
root->old_rtrs = root->new_rtrs;
|
||||||
|
root->new_rtrs = new_rtrs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ABRs may require additional changes, see RFC
|
||||||
|
* 2328 16.7.
|
||||||
|
*/
|
||||||
|
monotime(&start_time);
|
||||||
|
if (IS_OSPF_ABR(ospf)) {
|
||||||
|
if (ospf->anyNSSA)
|
||||||
|
ospf_abr_nssa_check_status(ospf);
|
||||||
|
ospf_abr_task(ospf);
|
||||||
|
}
|
||||||
|
abr_time = monotime_since(&start_time, NULL);
|
||||||
|
|
||||||
|
/* Schedule Segment Routing update */
|
||||||
|
ospf_sr_update_task(ospf);
|
||||||
|
|
||||||
|
total_spf_time = monotime_since(&spf_start_time,
|
||||||
|
&ospf->ts_spf_duration);
|
||||||
|
|
||||||
|
ospf_spf_calculation_reason2str(rbuf);
|
||||||
|
|
||||||
|
if (IS_DEBUG_OSPF_ORR) {
|
||||||
|
zlog_info("SPF Processing Time(usecs): %ld",
|
||||||
|
total_spf_time);
|
||||||
|
zlog_info(" SPF Time: %ld",
|
||||||
|
spf_time);
|
||||||
|
zlog_info(" InterArea: %ld", ia_time);
|
||||||
|
zlog_info(" RouteInstall: %ld", rt_time);
|
||||||
|
if (IS_OSPF_ABR(ospf))
|
||||||
|
zlog_info(
|
||||||
|
" ABR: %ld (%d areas)",
|
||||||
|
abr_time, ospf->areas->count);
|
||||||
|
zlog_info("Reason(s) for SPF: %s", rbuf);
|
||||||
|
}
|
||||||
|
} /* ALL_LIST_ELEMENTS_RO() */
|
||||||
|
} /* FOREACH_AFI_SAFI() */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer
|
* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer
|
||||||
* for SPF calc.
|
* for SPF calc.
|
||||||
@ -2025,6 +2173,7 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
|
|||||||
zlog_debug("SPF: calculation timer delay = %ld msec", delay);
|
zlog_debug("SPF: calculation timer delay = %ld msec", delay);
|
||||||
|
|
||||||
ospf->t_spf_calc = NULL;
|
ospf->t_spf_calc = NULL;
|
||||||
|
|
||||||
thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
|
thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
|
||||||
delay, &ospf->t_spf_calc);
|
delay, &ospf->t_spf_calc);
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,10 @@ typedef enum {
|
|||||||
SPF_FLAG_ASBR_STATUS_CHANGE,
|
SPF_FLAG_ASBR_STATUS_CHANGE,
|
||||||
SPF_FLAG_CONFIG_CHANGE,
|
SPF_FLAG_CONFIG_CHANGE,
|
||||||
SPF_FLAG_GR_FINISH,
|
SPF_FLAG_GR_FINISH,
|
||||||
|
SPF_FLAG_ORR_ROOT_CHANGE,
|
||||||
} ospf_spf_reason_t;
|
} ospf_spf_reason_t;
|
||||||
|
|
||||||
|
extern unsigned int ospf_get_spf_reason_flags(void);
|
||||||
extern void ospf_spf_calculate_schedule(struct ospf *, ospf_spf_reason_t);
|
extern void ospf_spf_calculate_schedule(struct ospf *, ospf_spf_reason_t);
|
||||||
extern void ospf_spf_calculate(struct ospf_area *area,
|
extern void ospf_spf_calculate(struct ospf_area *area,
|
||||||
struct ospf_lsa *root_lsa,
|
struct ospf_lsa *root_lsa,
|
||||||
@ -103,5 +105,6 @@ extern int vertex_parent_cmp(void *aa, void *bb);
|
|||||||
|
|
||||||
extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i);
|
extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i);
|
||||||
extern void ospf_restart_spf(struct ospf *ospf);
|
extern void ospf_restart_spf(struct ospf *ospf);
|
||||||
|
extern void ospf_orr_spf_calculate_schedule_worker(struct thread *thread);
|
||||||
/* void ospf_spf_calculate_timer_add (); */
|
/* void ospf_spf_calculate_timer_add (); */
|
||||||
#endif /* _QUAGGA_OSPF_SPF_H */
|
#endif /* _QUAGGA_OSPF_SPF_H */
|
||||||
|
128
ospfd/ospf_vty.c
128
ospfd/ospf_vty.c
@ -55,6 +55,7 @@
|
|||||||
#include "ospfd/ospf_dump.h"
|
#include "ospfd/ospf_dump.h"
|
||||||
#include "ospfd/ospf_bfd.h"
|
#include "ospfd/ospf_bfd.h"
|
||||||
#include "ospfd/ospf_ldp_sync.h"
|
#include "ospfd/ospf_ldp_sync.h"
|
||||||
|
#include "ospfd/ospf_orr.h"
|
||||||
|
|
||||||
|
|
||||||
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
|
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
|
||||||
@ -10982,6 +10983,131 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
|
|||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void show_ip_ospf_route_orr_root(struct vty *vty, struct ospf *ospf,
|
||||||
|
struct orr_root *root, bool use_vrf)
|
||||||
|
{
|
||||||
|
if (ospf->instance)
|
||||||
|
vty_out(vty, "\nOSPF Instance: %d\n", ospf->instance);
|
||||||
|
|
||||||
|
ospf_show_vrf_name(ospf, vty, NULL, use_vrf);
|
||||||
|
|
||||||
|
vty_out(vty, "ORR Group: %s\n", root->group_name);
|
||||||
|
vty_out(vty, "Active Root: %pI4\n\n", &root->router_id);
|
||||||
|
vty_out(vty, "SPF calculated from %pI4\n\n", &root->router_id);
|
||||||
|
|
||||||
|
if (root->new_table)
|
||||||
|
show_ip_ospf_route_network(vty, ospf, root->new_table, NULL);
|
||||||
|
|
||||||
|
if (root->new_rtrs)
|
||||||
|
show_ip_ospf_route_router(vty, ospf, root->new_rtrs, NULL);
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_ip_ospf_route_orr_common(struct vty *vty, struct ospf *ospf,
|
||||||
|
const char *orr_group, bool use_vrf)
|
||||||
|
{
|
||||||
|
afi_t afi;
|
||||||
|
safi_t safi;
|
||||||
|
struct orr_root *root = NULL;
|
||||||
|
struct listnode *node = NULL;
|
||||||
|
struct list *orr_root_list = NULL;
|
||||||
|
|
||||||
|
if (!ospf->orr_spf_request)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FOREACH_AFI_SAFI (afi, safi) {
|
||||||
|
orr_root_list = ospf->orr_root[afi][safi];
|
||||||
|
if (!orr_root_list)
|
||||||
|
continue;
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root)) {
|
||||||
|
if (orr_group) {
|
||||||
|
if (!strmatch(root->group_name, orr_group))
|
||||||
|
continue;
|
||||||
|
show_ip_ospf_route_orr_root(vty, ospf, root,
|
||||||
|
use_vrf);
|
||||||
|
} else
|
||||||
|
show_ip_ospf_route_orr_root(vty, ospf, root,
|
||||||
|
use_vrf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (show_ip_ospf_instance_route_orr,
|
||||||
|
show_ip_ospf_instance_route_orr_cmd,
|
||||||
|
"show ip ospf (1-65535)$instance route orr [WORD$orr_group]",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
OSPF_STR
|
||||||
|
"Instance ID\n"
|
||||||
|
"OSPF routing table\n"
|
||||||
|
"Optimal Route Reflection\n"
|
||||||
|
"ORR Group name\n")
|
||||||
|
{
|
||||||
|
struct ospf *ospf;
|
||||||
|
|
||||||
|
if (instance != ospf_instance)
|
||||||
|
return CMD_NOT_MY_INSTANCE;
|
||||||
|
|
||||||
|
ospf = ospf_lookup_instance(instance);
|
||||||
|
if (!ospf || !ospf->oi_running)
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
|
||||||
|
show_ip_ospf_route_orr_common(vty, ospf, orr_group, false);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (show_ip_ospf_route_orr,
|
||||||
|
show_ip_ospf_route_orr_cmd,
|
||||||
|
"show ip ospf [vrf <NAME$vrf_name|all$all_vrf>] route orr [WORD$orr_group]",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
OSPF_STR
|
||||||
|
VRF_CMD_HELP_STR
|
||||||
|
"All VRFs\n"
|
||||||
|
"OSPF routing table\n"
|
||||||
|
"Optimal Route Reflection\n"
|
||||||
|
"ORR Group name\n")
|
||||||
|
{
|
||||||
|
struct ospf *ospf = NULL;
|
||||||
|
struct listnode *node = NULL;
|
||||||
|
int ret = CMD_SUCCESS;
|
||||||
|
int inst = 0;
|
||||||
|
bool use_vrf = vrf_name || all_vrf;
|
||||||
|
|
||||||
|
if (all_vrf) {
|
||||||
|
bool ospf_output = false;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
|
||||||
|
if (!ospf->oi_running)
|
||||||
|
continue;
|
||||||
|
ospf_output = true;
|
||||||
|
|
||||||
|
show_ip_ospf_route_orr_common(vty, ospf, orr_group,
|
||||||
|
use_vrf);
|
||||||
|
}
|
||||||
|
if (!ospf_output)
|
||||||
|
vty_out(vty, "%% OSPF is not enabled\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vrf_name)
|
||||||
|
ospf = ospf_lookup_by_inst_name(inst, vrf_name);
|
||||||
|
else
|
||||||
|
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
|
||||||
|
|
||||||
|
if (!ospf || !ospf->oi_running) {
|
||||||
|
vty_out(vty, "%% OSPF is not enabled in vrf %s\n",
|
||||||
|
vrf_name ? vrf_name : "default");
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
show_ip_ospf_route_orr_common(vty, ospf, orr_group, use_vrf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int show_ip_ospf_reachable_routers_common(struct vty *vty,
|
static int show_ip_ospf_reachable_routers_common(struct vty *vty,
|
||||||
struct ospf *ospf,
|
struct ospf *ospf,
|
||||||
uint8_t use_vrf)
|
uint8_t use_vrf)
|
||||||
@ -12694,11 +12820,13 @@ void ospf_vty_show_init(void)
|
|||||||
install_element(VIEW_NODE, &show_ip_ospf_route_cmd);
|
install_element(VIEW_NODE, &show_ip_ospf_route_cmd);
|
||||||
install_element(VIEW_NODE, &show_ip_ospf_border_routers_cmd);
|
install_element(VIEW_NODE, &show_ip_ospf_border_routers_cmd);
|
||||||
install_element(VIEW_NODE, &show_ip_ospf_reachable_routers_cmd);
|
install_element(VIEW_NODE, &show_ip_ospf_reachable_routers_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ip_ospf_route_orr_cmd);
|
||||||
|
|
||||||
install_element(VIEW_NODE, &show_ip_ospf_instance_route_cmd);
|
install_element(VIEW_NODE, &show_ip_ospf_instance_route_cmd);
|
||||||
install_element(VIEW_NODE, &show_ip_ospf_instance_border_routers_cmd);
|
install_element(VIEW_NODE, &show_ip_ospf_instance_border_routers_cmd);
|
||||||
install_element(VIEW_NODE,
|
install_element(VIEW_NODE,
|
||||||
&show_ip_ospf_instance_reachable_routers_cmd);
|
&show_ip_ospf_instance_reachable_routers_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ip_ospf_instance_route_orr_cmd);
|
||||||
|
|
||||||
/* "show ip ospf vrfs" commands. */
|
/* "show ip ospf vrfs" commands. */
|
||||||
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
|
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "ospfd/ospf_te.h"
|
#include "ospfd/ospf_te.h"
|
||||||
#include "ospfd/ospf_sr.h"
|
#include "ospfd/ospf_sr.h"
|
||||||
#include "ospfd/ospf_ldp_sync.h"
|
#include "ospfd/ospf_ldp_sync.h"
|
||||||
|
#include "ospfd/ospf_orr.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table");
|
DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table");
|
||||||
DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute");
|
DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute");
|
||||||
@ -2081,6 +2082,7 @@ static void ospf_zebra_connected(struct zclient *zclient)
|
|||||||
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
|
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
|
||||||
|
|
||||||
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
||||||
|
zclient_register_opaque(zclient, ORR_IGP_METRIC_REGISTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2093,6 +2095,7 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
|||||||
struct ldp_igp_sync_if_state state;
|
struct ldp_igp_sync_if_state state;
|
||||||
struct ldp_igp_sync_announce announce;
|
struct ldp_igp_sync_announce announce;
|
||||||
struct zapi_opaque_reg_info dst;
|
struct zapi_opaque_reg_info dst;
|
||||||
|
struct orr_igp_metric_reg orr_reg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
s = zclient->ibuf;
|
s = zclient->ibuf;
|
||||||
@ -2116,6 +2119,10 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
|||||||
STREAM_GET(&announce, s, sizeof(announce));
|
STREAM_GET(&announce, s, sizeof(announce));
|
||||||
ret = ospf_ldp_sync_announce_update(announce);
|
ret = ospf_ldp_sync_announce_update(announce);
|
||||||
break;
|
break;
|
||||||
|
case ORR_IGP_METRIC_REGISTER:
|
||||||
|
STREAM_GET(&orr_reg, s, sizeof(orr_reg));
|
||||||
|
ret = ospf_orr_igp_metric_register(orr_reg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -795,6 +795,7 @@ static void ospf_finish_final(struct ospf *ospf)
|
|||||||
THREAD_OFF(ospf->t_write);
|
THREAD_OFF(ospf->t_write);
|
||||||
THREAD_OFF(ospf->t_spf_calc);
|
THREAD_OFF(ospf->t_spf_calc);
|
||||||
THREAD_OFF(ospf->t_ase_calc);
|
THREAD_OFF(ospf->t_ase_calc);
|
||||||
|
THREAD_OFF(ospf->t_orr_calc);
|
||||||
THREAD_OFF(ospf->t_maxage);
|
THREAD_OFF(ospf->t_maxage);
|
||||||
THREAD_OFF(ospf->t_maxage_walker);
|
THREAD_OFF(ospf->t_maxage_walker);
|
||||||
THREAD_OFF(ospf->t_abr_task);
|
THREAD_OFF(ospf->t_abr_task);
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
#include "ospf_memory.h"
|
#include "ospf_memory.h"
|
||||||
#include "ospf_dump_api.h"
|
#include "ospf_dump_api.h"
|
||||||
|
|
||||||
|
#include "orr_msg.h"
|
||||||
|
|
||||||
#define OSPF_VERSION 2
|
#define OSPF_VERSION 2
|
||||||
|
|
||||||
/* VTY port number. */
|
/* VTY port number. */
|
||||||
@ -261,6 +263,7 @@ struct ospf {
|
|||||||
struct thread *t_distribute_update; /* Distirbute list update timer. */
|
struct thread *t_distribute_update; /* Distirbute list update timer. */
|
||||||
struct thread *t_spf_calc; /* SPF calculation timer. */
|
struct thread *t_spf_calc; /* SPF calculation timer. */
|
||||||
struct thread *t_ase_calc; /* ASE calculation timer. */
|
struct thread *t_ase_calc; /* ASE calculation timer. */
|
||||||
|
struct thread *t_orr_calc; /* ORR calculation timer. */
|
||||||
struct thread
|
struct thread
|
||||||
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
|
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
|
||||||
struct thread *t_sr_update; /* Segment Routing update timer */
|
struct thread *t_sr_update; /* Segment Routing update timer */
|
||||||
@ -406,6 +409,10 @@ struct ospf {
|
|||||||
bool ti_lfa_enabled;
|
bool ti_lfa_enabled;
|
||||||
enum protection_type ti_lfa_protection_type;
|
enum protection_type ti_lfa_protection_type;
|
||||||
|
|
||||||
|
/* BGP ORR Root node list */
|
||||||
|
uint32_t orr_spf_request;
|
||||||
|
struct list *orr_root[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
QOBJ_FIELDS;
|
QOBJ_FIELDS;
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(ospf);
|
DECLARE_QOBJ_TYPE(ospf);
|
||||||
@ -591,6 +598,9 @@ struct ospf_area {
|
|||||||
uint32_t act_ints; /* Active interfaces. */
|
uint32_t act_ints; /* Active interfaces. */
|
||||||
uint32_t full_nbrs; /* Fully adjacent neighbors. */
|
uint32_t full_nbrs; /* Fully adjacent neighbors. */
|
||||||
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
|
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
|
||||||
|
|
||||||
|
/* BGP-ORR Received LSAs */
|
||||||
|
struct ospf_lsa *router_lsa_rcvd;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* OSPF config network structure. */
|
/* OSPF config network structure. */
|
||||||
|
@ -48,6 +48,7 @@ ospfd_libfrrospf_a_SOURCES = \
|
|||||||
ospfd/ospf_network.c \
|
ospfd/ospf_network.c \
|
||||||
ospfd/ospf_nsm.c \
|
ospfd/ospf_nsm.c \
|
||||||
ospfd/ospf_opaque.c \
|
ospfd/ospf_opaque.c \
|
||||||
|
ospfd/ospf_orr.c \
|
||||||
ospfd/ospf_packet.c \
|
ospfd/ospf_packet.c \
|
||||||
ospfd/ospf_ri.c \
|
ospfd/ospf_ri.c \
|
||||||
ospfd/ospf_route.c \
|
ospfd/ospf_route.c \
|
||||||
@ -101,6 +102,7 @@ noinst_HEADERS += \
|
|||||||
ospfd/ospf_memory.h \
|
ospfd/ospf_memory.h \
|
||||||
ospfd/ospf_neighbor.h \
|
ospfd/ospf_neighbor.h \
|
||||||
ospfd/ospf_network.h \
|
ospfd/ospf_network.h \
|
||||||
|
ospfd/ospf_orr.h \
|
||||||
ospfd/ospf_packet.h \
|
ospfd/ospf_packet.h \
|
||||||
ospfd/ospf_ri.h \
|
ospfd/ospf_ri.h \
|
||||||
ospfd/ospf_gr.h \
|
ospfd/ospf_gr.h \
|
||||||
|
Loading…
Reference in New Issue
Block a user