mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-02 20:27:14 +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_PREFIX_SID, "PREFIX_SID"},
|
||||
{BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
|
||||
{BGP_ATTR_AIGP, "AIGP"},
|
||||
{0}};
|
||||
|
||||
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)
|
||||
{
|
||||
return p;
|
||||
@ -702,6 +807,7 @@ unsigned int attrhash_key_make(const void *p)
|
||||
MIX(attr->nh_type);
|
||||
MIX(attr->bh_type);
|
||||
MIX(attr->otc);
|
||||
MIX(bgp_attr_get_aigp_metric(attr));
|
||||
|
||||
return key;
|
||||
}
|
||||
@ -736,6 +842,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
|
||||
== bgp_attr_get_cluster(attr2)
|
||||
&& bgp_attr_get_transit(attr1)
|
||||
== 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->encap_tunneltype == attr2->encap_tunneltype)
|
||||
&& 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_IPV6_EXT_COMMUNITIES] =
|
||||
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;
|
||||
|
||||
@ -3053,6 +3162,45 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
|
||||
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. */
|
||||
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:
|
||||
ret = bgp_attr_otc(&attr_args);
|
||||
break;
|
||||
case BGP_ATTR_AIGP:
|
||||
ret = bgp_attr_aigp(&attr_args);
|
||||
break;
|
||||
default:
|
||||
ret = bgp_attr_unknown(&attr_args);
|
||||
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 peer *from, struct prefix_rd *prd,
|
||||
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 aspath_sizep;
|
||||
@ -4457,6 +4609,22 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
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. */
|
||||
struct transit *transit = bgp_attr_get_transit(attr);
|
||||
|
||||
@ -4540,7 +4708,7 @@ void bgp_attr_finish(void)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
unsigned long cp;
|
||||
@ -4549,6 +4717,7 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
||||
struct aspath *aspath;
|
||||
bool addpath_capable = false;
|
||||
uint32_t addpath_tx_id = 0;
|
||||
struct attr *attr = bpi->attr;
|
||||
|
||||
/* Remember current pointer. */
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
len = stream_get_endp(s) - cp - 2;
|
||||
stream_putw_at(s, cp, len);
|
||||
|
@ -329,6 +329,9 @@ struct attr {
|
||||
|
||||
/* OTC value if set */
|
||||
uint32_t otc;
|
||||
|
||||
/* AIGP Metric */
|
||||
uint64_t aigp_metric;
|
||||
};
|
||||
|
||||
/* rmap_change_flags definition */
|
||||
@ -396,15 +399,13 @@ extern struct attr *bgp_attr_aggregate_intern(
|
||||
struct community *community, struct ecommunity *ecommunity,
|
||||
struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
|
||||
uint8_t atomic_aggregate, const struct prefix *p);
|
||||
extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
struct stream *s, struct attr *attr,
|
||||
struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *p, afi_t afi, safi_t safi,
|
||||
struct peer *from, struct prefix_rd *prd,
|
||||
mpls_label_t *label, uint32_t num_labels,
|
||||
bool addpath_capable,
|
||||
uint32_t addpath_tx_id);
|
||||
extern void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
||||
extern bgp_size_t bgp_packet_attribute(
|
||||
struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr,
|
||||
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi,
|
||||
safi_t safi, struct peer *from, struct prefix_rd *prd,
|
||||
mpls_label_t *label, uint32_t num_labels, bool addpath_capable,
|
||||
uint32_t addpath_tx_id, struct bgp_path_info *bpi);
|
||||
extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
|
||||
const struct prefix *p);
|
||||
extern bool attrhash_cmp(const void *arg1, const void *arg2);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return attr->cluster1;
|
||||
|
@ -853,8 +853,9 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
|
||||
stream_putw(s, 0);
|
||||
|
||||
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
|
||||
total_attr_len = bgp_packet_attribute(NULL, peer, s, attr,
|
||||
&vecarr, NULL, afi, safi, peer, NULL, NULL, 0, 0, 0);
|
||||
total_attr_len =
|
||||
bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi,
|
||||
safi, peer, NULL, NULL, 0, 0, 0, NULL);
|
||||
|
||||
/* 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),
|
||||
", 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)))
|
||||
snprintf(buf + strlen(buf), size - strlen(buf), ", metric %u",
|
||||
attr->med);
|
||||
|
@ -376,7 +376,7 @@ bgp_dump_route_node_record(int afi, struct bgp_dest *dest,
|
||||
|
||||
/* Dump attribute. */
|
||||
/* 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);
|
||||
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",
|
||||
.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,
|
||||
.title = "BGP peergroup operated on in error",
|
||||
|
@ -34,6 +34,7 @@ enum bgp_log_refs {
|
||||
EC_BGP_ATTR_PMSI_TYPE,
|
||||
EC_BGP_ATTR_PMSI_LEN,
|
||||
EC_BGP_ATTR_NH_SEND_LEN,
|
||||
EC_BGP_ATTR_AIGP,
|
||||
EC_BGP_PEER_GROUP,
|
||||
EC_BGP_PEER_DELETE,
|
||||
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:
|
||||
* - BGP_ROUTE_STATIC
|
||||
* - BGP_ROUTE_AGGREGATE
|
||||
@ -6139,6 +6169,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
|
||||
if (afi == AFI_IP)
|
||||
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)
|
||||
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.tag = tag;
|
||||
|
||||
if (metric)
|
||||
bgp_attr_set_aigp_metric(&attr, metric);
|
||||
|
||||
afi = family2afi(p->family);
|
||||
|
||||
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. */
|
||||
attr_new = attr;
|
||||
|
||||
if (red->redist_metric_flag)
|
||||
if (red->redist_metric_flag) {
|
||||
attr_new.med = red->redist_metric;
|
||||
bgp_attr_set_aigp_metric(&attr_new, red->redist_metric);
|
||||
}
|
||||
|
||||
/* Apply route-map. */
|
||||
if (red->rmap.name) {
|
||||
@ -8944,6 +8982,8 @@ const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason)
|
||||
return "Accept Own";
|
||||
case bgp_path_selection_local_route:
|
||||
return "Local Route";
|
||||
case bgp_path_selection_aigp:
|
||||
return "AIGP";
|
||||
case bgp_path_selection_confed_as_path:
|
||||
return "Confederation based 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);
|
||||
}
|
||||
|
||||
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 (json_paths)
|
||||
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,
|
||||
};
|
||||
|
||||
/* 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' */
|
||||
struct aggregator {
|
||||
as_t as;
|
||||
@ -6354,6 +6394,42 @@ DEFUN_YANG (no_set_atomic_aggregate,
|
||||
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,
|
||||
set_aggregator_as_cmd,
|
||||
"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_origin_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_community_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, &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, &no_set_aggregator_as_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,
|
||||
}
|
||||
},
|
||||
{
|
||||
.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",
|
||||
.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_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_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_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);
|
||||
|
@ -2088,6 +2088,58 @@ lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(
|
||||
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:
|
||||
* /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_accept_own,
|
||||
bgp_path_selection_local_route,
|
||||
bgp_path_selection_aigp,
|
||||
bgp_path_selection_confed_as_path,
|
||||
bgp_path_selection_as_path,
|
||||
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);
|
||||
|
||||
/* 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]) {
|
||||
char *soo_str = ecommunity_str(peer->soo[afi][safi]);
|
||||
|
||||
|
@ -752,7 +752,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
* attr. */
|
||||
total_attr_len = bgp_packet_attribute(
|
||||
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 =
|
||||
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);
|
||||
total_attr_len = bgp_packet_attribute(
|
||||
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. */
|
||||
stream_putw_at(s, pos, total_attr_len);
|
||||
|
@ -3575,6 +3575,26 @@ DEFUN (no_bgp_fast_external_failover,
|
||||
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. */
|
||||
DEFUN (bgp_bestpath_compare_router_id,
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
|
||||
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))
|
||||
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)
|
||||
|| CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) {
|
||||
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, &no_neighbor_role_cmd);
|
||||
|
||||
/* "neighbor aigp" commands. */
|
||||
install_element(BGP_NODE, &neighbor_aigp_cmd);
|
||||
|
||||
/* bgp disable-ebgp-connected-nh-check */
|
||||
install_element(BGP_NODE, &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, &no_bgp_fast_external_failover_cmd);
|
||||
|
||||
/* "bgp bestpath aigp" commands */
|
||||
install_element(BGP_NODE, &bgp_bestpath_aigp_cmd);
|
||||
|
||||
/* "bgp bestpath compare-routerid" commands */
|
||||
install_element(BGP_NODE, &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, 0, peer_change_reset},
|
||||
{PEER_FLAG_PORT, 0, peer_change_reset},
|
||||
{PEER_FLAG_AIGP, 0, peer_change_none},
|
||||
{0, 0, 0}};
|
||||
|
||||
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. */
|
||||
uint64_t flags;
|
||||
#define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0)
|
||||
#define BGP_FLAG_DETERMINISTIC_MED (1 << 1)
|
||||
#define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2)
|
||||
#define BGP_FLAG_MED_CONFED (1 << 3)
|
||||
#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 4)
|
||||
#define BGP_FLAG_COMPARE_ROUTER_ID (1 << 5)
|
||||
#define BGP_FLAG_ASPATH_IGNORE (1 << 6)
|
||||
#define BGP_FLAG_IMPORT_CHECK (1 << 7)
|
||||
#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 8)
|
||||
#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 9)
|
||||
#define BGP_FLAG_ALWAYS_COMPARE_MED (1ULL << 0)
|
||||
#define BGP_FLAG_DETERMINISTIC_MED (1ULL << 1)
|
||||
#define BGP_FLAG_MED_MISSING_AS_WORST (1ULL << 2)
|
||||
#define BGP_FLAG_MED_CONFED (1ULL << 3)
|
||||
#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1ULL << 4)
|
||||
#define BGP_FLAG_COMPARE_ROUTER_ID (1ULL << 5)
|
||||
#define BGP_FLAG_ASPATH_IGNORE (1ULL << 6)
|
||||
#define BGP_FLAG_IMPORT_CHECK (1ULL << 7)
|
||||
#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1ULL << 8)
|
||||
#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1ULL << 9)
|
||||
|
||||
/* 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_MULTIPATH_RELAX (1 << 12)
|
||||
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 13)
|
||||
#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 14)
|
||||
#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1 << 15)
|
||||
#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 16)
|
||||
#define BGP_FLAG_SHOW_HOSTNAME (1 << 17)
|
||||
#define BGP_FLAG_GR_PRESERVE_FWD (1 << 18)
|
||||
#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 19)
|
||||
#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 20)
|
||||
#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 21)
|
||||
#define BGP_FLAG_GR_DISABLE_EOR (1 << 22)
|
||||
#define BGP_FLAG_EBGP_REQUIRES_POLICY (1 << 23)
|
||||
#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1 << 24)
|
||||
#define BGP_FLAG_ASPATH_CONFED (1ULL << 11)
|
||||
#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1ULL << 12)
|
||||
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1ULL << 13)
|
||||
#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1ULL << 14)
|
||||
#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1ULL << 15)
|
||||
#define BGP_FLAG_FORCE_STATIC_PROCESS (1ULL << 16)
|
||||
#define BGP_FLAG_SHOW_HOSTNAME (1ULL << 17)
|
||||
#define BGP_FLAG_GR_PRESERVE_FWD (1ULL << 18)
|
||||
#define BGP_FLAG_GRACEFUL_SHUTDOWN (1ULL << 19)
|
||||
#define BGP_FLAG_DELETE_IN_PROGRESS (1ULL << 20)
|
||||
#define BGP_FLAG_SELECT_DEFER_DISABLE (1ULL << 21)
|
||||
#define BGP_FLAG_GR_DISABLE_EOR (1ULL << 22)
|
||||
#define BGP_FLAG_EBGP_REQUIRES_POLICY (1ULL << 23)
|
||||
#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1ULL << 24)
|
||||
|
||||
/* This flag is set if the instance is in administrative shutdown */
|
||||
#define BGP_FLAG_SHUTDOWN (1 << 25)
|
||||
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 26)
|
||||
#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 27)
|
||||
#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 29)
|
||||
#define BGP_FLAG_SHUTDOWN (1ULL << 25)
|
||||
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1ULL << 26)
|
||||
#define BGP_FLAG_SUPPRESS_DUPLICATES (1ULL << 27)
|
||||
#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1ULL << 29)
|
||||
/* 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' */
|
||||
#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.
|
||||
* New peers inherit enabled afi/safis from bgp instance.
|
||||
@ -1405,6 +1407,7 @@ struct peer {
|
||||
/* `local-role` configured */
|
||||
#define PEER_FLAG_ROLE (1ULL << 32)
|
||||
#define PEER_FLAG_PORT (1ULL << 33)
|
||||
#define PEER_FLAG_AIGP (1ULL << 34)
|
||||
|
||||
/*
|
||||
*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_ENCAP 23
|
||||
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
|
||||
#define BGP_ATTR_AIGP 26
|
||||
#define BGP_ATTR_LARGE_COMMUNITIES 32
|
||||
#define BGP_ATTR_OTC 35
|
||||
#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_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(). */
|
||||
enum bgp_clear_type {
|
||||
BGP_CLEAR_SOFT_NONE,
|
||||
|
@ -348,6 +348,7 @@ DECLARE_QOBJ_TYPE(route_map);
|
||||
(strmatch(A, "frr-bgp-route-map:set-origin"))
|
||||
#define IS_SET_ATOMIC_AGGREGATE(A) \
|
||||
(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) \
|
||||
(strmatch(A, "frr-bgp-route-map:originator-id"))
|
||||
#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"));
|
||||
} else if (IS_SET_ATOMIC_AGGREGATE(action)) {
|
||||
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)) {
|
||||
vty_out(vty, " set originator-id %s\n",
|
||||
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";
|
||||
}
|
||||
|
||||
identity aigp-metric {
|
||||
base frr-route-map:rmap-set-type;
|
||||
description
|
||||
"Set BGP AIGP attribute (AIGP TLV Metric)";
|
||||
}
|
||||
|
||||
identity as-path-prepend {
|
||||
base frr-route-map:rmap-set-type;
|
||||
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 {
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user