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:
Donatas Abraitis 2022-10-12 21:06:47 +03:00
parent 91e9aee087
commit 97a52c82a5
43 changed files with 1037 additions and 48 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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? */

View File

@ -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);

View File

@ -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

View File

@ -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",

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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 = {

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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]);

View File

@ -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);

View File

@ -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);

View File

@ -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[] = {

View File

@ -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,

View File

@ -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) \

View File

@ -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(

View File

View 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
!

View 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

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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
!

View 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))

View File

@ -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 {