summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c108
-rw-r--r--bgpd/bgp_attr.h20
-rw-r--r--bgpd/bgp_bmp.c7
-rw-r--r--bgpd/bgp_debug.c4
-rw-r--r--bgpd/bgp_ecommunity.c71
-rw-r--r--bgpd/bgp_ecommunity.h3
-rw-r--r--bgpd/bgp_route.c180
-rw-r--r--bgpd/bgp_routemap.c30
-rw-r--r--bgpd/bgp_updgrp_packet.c15
-rw-r--r--doc/developer/topotests.rst15
-rw-r--r--doc/user/routemap.rst2
-rw-r--r--isisd/isis_spf.c4
-rw-r--r--lib/event.c25
-rw-r--r--lib/libfrr.c14
-rw-r--r--ospfd/ospf_vty.c2
-rw-r--r--tests/topotests/bgp_aigp_rr/r1/bgpd.conf27
-rw-r--r--tests/topotests/bgp_aigp_rr/r1/ospfd.conf23
-rw-r--r--tests/topotests/bgp_aigp_rr/r1/zebra.conf13
-rw-r--r--tests/topotests/bgp_aigp_rr/r2/bgpd.conf18
-rw-r--r--tests/topotests/bgp_aigp_rr/r2/ospfd.conf18
-rw-r--r--tests/topotests/bgp_aigp_rr/r2/zebra.conf11
-rw-r--r--tests/topotests/bgp_aigp_rr/r3/bgpd.conf11
-rw-r--r--tests/topotests/bgp_aigp_rr/r3/ospfd.conf18
-rw-r--r--tests/topotests/bgp_aigp_rr/r3/zebra.conf10
-rw-r--r--tests/topotests/bgp_aigp_rr/r4/bgpd.conf11
-rw-r--r--tests/topotests/bgp_aigp_rr/r4/ospfd.conf13
-rw-r--r--tests/topotests/bgp_aigp_rr/r4/zebra.conf7
-rw-r--r--tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py128
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf2
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf6
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/r3/frr.conf16
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/r4/frr.conf10
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py61
-rw-r--r--tests/topotests/bgp_oad/r1/frr.conf7
-rw-r--r--tests/topotests/bgp_oad/test_bgp_oad.py36
-rw-r--r--tests/topotests/lib/topotest.py8
-rw-r--r--zebra/kernel_netlink.c6
-rw-r--r--zebra/zebra_rib.c6
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);