#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"
const struct prefix *prefix),
(peer, attr, prefix));
-/* Render dest to prefix_rd based on safi */
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
- safi_t safi);
-
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
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;
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. */
return 0;
}
+ /* If a BGP speaker supports ACCEPT_OWN and is configured for the
+ * extensions defined in this document, the following step is inserted
+ * after the LOCAL_PREF comparison step in the BGP decision process:
+ * When comparing a pair of routes for a BGP destination, the
+ * route with the ACCEPT_OWN community attached is preferred over
+ * the route that does not have the community.
+ * This extra step MUST only be invoked during the best path selection
+ * process of VPN-IP routes.
+ */
+ if (safi == SAFI_MPLS_VPN &&
+ (CHECK_FLAG(new->peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN) ||
+ CHECK_FLAG(exist->peer->af_flags[afi][safi],
+ PEER_FLAG_ACCEPT_OWN))) {
+ bool new_accept_own = false;
+ bool exist_accept_own = false;
+ uint32_t accept_own = COMMUNITY_ACCEPT_OWN;
+
+ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ new_accept_own = community_include(
+ bgp_attr_get_community(newattr), accept_own);
+ if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ exist_accept_own = community_include(
+ bgp_attr_get_community(existattr), accept_own);
+
+ if (new_accept_own && !exist_accept_own) {
+ *reason = bgp_path_selection_accept_own;
+ if (debug)
+ zlog_debug(
+ "%s: %s wins over %s due to accept-own",
+ pfx_buf, new_buf, exist_buf);
+ return 1;
+ }
+
+ if (!new_accept_own && exist_accept_own) {
+ *reason = bgp_path_selection_accept_own;
+ if (debug)
+ zlog_debug(
+ "%s: %s loses to %s due to accept-own",
+ pfx_buf, new_buf, exist_buf);
+ return 0;
+ }
+ }
+
/* 3. Local route check. We prefer:
* - BGP_ROUTE_STATIC
* - BGP_ROUTE_AGGREGATE
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(
bgp_attr_set_community(attr, new);
}
+static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi,
+ struct attr *attr, const struct prefix *prefix,
+ int *sub_type)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ bool accept_own_found = false;
+
+ if (safi != SAFI_MPLS_VPN)
+ return false;
+
+ /* Processing of the ACCEPT_OWN community is enabled by configuration */
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN))
+ return false;
+
+ /* The route in question carries the ACCEPT_OWN community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
+ struct community *comm = bgp_attr_get_community(attr);
+
+ if (community_include(comm, COMMUNITY_ACCEPT_OWN))
+ accept_own_found = true;
+ }
+
+ /* The route in question is targeted to one or more destination VRFs
+ * on the router (as determined by inspecting the Route Target(s)).
+ */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ if (accept_own_found &&
+ ecommunity_include(
+ bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
+ bgp_attr_get_ecommunity(attr))) {
+ if (bgp_debug_update(peer, prefix, NULL, 1))
+ zlog_debug(
+ "%pBP prefix %pFX has ORIGINATOR_ID, but it's accepted due to ACCEPT_OWN",
+ peer, prefix);
+
+ /* Treat this route as imported, because it's leaked
+ * already from another VRF, and we got an updated
+ * version from route-reflector with ACCEPT_OWN
+ * community.
+ */
+ *sub_type = BGP_ROUTE_IMPORTED;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
bool force_evpn_import = false;
safi_t orig_safi = safi;
bool leak_success = true;
+ int allowas_in = 0;
if (frrtrace_enabled(frr_bgp, process_update)) {
char pfxprint[PREFIX2STR_BUFFER];
&& peer != bgp->peer_self)
bgp_adj_in_set(dest, peer, attr, addpath_id);
+ /* Update permitted loop count */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
+ allowas_in = peer->allowas_in[afi][safi];
+
/* Check previously received route. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == peer && pi->type == type
/* AS path local-as loop check. */
if (peer->change_local_as) {
- if (peer->allowas_in[afi][safi])
- aspath_loop_count = peer->allowas_in[afi][safi];
+ if (allowas_in)
+ aspath_loop_count = allowas_in;
else if (!CHECK_FLAG(peer->flags,
PEER_FLAG_LOCAL_AS_NO_PREPEND))
aspath_loop_count = 1;
/* AS path loop check. */
if (do_loop_check) {
- if (aspath_loop_check(attr->aspath, bgp->as)
- > peer->allowas_in[afi][safi]
- || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
- && aspath_loop_check(attr->aspath, bgp->confed_id)
- > peer->allowas_in[afi][safi])) {
+ if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
+ (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) &&
+ (aspath_loop_check(attr->aspath, bgp->confed_id) >
+ allowas_in))) {
peer->stat_pfx_aspath_loop++;
reason = "as-path contains our own AS;";
goto filtered;
}
}
- /* Route reflector originator ID check. */
+ /* Route reflector originator ID check. If ACCEPT_OWN mechanism is
+ * enabled, then take care of that too.
+ */
+ bool accept_own = false;
+
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)
&& IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) {
- peer->stat_pfx_originator_loop++;
- reason = "originator is us;";
- goto filtered;
+ accept_own =
+ bgp_accept_own(peer, afi, safi, attr, p, &sub_type);
+ if (!accept_own) {
+ peer->stat_pfx_originator_loop++;
+ reason = "originator is us;";
+ goto filtered;
+ }
}
/* Route reflector cluster ID check. */
bgp_path_info_unset_flag(dest, pi,
BGP_PATH_VALID);
}
- } else
+ } else {
+ if (accept_own)
+ bgp_path_info_set_flag(dest, pi,
+ BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
+ }
#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-
- leak_success = vpn_leak_to_vrf_update(bgp, pi);
+ leak_success = vpn_leak_to_vrf_update(bgp, pi, prd);
}
#ifdef ENABLE_BGP_VNC
}
bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID);
}
- } else
+ } else {
+ if (accept_own)
+ bgp_path_info_set_flag(dest, new, BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
+ }
/* Addpath ID */
new->addpath_rx_id = addpath_id;
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
- leak_success = vpn_leak_to_vrf_update(bgp, new);
+ leak_success = vpn_leak_to_vrf_update(bgp, new, prd);
}
#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
if (SAFI_MPLS_VPN == safi
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
- vpn_leak_to_vrf_update(bgp, pi);
+ vpn_leak_to_vrf_update(bgp, pi,
+ &bgp_static->prd);
}
#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd,
if (SAFI_MPLS_VPN == safi
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
- vpn_leak_to_vrf_update(bgp, new);
+ vpn_leak_to_vrf_update(bgp, new, &bgp_static->prd);
}
#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
return "Weight";
case bgp_path_selection_local_pref:
return "Local Pref";
+ case bgp_path_selection_accept_own:
+ return "Accept Own";
case bgp_path_selection_local_route:
return "Local Route";
case bgp_path_selection_confed_as_path:
vty_out(vty, "I");
else if (rpki_state == RPKI_NOTFOUND)
vty_out(vty, "N");
+ else
+ vty_out(vty, " ");
/* Route status display. */
if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED))
/*
* Return rd based on safi
*/
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
- safi_t safi)
+const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
+ safi_t safi)
{
switch (safi) {
case SAFI_MPLS_VPN:
return (struct prefix_rd *)(bgp_dest_get_prefix(dest));
default:
return NULL;
-
}
}
return CMD_WARNING;
if (argv_find(argv, argc, "AA:BB:CC", &idx)) {
- if (argv_find(argv, argc, "exact-match", &idx))
+ if (argv_find(argv, argc, "exact-match", &idx)) {
+ argc--;
exact_match = 1;
+ }
return bgp_show_lcommunity(vty, bgp, argc, argv,
exact_match, afi, safi, uj);
} else
|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
"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")
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--;
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,
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,
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,