mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-09 05:33:42 +00:00
bgpd: Implement Accumulated IGP Metric Attribute for BGP
https://www.rfc-editor.org/rfc/rfc7311.html Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
parent
91e9aee087
commit
97a52c82a5
187
bgpd/bgp_attr.c
187
bgpd/bgp_attr.c
@ -83,6 +83,7 @@ static const struct message attr_str[] = {
|
|||||||
{BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
|
{BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
|
||||||
{BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
|
{BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
|
||||||
{BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
|
{BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
|
||||||
|
{BGP_ATTR_AIGP, "AIGP"},
|
||||||
{0}};
|
{0}};
|
||||||
|
|
||||||
static const struct message attr_flag_str[] = {
|
static const struct message attr_flag_str[] = {
|
||||||
@ -448,6 +449,110 @@ static void transit_unintern(struct transit **transit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length,
|
||||||
|
uint64_t *aigp)
|
||||||
|
{
|
||||||
|
uint8_t *data = pnt;
|
||||||
|
uint8_t tlv_type;
|
||||||
|
uint16_t tlv_length;
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
tlv_type = *data;
|
||||||
|
ptr_get_be16(data + 1, &tlv_length);
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
/* The value field of the AIGP TLV is always 8 octets
|
||||||
|
* long and its value is interpreted as an unsigned 64-bit
|
||||||
|
* integer.
|
||||||
|
*/
|
||||||
|
if (tlv_type == BGP_AIGP_TLV_METRIC) {
|
||||||
|
(void)ptr_get_be64(data + 3, aigp);
|
||||||
|
|
||||||
|
/* If an AIGP attribute is received and its first AIGP
|
||||||
|
* TLV contains the maximum value 0xffffffffffffffff,
|
||||||
|
* the attribute SHOULD be considered to be malformed
|
||||||
|
* and SHOULD be discarded as specified in this section.
|
||||||
|
*/
|
||||||
|
if (*aigp == BGP_AIGP_TLV_METRIC_MAX) {
|
||||||
|
zlog_err("Bad AIGP TLV (%s) length: %llu",
|
||||||
|
BGP_AIGP_TLV_METRIC_DESC,
|
||||||
|
BGP_AIGP_TLV_METRIC_MAX);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += tlv_length;
|
||||||
|
length -= tlv_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi)
|
||||||
|
{
|
||||||
|
uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
|
||||||
|
|
||||||
|
if (bpi->nexthop)
|
||||||
|
return aigp + bpi->nexthop->metric;
|
||||||
|
else
|
||||||
|
return aigp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stream_put_bgp_aigp_tlv_metric(struct stream *s,
|
||||||
|
struct bgp_path_info *bpi)
|
||||||
|
{
|
||||||
|
stream_putc(s, BGP_AIGP_TLV_METRIC);
|
||||||
|
stream_putw(s, BGP_AIGP_TLV_METRIC_LEN);
|
||||||
|
stream_putq(s, bgp_aigp_metric_total(bpi));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
|
||||||
|
{
|
||||||
|
uint8_t *data = pnt;
|
||||||
|
uint8_t tlv_type;
|
||||||
|
uint16_t tlv_length;
|
||||||
|
|
||||||
|
if (length < 3) {
|
||||||
|
zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
|
||||||
|
length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
tlv_type = *data;
|
||||||
|
ptr_get_be16(data + 1, &tlv_length);
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
if (length < tlv_length) {
|
||||||
|
zlog_err(
|
||||||
|
"Bad AIGP attribute length: %u, but TLV length: %u",
|
||||||
|
length, tlv_length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tlv_length < 3) {
|
||||||
|
zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
|
||||||
|
tlv_length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AIGP TLV, Length: 11 */
|
||||||
|
if (tlv_type == BGP_AIGP_TLV_METRIC &&
|
||||||
|
tlv_length != BGP_AIGP_TLV_METRIC_LEN) {
|
||||||
|
zlog_err("Bad AIGP TLV (%s) length: %u",
|
||||||
|
BGP_AIGP_TLV_METRIC_DESC, tlv_length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += tlv_length;
|
||||||
|
length -= tlv_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void *srv6_l3vpn_hash_alloc(void *p)
|
static void *srv6_l3vpn_hash_alloc(void *p)
|
||||||
{
|
{
|
||||||
return p;
|
return p;
|
||||||
@ -702,6 +807,7 @@ unsigned int attrhash_key_make(const void *p)
|
|||||||
MIX(attr->nh_type);
|
MIX(attr->nh_type);
|
||||||
MIX(attr->bh_type);
|
MIX(attr->bh_type);
|
||||||
MIX(attr->otc);
|
MIX(attr->otc);
|
||||||
|
MIX(bgp_attr_get_aigp_metric(attr));
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@ -736,6 +842,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
|
|||||||
== bgp_attr_get_cluster(attr2)
|
== bgp_attr_get_cluster(attr2)
|
||||||
&& bgp_attr_get_transit(attr1)
|
&& bgp_attr_get_transit(attr1)
|
||||||
== bgp_attr_get_transit(attr2)
|
== bgp_attr_get_transit(attr2)
|
||||||
|
&& bgp_attr_get_aigp_metric(attr1)
|
||||||
|
== bgp_attr_get_aigp_metric(attr2)
|
||||||
&& attr1->rmap_table_id == attr2->rmap_table_id
|
&& attr1->rmap_table_id == attr2->rmap_table_id
|
||||||
&& (attr1->encap_tunneltype == attr2->encap_tunneltype)
|
&& (attr1->encap_tunneltype == attr2->encap_tunneltype)
|
||||||
&& encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
|
&& encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
|
||||||
@ -1387,6 +1495,7 @@ const uint8_t attr_flags_values[] = {
|
|||||||
[BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
[BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||||
[BGP_ATTR_IPV6_EXT_COMMUNITIES] =
|
[BGP_ATTR_IPV6_EXT_COMMUNITIES] =
|
||||||
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||||
|
[BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||||
};
|
};
|
||||||
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
|
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
|
||||||
|
|
||||||
@ -3053,6 +3162,45 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
|
|||||||
return BGP_ATTR_PARSE_PROCEED;
|
return BGP_ATTR_PARSE_PROCEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AIGP attribute (rfc7311) */
|
||||||
|
static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
|
||||||
|
{
|
||||||
|
struct peer *const peer = args->peer;
|
||||||
|
struct attr *const attr = args->attr;
|
||||||
|
const bgp_size_t length = args->length;
|
||||||
|
uint8_t *s = stream_pnt(peer->curr);
|
||||||
|
uint64_t aigp = 0;
|
||||||
|
|
||||||
|
/* If an AIGP attribute is received on a BGP session for which
|
||||||
|
* AIGP_SESSION is disabled, the attribute MUST be treated exactly
|
||||||
|
* as if it were an unrecognized non-transitive attribute.
|
||||||
|
* That is, it "MUST be quietly ignored and not passed along to
|
||||||
|
* other BGP peers".
|
||||||
|
* For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
|
||||||
|
* sessions between members of the same BGP Confederation,
|
||||||
|
* the default value of AIGP_SESSION SHOULD be "enabled".
|
||||||
|
*/
|
||||||
|
if (peer->sort == BGP_PEER_EBGP &&
|
||||||
|
!CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) {
|
||||||
|
zlog_warn(
|
||||||
|
"%pBP received AIGP attribute, but eBGP peer do not support it",
|
||||||
|
peer);
|
||||||
|
goto aigp_ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bgp_attr_aigp_valid(s, length))
|
||||||
|
goto aigp_ignore;
|
||||||
|
|
||||||
|
/* Extract AIGP Metric TLV */
|
||||||
|
if (bgp_attr_aigp_get_tlv_metric(s, length, &aigp))
|
||||||
|
bgp_attr_set_aigp_metric(attr, aigp);
|
||||||
|
|
||||||
|
aigp_ignore:
|
||||||
|
stream_forward_getp(peer->curr, length);
|
||||||
|
|
||||||
|
return BGP_ATTR_PARSE_PROCEED;
|
||||||
|
}
|
||||||
|
|
||||||
/* OTC attribute. */
|
/* OTC attribute. */
|
||||||
static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
|
static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
|
||||||
{
|
{
|
||||||
@ -3431,6 +3579,9 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
|
|||||||
case BGP_ATTR_OTC:
|
case BGP_ATTR_OTC:
|
||||||
ret = bgp_attr_otc(&attr_args);
|
ret = bgp_attr_otc(&attr_args);
|
||||||
break;
|
break;
|
||||||
|
case BGP_ATTR_AIGP:
|
||||||
|
ret = bgp_attr_aigp(&attr_args);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = bgp_attr_unknown(&attr_args);
|
ret = bgp_attr_unknown(&attr_args);
|
||||||
break;
|
break;
|
||||||
@ -3951,7 +4102,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||||||
struct prefix *p, afi_t afi, safi_t safi,
|
struct prefix *p, afi_t afi, safi_t safi,
|
||||||
struct peer *from, struct prefix_rd *prd,
|
struct peer *from, struct prefix_rd *prd,
|
||||||
mpls_label_t *label, uint32_t num_labels,
|
mpls_label_t *label, uint32_t num_labels,
|
||||||
bool addpath_capable, uint32_t addpath_tx_id)
|
bool addpath_capable, uint32_t addpath_tx_id,
|
||||||
|
struct bgp_path_info *bpi)
|
||||||
{
|
{
|
||||||
size_t cp;
|
size_t cp;
|
||||||
size_t aspath_sizep;
|
size_t aspath_sizep;
|
||||||
@ -4457,6 +4609,22 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
|||||||
stream_putl(s, attr->otc);
|
stream_putl(s, attr->otc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AIGP */
|
||||||
|
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
|
||||||
|
(CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
|
||||||
|
peer->sort != BGP_PEER_EBGP)) {
|
||||||
|
/* At the moment only AIGP Metric TLV exists for AIGP
|
||||||
|
* attribute. If more comes in, do not forget to update
|
||||||
|
* attr_len variable to include new ones.
|
||||||
|
*/
|
||||||
|
uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
|
||||||
|
|
||||||
|
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
|
||||||
|
stream_putc(s, BGP_ATTR_AIGP);
|
||||||
|
stream_putc(s, attr_len);
|
||||||
|
stream_put_bgp_aigp_tlv_metric(s, bpi);
|
||||||
|
}
|
||||||
|
|
||||||
/* Unknown transit attribute. */
|
/* Unknown transit attribute. */
|
||||||
struct transit *transit = bgp_attr_get_transit(attr);
|
struct transit *transit = bgp_attr_get_transit(attr);
|
||||||
|
|
||||||
@ -4540,7 +4708,7 @@ void bgp_attr_finish(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make attribute packet. */
|
/* Make attribute packet. */
|
||||||
void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
||||||
const struct prefix *prefix)
|
const struct prefix *prefix)
|
||||||
{
|
{
|
||||||
unsigned long cp;
|
unsigned long cp;
|
||||||
@ -4549,6 +4717,7 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
|||||||
struct aspath *aspath;
|
struct aspath *aspath;
|
||||||
bool addpath_capable = false;
|
bool addpath_capable = false;
|
||||||
uint32_t addpath_tx_id = 0;
|
uint32_t addpath_tx_id = 0;
|
||||||
|
struct attr *attr = bpi->attr;
|
||||||
|
|
||||||
/* Remember current pointer. */
|
/* Remember current pointer. */
|
||||||
cp = stream_get_endp(s);
|
cp = stream_get_endp(s);
|
||||||
@ -4712,6 +4881,20 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
|||||||
stream_putl(s, attr->otc);
|
stream_putl(s, attr->otc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AIGP */
|
||||||
|
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
|
||||||
|
/* At the moment only AIGP Metric TLV exists for AIGP
|
||||||
|
* attribute. If more comes in, do not forget to update
|
||||||
|
* attr_len variable to include new ones.
|
||||||
|
*/
|
||||||
|
uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
|
||||||
|
|
||||||
|
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
|
||||||
|
stream_putc(s, BGP_ATTR_AIGP);
|
||||||
|
stream_putc(s, attr_len);
|
||||||
|
stream_put_bgp_aigp_tlv_metric(s, bpi);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return total size of attribute. */
|
/* Return total size of attribute. */
|
||||||
len = stream_get_endp(s) - cp - 2;
|
len = stream_get_endp(s) - cp - 2;
|
||||||
stream_putw_at(s, cp, len);
|
stream_putw_at(s, cp, len);
|
||||||
|
@ -329,6 +329,9 @@ struct attr {
|
|||||||
|
|
||||||
/* OTC value if set */
|
/* OTC value if set */
|
||||||
uint32_t otc;
|
uint32_t otc;
|
||||||
|
|
||||||
|
/* AIGP Metric */
|
||||||
|
uint64_t aigp_metric;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* rmap_change_flags definition */
|
/* rmap_change_flags definition */
|
||||||
@ -396,15 +399,13 @@ extern struct attr *bgp_attr_aggregate_intern(
|
|||||||
struct community *community, struct ecommunity *ecommunity,
|
struct community *community, struct ecommunity *ecommunity,
|
||||||
struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
|
struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
|
||||||
uint8_t atomic_aggregate, const struct prefix *p);
|
uint8_t atomic_aggregate, const struct prefix *p);
|
||||||
extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
extern bgp_size_t bgp_packet_attribute(
|
||||||
struct stream *s, struct attr *attr,
|
struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr,
|
||||||
struct bpacket_attr_vec_arr *vecarr,
|
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi,
|
||||||
struct prefix *p, afi_t afi, safi_t safi,
|
safi_t safi, struct peer *from, struct prefix_rd *prd,
|
||||||
struct peer *from, struct prefix_rd *prd,
|
mpls_label_t *label, uint32_t num_labels, bool addpath_capable,
|
||||||
mpls_label_t *label, uint32_t num_labels,
|
uint32_t addpath_tx_id, struct bgp_path_info *bpi);
|
||||||
bool addpath_capable,
|
extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
||||||
uint32_t addpath_tx_id);
|
|
||||||
extern void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
|
||||||
const struct prefix *p);
|
const struct prefix *p);
|
||||||
extern bool attrhash_cmp(const void *arg1, const void *arg2);
|
extern bool attrhash_cmp(const void *arg1, const void *arg2);
|
||||||
extern unsigned int attrhash_key_make(const void *p);
|
extern unsigned int attrhash_key_make(const void *p);
|
||||||
@ -585,6 +586,19 @@ static inline void bgp_attr_set_transit(struct attr *attr,
|
|||||||
attr->transit = transit;
|
attr->transit = transit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr)
|
||||||
|
{
|
||||||
|
return attr->aigp_metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp)
|
||||||
|
{
|
||||||
|
attr->aigp_metric = aigp;
|
||||||
|
|
||||||
|
if (aigp)
|
||||||
|
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP);
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr)
|
static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr)
|
||||||
{
|
{
|
||||||
return attr->cluster1;
|
return attr->cluster1;
|
||||||
|
@ -853,8 +853,9 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
|
|||||||
stream_putw(s, 0);
|
stream_putw(s, 0);
|
||||||
|
|
||||||
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
|
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
|
||||||
total_attr_len = bgp_packet_attribute(NULL, peer, s, attr,
|
total_attr_len =
|
||||||
&vecarr, NULL, afi, safi, peer, NULL, NULL, 0, 0, 0);
|
bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi,
|
||||||
|
safi, peer, NULL, NULL, 0, 0, 0, NULL);
|
||||||
|
|
||||||
/* space check? */
|
/* space check? */
|
||||||
|
|
||||||
|
@ -412,6 +412,11 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
|
|||||||
snprintf(buf + strlen(buf), size - strlen(buf),
|
snprintf(buf + strlen(buf), size - strlen(buf),
|
||||||
", localpref %u", attr->local_pref);
|
", localpref %u", attr->local_pref);
|
||||||
|
|
||||||
|
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)))
|
||||||
|
snprintf(buf + strlen(buf), size - strlen(buf),
|
||||||
|
", aigp-metric %" PRIu64,
|
||||||
|
(unsigned long long)bgp_attr_get_aigp_metric(attr));
|
||||||
|
|
||||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
|
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
|
||||||
snprintf(buf + strlen(buf), size - strlen(buf), ", metric %u",
|
snprintf(buf + strlen(buf), size - strlen(buf), ", metric %u",
|
||||||
attr->med);
|
attr->med);
|
||||||
|
@ -376,7 +376,7 @@ bgp_dump_route_node_record(int afi, struct bgp_dest *dest,
|
|||||||
|
|
||||||
/* Dump attribute. */
|
/* Dump attribute. */
|
||||||
/* Skip prefix & AFI/SAFI for MP_NLRI */
|
/* Skip prefix & AFI/SAFI for MP_NLRI */
|
||||||
bgp_dump_routes_attr(obuf, path->attr, p);
|
bgp_dump_routes_attr(obuf, path, p);
|
||||||
|
|
||||||
cur_endp = stream_get_endp(obuf);
|
cur_endp = stream_get_endp(obuf);
|
||||||
if (cur_endp > BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
|
if (cur_endp > BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
|
||||||
|
@ -235,6 +235,12 @@ static struct log_ref ferr_bgp_err[] = {
|
|||||||
.description = "BGP update has invalid length for PMSI tunnel",
|
.description = "BGP update has invalid length for PMSI tunnel",
|
||||||
.suggestion = "Determine the source of the update and determine why the PMSI tunnel attribute length has been set incorrectly"
|
.suggestion = "Determine the source of the update and determine why the PMSI tunnel attribute length has been set incorrectly"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.code = EC_BGP_ATTR_AIGP,
|
||||||
|
.title = "BGP AIGP attribute is incorrect",
|
||||||
|
.description = "BGP AIGP attribute is incorrect",
|
||||||
|
.suggestion = "Determine the source of the attribute and determine why the AIGP attribute has been set incorrectly"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.code = EC_BGP_PEER_GROUP,
|
.code = EC_BGP_PEER_GROUP,
|
||||||
.title = "BGP peergroup operated on in error",
|
.title = "BGP peergroup operated on in error",
|
||||||
|
@ -34,6 +34,7 @@ enum bgp_log_refs {
|
|||||||
EC_BGP_ATTR_PMSI_TYPE,
|
EC_BGP_ATTR_PMSI_TYPE,
|
||||||
EC_BGP_ATTR_PMSI_LEN,
|
EC_BGP_ATTR_PMSI_LEN,
|
||||||
EC_BGP_ATTR_NH_SEND_LEN,
|
EC_BGP_ATTR_NH_SEND_LEN,
|
||||||
|
EC_BGP_ATTR_AIGP,
|
||||||
EC_BGP_PEER_GROUP,
|
EC_BGP_PEER_GROUP,
|
||||||
EC_BGP_PEER_DELETE,
|
EC_BGP_PEER_DELETE,
|
||||||
EC_BGP_TABLE_CHUNK,
|
EC_BGP_TABLE_CHUNK,
|
||||||
|
@ -920,6 +920,36 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tie-breaker - AIGP (Metric TLV) attribute */
|
||||||
|
if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
|
||||||
|
CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
|
||||||
|
CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) {
|
||||||
|
uint64_t new_aigp = bgp_attr_get_aigp_metric(newattr);
|
||||||
|
uint64_t exist_aigp = bgp_attr_get_aigp_metric(existattr);
|
||||||
|
|
||||||
|
if (new_aigp < exist_aigp) {
|
||||||
|
*reason = bgp_path_selection_aigp;
|
||||||
|
if (debug)
|
||||||
|
zlog_debug(
|
||||||
|
"%s: %s wins over %s due to AIGP %" PRIu64
|
||||||
|
" < %" PRIu64,
|
||||||
|
pfx_buf, new_buf, exist_buf, new_aigp,
|
||||||
|
exist_aigp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_aigp > exist_aigp) {
|
||||||
|
*reason = bgp_path_selection_aigp;
|
||||||
|
if (debug)
|
||||||
|
zlog_debug(
|
||||||
|
"%s: %s loses to %s due to AIGP %" PRIu64
|
||||||
|
" > %" PRIu64,
|
||||||
|
pfx_buf, new_buf, exist_buf, new_aigp,
|
||||||
|
exist_aigp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 3. Local route check. We prefer:
|
/* 3. Local route check. We prefer:
|
||||||
* - BGP_ROUTE_STATIC
|
* - BGP_ROUTE_STATIC
|
||||||
* - BGP_ROUTE_AGGREGATE
|
* - BGP_ROUTE_AGGREGATE
|
||||||
@ -6139,6 +6169,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
|
|||||||
if (afi == AFI_IP)
|
if (afi == AFI_IP)
|
||||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||||
|
|
||||||
|
if (bgp_static->igpmetric)
|
||||||
|
bgp_attr_set_aigp_metric(&attr, bgp_static->igpmetric);
|
||||||
|
|
||||||
if (bgp_static->atomic)
|
if (bgp_static->atomic)
|
||||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
|
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
|
||||||
|
|
||||||
@ -8684,6 +8717,9 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
|
|||||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
|
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
|
||||||
attr.tag = tag;
|
attr.tag = tag;
|
||||||
|
|
||||||
|
if (metric)
|
||||||
|
bgp_attr_set_aigp_metric(&attr, metric);
|
||||||
|
|
||||||
afi = family2afi(p->family);
|
afi = family2afi(p->family);
|
||||||
|
|
||||||
red = bgp_redist_lookup(bgp, afi, type, instance);
|
red = bgp_redist_lookup(bgp, afi, type, instance);
|
||||||
@ -8693,8 +8729,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
|
|||||||
/* Copy attribute for modification. */
|
/* Copy attribute for modification. */
|
||||||
attr_new = attr;
|
attr_new = attr;
|
||||||
|
|
||||||
if (red->redist_metric_flag)
|
if (red->redist_metric_flag) {
|
||||||
attr_new.med = red->redist_metric;
|
attr_new.med = red->redist_metric;
|
||||||
|
bgp_attr_set_aigp_metric(&attr_new, red->redist_metric);
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply route-map. */
|
/* Apply route-map. */
|
||||||
if (red->rmap.name) {
|
if (red->rmap.name) {
|
||||||
@ -8944,6 +8982,8 @@ const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason)
|
|||||||
return "Accept Own";
|
return "Accept Own";
|
||||||
case bgp_path_selection_local_route:
|
case bgp_path_selection_local_route:
|
||||||
return "Local Route";
|
return "Local Route";
|
||||||
|
case bgp_path_selection_aigp:
|
||||||
|
return "AIGP";
|
||||||
case bgp_path_selection_confed_as_path:
|
case bgp_path_selection_confed_as_path:
|
||||||
return "Confederation based AS Path";
|
return "Confederation based AS Path";
|
||||||
case bgp_path_selection_as_path:
|
case bgp_path_selection_as_path:
|
||||||
@ -10678,6 +10718,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
|||||||
vty_out(vty, ", localpref %u", attr->local_pref);
|
vty_out(vty, ", localpref %u", attr->local_pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
|
||||||
|
if (json_paths)
|
||||||
|
json_object_int_add(json_path, "aigpMetric",
|
||||||
|
bgp_attr_get_aigp_metric(attr));
|
||||||
|
else
|
||||||
|
vty_out(vty, ", aigp-metric %" PRIu64,
|
||||||
|
bgp_attr_get_aigp_metric(attr));
|
||||||
|
}
|
||||||
|
|
||||||
if (attr->weight != 0) {
|
if (attr->weight != 0) {
|
||||||
if (json_paths)
|
if (json_paths)
|
||||||
json_object_int_add(json_path, "weight", attr->weight);
|
json_object_int_add(json_path, "weight", attr->weight);
|
||||||
|
@ -3043,6 +3043,46 @@ static const struct route_map_rule_cmd route_set_atomic_aggregate_cmd = {
|
|||||||
route_set_atomic_aggregate_free,
|
route_set_atomic_aggregate_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* AIGP TLV Metric */
|
||||||
|
static enum route_map_cmd_result_t
|
||||||
|
route_set_aigp_metric(void *rule, const struct prefix *pfx, void *object)
|
||||||
|
{
|
||||||
|
const char *aigp_metric = rule;
|
||||||
|
struct bgp_path_info *path = object;
|
||||||
|
uint32_t aigp = 0;
|
||||||
|
|
||||||
|
if (strmatch(aigp_metric, "igp-metric")) {
|
||||||
|
if (!path->nexthop)
|
||||||
|
return RMAP_NOMATCH;
|
||||||
|
|
||||||
|
bgp_attr_set_aigp_metric(path->attr, path->nexthop->metric);
|
||||||
|
} else {
|
||||||
|
aigp = atoi(aigp_metric);
|
||||||
|
bgp_attr_set_aigp_metric(path->attr, aigp);
|
||||||
|
}
|
||||||
|
|
||||||
|
path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP);
|
||||||
|
|
||||||
|
return RMAP_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *route_set_aigp_metric_compile(const char *arg)
|
||||||
|
{
|
||||||
|
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void route_set_aigp_metric_free(void *rule)
|
||||||
|
{
|
||||||
|
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct route_map_rule_cmd route_set_aigp_metric_cmd = {
|
||||||
|
"aigp-metric",
|
||||||
|
route_set_aigp_metric,
|
||||||
|
route_set_aigp_metric_compile,
|
||||||
|
route_set_aigp_metric_free,
|
||||||
|
};
|
||||||
|
|
||||||
/* `set aggregator as AS A.B.C.D' */
|
/* `set aggregator as AS A.B.C.D' */
|
||||||
struct aggregator {
|
struct aggregator {
|
||||||
as_t as;
|
as_t as;
|
||||||
@ -6354,6 +6394,42 @@ DEFUN_YANG (no_set_atomic_aggregate,
|
|||||||
return nb_cli_apply_changes(vty, NULL);
|
return nb_cli_apply_changes(vty, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY_YANG (set_aigp_metric,
|
||||||
|
set_aigp_metric_cmd,
|
||||||
|
"set aigp-metric <igp-metric|(1-4294967295)>$aigp_metric",
|
||||||
|
SET_STR
|
||||||
|
"BGP AIGP attribute (AIGP Metric TLV)\n"
|
||||||
|
"AIGP Metric value from IGP protocol\n"
|
||||||
|
"Manual AIGP Metric value\n")
|
||||||
|
{
|
||||||
|
const char *xpath =
|
||||||
|
"./set-action[action='frr-bgp-route-map:aigp-metric']";
|
||||||
|
char xpath_value[XPATH_MAXLEN];
|
||||||
|
|
||||||
|
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
|
||||||
|
snprintf(xpath_value, sizeof(xpath_value),
|
||||||
|
"%s/rmap-set-action/frr-bgp-route-map:aigp-metric", xpath);
|
||||||
|
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, aigp_metric);
|
||||||
|
|
||||||
|
return nb_cli_apply_changes(vty, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY_YANG (no_set_aigp_metric,
|
||||||
|
no_set_aigp_metric_cmd,
|
||||||
|
"no set aigp-metric [<igp-metric|(1-4294967295)>]",
|
||||||
|
NO_STR
|
||||||
|
SET_STR
|
||||||
|
"BGP AIGP attribute (AIGP Metric TLV)\n"
|
||||||
|
"AIGP Metric value from IGP protocol\n"
|
||||||
|
"Manual AIGP Metric value\n")
|
||||||
|
{
|
||||||
|
const char *xpath =
|
||||||
|
"./set-action[action='frr-bgp-route-map:aigp-metric']";
|
||||||
|
|
||||||
|
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||||
|
return nb_cli_apply_changes(vty, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN_YANG (set_aggregator_as,
|
DEFUN_YANG (set_aggregator_as,
|
||||||
set_aggregator_as_cmd,
|
set_aggregator_as_cmd,
|
||||||
"set aggregator as (1-4294967295) A.B.C.D",
|
"set aggregator as (1-4294967295) A.B.C.D",
|
||||||
@ -7013,6 +7089,7 @@ void bgp_route_map_init(void)
|
|||||||
route_map_install_set(&route_set_aspath_replace_cmd);
|
route_map_install_set(&route_set_aspath_replace_cmd);
|
||||||
route_map_install_set(&route_set_origin_cmd);
|
route_map_install_set(&route_set_origin_cmd);
|
||||||
route_map_install_set(&route_set_atomic_aggregate_cmd);
|
route_map_install_set(&route_set_atomic_aggregate_cmd);
|
||||||
|
route_map_install_set(&route_set_aigp_metric_cmd);
|
||||||
route_map_install_set(&route_set_aggregator_as_cmd);
|
route_map_install_set(&route_set_aggregator_as_cmd);
|
||||||
route_map_install_set(&route_set_community_cmd);
|
route_map_install_set(&route_set_community_cmd);
|
||||||
route_map_install_set(&route_set_community_delete_cmd);
|
route_map_install_set(&route_set_community_delete_cmd);
|
||||||
@ -7095,6 +7172,8 @@ void bgp_route_map_init(void)
|
|||||||
install_element(RMAP_NODE, &no_set_origin_cmd);
|
install_element(RMAP_NODE, &no_set_origin_cmd);
|
||||||
install_element(RMAP_NODE, &set_atomic_aggregate_cmd);
|
install_element(RMAP_NODE, &set_atomic_aggregate_cmd);
|
||||||
install_element(RMAP_NODE, &no_set_atomic_aggregate_cmd);
|
install_element(RMAP_NODE, &no_set_atomic_aggregate_cmd);
|
||||||
|
install_element(RMAP_NODE, &set_aigp_metric_cmd);
|
||||||
|
install_element(RMAP_NODE, &no_set_aigp_metric_cmd);
|
||||||
install_element(RMAP_NODE, &set_aggregator_as_cmd);
|
install_element(RMAP_NODE, &set_aggregator_as_cmd);
|
||||||
install_element(RMAP_NODE, &no_set_aggregator_as_cmd);
|
install_element(RMAP_NODE, &no_set_aggregator_as_cmd);
|
||||||
install_element(RMAP_NODE, &set_community_cmd);
|
install_element(RMAP_NODE, &set_community_cmd);
|
||||||
|
@ -282,6 +282,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
|
|||||||
.destroy = lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy,
|
.destroy = lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aigp-metric",
|
||||||
|
.cbs = {
|
||||||
|
.modify = lib_route_map_entry_set_action_rmap_set_action_aigp_metric_modify,
|
||||||
|
.destroy = lib_route_map_entry_set_action_rmap_set_action_aigp_metric_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path",
|
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path",
|
||||||
.cbs = {
|
.cbs = {
|
||||||
|
@ -106,6 +106,10 @@ int lib_route_map_entry_set_action_rmap_set_action_table_modify(struct nb_cb_mod
|
|||||||
int lib_route_map_entry_set_action_rmap_set_action_table_destroy(struct nb_cb_destroy_args *args);
|
int lib_route_map_entry_set_action_rmap_set_action_table_destroy(struct nb_cb_destroy_args *args);
|
||||||
int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_create(struct nb_cb_create_args *args);
|
int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_create(struct nb_cb_create_args *args);
|
||||||
int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(struct nb_cb_destroy_args *args);
|
int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(struct nb_cb_destroy_args *args);
|
||||||
|
int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_modify(
|
||||||
|
struct nb_cb_modify_args *args);
|
||||||
|
int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_destroy(
|
||||||
|
struct nb_cb_destroy_args *args);
|
||||||
int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify(struct nb_cb_modify_args *args);
|
int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify(struct nb_cb_modify_args *args);
|
||||||
int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_destroy(struct nb_cb_destroy_args *args);
|
int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_destroy(struct nb_cb_destroy_args *args);
|
||||||
int lib_route_map_entry_set_action_rmap_set_action_last_as_modify(struct nb_cb_modify_args *args);
|
int lib_route_map_entry_set_action_rmap_set_action_last_as_modify(struct nb_cb_modify_args *args);
|
||||||
|
@ -2088,6 +2088,58 @@ lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(
|
|||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath:
|
||||||
|
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aigp-metric
|
||||||
|
*/
|
||||||
|
int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_modify(
|
||||||
|
struct nb_cb_modify_args *args)
|
||||||
|
{
|
||||||
|
struct routemap_hook_context *rhc;
|
||||||
|
const char *aigp;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
/* Add configuration. */
|
||||||
|
rhc = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
aigp = yang_dnode_get_string(args->dnode, NULL);
|
||||||
|
|
||||||
|
/* Set destroy information. */
|
||||||
|
rhc->rhc_shook = generic_set_delete;
|
||||||
|
rhc->rhc_rule = "aigp-metric";
|
||||||
|
rhc->rhc_event = RMAP_EVENT_SET_DELETED;
|
||||||
|
|
||||||
|
rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, aigp,
|
||||||
|
args->errmsg, args->errmsg_len);
|
||||||
|
if (rv != CMD_SUCCESS) {
|
||||||
|
rhc->rhc_shook = NULL;
|
||||||
|
return NB_ERR_INCONSISTENCY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_destroy(
|
||||||
|
struct nb_cb_destroy_args *args)
|
||||||
|
{
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
return lib_route_map_entry_set_destroy(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XPath:
|
* XPath:
|
||||||
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path
|
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path
|
||||||
|
@ -65,6 +65,7 @@ enum bgp_path_selection_reason {
|
|||||||
bgp_path_selection_local_pref,
|
bgp_path_selection_local_pref,
|
||||||
bgp_path_selection_accept_own,
|
bgp_path_selection_accept_own,
|
||||||
bgp_path_selection_local_route,
|
bgp_path_selection_local_route,
|
||||||
|
bgp_path_selection_aigp,
|
||||||
bgp_path_selection_confed_as_path,
|
bgp_path_selection_confed_as_path,
|
||||||
bgp_path_selection_as_path,
|
bgp_path_selection_as_path,
|
||||||
bgp_path_selection_origin,
|
bgp_path_selection_origin,
|
||||||
|
@ -436,6 +436,11 @@ static unsigned int updgrp_hash_key_make(const void *p)
|
|||||||
*/
|
*/
|
||||||
key = jhash_1word(peer->local_role, key);
|
key = jhash_1word(peer->local_role, key);
|
||||||
|
|
||||||
|
/* Neighbors configured with the AIGP attribute are put in a separate
|
||||||
|
* update group from other neighbors.
|
||||||
|
*/
|
||||||
|
key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
|
||||||
|
|
||||||
if (peer->soo[afi][safi]) {
|
if (peer->soo[afi][safi]) {
|
||||||
char *soo_str = ecommunity_str(peer->soo[afi][safi]);
|
char *soo_str = ecommunity_str(peer->soo[afi][safi]);
|
||||||
|
|
||||||
|
@ -752,7 +752,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
|||||||
* attr. */
|
* attr. */
|
||||||
total_attr_len = bgp_packet_attribute(
|
total_attr_len = bgp_packet_attribute(
|
||||||
NULL, peer, s, adv->baa->attr, &vecarr, NULL,
|
NULL, peer, s, adv->baa->attr, &vecarr, NULL,
|
||||||
afi, safi, from, NULL, NULL, 0, 0, 0);
|
afi, safi, from, NULL, NULL, 0, 0, 0, path);
|
||||||
|
|
||||||
space_remaining =
|
space_remaining =
|
||||||
STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
|
STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
|
||||||
@ -1125,7 +1125,8 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
|
|||||||
stream_putw(s, 0);
|
stream_putw(s, 0);
|
||||||
total_attr_len = bgp_packet_attribute(
|
total_attr_len = bgp_packet_attribute(
|
||||||
NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL,
|
NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL,
|
||||||
0, addpath_capable, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
|
0, addpath_capable, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* Set Total Path Attribute Length. */
|
/* Set Total Path Attribute Length. */
|
||||||
stream_putw_at(s, pos, total_attr_len);
|
stream_putw_at(s, pos, total_attr_len);
|
||||||
|
@ -3575,6 +3575,26 @@ DEFUN (no_bgp_fast_external_failover,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (bgp_bestpath_aigp,
|
||||||
|
bgp_bestpath_aigp_cmd,
|
||||||
|
"[no$no] bgp bestpath aigp",
|
||||||
|
NO_STR
|
||||||
|
BGP_STR
|
||||||
|
"Change the default bestpath selection\n"
|
||||||
|
"Evaluate the AIGP attribute during the best path selection process\n")
|
||||||
|
{
|
||||||
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
|
|
||||||
|
if (no)
|
||||||
|
UNSET_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP);
|
||||||
|
else
|
||||||
|
SET_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP);
|
||||||
|
|
||||||
|
bgp_recalculate_all_bestpaths(bgp);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* "bgp bestpath compare-routerid" configuration. */
|
/* "bgp bestpath compare-routerid" configuration. */
|
||||||
DEFUN (bgp_bestpath_compare_router_id,
|
DEFUN (bgp_bestpath_compare_router_id,
|
||||||
bgp_bestpath_compare_router_id_cmd,
|
bgp_bestpath_compare_router_id_cmd,
|
||||||
@ -6555,6 +6575,26 @@ DEFUN (no_neighbor_ebgp_multihop,
|
|||||||
return peer_ebgp_multihop_unset_vty(vty, argv[idx_peer]->arg);
|
return peer_ebgp_multihop_unset_vty(vty, argv[idx_peer]->arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (neighbor_aigp,
|
||||||
|
neighbor_aigp_cmd,
|
||||||
|
"[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor aigp",
|
||||||
|
NO_STR
|
||||||
|
NEIGHBOR_STR
|
||||||
|
NEIGHBOR_ADDR_STR2
|
||||||
|
"Enable send and receive of the AIGP attribute per neighbor\n")
|
||||||
|
{
|
||||||
|
struct peer *peer;
|
||||||
|
|
||||||
|
peer = peer_and_group_lookup_vty(vty, neighbor);
|
||||||
|
if (!peer)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
|
||||||
|
if (no)
|
||||||
|
return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AIGP);
|
||||||
|
else
|
||||||
|
return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AIGP);
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t get_role_by_name(const char *role_str)
|
static uint8_t get_role_by_name(const char *role_str)
|
||||||
{
|
{
|
||||||
if (strncmp(role_str, "peer", 2) == 0)
|
if (strncmp(role_str, "peer", 2) == 0)
|
||||||
@ -17162,6 +17202,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* aigp */
|
||||||
|
if (peergroup_flag_check(peer, PEER_FLAG_AIGP))
|
||||||
|
vty_out(vty, " neighbor %s aigp\n", addr);
|
||||||
|
|
||||||
/* role */
|
/* role */
|
||||||
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
|
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
|
||||||
peer->local_role != ROLE_UNDEFINED)
|
peer->local_role != ROLE_UNDEFINED)
|
||||||
@ -17996,6 +18040,8 @@ int bgp_config_write(struct vty *vty)
|
|||||||
}
|
}
|
||||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID))
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID))
|
||||||
vty_out(vty, " bgp bestpath compare-routerid\n");
|
vty_out(vty, " bgp bestpath compare-routerid\n");
|
||||||
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP))
|
||||||
|
vty_out(vty, " bgp bestpath aigp\n");
|
||||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED)
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED)
|
||||||
|| CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) {
|
|| CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) {
|
||||||
vty_out(vty, " bgp bestpath med");
|
vty_out(vty, " bgp bestpath med");
|
||||||
@ -18570,6 +18616,9 @@ void bgp_vty_init(void)
|
|||||||
install_element(BGP_NODE, &neighbor_role_strict_cmd);
|
install_element(BGP_NODE, &neighbor_role_strict_cmd);
|
||||||
install_element(BGP_NODE, &no_neighbor_role_cmd);
|
install_element(BGP_NODE, &no_neighbor_role_cmd);
|
||||||
|
|
||||||
|
/* "neighbor aigp" commands. */
|
||||||
|
install_element(BGP_NODE, &neighbor_aigp_cmd);
|
||||||
|
|
||||||
/* bgp disable-ebgp-connected-nh-check */
|
/* bgp disable-ebgp-connected-nh-check */
|
||||||
install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
|
install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
|
||||||
install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
|
install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
|
||||||
@ -18704,6 +18753,9 @@ void bgp_vty_init(void)
|
|||||||
install_element(BGP_NODE, &bgp_fast_external_failover_cmd);
|
install_element(BGP_NODE, &bgp_fast_external_failover_cmd);
|
||||||
install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd);
|
install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd);
|
||||||
|
|
||||||
|
/* "bgp bestpath aigp" commands */
|
||||||
|
install_element(BGP_NODE, &bgp_bestpath_aigp_cmd);
|
||||||
|
|
||||||
/* "bgp bestpath compare-routerid" commands */
|
/* "bgp bestpath compare-routerid" commands */
|
||||||
install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
|
install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
|
||||||
install_element(BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd);
|
install_element(BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd);
|
||||||
|
@ -4281,6 +4281,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
|
|||||||
{PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_reset},
|
{PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_reset},
|
||||||
{PEER_FLAG_ROLE, 0, peer_change_reset},
|
{PEER_FLAG_ROLE, 0, peer_change_reset},
|
||||||
{PEER_FLAG_PORT, 0, peer_change_reset},
|
{PEER_FLAG_PORT, 0, peer_change_reset},
|
||||||
|
{PEER_FLAG_AIGP, 0, peer_change_none},
|
||||||
{0, 0, 0}};
|
{0, 0, 0}};
|
||||||
|
|
||||||
static const struct peer_flag_action peer_af_flag_action_list[] = {
|
static const struct peer_flag_action peer_af_flag_action_list[] = {
|
||||||
|
73
bgpd/bgpd.h
73
bgpd/bgpd.h
@ -494,44 +494,46 @@ struct bgp {
|
|||||||
|
|
||||||
/* BGP flags. */
|
/* BGP flags. */
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
#define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0)
|
#define BGP_FLAG_ALWAYS_COMPARE_MED (1ULL << 0)
|
||||||
#define BGP_FLAG_DETERMINISTIC_MED (1 << 1)
|
#define BGP_FLAG_DETERMINISTIC_MED (1ULL << 1)
|
||||||
#define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2)
|
#define BGP_FLAG_MED_MISSING_AS_WORST (1ULL << 2)
|
||||||
#define BGP_FLAG_MED_CONFED (1 << 3)
|
#define BGP_FLAG_MED_CONFED (1ULL << 3)
|
||||||
#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 4)
|
#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1ULL << 4)
|
||||||
#define BGP_FLAG_COMPARE_ROUTER_ID (1 << 5)
|
#define BGP_FLAG_COMPARE_ROUTER_ID (1ULL << 5)
|
||||||
#define BGP_FLAG_ASPATH_IGNORE (1 << 6)
|
#define BGP_FLAG_ASPATH_IGNORE (1ULL << 6)
|
||||||
#define BGP_FLAG_IMPORT_CHECK (1 << 7)
|
#define BGP_FLAG_IMPORT_CHECK (1ULL << 7)
|
||||||
#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 8)
|
#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1ULL << 8)
|
||||||
#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 9)
|
#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1ULL << 9)
|
||||||
|
|
||||||
/* This flag is set when we have full BGP Graceful-Restart mode enable */
|
/* This flag is set when we have full BGP Graceful-Restart mode enable */
|
||||||
#define BGP_FLAG_GRACEFUL_RESTART (1 << 10)
|
#define BGP_FLAG_GRACEFUL_RESTART (1ULL << 10)
|
||||||
|
|
||||||
#define BGP_FLAG_ASPATH_CONFED (1 << 11)
|
#define BGP_FLAG_ASPATH_CONFED (1ULL << 11)
|
||||||
#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 12)
|
#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1ULL << 12)
|
||||||
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 13)
|
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1ULL << 13)
|
||||||
#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 14)
|
#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1ULL << 14)
|
||||||
#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1 << 15)
|
#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1ULL << 15)
|
||||||
#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 16)
|
#define BGP_FLAG_FORCE_STATIC_PROCESS (1ULL << 16)
|
||||||
#define BGP_FLAG_SHOW_HOSTNAME (1 << 17)
|
#define BGP_FLAG_SHOW_HOSTNAME (1ULL << 17)
|
||||||
#define BGP_FLAG_GR_PRESERVE_FWD (1 << 18)
|
#define BGP_FLAG_GR_PRESERVE_FWD (1ULL << 18)
|
||||||
#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 19)
|
#define BGP_FLAG_GRACEFUL_SHUTDOWN (1ULL << 19)
|
||||||
#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 20)
|
#define BGP_FLAG_DELETE_IN_PROGRESS (1ULL << 20)
|
||||||
#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 21)
|
#define BGP_FLAG_SELECT_DEFER_DISABLE (1ULL << 21)
|
||||||
#define BGP_FLAG_GR_DISABLE_EOR (1 << 22)
|
#define BGP_FLAG_GR_DISABLE_EOR (1ULL << 22)
|
||||||
#define BGP_FLAG_EBGP_REQUIRES_POLICY (1 << 23)
|
#define BGP_FLAG_EBGP_REQUIRES_POLICY (1ULL << 23)
|
||||||
#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1 << 24)
|
#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1ULL << 24)
|
||||||
|
|
||||||
/* This flag is set if the instance is in administrative shutdown */
|
/* This flag is set if the instance is in administrative shutdown */
|
||||||
#define BGP_FLAG_SHUTDOWN (1 << 25)
|
#define BGP_FLAG_SHUTDOWN (1ULL << 25)
|
||||||
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 26)
|
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1ULL << 26)
|
||||||
#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 27)
|
#define BGP_FLAG_SUPPRESS_DUPLICATES (1ULL << 27)
|
||||||
#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 29)
|
#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1ULL << 29)
|
||||||
/* Indicate Graceful Restart support for BGP NOTIFICATION messages */
|
/* Indicate Graceful Restart support for BGP NOTIFICATION messages */
|
||||||
#define BGP_FLAG_GRACEFUL_NOTIFICATION (1 << 30)
|
#define BGP_FLAG_GRACEFUL_NOTIFICATION (1ULL << 30)
|
||||||
/* Send Hard Reset CEASE Notification for 'Administrative Reset' */
|
/* Send Hard Reset CEASE Notification for 'Administrative Reset' */
|
||||||
#define BGP_FLAG_HARD_ADMIN_RESET (1 << 31)
|
#define BGP_FLAG_HARD_ADMIN_RESET (1ULL << 31)
|
||||||
|
/* Evaluate the AIGP attribute during the best path selection process */
|
||||||
|
#define BGP_FLAG_COMPARE_AIGP (1ULL << 32)
|
||||||
|
|
||||||
/* BGP default address-families.
|
/* BGP default address-families.
|
||||||
* New peers inherit enabled afi/safis from bgp instance.
|
* New peers inherit enabled afi/safis from bgp instance.
|
||||||
@ -1405,6 +1407,7 @@ struct peer {
|
|||||||
/* `local-role` configured */
|
/* `local-role` configured */
|
||||||
#define PEER_FLAG_ROLE (1ULL << 32)
|
#define PEER_FLAG_ROLE (1ULL << 32)
|
||||||
#define PEER_FLAG_PORT (1ULL << 33)
|
#define PEER_FLAG_PORT (1ULL << 33)
|
||||||
|
#define PEER_FLAG_AIGP (1ULL << 34)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
|
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
|
||||||
@ -1898,6 +1901,7 @@ struct bgp_nlri {
|
|||||||
#define BGP_ATTR_PMSI_TUNNEL 22
|
#define BGP_ATTR_PMSI_TUNNEL 22
|
||||||
#define BGP_ATTR_ENCAP 23
|
#define BGP_ATTR_ENCAP 23
|
||||||
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
|
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
|
||||||
|
#define BGP_ATTR_AIGP 26
|
||||||
#define BGP_ATTR_LARGE_COMMUNITIES 32
|
#define BGP_ATTR_LARGE_COMMUNITIES 32
|
||||||
#define BGP_ATTR_OTC 35
|
#define BGP_ATTR_OTC 35
|
||||||
#define BGP_ATTR_PREFIX_SID 40
|
#define BGP_ATTR_PREFIX_SID 40
|
||||||
@ -2026,6 +2030,13 @@ struct bgp_nlri {
|
|||||||
#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN 1
|
#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN 1
|
||||||
#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX 65535
|
#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX 65535
|
||||||
|
|
||||||
|
/* BGP AIGP */
|
||||||
|
#define BGP_AIGP_TLV_RESERVED 0 /* AIGP Reserved */
|
||||||
|
#define BGP_AIGP_TLV_METRIC 1 /* AIGP Metric */
|
||||||
|
#define BGP_AIGP_TLV_METRIC_LEN 11
|
||||||
|
#define BGP_AIGP_TLV_METRIC_MAX 0xffffffffffffffffULL
|
||||||
|
#define BGP_AIGP_TLV_METRIC_DESC "Accumulated IGP Metric"
|
||||||
|
|
||||||
/* Flag for peer_clear_soft(). */
|
/* Flag for peer_clear_soft(). */
|
||||||
enum bgp_clear_type {
|
enum bgp_clear_type {
|
||||||
BGP_CLEAR_SOFT_NONE,
|
BGP_CLEAR_SOFT_NONE,
|
||||||
|
@ -348,6 +348,7 @@ DECLARE_QOBJ_TYPE(route_map);
|
|||||||
(strmatch(A, "frr-bgp-route-map:set-origin"))
|
(strmatch(A, "frr-bgp-route-map:set-origin"))
|
||||||
#define IS_SET_ATOMIC_AGGREGATE(A) \
|
#define IS_SET_ATOMIC_AGGREGATE(A) \
|
||||||
(strmatch(A, "frr-bgp-route-map:atomic-aggregate"))
|
(strmatch(A, "frr-bgp-route-map:atomic-aggregate"))
|
||||||
|
#define IS_SET_AIGP_METRIC(A) (strmatch(A, "frr-bgp-route-map:aigp-metric"))
|
||||||
#define IS_SET_ORIGINATOR_ID(A) \
|
#define IS_SET_ORIGINATOR_ID(A) \
|
||||||
(strmatch(A, "frr-bgp-route-map:originator-id"))
|
(strmatch(A, "frr-bgp-route-map:originator-id"))
|
||||||
#define IS_SET_COMM_LIST_DEL(A) \
|
#define IS_SET_COMM_LIST_DEL(A) \
|
||||||
|
@ -1089,6 +1089,11 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
|
|||||||
"./rmap-set-action/frr-bgp-route-map:origin"));
|
"./rmap-set-action/frr-bgp-route-map:origin"));
|
||||||
} else if (IS_SET_ATOMIC_AGGREGATE(action)) {
|
} else if (IS_SET_ATOMIC_AGGREGATE(action)) {
|
||||||
vty_out(vty, " set atomic-aggregate\n");
|
vty_out(vty, " set atomic-aggregate\n");
|
||||||
|
} else if (IS_SET_AIGP_METRIC(action)) {
|
||||||
|
vty_out(vty, " set aigp-metric %s\n",
|
||||||
|
yang_dnode_get_string(
|
||||||
|
dnode,
|
||||||
|
"./rmap-set-action/frr-bgp-route-map:aigp-metric"));
|
||||||
} else if (IS_SET_ORIGINATOR_ID(action)) {
|
} else if (IS_SET_ORIGINATOR_ID(action)) {
|
||||||
vty_out(vty, " set originator-id %s\n",
|
vty_out(vty, " set originator-id %s\n",
|
||||||
yang_dnode_get_string(
|
yang_dnode_get_string(
|
||||||
|
0
tests/topotests/bgp_aigp/__init__.py
Normal file
0
tests/topotests/bgp_aigp/__init__.py
Normal file
12
tests/topotests/bgp_aigp/r1/bgpd.conf
Normal file
12
tests/topotests/bgp_aigp/r1/bgpd.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 10.0.0.2 remote-as internal
|
||||||
|
neighbor 10.0.0.2 update-source lo
|
||||||
|
neighbor 10.0.0.2 timers 1 3
|
||||||
|
neighbor 10.0.0.2 timers connect 1
|
||||||
|
neighbor 10.0.0.3 remote-as internal
|
||||||
|
neighbor 10.0.0.3 timers 1 3
|
||||||
|
neighbor 10.0.0.3 timers connect 1
|
||||||
|
neighbor 10.0.0.3 update-source lo
|
||||||
|
!
|
17
tests/topotests/bgp_aigp/r1/ospfd.conf
Normal file
17
tests/topotests/bgp_aigp/r1/ospfd.conf
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r1-eth0
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r1-eth1
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 30
|
||||||
|
!
|
||||||
|
router ospf
|
||||||
|
router-id 10.0.0.1
|
||||||
|
network 0.0.0.0/0 area 0
|
10
tests/topotests/bgp_aigp/r1/zebra.conf
Normal file
10
tests/topotests/bgp_aigp/r1/zebra.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.1/32
|
||||||
|
!
|
||||||
|
interface r1-eth0
|
||||||
|
ip address 192.168.12.1/24
|
||||||
|
!
|
||||||
|
interface r1-eth1
|
||||||
|
ip address 192.168.13.1/24
|
||||||
|
!
|
14
tests/topotests/bgp_aigp/r2/bgpd.conf
Normal file
14
tests/topotests/bgp_aigp/r2/bgpd.conf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 10.0.0.1 remote-as internal
|
||||||
|
neighbor 10.0.0.1 timers 1 3
|
||||||
|
neighbor 10.0.0.1 timers connect 1
|
||||||
|
neighbor 192.168.24.4 remote-as external
|
||||||
|
neighbor 192.168.24.4 timers 1 3
|
||||||
|
neighbor 192.168.24.4 timers connect 1
|
||||||
|
neighbor 192.168.24.4 aigp
|
||||||
|
address-family ipv4
|
||||||
|
redistribute connected
|
||||||
|
exit-address-family
|
||||||
|
!
|
13
tests/topotests/bgp_aigp/r2/ospfd.conf
Normal file
13
tests/topotests/bgp_aigp/r2/ospfd.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r2-eth0
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
router ospf
|
||||||
|
router-id 10.0.0.2
|
||||||
|
network 192.168.12.0/24 area 0
|
||||||
|
network 10.0.0.2/32 area 0
|
10
tests/topotests/bgp_aigp/r2/zebra.conf
Normal file
10
tests/topotests/bgp_aigp/r2/zebra.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.2/32
|
||||||
|
!
|
||||||
|
interface r2-eth0
|
||||||
|
ip address 192.168.12.2/24
|
||||||
|
!
|
||||||
|
interface r2-eth1
|
||||||
|
ip address 192.168.24.2/24
|
||||||
|
!
|
14
tests/topotests/bgp_aigp/r3/bgpd.conf
Normal file
14
tests/topotests/bgp_aigp/r3/bgpd.conf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 10.0.0.1 remote-as internal
|
||||||
|
neighbor 10.0.0.1 timers 1 3
|
||||||
|
neighbor 10.0.0.1 timers connect 1
|
||||||
|
neighbor 192.168.35.5 remote-as external
|
||||||
|
neighbor 192.168.35.5 timers 1 3
|
||||||
|
neighbor 192.168.35.5 timers connect 1
|
||||||
|
neighbor 192.168.35.5 aigp
|
||||||
|
address-family ipv4
|
||||||
|
redistribute connected
|
||||||
|
exit-address-family
|
||||||
|
!
|
13
tests/topotests/bgp_aigp/r3/ospfd.conf
Normal file
13
tests/topotests/bgp_aigp/r3/ospfd.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r3-eth0
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 30
|
||||||
|
!
|
||||||
|
router ospf
|
||||||
|
router-id 10.0.0.3
|
||||||
|
network 192.168.13.0/24 area 0
|
||||||
|
network 10.0.0.3/32 area 0
|
10
tests/topotests/bgp_aigp/r3/zebra.conf
Normal file
10
tests/topotests/bgp_aigp/r3/zebra.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.3/32
|
||||||
|
!
|
||||||
|
interface r3-eth0
|
||||||
|
ip address 192.168.13.3/24
|
||||||
|
!
|
||||||
|
interface r3-eth1
|
||||||
|
ip address 192.168.35.3/24
|
||||||
|
!
|
16
tests/topotests/bgp_aigp/r4/bgpd.conf
Normal file
16
tests/topotests/bgp_aigp/r4/bgpd.conf
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.24.2 remote-as external
|
||||||
|
neighbor 192.168.24.2 timers 1 3
|
||||||
|
neighbor 192.168.24.2 timers connect 1
|
||||||
|
neighbor 192.168.24.2 aigp
|
||||||
|
neighbor 10.0.0.6 remote-as internal
|
||||||
|
neighbor 10.0.0.6 timers 1 3
|
||||||
|
neighbor 10.0.0.6 timers connect 1
|
||||||
|
neighbor 10.0.0.6 update-source lo
|
||||||
|
address-family ipv4
|
||||||
|
redistribute connected
|
||||||
|
redistribute ospf
|
||||||
|
exit-address-family
|
||||||
|
!
|
13
tests/topotests/bgp_aigp/r4/ospfd.conf
Normal file
13
tests/topotests/bgp_aigp/r4/ospfd.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r4-eth1
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 20
|
||||||
|
!
|
||||||
|
router ospf
|
||||||
|
router-id 10.0.0.4
|
||||||
|
network 192.168.46.0/24 area 0
|
||||||
|
network 10.0.0.4/32 area 0
|
10
tests/topotests/bgp_aigp/r4/zebra.conf
Normal file
10
tests/topotests/bgp_aigp/r4/zebra.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.4/32
|
||||||
|
!
|
||||||
|
interface r4-eth0
|
||||||
|
ip address 192.168.24.4/24
|
||||||
|
!
|
||||||
|
interface r4-eth1
|
||||||
|
ip address 192.168.46.4/24
|
||||||
|
!
|
16
tests/topotests/bgp_aigp/r5/bgpd.conf
Normal file
16
tests/topotests/bgp_aigp/r5/bgpd.conf
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.35.3 remote-as external
|
||||||
|
neighbor 192.168.35.3 timers 1 3
|
||||||
|
neighbor 192.168.35.3 timers connect 1
|
||||||
|
neighbor 192.168.35.3 aigp
|
||||||
|
neighbor 10.0.0.6 remote-as internal
|
||||||
|
neighbor 10.0.0.6 timers 1 3
|
||||||
|
neighbor 10.0.0.6 timers connect 1
|
||||||
|
neighbor 10.0.0.6 update-source lo
|
||||||
|
address-family ipv4
|
||||||
|
redistribute connected
|
||||||
|
redistribute ospf
|
||||||
|
exit-address-family
|
||||||
|
!
|
13
tests/topotests/bgp_aigp/r5/ospfd.conf
Normal file
13
tests/topotests/bgp_aigp/r5/ospfd.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r5-eth1
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
router ospf
|
||||||
|
router-id 10.0.0.5
|
||||||
|
network 192.168.56.0/24 area 0
|
||||||
|
network 10.0.0.5/32 area 0
|
10
tests/topotests/bgp_aigp/r5/zebra.conf
Normal file
10
tests/topotests/bgp_aigp/r5/zebra.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.5/32
|
||||||
|
!
|
||||||
|
interface r5-eth0
|
||||||
|
ip address 192.168.35.5/24
|
||||||
|
!
|
||||||
|
interface r5-eth1
|
||||||
|
ip address 192.168.56.5/24
|
||||||
|
!
|
20
tests/topotests/bgp_aigp/r6/bgpd.conf
Normal file
20
tests/topotests/bgp_aigp/r6/bgpd.conf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 10.0.0.4 remote-as internal
|
||||||
|
neighbor 10.0.0.4 timers 1 3
|
||||||
|
neighbor 10.0.0.4 timers connect 1
|
||||||
|
neighbor 10.0.0.4 route-reflector-client
|
||||||
|
neighbor 10.0.0.4 update-source lo
|
||||||
|
neighbor 10.0.0.5 remote-as internal
|
||||||
|
neighbor 10.0.0.5 timers 1 3
|
||||||
|
neighbor 10.0.0.5 timers connect 1
|
||||||
|
neighbor 10.0.0.5 route-reflector-client
|
||||||
|
neighbor 10.0.0.5 update-source lo
|
||||||
|
neighbor 192.168.67.7 remote-as internal
|
||||||
|
neighbor 192.168.67.7 timers 1 3
|
||||||
|
neighbor 192.168.67.7 timers connect 1
|
||||||
|
address-family ipv4
|
||||||
|
redistribute ospf
|
||||||
|
exit-address-family
|
||||||
|
!
|
17
tests/topotests/bgp_aigp/r6/ospfd.conf
Normal file
17
tests/topotests/bgp_aigp/r6/ospfd.conf
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
interface r6-eth0
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 20
|
||||||
|
!
|
||||||
|
interface r6-eth1
|
||||||
|
ip ospf dead-interval 4
|
||||||
|
ip ospf hello-interval 1
|
||||||
|
ip ospf cost 10
|
||||||
|
!
|
||||||
|
router ospf
|
||||||
|
router-id 10.0.0.6
|
||||||
|
network 0.0.0.0/0 area 0
|
13
tests/topotests/bgp_aigp/r6/zebra.conf
Normal file
13
tests/topotests/bgp_aigp/r6/zebra.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.6/32
|
||||||
|
!
|
||||||
|
interface r6-eth0
|
||||||
|
ip address 192.168.46.6/24
|
||||||
|
!
|
||||||
|
interface r6-eth1
|
||||||
|
ip address 192.168.56.6/24
|
||||||
|
!
|
||||||
|
interface r6-eth2
|
||||||
|
ip address 192.168.67.6/24
|
||||||
|
!
|
22
tests/topotests/bgp_aigp/r7/bgpd.conf
Normal file
22
tests/topotests/bgp_aigp/r7/bgpd.conf
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
no bgp network import-check
|
||||||
|
neighbor 192.168.67.6 remote-as internal
|
||||||
|
neighbor 192.168.67.6 timers 1 3
|
||||||
|
neighbor 192.168.67.6 timers connect 1
|
||||||
|
address-family ipv4
|
||||||
|
redistribute connected route-map rmap metric 71
|
||||||
|
exit-address-family
|
||||||
|
!
|
||||||
|
ip prefix-list p71 seq 5 permit 10.0.0.71/32
|
||||||
|
ip prefix-list p72 seq 5 permit 10.0.0.72/32
|
||||||
|
!
|
||||||
|
route-map rmap permit 10
|
||||||
|
match ip address prefix-list p71
|
||||||
|
set aigp igp-metric
|
||||||
|
!
|
||||||
|
route-map rmap permit 20
|
||||||
|
match ip address prefix-list p72
|
||||||
|
set aigp 72
|
||||||
|
exit
|
||||||
|
!
|
9
tests/topotests/bgp_aigp/r7/zebra.conf
Normal file
9
tests/topotests/bgp_aigp/r7/zebra.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 10.0.0.7/32
|
||||||
|
ip address 10.0.0.71/32
|
||||||
|
ip address 10.0.0.72/32
|
||||||
|
!
|
||||||
|
interface r7-eth0
|
||||||
|
ip address 192.168.67.7/24
|
||||||
|
!
|
224
tests/topotests/bgp_aigp/test_bgp_aigp.py
Normal file
224
tests/topotests/bgp_aigp/test_bgp_aigp.py
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 by
|
||||||
|
# Donatas Abraitis <donatas@opensourcerouting.org>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software
|
||||||
|
# for any purpose with or without fee is hereby granted, provided
|
||||||
|
# that the above copyright notice and this permission notice appear
|
||||||
|
# in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||||
|
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||||
|
# OF THIS SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32.
|
||||||
|
|
||||||
|
r6 receives those routes with aigp-metric TLV.
|
||||||
|
|
||||||
|
r2 and r3 receives those routes with aigp-metric TLV increased by 20,
|
||||||
|
and 30 appropriately.
|
||||||
|
|
||||||
|
r1 receives routes with aigp-metric TLV 91,101 and 92,102 appropriately.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import functools
|
||||||
|
|
||||||
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(os.path.join(CWD, "../"))
|
||||||
|
|
||||||
|
# pylint: disable=C0413
|
||||||
|
from lib import topotest
|
||||||
|
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||||
|
from lib.common_config import step
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.bgpd]
|
||||||
|
|
||||||
|
|
||||||
|
def build_topo(tgen):
|
||||||
|
for routern in range(1, 8):
|
||||||
|
tgen.add_router("r{}".format(routern))
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s1")
|
||||||
|
switch.add_link(tgen.gears["r1"])
|
||||||
|
switch.add_link(tgen.gears["r2"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s2")
|
||||||
|
switch.add_link(tgen.gears["r1"])
|
||||||
|
switch.add_link(tgen.gears["r3"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s3")
|
||||||
|
switch.add_link(tgen.gears["r2"])
|
||||||
|
switch.add_link(tgen.gears["r4"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s4")
|
||||||
|
switch.add_link(tgen.gears["r3"])
|
||||||
|
switch.add_link(tgen.gears["r5"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s5")
|
||||||
|
switch.add_link(tgen.gears["r4"])
|
||||||
|
switch.add_link(tgen.gears["r6"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s6")
|
||||||
|
switch.add_link(tgen.gears["r5"])
|
||||||
|
switch.add_link(tgen.gears["r6"])
|
||||||
|
|
||||||
|
switch = tgen.add_switch("s7")
|
||||||
|
switch.add_link(tgen.gears["r6"])
|
||||||
|
switch.add_link(tgen.gears["r7"])
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(mod):
|
||||||
|
tgen = Topogen(build_topo, mod.__name__)
|
||||||
|
tgen.start_topology()
|
||||||
|
|
||||||
|
router_list = tgen.routers()
|
||||||
|
|
||||||
|
for i, (rname, router) in enumerate(router_list.items(), 1):
|
||||||
|
router.load_config(
|
||||||
|
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
|
||||||
|
)
|
||||||
|
router.load_config(
|
||||||
|
TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
|
||||||
|
)
|
||||||
|
router.load_config(
|
||||||
|
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
|
||||||
|
)
|
||||||
|
|
||||||
|
tgen.start_router()
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module(mod):
|
||||||
|
tgen = get_topogen()
|
||||||
|
tgen.stop_topology()
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_aigp():
|
||||||
|
tgen = get_topogen()
|
||||||
|
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
r1 = tgen.gears["r1"]
|
||||||
|
r2 = tgen.gears["r2"]
|
||||||
|
r3 = tgen.gears["r3"]
|
||||||
|
r4 = tgen.gears["r4"]
|
||||||
|
r5 = tgen.gears["r5"]
|
||||||
|
|
||||||
|
def _bgp_converge():
|
||||||
|
output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.0.0.71/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"aigpMetric": 101,
|
||||||
|
"valid": True,
|
||||||
|
"bestpath": {"selectionReason": "Router ID"},
|
||||||
|
"nexthops": [{"hostname": "r2", "accessible": True}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aigpMetric": 91,
|
||||||
|
"valid": True,
|
||||||
|
"nexthops": [{"hostname": "r3", "accessible": True}],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
def _bgp_check_aigp_metric(router, prefix, aigp):
|
||||||
|
output = json.loads(
|
||||||
|
router.vtysh_cmd("show bgp ipv4 unicast {} json".format(prefix))
|
||||||
|
)
|
||||||
|
expected = {"paths": [{"aigpMetric": aigp, "valid": True}]}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
def _bgp_check_aigp_metric_bestpath():
|
||||||
|
output = json.loads(
|
||||||
|
r1.vtysh_cmd(
|
||||||
|
"show bgp ipv4 unicast 10.0.0.64/28 longer-prefixes json detail"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
expected = {
|
||||||
|
"routes": {
|
||||||
|
"10.0.0.71/32": [
|
||||||
|
{
|
||||||
|
"aigpMetric": 101,
|
||||||
|
"valid": True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aigpMetric": 91,
|
||||||
|
"valid": True,
|
||||||
|
"bestpath": {"selectionReason": "AIGP"},
|
||||||
|
"nexthops": [{"hostname": "r3", "accessible": True}],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"10.0.0.72/32": [
|
||||||
|
{
|
||||||
|
"aigpMetric": 102,
|
||||||
|
"valid": True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aigpMetric": 92,
|
||||||
|
"valid": True,
|
||||||
|
"bestpath": {"selectionReason": "AIGP"},
|
||||||
|
"nexthops": [{"hostname": "r3", "accessible": True}],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
# Initial converge, AIGP is not involved in best-path selection process
|
||||||
|
test_func = functools.partial(_bgp_converge)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "can't converge initially"
|
||||||
|
|
||||||
|
# Enable `bgp bestpath aigp`
|
||||||
|
r1.vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp
|
||||||
|
bgp bestpath aigp
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
# r4, 10.0.0.71/32 with aigp-metric 71
|
||||||
|
test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.0.71/32", 71)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "aigp-metric for 10.0.0.71/32 is not 71"
|
||||||
|
|
||||||
|
# r5, 10.0.0.72/32 with aigp-metric 72
|
||||||
|
test_func = functools.partial(_bgp_check_aigp_metric, r5, "10.0.0.72/32", 72)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "aigp-metric for 10.0.0.72/32 is not 72"
|
||||||
|
|
||||||
|
# r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30)
|
||||||
|
test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 101)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "aigp-metric for 10.0.0.71/32 is not 101"
|
||||||
|
|
||||||
|
# r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20)
|
||||||
|
test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 92)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "aigp-metric for 10.0.0.72/32 is not 92"
|
||||||
|
|
||||||
|
# r1, check if AIGP is considered in best-path selection (lowest wins)
|
||||||
|
test_func = functools.partial(_bgp_check_aigp_metric_bestpath)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "AIGP attribute is not considered in best-path selection"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
sys.exit(pytest.main(args))
|
@ -276,6 +276,12 @@ module frr-bgp-route-map {
|
|||||||
"Set BGP atomic-aggregate attribute";
|
"Set BGP atomic-aggregate attribute";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
identity aigp-metric {
|
||||||
|
base frr-route-map:rmap-set-type;
|
||||||
|
description
|
||||||
|
"Set BGP AIGP attribute (AIGP TLV Metric)";
|
||||||
|
}
|
||||||
|
|
||||||
identity as-path-prepend {
|
identity as-path-prepend {
|
||||||
base frr-route-map:rmap-set-type;
|
base frr-route-map:rmap-set-type;
|
||||||
description
|
description
|
||||||
@ -800,6 +806,15 @@ module frr-bgp-route-map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case aigp-metric {
|
||||||
|
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:aigp-metric')";
|
||||||
|
leaf aigp-metric {
|
||||||
|
type string;
|
||||||
|
description
|
||||||
|
"Set BGP AIGP attribute (AIGP Metric TLV)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case as-path-prepend {
|
case as-path-prepend {
|
||||||
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:as-path-prepend')";
|
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:as-path-prepend')";
|
||||||
choice as-path-prepend {
|
choice as-path-prepend {
|
||||||
|
Loading…
Reference in New Issue
Block a user