Merge pull request #11159 from maduri111/bgpd-orr

bgpd: optimal route reflection
This commit is contained in:
Russ White 2022-10-12 09:30:36 -04:00 committed by GitHub
commit 984eb32b58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 3175 additions and 44 deletions

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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 */

View File

@ -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");

View File

@ -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

File diff suppressed because it is too large Load Diff

102
bgpd/bgp_orr.h Normal file
View 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 */

View File

@ -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,

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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 \

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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
==================== ====================

View File

@ -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
View 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 */

View File

@ -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 \

View File

@ -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.

View File

@ -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);

View File

@ -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[];

View File

@ -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];

View File

@ -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 *);

View File

@ -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)

View File

@ -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");

View File

@ -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
View 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
View 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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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);
} }

View File

@ -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 */

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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. */

View File

@ -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 \