summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_debug.c43
-rw-r--r--bgpd/bgp_debug.h3
-rw-r--r--bgpd/bgp_fsm.c3
-rw-r--r--bgpd/bgp_fsm.h2
-rw-r--r--bgpd/bgp_memory.c4
-rw-r--r--bgpd/bgp_memory.h2
-rw-r--r--bgpd/bgp_orr.c1176
-rw-r--r--bgpd/bgp_orr.h102
-rw-r--r--bgpd/bgp_route.c70
-rw-r--r--bgpd/bgp_vty.c82
-rw-r--r--bgpd/bgp_zebra.c35
-rw-r--r--bgpd/bgpd.c15
-rw-r--r--bgpd/bgpd.h55
-rw-r--r--bgpd/subdir.am2
-rw-r--r--doc/user/bgp.rst317
-rw-r--r--doc/user/ospfd.rst10
-rw-r--r--lib/command.h1
-rw-r--r--lib/orr_msg.h94
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/zclient.h6
-rw-r--r--ospfd/ospf_dump.c46
-rw-r--r--ospfd/ospf_dump.h5
-rw-r--r--ospfd/ospf_lsa.c97
-rw-r--r--ospfd/ospf_lsa.h26
-rw-r--r--ospfd/ospf_lsdb.c9
-rw-r--r--ospfd/ospf_memory.c1
-rw-r--r--ospfd/ospf_memory.h1
-rw-r--r--ospfd/ospf_orr.c594
-rw-r--r--ospfd/ospf_orr.h58
-rw-r--r--ospfd/ospf_route.c4
-rw-r--r--ospfd/ospf_route.h3
-rw-r--r--ospfd/ospf_spf.c201
-rw-r--r--ospfd/ospf_spf.h3
-rw-r--r--ospfd/ospf_vty.c128
-rw-r--r--ospfd/ospf_zebra.c7
-rw-r--r--ospfd/ospfd.c1
-rw-r--r--ospfd/ospfd.h10
-rw-r--r--ospfd/subdir.am2
38 files changed, 3175 insertions, 44 deletions
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 264dd85fbc..580c18b58d 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -71,6 +71,7 @@ unsigned long conf_bgp_debug_graceful_restart;
unsigned long conf_bgp_debug_evpn_mh;
unsigned long conf_bgp_debug_bfd;
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_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_bfd;
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_keepalive_peers = NULL;
@@ -2044,6 +2046,33 @@ DEFPY (debug_bgp_evpn_mh,
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,
debug_bgp_labelpool_cmd,
"debug bgp labelpool",
@@ -2182,6 +2211,7 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
TERM_DEBUG_OFF(bfd, BFD_LIB);
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");
@@ -2278,6 +2308,10 @@ DEFUN_NOSH (show_debugging_bgp,
vty_out(vty,
" 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);
return CMD_SUCCESS;
@@ -2414,6 +2448,11 @@ static int bgp_config_write_debug(struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG(optimal_route_reflection, ORR)) {
+ vty_out(vty, "debug bgp optimal-route-reflection\n");
+ write++;
+ }
+
return write;
}
@@ -2546,6 +2585,10 @@ void bgp_debug_init(void)
/* debug bgp conditional advertisement */
install_element(ENABLE_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
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index be5ed0afdc..f7090260ac 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -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_bfd;
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_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_bfd;
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_keepalive_peers;
@@ -138,6 +140,7 @@ struct bgp_debug_filter {
#define BGP_DEBUG_PBR_ERROR 0x02
#define BGP_DEBUG_EVPN_MH_ES 0x01
#define BGP_DEBUG_EVPN_MH_RT 0x02
+#define BGP_DEBUG_ORR 0x01
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index ddda100774..a85432a33b 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1330,6 +1330,9 @@ void bgp_fsm_change_status(struct peer *peer, int status)
&& bgp_update_delay_applicable(peer->bgp))
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))
zlog_debug("%s went from %s to %s", peer->host,
lookup_msg(bgp_status_msg, peer->ostatus, NULL),
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index aaf6c480b2..368c2c5001 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -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_cmd(enum global_gr_command gl_gr_cmd);
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 */
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 850657d35e..ced3e1890e 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -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_VPN, "BGP prefix-sid srv6 vpn service");
+
DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
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");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 510cfa21c9..990c6e1faa 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -137,5 +137,7 @@ DECLARE_MTYPE(BGP_SRV6_FUNCTION);
DECLARE_MTYPE(EVPN_REMOTE_IP);
DECLARE_MTYPE(BGP_NOTIFICATION);
+DECLARE_MTYPE(BGP_ORR_GROUP);
+DECLARE_MTYPE(BGP_ORR_GROUP_NAME);
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_orr.c b/bgpd/bgp_orr.c
new file mode 100644
index 0000000000..7fed6b775e
--- /dev/null
+++ b/bgpd/bgp_orr.c
@@ -0,0 +1,1176 @@
+/*
+ * 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
+ */
+
+#include <zebra.h>
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_orr.h"
+#include "bgpd/bgp_vty.h"
+#include "zclient.h"
+
+DEFINE_MTYPE_STATIC(BGPD, ORR_IGP_INFO, "ORR IGP Metric info");
+
+static inline bool is_orr_primary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->primary && strmatch(orr_group->primary->host, host);
+}
+
+static inline bool is_orr_secondary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->secondary &&
+ strmatch(orr_group->secondary->host, host);
+}
+
+static inline bool is_orr_tertiary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->tertiary && strmatch(orr_group->tertiary->host, host);
+}
+
+static inline bool is_orr_active_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->active && strmatch(orr_group->active->host, host);
+}
+
+static inline bool is_orr_root_node(struct bgp_orr_group *orr_group, char *host)
+{
+ return is_orr_primary_root(orr_group, host) ||
+ is_orr_secondary_root(orr_group, host) ||
+ is_orr_tertiary_root(orr_group, host);
+}
+
+static inline bool is_peer_orr_group_member(struct peer *peer, afi_t afi,
+ safi_t safi, const char *name)
+{
+ return peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP) &&
+ strmatch(peer->orr_group_name[afi][safi], name);
+}
+
+static inline bool is_peer_reachable(struct peer *peer, afi_t afi, safi_t safi)
+{
+ return peer && peer->afc_nego[afi][safi] && peer_established(peer);
+}
+
+static inline bool is_peer_active_eligible(struct peer *peer, afi_t afi,
+ safi_t safi, const char *name)
+{
+ return is_peer_reachable(peer, afi, safi) &&
+ is_peer_orr_group_member(peer, afi, safi, name);
+}
+
+static void bgp_orr_igp_metric_register(struct bgp_orr_group *orr_group,
+ bool reg);
+
+static void
+bgp_peer_update_orr_group_active_root(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_orr_group *orr_group);
+
+static struct bgp_orr_group *bgp_orr_group_new(struct bgp *bgp, afi_t afi,
+ safi_t safi, const char *name)
+{
+ int ret;
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(bgp && name);
+
+ if (!bgp->orr_group[afi][safi])
+ bgp->orr_group[afi][safi] = list_new();
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ orr_group = XCALLOC(MTYPE_BGP_ORR_GROUP, sizeof(struct bgp_orr_group));
+
+ listnode_add(orr_group_list, orr_group);
+
+ orr_group->name = XSTRDUP(MTYPE_BGP_ORR_GROUP_NAME, name);
+ orr_group->afi = afi;
+ orr_group->safi = safi;
+ orr_group->primary = orr_group->secondary = orr_group->tertiary = NULL;
+ orr_group->bgp = bgp;
+
+ /* Initialize ORR Group route table */
+ orr_group->route_table = bgp_table_init(bgp, afi, safi);
+ assert(orr_group->route_table);
+
+ /*
+ * Register for opaque messages from IGPs when first ORR group is
+ * configured.
+ */
+ if (!bgp->orr_group_count) {
+ ret = zclient_register_opaque(zclient, ORR_IGP_METRIC_UPDATE);
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ bgp_orr_debug(
+ "%s: zclient_register_opaque failed with ret = %d",
+ __func__, ret);
+ }
+
+ bgp->orr_group_count++;
+
+ return orr_group;
+}
+
+static void bgp_orr_group_free(struct bgp_orr_group *orr_group)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ assert(orr_group && orr_group->bgp && orr_group->name);
+
+ bgp_orr_debug("%s: Deleting ORR group %s", __func__, orr_group->name);
+
+ afi = orr_group->afi;
+ safi = orr_group->safi;
+ bgp = orr_group->bgp;
+
+ /*
+ * Unregister with IGP for metric calculation from specified location
+ * and delete igp_metric_info calculated for this group
+ */
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ /* Free RR client list associated with this ORR group */
+ if (orr_group->rr_client_list)
+ list_delete(&orr_group->rr_client_list);
+
+ /* Free route table */
+ bgp_table_unlock(orr_group->route_table);
+ orr_group->route_table = NULL;
+
+ /* Unset ORR Group parameters */
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME, orr_group->name);
+
+ listnode_delete(bgp->orr_group[afi][safi], orr_group);
+ XFREE(MTYPE_BGP_ORR_GROUP, orr_group);
+
+ bgp->orr_group_count--;
+
+ if (!bgp->orr_group[afi][safi]->count)
+ list_delete(&bgp->orr_group[afi][safi]);
+}
+
+struct bgp_orr_group *bgp_orr_group_lookup_by_name(struct bgp *bgp, afi_t afi,
+ safi_t safi,
+ const char *name)
+{
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *group = NULL;
+ struct listnode *node;
+
+ assert(bgp);
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, group))
+ if (strmatch(group->name, name))
+ return group;
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' not found.", __func__,
+ get_afi_safi_str(afi, safi, false), name);
+
+ return NULL;
+}
+
+static char *bgp_orr_group_rrclient_lookup(struct bgp_orr_group *orr_group,
+ const char *rr_client_host)
+{
+ char *rrclient = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct listnode *node;
+
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node, rrclient))
+ if (strmatch(rrclient, rr_client_host))
+ return rrclient;
+
+ bgp_orr_debug(
+ "%s: For %s, %s not found in ORR Group '%s' RR Client list",
+ __func__,
+ get_afi_safi_str(orr_group->afi, orr_group->safi, false),
+ rr_client_host, orr_group->name);
+
+ return NULL;
+}
+
+static void bgp_orr_group_rrclient_update(struct peer *peer, afi_t afi,
+ safi_t safi,
+ const char *orr_group_name, bool add)
+{
+ char *rr_client = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+ struct list *rr_client_list = NULL;
+
+ assert(peer && peer->bgp && orr_group_name);
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ bgp_orr_debug("%s: For %s, ORR Group '%s' not found.", __func__,
+ get_afi_safi_str(afi, safi, false),
+ orr_group_name);
+ return;
+ }
+
+ /* Get BGP ORR client entry for the given RR client */
+ rr_client = bgp_orr_group_rrclient_lookup(orr_group, peer->host);
+
+ /* Nothing to do */
+ if ((rr_client && add) || (!rr_client && !add))
+ return;
+
+ if (add) {
+ /* Create BGP ORR RR client entry to the ORR Group */
+ if (!orr_group->rr_client_list)
+ orr_group->rr_client_list = list_new();
+ rr_client_list = orr_group->rr_client_list;
+ rr_client = XSTRDUP(MTYPE_BGP_PEER_HOST, peer->host);
+
+ listnode_add(rr_client_list, rr_client);
+
+ bgp_orr_debug(
+ "%s: For %s, %pBP is added to ORR Group '%s' RR Client list.",
+ __func__, get_afi_safi_str(afi, safi, false), peer,
+ orr_group_name);
+ } else {
+ /* Delete BGP ORR RR client entry from the ORR Group */
+ listnode_delete(orr_group->rr_client_list, rr_client);
+ XFREE(MTYPE_BGP_PEER_HOST, rr_client);
+ if (!orr_group->rr_client_list->count)
+ list_delete(&orr_group->rr_client_list);
+
+ bgp_orr_debug(
+ "%s: For %s, %pBP is removed from ORR Group '%s' RR Client list.",
+ __func__, get_afi_safi_str(afi, safi, false), peer,
+ orr_group_name);
+ }
+}
+
+/* Create/Update BGP Optimal Route Reflection Group */
+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)
+{
+ bool primary_eligible = false;
+ bool secondary_eligible = false;
+ bool tertiary_eligible = false;
+ struct bgp_orr_group *orr_group = NULL;
+
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' Primary %pBP Secondary %pBP Tertiary %pBP",
+ __func__, get_afi_safi_str(afi, safi, false), name, primary,
+ secondary, tertiary);
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi, name);
+ if (!orr_group) {
+ /* Create BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_new(bgp, afi, safi, name);
+ }
+
+ /* Compare and update Primary Root Address */
+ if (primary) {
+ if (!orr_group->primary ||
+ !strmatch(orr_group->primary->host, primary->host))
+ orr_group->primary = primary;
+ else
+ bgp_orr_debug("%s: No change in Primary Root",
+ __func__);
+
+ /*
+ * Update Active Root if there is a change and primary is
+ * reachable.
+ */
+ primary_eligible =
+ is_peer_active_eligible(primary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = primary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (orr_group->primary &&
+ !strmatch(orr_group->active->host,
+ orr_group->primary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = primary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug("%s: %s", __func__,
+ orr_group->primary
+ ? "No change in Active Root"
+ : "Primary Root is NULL");
+ } else {
+ if (orr_group->primary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->primary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->primary = NULL;
+ }
+ }
+
+ /* Compare and update Secondary Root Address */
+ if (secondary) {
+ if (!orr_group->secondary ||
+ !strmatch(orr_group->secondary->host, secondary->host))
+ orr_group->secondary = secondary;
+ else
+ bgp_orr_debug("%s: No change in Secondary Root",
+ __func__);
+
+ /* Update Active Root if Primary is not reachable */
+ secondary_eligible =
+ is_peer_active_eligible(secondary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (!primary_eligible && orr_group->secondary &&
+ !strmatch(orr_group->active->host,
+ orr_group->secondary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug(
+ "%s: %s", __func__,
+ primary_eligible
+ ? "Primary is Active Root"
+ : orr_group->secondary
+ ? "No change in Active Root"
+ : "Secondary Root is NULL");
+ } else {
+ if (orr_group->secondary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->secondary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->secondary = NULL;
+ }
+ }
+
+ /* Compare and update Tertiary Root Address */
+ if (tertiary) {
+ if (!orr_group->tertiary ||
+ !strmatch(orr_group->tertiary->host, tertiary->host))
+ orr_group->tertiary = tertiary;
+ else
+ bgp_orr_debug("%s: No change in Tertiay Root",
+ __func__);
+
+ /*
+ * Update Active Root if Primary & Secondary are not reachable
+ */
+ tertiary_eligible =
+ is_peer_active_eligible(tertiary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (!primary_eligible && !secondary_eligible &&
+ orr_group->tertiary &&
+ !strmatch(orr_group->active->host,
+ orr_group->tertiary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug(
+ "%s: %s", __func__,
+ primary_eligible
+ ? "Primary is Active Root"
+ : secondary_eligible
+ ? "Secondary is Active Root"
+ : !orr_group->tertiary
+ ? "Tertiary Root is NULL"
+ : "No change in Active Root");
+ } else {
+ if (orr_group->tertiary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->tertiary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->tertiary = NULL;
+ }
+ }
+
+ if (orr_group->active && !primary_eligible && !secondary_eligible &&
+ !tertiary_eligible) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' Active Root is %pBP",
+ __func__, get_afi_safi_str(afi, safi, false), name,
+ orr_group->active);
+
+ return CMD_SUCCESS;
+}
+
+/* Delete BGP Optimal Route Reflection Group */
+int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name)
+{
+ struct bgp_orr_group *orr_group;
+
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi, name);
+ if (!orr_group)
+ return CMD_WARNING;
+
+ /* Check if there are any neighbors configured with this ORR Group */
+ if (orr_group->rr_client_list) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' not removed as '%s' is configured on neighbor(s)",
+ __func__,
+ get_afi_safi_str(orr_group->afi, orr_group->safi,
+ false),
+ name, name);
+ return CMD_WARNING;
+ }
+
+ bgp_orr_group_free(orr_group);
+ return CMD_SUCCESS;
+}
+
+/* Set optimal route reflection group to the peer */
+static int peer_orr_group_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name)
+{
+ struct bgp_orr_group *orr_group = NULL;
+
+ if (!peer)
+ return CMD_WARNING;
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ /* Create BGP ORR entry for the given address-family */
+ orr_group =
+ bgp_orr_group_new(peer->bgp, afi, safi, orr_group_name);
+ }
+
+ /* Skip processing if there is no change in ORR Group */
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP)) {
+ if (strmatch(peer->orr_group_name[afi][safi], orr_group_name)) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' is already configured on %pBP",
+ __func__, get_afi_safi_str(afi, safi, false),
+ orr_group_name, peer);
+ return CMD_SUCCESS;
+ }
+ /* Remove the peer from ORR Group's peer list */
+ bgp_orr_group_rrclient_update(peer, afi, safi,
+ peer->orr_group_name[afi][safi],
+ false);
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME,
+ peer->orr_group_name[afi][safi]);
+ }
+
+ peer->orr_group_name[afi][safi] =
+ XSTRDUP(MTYPE_BGP_ORR_GROUP_NAME, orr_group_name);
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORR_GROUP);
+
+ /* Add the peer to ORR Group's client list */
+ bgp_orr_group_rrclient_update(peer, afi, safi, orr_group_name, true);
+
+ /* Update ORR group active root and register with IGP */
+ bgp_peer_update_orr_group_active_root(peer, afi, safi, orr_group);
+
+ return CMD_SUCCESS;
+}
+
+/* Unset optimal route reflection group from the peer*/
+int peer_orr_group_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name)
+{
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(peer && peer->bgp && orr_group_name);
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP) ||
+ !strmatch(peer->orr_group_name[afi][safi], orr_group_name)) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' is not configured on %pBP",
+ __func__, get_afi_safi_str(afi, safi, false),
+ orr_group_name, peer);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* Check if this RR Client is one of the root nodes */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+
+ /* Should not be Null when orr-group is enabled on peer */
+ assert(orr_group);
+
+ /* Check if the peer is one of the root nodes of the ORR group */
+ if (is_orr_root_node(orr_group, peer->host))
+ return CMD_WARNING;
+
+ /* Remove the peer from ORR Group's client list */
+ bgp_orr_group_rrclient_update(peer, afi, safi, orr_group_name, false);
+
+ /* Update ORR group active root and unregister with IGP */
+ bgp_peer_update_orr_group_active_root(peer, afi, safi, orr_group);
+
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORR_GROUP);
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME, peer->orr_group_name[afi][safi]);
+
+ return CMD_SUCCESS;
+}
+
+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)
+{
+ int ret = CMD_WARNING_CONFIG_FAILED;
+ struct bgp *bgp;
+ struct peer *primary = NULL, *secondary = NULL, *tertiary = NULL;
+
+ bgp = bgp_get_default();
+ if (!bgp) {
+ vty_out(vty, "%% No BGP process is configured\n");
+ return ret;
+ }
+
+ if (unset) {
+ ret = bgp_afi_safi_orr_group_unset(bgp, afi, safi, name);
+ if (ret != CMD_SUCCESS)
+ vty_out(vty,
+ "%% ORR Group %s not removed as '%s' is not found OR configured on neighbor(s)\n",
+ name, name);
+ return ret;
+ }
+
+ primary = peer_and_group_lookup_vty(vty, primary_str);
+ if (!primary || !peer_af_flag_check(primary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Primary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+
+ if (secondary_str) {
+ secondary = peer_and_group_lookup_vty(vty, secondary_str);
+ if (!secondary ||
+ !peer_af_flag_check(secondary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Secondary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+ }
+
+ if (tertiary_str) {
+ tertiary = peer_and_group_lookup_vty(vty, tertiary_str);
+ if (!tertiary ||
+ !peer_af_flag_check(tertiary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Tertiary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+ }
+ return bgp_afi_safi_orr_group_set(bgp, afi, safi, name, primary,
+ secondary, tertiary);
+}
+
+/* Set optimal route reflection group name to the peer. */
+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)
+{
+ int ret = CMD_WARNING_CONFIG_FAILED;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, ip_str);
+ if (!peer)
+ return ret;
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty, "%% Neighbor %s is not a Route Reflector Client\n",
+ peer->host);
+ return ret;
+ }
+
+ if (!unset) {
+ ret = peer_orr_group_set(peer, afi, safi, orr_group_name);
+ if (ret != CMD_SUCCESS)
+ vty_out(vty, "%% ORR Group '%s' is not configured\n",
+ orr_group_name);
+ } else {
+ ret = peer_orr_group_unset(peer, afi, safi, orr_group_name);
+ if (ret == CMD_ERR_NO_MATCH)
+ vty_out(vty,
+ "%% ORR Group '%s' is not configured on %s\n",
+ orr_group_name, peer->host);
+ else if (ret == CMD_WARNING)
+ vty_out(vty,
+ "%% %s is one of the root nodes of ORR Group '%s'.\n",
+ peer->host, orr_group_name);
+ }
+ return bgp_vty_return(vty, ret);
+}
+
+void bgp_config_write_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
+{
+ struct list *orr_group_list;
+ struct listnode *node;
+ struct bgp_orr_group *orr_group;
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group)) {
+ /* optimal route reflection configuration */
+ vty_out(vty, " optimal-route-reflection %s", orr_group->name);
+ if (orr_group->primary)
+ vty_out(vty, " %s", orr_group->primary->host);
+ if (orr_group->secondary)
+ vty_out(vty, " %s", orr_group->secondary->host);
+ if (orr_group->tertiary)
+ vty_out(vty, " %s", orr_group->tertiary->host);
+ vty_out(vty, "\n");
+ }
+}
+
+static void bgp_show_orr_group(struct vty *vty, struct bgp_orr_group *orr_group,
+ afi_t afi, safi_t safi)
+{
+ char *rrclient = NULL;
+ struct listnode *node;
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct list *orr_group_igp_metric_info = NULL;
+
+ if (!orr_group)
+ return;
+
+ vty_out(vty, "\nORR group: %s, %s\n", orr_group->name,
+ get_afi_safi_str(afi, safi, false));
+ vty_out(vty, "Configured root:");
+ vty_out(vty, " primary: %pBP,", orr_group->primary);
+ vty_out(vty, " secondary: %pBP,", orr_group->secondary);
+ vty_out(vty, " tertiary: %pBP\n", orr_group->tertiary);
+ vty_out(vty, "Active Root: %pBP\n", orr_group->active);
+
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ return;
+
+ vty_out(vty, "\nRR Clients mapped:\n");
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node, rrclient))
+ vty_out(vty, "%s\n", rrclient);
+
+ vty_out(vty, "\nNumber of mapping entries: %d\n\n",
+ orr_group_rrclient_list->count);
+
+
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (!orr_group_igp_metric_info)
+ return;
+ vty_out(vty, "Prefix\t\t\t\t\t\tCost\n");
+ for (ALL_LIST_ELEMENTS_RO(orr_group_igp_metric_info, node,
+ igp_metric)) {
+ vty_out(vty, "%pFX\t\t\t\t\t\t%d\n", &igp_metric->prefix,
+ igp_metric->igp_metric);
+ }
+ vty_out(vty, "\nNumber of mapping entries: %d\n\n",
+ orr_group_igp_metric_info->count);
+}
+
+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)
+{
+ struct listnode *node;
+ struct bgp_orr_group *orr_group = NULL;
+ struct list *orr_group_list = NULL;
+ int ret = 0;
+
+ assert(bgp);
+
+ /* Display the matching entries for the given ORR Group */
+ if (orr_group_name) {
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ vty_out(vty, "%% ORR Group %s not found\n",
+ orr_group_name);
+ return CMD_WARNING;
+ }
+ bgp_show_orr_group(vty, orr_group, afi, safi);
+ return ret;
+ }
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return ret;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group))
+ bgp_show_orr_group(vty, orr_group, afi, safi);
+
+ return ret;
+}
+
+/* Check if the Route Reflector Client belongs to any ORR Group */
+bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi)
+{
+ char *rrclient = NULL;
+ struct listnode *node;
+ struct list *orr_group_list = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(peer && peer->bgp);
+
+ orr_group_list = peer->bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return false;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group)) {
+ /* Check if peer configured as primary/secondary/tertiary root
+ */
+ if (is_orr_root_node(orr_group, peer->host))
+ return true;
+ /*
+ * Check if peer is mapped to any ORR Group in this
+ * Address Family.
+ */
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node,
+ rrclient))
+ if (strmatch(rrclient, peer->host))
+ return true;
+ }
+ return false;
+}
+
+static void
+bgp_peer_update_orr_group_active_root(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_orr_group *orr_group)
+{
+ assert(peer && orr_group);
+
+ /* Nothing to do if this peer is not one of the root nodes */
+ if (!is_orr_root_node(orr_group, peer->host))
+ return;
+
+ /* Root is reachable and group member, update Active Root if needed */
+ if (is_peer_active_eligible(peer, afi, safi, orr_group->name)) {
+ /* Nothing to do, if this is the current Active Root */
+ if (is_orr_active_root(orr_group, peer->host))
+ return;
+
+ /* If Active is null, update this node as Active Root */
+ if (!orr_group->active) {
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /* If this is Primary and current Active is not Primary */
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /*
+ * If this is Secondary and current Active is not
+ * Primary/Secondary
+ */
+ if (is_orr_secondary_root(orr_group, peer->host)) {
+ if (is_orr_active_root(orr_group,
+ orr_group->primary->host))
+ return;
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ return;
+ }
+
+ /* Non Active Root is unreachable, so nothing to do */
+ if (!is_orr_active_root(orr_group, peer->host))
+ return;
+
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ /* If secondary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->secondary, afi, safi,
+ orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /* If tertiary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->tertiary, afi, safi,
+ orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ } else {
+ if (is_orr_secondary_root(orr_group, peer->host)) {
+ /* If tertiary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->tertiary, afi,
+ safi, orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ }
+ }
+
+ /* Assign Active as null */
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = NULL;
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' has no active root", __func__,
+ get_afi_safi_str(afi, safi, false),
+ peer->orr_group_name[afi][safi]);
+}
+
+void bgp_peer_update_orr_active_roots(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_orr_group *orr_group;
+
+ assert(peer && peer->bgp);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->orr_group_name[afi][safi])
+ continue;
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(
+ peer->bgp, afi, safi, peer->orr_group_name[afi][safi]);
+ assert(orr_group);
+
+ /* Free ORR related memory. */
+ if (peer->status != Deleted) {
+ bgp_peer_update_orr_group_active_root(peer, afi, safi,
+ orr_group);
+ continue;
+ }
+
+ if (!is_orr_root_node(orr_group, peer->host)) {
+ peer_orr_group_unset(peer, afi, safi,
+ peer->orr_group_name[afi][safi]);
+ continue;
+ }
+
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ orr_group->primary = orr_group->secondary;
+ orr_group->secondary = orr_group->tertiary;
+ } else if (is_orr_secondary_root(orr_group, peer->host))
+ orr_group->secondary = orr_group->tertiary;
+ orr_group->tertiary = NULL;
+
+ bgp_afi_safi_orr_group_set(peer->bgp, afi, safi,
+ orr_group->name, orr_group->primary,
+ orr_group->secondary,
+ orr_group->tertiary);
+ peer_orr_group_unset(peer, afi, safi,
+ peer->orr_group_name[afi][safi]);
+ }
+}
+
+/* IGP metric calculated from Active Root */
+static int bgp_orr_igp_metric_update(struct orr_igp_metric_info *table)
+{
+ afi_t afi;
+ safi_t safi;
+ bool add = false;
+ bool root_found = false;
+ uint32_t instId = 0;
+ uint32_t numEntries = 0;
+ uint32_t entry = 0;
+ uint8_t proto = ZEBRA_ROUTE_MAX;
+ struct bgp *bgp = NULL;
+ struct prefix pfx, root = {0};
+
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *group = NULL;
+ struct listnode *node, *nnode;
+
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *bgp_orr_igp_metric = NULL;
+
+ bgp = bgp_get_default();
+ assert(bgp && table);
+
+ proto = table->proto;
+ afi = family2afi(table->root.family);
+ safi = table->safi;
+ instId = table->instId;
+ add = table->add;
+ numEntries = table->num_entries;
+ prefix_copy(&root, &table->root);
+
+ if ((proto != ZEBRA_ROUTE_OSPF) && (proto != ZEBRA_ROUTE_OSPF6) &&
+ (proto != ZEBRA_ROUTE_ISIS)) {
+ bgp_orr_debug("%s: Message received from unsupported protocol",
+ __func__);
+ return -1;
+ }
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list) {
+ bgp_orr_debug(
+ "%s: Address family %s has no ORR Groups configured",
+ __func__, get_afi_safi_str(afi, safi, false));
+ return -1;
+ }
+
+ if (BGP_DEBUG(optimal_route_reflection, ORR)) {
+ zlog_debug(
+ "[BGP-ORR] %s: Received metric update from protocol %s instance %d",
+ __func__,
+ proto == ZEBRA_ROUTE_ISIS
+ ? "ISIS"
+ : (proto == ZEBRA_ROUTE_OSPF ? "OSPF"
+ : "OSPF6"),
+ instId);
+ zlog_debug("[BGP-ORR] %s: Address family %s", __func__,
+ get_afi_safi_str(afi, safi, false));
+ zlog_debug("[BGP-ORR] %s: Root %pFX", __func__, &root);
+ zlog_debug("[BGP-ORR] %s: Number of entries to be %s %d",
+ __func__, add ? "added" : "deleted", numEntries);
+ zlog_debug("[BGP-ORR] %s: Prefix (Cost) :", __func__);
+ for (entry = 0; entry < numEntries; entry++)
+ zlog_debug("[BGP-ORR] %s: %pFX (%d)", __func__,
+ &table->nexthop[entry].prefix,
+ table->nexthop[entry].metric);
+ }
+ /*
+ * Update IGP metric info of all ORR Groups having this as active root
+ */
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, group)) {
+ if (str2prefix(group->active->host, &pfx) == 0) {
+ bgp_orr_debug("%s: Malformed prefix for %pBP", __func__,
+ group->active);
+ continue;
+ }
+ /*
+ * Copy IGP info if root matches with the active root of the
+ * group
+ */
+ if (prefix_cmp(&pfx, &root) == 0) {
+ if (add) {
+ /* Add new routes */
+ if (!group->igp_metric_info)
+ group->igp_metric_info = list_new();
+
+ bgp_orr_igp_metric = group->igp_metric_info;
+ if (!bgp_orr_igp_metric)
+ bgp_orr_igp_metric_register(group,
+ false);
+ assert(bgp_orr_igp_metric);
+
+ for (entry = 0; entry < numEntries; entry++) {
+ igp_metric = XCALLOC(
+ MTYPE_ORR_IGP_INFO,
+ sizeof(struct
+ bgp_orr_igp_metric));
+ if (!igp_metric)
+ bgp_orr_igp_metric_register(
+ group, false);
+
+ prefix_copy(
+ &igp_metric->prefix,
+ &table->nexthop[entry].prefix);
+ igp_metric->igp_metric =
+ table->nexthop[entry].metric;
+ listnode_add(bgp_orr_igp_metric,
+ igp_metric);
+ }
+ } else {
+ /* Delete old routes */
+ for (entry = 0; entry < numEntries; entry++) {
+ for (ALL_LIST_ELEMENTS(
+ group->igp_metric_info,
+ node, nnode, igp_metric)) {
+ if (prefix_cmp(
+ &igp_metric->prefix,
+ &table->nexthop[entry]
+ .prefix))
+ continue;
+ listnode_delete(
+ group->igp_metric_info,
+ igp_metric);
+ XFREE(MTYPE_ORR_IGP_INFO,
+ igp_metric);
+ }
+ }
+ }
+ root_found = true;
+ break;
+ }
+ }
+ /* Received IGP for root node thats not found in ORR active roots */
+ if (!root_found) {
+ bgp_orr_debug(
+ "%s: Received IGP SPF information for root %pFX which is not an ORR active root",
+ __func__, &root);
+ }
+ assert(root_found);
+ return 0;
+}
+
+/* Register with IGP for sending SPF info */
+static void bgp_orr_igp_metric_register(struct bgp_orr_group *orr_group,
+ bool reg)
+{
+ int ret;
+ struct orr_igp_metric_reg msg;
+ struct prefix p;
+ char *rr_client = NULL;
+
+ assert(orr_group);
+
+ if (!orr_group->active)
+ return;
+
+ memset(&msg, 0, sizeof(msg));
+ ret = str2prefix(orr_group->active->host, &p);
+
+ /* Malformed prefix */
+ assert(ret);
+
+ /* Check if the active root is part of this ORR group */
+ rr_client = bgp_orr_group_rrclient_lookup(orr_group,
+ orr_group->active->host);
+ if (reg && !rr_client) {
+ bgp_orr_debug(
+ "%s: active root %pBP is not part of this ORR group",
+ __func__, orr_group->active);
+ return;
+ }
+
+ msg.reg = reg;
+ msg.proto = ZEBRA_ROUTE_BGP;
+ msg.safi = orr_group->safi;
+ prefix_copy(&msg.prefix, &p);
+ strlcpy(msg.group_name, orr_group->name, sizeof(msg.group_name));
+
+ bgp_orr_debug(
+ "%s: %s with IGP for metric calculation from location %pFX",
+ __func__, reg ? "Register" : "Unregister", &msg.prefix);
+
+ if (zclient_send_opaque(zclient, ORR_IGP_METRIC_REGISTER,
+ (uint8_t *)&msg,
+ sizeof(msg)) == ZCLIENT_SEND_FAILURE)
+ zlog_warn("[BGP-ORR] %s: Failed to send message to IGP.",
+ __func__);
+
+ /* Free IGP metric info calculated from previous active location */
+ if (!reg && orr_group->igp_metric_info)
+ list_delete(&orr_group->igp_metric_info);
+}
+
+/* BGP ORR message processing */
+int bgg_orr_message_process(enum bgp_orr_msg_type msg_type, void *msg)
+{
+ int ret = 0;
+
+ assert(msg && msg_type > BGP_ORR_IMSG_INVALID &&
+ msg_type < BGP_ORR_IMSG_MAX);
+ switch (msg_type) {
+ case BGP_ORR_IMSG_GROUP_CREATE:
+ break;
+ case BGP_ORR_IMSG_GROUP_DELETE:
+ break;
+ case BGP_ORR_IMSG_GROUP_UPDATE:
+ break;
+ case BGP_ORR_IMSG_SET_ORR_ON_PEER:
+ break;
+ case BGP_ORR_IMSG_UNSET_ORR_ON_PEER:
+ break;
+ case BGP_ORR_IMSG_IGP_METRIC_UPDATE:
+ ret = bgp_orr_igp_metric_update(
+ (struct orr_igp_metric_info *)msg);
+ break;
+ case BGP_ORR_IMSG_SHOW_ORR:
+ /* bgp_show_orr */
+ break;
+ case BGP_ORR_IMSG_SHOW_ORR_GROUP:
+ /* bgp_show_orr_group */
+ break;
+ default:
+ break;
+ }
+
+ /* Free Memory */
+ return ret;
+}
+
+/*
+ * Cleanup ORR information - invoked at the time of bgpd exit or
+ * when the BGP instance (default) is being freed.
+ */
+void bgp_orr_cleanup(struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct listnode *node, *nnode;
+ struct bgp_orr_group *orr_group;
+
+ assert(bgp);
+
+ if (!bgp->orr_group_count)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ for (ALL_LIST_ELEMENTS(bgp->orr_group[afi][safi], node, nnode,
+ orr_group))
+ bgp_orr_group_free(orr_group);
+ }
+}
diff --git a/bgpd/bgp_orr.h b/bgpd/bgp_orr.h
new file mode 100644
index 0000000000..158de30342
--- /dev/null
+++ b/bgpd/bgp_orr.h
@@ -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 */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index a07c3b331e..0b411d0ec1 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -72,6 +72,7 @@
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_orr.h"
#include "bgpd/bgp_trace.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)
{
const struct prefix *new_p;
+ struct prefix exist_p;
struct attr *newattr, *existattr;
enum bgp_peer_sort new_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;
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;
/* 0. Null check. */
@@ -1061,6 +1068,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
if (exist->extra)
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 (debug && peer_sort_ret < 0)
zlog_debug(
@@ -12406,6 +12456,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|alias ALIAS_NAME\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
+ |optimal-route-reflection [WORD$orr_group_name]\
] [json$uj [detail$detail] | wide$wide]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_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"
"IPv6 prefix\n"
"Display route and more specific routes\n"
+ "Display Optimal Route Reflection RR Clients\n"
+ "ORR Group name\n"
JSON_STR
"Display detailed version of JSON output\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;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
struct prefix p;
+ bool orr_group = false;
if (uj) {
argc--;
@@ -12644,12 +12698,18 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
output_arg = &p;
}
+ if (argv_find(argv, argc, "optimal-route-reflection", &idx))
+ orr_group = true;
+
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
return bgp_show_community(vty, bgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ return bgp_show_orr(vty, bgp, afi, safi, orr_group_name,
+ show_flags);
else
return bgp_show(vty, bgp, afi, safi, sh_type,
output_arg, show_flags,
@@ -12695,6 +12755,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
vty, abgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ bgp_show_orr(vty, bgp, afi,
+ safi,
+ orr_group_name,
+ show_flags);
else
bgp_show(vty, abgp, afi, safi,
sh_type, output_arg,
@@ -12734,6 +12799,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
vty, abgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ bgp_show_orr(vty, bgp, afi,
+ safi,
+ orr_group_name,
+ show_flags);
else
bgp_show(vty, abgp, afi, safi,
sh_type, output_arg,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 89010b61bb..10396b8b4f 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -78,6 +78,8 @@
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
+#include "bgpd/bgp_orr.h"
+
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:
str = "External roles can be set only on eBGP session";
break;
+ case BGP_ERR_PEER_ORR_CONFIGURED:
+ str = "Deconfigure optimal-route-reflection on this peer first";
+ break;
}
if (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
"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. */
DEFUN (neighbor_route_server_client,
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],
PEER_FLAG_RSERVER_CLIENT))
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))
vty_out(vty,
" 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,
@@ -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");
}
@@ -18979,6 +19033,34 @@ void bgp_vty_init(void)
install_element(BGP_EVPN_NODE, &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.*/
install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
install_element(BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 209fe1ace4..b5c13fddd0 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -67,10 +67,13 @@
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_orr.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
+static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
+
/* hook to indicate vrf status change for SNMP */
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *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_MANAGER_GET_LOCATOR_CHUNK] =
bgp_zebra_process_srv6_locator_chunk,
+ [ZEBRA_OPAQUE_MESSAGE] = bgp_opaque_msg_handler,
};
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);
}
+
+/*
+ * 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;
+}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 1bcd714407..188402d0b4 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -92,6 +92,7 @@
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_mh.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, 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. */
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;
/* Stop peer. */
@@ -1877,6 +1880,11 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
/* reflector-client reset */
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],
PEER_FLAG_REFLECTOR_CLIENT);
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]);
}
+ bgp_orr_cleanup(bgp);
+
XFREE(MTYPE_BGP, bgp->name);
XFREE(MTYPE_BGP, bgp->name_pretty);
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)
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. */
if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP)
return BGP_ERR_REMOVE_PRIVATE_AS;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 7fc9c5c1ce..b9d24969e3 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -47,6 +47,7 @@
#include "bgp_io.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_PEER_MAX_HASH_SIZE 16384
@@ -197,6 +198,40 @@ struct bgp_redist {
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 {
BGP_VPN_POLICY_DIR_FROMVPN = 0,
BGP_VPN_POLICY_DIR_TOVPN = 1,
@@ -779,6 +814,10 @@ struct bgp {
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;
};
DECLARE_QOBJ_TYPE(bgp);
@@ -1422,6 +1461,10 @@ struct peer {
#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 28)
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29)
#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];
@@ -2029,7 +2072,10 @@ enum bgp_create_error_code {
/*BGP Open Policy ERRORS */
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 *,
union sockunion *);
+extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
/*
* Peers are incredibly easy to memory leak
* 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_free(struct bgp *);
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 */
int bgp_global_gr_init(struct bgp *bgp);
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index b1eeb937e1..765650313b 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -103,6 +103,7 @@ bgpd_libbgp_a_SOURCES = \
bgpd/bgp_vty.c \
bgpd/bgp_zebra.c \
bgpd/bgpd.c \
+ bgpd/bgp_orr.c \
bgpd/bgp_trace.c \
# end
@@ -183,6 +184,7 @@ noinst_HEADERS += \
bgpd/bgp_vty.h \
bgpd/bgp_zebra.h \
bgpd/bgpd.h \
+ bgpd/bgp_orr.h \
bgpd/bgp_trace.h \
\
bgpd/rfapi/bgp_rfapi_cfg.h \
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 25d1cbfb6b..cd7a0adff9 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -3478,6 +3478,319 @@ When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2
Total number of prefixes 3
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:
Debugging
@@ -3543,6 +3856,10 @@ Debugging
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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 3bb018548e..3aa3d47f35 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -831,6 +831,12 @@ Showing Information
Show the OSPF routing table, as determined by the most recent SPF
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]
Displays the Grcaeful Restart Helper details including helper
@@ -1138,6 +1144,10 @@ Debugging OSPF
.. clicmd:: show debugging ospf
+.. clicmd:: debug ospf orr
+
+ Enable or disable debugging of BGP Optimal Route Reflection.
+
Sample Configuration
====================
diff --git a/lib/command.h b/lib/command.h
index ca49efd262..42b4406212 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -417,6 +417,7 @@ struct cmd_node {
#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_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 NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions\n"
diff --git a/lib/orr_msg.h b/lib/orr_msg.h
new file mode 100644
index 0000000000..b0c4c48df8
--- /dev/null
+++ b/lib/orr_msg.h
@@ -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 */
diff --git a/lib/subdir.am b/lib/subdir.am
index d6defd7149..e04e700eb6 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -245,6 +245,7 @@ pkginclude_HEADERS += \
lib/ns.h \
lib/openbsd-queue.h \
lib/openbsd-tree.h \
+ lib/orr_msg.h \
lib/plist.h \
lib/prefix.h \
lib/printfrr.h \
diff --git a/lib/zclient.h b/lib/zclient.h
index c3ea2a16ff..fb5da9aad2 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -100,6 +100,8 @@ enum zserv_client_capabilities {
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
+#define ZAPI_ORR_FLAG_UNICAST 0x01
+
/* Zebra message types. */
typedef enum {
ZEBRA_INTERFACE_ADD,
@@ -1229,6 +1231,10 @@ enum zapi_opaque_registry {
LDP_RLFA_UNREGISTER_ALL = 8,
/* Announce LDP labels associated to a previously registered RLFA */
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.
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index 9f6adf3226..59f95c5da2 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -63,6 +63,7 @@ unsigned long conf_debug_ospf_ldp_sync;
unsigned long conf_debug_ospf_gr;
unsigned long conf_debug_ospf_bfd;
unsigned long conf_debug_ospf_client_api;
+unsigned long conf_debug_ospf_orr;
/* Enable debug option variables -- valid only session. */
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_bfd;
unsigned long term_debug_ospf_client_api;
+unsigned long term_debug_ospf_orr;
const char *ospf_redist_string(unsigned int route_type)
{
@@ -1601,6 +1603,33 @@ DEFPY (debug_ospf_client_api,
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,
no_debug_ospf_cmd,
"no debug ospf",
@@ -1643,6 +1672,8 @@ DEFUN (no_debug_ospf,
for (i = 0; i < 5; i++)
DEBUG_PACKET_OFF(i, flag);
+
+ DEBUG_OFF(orr, ORR);
}
for (i = 0; i < 5; i++)
@@ -1673,6 +1704,7 @@ DEFUN (no_debug_ospf,
TERM_DEBUG_OFF(ti_lfa, TI_LFA);
TERM_DEBUG_OFF(bfd, BFD_LIB);
TERM_DEBUG_OFF(client_api, CLIENT_API);
+ TERM_DEBUG_OFF(orr, ORR);
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)
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;
}
@@ -2014,6 +2052,12 @@ static int config_write_debug(struct vty *vty)
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;
}
@@ -2035,6 +2079,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &debug_ospf_default_info_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_orr_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_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_ldp_sync_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_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 251be7c8d1..e9ba8fc798 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -70,6 +70,8 @@
#define OSPF_DEBUG_CLIENT_API 0x01
+#define OSPF_DEBUG_ORR 0x01
+
/* Macro for setting debug option. */
#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)
@@ -129,6 +131,8 @@
#define AREA_NAME(A) ospf_area_name_string ((A))
#define IF_NAME(I) ospf_if_name_string ((I))
+#define IS_DEBUG_OSPF_ORR IS_DEBUG_OSPF(orr, ORR)
+
/* Extern debug flag. */
extern unsigned long term_debug_ospf_packet[];
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_bfd;
extern unsigned long term_debug_ospf_client_api;
+extern unsigned long term_debug_ospf_orr;
/* Message Strings. */
extern char *ospf_lsa_type_str[];
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 0df0072f6d..c67181cba6 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -52,6 +52,8 @@
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_abr.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,
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);
}
+ /* 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)
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL);
return new;
@@ -2651,7 +2660,6 @@ static struct ospf_lsa *ospf_network_lsa_install(struct ospf *ospf,
struct ospf_lsa *new,
int rt_recalc)
{
-
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
The entire routing table must be recalculated, starting with
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;
}
+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 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 prefix_ipv4 p;
- assert(CHECK_FLAG(lsa->flags, OSPF_LSA_SELF));
- assert(IS_LSA_SELF(lsa));
+ if (!CHECK_FLAG(lsa->flags, OSPF_LSA_SELF) && !IS_LSA_SELF(lsa) &&
+ !IS_LSA_ORR(lsa))
+ return NULL;
assert(lsa->lock > 0);
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;
assert(lsa->lock > 0);
- assert(IS_LSA_SELF(lsa));
+ if (!IS_LSA_SELF(lsa) && !IS_LSA_ORR(lsa))
+ return;
if (lsa->refresh_list < 0) {
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)
{
assert(lsa->lock > 0);
- assert(IS_LSA_SELF(lsa));
+ if (!IS_LSA_SELF(lsa) || !IS_LSA_ORR(lsa))
+ return;
if (lsa->refresh_list >= 0) {
struct list *refresh_list =
ospf->lsa_refresh_queue.qs[lsa->refresh_list];
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 97c15d1e3c..a2a2393c90 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -74,15 +74,16 @@ struct vertex;
/* OSPF LSA. */
struct ospf_lsa {
/* LSA origination flag. */
- uint8_t flags;
-#define OSPF_LSA_SELF 0x01
-#define OSPF_LSA_SELF_CHECKED 0x02
-#define OSPF_LSA_RECEIVED 0x04
-#define OSPF_LSA_APPROVED 0x08
-#define OSPF_LSA_DISCARD 0x10
-#define OSPF_LSA_LOCAL_XLT 0x20
-#define OSPF_LSA_PREMATURE_AGE 0x40
-#define OSPF_LSA_IN_MAXAGE 0x80
+ uint16_t flags;
+#define OSPF_LSA_SELF 0x0001
+#define OSPF_LSA_SELF_CHECKED 0x0002
+#define OSPF_LSA_RECEIVED 0x0004
+#define OSPF_LSA_APPROVED 0x0008
+#define OSPF_LSA_DISCARD 0x0010
+#define OSPF_LSA_LOCAL_XLT 0x0020
+#define OSPF_LSA_PREMATURE_AGE 0x0040
+#define OSPF_LSA_IN_MAXAGE 0x0080
+#define OSPF_LSA_ORR 0x0100
/* LSA data. and size */
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_MAX_SEQ(L) \
((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
@@ -292,6 +294,12 @@ extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *,
struct in_addr);
extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t,
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 *,
struct lsa_header *);
extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *);
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
index f4fb858a5f..3c65ac388d 100644
--- a/ospfd/ospf_lsdb.c
+++ b/ospfd/ospf_lsdb.c
@@ -30,6 +30,7 @@
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_orr.h"
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);
+ /* 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))
lsdb->type[lsa->data->type].count_self--;
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 */
lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum);
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)
diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c
index 2838443892..5577a291be 100644
--- a/ospfd/ospf_memory.c
+++ b/ospfd/ospf_memory.c
@@ -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_P_SPACE, "OSPF TI-LFA P-Space");
DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
+DEFINE_MTYPE(OSPFD, OSPF_ORR_ROOT, "OSPF ORR Root");
diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h
index 9bd0a844af..3d2133b11a 100644
--- a/ospfd/ospf_memory.h
+++ b/ospfd/ospf_memory.h
@@ -59,5 +59,6 @@ DECLARE_MTYPE(OSPF_GR_HELPER);
DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
DECLARE_MTYPE(OSPF_P_SPACE);
DECLARE_MTYPE(OSPF_Q_SPACE);
+DECLARE_MTYPE(OSPF_ORR_ROOT);
#endif /* _QUAGGA_OSPF_MEMORY_H */
diff --git a/ospfd/ospf_orr.c b/ospfd/ospf_orr.c
new file mode 100644
index 0000000000..eed948b190
--- /dev/null
+++ b/ospfd/ospf_orr.c
@@ -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);
+}
diff --git a/ospfd/ospf_orr.h b/ospfd/ospf_orr.h
new file mode 100644
index 0000000000..d0a6f6e790
--- /dev/null
+++ b/ospfd/ospf_orr.h
@@ -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 */
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index 6360d8ec60..26f593f089 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -151,8 +151,8 @@ void ospf_route_table_free(struct route_table *rt)
otherwise return 0. Since the ZEBRA-RIB does an implicit
withdraw, it is not necessary to send a delete, an add later
will act like an implicit delete. */
-static int ospf_route_exist_new_table(struct route_table *rt,
- struct prefix_ipv4 *prefix)
+int ospf_route_exist_new_table(struct route_table *rt,
+ struct prefix_ipv4 *prefix)
{
struct route_node *rn;
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
index fa9478fced..e7e2b651c5 100644
--- a/ospfd/ospf_route.h
+++ b/ospfd/ospf_route.h
@@ -172,5 +172,6 @@ extern void ospf_delete_discard_route(struct ospf *, struct route_table *,
struct prefix_ipv4 *);
extern int ospf_route_match_same(struct route_table *, struct prefix_ipv4 *,
struct ospf_route *);
-
+extern int ospf_route_exist_new_table(struct route_table *rt,
+ struct prefix_ipv4 *prefix);
#endif /* _ZEBRA_OSPF_ROUTE_H */
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 4edc1de811..74213d7de2 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -53,6 +53,8 @@
#include "ospfd/ospf_apiserver.h"
#endif
+#include "ospfd/ospf_orr.h"
+
/* Variables to ensure a SPF scheduled log message is printed only once */
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);
}
+/* 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. */
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_timer_add(ospf);
+ ospf_orr_spf_calculate_schedule(ospf);
+
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"%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
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
#endif
-
/* Free old ABR/ASBR routing table */
if (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 =
monotime_since(&spf_start_time, &ospf->ts_spf_duration);
- 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_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';
- }
+ ospf_spf_calculation_reason2str(rbuf);
if (IS_DEBUG_OSPF_EVENT) {
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();
}
+/* 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
* 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);
ospf->t_spf_calc = NULL;
+
thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
delay, &ospf->t_spf_calc);
}
diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h
index 834bfd0bb0..2578051c2c 100644
--- a/ospfd/ospf_spf.h
+++ b/ospfd/ospf_spf.h
@@ -70,8 +70,10 @@ typedef enum {
SPF_FLAG_ASBR_STATUS_CHANGE,
SPF_FLAG_CONFIG_CHANGE,
SPF_FLAG_GR_FINISH,
+ SPF_FLAG_ORR_ROOT_CHANGE,
} 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(struct ospf_area *area,
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_restart_spf(struct ospf *ospf);
+extern void ospf_orr_spf_calculate_schedule_worker(struct thread *thread);
/* void ospf_spf_calculate_timer_add (); */
#endif /* _QUAGGA_OSPF_SPF_H */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index c957c8c014..4f0fa6194a 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -55,6 +55,7 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_ldp_sync.h"
+#include "ospfd/ospf_orr.h"
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");
}
+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,
struct ospf *ospf,
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_border_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_border_routers_cmd);
install_element(VIEW_NODE,
&show_ip_ospf_instance_reachable_routers_cmd);
+ install_element(VIEW_NODE, &show_ip_ospf_instance_route_orr_cmd);
/* "show ip ospf vrfs" commands. */
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 1754512b5b..4615864244 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -53,6 +53,7 @@
#include "ospfd/ospf_te.h"
#include "ospfd/ospf_sr.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_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);
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_announce announce;
struct zapi_opaque_reg_info dst;
+ struct orr_igp_metric_reg orr_reg;
int ret = 0;
s = zclient->ibuf;
@@ -2116,6 +2119,10 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
STREAM_GET(&announce, s, sizeof(announce));
ret = ospf_ldp_sync_announce_update(announce);
break;
+ case ORR_IGP_METRIC_REGISTER:
+ STREAM_GET(&orr_reg, s, sizeof(orr_reg));
+ ret = ospf_orr_igp_metric_register(orr_reg);
+ break;
default:
break;
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index e0c36d86fe..3f82d86921 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -795,6 +795,7 @@ static void ospf_finish_final(struct ospf *ospf)
THREAD_OFF(ospf->t_write);
THREAD_OFF(ospf->t_spf_calc);
THREAD_OFF(ospf->t_ase_calc);
+ THREAD_OFF(ospf->t_orr_calc);
THREAD_OFF(ospf->t_maxage);
THREAD_OFF(ospf->t_maxage_walker);
THREAD_OFF(ospf->t_abr_task);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 3a43010f85..c7735136bc 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -35,6 +35,8 @@
#include "ospf_memory.h"
#include "ospf_dump_api.h"
+#include "orr_msg.h"
+
#define OSPF_VERSION 2
/* VTY port number. */
@@ -261,6 +263,7 @@ struct ospf {
struct thread *t_distribute_update; /* Distirbute list update timer. */
struct thread *t_spf_calc; /* SPF calculation timer. */
struct thread *t_ase_calc; /* ASE calculation timer. */
+ struct thread *t_orr_calc; /* ORR calculation timer. */
struct thread
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
struct thread *t_sr_update; /* Segment Routing update timer */
@@ -406,6 +409,10 @@ struct ospf {
bool ti_lfa_enabled;
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;
};
DECLARE_QOBJ_TYPE(ospf);
@@ -591,6 +598,9 @@ struct ospf_area {
uint32_t act_ints; /* Active interfaces. */
uint32_t full_nbrs; /* Fully adjacent neighbors. */
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
+
+ /* BGP-ORR Received LSAs */
+ struct ospf_lsa *router_lsa_rcvd;
};
/* OSPF config network structure. */
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 4f9cbc7b1e..78688fac95 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -48,6 +48,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_network.c \
ospfd/ospf_nsm.c \
ospfd/ospf_opaque.c \
+ ospfd/ospf_orr.c \
ospfd/ospf_packet.c \
ospfd/ospf_ri.c \
ospfd/ospf_route.c \
@@ -101,6 +102,7 @@ noinst_HEADERS += \
ospfd/ospf_memory.h \
ospfd/ospf_neighbor.h \
ospfd/ospf_network.h \
+ ospfd/ospf_orr.h \
ospfd/ospf_packet.h \
ospfd/ospf_ri.h \
ospfd/ospf_gr.h \