return 0;
}
+int
+aspath_get_firstas (struct aspath *aspath)
+{
+ if (aspath == NULL || aspath->segments == NULL)
+ return 0;
+
+ return aspath->segments->as[0];
+}
+
/* AS path loop check. If aspath contains asno then return >= 1. */
int
aspath_loop_check (struct aspath *aspath, as_t asno)
extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *);
extern void aspath_print_all_vty (struct vty *);
extern unsigned int aspath_key_make (void *);
+extern int aspath_get_firstas (struct aspath *);
extern int aspath_loop_check (struct aspath *, as_t);
extern int aspath_private_as_check (struct aspath *);
extern int aspath_single_asn_check (struct aspath *, as_t asn);
/* Only advertise addpath TX if a feature that will use it is
* configured */
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS) ||
+ CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
adv_addpath_tx = 1;
}
return 0;
}
+ /* If this is not the bestpath then check to see if there is an enabled addpath
+ * feature that requires us to advertise it */
+ if (! CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+ {
+ if (! bgp_addpath_tx_path(peer, afi, safi, ri))
+ {
+ return 0;
+ }
+ }
+
/* Aggregate-address suppress check. */
if (ri->extra && ri->extra->suppress)
if (! UNSUPPRESS_MAP_NAME (filter))
/* bgp deterministic-med */
new_select = NULL;
if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
- for (ri1 = rn->info; ri1; ri1 = ri1->next)
- {
- if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK))
- continue;
- if (BGP_INFO_HOLDDOWN (ri1))
- continue;
- if (ri1->peer && ri1->peer != bgp->peer_self)
- if (ri1->peer->status != Established)
+ {
+
+ /* Clear BGP_INFO_DMED_SELECTED for all paths */
+ for (ri1 = rn->info; ri1; ri1 = ri1->next)
+ bgp_info_unset_flag (rn, ri1, BGP_INFO_DMED_SELECTED);
+
+ for (ri1 = rn->info; ri1; ri1 = ri1->next)
+ {
+ if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK))
continue;
+ if (BGP_INFO_HOLDDOWN (ri1))
+ continue;
+ if (ri1->peer && ri1->peer != bgp->peer_self)
+ if (ri1->peer->status != Established)
+ continue;
- new_select = ri1;
- old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL;
- if (ri1->next)
- for (ri2 = ri1->next; ri2; ri2 = ri2->next)
- {
- if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK))
- continue;
- if (BGP_INFO_HOLDDOWN (ri2))
- continue;
- if (ri2->peer &&
- ri2->peer != bgp->peer_self &&
- !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT))
- if (ri2->peer->status != Established)
- continue;
+ new_select = ri1;
+ old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL;
+ if (ri1->next)
+ {
+ for (ri2 = ri1->next; ri2; ri2 = ri2->next)
+ {
+ if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK))
+ continue;
+ if (BGP_INFO_HOLDDOWN (ri2))
+ continue;
+ if (ri2->peer &&
+ ri2->peer != bgp->peer_self &&
+ !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT))
+ if (ri2->peer->status != Established)
+ continue;
- if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
- || aspath_cmp_left_confed (ri1->attr->aspath,
- ri2->attr->aspath))
- {
- if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED))
- old_select = ri2;
- if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq,
- mpath_cfg, debug, pfx_buf))
- {
- bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
- new_select = ri2;
- }
+ if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
+ || aspath_cmp_left_confed (ri1->attr->aspath,
+ ri2->attr->aspath))
+ {
+ if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED))
+ old_select = ri2;
+ if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq,
+ mpath_cfg, debug, pfx_buf))
+ {
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
+ new_select = ri2;
+ }
- bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
- }
- }
- bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
- bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
- }
+ bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
+ }
+ }
+ }
+ bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
+ bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
+
+ if (debug)
+ zlog_debug("%s: path %s is the bestpath from AS %d",
+ pfx_buf, new_select->peer->host,
+ aspath_get_firstas(new_select->attr->aspath));
+ }
+ }
/* Check old selected route and new selected route. */
old_select = NULL;
bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK);
continue;
}
+
bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK);
- bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED);
if (bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, debug, pfx_buf))
{
struct peer *peer;
int addpath_capable;
int has_adj;
+ int first_as;
if (json_paths)
{
vty_out (vty, ", multipath");
}
+ // Mark the bestpath(s)
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_DMED_SELECTED))
+ {
+ first_as = aspath_get_firstas(attr->aspath);
+
+ if (json_paths)
+ {
+ if (!json_bestpath)
+ json_bestpath = json_object_new_object();
+ json_object_int_add(json_bestpath, "bestpathFromAs", first_as);
+ }
+ else
+ {
+ if (first_as)
+ vty_out (vty, ", bestpath-from-AS %d", first_as);
+ else
+ vty_out (vty, ", bestpath-from-AS Local");
+ }
+ }
+
if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
{
if (json_paths)
{
- json_bestpath = json_object_new_object();
+ if (!json_bestpath)
+ json_bestpath = json_object_new_object();
json_object_boolean_true_add(json_bestpath, "overall");
- json_object_object_add(json_path, "bestpath", json_bestpath);
}
else
vty_out (vty, ", best");
}
+ if (json_bestpath)
+ json_object_object_add(json_path, "bestpath", json_bestpath);
+
if (!json_paths)
vty_out (vty, "%s", VTY_NEWLINE);
return UPDWALK_CONTINUE;
}
+/* Return true if we should addpath encode NLRI to this peer */
int
bgp_addpath_encode_tx (struct peer *peer, afi_t afi, safi_t safi)
{
return (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV) &&
CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV));
}
+
+/*
+ * Return true if this is a path we should advertise due to a
+ * configured addpath-tx knob
+ */
+int
+bgp_addpath_tx_path (struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_info *ri)
+{
+ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+ return 1;
+
+ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS) &&
+ CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))
+ return 1;
+
+ return 0;
+}
PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \
PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | \
PEER_FLAG_ADDPATH_TX_ALL_PATHS | \
+ PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS | \
PEER_FLAG_AS_OVERRIDE)
#define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
extern void update_bgp_group_free(struct bgp *bgp);
extern int bgp_addpath_encode_tx (struct peer *peer, afi_t afi, safi_t safi);
+extern int bgp_addpath_tx_path (struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_info *ri);
/*
* Inline functions
}
}
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+ for (ri = ctx->rn->info; ri; ri = ri->next)
{
- for (ri = ctx->rn->info; ri; ri = ri->next)
- {
- if (ri == ctx->ri)
- continue;
- subgroup_process_announce_selected (subgrp, ri, ctx->rn, ri->addpath_tx_id);
- }
+ /* Skip the bestpath for now */
+ if (ri == ctx->ri)
+ continue;
+
+ subgroup_process_announce_selected (subgrp, ri, ctx->rn, ri->addpath_tx_id);
}
+ /* Process the bestpath last so the "show ip bgp neighbor x.x.x.x advertised"
+ * output shows the attributes from the bestpath */
if (ctx->ri)
subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn, ctx->ri->addpath_tx_id);
}
for (ri = rn->info; ri; ri = ri->next)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) ||
- (addpath_capable &&
- CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS)))
+ (addpath_capable && bgp_addpath_tx_path(peer, afi, safi, ri)))
{
if (!rsclient
&& subgroup_announce_check (ri, subgrp, &rn->p, &attr))
clear_as
};
-/* Force a bestpath recalculation for all prefixes. This is used
- * when 'bgp bestpath' commands are entered.
- */
-static void
-bgp_recalculate_all_bestpaths (struct bgp *bgp)
-{
- afi_t afi;
- safi_t safi;
- struct bgp_node *rn;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- {
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn))
- {
- bgp_process (bgp, rn, afi, safi);
- }
- }
- }
-}
-
static void
bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi,
safi_t safi, int error)
"Pick the best-MED path among paths advertised from the neighboring AS\n")
{
struct bgp *bgp;
+ int bestpath_per_as_used;
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ struct listnode *node, *nnode;
bgp = vty->index;
if (bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED))
{
- bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED);
- bgp_recalculate_all_bestpaths (bgp);
+ bestpath_per_as_used = 0;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+ {
+ bestpath_per_as_used = 1;
+ break;
+ }
+
+ if (bestpath_per_as_used)
+ break;
+ }
+
+ if (bestpath_per_as_used)
+ {
+ vty_out (vty, "bgp deterministic-med cannot be disabled while addpath-tx-bestpath-per-AS is in use%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ else
+ {
+ bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED);
+ bgp_recalculate_all_bestpaths (bgp);
+ }
}
return CMD_SUCCESS;
PEER_FLAG_ADDPATH_TX_ALL_PATHS);
}
+DEFUN (neighbor_addpath_tx_bestpath_per_as,
+ neighbor_addpath_tx_bestpath_per_as_cmd,
+ NEIGHBOR_CMD2 "addpath-tx-bestpath-per-AS",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Use addpath to advertise the bestpath per each neighboring AS\n")
+{
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty (vty, argv[0]);
+ if (! peer)
+ return CMD_WARNING;
+
+ return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
+}
+
+DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
+ no_neighbor_addpath_tx_bestpath_per_as_cmd,
+ NO_NEIGHBOR_CMD2 "addpath-tx-bestpath-per-AS",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Use addpath to advertise the bestpath per each neighboring AS\n")
+{
+ return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
+}
+
+
/* Address family configuration. */
DEFUN (address_family_ipv4,
address_family_ipv4_cmd,
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
json_object_boolean_true_add(json_addr, "addpathTxAllPaths");
+ if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+ json_object_boolean_true_add(json_addr, "addpathTxBestpathPerAS");
+
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
json_object_string_add(json_addr, "overrideASNsInOutboundUpdates", "ifAspathEqualRemoteAs");
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
vty_out (vty, " Advertise all paths via addpath%s", VTY_NEWLINE);
+ if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+ vty_out (vty, " Advertise bestpath per AS via addpath%s", VTY_NEWLINE);
+
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
vty_out (vty, " Override ASNs in outbound updates if aspath equals remote-as%s", VTY_NEWLINE);
install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+ /* "neighbor addpath-tx-bestpath-per-AS" commands.*/
+ install_element (BGP_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+
/* "neighbor passive" commands. */
install_element (BGP_NODE, &neighbor_passive_cmd);
install_element (BGP_NODE, &no_neighbor_passive_cmd);
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
}
+/* Force a bestpath recalculation for all prefixes. This is used
+ * when 'bgp bestpath' commands are entered.
+ */
+void
+bgp_recalculate_all_bestpaths (struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_node *rn;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn))
+ {
+ bgp_process (bgp, rn, afi, safi);
+ }
+ }
+ }
+}
+
/* Create new BGP peer. */
struct peer *
peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
{ PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out },
{ PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,1, peer_change_reset_out },
{ PEER_FLAG_ADDPATH_TX_ALL_PATHS, 1, peer_change_reset },
+ { PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, 1, peer_change_reset },
{ 0, 0, 0 }
};
}
/* Track if addpath TX is in use */
- if (flag & PEER_FLAG_ADDPATH_TX_ALL_PATHS)
+ if (flag & (PEER_FLAG_ADDPATH_TX_ALL_PATHS|PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
{
bgp = peer->bgp;
addpath_tx_used = 0;
if (set)
{
addpath_tx_used = 1;
+
+ if (flag & PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)
+ {
+ if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+ {
+ zlog_warn("%s: enabling bgp deterministic-med, this is required"\
+ " for addpath-tx-bestpath-per-AS",
+ peer->host);
+ bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
+ bgp_recalculate_all_bestpaths (bgp);
+ }
+ }
}
else
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, tmp_peer))
{
- if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+ if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS) ||
+ CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
{
addpath_tx_used = 1;
break;
/* addpath TX knobs */
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ADDPATH_TX_ALL_PATHS))
- vty_out (vty, " neighbor %s addpath-tx-all-paths%s", addr,
- VTY_NEWLINE);
+ vty_out (vty, " neighbor %s addpath-tx-all-paths%s", addr, VTY_NEWLINE);
+
+ if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+ vty_out (vty, " neighbor %s addpath-tx-bestpath-per-AS%s", addr, VTY_NEWLINE);
/* ORF capability. */
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) ||
#define PEER_FLAG_AS_OVERRIDE (1 << 20) /* as-override */
#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1 << 21) /* remove-private-as all replace-as */
#define PEER_FLAG_ADDPATH_TX_ALL_PATHS (1 << 22) /* addpath-tx-all-paths */
+#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
/* MD5 password */
char *password;
extern bgp_peer_sort_t peer_sort (struct peer *peer);
extern int peer_active (struct peer *);
extern int peer_active_nego (struct peer *);
+extern void bgp_recalculate_all_bestpaths (struct bgp *bgp);
extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
as_t, as_t, int, afi_t, safi_t);
extern struct peer *peer_create_accept (struct bgp *);