diff options
38 files changed, 727 insertions, 239 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 596d820f1b..b62319b211 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -480,12 +480,11 @@ static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length, return false; } -static void stream_put_bgp_aigp_tlv_metric(struct stream *s, - struct bgp_path_info *bpi) +static void stream_put_bgp_aigp_tlv_metric(struct stream *s, uint64_t aigp) { stream_putc(s, BGP_AIGP_TLV_METRIC); stream_putw(s, BGP_AIGP_TLV_METRIC_LEN); - stream_putq(s, bgp_aigp_metric_total(bpi)); + stream_putq(s, aigp); } static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) @@ -4483,77 +4482,30 @@ static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi) } static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer, - struct ecommunity *ecomm, - bool transparent, int attribute) + struct ecommunity *ecomm, int attribute) { - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || - peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) { - if (ecomm->size * ecomm->unit_size > 255) { - stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | - BGP_ATTR_FLAG_TRANS | - BGP_ATTR_FLAG_EXTLEN); - stream_putc(s, attribute); - stream_putw(s, ecomm->size * ecomm->unit_size); - } else { - stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | - BGP_ATTR_FLAG_TRANS); - stream_putc(s, attribute); - stream_putc(s, ecomm->size * ecomm->unit_size); - } - stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size); - } else { - uint8_t *pnt; - int tbit; - int ecom_tr_size = 0; - uint32_t i; - - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * ecomm->unit_size); - tbit = *pnt; - - if (CHECK_FLAG(tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; - - ecom_tr_size++; - } - - if (ecom_tr_size) { - if (ecom_tr_size * ecomm->unit_size > 255) { - stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | - BGP_ATTR_FLAG_TRANS | - BGP_ATTR_FLAG_EXTLEN); - stream_putc(s, attribute); - stream_putw(s, ecom_tr_size * ecomm->unit_size); - } else { - stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | - BGP_ATTR_FLAG_TRANS); - stream_putc(s, attribute); - stream_putc(s, ecom_tr_size * ecomm->unit_size); - } - - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * ecomm->unit_size); - tbit = *pnt; - - if (CHECK_FLAG(tbit, - ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; + if (!ecomm || !ecomm->size) + return; - stream_put(s, pnt, ecomm->unit_size); - } - } + if (ecomm->size * ecomm->unit_size > 255) { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, attribute); + stream_putw(s, ecomm->size * ecomm->unit_size); + } else { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); + stream_putc(s, attribute); + stream_putc(s, ecomm->size * ecomm->unit_size); } + + stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size); } /* Make attribute packet. */ -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, uint8_t num_labels, - bool addpath_capable, uint32_t addpath_tx_id, - struct bgp_path_info *bpi) +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, uint8_t num_labels, + bool addpath_capable, uint32_t addpath_tx_id) { size_t cp; size_t aspath_sizep; @@ -4852,19 +4804,11 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* Extended IPv6/Communities attributes. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) { - bool transparent = CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_RSERVER_CLIENT) && - from && - CHECK_FLAG(from->af_flags[afi][safi], - PEER_FLAG_RSERVER_CLIENT); - if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); - bgp_packet_ecommunity_attribute(s, peer, ecomm, - transparent, - BGP_ATTR_EXT_COMMUNITIES); + bgp_packet_ecommunity_attribute(s, peer, ecomm, BGP_ATTR_EXT_COMMUNITIES); } if (CHECK_FLAG(attr->flag, @@ -4873,7 +4817,6 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_attr_get_ipv6_ecommunity(attr); bgp_packet_ecommunity_attribute(s, peer, ecomm, - transparent, BGP_ATTR_IPV6_EXT_COMMUNITIES); } } @@ -5032,10 +4975,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* AIGP */ - if (bpi && CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && - (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || - peer->sub_sort == BGP_PEER_EBGP_OAD || - peer->sort != BGP_PEER_EBGP)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) { /* 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. @@ -5045,7 +4985,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_AIGP); stream_putc(s, attr_len); - stream_put_bgp_aigp_tlv_metric(s, bpi); + stream_put_bgp_aigp_tlv_metric(s, attr->aigp_metric); } /* Unknown transit attribute. */ @@ -5314,7 +5254,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, 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); + stream_put_bgp_aigp_tlv_metric(s, attr->aigp_metric); } /* Return total size of attribute. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 0a43399be6..c5532f4005 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -387,12 +387,12 @@ 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, uint8_t num_labels, bool addpath_capable, - uint32_t addpath_tx_id, struct bgp_path_info *bpi); +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, + uint8_t num_labels, bool addpath_capable, + uint32_t addpath_tx_id); 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); @@ -515,7 +515,7 @@ static inline void bgp_attr_set_ecommunity(struct attr *attr, { attr->ecommunity = ecomm; - if (ecomm) + if (ecomm && ecomm->size) SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); else UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); @@ -566,7 +566,7 @@ static inline void bgp_attr_set_ipv6_ecommunity(struct attr *attr, { attr->ipv6_ecommunity = ipv6_ecomm; - if (ipv6_ecomm) + if (ipv6_ecomm && ipv6_ecomm->size) SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)); else @@ -585,6 +585,10 @@ static inline void bgp_attr_set_transit(struct attr *attr, attr->transit = transit; } +#define AIGP_TRANSMIT_ALLOWED(peer) \ + (CHECK_FLAG((peer)->flags, PEER_FLAG_AIGP) || ((peer)->sub_sort == BGP_PEER_EBGP_OAD) || \ + ((peer)->sort != BGP_PEER_EBGP)) + static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr) { return attr->aigp_metric; diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 59efb35235..4d9e580a23 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1016,9 +1016,8 @@ 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, NULL); + total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, safi, peer, + NULL, NULL, 0, 0, 0); /* space check? */ @@ -1983,6 +1982,8 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp) bbpeer->open_tx_len = open_len; bbpeer->open_tx = bbpeer->open_rx; + + stream_free(s); } /* update the vrf status of the bmpbgp struct for vrf peer up/down diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 97c3e5740f..097d3684f6 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -449,6 +449,10 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size) ", extcommunity %s", ecommunity_str(bgp_attr_get_ecommunity(attr))); + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) + snprintf(buf + strlen(buf), size - strlen(buf), ", ipv6-extcommunity %s", + ecommunity_str(bgp_attr_get_ipv6_ecommunity(attr))); + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) snprintf(buf + strlen(buf), size - strlen(buf), ", atomic-aggregate"); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 547dcdf7f3..df32d75103 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1408,9 +1408,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) "FS:marking %u", *(pnt + 5)); } else unk_ecom = true; - } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) { + } else if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE) || + type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) { sub_type = *pnt++; - if (sub_type == ECOMMUNITY_LINK_BANDWIDTH) + if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE) + ecommunity_origin_validation_state_str(encbuf, sizeof(encbuf), pnt); + else if (sub_type == ECOMMUNITY_LINK_BANDWIDTH) ecommunity_lb_str(encbuf, sizeof(encbuf), pnt, ecom->disable_ieee_floating); else if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) @@ -1418,20 +1421,13 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) pnt, len); else unk_ecom = true; - } else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) { + } else if (CHECK_FLAG(type, ECOMMUNITY_ENCODE_IP_NON_TRANS)) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_NODE_TARGET) ecommunity_node_target_str( encbuf, sizeof(encbuf), pnt, format); else unk_ecom = true; - } else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) { - sub_type = *pnt++; - if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE) - ecommunity_origin_validation_state_str( - encbuf, sizeof(encbuf), pnt); - else - unk_ecom = true; } else { sub_type = *pnt++; unk_ecom = true; @@ -1587,6 +1583,57 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, return true; } +static bool ecommunity_non_transitive(uint8_t type) +{ + return (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE) || + CHECK_FLAG(type, ECOMMUNITY_ENCODE_IP_NON_TRANS) || + type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS); +} + +/* Delete all non-transitive extended communities */ +bool ecommunity_strip_non_transitive(struct ecommunity *ecom) +{ + uint8_t *p, *q, *new; + uint32_t c, found = 0; + + if (!ecom || !ecom->val) + return false; + + /* Certain extended communities like the Route Target can be present + * multiple times, handle that. + */ + c = 0; + for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++) + if (ecommunity_non_transitive(*p)) + found++; + + if (!found) + return false; + + /* Handle the case where everything needs to be stripped. */ + if (found == ecom->size) { + XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val); + ecom->size = 0; + return true; + } + + /* Strip extended communities with non-transitive flag set */ + new = XMALLOC(MTYPE_ECOMMUNITY_VAL, (ecom->size - found) * ecom->unit_size); + q = new; + for (c = 0, p = ecom->val; c < ecom->size; c++, p += ecom->unit_size) { + if (!ecommunity_non_transitive(*p)) { + memcpy(q, p, ecom->unit_size); + q += ecom->unit_size; + } + } + + XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val); + ecom->val = new; + ecom->size -= found; + + return true; +} + /* * Remove specified extended community value from extended community. * Returns 1 if value was present (and hence, removed), 0 otherwise. @@ -1883,9 +1930,7 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw) if (len < ecom->unit_size) return NULL; - if ((type == ECOMMUNITY_ENCODE_AS || - type == ECOMMUNITY_ENCODE_AS_NON_TRANS) && - sub_type == ECOMMUNITY_LINK_BANDWIDTH) { + if ((type == ECOMMUNITY_ENCODE_AS) && sub_type == ECOMMUNITY_LINK_BANDWIDTH) { uint32_t bwval; pnt += 2; /* bandwidth is encoded as AS:val */ diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 67c16aeb9e..0544cbd316 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -32,9 +32,7 @@ #define ECOMMUNITY_EXTENDED_COMMUNITY_PART_3 0x82 /* Non-transitive extended community types. */ -#define ECOMMUNITY_ENCODE_AS_NON_TRANS 0x40 #define ECOMMUNITY_ENCODE_IP_NON_TRANS 0x41 -#define ECOMMUNITY_ENCODE_AS4_NON_TRANS 0x42 #define ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS 0x43 /* Low-order octet of the Extended Communities type field. */ @@ -398,6 +396,7 @@ extern struct ecommunity *ecommunity_new(void); extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, uint8_t subtype); extern struct ecommunity *ecommunity_new(void); +extern bool ecommunity_strip_non_transitive(struct ecommunity *ecom); extern bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval); struct bgp_pbr_entry_action; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ed1dbc6b42..70da39ee8b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -648,7 +648,7 @@ static bool use_bgp_med_value(struct attr *attr, struct bgp *bgp) missing-as-worst" is specified, treat it as the worst value. */ static uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp) { - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) return attr->med; else { if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) @@ -996,9 +996,9 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* 2. Local preference check. */ new_pref = exist_pref = bgp->default_local_pref; - if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) new_pref = newattr->local_pref; - if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + if (CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) exist_pref = existattr->local_pref; if (new_pref > exist_pref) { @@ -1038,10 +1038,10 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, bool exist_accept_own = false; uint32_t accept_own = COMMUNITY_ACCEPT_OWN; - if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) + if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) new_accept_own = community_include( bgp_attr_get_community(newattr), accept_own); - if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) + if (CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) exist_accept_own = community_include( bgp_attr_get_community(existattr), accept_own); @@ -1500,11 +1500,11 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * be 0 and would always win over the other path. If originator id is * used for the comparison, it will decide which path is better. */ - if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))) new_id.s_addr = newattr->originator_id.s_addr; else new_id.s_addr = peer_new->remote_id.s_addr; - if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + if (CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))) exist_id.s_addr = existattr->originator_id.s_addr; else exist_id.s_addr = peer_exist->remote_id.s_addr; @@ -1779,14 +1779,13 @@ static bool bgp_community_filter(struct peer *peer, struct attr *attr) return true; /* NO_EXPORT check. */ - if (peer->sort == BGP_PEER_EBGP && - community_include(bgp_attr_get_community(attr), - COMMUNITY_NO_EXPORT)) + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD && + community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT)) return true; /* NO_EXPORT_SUBCONFED check. */ - if (peer->sort == BGP_PEER_EBGP - || peer->sort == BGP_PEER_CONFED) + if ((peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) || + peer->sort == BGP_PEER_CONFED) if (community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT_SUBCONFED)) return true; @@ -1801,7 +1800,7 @@ static bool bgp_cluster_filter(struct peer *peer, struct attr *attr) struct cluster_list *cluster = bgp_attr_get_cluster(attr); if (cluster) { - if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID) + if (CHECK_FLAG(peer->bgp->config, BGP_CONFIG_CLUSTER_ID)) cluster_id = peer->bgp->cluster_id; else cluster_id = peer->bgp->router_id; @@ -1814,7 +1813,7 @@ static bool bgp_cluster_filter(struct peer *peer, struct attr *attr) static bool bgp_otc_filter(struct peer *peer, struct attr *attr) { - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) { if (peer->local_role == ROLE_PROVIDER || peer->local_role == ROLE_RS_SERVER) return true; @@ -1825,7 +1824,7 @@ static bool bgp_otc_filter(struct peer *peer, struct attr *attr) if (peer->local_role == ROLE_CUSTOMER || peer->local_role == ROLE_PEER || peer->local_role == ROLE_RS_CLIENT) { - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC); + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC)); attr->otc = peer->as; } return false; @@ -1833,7 +1832,7 @@ static bool bgp_otc_filter(struct peer *peer, struct attr *attr) static bool bgp_otc_egress(struct peer *peer, struct attr *attr) { - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) { if (peer->local_role == ROLE_CUSTOMER || peer->local_role == ROLE_RS_CLIENT || peer->local_role == ROLE_PEER) @@ -1843,7 +1842,7 @@ static bool bgp_otc_egress(struct peer *peer, struct attr *attr) if (peer->local_role == ROLE_PROVIDER || peer->local_role == ROLE_PEER || peer->local_role == ROLE_RS_SERVER) { - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC); + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC)); attr->otc = peer->bgp->as; } return false; @@ -2100,7 +2099,7 @@ void bgp_attr_add_gshut_community(struct attr *attr) /* When we add the graceful-shutdown community we must also * lower the local-preference */ - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)); attr->local_pref = BGP_GSHUT_LOCAL_PREF; } @@ -2304,8 +2303,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If the attribute has originator-id and it is same as remote peer's id. */ - if (onlypeer && piattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID) - && (IPV4_ADDR_SAME(&onlypeer->remote_id, &piattr->originator_id))) { + if (onlypeer && (CHECK_FLAG(piattr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))) && + (IPV4_ADDR_SAME(&onlypeer->remote_id, &piattr->originator_id))) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( "%pBP [Update:SEND] %pFX originator-id is same as remote router-id", @@ -2402,15 +2401,15 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, RESET_FLAG(attr->rmap_change_flags); /* If local-preference is not set. */ - if ((peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) - && (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))) { - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + if ((peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) && + (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))) { + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)); attr->local_pref = bgp->default_local_pref; } /* If originator-id is not set and the route is to be reflected, set the originator id */ - if (ibgp_to_ibgp && (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { + if (ibgp_to_ibgp && (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { IPV4_ADDR_COPY(&(attr->originator_id), &(from->remote_id)); SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); } @@ -2418,12 +2417,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD && - attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { + CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) { if (from != bgp->peer_self && !transparent && !CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) - attr->flag &= - ~(ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)); + UNSET_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))); } /* Since the nexthop attribute can vary per peer, it is not explicitly @@ -2619,8 +2617,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * one. If they match, do not announce, to prevent routing * loops. */ - if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) && - peer->soo[afi][safi]) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) && peer->soo[afi][safi]) { struct ecommunity *ecomm_soo = peer->soo[afi][safi]; struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); @@ -2647,7 +2644,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || peer->sub_sort == BGP_PEER_EBGP_OAD) { - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)); attr->local_pref = BGP_GSHUT_LOCAL_PREF; } else { bgp_attr_add_gshut_community(attr); @@ -2823,6 +2820,65 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, false)); } + /* + * Adjust AIGP for propagation when the nexthop is set to ourselves, + * e.g., using "set ip nexthop peer-address" or when advertising to + * EBGP. Note in route reflection the nexthop is usually unmodified + * and the AIGP should not be adjusted in that case. + */ + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) { + if (nh_reset || + CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS)) { + uint64_t aigp = bgp_aigp_metric_total(pi); + + bgp_attr_set_aigp_metric(attr, aigp); + } + } + + /* Extended communities can be transitive and non-transitive. + * If the extended community is non-transitive, strip it off, + * unless it's a locally originated route (static, aggregate, + * redistributed, etc.). + */ + if (from->sort == BGP_PEER_EBGP && peer->sort == BGP_PEER_EBGP && + pi->sub_type == BGP_ROUTE_NORMAL) { + struct ecommunity *new_ecomm; + struct ecommunity *old_ecomm; + + old_ecomm = bgp_attr_get_ecommunity(attr); + if (old_ecomm) { + new_ecomm = ecommunity_dup(old_ecomm); + if (ecommunity_strip_non_transitive(new_ecomm)) { + bgp_attr_set_ecommunity(attr, new_ecomm); + if (!old_ecomm->refcnt) + ecommunity_free(&old_ecomm); + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug("%pBP: %pFX stripped non-transitive extended communities", + peer, p); + } else { + ecommunity_free(&new_ecomm); + } + } + + /* Extended link-bandwidth communities are encoded as IPv6 + * address-specific extended communities. + */ + old_ecomm = bgp_attr_get_ipv6_ecommunity(attr); + if (old_ecomm) { + new_ecomm = ecommunity_dup(old_ecomm); + if (ecommunity_strip_non_transitive(new_ecomm)) { + bgp_attr_set_ipv6_ecommunity(attr, new_ecomm); + if (!old_ecomm->refcnt) + ecommunity_free(&old_ecomm); + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug("%pBP: %pFX stripped non-transitive ipv6 extended communities", + peer, p); + } else { + ecommunity_free(&new_ecomm); + } + } + } + return true; } @@ -4419,7 +4475,7 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, return false; /* If NEXT_HOP is present, validate it. */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))) { if (attr->nexthop.s_addr == INADDR_ANY || !ipv4_unicast_valid(&attr->nexthop) || bgp_nexthop_self(bgp, afi, type, stype, attr, dest)) @@ -4519,7 +4575,7 @@ static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi, return false; /* The route in question carries the ACCEPT_OWN community */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) { struct community *comm = bgp_attr_get_community(attr); if (community_include(comm, COMMUNITY_ACCEPT_OWN)) @@ -4706,8 +4762,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, */ bool accept_own = false; - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID) - && IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) && + IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) { accept_own = bgp_accept_own(peer, afi, safi, attr, p, &sub_type); if (!accept_own) { @@ -4744,7 +4800,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* If the route has Node Target Extended Communities, check * if it's allowed to be installed locally. */ - if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); if (ecommunity_lookup(ecomm, ECOMMUNITY_ENCODE_IP, @@ -4846,7 +4902,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (bgp_attr_get_community(&new_attr) && community_include(bgp_attr_get_community(&new_attr), COMMUNITY_GSHUT)) { - new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + SET_FLAG(new_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)); new_attr.local_pref = BGP_GSHUT_LOCAL_PREF; /* If graceful-shutdown is configured globally or @@ -5067,10 +5123,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, */ if (((safi == SAFI_EVPN) || (safi == SAFI_MPLS_VPN)) && !same_attr) { - if ((pi->attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) - && (attr_new->flag - & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + if (CHECK_FLAG(pi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) && + CHECK_FLAG(attr_new->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { int cmp; cmp = ecommunity_cmp( @@ -6755,12 +6809,12 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; if (bgp_static->atomic) - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); + SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)); /* Store label index, if required. */ if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) { attr.label_index = bgp_static->label_index; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID); + SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)); } if (safi == SAFI_EVPN || safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) { @@ -8053,8 +8107,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (BGP_PATH_HOLDDOWN(pi)) continue; - if (pi->attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) + if (CHECK_FLAG(pi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) atomic_aggregate = 1; if (pi->sub_type == BGP_ROUTE_AGGREGATE) @@ -9793,7 +9846,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } /* Local Pref */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) if (json_paths) json_object_int_add(json_path, "locPrf", attr->local_pref); @@ -9834,7 +9887,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p, esi_buf, sizeof(esi_buf))); } if (safi == SAFI_EVPN && - attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { + CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { json_ext_community = json_object_new_object(); json_object_string_add( json_ext_community, "string", @@ -9888,8 +9941,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p, vty_out(vty, "\n"); } - if (attr->flag & - ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { vty_out(vty, "%*s", 20, " "); vty_out(vty, "%s\n", bgp_attr_get_ecommunity(attr)->str); @@ -9971,7 +10023,7 @@ void route_vty_out_tmp(struct vty *vty, struct bgp *bgp, struct bgp_dest *dest, json_object_int_add(json_net, "metric", value); } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) json_object_int_add(json_net, "locPrf", attr->local_pref); @@ -10022,7 +10074,7 @@ void route_vty_out_tmp(struct vty *vty, struct bgp *bgp, struct bgp_dest *dest, else vty_out(vty, " "); - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) vty_out(vty, "%7u", attr->local_pref); else vty_out(vty, " "); @@ -10934,7 +10986,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, &path->peer->connection->su); } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))) vty_out(vty, " (%pI4)", &attr->originator_id); else vty_out(vty, " (%pI4)", &path->peer->remote_id); @@ -11057,7 +11109,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ", metric %u", value); } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) { if (json_paths) json_object_int_add(json_path, "locPrf", attr->local_pref); @@ -11065,7 +11117,7 @@ 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 (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP))) { if (json_paths) json_object_int_add(json_path, "aigpMetric", bgp_attr_get_aigp_metric(attr)); @@ -11165,7 +11217,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) { if (json_paths) json_object_boolean_true_add(json_path, "atomicAggregate"); @@ -11173,7 +11225,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ", atomic-aggregate"); } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) { if (json_paths) json_object_int_add(json_path, "otc", attr->otc); else @@ -11237,7 +11289,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, "\n"); /* Line 4 display Community */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) { if (json_paths) { if (!bgp_attr_get_community(attr)->json) community_str(bgp_attr_get_community(attr), @@ -11253,7 +11305,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } /* Line 5 display Extended-community */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { if (json_paths) { json_ext_community = json_object_new_object(); json_object_string_add( @@ -11267,7 +11319,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) { if (json_paths) { json_ext_ipv6_community = json_object_new_object(); json_object_string_add(json_ext_ipv6_community, "string", @@ -11283,7 +11335,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } /* Line 6 display Large community */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) { if (json_paths) { if (!bgp_attr_get_lcommunity(attr)->json) lcommunity_str(bgp_attr_get_lcommunity(attr), @@ -11299,11 +11351,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } /* Line 7 display Originator, Cluster-id */ - if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || + CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { char buf[BUFSIZ] = {0}; - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))) { if (json_paths) json_object_string_addf(json_path, "originatorId", "%pI4", @@ -11313,7 +11365,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, &attr->originator_id); } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { struct cluster_list *cluster = bgp_attr_get_cluster(attr); int i; @@ -11482,7 +11534,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf)); /* Line 10 display PMSI tunnel attribute, if present */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) { const char *str = lookup_msg(bgp_pmsi_tnltype_str, bgp_attr_get_pmsi_tnl_type(attr), PMSI_TNLTYPE_STR_DEFAULT); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 8dd48575e5..8666831c7f 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -480,7 +480,7 @@ route_match_script(void *rule, const struct prefix *prefix, void *object) path->attr->med = newattr.med; - if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + if (CHECK_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) locpref = path->attr->local_pref; if (locpref != newattr.local_pref) { SET_FLAG(path->attr->flag, @@ -713,15 +713,15 @@ route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist, afi); if (ret < 0) return RMAP_NOMATCH; - if (api.match_bitmask & PREFIX_DST_PRESENT || - api.match_bitmask_iprule & PREFIX_DST_PRESENT) { + if (CHECK_FLAG(api.match_bitmask, PREFIX_DST_PRESENT) || + CHECK_FLAG(api.match_bitmask_iprule, PREFIX_DST_PRESENT)) { if (family2afi((&api.dst_prefix)->family) != afi) return RMAP_NOMATCH; return prefix_list_apply(plist, &api.dst_prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH; - } else if (api.match_bitmask & PREFIX_SRC_PRESENT || - api.match_bitmask_iprule & PREFIX_SRC_PRESENT) { + } else if (CHECK_FLAG(api.match_bitmask, PREFIX_SRC_PRESENT) || + CHECK_FLAG(api.match_bitmask_iprule, PREFIX_SRC_PRESENT)) { if (family2afi((&api.src_prefix)->family) != afi) return RMAP_NOMATCH; return (prefix_list_apply(plist, &api.src_prefix) == PREFIX_DENY @@ -2071,7 +2071,7 @@ route_set_ip_nexthop(void *rule, const struct prefix *prefix, void *object) sockunion_family(peer->su_remote) == AF_INET) { path->attr->nexthop.s_addr = sockunion2ip(peer->su_remote); - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)); } else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) { /* The next hop value will be set as part of * packet rewrite. Set the flags here to indicate @@ -2084,7 +2084,7 @@ route_set_ip_nexthop(void *rule, const struct prefix *prefix, void *object) } } else { /* Set next hop value. */ - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)); path->attr->nexthop = *rins->address; SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV4_NHOP_CHANGED); @@ -2218,7 +2218,7 @@ route_set_local_pref(void *rule, const struct prefix *prefix, void *object) if (path->attr->local_pref) locpref = path->attr->local_pref; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)); path->attr->local_pref = route_value_adjust(rv, locpref, path); return RMAP_OKAY; @@ -2293,7 +2293,7 @@ route_set_metric(void *rule, const struct prefix *prefix, void *object) rv = rule; path = object; - if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) + if (CHECK_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) med = path->attr->med; bgp_attr_set_med(path->attr, route_value_adjust(rv, med, path)); @@ -3493,7 +3493,7 @@ route_set_atomic_aggregate(void *rule, const struct prefix *pfx, void *object) struct bgp_path_info *path; path = object; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)); return RMAP_OKAY; } @@ -3571,7 +3571,7 @@ route_set_aggregator_as(void *rule, const struct prefix *prefix, void *object) path->attr->aggregator_as = aggregator->as; path->attr->aggregator_addr = aggregator->address; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)); return RMAP_OKAY; } @@ -3651,7 +3651,7 @@ route_set_label_index(void *rule, const struct prefix *prefix, void *object) label_index = rv->value; if (label_index) { path->attr->label_index = label_index; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)); } return RMAP_OKAY; @@ -4318,7 +4318,7 @@ route_set_originator_id(void *rule, const struct prefix *prefix, void *object) address = rule; path = object; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID); + SET_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)); path->attr->originator_id = *address; return RMAP_OKAY; @@ -7255,7 +7255,7 @@ DEFUN_YANG (no_set_atomic_aggregate, DEFPY_YANG (set_aigp_metric, set_aigp_metric_cmd, - "set aigp-metric <igp-metric|(1-4294967295)>$aigp_metric", + "set aigp-metric <igp-metric|(0-4294967295)>$aigp_metric", SET_STR "BGP AIGP attribute (AIGP Metric TLV)\n" "AIGP Metric value from IGP protocol\n" @@ -7275,7 +7275,7 @@ DEFPY_YANG (set_aigp_metric, DEFPY_YANG (no_set_aigp_metric, no_set_aigp_metric_cmd, - "no set aigp-metric [<igp-metric|(1-4294967295)>]", + "no set aigp-metric [<igp-metric|(0-4294967295)>]", NO_STR SET_STR "BGP AIGP attribute (AIGP Metric TLV)\n" diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index bed00a6640..3ce136ef87 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -738,9 +738,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) /* 5: Encode all the attributes, except MP_REACH_NLRI * attr. */ - total_attr_len = bgp_packet_attribute( - NULL, peer, s, adv->baa->attr, &vecarr, NULL, - afi, safi, from, NULL, NULL, 0, 0, 0, path); + total_attr_len = bgp_packet_attribute(NULL, peer, s, adv->baa->attr, + &vecarr, NULL, afi, safi, from, NULL, + NULL, 0, 0, 0); space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) @@ -1149,12 +1149,9 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, /* Make place for total attribute length. */ pos = stream_get_endp(s); stream_putw(s, 0); - total_attr_len = - bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, - safi, from, NULL, &label, num_labels, - addpath_capable, - BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, - NULL); + total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, safi, from, + NULL, &label, num_labels, addpath_capable, + BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); /* Set Total Path Attribute Length. */ stream_putw_at(s, pos, total_attr_len); diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 6209749636..1ec516a1e1 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -1393,21 +1393,22 @@ or using unified config (specifying which daemons to run is optional): Requirements: - Directory name for a new topotest must not contain hyphen (``-``) characters. - To separate words, use underscores (``_``). For example, ``tests/topotests/bgp_new_example``. + To separate words, use underscores (``_``). For example, ``tests/topotests/bgp_new_example``; - Test code should always be declared inside functions that begin with the ``test_`` prefix. Functions beginning with different prefixes will not be run - by pytest. + by pytest; - Configuration files and long output commands should go into separated files - inside folders named after the equipment. + inside folders named after the equipment; - Tests must be able to run without any interaction. To make sure your test - conforms with this, run it without the :option:`-s` parameter. + conforms with this, run it without the :option:`-s` parameter; - Use `black <https://github.com/psf/black>`_ code formatter before creating - a pull request. This ensures we have a unified code style. + a pull request. This ensures we have a unified code style; - Mark test modules with pytest markers depending on the daemons used during the - tests (see :ref:`topotests-markers`) + tests (see :ref:`topotests-markers`); - Always use IPv4 :rfc:`5737` (``192.0.2.0/24``, ``198.51.100.0/24``, ``203.0.113.0/24``) and IPv6 :rfc:`3849` (``2001:db8::/32``) ranges reserved - for documentation. + for documentation; +- Use unified config (``frr.conf``) for all new [tests](#writing-tests). Tips: diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 60e458a28a..02d674dff0 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -331,7 +331,7 @@ Route Map Set Command Set the maximum metric for the route. -.. clicmd:: set aigp-metric <igp-metric|(1-4294967295)> +.. clicmd:: set aigp-metric <igp-metric|(0-4294967295)> Set the BGP attribute AIGP to a specific value. If ``igp-metric`` is specified, then the value is taken from the IGP protocol, otherwise an arbitrary value. diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 8fc0f144b2..9c32a8447c 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -3258,6 +3258,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, json_object *json = NULL, *json_vrf = NULL; uint8_t algorithm = SR_ALGORITHM_SPF; + ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); if (argv_find(argv, argc, "level-1", &idx)) levels = ISIS_LEVEL1; else if (argv_find(argv, argc, "level-2", &idx)) @@ -3269,7 +3270,6 @@ DEFUN(show_isis_route, show_isis_route_cmd, vty_out(vty, "IS-IS Routing Process not enabled\n"); return CMD_SUCCESS; } - ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); if (argv_find(argv, argc, "prefix-sid", &idx)) prefix_sid = true; @@ -3520,6 +3520,7 @@ DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd, bool all_vrf = false; int idx = 0; + ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); if (argv_find(argv, argc, "level-1", &idx)) levels = ISIS_LEVEL1; else if (argv_find(argv, argc, "level-2", &idx)) @@ -3531,7 +3532,6 @@ DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd, vty_out(vty, "IS-IS Routing Process not enabled\n"); return CMD_SUCCESS; } - ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) diff --git a/lib/event.c b/lib/event.c index d925d0d5f0..c573923f51 100644 --- a/lib/event.c +++ b/lib/event.c @@ -979,7 +979,7 @@ void _event_add_read_write(const struct xref_eventsched *xref, * if we already have a pollfd for our file descriptor, find and * use it */ - for (nfds_t i = 0; i < m->handler.pfdcount; i++) + for (nfds_t i = 0; i < m->handler.pfdcount; i++) { if (m->handler.pfds[i].fd == fd) { queuepos = i; @@ -993,6 +993,15 @@ void _event_add_read_write(const struct xref_eventsched *xref, #endif break; } + /* + * We are setting the fd = -1 for the + * case when a read/write event is going + * away. if we find a -1 we can stuff it + * into that spot, so note it + */ + if (m->handler.pfds[i].fd == -1 && queuepos == m->handler.pfdcount) + queuepos = i; + } /* make sure we have room for this fd + pipe poker fd */ assert(queuepos + 1 < m->handler.pfdsize); @@ -1269,6 +1278,14 @@ static void cancel_arg_helper(struct event_loop *master, for (i = 0; i < master->handler.pfdcount;) { pfd = master->handler.pfds + i; + /* + * Skip this spot, nothing here to see + */ + if (pfd->fd == -1) { + i++; + continue; + } + if (pfd->events & POLLIN) t = master->read[pfd->fd]; else @@ -1590,6 +1607,12 @@ static int thread_process_io_helper(struct event_loop *m, struct event *thread, * we should. */ m->handler.pfds[pos].events &= ~(state); + /* + * ppoll man page says that a fd of -1 causes the particular + * array item to be skipped. So let's skip it + */ + if (m->handler.pfds[pos].events == 0) + m->handler.pfds[pos].fd = -1; if (!thread) { if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP) diff --git a/lib/libfrr.c b/lib/libfrr.c index f2247a48e5..313fe99fd3 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -1126,12 +1126,9 @@ static void frr_terminal_close(int isexit) * don't redirect when stdout is set with --log stdout */ for (fd = 2; fd >= 0; fd--) - if (logging_to_stdout && isatty(fd) && - fd == STDOUT_FILENO) { - /* Do nothing. */ - } else { + if (isatty(fd) && + (fd != STDOUT_FILENO || !logging_to_stdout)) dup2(nullfd, fd); - } close(nullfd); } } @@ -1217,12 +1214,9 @@ void frr_run(struct event_loop *master) * stdout */ for (fd = 2; fd >= 0; fd--) - if (logging_to_stdout && isatty(fd) && - fd == STDOUT_FILENO) { - /* Do nothing. */ - } else { + if (isatty(fd) && + (fd != STDOUT_FILENO || !logging_to_stdout)) dup2(nullfd, fd); - } close(nullfd); } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 01cbfedc1c..3be3de24cf 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -748,6 +748,8 @@ DEFUN (no_ospf_area_range, ospf_area_range_unset(ospf, area, area->ranges, &p); + ospf_area_check_free(ospf, area_id); + return CMD_SUCCESS; } diff --git a/tests/topotests/bgp_aigp_rr/r1/bgpd.conf b/tests/topotests/bgp_aigp_rr/r1/bgpd.conf new file mode 100644 index 0000000000..90d34bdf83 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r1/bgpd.conf @@ -0,0 +1,27 @@ +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + bgp route-reflector allow-outbound-policy + 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.2 route-reflector-client + neighbor 10.0.0.3 remote-as internal + neighbor 10.0.0.3 update-source lo + neighbor 10.0.0.3 timers 1 3 + neighbor 10.0.0.3 timers connect 1 + neighbor 10.0.0.3 route-reflector-client + neighbor 10.0.0.4 remote-as internal + neighbor 10.0.0.4 update-source lo + neighbor 10.0.0.4 timers 1 3 + neighbor 10.0.0.4 timers connect 1 + neighbor 10.0.0.4 route-reflector-client + address-family ipv4 + neighbor 10.0.0.4 route-map set-nexthop out + exit-address-family +! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp_rr/r1/ospfd.conf b/tests/topotests/bgp_aigp_rr/r1/ospfd.conf new file mode 100644 index 0000000000..b5b43c76be --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r1/ospfd.conf @@ -0,0 +1,23 @@ +! +interface lo + ip ospf passive +! +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 10 +! +interface r1-eth2 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.1 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r1/zebra.conf b/tests/topotests/bgp_aigp_rr/r1/zebra.conf new file mode 100644 index 0000000000..bf4a3497e8 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r1/zebra.conf @@ -0,0 +1,13 @@ +! +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 +! +interface r1-eth2 + ip address 192.168.14.1/24 +! diff --git a/tests/topotests/bgp_aigp_rr/r2/bgpd.conf b/tests/topotests/bgp_aigp_rr/r2/bgpd.conf new file mode 100644 index 0000000000..97059fdd33 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r2/bgpd.conf @@ -0,0 +1,18 @@ +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 update-source lo + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + address-family ipv4 + redistribute connected route-map connected-to-bgp + neighbor 10.0.0.1 next-hop-self + exit-address-family +! +ip prefix-list p22 seq 5 permit 10.0.2.2/32 +! +route-map connected-to-bgp permit 10 + match ip address prefix-list p22 + set aigp 2 +! diff --git a/tests/topotests/bgp_aigp_rr/r2/ospfd.conf b/tests/topotests/bgp_aigp_rr/r2/ospfd.conf new file mode 100644 index 0000000000..dd91101d90 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r2/ospfd.conf @@ -0,0 +1,18 @@ +! +interface lo + ip ospf passive +! +interface r2-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +interface r2-eth1 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r2/zebra.conf b/tests/topotests/bgp_aigp_rr/r2/zebra.conf new file mode 100644 index 0000000000..6e2130f7e8 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r2/zebra.conf @@ -0,0 +1,11 @@ +! +interface lo + ip address 10.0.0.2/32 + ip address 10.0.2.2/32 +! +interface r2-eth0 + ip address 192.168.12.2/24 +! +interface r2-eth1 + ip address 192.168.23.2/24 +! diff --git a/tests/topotests/bgp_aigp_rr/r3/bgpd.conf b/tests/topotests/bgp_aigp_rr/r3/bgpd.conf new file mode 100644 index 0000000000..b8a36c5ad0 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r3/bgpd.conf @@ -0,0 +1,11 @@ +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 update-source lo + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + address-family ipv4 + neighbor 10.0.0.1 next-hop-self + exit-address-family +! diff --git a/tests/topotests/bgp_aigp_rr/r3/ospfd.conf b/tests/topotests/bgp_aigp_rr/r3/ospfd.conf new file mode 100644 index 0000000000..48702e4e4c --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r3/ospfd.conf @@ -0,0 +1,18 @@ +! +interface lo + ip ospf passive +! +interface r3-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +interface r3-eth1 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.3 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r3/zebra.conf b/tests/topotests/bgp_aigp_rr/r3/zebra.conf new file mode 100644 index 0000000000..ea6663724e --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r3/zebra.conf @@ -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.23.3/24 +! diff --git a/tests/topotests/bgp_aigp_rr/r4/bgpd.conf b/tests/topotests/bgp_aigp_rr/r4/bgpd.conf new file mode 100644 index 0000000000..b8a36c5ad0 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r4/bgpd.conf @@ -0,0 +1,11 @@ +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 update-source lo + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + address-family ipv4 + neighbor 10.0.0.1 next-hop-self + exit-address-family +! diff --git a/tests/topotests/bgp_aigp_rr/r4/ospfd.conf b/tests/topotests/bgp_aigp_rr/r4/ospfd.conf new file mode 100644 index 0000000000..1d95b2ac2b --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r4/ospfd.conf @@ -0,0 +1,13 @@ +! +interface lo + ip ospf passive +! +interface r4-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.4 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r4/zebra.conf b/tests/topotests/bgp_aigp_rr/r4/zebra.conf new file mode 100644 index 0000000000..d7a7dece2b --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r4/zebra.conf @@ -0,0 +1,7 @@ +! +interface lo + ip address 10.0.0.4/32 +! +interface r4-eth0 + ip address 192.168.14.4/24 +! diff --git a/tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py b/tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py new file mode 100644 index 0000000000..0079535da7 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024, Palo Alto Networks, Inc. +# Enke Chen <enchen@paloaltonetworks.com> +# + +""" +r1, r2, and r3 are directly connectd to each other. +r4 is only connected to r1 directly. + +r1 is the route reflector. +r1 sets the nexthop to itself when advertising routes to r4. + +r2 sources 10.0.2.2/32 with agigp-metric 2. + +Results: + +r1, r2 and r3 should have aigp-meric 2. +r4 should have aigp-metric 12, i.e., aigp + nexthop-metric. +""" + +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 + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 5): + 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["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (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_rr(): + 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"] + + 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) + + + # r2, 10.0.2.2/32 with aigp-metric 2 + test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.2.2/32", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 2" + + # r1, 10.0.2.2/32 with aigp-metric 2 + test_func = functools.partial(_bgp_check_aigp_metric, r1, "10.0.2.2/32", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 2" + + # r3, 10.0.2.2/32 with aigp-metric 2 + test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.2.2/32", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 2" + + # r4, 10.0.2.2/32 with aigp-metric 12: aigp + nexthop-metric + test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.2.2/32", 12) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 12" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf index d0c0813e84..18b312c60f 100644 --- a/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf +++ b/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf @@ -22,7 +22,7 @@ ip prefix-list p200 seq 5 permit 10.10.10.200/32 ! route-map r2 permit 10 match ip address prefix-list p40 - set extcommunity bandwidth 40000 + set extcommunity bandwidth 40000 non-transitive route-map r2 permit 20 match ip address prefix-list p100 set extcommunity bandwidth 100000 diff --git a/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf index 5cad150aef..af07c7cc5c 100644 --- a/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf +++ b/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf @@ -2,9 +2,15 @@ int r2-eth0 ip address 192.168.1.2/24 ! +int r2-eth1 + ip address 192.168.2.2/24 +! router bgp 65000 no bgp ebgp-requires-policy neighbor 192.168.1.1 remote-as internal neighbor 192.168.1.1 timers 1 3 neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.2.1 remote-as external + neighbor 192.168.2.1 timers 1 3 + neighbor 192.168.2.1 timers connect 1 ! diff --git a/tests/topotests/bgp_extended_link_bandwidth/r3/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r3/frr.conf new file mode 100644 index 0000000000..61b13c8893 --- /dev/null +++ b/tests/topotests/bgp_extended_link_bandwidth/r3/frr.conf @@ -0,0 +1,16 @@ +! +int r3-eth0 + ip address 192.168.2.1/24 +! +int r3-eth1 + ip address 192.168.3.1/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers 1 3 + neighbor 192.168.2.2 timers connect 1 + neighbor 192.168.3.2 remote-as external + neighbor 192.168.3.2 timers 1 3 + neighbor 192.168.3.2 timers connect 1 +! diff --git a/tests/topotests/bgp_extended_link_bandwidth/r4/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r4/frr.conf new file mode 100644 index 0000000000..49f0caf7de --- /dev/null +++ b/tests/topotests/bgp_extended_link_bandwidth/r4/frr.conf @@ -0,0 +1,10 @@ +! +int r4-eth0 + ip address 192.168.3.2/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor 192.168.3.1 remote-as external + neighbor 192.168.3.1 timers 1 3 + neighbor 192.168.3.1 timers connect 1 +! diff --git a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py index e9006b81c9..3e5be0310f 100644 --- a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py +++ b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py @@ -22,7 +22,7 @@ pytestmark = [pytest.mark.bgpd] def setup_module(mod): - topodef = {"s1": ("r1", "r2")} + topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3"), "s3": ("r3", "r4")} tgen = Topogen(topodef, mod.__name__) tgen.start_topology() @@ -46,9 +46,11 @@ def test_bgp_dynamic_capability_role(): pytest.skip(tgen.errors) r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] - def _bgp_converge(): - output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail")) + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json detail")) expected = { "routes": { "10.10.10.40/32": { @@ -84,9 +86,60 @@ def test_bgp_dynamic_capability_role(): test_func = functools.partial( _bgp_converge, + r2, ) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) - assert result is None, "Can't see link bandwidths as expected" + assert result is None, "r2 (iBGP) should see link bandwidth extended communities" + + test_func = functools.partial( + _bgp_converge, + r3, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "r3 (eBGP) should see link bandwidth extended communities (including non-transitive)" + + def _bgp_check_non_transitive_extended_communities(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast json detail")) + expected = { + "routes": { + "10.10.10.40/32": { + "paths": [ + { + "extendedIpv6Community": None, + } + ] + }, + "10.10.10.100/32": { + "paths": [ + { + "extendedIpv6Community": { + "string": "LB:65000:12500000000 (100.000 Gbps)", + } + } + ] + }, + "10.10.10.200/32": { + "paths": [ + { + "extendedIpv6Community": { + "string": "LB:65000:25000000000 (200.000 Gbps)", + } + } + ] + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_non_transitive_extended_communities, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "r4 (eBGP) should NOT see non-transitive link bandwidth extended communities" if __name__ == "__main__": diff --git a/tests/topotests/bgp_oad/r1/frr.conf b/tests/topotests/bgp_oad/r1/frr.conf index 39045ba648..f00bdfe7d2 100644 --- a/tests/topotests/bgp_oad/r1/frr.conf +++ b/tests/topotests/bgp_oad/r1/frr.conf @@ -4,6 +4,7 @@ int r1-eth0 ! router bgp 65001 no bgp ebgp-requires-policy + no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 192.168.1.2 timers 1 3 neighbor 192.168.1.2 timers connect 1 @@ -12,10 +13,14 @@ router bgp 65001 neighbor 192.168.1.4 timers 1 3 neighbor 192.168.1.4 timers connect 1 address-family ipv4 unicast + network 10.10.10.1/32 route-map local neighbor 192.168.1.4 route-map r4 in exit-address-family ! route-map r4 permit 10 set local-preference 123 set metric 123 -exit +! +route-map local permit 10 + set community no-export +! diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py index 6dd46fbdaa..b2ea7e0f19 100644 --- a/tests/topotests/bgp_oad/test_bgp_oad.py +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -8,6 +8,8 @@ """ Test if local-preference is passed between different EBGP peers when EBGP-OAD is configured. + +Also check if no-export community is passed to the EBGP-OAD peer. """ import os @@ -51,6 +53,9 @@ def test_bgp_oad(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] def _bgp_converge(): output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) @@ -85,6 +90,37 @@ def test_bgp_oad(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Can't converge" + def _bgp_check_no_export(router, arg=[{"valid": True}]): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.10.10.1/32": arg, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_no_export, + r2, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 should be advertised to r2" + + test_func = functools.partial( + _bgp_check_no_export, + r3, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 should be advertised to r3" + + test_func = functools.partial( + _bgp_check_no_export, + r4, + None, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 should not be advertised to r4 (not OAD peer)" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index d15fefc039..bd98958355 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1244,8 +1244,8 @@ def _sysctl_assure(commander, variable, value): def sysctl_atleast(commander, variable, min_value, raises=False): try: if commander is None: - logger = logging.getLogger("topotest") - commander = micronet.Commander("sysctl", logger=logger) + topotest_logger = logging.getLogger("topotest") + commander = micronet.Commander("sysctl", logger=topotest_logger) return _sysctl_atleast(commander, variable, min_value) except subprocess.CalledProcessError as error: @@ -1262,8 +1262,8 @@ def sysctl_atleast(commander, variable, min_value, raises=False): def sysctl_assure(commander, variable, value, raises=False): try: if commander is None: - logger = logging.getLogger("topotest") - commander = micronet.Commander("sysctl", logger=logger) + topotest_logger = logging.getLogger("topotest") + commander = micronet.Commander("sysctl", logger=topotest_logger) return _sysctl_assure(commander, variable, value) except subprocess.CalledProcessError as error: logger.warning( diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 3547314f84..2148d131ec 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -405,10 +405,6 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return netlink_route_change(h, ns_id, startup); case RTM_DELROUTE: return netlink_route_change(h, ns_id, startup); - case RTM_NEWLINK: - return netlink_link_change(h, ns_id, startup); - case RTM_DELLINK: - return 0; case RTM_NEWNEIGH: case RTM_DELNEIGH: case RTM_GETNEIGH: @@ -438,6 +434,8 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; /* Messages handled in the dplane thread */ + case RTM_NEWLINK: + case RTM_DELLINK: case RTM_NEWADDR: case RTM_DELADDR: case RTM_NEWNETCONF: diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 72421dc8ee..4c1401124b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -640,20 +640,16 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, struct nexthop *nexthop; struct rib_table_info *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(re->vrf_id); - const struct prefix *p, *src_p; enum zebra_dplane_result ret; rib_dest_t *dest = rib_dest_from_rnode(rn); - srcdest_rnode_prefixes(rn, &p, &src_p); - if (info->safi != SAFI_UNICAST) { for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } - /* * Install the resolved nexthop object first. */ @@ -1339,7 +1335,6 @@ static void rib_process(struct route_node *rn) if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { proto_re_changed = re; if (!nexthop_active_update(rn, re, old_fib)) { - const struct prefix *p; struct rib_table_info *info; if (re->type == ZEBRA_ROUTE_TABLE) { @@ -1373,7 +1368,6 @@ static void rib_process(struct route_node *rn) } info = srcdest_rnode_table_info(rn); - srcdest_rnode_prefixes(rn, &p, NULL); zsend_route_notify_owner( rn, re, ZAPI_ROUTE_FAIL_INSTALL, info->afi, info->safi); |
